Skip to content

Commit 33deb72

Browse files
authored
Merge pull request #5988 from dotty-staging/fix-#5965
Fix #5965: Make scala.quoted.Type poly-kinded
2 parents f1cae1f + 242cb92 commit 33deb72

File tree

21 files changed

+174
-10
lines changed

21 files changed

+174
-10
lines changed

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ class ScalaSettings extends Settings.SettingGroup {
138138
//.withPostSetHook( _ => YprofileEnabled.value = true )
139139

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

143143
/** Area-specific debug output */
144144
val YexplainLowlevel: Setting[Boolean] = BooleanSetting("-Yexplain-lowlevel", "When explaining type errors, show types at a lower level.")

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ class Definitions {
320320

321321
lazy val AnyKindClass: ClassSymbol = {
322322
val cls = ctx.newCompleteClassSymbol(ScalaPackageClass, tpnme.AnyKind, AbstractFinal | Permanent, Nil)
323-
if (ctx.settings.YkindPolymorphism.value) {
323+
if (!ctx.settings.YnoKindPolymorphism.value) {
324324
// Enable kind-polymorphism by exposing scala.AnyKind
325325
cls.entered
326326
}

compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -351,10 +351,6 @@ class ReifyQuotes extends MacroTransform {
351351
// typer to allow pickling/unpickling phase consistent types
352352
transformSplice(spliceTree)
353353

354-
case tree: TypeTree if tree.tpe.typeSymbol.isSplice =>
355-
val splicedType = tree.tpe.stripTypeVar.asInstanceOf[TypeRef].prefix.termSymbol
356-
transformSplice(ref(splicedType).select(tpnme.splice).withSpan(tree.span))
357-
358354
case tree: RefTree if isCaptured(tree.symbol, level) =>
359355
val t = capturers(tree.symbol).apply(tree)
360356
transformSplice(t.select(if (tree.isTerm) nme.splice else tpnme.splice))

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ class CompilationTests extends ParallelTesting {
9191
compileFilesInDir("tests/pos-scala2", scala2Mode) +
9292
compileFilesInDir("tests/pos", defaultOptions) +
9393
compileFilesInDir("tests/pos-deep-subtype", allowDeepSubtypes) +
94-
compileFilesInDir("tests/pos-kind-polymorphism", defaultOptions and "-Ykind-polymorphism") +
9594
compileFile(
9695
// succeeds despite -Xfatal-warnings because of -nowarn
9796
"tests/neg-custom-args/fatal-warnings/xfatalWarnings.scala",
@@ -145,7 +144,7 @@ class CompilationTests extends ParallelTesting {
145144
implicit val testGroup: TestGroup = TestGroup("compileNeg")
146145
compileFilesInDir("tests/neg", defaultOptions) +
147146
compileFilesInDir("tests/neg-tailcall", defaultOptions) +
148-
compileFilesInDir("tests/neg-kind-polymorphism", defaultOptions and "-Ykind-polymorphism") +
147+
compileFilesInDir("tests/neg-no-kind-polymorphism", defaultOptions and "-Yno-kind-polymorphism") +
149148
compileFilesInDir("tests/neg-custom-args/deprecation", defaultOptions.and("-Xfatal-warnings", "-deprecation")) +
150149
compileFilesInDir("tests/neg-custom-args/fatal-warnings", defaultOptions.and("-Xfatal-warnings")) +
151150
compileFilesInDir("tests/neg-custom-args/allow-double-bindings", allowDoubleBindings) +

docs/docs/reference/other-new-features/kind-polymorphism.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,5 @@ It is declared `abstract` and `final`, so it can be neither instantiated nor ext
4242

4343
`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).
4444

45-
**Note**: This feature is considered experimental and is only enabled under a compiler flag
46-
(i.e. `-Ykind-polymorphism`).
45+
**Note**: This feature is considered experimental but stable and it can be disabled under compiler flag
46+
(i.e. `-Yno-kind-polymorphism`).
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package scala.quoted
2+
3+
import scala.quoted.Types.TaggedType
4+
import scala.reflect.ClassTag
5+
import scala.runtime.quoted.Unpickler.Pickled
6+
7+
sealed abstract class Type[T <: AnyKind] {
8+
type `$splice` = T
9+
}
10+
11+
/** Some basic type tags, currently incomplete */
12+
object Type {
13+
/** A term quote is desugared by the compiler into a call to this method */
14+
def apply[T <: AnyKind]: Type[T] =
15+
throw new Error("Internal error: this method call should have been replaced by the compiler")
16+
17+
implicit def UnitTag: Type[Unit] = new TaggedType[Unit]
18+
implicit def BooleanTag: Type[Boolean] = new TaggedType[Boolean]
19+
implicit def ByteTag: Type[Byte] = new TaggedType[Byte]
20+
implicit def CharTag: Type[Char] = new TaggedType[Char]
21+
implicit def ShortTag: Type[Short] = new TaggedType[Short]
22+
implicit def IntTag: Type[Int] = new TaggedType[Int]
23+
implicit def LongTag: Type[Long] = new TaggedType[Long]
24+
implicit def FloatTag: Type[Float] = new TaggedType[Float]
25+
implicit def DoubleTag: Type[Double] = new TaggedType[Double]
26+
}
27+
28+
/** All implementations of Type[T].
29+
* These should never be used directly.
30+
*/
31+
object Types {
32+
/** A Type backed by a pickled TASTY tree */
33+
final class TastyType[T](val tasty: Pickled, val args: Seq[Any]) extends Type[T] {
34+
override def toString(): String = s"Type(<pickled tasty>)"
35+
}
36+
37+
/** An Type backed by a value */
38+
final class TaggedType[T](implicit val ct: ClassTag[T]) extends Type[T] {
39+
override def toString: String = s"Type($ct)"
40+
}
41+
42+
/** An Type backed by a tree */
43+
final class TreeType[Tree](val typeTree: Tree) extends quoted.Type[Any] {
44+
override def toString: String = s"Type(<tasty tree>)"
45+
}
46+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package scala.tasty.reflect
2+
3+
/** Extension methods on scala.quoted.{Expr|Type} to convert to scala.tasty.Tasty objects */
4+
trait QuotedOps extends Core {
5+
6+
implicit class QuotedExprAPI[T](expr: scala.quoted.Expr[T]) {
7+
/** View this expression `Expr[T]` as a `Term` */
8+
def unseal(implicit ctx: Context): Term =
9+
kernel.QuotedExpr_unseal(expr)
10+
}
11+
12+
implicit class QuotedTypeAPI[T <: AnyKind](tpe: scala.quoted.Type[T]) {
13+
/** View this expression `Type[T]` as a `TypeTree` */
14+
def unseal(implicit ctx: Context): TypeTree =
15+
kernel.QuotedType_unseal(tpe)
16+
}
17+
18+
implicit class TermToQuotedAPI(term: Term) {
19+
/** Convert `Term` to an `Expr[T]` and check that it conforms to `T` */
20+
def seal[T](implicit tpe: scala.quoted.Type[T], ctx: Context): scala.quoted.Expr[T] =
21+
kernel.QuotedExpr_seal(term)(tpe)
22+
}
23+
24+
implicit class TypeToQuotedAPI(tpe: Type) {
25+
/** Convert `Type` to an `quoted.Type[T]` */
26+
def seal(implicit ctx: Context): scala.quoted.Type[_] =
27+
kernel.QuotedType_seal(tpe)
28+
}
29+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
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.

tests/run-with-compiler/i5965.check

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
val y: collection.immutable.List[scala.Int] = scala.List.apply[scala.Int](1, 2, 3)
3+
4+
(y: collection.immutable.List[scala.Int])
5+
}
6+
List(1, 2, 3)
7+
{
8+
val y: scala.Option[scala.Int] = scala.Option.apply[scala.Int](4)
9+
10+
(y: scala.Option[scala.Int])
11+
}
12+
Some(4)
13+
{
14+
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))
15+
16+
(y: collection.immutable.Map[scala.Int, scala.Int])
17+
}
18+
Map(4 -> 1)

tests/run-with-compiler/i5965.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import scala.quoted._
2+
3+
import scala.tasty._
4+
5+
object Test {
6+
7+
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make
8+
9+
def main(args: Array[String]): Unit = {
10+
'[List]
11+
val list = bound('{List(1, 2, 3)})
12+
println(list.show)
13+
println(list.run)
14+
15+
val opt = bound('{Option(4)})
16+
println(opt.show)
17+
println(opt.run)
18+
19+
val map = bound('{Map(4 -> 1)})
20+
println(map.show)
21+
println(map.run)
22+
}
23+
24+
def bound[T: Type, S[_]: Type](x: Expr[S[T]]): Expr[S[T]] = '{
25+
val y: S[T] = $x
26+
y
27+
}
28+
}

tests/run-with-compiler/i5965b.check

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
val y: collection.immutable.List[scala.Int] = scala.List.apply[scala.Int](1, 2, 3)
3+
4+
(y: collection.immutable.List[scala.Int])
5+
}
6+
List(1, 2, 3)
7+
{
8+
val y: scala.Option[scala.Int] = scala.Option.apply[scala.Int](4)
9+
10+
(y: scala.Option[scala.Int])
11+
}
12+
Some(4)
13+
{
14+
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))
15+
16+
(y: collection.immutable.Map[scala.Int, scala.Int])
17+
}
18+
Map(4 -> 1)

tests/run-with-compiler/i5965b.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import scala.quoted._
2+
3+
import scala.tasty._
4+
5+
object Test {
6+
7+
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make
8+
9+
def main(args: Array[String]): Unit = {
10+
'[List]
11+
val list = bound('{List(1, 2, 3)})
12+
println(list.show)
13+
println(list.run)
14+
15+
val opt = bound('{Option(4)})
16+
println(opt.show)
17+
println(opt.run)
18+
19+
val map = bound('{Map(4 -> 1)})
20+
println(map.show)
21+
println(map.run)
22+
}
23+
24+
def bound[T: Type, S[_]: Type](x: Expr[S[T]]): Expr[S[T]] = '{
25+
val y = $x
26+
y
27+
}
28+
}

0 commit comments

Comments
 (0)