Skip to content

Commit d49a656

Browse files
authored
Merge pull request #4329 from dotty-staging/fix-contrarivant
Fix comment in isAsSpecificValue type and add test
2 parents 8698e48 + c9e67cb commit d49a656

File tree

2 files changed

+31
-6
lines changed

2 files changed

+31
-6
lines changed

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,15 +1149,15 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
11491149
*
11501150
* flip(T) <: flip(U)
11511151
*
1152-
* where `flip` changes top-level contravariant type aliases to covariant ones.
1153-
* Intuitively `<:s` means subtyping `<:`, except that all top-level arguments
1152+
* where `flip` changes covariant occurrences of contravariant type parameters to
1153+
* covariant ones. Intuitively `<:s` means subtyping `<:`, except that all arguments
11541154
* to contravariant parameters are compared as if they were covariant. E.g. given class
11551155
*
11561156
* class Cmp[-X]
11571157
*
1158-
* `Cmp[T] <:s Cmp[U]` if `T <: U`. On the other hand, nested occurrences
1159-
* of parameters are not affected.
1160-
* So `T <: U` would imply `List[Cmp[U]] <:s List[Cmp[T]]`, as usual.
1158+
* `Cmp[T] <:s Cmp[U]` if `T <: U`. On the other hand, non-variant occurrences
1159+
* of parameters are not affected. So `T <: U` would imply `Set[Cmp[U]] <:s Set[Cmp[T]]`,
1160+
* as usual, because `Set` is non-variant.
11611161
*
11621162
* This relation might seem strange, but it models closely what happens for methods.
11631163
* Indeed, if we integrate the existing rules for methods into `<:s` we have now that
@@ -1174,7 +1174,6 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
11741174
else {
11751175
val flip = new TypeMap {
11761176
def apply(t: Type) = t match {
1177-
case t: TypeBounds => t
11781177
case t @ AppliedType(tycon, args) =>
11791178
def mapArg(arg: Type, tparam: TypeParamInfo) =
11801179
if (variance > 0 && tparam.paramVariance < 0) defn.FunctionOf(arg :: Nil, defn.UnitType)

tests/run/contrarivant.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
object Test extends App {
2+
3+
// toplevel contra
4+
implicit def f: String => String = x => "f"
5+
implicit def g: Object => String = x => "g"
6+
def h(implicit x: String => String) = x("")
7+
assert(h == "f", h)
8+
9+
// nested contra
10+
implicit def fs: List[String => String] = List(f)
11+
implicit def gs: List[Object => String] = List(g)
12+
def hs(implicit xs: List[String => String]) = xs.head("")
13+
assert(hs == "f", hs)
14+
15+
// covariant subapplication nested in toplevel contra
16+
implicit def f2: (Unit => String) => String = x => "f2"
17+
implicit def g2: (Unit => Object) => String = x => "g2"
18+
def h2(implicit x: (Unit => String) => String) = x(_ => "")
19+
assert(h2 == "f2", h2)
20+
21+
// covariant subapplication nested in nested contra
22+
implicit def fs2: List[(Unit => String) => String] = List(f2)
23+
implicit def gs2: List[(Unit => Object) => String] = List(g2)
24+
def hs2(implicit xs: List[(Unit => String) => String]) = xs.head(_ => "")
25+
assert(hs2 == "f2", hs2)
26+
}

0 commit comments

Comments
 (0)