Skip to content

Commit 9f6b985

Browse files
committed
Fix #5247: Support type blocks
Type block are represented with `Block` nodes where all statements are `TypeDef`s and the expression is a `TypeTree`.
1 parent d3a0ac8 commit 9f6b985

File tree

12 files changed

+86
-26
lines changed

12 files changed

+86
-26
lines changed

compiler/src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,8 +484,10 @@ object Trees {
484484

485485
/** { stats; expr } */
486486
case class Block[-T >: Untyped] private[ast] (stats: List[Tree[T]], expr: Tree[T])
487-
extends TermTree[T] {
487+
extends Tree[T] {
488488
type ThisTree[-T >: Untyped] = Block[T]
489+
override def isTerm: Boolean = expr.isTerm
490+
override def isType: Boolean = expr.isType
489491
}
490492

491493
/** if cond then thenp else elsep */

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ object Printers {
2828
val overload: Printer = noPrinter
2929
val patmatch: Printer = noPrinter
3030
val pickling: Printer = noPrinter
31+
val quotePickling: Printer = noPrinter
3132
val plugins: Printer = noPrinter
3233
val simplify: Printer = noPrinter
3334
val subtyping: Printer = noPrinter

compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,20 +89,20 @@ object PickledQuotes {
8989
if (tree.pos.exists)
9090
new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil)
9191

92-
if (pickling ne noPrinter)
92+
if (quotePickling ne noPrinter)
9393
println(i"**** pickling quote of \n${tree.show}")
9494

9595
val pickled = pickler.assembleParts()
9696

97-
if (pickling ne noPrinter)
97+
if (quotePickling ne noPrinter)
9898
new TastyPrinter(pickled).printContents()
9999

100100
pickled
101101
}
102102

103103
/** Unpickle TASTY bytes into it's tree */
104104
private def unpickle(bytes: Array[Byte], splices: Seq[Any], isType: Boolean)(implicit ctx: Context): Tree = {
105-
if (pickling ne noPrinter) {
105+
if (quotePickling ne noPrinter) {
106106
println(i"**** unpickling quote from TASTY")
107107
new TastyPrinter(bytes).printContents()
108108
}
@@ -112,7 +112,7 @@ object PickledQuotes {
112112
unpickler.enter(Set.empty)
113113
val tree = unpickler.tree
114114

115-
if (pickling ne noPrinter)
115+
if (quotePickling ne noPrinter)
116116
println(i"**** unpickle quote ${tree.show}")
117117

118118
tree

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,35 @@ package core
44
package tasty
55

66
import Comments.CommentsContext
7-
import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._
8-
import StdNames._, Flags._, Constants._, Annotations._
7+
import Contexts._
8+
import Symbols._
9+
import Types._
10+
import Scopes._
11+
import SymDenotations._
12+
import Names._
13+
import NameOps._
14+
import StdNames._
15+
import Flags._
16+
import Constants._
17+
import Annotations._
918
import NameKinds._
1019
import typer.Checking.checkNonCyclic
1120
import util.Positions._
12-
import ast.{tpd, untpd, Trees}
21+
import ast.{TreeTypeMap, Trees, tpd, untpd}
1322
import Trees._
1423
import Decorators._
1524
import transform.SymUtils._
1625
import TastyBuffer._
17-
import scala.annotation.{tailrec, switch}
26+
27+
import scala.annotation.{switch, tailrec}
1828
import scala.collection.mutable.ListBuffer
1929
import scala.collection.mutable
2030
import config.Printers.pickling
2131
import core.quoted.PickledQuotes
32+
2233
import scala.quoted
2334
import scala.quoted.Types.TreeType
2435
import scala.quoted.Exprs.TastyTreeExpr
25-
2636
import scala.annotation.internal.sharable
2737

2838
/** Unpickler for typed trees
@@ -353,8 +363,6 @@ class TreeUnpickler(reader: TastyReader,
353363
readTypeRef() match {
354364
case binder: LambdaType => binder.paramRefs(readNat())
355365
}
356-
case HOLE =>
357-
readHole(end, isType = true).tpe
358366
}
359367
assert(currentAddr == end, s"$start $currentAddr $end ${astTagToString(tag)}")
360368
result
@@ -1166,17 +1174,32 @@ class TreeUnpickler(reader: TastyReader,
11661174
setPos(start, tree)
11671175
}
11681176

1169-
def readTpt()(implicit ctx: Context): Tree =
1170-
if (nextByte == SHAREDterm) {
1171-
readByte()
1172-
forkAt(readAddr()).readTpt()
1173-
}
1174-
else if (isTypeTreeTag(nextByte)) readTerm()
1175-
else {
1176-
val start = currentAddr
1177-
val tp = readType()
1178-
if (tp.exists) setPos(start, TypeTree(tp)) else EmptyTree
1177+
def readTpt()(implicit ctx: Context): Tree = {
1178+
nextByte match {
1179+
case SHAREDterm =>
1180+
readByte()
1181+
forkAt(readAddr()).readTpt()
1182+
case BLOCK =>
1183+
readByte()
1184+
val end = readEnd()
1185+
val typeReader = fork
1186+
skipTree()
1187+
val aliases = readStats(ctx.owner, end)
1188+
val tpt = typeReader.readTpt()
1189+
Block(aliases, tpt)
1190+
case HOLE =>
1191+
readByte()
1192+
val end = readEnd()
1193+
readHole(end, isType = true)
1194+
case _ =>
1195+
if (isTypeTreeTag(nextByte)) readTerm()
1196+
else {
1197+
val start = currentAddr
1198+
val tp = readType()
1199+
if (tp.exists) setPos(start, TypeTree(tp)) else EmptyTree
1200+
}
11791201
}
1202+
}
11801203

11811204
def readCases(end: Addr)(implicit ctx: Context): List[CaseDef] =
11821205
collectWhile((nextUnsharedTag == CASEDEF) && currentAddr != end) {

compiler/src/dotty/tools/dotc/quoted/TreeCleaner.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ class TreeCleaner extends tpd.TreeMap {
3939
}
4040
expr1 match {
4141
case Block(stats3, expr3) => Block(flatStats ::: stats3, expr3)
42-
case expr3 => Block(flatStats, expr3)
42+
case expr3 =>
43+
if (flatStats.isEmpty) expr3
44+
else Block(flatStats, expr3)
4345
}
4446
case tree1: TypeTree => TypeTree(tree1.tpe.subst(aliasesSyms, aliasesTypes))
4547
case tree1: Ident => aliases.get(tree1.symbol).getOrElse(tree1)

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,13 @@ trait TypeOrBoundsTreesOpsImpl extends scala.tasty.reflect.TypeOrBoundsTreeOps w
120120
case _ => None
121121
}
122122
}
123+
124+
object Block extends BlockExtractor {
125+
def unapply(x: TypeTree)(implicit ctx: Context): Option[(List[TypeDef], TypeTree)] = x match {
126+
case x: tpd.Block => Some((x.stats.map { case alias: TypeDef => alias }, x.expr))
127+
case _ => None
128+
}
129+
}
123130
}
124131

125132
// ----- TypeBoundsTrees ------------------------------------------------

library/src/scala/tasty/reflect/TypeOrBoundsTreeOps.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ trait TypeOrBoundsTreeOps extends TastyCore {
9191
abstract class BindExtractor{
9292
def unapply(typeOrBoundsTree: TypeOrBoundsTree)(implicit ctx: Context): Option[(String, TypeBoundsTree)]
9393
}
94+
95+
val Block: BlockExtractor
96+
abstract class BlockExtractor{
97+
def unapply(typeOrBoundsTree: TypeOrBoundsTree)(implicit ctx: Context): Option[(List[TypeDef], TypeTree)]
98+
}
9499
}
95100

96101
// ----- TypeBoundsTrees ------------------------------------------------

library/src/scala/tasty/util/ShowExtractors.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,11 @@ class ShowExtractors[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
116116
case TypeTree.Annotated(arg, annot) =>
117117
this += "TypeTree.Annotated(" += arg += ", " += annot += ")"
118118
case TypeTree.TypeLambdaTree(tparams, body) =>
119-
this += "LambdaTypeTree(" ++= tparams += ", " += body += ")"
119+
this += "TypeTree.LambdaTypeTree(" ++= tparams += ", " += body += ")"
120120
case TypeTree.Bind(name, bounds) =>
121-
this += "Bind(" += name += ", " += bounds += ")"
121+
this += "TypeTree.Bind(" += name += ", " += bounds += ")"
122+
case TypeTree.Block(aliases, tpt) =>
123+
this += "TypeTree.Block(" ++= aliases += ", " += tpt += ")"
122124
case TypeBoundsTree(lo, hi) =>
123125
this += "TypeBoundsTree(" += lo += ", " += hi += ")"
124126
case SyntheticBounds() =>

library/src/scala/tasty/util/ShowSourceCode.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,12 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
816816
case TypeTree.Bind(name, _) =>
817817
this += highlightTypeDef(name, color)
818818

819+
case TypeTree.Block(aliases, tpt) =>
820+
inBlock {
821+
printTrees(aliases, lineBreak())
822+
printTypeTree(tpt)
823+
}
824+
819825
case _ =>
820826
throw new MatchError(tree.show)
821827

tests/run-with-compiler/i5247.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
null.asInstanceOf[lang.Object]

tests/run-with-compiler/i5247.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import scala.quoted._
2+
object Test {
3+
def main(args: Array[String]): Unit = {
4+
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make
5+
println(foo[Object].show)
6+
}
7+
def foo[H : Type]: Expr[H] = {
8+
val t = '[H]
9+
'{ null.asInstanceOf[~t] }
10+
}
11+
}

tests/run-with-compiler/quote-owners-2.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
{
33
def ff: scala.Int = {
44
val a: immutable.List[scala.Int] = {
5-
type T = immutable.List[scala.Int]
5+
type T = scala.List[scala.Int]
66
val b: T = scala.Nil.::[scala.Int](3)
77
(b: collection.immutable.List[scala.Int])
88
}

0 commit comments

Comments
 (0)