diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index 86649d78ed54..191f326e1b37 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -275,7 +275,7 @@ object Inferencing { if (constraint.uninstVars exists qualifies) interpolate() } - /** Instantiate undetermined type variables to that type `tp` is + /** Instantiate undetermined type variables so that type `tp` is * maximized and return None. If this is not possible, because a non-variant * typevar is not uniquely determined, return that typevar in a Some. */ @@ -302,7 +302,7 @@ object Inferencing { * +1 means: only covariant occurrences * 0 means: mixed or non-variant occurrences * - * Note: We intentionally use a relaxed version of variance here, + * Note 1: We intentionally use a relaxed version of variance here, * where the variance does not change under a prefix of a named type * (the strict version makes prefixes invariant). This turns out to be * better for type inference. In a nutshell, if a type variable occurs @@ -311,6 +311,10 @@ object Inferencing { * (U? >: x.type) # T * * we want to instantiate U to x.type right away. No need to wait further. + * + * Note 2: Parameters of implicit method types are assumed to be non-variant here. + * This is necessary to prevent them from getting interpolated before an implicit + * parameter search. */ private def variances(tp: Type, include: TypeVar => Boolean)(implicit ctx: Context): VarianceMap = Stats.track("variances") { val constraint = ctx.typerState.constraint @@ -324,6 +328,11 @@ object Inferencing { if (v == null) vmap.updated(t, variance) else if (v == variance || v == 0) vmap else vmap.updated(t, 0) + case t: ImplicitMethodType => + val saved = variance + variance = 0 + val vmap1 = try foldOver(vmap, t.paramTypes) finally variance = saved + apply(vmap1, t.resultType) case _ => foldOver(vmap, t) } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index fe158dfe2005..d39a46c32b76 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1697,8 +1697,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def adapt(tree: Tree, pt: Type, original: untpd.Tree = untpd.EmptyTree)(implicit ctx: Context): Tree = /*>|>*/ track("adapt") /*<|<*/ { /*>|>*/ ctx.traceIndented(i"adapting $tree of type ${tree.tpe} to $pt", typr, show = true) /*<|<*/ { + def shouldInterpolate(tp: Type) = tp match { + case tp: PolyType => false + case tp: MethodType => tp.isImplicit + case _ => true + } if (tree.isDef) interpolateUndetVars(tree, tree.symbol) - else if (!tree.tpe.widen.isInstanceOf[MethodOrPoly]) interpolateUndetVars(tree, NoSymbol) + else if (shouldInterpolate(tree.tpe.widen)) interpolateUndetVars(tree, NoSymbol) tree.overwriteType(tree.tpe.simplified) adaptInterpolated(tree, pt, original) } diff --git a/tests/pos/i1857.scala b/tests/pos/i1857.scala new file mode 100644 index 000000000000..a48e41932dfa --- /dev/null +++ b/tests/pos/i1857.scala @@ -0,0 +1,34 @@ +trait CommandeerDSL[Host] { + trait Operation[T] + type Op[T] <: Operation[T] +} + +object CommandeerDSL { + def apply[Host, DSL <: CommandeerDSL[Host]](host: Host)(implicit dsl: DSL): DSL = dsl +} + +trait Foo { + def bar(a: String, b: Int): Double +} + +object Foo { + implicit val fooDSL: FooDSL = new FooDSL {} +} + +trait FooDSL extends CommandeerDSL[Foo] { + sealed trait FooOperation[T] extends Operation[T] + type Op[T] = FooOperation[T] + + case class Bar(a: String, b: Int) extends FooOperation[Double] +} + +object RunMe { + def main(args: Array[String]): Unit = { + println("Hi Mum") + + val kevin = CommandeerDSL(null.asInstanceOf[Foo]) + println(s"Found DSL for Foo: $kevin") + val bar = kevin.Bar("bob", 3) + println(s"Made a bar: $bar") + } +} diff --git a/tests/pos/i1857a.scala b/tests/pos/i1857a.scala new file mode 100644 index 000000000000..a7b3b3089a41 --- /dev/null +++ b/tests/pos/i1857a.scala @@ -0,0 +1,10 @@ +object Test { + def foo1[T](x: T)(implicit ev: T): Nothing = ??? + + def test1: Unit = { + implicit val ii: Int = 42 + implicit val ss: String = "foo" + + foo1(10) // ambiguous implicit because T=Any + } +}