Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support variance annotations in -Ykind-projector mode #12341

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
13 changes: 10 additions & 3 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to add a comment mentioning that we can strip the variance because it's inferred.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smarter Added a comment explaining the decision to just strip the variance

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.
Expand All @@ -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)
Expand Down
28 changes: 28 additions & 0 deletions tests/pos-special/kind-projector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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]]]