Skip to content

Commit 6264a67

Browse files
committed
Widen return type of implied wrappers
1 parent b1a0234 commit 6264a67

File tree

3 files changed

+57
-4
lines changed

3 files changed

+57
-4
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -650,9 +650,12 @@ object desugar {
650650
// TODO: drop this once we do not silently insert empty class parameters anymore
651651
case paramss => paramss
652652
}
653-
// implicit wrapper is typechecked in same scope as constructor, so
654-
// we can reuse the constructor parameters; no derived params are needed.
655-
DefDef(className.toTermName, constrTparams, defParamss, classTypeRef, creatorExpr)
653+
// implicit wrapper is typechecked in same scope as constructor, so
654+
// we can reuse the constructor parameters; no derived params are needed.
655+
val resType =
656+
if (mods.is(Implicit)) classTypeRef
657+
else TypeTree() // infer by widening the rhs type, see widenImplied in Namer
658+
DefDef(className.toTermName, constrTparams, defParamss, resType, creatorExpr)
656659
.withMods(companionMods | mods.flags.toTermFlags & ImplicitOrImplied | Synthetic | Final)
657660
.withSpan(cdef.span) :: Nil
658661
}

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1227,7 +1227,27 @@ class Namer { typer: Typer =>
12271227
}
12281228
}
12291229

1230-
def cookedRhsType = deskolemize(dealiasIfUnit(widenRhs(rhsType)))
1230+
/** Widen type of implied def from the type of the implementing class
1231+
* to the type for which it is implied. Example:
1232+
*
1233+
* implied I[X] for T { ... }
1234+
*
1235+
* This desugars to
1236+
*
1237+
* class I[X] extends T { ... }
1238+
* implied def I[X] = new I[X]
1239+
*
1240+
* The inferred result type of the `def` should be `T`, not `I[X]`.
1241+
*/
1242+
def widenImplied(tp: Type) =
1243+
if (sym.is(Implied))
1244+
tp.parents match {
1245+
case Nil => tp
1246+
case ps => ps.reduce(AndType(_, _))
1247+
}
1248+
else tp
1249+
1250+
def cookedRhsType = deskolemize(dealiasIfUnit(widenImplied(widenRhs(rhsType))))
12311251
def lhsType = fullyDefinedType(cookedRhsType, "right-hand side", mdef.span)
12321252
//if (sym.name.toString == "y") println(i"rhs = $rhsType, cooked = $cookedRhsType")
12331253
if (inherited.exists) {

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)