diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 0a76ff9f240b..2f3ee867af4b 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1181,7 +1181,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w * If the original left-hand type `leftRoot` is a path `p.type`, * and the current widened left type is an application with wildcard arguments * such as `C[_]`, where `X` is `C`'s type parameter corresponding to the `_` argument, - * compare with `C[p.X]` instead. Otherwise return `false`. + * compare with `C[p.X]` instead. Otherwise approximate based on variance. * Also do a capture conversion in either of the following cases: * * - If we are after typer. We generally relax soundness requirements then. @@ -1203,10 +1203,18 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w * paths is less intrusive than skolemization. */ def compareCaptured(arg1: TypeBounds, arg2: Type) = tparam match { - case tparam: Symbol - if leftRoot.isStable || (ctx.isAfterTyper || ctx.mode.is(Mode.TypevarsMissContext)) && leftRoot.member(tparam.name).exists => - val captured = TypeRef(leftRoot, tparam) - isSubArg(captured, arg2) + case tparam: Symbol => + if (leftRoot.isStable || (ctx.isAfterTyper || ctx.mode.is(Mode.TypevarsMissContext)) + && leftRoot.member(tparam.name).exists) { + val captured = TypeRef(leftRoot, tparam) + isSubArg(captured, arg2) + } + else if (v > 0) + isSubType(paramBounds(tparam).hi, arg2) + else if (v < 0) + isSubType(arg2, paramBounds(tparam).lo) + else + false case _ => false } diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 995c78c95cca..a9b2df9a75b9 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -107,8 +107,8 @@ class ExpandSAMs extends MiniPhase { anon.rhs match { case PartialFunctionRHS(pf) => val anonSym = anon.symbol - - val parents = List(defn.AbstractPartialFunctionType.appliedTo(tpe.argInfos), defn.SerializableType) + val anonTpe = anon.tpe.widen + val parents = List(defn.AbstractPartialFunctionType.appliedTo(anonTpe.firstParamTypes.head, anonTpe.resultType), defn.SerializableType) val pfSym = ctx.newNormalizedClassSymbol(anonSym.owner, tpnme.ANON_CLASS, Synthetic | Final, parents, coord = tree.span) def overrideSym(sym: Symbol) = sym.copy( diff --git a/tests/neg/t5729.scala b/tests/neg/t5729.scala new file mode 100644 index 000000000000..cdee8477f7c6 --- /dev/null +++ b/tests/neg/t5729.scala @@ -0,0 +1,7 @@ +object C { + def join(in: Seq[List[_]]): Int = 1 + def join[S](in: Seq[List[S]]): String = "x" + + val x= join(Seq[List[Int]]()) // error: ambiguous overload + assert(x == "x") +} diff --git a/tests/fuzzy/AE-9a131723f09b9f77c99c52b709965e580a61706e.scala b/tests/pos/AE-9a131723f09b9f77c99c52b709965e580a61706e.scala similarity index 100% rename from tests/fuzzy/AE-9a131723f09b9f77c99c52b709965e580a61706e.scala rename to tests/pos/AE-9a131723f09b9f77c99c52b709965e580a61706e.scala diff --git a/tests/pos/capture-variance.scala b/tests/pos/capture-variance.scala new file mode 100644 index 000000000000..9f856e31438e --- /dev/null +++ b/tests/pos/capture-variance.scala @@ -0,0 +1,13 @@ +class Hi +class Lo extends Hi +class Cov1[+T] +class Cov2[+T >: Lo <: Hi] +class Contra1[-T] +class Contra2[-T >: Lo <: Hi] + +object Test { + val a: List[Cov1[Any]] = ??? : List[Cov1[_]] + val b: List[Cov2[Hi]] = ??? : List[Cov2[_]] + val c: List[Contra1[Nothing]] = ??? : List[Contra1[_]] + val d: List[Contra2[Lo]] = ??? : List[Contra2[_]] +} diff --git a/tests/run/t5729.scala b/tests/run/t5729.scala index 3fe3a1dc7f8b..e643ed73ed67 100644 --- a/tests/run/t5729.scala +++ b/tests/run/t5729.scala @@ -4,13 +4,4 @@ object Test extends App { def join[S](in: Seq[T[S]]): String = "x" val x = join(null: Seq[T[_]]) assert(x == 1) // first alt chosen, since second requires a capture conversion in adapt - C -} - -object C { - def join(in: Seq[List[_]]): Int = 1 - def join[S](in: Seq[List[S]]): String = "x" - - val x= join(Seq[List[Int]]()) // second alt chosen, since it is more specific - assert(x == "x") }