Skip to content

Commit 536661d

Browse files
committed
Support variance annotations in -Ykind-projector mode
This change expands the supported subset of `kind-projector` syntax, specifically: * `+*` and `-*` variance annotated variants of `*` placeholder * Variance annotated named parameters in `λ` - `λ[(`-R`, `+E`, `+A`) => F[R, E, A]]`
1 parent 71008dd commit 536661d

File tree

3 files changed

+41
-3
lines changed

3 files changed

+41
-3
lines changed

compiler/src/dotty/tools/dotc/core/StdNames.scala

+3
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,9 @@ object StdNames {
660660
final val STAR : N = "*"
661661
final val TILDE: N = "~"
662662

663+
final val MINUS_STAR: N = "-*"
664+
final val PLUS_STAR : N = "+*"
665+
663666
final val isUnary: Set[Name] = Set(MINUS, PLUS, TILDE, BANG)
664667
}
665668

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

+10-3
Original file line numberDiff line numberDiff line change
@@ -1447,8 +1447,15 @@ object Parsers {
14471447
}
14481448
}
14491449

1450-
private def makeKindProjectorTypeDef(name: TypeName): TypeDef =
1451-
TypeDef(name, WildcardTypeBoundsTree()).withFlags(Param)
1450+
private def makeKindProjectorTypeDef(name: TypeName): TypeDef = {
1451+
val isVarianceAnnotated = name.startsWith("+") || name.startsWith("-")
1452+
// We remove the variance marker from the name without passing along the specified variance at all
1453+
// The real variance will be inferred at a later stage but may contradict the variance specified,
1454+
// This is ok, because `-Ykind-projector` is for cross-compiling existing Scala 2 code, not for writing new code,
1455+
// we may assume that variance annotations have already been checked by the Scala 2 compiler.
1456+
val unannotatedName = if (isVarianceAnnotated) name.mapLast(_.drop(1)) else name
1457+
TypeDef(unannotatedName, WildcardTypeBoundsTree()).withFlags(Param)
1458+
}
14521459

14531460
/** Replaces kind-projector's `*` in a list of types arguments with synthetic names,
14541461
* returning the new argument list and the synthetic type definitions.
@@ -1457,7 +1464,7 @@ object Parsers {
14571464
val tparams = new ListBuffer[TypeDef]
14581465

14591466
val newParams = params.mapConserve {
1460-
case param @ Ident(tpnme.raw.STAR) =>
1467+
case param @ Ident(tpnme.raw.STAR | tpnme.raw.MINUS_STAR | tpnme.raw.PLUS_STAR) =>
14611468
val name = WildcardParamName.fresh().toTypeName
14621469
tparams += makeKindProjectorTypeDef(name)
14631470
Ident(name)

tests/pos-special/kind-projector.scala

+28
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ trait Foo[F[_]]
44
trait Qux[F[_, _]]
55
trait Baz[F[_], A, B]
66

7+
trait FooPlus[+F[+_]]
8+
trait QuxPlus[+F[+_, +_]]
9+
trait BazPlus[+F[+_], +A, +B]
10+
11+
trait FooMinus[-F[-_]]
12+
trait QuxMinus[-F[-_, -_]]
13+
trait BazMinus[-F[-_], -A, -B]
14+
715
class Bar1 extends Foo[Either[Int, *]]
816
class Bar2 extends Foo[Either[*, Int]]
917
class Bar3 extends Foo[* => Int]
@@ -13,3 +21,23 @@ class Bar6 extends Foo[λ[x => Either[Int, x]]]
1321
class Bar7 extends Qux[λ[(x, y) => Either[y, x]]]
1422
class Bar8 extends Foo[Baz[Int => *, *, Int]]
1523
class Bar9 extends Foo[λ[x => Baz[x => *, Int, x]]]
24+
25+
class BarPlus1 extends FooPlus[Either[Int, +*]]
26+
class BarPlus2 extends FooPlus[Either[+*, Int]]
27+
class BarPlus3 extends FooPlus[Int => +*]
28+
class BarPlus4 extends FooPlus[(Int, +*, Int)]
29+
class BarPlus5 extends FooPlus[λ[`+x` => Either[Int, x]]]
30+
class BarPlus6 extends QuxPlus[λ[(`+x`, `+y`) => Either[y, x]]]
31+
class BarPlus7 extends FooPlus[BazPlus[Int => +*, +*, Int]]
32+
33+
class BarMinus1 extends FooMinus[-* => Int]
34+
35+
class VarianceAnnotationIsActuallyIgnored1 extends FooPlus[Either[Int, -*]]
36+
class VarianceAnnotationIsActuallyIgnored2 extends FooPlus[Either[-*, Int]]
37+
class VarianceAnnotationIsActuallyIgnored3 extends FooMinus[+* => Int]
38+
class VarianceAnnotationIsActuallyIgnored4 extends FooPlus[Int => -*]
39+
class VarianceAnnotationIsActuallyIgnored5 extends FooPlus[(Int, -*, Int)]
40+
class VarianceAnnotationIsActuallyIgnored6 extends FooPlus[λ[`-x` => Either[Int, x]]]
41+
class VarianceAnnotationIsActuallyIgnored7 extends QuxPlus[λ[(`-x`, `-y`) => Either[y, x]]]
42+
class VarianceAnnotationIsActuallyIgnored8 extends FooPlus[BazPlus[Int => -*, -*, Int]]
43+
class VarianceAnnotationIsActuallyIgnored9 extends Foo[λ[`-x` => BazPlus[x => -*, Int, x]]]

0 commit comments

Comments
 (0)