Skip to content

Commit b17435f

Browse files
committed
Widen result types of implied methods for specificity testing
When testing specificity of methods, widen result type of synthetic implied methods. I tried widening the inferred result type of these methods already in Namer instead, but this causes problems since it can hide extension methods.
1 parent b1a0234 commit b17435f

File tree

3 files changed

+67
-7
lines changed

3 files changed

+67
-7
lines changed

compiler/src/dotty/tools/dotc/core/Flags.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,10 @@ object Flags {
612612
final val InlineParam: FlagConjunction = allOf(Inline, Param)
613613

614614
/** An extension method */
615-
final val ExtensionMethod = allOf(Method, Extension)
615+
final val ExtensionMethod = allOf(Extension, Method)
616+
617+
/** An implied method */
618+
final val SyntheticImpliedMethod: FlagConjunction = allOf(Synthetic, Implied, Method)
616619

617620
/** An enum case */
618621
final val EnumCase: FlagConjunction = allOf(Enum, Case)

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,23 +1296,50 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
12961296
// # skipped implicit parameters in tp1 - # skipped implicit parameters in tp2
12971297
var implicitBalance: Int = 0
12981298

1299+
/** Widen the type of synthetic implied methods from the implementation class to the
1300+
* type that's implemented. Example
1301+
*
1302+
* implied I[X] for T { ... }
1303+
*
1304+
* This desugars to
1305+
*
1306+
* class I[X] extends T { ... }
1307+
* implied def I[X]: I[X] = new I[X]
1308+
*
1309+
* To compare specificity we should compare with `T`, not with its implementation `I[X]`.
1310+
* No such widening is performed for implied aliases, which are not synthetic. E.g.
1311+
*
1312+
* implied J[X] for T = rhs
1313+
*
1314+
* already has the right result type `T`. Neither is widening performed for implied
1315+
* objects, since these are anyway taken to be more specific than methods
1316+
* (by condition 3a above).
1317+
*/
1318+
def widenImplied(tp: Type, alt: TermRef): Type =
1319+
if (alt.symbol.is(SyntheticImpliedMethod))
1320+
tp.parents match {
1321+
case Nil => tp
1322+
case ps => ps.reduceLeft(AndType(_, _))
1323+
}
1324+
else tp
1325+
12991326
/** Drop any implicit parameter section */
1300-
def stripImplicit(tp: Type, weight: Int): Type = tp match {
1327+
def stripImplicit(tp: Type, alt: TermRef, weight: Int): Type = tp match {
13011328
case mt: MethodType if mt.isImplicitMethod =>
13021329
implicitBalance += mt.paramInfos.length * weight
1303-
resultTypeApprox(mt)
1330+
widenImplied(resultTypeApprox(mt), alt)
13041331
case pt: PolyType =>
1305-
pt.derivedLambdaType(pt.paramNames, pt.paramInfos, stripImplicit(pt.resultType, weight))
1332+
pt.derivedLambdaType(pt.paramNames, pt.paramInfos, stripImplicit(pt.resultType, alt, weight))
13061333
case _ =>
1307-
tp
1334+
widenImplied(tp, alt)
13081335
}
13091336

13101337
val owner1 = if (alt1.symbol.exists) alt1.symbol.owner else NoSymbol
13111338
val owner2 = if (alt2.symbol.exists) alt2.symbol.owner else NoSymbol
13121339
val ownerScore = compareOwner(owner1, owner2)
13131340

1314-
val tp1 = stripImplicit(alt1.widen, -1)
1315-
val tp2 = stripImplicit(alt2.widen, +1)
1341+
val tp1 = stripImplicit(alt1.widen, alt1, -1)
1342+
val tp2 = stripImplicit(alt2.widen, alt2, +1)
13161343
def winsType1 = isAsSpecific(alt1, tp1, alt2, tp2)
13171344
def winsType2 = isAsSpecific(alt2, tp2, alt1, tp1)
13181345

tests/run/implied-specifity.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
case class Show[T](val i: Int)
2+
object Show {
3+
def apply[T](implicit st: Show[T]): Int = st.i
4+
5+
implied showInt for Show[Int](0)
6+
implied fallback[T] for Show[T](1)
7+
}
8+
9+
class Generic
10+
object Generic {
11+
implied gen for Generic
12+
implied showGen[T] given Generic for Show[T](2)
13+
}
14+
15+
object Contextual {
16+
trait Context
17+
implied ctx for Context
18+
implied showGen2[T] given Generic for Show[T](2)
19+
implied showGen3[T] given Generic, Context for Show[T](3)
20+
}
21+
22+
object Test extends App {
23+
assert(Show[Int] == 0)
24+
assert(Show[String] == 1)
25+
assert(Show[Generic] == 2) // showGen beats fallback due to longer argument list
26+
27+
{ import implied Contextual._
28+
assert(Show[Generic] == 3)
29+
}
30+
}

0 commit comments

Comments
 (0)