Skip to content

Commit d436677

Browse files
authored
Merge pull request #8824 from dotty-staging/fix-#8802
Fix #8802: Use wildcards for result type approximation of implicits
2 parents 96e45a7 + 7f8a4db commit d436677

File tree

3 files changed

+50
-8
lines changed

3 files changed

+50
-8
lines changed

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -534,22 +534,23 @@ object ProtoTypes {
534534
newTypeVar(TypeBounds.upper(AndType(tp.widenExpr, defn.SingletonClass.typeRef)))
535535

536536
/** The result type of `mt`, where all references to parameters of `mt` are
537-
* replaced by either wildcards (if typevarsMissContext) or TypeParamRefs.
537+
* replaced by either wildcards 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
550551
* - unwraps polymorphic types, tracking their parameters in the current constraint
551552
* - skips implicit parameters of methods and functions;
552-
* if result type depends on implicit parameter, replace with fresh type dependent parameter.
553+
* if result type depends on implicit parameter, replace with wildcard.
553554
* - converts non-dependent method types to the corresponding function types
554555
* unless the expected type is an ApplyingProto or IgnoredProto.
555556
* - dereferences parameterless method types
@@ -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+
}

tests/pos/i8825.scala

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
sealed trait Nat
2+
case class Succ[N <: Nat](n: N) extends Nat
3+
case object Zero extends Nat
4+
type Zero = Zero.type
5+
type One = Succ[Zero]
6+
7+
sealed trait HList
8+
case class HCons[+H, +T <: HList](head: H, tail: T) extends HList
9+
case object HNil extends HList
10+
type HNil = HNil.type
11+
12+
trait Length[L <: HList] {
13+
type Out <: Nat
14+
}
15+
object Length {
16+
type Aux[L <: HList, Out0 <: Nat] = Length[L] { type Out = Out0 }
17+
def instance[L <: HList, Out0 <: Nat]: Aux[L, Out0] = new Length[L] { type Out = Out0 }
18+
19+
given hnilLength as Aux[HNil, Zero] = instance
20+
given hconsLength[H, T <: HList] (using length: Length[T]) as Aux[HCons[H, T], Succ[length.Out]] = instance // (*)
21+
//given hconsLength[H, T <: HList, N <: Nat] (using length: Aux[T, N]) as Aux[HCons[H, T], Succ[N]] = instance // (**)
22+
}
23+
24+
val test = summon[Length.Aux[HCons[Int, HNil], One]]

0 commit comments

Comments
 (0)