diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index e922a1a55c14..5f6a288bfc28 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -393,7 +393,7 @@ trait ImplicitRunInfo { self: RunInfo => case tp: AppliedType if !tp.tycon.typeSymbol.isClass => def applyArg(arg: Type) = arg match { case TypeBounds(lo, hi) => AndType.make(lo, hi) - case _: WildcardType => defn.AnyType + case WildcardType(TypeBounds(lo, hi)) => AndType.make(lo, hi) case _ => arg } (apply(tp.tycon) /: tp.args)((tc, arg) => AndType.make(tc, applyArg(arg))) diff --git a/tests/pos/i3590.scala b/tests/pos/i3590.scala new file mode 100644 index 000000000000..fe7797a65e1f --- /dev/null +++ b/tests/pos/i3590.scala @@ -0,0 +1,39 @@ +trait Tagged[T] + +object Tagged { + type Aux[T, UNUSED] = Tagged[T] +} + +trait Fun[R] { + type Out +} + +object Fun extends Fun0 { + // In Dotty there is a difference between asking for Tagged.Aux[T, Int] + // and asking for Tagged[T]. In the former case the companion of T is + // not considered as a valid scope during implicit search. In scalac + // both cases are treated equally. + implicit def tagged[T](implicit t: Tagged.Aux[T, Int]): Fun[T] { type Out = Int } = ??? +} + +trait Fun0 { + implicit def default[T]: Fun[T] { type Out = String } = ??? +} + +object FunDemo extends App { + case class A(x: Int, y: String) + object A { + implicit val tag: Tagged[A] = ??? + } + + // Precise version of implicitly that keeps type members + def the[T <: AnyRef](implicit ev: T): ev.type = ev + + val adhl = the[Fun[A]] + + // Compiles in scalac: the tagged case wins the implicit search using A.tag + // Does not compile in Dotty: because of Tagged.Aux[T, _] the companion + // object of T is not explored during the search, + // it fallbacks to default (type Out = String) + identity[Fun[A] { type Out = Int }](adhl) +}