diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 7d77920e8741..48858d321d73 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1142,15 +1142,15 @@ trait Applications extends Compatibility { self: Typer with Dynamic => * * flip(T) <: flip(U) * - * where `flip` changes top-level contravariant type aliases to covariant ones. - * Intuitively `<:s` means subtyping `<:`, except that all top-level arguments + * where `flip` changes covariant occurrences of contravariant type parameters to + * covariant ones. Intuitively `<:s` means subtyping `<:`, except that all arguments * to contravariant parameters are compared as if they were covariant. E.g. given class * * class Cmp[-X] * - * `Cmp[T] <:s Cmp[U]` if `T <: U`. On the other hand, nested occurrences - * of parameters are not affected. - * So `T <: U` would imply `List[Cmp[U]] <:s List[Cmp[T]]`, as usual. + * `Cmp[T] <:s Cmp[U]` if `T <: U`. On the other hand, non-variant occurrences + * of parameters are not affected. So `T <: U` would imply `Set[Cmp[U]] <:s Set[Cmp[T]]`, + * as usual, because `Set` is non-variant. * * This relation might seem strange, but it models closely what happens for methods. * Indeed, if we integrate the existing rules for methods into `<:s` we have now that @@ -1167,7 +1167,6 @@ trait Applications extends Compatibility { self: Typer with Dynamic => else { val flip = new TypeMap { def apply(t: Type) = t match { - case t: TypeBounds => t case t @ AppliedType(tycon, args) => def mapArg(arg: Type, tparam: TypeParamInfo) = if (variance > 0 && tparam.paramVariance < 0) defn.FunctionOf(arg :: Nil, defn.UnitType) diff --git a/tests/run/contrarivant.scala b/tests/run/contrarivant.scala new file mode 100644 index 000000000000..d5781146add1 --- /dev/null +++ b/tests/run/contrarivant.scala @@ -0,0 +1,26 @@ +object Test extends App { + + // toplevel contra + implicit def f: String => String = x => "f" + implicit def g: Object => String = x => "g" + def h(implicit x: String => String) = x("") + assert(h == "f", h) + + // nested contra + implicit def fs: List[String => String] = List(f) + implicit def gs: List[Object => String] = List(g) + def hs(implicit xs: List[String => String]) = xs.head("") + assert(hs == "f", hs) + + // covariant subapplication nested in toplevel contra + implicit def f2: (Unit => String) => String = x => "f2" + implicit def g2: (Unit => Object) => String = x => "g2" + def h2(implicit x: (Unit => String) => String) = x(_ => "") + assert(h2 == "f2", h2) + + // covariant subapplication nested in nested contra + implicit def fs2: List[(Unit => String) => String] = List(f2) + implicit def gs2: List[(Unit => Object) => String] = List(g2) + def hs2(implicit xs: List[(Unit => String) => String]) = xs.head(_ => "") + assert(hs2 == "f2", hs2) +}