Skip to content

Commit 8484b2f

Browse files
committed
Fix #5965: Make scala.quoted.Type poly-kinded
1 parent b885862 commit 8484b2f

File tree

10 files changed

+137
-10
lines changed

10 files changed

+137
-10
lines changed

compiler/src/dotty/tools/dotc/tastyreflect/QuotedOpsImpl.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ trait QuotedOpsImpl extends scala.tasty.reflect.QuotedOps with CoreImpl {
1414
def unseal(implicit ctx: Context): Term = PickledQuotes.quotedExprToTree(x)
1515
}
1616

17-
def QuotedTypeDeco[T](x: scala.quoted.Type[T]): QuotedTypeAPI = new QuotedTypeAPI {
18-
def unseal(implicit ctx: Context): TypeTree = PickledQuotes.quotedTypeToTree(x)
19-
}
17+
protected def unsealType(tpe: quoted.Type[_])(implicit ctx: Context): TypeTree =
18+
PickledQuotes.quotedTypeToTree(tpe)
2019

2120
def TermToQuoteDeco(term: Term): TermToQuotedAPI = new TermToQuotedAPI {
2221

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,14 @@ class ReifyQuotes extends MacroTransform {
352352
transformSplice(spliceTree)
353353

354354
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))
355+
tree.tpe.stripTypeVar match {
356+
case tp: AppliedType =>
357+
val splicedType = tp.tycon.asInstanceOf[TypeRef].prefix.termSymbol
358+
AppliedTypeTree(transformSplice(ref(splicedType).select(tpnme.splice)), tp.args.map(TypeTree(_))).withSpan(tree.span)
359+
case tp: TypeRef =>
360+
val splicedType = tp.prefix.termSymbol
361+
transformSplice(ref(splicedType).select(tpnme.splice).withSpan(tree.span))
362+
}
357363

358364
case tree: RefTree if isCaptured(tree.symbol, level) =>
359365
val t = capturers(tree.symbol).apply(tree)

compiler/test/dotty/tools/vulpix/TestConfiguration.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ object TestConfiguration {
4747
val yCheckOptions = Array("-Ycheck:all")
4848

4949
val commonOptions = checkOptions ++ noCheckOptions ++ yCheckOptions
50-
val defaultOptions = TestFlags(basicClasspath, commonOptions)
50+
val defaultOptions = TestFlags(basicClasspath, commonOptions) and "-Ykind-polymorphism" // FIXME remove "-Ykind-polymorphism"
5151
val withCompilerOptions =
5252
defaultOptions.withClasspath(withCompilerClasspath).withRunClasspath(withCompilerClasspath)
5353
val allowDeepSubtypes = defaultOptions without "-Yno-deep-subtypes"

library/src/scala/quoted/Type.scala renamed to library/src-bootstrapped/scala/quoted/Type.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import scala.quoted.Types.TaggedType
44
import scala.reflect.ClassTag
55
import scala.runtime.quoted.Unpickler.Pickled
66

7-
sealed abstract class Type[T] {
7+
sealed abstract class Type[T <: AnyKind] {
88
type `$splice` = T
99
}
1010

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

1717
implicit def UnitTag: Type[Unit] = new TaggedType[Unit]
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
trait QuotedExprAPI {
7+
/** View this expression `Expr[T]` as a `Term` */
8+
def unseal(implicit ctx: Context): Term
9+
}
10+
implicit def QuotedExprDeco[T](expr: quoted.Expr[T]): QuotedExprAPI
11+
12+
trait QuotedTypeAPI {
13+
/** View this expression `Type[T]` as a `TypeTree` */
14+
def unseal(implicit ctx: Context): TypeTree
15+
}
16+
implicit def QuotedTypeDeco[T <: AnyKind](tpe: quoted.Type[T]): QuotedTypeAPI = new QuotedTypeAPI {
17+
override def unseal(implicit ctx: Context): TypeTree = unsealType(tpe)
18+
}
19+
20+
protected def unsealType(tpe: quoted.Type[_])(implicit ctx: Context): TypeTree
21+
22+
trait TermToQuotedAPI {
23+
/** Convert `Term` to an `Expr[T]` and check that it conforms to `T` */
24+
def seal[T: scala.quoted.Type](implicit ctx: Context): scala.quoted.Expr[T]
25+
}
26+
implicit def TermToQuoteDeco(term: Term): TermToQuotedAPI
27+
28+
trait TypeToQuotedAPI {
29+
/** Convert `Type` to an `quoted.Type[T]` */
30+
def seal(implicit ctx: Context): scala.quoted.Type[_]
31+
}
32+
implicit def TypeToQuoteDeco(tpe: Type): TypeToQuotedAPI
33+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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] {
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]: Type[T] =
15+
throw new Error("Internal error: this method call should have been replaced by the compiler")
16+
}
17+
18+
/** All implementations of Type[T].
19+
* These should never be used directly.
20+
*/
21+
object Types {
22+
/** A Type backed by a pickled TASTY tree */
23+
final class TastyType[T](val tasty: Pickled, val args: Seq[Any]) extends Type[T] {
24+
override def toString(): String = s"Type(<pickled tasty>)"
25+
}
26+
27+
/** An Type backed by a value */
28+
final class TaggedType[T](implicit val ct: ClassTag[T]) extends Type[T] {
29+
override def toString: String = s"Type($ct)"
30+
}
31+
32+
/** An Type backed by a tree */
33+
final class TreeType[Tree](val typeTree: Tree) extends quoted.Type[Any] {
34+
override def toString: String = s"Type(<tasty tree>)"
35+
}
36+
}

library/src/scala/tasty/reflect/QuotedOps.scala renamed to library/src-non-bootstrapped/scala/tasty/reflect/QuotedOps.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ trait QuotedOps extends Core {
1313
/** View this expression `Type[T]` as a `TypeTree` */
1414
def unseal(implicit ctx: Context): TypeTree
1515
}
16-
implicit def QuotedTypeDeco[T](tpe: quoted.Type[T]): QuotedTypeAPI
16+
implicit def QuotedTypeDeco[T](tpe: quoted.Type[T]): QuotedTypeAPI = new QuotedTypeAPI {
17+
override def unseal(implicit ctx: Context): TypeTree = unsealType(tpe)
18+
}
19+
20+
protected def unsealType(tpe: quoted.Type[_])(implicit ctx: Context): TypeTree
1721

1822
trait TermToQuotedAPI {
1923
/** Convert `Term` to an `Expr[T]` and check that it conforms to `T` */

project/Build.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1135,11 +1135,17 @@ object Build {
11351135
def asDottyCompiler(implicit mode: Mode): Project = project.withCommonSettings.
11361136
dependsOn(`dotty-interfaces`).
11371137
dependsOn(dottyLibrary).
1138-
settings(dottyCompilerSettings)
1138+
settings(dottyCompilerSettings).
1139+
bootstrappedSettings(
1140+
// To support kind polymorphism of scala.quote.Type
1141+
scalacOptions in Compile += "-Ykind-polymorphism"
1142+
)
11391143

11401144
def asDottyLibrary(implicit mode: Mode): Project = project.withCommonSettings.
11411145
settings(dottyLibrarySettings).
11421146
bootstrappedSettings(
1147+
// To support kind polymorphism of scala.quote.Type
1148+
scalacOptions in Compile += "-Ykind-polymorphism",
11431149
// Needed so that the library sources are visible when `dotty.tools.dotc.core.Definitions#init` is called.
11441150
scalacOptions in Compile ++= Seq("-sourcepath", (scalaSource in Compile).value.getAbsolutePath)
11451151
)

tests/run-with-compiler/i5965.check

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

0 commit comments

Comments
 (0)