Skip to content

Fix #5965: Make scala.quoted.Type poly-kinded #5988

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

Merged
merged 5 commits into from
Mar 8, 2019
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
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ class ScalaSettings extends Settings.SettingGroup {
//.withPostSetHook( _ => YprofileEnabled.value = true )

// Extremely experimental language features
val YkindPolymorphism: Setting[Boolean] = BooleanSetting("-Ykind-polymorphism", "Enable kind polymorphism (see http://dotty.epfl.ch/docs/reference/kind-polymorphism.html). Potentially unsound.")
val YnoKindPolymorphism: Setting[Boolean] = BooleanSetting("-Yno-kind-polymorphism", "Enable kind polymorphism (see http://dotty.epfl.ch/docs/reference/kind-polymorphism.html). Potentially unsound.")

/** Area-specific debug output */
val YexplainLowlevel: Setting[Boolean] = BooleanSetting("-Yexplain-lowlevel", "When explaining type errors, show types at a lower level.")
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ class Definitions {

lazy val AnyKindClass: ClassSymbol = {
val cls = ctx.newCompleteClassSymbol(ScalaPackageClass, tpnme.AnyKind, AbstractFinal | Permanent, Nil)
if (ctx.settings.YkindPolymorphism.value) {
if (!ctx.settings.YnoKindPolymorphism.value) {
// Enable kind-polymorphism by exposing scala.AnyKind
cls.entered
}
Expand Down
4 changes: 0 additions & 4 deletions compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -351,10 +351,6 @@ class ReifyQuotes extends MacroTransform {
// typer to allow pickling/unpickling phase consistent types
transformSplice(spliceTree)

case tree: TypeTree if tree.tpe.typeSymbol.isSplice =>
val splicedType = tree.tpe.stripTypeVar.asInstanceOf[TypeRef].prefix.termSymbol
transformSplice(ref(splicedType).select(tpnme.splice).withSpan(tree.span))

case tree: RefTree if isCaptured(tree.symbol, level) =>
val t = capturers(tree.symbol).apply(tree)
transformSplice(t.select(if (tree.isTerm) nme.splice else tpnme.splice))
Expand Down
3 changes: 1 addition & 2 deletions compiler/test/dotty/tools/dotc/CompilationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ class CompilationTests extends ParallelTesting {
compileFilesInDir("tests/pos-scala2", scala2Mode) +
compileFilesInDir("tests/pos", defaultOptions) +
compileFilesInDir("tests/pos-deep-subtype", allowDeepSubtypes) +
compileFilesInDir("tests/pos-kind-polymorphism", defaultOptions and "-Ykind-polymorphism") +
compileFile(
// succeeds despite -Xfatal-warnings because of -nowarn
"tests/neg-custom-args/fatal-warnings/xfatalWarnings.scala",
Expand Down Expand Up @@ -145,7 +144,7 @@ class CompilationTests extends ParallelTesting {
implicit val testGroup: TestGroup = TestGroup("compileNeg")
compileFilesInDir("tests/neg", defaultOptions) +
compileFilesInDir("tests/neg-tailcall", defaultOptions) +
compileFilesInDir("tests/neg-kind-polymorphism", defaultOptions and "-Ykind-polymorphism") +
compileFilesInDir("tests/neg-no-kind-polymorphism", defaultOptions and "-Yno-kind-polymorphism") +
compileFilesInDir("tests/neg-custom-args/deprecation", defaultOptions.and("-Xfatal-warnings", "-deprecation")) +
compileFilesInDir("tests/neg-custom-args/fatal-warnings", defaultOptions.and("-Xfatal-warnings")) +
compileFilesInDir("tests/neg-custom-args/allow-double-bindings", allowDoubleBindings) +
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/reference/other-new-features/kind-polymorphism.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@ It is declared `abstract` and `final`, so it can be neither instantiated nor ext

`AnyKind` plays a special role in Scala's subtype system: It is a supertype of all other types no matter what their kind is. It is also assumed to be kind-compatible with all other types. Furthermore, `AnyKind` is treated as a higher-kinded type (so it cannot be used as a type of values), but at the same time it has no type parameters (so it cannot be instantiated).

**Note**: This feature is considered experimental and is only enabled under a compiler flag
(i.e. `-Ykind-polymorphism`).
**Note**: This feature is considered experimental but stable and it can be disabled under compiler flag
(i.e. `-Yno-kind-polymorphism`).
46 changes: 46 additions & 0 deletions library/src-bootstrapped/scala/quoted/Type.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package scala.quoted

import scala.quoted.Types.TaggedType
import scala.reflect.ClassTag
import scala.runtime.quoted.Unpickler.Pickled

sealed abstract class Type[T <: AnyKind] {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here I only added <: AnyKind and src-non-bootstrapped/scala/quoted/Type.scala contatins the current version without the bound.

type `$splice` = T
}

/** Some basic type tags, currently incomplete */
object Type {
/** A term quote is desugared by the compiler into a call to this method */
def apply[T <: AnyKind]: Type[T] =
throw new Error("Internal error: this method call should have been replaced by the compiler")

implicit def UnitTag: Type[Unit] = new TaggedType[Unit]
implicit def BooleanTag: Type[Boolean] = new TaggedType[Boolean]
implicit def ByteTag: Type[Byte] = new TaggedType[Byte]
implicit def CharTag: Type[Char] = new TaggedType[Char]
implicit def ShortTag: Type[Short] = new TaggedType[Short]
implicit def IntTag: Type[Int] = new TaggedType[Int]
implicit def LongTag: Type[Long] = new TaggedType[Long]
implicit def FloatTag: Type[Float] = new TaggedType[Float]
implicit def DoubleTag: Type[Double] = new TaggedType[Double]
}

/** All implementations of Type[T].
* These should never be used directly.
*/
object Types {
/** A Type backed by a pickled TASTY tree */
final class TastyType[T](val tasty: Pickled, val args: Seq[Any]) extends Type[T] {
override def toString(): String = s"Type(<pickled tasty>)"
}

/** An Type backed by a value */
final class TaggedType[T](implicit val ct: ClassTag[T]) extends Type[T] {
override def toString: String = s"Type($ct)"
}

/** An Type backed by a tree */
final class TreeType[Tree](val typeTree: Tree) extends quoted.Type[Any] {
override def toString: String = s"Type(<tasty tree>)"
}
}
29 changes: 29 additions & 0 deletions library/src-bootstrapped/scala/tasty/reflect/QuotedOps.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package scala.tasty.reflect

/** Extension methods on scala.quoted.{Expr|Type} to convert to scala.tasty.Tasty objects */
trait QuotedOps extends Core {

implicit class QuotedExprAPI[T](expr: scala.quoted.Expr[T]) {
/** View this expression `Expr[T]` as a `Term` */
def unseal(implicit ctx: Context): Term =
kernel.QuotedExpr_unseal(expr)
}

implicit class QuotedTypeAPI[T <: AnyKind](tpe: scala.quoted.Type[T]) {
/** View this expression `Type[T]` as a `TypeTree` */
def unseal(implicit ctx: Context): TypeTree =
kernel.QuotedType_unseal(tpe)
}

implicit class TermToQuotedAPI(term: Term) {
/** Convert `Term` to an `Expr[T]` and check that it conforms to `T` */
def seal[T](implicit tpe: scala.quoted.Type[T], ctx: Context): scala.quoted.Expr[T] =
kernel.QuotedExpr_seal(term)(tpe)
}

implicit class TypeToQuotedAPI(tpe: Type) {
/** Convert `Type` to an `quoted.Type[T]` */
def seal(implicit ctx: Context): scala.quoted.Type[_] =
kernel.QuotedType_seal(tpe)
}
}
2 changes: 2 additions & 0 deletions tests/neg-no-kind-polymorphism/anykind.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

trait Foo[T <: AnyKind] // error: Not found: type AnyKind
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
18 changes: 18 additions & 0 deletions tests/run-with-compiler/i5965.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
val y: collection.immutable.List[scala.Int] = scala.List.apply[scala.Int](1, 2, 3)

(y: collection.immutable.List[scala.Int])
}
List(1, 2, 3)
{
val y: scala.Option[scala.Int] = scala.Option.apply[scala.Int](4)

(y: scala.Option[scala.Int])
}
Some(4)
{
val y: collection.immutable.Map[scala.Int, scala.Int] = scala.Predef.Map.apply[scala.Int, scala.Int](scala.Predef.ArrowAssoc[scala.Int](4).->[scala.Int](1))

(y: collection.immutable.Map[scala.Int, scala.Int])
}
Map(4 -> 1)
28 changes: 28 additions & 0 deletions tests/run-with-compiler/i5965.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import scala.quoted._

import scala.tasty._

object Test {

implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make

def main(args: Array[String]): Unit = {
'[List]
val list = bound('{List(1, 2, 3)})
println(list.show)
println(list.run)

val opt = bound('{Option(4)})
println(opt.show)
println(opt.run)

val map = bound('{Map(4 -> 1)})
println(map.show)
println(map.run)
}

def bound[T: Type, S[_]: Type](x: Expr[S[T]]): Expr[S[T]] = '{
val y: S[T] = $x
y
}
}
18 changes: 18 additions & 0 deletions tests/run-with-compiler/i5965b.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
val y: collection.immutable.List[scala.Int] = scala.List.apply[scala.Int](1, 2, 3)

(y: collection.immutable.List[scala.Int])
}
List(1, 2, 3)
{
val y: scala.Option[scala.Int] = scala.Option.apply[scala.Int](4)

(y: scala.Option[scala.Int])
}
Some(4)
{
val y: collection.immutable.Map[scala.Int, scala.Int] = scala.Predef.Map.apply[scala.Int, scala.Int](scala.Predef.ArrowAssoc[scala.Int](4).->[scala.Int](1))

(y: collection.immutable.Map[scala.Int, scala.Int])
}
Map(4 -> 1)
28 changes: 28 additions & 0 deletions tests/run-with-compiler/i5965b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import scala.quoted._

import scala.tasty._

object Test {

implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make

def main(args: Array[String]): Unit = {
'[List]
val list = bound('{List(1, 2, 3)})
println(list.show)
println(list.run)

val opt = bound('{Option(4)})
println(opt.show)
println(opt.run)

val map = bound('{Map(4 -> 1)})
println(map.show)
println(map.run)
}

def bound[T: Type, S[_]: Type](x: Expr[S[T]]): Expr[S[T]] = '{
val y = $x
y
}
}