diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index e72f7eac0b38..b62e1bc7f0e7 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -534,22 +534,23 @@ object ProtoTypes { newTypeVar(TypeBounds.upper(AndType(tp.widenExpr, defn.SingletonClass.typeRef))) /** The result type of `mt`, where all references to parameters of `mt` are - * replaced by either wildcards (if typevarsMissContext) or TypeParamRefs. + * replaced by either wildcards or TypeParamRefs. */ - def resultTypeApprox(mt: MethodType)(using Context): Type = - if (mt.isResultDependent) { + def resultTypeApprox(mt: MethodType, wildcardOnly: Boolean = false)(using Context): Type = + if mt.isResultDependent then def replacement(tp: Type) = - if (ctx.mode.is(Mode.TypevarsMissContext) || - !tp.widenExpr.isValueTypeOrWildcard) WildcardType + if wildcardOnly + || ctx.mode.is(Mode.TypevarsMissContext) + || !tp.widenExpr.isValueTypeOrWildcard + then WildcardType else newDepTypeVar(tp) mt.resultType.substParams(mt, mt.paramInfos.map(replacement)) - } else mt.resultType /** The normalized form of a type * - unwraps polymorphic types, tracking their parameters in the current constraint * - skips implicit parameters of methods and functions; - * if result type depends on implicit parameter, replace with fresh type dependent parameter. + * if result type depends on implicit parameter, replace with wildcard. * - converts non-dependent method types to the corresponding function types * unless the expected type is an ApplyingProto or IgnoredProto. * - dereferences parameterless method types @@ -568,7 +569,7 @@ object ProtoTypes { case poly: PolyType => normalize(constrained(poly).resultType, pt) case mt: MethodType => - if (mt.isImplicitMethod) normalize(resultTypeApprox(mt), pt) + if (mt.isImplicitMethod) normalize(resultTypeApprox(mt, wildcardOnly = true), pt) else if (mt.isResultDependent) tp else { val rt = normalize(mt.resultType, pt) diff --git a/tests/pos/i8802.scala b/tests/pos/i8802.scala new file mode 100644 index 000000000000..e9afc174d748 --- /dev/null +++ b/tests/pos/i8802.scala @@ -0,0 +1,17 @@ +trait Foo[A, B] { + type Out +} + +object Test { + + type Bar[A] + + def unit: Bar[Unit] = ??? + def product[A, B](fst: Bar[A], snd: Bar[B])(implicit foo: Foo[A, B]): Bar[foo.Out] = ??? + + implicit def foo[A]: Foo[A, Unit] { type Out = A } = ??? + + def check[A](bar: Bar[A])(a: A): Unit = {} + + check(product(unit, unit))(()) // error +} \ No newline at end of file diff --git a/tests/pos/i8825.scala b/tests/pos/i8825.scala new file mode 100644 index 000000000000..49c85434ce98 --- /dev/null +++ b/tests/pos/i8825.scala @@ -0,0 +1,24 @@ +sealed trait Nat +case class Succ[N <: Nat](n: N) extends Nat +case object Zero extends Nat +type Zero = Zero.type +type One = Succ[Zero] + +sealed trait HList +case class HCons[+H, +T <: HList](head: H, tail: T) extends HList +case object HNil extends HList +type HNil = HNil.type + +trait Length[L <: HList] { + type Out <: Nat +} +object Length { + type Aux[L <: HList, Out0 <: Nat] = Length[L] { type Out = Out0 } + def instance[L <: HList, Out0 <: Nat]: Aux[L, Out0] = new Length[L] { type Out = Out0 } + + given hnilLength as Aux[HNil, Zero] = instance + given hconsLength[H, T <: HList] (using length: Length[T]) as Aux[HCons[H, T], Succ[length.Out]] = instance // (*) + //given hconsLength[H, T <: HList, N <: Nat] (using length: Aux[T, N]) as Aux[HCons[H, T], Succ[N]] = instance // (**) +} + +val test = summon[Length.Aux[HCons[Int, HNil], One]] \ No newline at end of file