From 653c5fd351584f78a602ed7861c8ed4d6b693707 Mon Sep 17 00:00:00 2001 From: Kai Date: Wed, 5 May 2021 20:49:42 +0100 Subject: [PATCH] Support variance annotations in `-Ykind-projector` mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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]]` --- .../src/dotty/tools/dotc/core/StdNames.scala | 3 ++ .../dotty/tools/dotc/parsing/Parsers.scala | 13 +++++++-- tests/pos-special/kind-projector.scala | 28 +++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 076010399651..e7a2dcdbd58f 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -660,6 +660,9 @@ object StdNames { final val STAR : N = "*" final val TILDE: N = "~" + final val MINUS_STAR: N = "-*" + final val PLUS_STAR : N = "+*" + final val isUnary: Set[Name] = Set(MINUS, PLUS, TILDE, BANG) } diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index c8ad2d706945..c4da4975268b 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1447,8 +1447,15 @@ object Parsers { } } - private def makeKindProjectorTypeDef(name: TypeName): TypeDef = - TypeDef(name, WildcardTypeBoundsTree()).withFlags(Param) + private def makeKindProjectorTypeDef(name: TypeName): TypeDef = { + val isVarianceAnnotated = name.startsWith("+") || name.startsWith("-") + // We remove the variance marker from the name without passing along the specified variance at all + // The real variance will be inferred at a later stage but may contradict the variance specified, + // This is ok, because `-Ykind-projector` is for cross-compiling existing Scala 2 code, not for writing new code, + // we may assume that variance annotations have already been checked by the Scala 2 compiler. + val unannotatedName = if (isVarianceAnnotated) name.mapLast(_.drop(1)) else name + TypeDef(unannotatedName, WildcardTypeBoundsTree()).withFlags(Param) + } /** Replaces kind-projector's `*` in a list of types arguments with synthetic names, * returning the new argument list and the synthetic type definitions. @@ -1457,7 +1464,7 @@ object Parsers { val tparams = new ListBuffer[TypeDef] val newParams = params.mapConserve { - case param @ Ident(tpnme.raw.STAR) => + case param @ Ident(tpnme.raw.STAR | tpnme.raw.MINUS_STAR | tpnme.raw.PLUS_STAR) => val name = WildcardParamName.fresh().toTypeName tparams += makeKindProjectorTypeDef(name) Ident(name) diff --git a/tests/pos-special/kind-projector.scala b/tests/pos-special/kind-projector.scala index 1bfd9a36433a..2143cd4ec779 100644 --- a/tests/pos-special/kind-projector.scala +++ b/tests/pos-special/kind-projector.scala @@ -4,6 +4,14 @@ trait Foo[F[_]] trait Qux[F[_, _]] trait Baz[F[_], A, B] +trait FooPlus[+F[+_]] +trait QuxPlus[+F[+_, +_]] +trait BazPlus[+F[+_], +A, +B] + +trait FooMinus[-F[-_]] +trait QuxMinus[-F[-_, -_]] +trait BazMinus[-F[-_], -A, -B] + class Bar1 extends Foo[Either[Int, *]] class Bar2 extends Foo[Either[*, Int]] class Bar3 extends Foo[* => Int] @@ -13,3 +21,23 @@ class Bar6 extends Foo[λ[x => Either[Int, x]]] class Bar7 extends Qux[λ[(x, y) => Either[y, x]]] class Bar8 extends Foo[Baz[Int => *, *, Int]] class Bar9 extends Foo[λ[x => Baz[x => *, Int, x]]] + +class BarPlus1 extends FooPlus[Either[Int, +*]] +class BarPlus2 extends FooPlus[Either[+*, Int]] +class BarPlus3 extends FooPlus[Int => +*] +class BarPlus4 extends FooPlus[(Int, +*, Int)] +class BarPlus5 extends FooPlus[λ[`+x` => Either[Int, x]]] +class BarPlus6 extends QuxPlus[λ[(`+x`, `+y`) => Either[y, x]]] +class BarPlus7 extends FooPlus[BazPlus[Int => +*, +*, Int]] + +class BarMinus1 extends FooMinus[-* => Int] + +class VarianceAnnotationIsActuallyIgnored1 extends FooPlus[Either[Int, -*]] +class VarianceAnnotationIsActuallyIgnored2 extends FooPlus[Either[-*, Int]] +class VarianceAnnotationIsActuallyIgnored3 extends FooMinus[+* => Int] +class VarianceAnnotationIsActuallyIgnored4 extends FooPlus[Int => -*] +class VarianceAnnotationIsActuallyIgnored5 extends FooPlus[(Int, -*, Int)] +class VarianceAnnotationIsActuallyIgnored6 extends FooPlus[λ[`-x` => Either[Int, x]]] +class VarianceAnnotationIsActuallyIgnored7 extends QuxPlus[λ[(`-x`, `-y`) => Either[y, x]]] +class VarianceAnnotationIsActuallyIgnored8 extends FooPlus[BazPlus[Int => -*, -*, Int]] +class VarianceAnnotationIsActuallyIgnored9 extends Foo[λ[`-x` => BazPlus[x => -*, Int, x]]]