Skip to content

Commit 1c60fcf

Browse files
committed
Fix #8802: Use wildcards for result type approximation of implicits
Use wildcards for result type approximation of dependent implicit methods. In a situation like ``` def f(using x: T): C[x.Out] ``` we need to go constrain the result type of `f` before doing the implicit search for `T`. Previously we created a fresh type variable `param(1)` with `T & Singleton` as upper bound. That works well for other uses of result type approximation, but in this case, we miss constraining `param(1)` from below by the result of the implicit search. So in the end `param(1)` gets interpolated to its upper bound, which leads to problems. One possible solution is to add the missing lower constraint for the dependent type variable. But it's easier to just use a Wildcard type, which is what this PR does.
1 parent 66f335c commit 1c60fcf

File tree

2 files changed

+24
-6
lines changed

2 files changed

+24
-6
lines changed

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -536,14 +536,15 @@ object ProtoTypes {
536536
/** The result type of `mt`, where all references to parameters of `mt` are
537537
* replaced by either wildcards (if typevarsMissContext) or TypeParamRefs.
538538
*/
539-
def resultTypeApprox(mt: MethodType)(using Context): Type =
540-
if (mt.isResultDependent) {
539+
def resultTypeApprox(mt: MethodType, wildcardOnly: Boolean = false)(using Context): Type =
540+
if mt.isResultDependent then
541541
def replacement(tp: Type) =
542-
if (ctx.mode.is(Mode.TypevarsMissContext) ||
543-
!tp.widenExpr.isValueTypeOrWildcard) WildcardType
542+
if wildcardOnly
543+
|| ctx.mode.is(Mode.TypevarsMissContext)
544+
|| !tp.widenExpr.isValueTypeOrWildcard
545+
then WildcardType
544546
else newDepTypeVar(tp)
545547
mt.resultType.substParams(mt, mt.paramInfos.map(replacement))
546-
}
547548
else mt.resultType
548549

549550
/** The normalized form of a type
@@ -568,7 +569,7 @@ object ProtoTypes {
568569
case poly: PolyType =>
569570
normalize(constrained(poly).resultType, pt)
570571
case mt: MethodType =>
571-
if (mt.isImplicitMethod) normalize(resultTypeApprox(mt), pt)
572+
if (mt.isImplicitMethod) normalize(resultTypeApprox(mt, wildcardOnly = true), pt)
572573
else if (mt.isResultDependent) tp
573574
else {
574575
val rt = normalize(mt.resultType, pt)

tests/pos/i8802.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
trait Foo[A, B] {
2+
type Out
3+
}
4+
5+
object Test {
6+
7+
type Bar[A]
8+
9+
def unit: Bar[Unit] = ???
10+
def product[A, B](fst: Bar[A], snd: Bar[B])(implicit foo: Foo[A, B]): Bar[foo.Out] = ???
11+
12+
implicit def foo[A]: Foo[A, Unit] { type Out = A } = ???
13+
14+
def check[A](bar: Bar[A])(a: A): Unit = {}
15+
16+
check(product(unit, unit))(()) // error
17+
}

0 commit comments

Comments
 (0)