aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Martres <smarter@ubuntu.com>2016-11-04 00:48:36 +0100
committerGitHub <noreply@github.com>2016-11-04 00:48:36 +0100
commit6ba6ea542d7915a48b426fea1f75f9cb8c2db424 (patch)
treef728f6c54fe8c2e57ae136ef08d6fb20eaca534b
parent98a92c6f4ec743edb9465071dcfd43f17dbf054b (diff)
parentd694f15a028cf14ea0cf210d3113c7b1d6af54e7 (diff)
downloaddotty-6ba6ea542d7915a48b426fea1f75f9cb8c2db424.tar.gz
dotty-6ba6ea542d7915a48b426fea1f75f9cb8c2db424.tar.bz2
dotty-6ba6ea542d7915a48b426fea1f75f9cb8c2db424.zip
Merge pull request #1587 from dotty-staging/change-tasty-pos
Fix Tasty positions
-rw-r--r--.gitignore2
-rw-r--r--src/dotty/tools/dotc/ast/Positioned.scala6
-rw-r--r--src/dotty/tools/dotc/ast/TreeInfo.scala69
-rw-r--r--src/dotty/tools/dotc/ast/Trees.scala39
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala7
-rw-r--r--src/dotty/tools/dotc/ast/untpd.scala5
-rw-r--r--src/dotty/tools/dotc/core/tasty/PositionPickler.scala58
-rw-r--r--src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala11
-rw-r--r--src/dotty/tools/dotc/core/tasty/TastyFormat.scala22
-rw-r--r--src/dotty/tools/dotc/core/tasty/TastyPickler.scala6
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeBuffer.scala36
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreePickler.scala69
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala99
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala21
-rw-r--r--src/dotty/tools/dotc/transform/FirstTransform.scala28
-rw-r--r--src/dotty/tools/dotc/transform/Pickler.scala11
-rw-r--r--src/dotty/tools/dotc/transform/PostTyper.scala116
-rw-r--r--src/dotty/tools/dotc/transform/TailRec.scala2
-rw-r--r--src/dotty/tools/dotc/transform/TreeTransform.scala5
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala87
-rw-r--r--src/dotty/tools/dotc/typer/EtaExpansion.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Inliner.scala5
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala2
-rw-r--r--src/dotty/tools/dotc/typer/RefChecks.scala9
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala39
-rw-r--r--test/dotc/tests.scala2
26 files changed, 444 insertions, 314 deletions
diff --git a/.gitignore b/.gitignore
index a34babd4f..7c5baf8f8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,3 +45,5 @@ build/
# Ignore build-file
.packages
+/.cache-main
+/.cache-tests
diff --git a/src/dotty/tools/dotc/ast/Positioned.scala b/src/dotty/tools/dotc/ast/Positioned.scala
index 8d364d439..bb6817603 100644
--- a/src/dotty/tools/dotc/ast/Positioned.scala
+++ b/src/dotty/tools/dotc/ast/Positioned.scala
@@ -24,7 +24,7 @@ abstract class Positioned extends DotClass with Product {
* positions in children.
*/
protected def setPos(pos: Position): Unit = {
- curPos = pos
+ setPosUnchecked(pos)
if (pos.exists) setChildPositions(pos.toSynthetic)
}
@@ -107,7 +107,7 @@ abstract class Positioned extends DotClass with Product {
/** The initial, synthetic position. This is usually the union of all positioned children's positions.
*/
- protected def initialPos: Position = {
+ def initialPos: Position = {
var n = productArity
var pos = NoPosition
while (n > 0) {
@@ -139,7 +139,7 @@ abstract class Positioned extends DotClass with Product {
(this.pos contains that.pos) && {
var n = productArity
var found = false
- while (n > 0 && !found) {
+ while (!found && n > 0) {
n -= 1
found = isParent(productElement(n))
}
diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala
index 7911840c6..8b2915174 100644
--- a/src/dotty/tools/dotc/ast/TreeInfo.scala
+++ b/src/dotty/tools/dotc/ast/TreeInfo.scala
@@ -6,6 +6,7 @@ import core._
import Flags._, Trees._, Types._, Contexts._
import Names._, StdNames._, NameOps._, Decorators._, Symbols._
import util.HashSet
+import typer.ConstFold
trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
import TreeInfo._
@@ -289,13 +290,14 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]
trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
import TreeInfo._
+ import tpd._
/** The purity level of this statement.
* @return pure if statement has no side effects
* idempotent if running the statement a second time has no side effects
* impure otherwise
*/
- private def statPurity(tree: tpd.Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
+ private def statPurity(tree: Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
case EmptyTree
| TypeDef(_, _)
| Import(_, _)
@@ -319,7 +321,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
* takes a different code path than all to follow; but they are idempotent
* because running the expression a second time gives the cached result.
*/
- private def exprPurity(tree: tpd.Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
+ private def exprPurity(tree: Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
case EmptyTree
| This(_)
| Super(_, _)
@@ -358,8 +360,8 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
private def minOf(l0: PurityLevel, ls: List[PurityLevel]) = (l0 /: ls)(_ min _)
- def isPureExpr(tree: tpd.Tree)(implicit ctx: Context) = exprPurity(tree) == Pure
- def isIdempotentExpr(tree: tpd.Tree)(implicit ctx: Context) = exprPurity(tree) >= Idempotent
+ def isPureExpr(tree: Tree)(implicit ctx: Context) = exprPurity(tree) == Pure
+ def isIdempotentExpr(tree: Tree)(implicit ctx: Context) = exprPurity(tree) >= Idempotent
/** The purity level of this reference.
* @return
@@ -369,17 +371,62 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
* @DarkDimius: need to make sure that lazy accessor methods have Lazy and Stable
* flags set.
*/
- private def refPurity(tree: tpd.Tree)(implicit ctx: Context): PurityLevel =
+ private def refPurity(tree: Tree)(implicit ctx: Context): PurityLevel =
if (!tree.tpe.widen.isParameterless) Pure
else if (!tree.symbol.isStable) Impure
else if (tree.symbol.is(Lazy)) Idempotent // TODO add Module flag, sinxce Module vals or not Lazy from the start.
else Pure
- def isPureRef(tree: tpd.Tree)(implicit ctx: Context) =
+ def isPureRef(tree: Tree)(implicit ctx: Context) =
refPurity(tree) == Pure
- def isIdempotentRef(tree: tpd.Tree)(implicit ctx: Context) =
+ def isIdempotentRef(tree: Tree)(implicit ctx: Context) =
refPurity(tree) >= Idempotent
+ /** If `tree` is a constant expression, its value as a Literal,
+ * or `tree` itself otherwise.
+ *
+ * Note: Demanding idempotency instead of purity in literalize is strictly speaking too loose.
+ * Example
+ *
+ * object O { final val x = 42; println("43") }
+ * O.x
+ *
+ * Strictly speaking we can't replace `O.x` with `42`. But this would make
+ * most expressions non-constant. Maybe we can change the spec to accept this
+ * kind of eliding behavior. Or else enforce true purity in the compiler.
+ * The choice will be affected by what we will do with `inline` and with
+ * Singleton type bounds (see SIP 23). Presumably
+ *
+ * object O1 { val x: Singleton = 42; println("43") }
+ * object O2 { inline val x = 42; println("43") }
+ *
+ * should behave differently.
+ *
+ * O1.x should have the same effect as { println("43"); 42 }
+ *
+ * whereas
+ *
+ * O2.x = 42
+ *
+ * Revisit this issue once we have implemented `inline`. Then we can demand
+ * purity of the prefix unless the selection goes to an inline val.
+ *
+ * Note: This method should be applied to all term tree nodes that are not literals,
+ * that can be idempotent, and that can have constant types. So far, only nodes
+ * of the following classes qualify:
+ *
+ * Ident
+ * Select
+ * TypeApply
+ */
+ def constToLiteral(tree: Tree)(implicit ctx: Context): Tree = {
+ val tree1 = ConstFold(tree)
+ tree1.tpe.widenTermRefExpr match {
+ case ConstantType(value) if isIdempotentExpr(tree1) => Literal(value)
+ case _ => tree1
+ }
+ }
+
/** Is symbol potentially a getter of a mutable variable?
*/
def mayBeVarGetter(sym: Symbol)(implicit ctx: Context): Boolean = {
@@ -394,7 +441,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
/** Is tree a reference to a mutable variable, or to a potential getter
* that has a setter in the same class?
*/
- def isVariableOrGetter(tree: tpd.Tree)(implicit ctx: Context) = {
+ def isVariableOrGetter(tree: Tree)(implicit ctx: Context) = {
def sym = tree.symbol
def isVar = sym is Mutable
def isGetter =
@@ -419,8 +466,8 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
}
/** Strips layers of `.asInstanceOf[T]` / `_.$asInstanceOf[T]()` from an expression */
- def stripCast(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = {
- def isCast(sel: tpd.Tree) = sel.symbol == defn.Any_asInstanceOf
+ def stripCast(tree: Tree)(implicit ctx: Context): Tree = {
+ def isCast(sel: Tree) = sel.symbol == defn.Any_asInstanceOf
unsplice(tree) match {
case TypeApply(sel @ Select(inner, _), _) if isCast(sel) =>
stripCast(inner)
@@ -456,7 +503,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
}
/** If tree is a closure, its body, otherwise tree itself */
- def closureBody(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
+ def closureBody(tree: Tree)(implicit ctx: Context): Tree = tree match {
case Block((meth @ DefDef(nme.ANON_FUN, _, _, _, _)) :: Nil, Closure(_, _, _)) => meth.rhs
case _ => tree
}
diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala
index 2c02e7d1e..9108a4d22 100644
--- a/src/dotty/tools/dotc/ast/Trees.scala
+++ b/src/dotty/tools/dotc/ast/Trees.scala
@@ -60,15 +60,19 @@ object Trees {
with Cloneable {
if (Stats.enabled) ntrees += 1
+
+ private def nxId = {
+ nextId += 1
+ //assert(nextId != 199, this)
+ nextId
+ }
/** A unique identifier for this tree. Used for debugging, and potentially
* tracking presentation compiler interactions
*/
- val uniqueId = {
- nextId += 1
- //assert(nextId != 214, this)
- nextId
- }
+ private var myUniqueId: Int = nxId
+
+ def uniqueId = myUniqueId
/** The type constructor at the root of the tree */
type ThisTree[T >: Untyped] <: Tree[T]
@@ -188,6 +192,12 @@ object Trees {
override def hashCode(): Int = uniqueId // for debugging; was: System.identityHashCode(this)
override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]
+
+ override def clone: Tree[T] = {
+ val tree = super.clone.asInstanceOf[Tree[T]]
+ tree.myUniqueId = nxId
+ tree
+ }
}
class UnAssignedTypeException[T >: Untyped](tree: Tree[T]) extends RuntimeException {
@@ -502,7 +512,9 @@ object Trees {
/** A tree representing inlined code.
*
- * @param call The original call that was inlined
+ * @param call Info about the original call that was inlined
+ * Until PostTyper, this is the full call, afterwards only
+ * a reference to the toplevel class from which the call was inlined.
* @param bindings Bindings for proxies to be used in the inlined code
* @param expansion The inlined tree, minus bindings.
*
@@ -520,13 +532,12 @@ object Trees {
}
/** A type tree that represents an existing or inferred type */
- case class TypeTree[-T >: Untyped] private[ast] (original: Tree[T])
+ case class TypeTree[-T >: Untyped] ()
extends DenotingTree[T] with TypTree[T] {
type ThisTree[-T >: Untyped] = TypeTree[T]
- override def initialPos = NoPosition
- override def isEmpty = !hasType && original.isEmpty
+ override def isEmpty = !hasType
override def toString =
- s"TypeTree${if (hasType) s"[$typeOpt]" else s"($original)"}"
+ s"TypeTree${if (hasType) s"[$typeOpt]" else ""}"
}
/** ref.type */
@@ -960,10 +971,6 @@ object Trees {
case tree: Inlined if (call eq tree.call) && (bindings eq tree.bindings) && (expansion eq tree.expansion) => tree
case _ => finalize(tree, untpd.Inlined(call, bindings, expansion))
}
- def TypeTree(tree: Tree)(original: Tree): TypeTree = tree match {
- case tree: TypeTree if original eq tree.original => tree
- case _ => finalize(tree, untpd.TypeTree(original))
- }
def SingletonTypeTree(tree: Tree)(ref: Tree): SingletonTypeTree = tree match {
case tree: SingletonTypeTree if ref eq tree.ref => tree
case _ => finalize(tree, untpd.SingletonTypeTree(ref))
@@ -1106,7 +1113,7 @@ object Trees {
cpy.SeqLiteral(tree)(transform(elems), transform(elemtpt))
case Inlined(call, bindings, expansion) =>
cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion))
- case TypeTree(original) =>
+ case TypeTree() =>
tree
case SingletonTypeTree(ref) =>
cpy.SingletonTypeTree(tree)(transform(ref))
@@ -1210,7 +1217,7 @@ object Trees {
this(this(x, elems), elemtpt)
case Inlined(call, bindings, expansion) =>
this(this(x, bindings), expansion)
- case TypeTree(original) =>
+ case TypeTree() =>
x
case SingletonTypeTree(ref) =>
this(x, ref)
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index d8db3306c..273fc8d0a 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -121,11 +121,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def Inlined(call: Tree, bindings: List[MemberDef], expansion: Tree)(implicit ctx: Context): Inlined =
ta.assignType(untpd.Inlined(call, bindings, expansion), bindings, expansion)
- def TypeTree(original: Tree)(implicit ctx: Context): TypeTree =
- TypeTree(original.tpe, original)
-
- def TypeTree(tp: Type, original: Tree = EmptyTree)(implicit ctx: Context): TypeTree =
- untpd.TypeTree(original).withType(tp)
+ def TypeTree(tp: Type)(implicit ctx: Context): TypeTree =
+ untpd.TypeTree().withType(tp)
def SingletonTypeTree(ref: Tree)(implicit ctx: Context): SingletonTypeTree =
ta.assignType(untpd.SingletonTypeTree(ref), ref)
diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala
index 6513dfdc3..ac3beaff4 100644
--- a/src/dotty/tools/dotc/ast/untpd.scala
+++ b/src/dotty/tools/dotc/ast/untpd.scala
@@ -186,7 +186,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
/** A type tree that gets its type from some other tree's symbol. Enters the
* type tree in the References attachment of the `from` tree as a side effect.
*/
- abstract class DerivedTypeTree extends TypeTree(EmptyTree) {
+ abstract class DerivedTypeTree extends TypeTree {
private var myWatched: Tree = EmptyTree
@@ -247,8 +247,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def SeqLiteral(elems: List[Tree], elemtpt: Tree): SeqLiteral = new SeqLiteral(elems, elemtpt)
def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree): JavaSeqLiteral = new JavaSeqLiteral(elems, elemtpt)
def Inlined(call: tpd.Tree, bindings: List[MemberDef], expansion: Tree): Inlined = new Inlined(call, bindings, expansion)
- def TypeTree(original: Tree): TypeTree = new TypeTree(original)
- def TypeTree() = new TypeTree(EmptyTree)
+ def TypeTree() = new TypeTree()
def SingletonTypeTree(ref: Tree): SingletonTypeTree = new SingletonTypeTree(ref)
def AndTypeTree(left: Tree, right: Tree): AndTypeTree = new AndTypeTree(left, right)
def OrTypeTree(left: Tree, right: Tree): OrTypeTree = new OrTypeTree(left, right)
diff --git a/src/dotty/tools/dotc/core/tasty/PositionPickler.scala b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala
index 63bb00a71..4b67bc188 100644
--- a/src/dotty/tools/dotc/core/tasty/PositionPickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala
@@ -13,15 +13,32 @@ import collection.mutable
import TastyBuffer._
import util.Positions._
-class PositionPickler(pickler: TastyPickler, addrOfTree: tpd.Tree => Option[Addr]) {
+class PositionPickler(pickler: TastyPickler, addrsOfTree: tpd.Tree => List[Addr]) {
val buf = new TastyBuffer(5000)
pickler.newSection("Positions", buf)
import buf._
import ast.tpd._
- def header(addrDelta: Int, hasStartDelta: Boolean, hasEndDelta: Boolean) = {
+ private val remainingAddrs = new java.util.IdentityHashMap[Tree, Iterator[Addr]]
+
+ def nextTreeAddr(tree: Tree): Option[Addr] = remainingAddrs.get(tree) match {
+ case null =>
+ addrsOfTree(tree) match {
+ case Nil =>
+ None
+ case addr :: Nil =>
+ Some(addr)
+ case addrs =>
+ remainingAddrs.put(tree, addrs.iterator)
+ nextTreeAddr(tree)
+ }
+ case it: Iterator[_] =>
+ if (it.hasNext) Some(it.next) else None
+ }
+
+ def header(addrDelta: Int, hasStartDelta: Boolean, hasEndDelta: Boolean, hasPoint: Boolean) = {
def toInt(b: Boolean) = if (b) 1 else 0
- (addrDelta << 2) | (toInt(hasStartDelta) << 1) | toInt(hasEndDelta)
+ (addrDelta << 3) | (toInt(hasStartDelta) << 2) | (toInt(hasEndDelta) << 1) | toInt(hasPoint)
}
def picklePositions(roots: List[Tree])(implicit ctx: Context) = {
@@ -31,29 +48,46 @@ class PositionPickler(pickler: TastyPickler, addrOfTree: tpd.Tree => Option[Addr
val addrDelta = index - lastIndex
val startDelta = pos.start - lastPos.start
val endDelta = pos.end - lastPos.end
- buf.writeInt(header(addrDelta, startDelta != 0, endDelta != 0))
+ buf.writeInt(header(addrDelta, startDelta != 0, endDelta != 0, !pos.isSynthetic))
if (startDelta != 0) buf.writeInt(startDelta)
if (endDelta != 0) buf.writeInt(endDelta)
+ if (!pos.isSynthetic) buf.writeInt(pos.pointDelta)
lastIndex = index
lastPos = pos
}
- def traverse(x: Any, parentPos: Position): Unit = x match {
+
+ /** True if x's position cannot be reconstructed automatically from its initialPos
+ */
+ def alwaysNeedsPos(x: Positioned) = x match {
+ case _: WithLazyField[_] // initialPos is inaccurate for trees with lazy field
+ | _: Trees.PackageDef[_] => true // package defs might be split into several Tasty files
+ case x: Trees.Tree[_] => x.isType // types are unpickled as TypeTrees, so child positions are not available
+ case _ => false
+ }
+
+ def traverse(x: Any): Unit = x match {
case x: Tree @unchecked =>
- if (x.pos.exists && x.pos.toSynthetic != parentPos.toSynthetic) {
- addrOfTree(x) match {
- case Some(addr) => pickleDeltas(addr.index, x.pos)
+ val pos = if (x.isInstanceOf[MemberDef]) x.pos else x.pos.toSynthetic
+ if (pos.exists && (pos != x.initialPos.toSynthetic || alwaysNeedsPos(x))) {
+ nextTreeAddr(x) match {
+ case Some(addr) =>
+ //println(i"pickling $x with $pos at $addr")
+ pickleDeltas(addr.index, pos)
case _ =>
+ //println(i"no address for $x")
}
}
+ //else if (x.pos.exists) println(i"skipping $x")
x match {
- case x: MemberDef @unchecked => traverse(x.symbol.annotations, x.pos)
+ case x: MemberDef @unchecked =>
+ for (ann <- x.symbol.annotations) traverse(ann.tree)
case _ =>
}
- traverse(x.productIterator, x.pos)
+ traverse(x.productIterator)
case xs: TraversableOnce[_] =>
- xs.foreach(traverse(_, parentPos))
+ xs.foreach(traverse)
case _ =>
}
- traverse(roots, NoPosition)
+ traverse(roots)
}
}
diff --git a/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala b/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala
index c29aeba70..cbe213d89 100644
--- a/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala
@@ -19,14 +19,17 @@ class PositionUnpickler(reader: TastyReader) {
var curEnd = 0
while (!isAtEnd) {
val header = readInt()
- val addrDelta = header >> 2
- val hasStart = (header & 2) != 0
- val hasEnd = (header & 1) != 0
+ val addrDelta = header >> 3
+ val hasStart = (header & 4) != 0
+ val hasEnd = (header & 2) != 0
+ val hasPoint = (header & 1) != 0
curIndex += addrDelta
assert(curIndex >= 0)
if (hasStart) curStart += readInt()
if (hasEnd) curEnd += readInt()
- positions(Addr(curIndex)) = Position(curStart, curEnd)
+ positions(Addr(curIndex)) =
+ if (hasPoint) Position(curStart, curEnd, curStart + readInt())
+ else Position(curStart, curEnd)
}
positions
}
diff --git a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
index 8e8d58b47..f9743d9d2 100644
--- a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
+++ b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
@@ -57,7 +57,8 @@ Standard-Section: "ASTs" TopLevelStat*
TYPEDEF Length NameRef (Type | Template) Modifier*
IMPORT Length qual_Term Selector*
Selector = IMPORTED name_NameRef
- RENAMED Length from_NameRef to_NameRef
+ RENAMED to_NameRef
+
// Imports are for scala.meta, they are not used in the backend
TypeParam = TYPEPARAM Length NameRef Type Modifier*
@@ -78,6 +79,7 @@ Standard-Section: "ASTs" TopLevelStat*
NAMEDARG Length paramName_NameRef arg_Term
ASSIGN Length lhs_Term rhs_Term
BLOCK Length expr_Term Stat*
+ INLINED Length call_Term expr_Term Stat*
LAMBDA Length meth_Term target_Type
IF Length cond_Term then_Term else_Term
MATCH Length sel_Term CaseDef*
@@ -137,12 +139,11 @@ Standard-Section: "ASTs" TopLevelStat*
BIND Length boundName_NameRef bounds_Type
// for type-variables defined in a type pattern
BYNAMEtype underlying_Type
- LAMBDAtype Length result_Type NamesTypes // variance encoded in front of name: +/-/=
- POLYtype Length result_Type NamesTypes // needed for refinements
+ POLYtype Length result_Type NamesTypes // variance encoded in front of name: +/-/=
METHODtype Length result_Type NamesTypes // needed for refinements
PARAMtype Length binder_ASTref paramNum_Nat // needed for refinements
SHARED type_ASTRef
- NamesTypes = ParamType*
+ NamesTypes = NameType*
NameType = paramName_NameRef typeOrBounds_ASTRef
Modifier = PRIVATE
@@ -264,6 +265,7 @@ object TastyFormat {
final val DOUBLEconst = 76
final val STRINGconst = 77
final val IMPORTED = 78
+ final val RENAMED = 79
final val THIS = 96
final val CLASSconst = 97
@@ -291,11 +293,10 @@ object TastyFormat {
final val TYPEPARAM = 133
final val PARAMS = 134
final val PARAM = 136
- final val RENAMED = 138
+
final val APPLY = 139
final val TYPEAPPLY = 140
-
final val TYPED = 143
final val NAMEDARG = 144
final val ASSIGN = 145
@@ -305,6 +306,7 @@ object TastyFormat {
final val MATCH = 149
final val RETURN = 150
final val TRY = 151
+ final val INLINED = 152
final val REPEATED = 153
final val BIND = 154
final val ALTERNATIVE = 155
@@ -322,9 +324,8 @@ object TastyFormat {
final val ORtype = 172
final val METHODtype = 174
final val POLYtype = 175
- final val LAMBDAtype = 176
- final val PARAMtype = 177
- final val ANNOTATION = 178
+ final val PARAMtype = 176
+ final val ANNOTATION = 177
final val firstSimpleTreeTag = UNITconst
final val firstNatTreeTag = SHARED
@@ -455,6 +456,7 @@ object TastyFormat {
case LAMBDA => "LAMBDA"
case MATCH => "MATCH"
case RETURN => "RETURN"
+ case INLINED => "INLINED"
case TRY => "TRY"
case REPEATED => "REPEATED"
case BIND => "BIND"
@@ -485,7 +487,7 @@ object TastyFormat {
case PROTECTEDqualified => "PROTECTEDqualified"
}
- /** @return If non-negative, the number of leading references of a length/trees entry.
+ /** @return If non-negative, the number of leading references (represented as nats) of a length/trees entry.
* If negative, minus the number of leading non-reference trees.
*/
def numRefs(tag: Int) = tag match {
diff --git a/src/dotty/tools/dotc/core/tasty/TastyPickler.scala b/src/dotty/tools/dotc/core/tasty/TastyPickler.scala
index 98b0dc7c6..f847dda68 100644
--- a/src/dotty/tools/dotc/core/tasty/TastyPickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TastyPickler.scala
@@ -57,9 +57,11 @@ class TastyPickler {
/**
* Addresses in TASTY file of trees, stored by pickling.
* Note that trees are checked for reference equality,
- * so one can reliably use this function only directly after `pickler`
+ * so one can reliably use this function only directly after `pickler`.
+ * Note that a tree can have several addresses, if it is shared,
+ * i.e. accessible from different paths. Any such sharing is undone by pickling.
*/
- var addrOfTree: tpd.Tree => Option[Addr] = (_ => None)
+ var addrsOfTree: tpd.Tree => List[Addr] = (_ => Nil)
/**
* Addresses in TASTY file of symbols, stored by pickling.
diff --git a/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala b/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala
index d741c42c3..f2681ecde 100644
--- a/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreeBuffer.scala
@@ -6,7 +6,7 @@ package tasty
import util.Util.{bestFit, dble}
import TastyBuffer.{Addr, AddrWidth}
import config.Printers.pickling
-import ast.tpd.Tree
+import ast.untpd.Tree
class TreeBuffer extends TastyBuffer(50000) {
@@ -17,11 +17,26 @@ class TreeBuffer extends TastyBuffer(50000) {
private var delta: Array[Int] = _
private var numOffsets = 0
- private[tasty] val pickledTrees = new java.util.IdentityHashMap[Tree, Any] // Value type is really Addr, but that's not compatible with null
+ private type TreeAddrs = Any // really: Addr | List[Addr]
- def addrOfTree(tree: Tree): Option[Addr] = pickledTrees.get(tree) match {
- case null => None
- case n => Some(n.asInstanceOf[Addr])
+ /** A map from trees to the address(es) at which a tree is pickled. There may be several
+ * such addresses if the tree is shared. To keep the map compact, the value type is a
+ * disjunction of a single address (which is the common case) and a list of addresses.
+ */
+ private val treeAddrs = new java.util.IdentityHashMap[Tree, TreeAddrs]
+
+ def registerTreeAddr(tree: Tree) =
+ treeAddrs.put(tree,
+ treeAddrs.get(tree) match {
+ case null => currentAddr
+ case x: Addr => x :: currentAddr :: Nil
+ case xs: List[_] => xs :+ currentAddr
+ })
+
+ def addrsOfTree(tree: Tree): List[Addr] = treeAddrs.get(tree) match {
+ case null => Nil
+ case addr: Addr => addr :: Nil
+ case addrs: List[Addr] => addrs
}
private def offset(i: Int): Addr = Addr(offsets(i))
@@ -147,11 +162,14 @@ class TreeBuffer extends TastyBuffer(50000) {
wasted
}
- def adjustPickledTrees(): Unit = {
- val it = pickledTrees.keySet.iterator
+ def adjustTreeAddrs(): Unit = {
+ val it = treeAddrs.keySet.iterator
while (it.hasNext) {
val tree = it.next
- pickledTrees.put(tree, adjusted(pickledTrees.get(tree).asInstanceOf[Addr]))
+ treeAddrs.get(tree) match {
+ case addr: Addr => treeAddrs.put(tree, adjusted(addr))
+ case addrs: List[Addr] => treeAddrs.put(tree, addrs.map(adjusted))
+ }
}
}
@@ -172,7 +190,7 @@ class TreeBuffer extends TastyBuffer(50000) {
pickling.println(s"adjusting deltas, saved = $saved")
} while (saved > 0 && length / saved < 100)
adjustOffsets()
- adjustPickledTrees()
+ adjustTreeAddrs()
val wasted = compress()
pickling.println(s"original length: $origLength, compressed to: $length, wasted: $wasted") // DEBUG, for now.
}
diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index 8889e8a5c..9dfb78798 100644
--- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -4,6 +4,7 @@ package core
package tasty
import ast.Trees._
+import ast.untpd
import TastyFormat._
import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annotations._, StdNames.tpnme, NameOps._
import collection.mutable
@@ -48,6 +49,10 @@ class TreePickler(pickler: TastyPickler) {
case None =>
}
}
+
+ def rhs(tdef: TypeDef)(implicit ctx: Context) =
+ if (tdef.symbol.isClass) tdef.rhs
+ else TypeTree(tdef.symbol.info).withPos(tdef.rhs.pos)
private def pickleName(name: Name): Unit = writeNat(nameIndex(name).index)
private def pickleName(name: TastyName): Unit = writeNat(nameIndex(name).index)
@@ -152,6 +157,11 @@ class TreePickler(pickler: TastyPickler) {
throw ex
}
+ def pickleTypeWithPos(tpe: Type, tree: Tree)(implicit ctx: Context): Unit = {
+ registerTreeAddr(tree)
+ pickleType(tpe)
+ }
+
private def pickleNewType(tpe: Type, richTypes: Boolean)(implicit ctx: Context): Unit = try { tpe match {
case AppliedType(tycon, args) =>
writeByte(APPLIEDtype)
@@ -252,7 +262,7 @@ class TreePickler(pickler: TastyPickler) {
writeByte(BYNAMEtype)
pickleType(tpe.underlying)
case tpe: PolyType =>
- writeByte(LAMBDAtype)
+ writeByte(POLYtype)
val paramNames = tpe.typeParams.map(tparam =>
varianceToPrefix(tparam.paramVariance) +: tparam.paramName)
pickleMethodic(tpe.resultType, paramNames, tpe.paramBounds)
@@ -299,7 +309,8 @@ class TreePickler(pickler: TastyPickler) {
pickled
}
- def pickleTpt(tpt: Tree)(implicit ctx: Context): Unit = pickleType(tpt.tpe) // TODO correlate with original when generating positions
+ def pickleTpt(tpt: Tree)(implicit ctx: Context): Unit =
+ pickleTypeWithPos(tpt.tpe, tpt) // TODO correlate with original when generating positions
def pickleTreeUnlessEmpty(tree: Tree)(implicit ctx: Context): Unit =
if (!tree.isEmpty) pickleTree(tree)
@@ -312,18 +323,21 @@ class TreePickler(pickler: TastyPickler) {
pickleName(sym)
pickleParams
tpt match {
- case tpt: TypeTree => pickleTpt(tpt)
- case _ => pickleTree(tpt)
+ case templ: Template => pickleTree(tpt)
+ case _ if tpt.isType => pickleTpt(tpt)
}
pickleTreeUnlessEmpty(rhs)
pickleModifiers(sym)
}
}
- def pickleParam(tree: Tree)(implicit ctx: Context): Unit = tree match {
- case tree: ValDef => pickleDef(PARAM, tree.symbol, tree.tpt)
- case tree: DefDef => pickleDef(PARAM, tree.symbol, tree.tpt, tree.rhs)
- case tree: TypeDef => pickleDef(TYPEPARAM, tree.symbol, tree.rhs)
+ def pickleParam(tree: Tree)(implicit ctx: Context): Unit = {
+ registerTreeAddr(tree)
+ tree match {
+ case tree: ValDef => pickleDef(PARAM, tree.symbol, tree.tpt)
+ case tree: DefDef => pickleDef(PARAM, tree.symbol, tree.tpt, tree.rhs)
+ case tree: TypeDef => pickleDef(TYPEPARAM, tree.symbol, rhs(tree))
+ }
}
def pickleParams(trees: List[Tree])(implicit ctx: Context): Unit = {
@@ -337,8 +351,10 @@ class TreePickler(pickler: TastyPickler) {
}
def pickleTree(tree: Tree)(implicit ctx: Context): Unit = try {
- pickledTrees.put(tree, currentAddr)
+ registerTreeAddr(tree)
tree match {
+ case tree if tree.isType =>
+ pickleTpt(tree)
case Ident(name) =>
tree.tpe match {
case tp: TermRef => pickleType(tp)
@@ -428,17 +444,10 @@ class TreePickler(pickler: TastyPickler) {
case SeqLiteral(elems, elemtpt) =>
writeByte(REPEATED)
withLength { pickleTree(elemtpt); elems.foreach(pickleTree) }
- case tree: Inlined =>
- // Why drop Inlined info when pickling?
- // Since we never inline inside an inlined method, we know that
- // any code that continas an Inlined tree is not inlined itself.
- // So position information for inline expansion is no longer needed.
- // The only reason to keep the inline info around would be to have fine-grained
- // position information in the linker. We should come back to this
- // point once we know more what we would do with such information.
- pickleTree(Inliner.dropInlined(tree))
- case TypeTree(original) =>
- pickleTpt(tree)
+ case Inlined(call, bindings, expansion) =>
+ writeByte(INLINED)
+ bindings.foreach(preRegister)
+ withLength { pickleTree(call); pickleTree(expansion); bindings.foreach(pickleTree) }
case Bind(name, body) =>
registerDef(tree.symbol)
writeByte(BIND)
@@ -469,7 +478,7 @@ class TreePickler(pickler: TastyPickler) {
}
pickleDef(DEFDEF, tree.symbol, tree.tpt, tree.rhs, pickleAllParams)
case tree: TypeDef =>
- pickleDef(TYPEDEF, tree.symbol, tree.rhs)
+ pickleDef(TYPEDEF, tree.symbol, rhs(tree))
case tree: Template =>
registerDef(tree.symbol)
writeByte(TEMPLATE)
@@ -486,6 +495,7 @@ class TreePickler(pickler: TastyPickler) {
if ((selfInfo ne NoType) || !tree.self.isEmpty) {
writeByte(SELFDEF)
pickleName(tree.self.name)
+ if (!tree.self.isEmpty) registerTreeAddr(tree.self.tpt)
pickleType {
cinfo.selfInfo match {
case sym: Symbol => sym.info
@@ -500,12 +510,11 @@ class TreePickler(pickler: TastyPickler) {
withLength {
pickleTree(expr)
selectors foreach {
- case Thicket(Ident(from) :: Ident(to) :: Nil) =>
- writeByte(RENAMED)
- withLength { pickleName(from); pickleName(to) }
- case Ident(name) =>
- writeByte(IMPORTED)
- pickleName(name)
+ case Thicket((from @ Ident(_)) :: (to @ Ident(_)) :: Nil) =>
+ pickleSelector(IMPORTED, from)
+ pickleSelector(RENAMED, to)
+ case id @ Ident(_) =>
+ pickleSelector(IMPORTED, id)
}
}
case PackageDef(pid, stats) =>
@@ -518,6 +527,12 @@ class TreePickler(pickler: TastyPickler) {
throw ex
}
+ def pickleSelector(tag: Int, id: untpd.Ident)(implicit ctx: Context): Unit = {
+ registerTreeAddr(id)
+ writeByte(tag)
+ pickleName(id.name)
+ }
+
def qualifiedName(sym: Symbol)(implicit ctx: Context): TastyName =
if (sym.isRoot || sym.owner.isRoot) TastyName.Simple(sym.name.toTermName)
else TastyName.Qualified(nameIndex(qualifiedName(sym.owner)), nameIndex(sym.name))
diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
index f67159808..a0d788955 100644
--- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -266,7 +266,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
val sym = ctx.newSymbol(ctx.owner, readName().toTypeName, BindDefinedType, readType())
registerSym(start, sym)
TypeRef.withFixedSym(NoPrefix, sym.name, sym)
- case LAMBDAtype =>
+ case POLYtype =>
val (rawNames, paramReader) = readNamesSkipParams
val (variances, paramNames) = rawNames
.map(name => (prefixToVariance(name.head), name.tail.toTypeName)).unzip
@@ -275,13 +275,6 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
pt => readType())
goto(end)
result
- case POLYtype =>
- val (names, paramReader) = readNamesSkipParams
- val result = PolyType(names.map(_.toTypeName))(
- pt => registeringType(pt, paramReader.readParamTypes[TypeBounds](end)),
- pt => readType())
- goto(end)
- result
case METHODtype =>
val (names, paramReader) = readNamesSkipParams
val result = MethodType(names.map(_.toTermName), paramReader.readParamTypes[Type](end))(
@@ -383,12 +376,6 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
def readTypeRef(): Type =
typeAtAddr(readAddr())
- def readPath()(implicit ctx: Context): Type = {
- val tp = readType()
- assert(tp.isInstanceOf[SingletonType])
- tp
- }
-
def readTermRef()(implicit ctx: Context): TermRef =
readType().asInstanceOf[TermRef]
@@ -655,12 +642,18 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
def localCtx = localContext(sym)
+ def ValDef(tpt: Tree) =
+ ta.assignType(untpd.ValDef(sym.name.asTermName, tpt, readRhs(localCtx)), sym)
+
def DefDef(tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree) =
ta.assignType(
untpd.DefDef(
sym.name.asTermName, tparams, vparamss, tpt, readRhs(localCtx)),
sym)
+ def TypeDef(rhs: Tree) =
+ ta.assignType(untpd.TypeDef(sym.name.asTypeName, rhs), sym)
+
def ta = ctx.typeAssigner
val name = readName()
@@ -682,8 +675,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
}
DefDef(tparams, vparamss, tpt)
case VALDEF =>
- sym.info = readType()
- ValDef(sym.asTerm, readRhs(localCtx))
+ val tpt = readTpt()
+ sym.info = tpt.tpe
+ ValDef(tpt)
case TYPEDEF | TYPEPARAM =>
if (sym.isClass) {
val companion = sym.scalacLinkedClass
@@ -699,22 +693,23 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
if (sym is Flags.ModuleClass) sym.registerCompanionMethod(nme.COMPANION_CLASS_METHOD, companion)
else sym.registerCompanionMethod(nme.COMPANION_MODULE_METHOD, companion)
}
- ta.assignType(untpd.TypeDef(sym.name.asTypeName, readTemplate(localCtx)), sym)
+ TypeDef(readTemplate(localCtx))
} else {
- sym.info = readType()
- TypeDef(sym.asType)
+ val rhs = readTpt()
+ sym.info = rhs.tpe
+ TypeDef(rhs)
}
case PARAM =>
- val info = readType()
+ val tpt = readTpt()
if (noRhs(end)) {
- sym.info = info
- ValDef(sym.asTerm)
+ sym.info = tpt.tpe
+ ValDef(tpt)
}
else {
sym.setFlag(Method)
- sym.info = ExprType(info)
+ sym.info = ExprType(tpt.tpe)
pickling.println(i"reading param alias $name -> $currentAddr")
- DefDef(Nil, Nil, TypeTree(info))
+ DefDef(Nil, Nil, tpt)
}
}
val mods =
@@ -816,21 +811,28 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
}
def readImport()(implicit ctx: Context): Tree = {
+ val start = currentAddr
readByte()
readEnd()
val expr = readTerm()
def readSelectors(): List[untpd.Tree] = nextByte match {
- case RENAMED =>
- readByte()
- readEnd()
- untpd.Thicket(untpd.Ident(readName()), untpd.Ident(readName())) :: readSelectors()
case IMPORTED =>
+ val start = currentAddr
readByte()
- untpd.Ident(readName()) :: readSelectors()
- case _ =>
- Nil
+ val from = setPos(start, untpd.Ident(readName()))
+ nextByte match {
+ case RENAMED =>
+ val start2 = currentAddr
+ readByte()
+ val to = setPos(start2, untpd.Ident(readName()))
+ untpd.Thicket(from, to) :: readSelectors()
+ case _ =>
+ from :: readSelectors()
+ }
+ case _ =>
+ Nil
}
- Import(expr, readSelectors())
+ setPos(start, Import(expr, readSelectors()))
}
def readIndexedStats(exprOwner: Symbol, end: Addr)(implicit ctx: Context): List[Tree] =
@@ -853,7 +855,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
def readPathTerm(): Tree = {
goto(start)
- readPath() match {
+ readType() match {
case path: TermRef => ref(path)
case path: ThisType => This(path.cls)
case path: ConstantType => Literal(path.value)
@@ -889,6 +891,15 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
def readLengthTerm(): Tree = {
val end = readEnd()
+ def readBlock(mkTree: (List[Tree], Tree) => Tree): Tree = {
+ val exprReader = fork
+ skipTree()
+ val localCtx = ctx.fresh.setNewScope
+ val stats = readStats(ctx.owner, end)(localCtx)
+ val expr = exprReader.readTerm()(localCtx)
+ mkTree(stats, expr)
+ }
+
val result =
(tag: @switch) match {
case SUPER =>
@@ -921,12 +932,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
case ASSIGN =>
Assign(readTerm(), readTerm())
case BLOCK =>
- val exprReader = fork
- skipTree()
- val localCtx = ctx.fresh.setNewScope
- val stats = readStats(ctx.owner, end)(localCtx)
- val expr = exprReader.readTerm()(localCtx)
- Block(stats, expr)
+ readBlock(Block)
+ case INLINED =>
+ val call = setPos(currentAddr, TypeTree(readType()))
+ readBlock((defs, expr) => Inlined(call, defs.asInstanceOf[List[MemberDef]], expr))
case IF =>
If(readTerm(), readTerm(), readTerm())
case LAMBDA =>
@@ -1002,11 +1011,17 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
// ------ Setting positions ------------------------------------------------
/** Set position of `tree` at given `addr`. */
- def setPos[T <: Tree](addr: Addr, tree: T)(implicit ctx: Context): tree.type =
+ def setPos[T <: untpd.Tree](addr: Addr, tree: T)(implicit ctx: Context): tree.type =
if (ctx.mode.is(Mode.ReadPositions)) {
posUnpicklerOpt match {
- case Some(posUnpickler) => tree.withPos(posUnpickler.posAt(addr))
- case _ => tree
+ case Some(posUnpickler) =>
+ //println(i"setPos $tree / ${tree.getClass} at $addr to ${posUnpickler.posAt(addr)}")
+ val pos = posUnpickler.posAt(addr)
+ if (pos.exists) tree.setPosUnchecked(pos)
+ tree
+ case _ =>
+ //println(i"no pos $tree")
+ tree
}
}
else tree
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 6315cfabc..7aaf2e190 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -351,12 +351,12 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case SeqLiteral(elems, elemtpt) =>
"[" ~ toTextGlobal(elems, ",") ~ " : " ~ toText(elemtpt) ~ "]"
case tree @ Inlined(call, bindings, body) =>
- if (homogenizedView) toTextCore(Inliner.dropInlined(tree.asInstanceOf[tpd.Inlined]))
- else "/* inlined from " ~ toText(call) ~ "*/ " ~ blockText(bindings :+ body)
+ (("/* inlined from " ~ toText(call) ~ "*/ ") provided !homogenizedView) ~
+ blockText(bindings :+ body)
case tpt: untpd.DerivedTypeTree =>
"<derived typetree watching " ~ summarized(toText(tpt.watched)) ~ ">"
- case TypeTree(orig) =>
- if (tree.hasType) toText(tree.typeOpt) else toText(orig)
+ case TypeTree() =>
+ toText(tree.typeOpt)
case SingletonTypeTree(ref) =>
toTextLocal(ref) ~ ".type"
case AndTypeTree(l, r) =>
@@ -426,7 +426,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case _ => toTextGlobal(sel)
}
val selectorsText: Text = selectors match {
- case Ident(name) :: Nil => toText(name)
+ case id :: Nil => toText(id)
case _ => "{" ~ Text(selectors map selectorText, ", ") ~ "}"
}
"import " ~ toTextLocal(expr) ~ "." ~ selectorsText
@@ -525,8 +525,15 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
if (tree.isType) txt = toText(tp)
else if (!tree.isDef) txt = ("<" ~ txt ~ ":" ~ toText(tp) ~ ">").close
}
- if (ctx.settings.Yprintpos.value && !tree.isInstanceOf[WithoutTypeOrPos[_]])
- txt = txt ~ "@" ~ tree.pos.toString
+ else if (homogenizedView && tree.isType)
+ txt = toText(tree.typeOpt)
+ if (ctx.settings.Yprintpos.value && !tree.isInstanceOf[WithoutTypeOrPos[_]]) {
+ val pos =
+ if (homogenizedView && !tree.isInstanceOf[MemberDef]) tree.pos.toSynthetic
+ else tree.pos
+ val clsStr = "" // DEBUG: if (tree.isType) tree.getClass.toString else ""
+ txt = (txt ~ "@" ~ pos.toString ~ clsStr).close
+ }
tree match {
case Block(_, _) | Template(_, _, _, _) => txt
case _ => txt.close
diff --git a/src/dotty/tools/dotc/transform/FirstTransform.scala b/src/dotty/tools/dotc/transform/FirstTransform.scala
index 74dc9b9d6..597146514 100644
--- a/src/dotty/tools/dotc/transform/FirstTransform.scala
+++ b/src/dotty/tools/dotc/transform/FirstTransform.scala
@@ -28,7 +28,9 @@ import StdNames._
* - ensures there are companion objects for all classes except module classes
* - eliminates some kinds of trees: Imports, NamedArgs
* - stubs out native methods
- * - eliminate self tree in Template and self symbol in ClassInfo
+ * - eliminates self tree in Template and self symbol in ClassInfo
+ * - collapsess all type trees to trees of class TypeTree
+ * - converts idempotent expressions with constant types
*/
class FirstTransform extends MiniPhaseTransform with InfoTransformer with AnnotationTransformer { thisTransformer =>
import ast.tpd._
@@ -146,7 +148,7 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota
override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo): Tree = {
cpy.Template(impl)(self = EmptyValDef)
}
-
+
override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = {
if (ddef.symbol.hasAnnotation(defn.NativeAnnot)) {
ddef.symbol.resetFlag(Deferred)
@@ -162,9 +164,29 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota
override def transformOther(tree: Tree)(implicit ctx: Context, info: TransformerInfo) = tree match {
case tree: Import => EmptyTree
case tree: NamedArg => transform(tree.arg)
- case tree => tree
+ case tree => if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos) else tree
}
+ override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo) =
+ if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos)
+ else constToLiteral(tree)
+
+ override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) =
+ if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos)
+ else constToLiteral(tree)
+
+ override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo) =
+ constToLiteral(tree)
+
+ override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo) =
+ constToLiteral(tree)
+
+ override def transformTyped(tree: Typed)(implicit ctx: Context, info: TransformerInfo) =
+ constToLiteral(tree)
+
+ override def transformBlock(tree: Block)(implicit ctx: Context, info: TransformerInfo) =
+ constToLiteral(tree)
+
// invariants: all modules have companion objects
// all types are TypeTrees
// all this types are explicit
diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala
index 90e62b65c..fc70ac4f2 100644
--- a/src/dotty/tools/dotc/transform/Pickler.scala
+++ b/src/dotty/tools/dotc/transform/Pickler.scala
@@ -46,10 +46,10 @@ class Pickler extends Phase {
val treePkl = pickler.treePkl
treePkl.pickle(tree :: Nil)
treePkl.compactify()
- pickler.addrOfTree = treePkl.buf.addrOfTree
+ pickler.addrsOfTree = treePkl.buf.addrsOfTree
pickler.addrOfSym = treePkl.addrOfSym
if (tree.pos.exists)
- new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil)
+ new PositionPickler(pickler, treePkl.buf.addrsOfTree).picklePositions(tree :: Nil)
def rawBytes = // not needed right now, but useful to print raw format.
pickler.assembleParts().iterator.grouped(10).toList.zipWithIndex.map {
@@ -66,7 +66,10 @@ class Pickler extends Phase {
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
val result = super.runOn(units)
if (ctx.settings.YtestPickler.value)
- testUnpickler(units)(ctx.fresh.setPeriod(Period(ctx.runId + 1, FirstPhaseId)))
+ testUnpickler(units)(
+ ctx.fresh
+ .setPeriod(Period(ctx.runId + 1, FirstPhaseId))
+ .addMode(Mode.ReadPositions))
result
}
@@ -81,7 +84,7 @@ class Pickler extends Phase {
}
pickling.println("************* entered toplevel ***********")
for ((cls, unpickler) <- unpicklers) {
- val unpickled = unpickler.body(ctx.addMode(Mode.ReadPositions))
+ val unpickled = unpickler.body
testSame(i"$unpickled%\n%", beforePickling(cls), cls)
}
}
diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala
index 12d48d98e..7e51635e5 100644
--- a/src/dotty/tools/dotc/transform/PostTyper.scala
+++ b/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -41,6 +41,9 @@ import Symbols._, TypeUtils._
*
* (10) Adds Child annotations to all sealed classes
*
+ * (11) Minimizes `call` fields of `Inline` nodes to just point to the toplevel
+ * class from which code was inlined.
+ *
* The reason for making this a macro transform is that some functions (in particular
* super and protected accessors and instantiation checks) are naturally top-down and
* don't lend themselves to the bottom-up approach of a mini phase. The other two functions
@@ -73,48 +76,6 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
// TODO fill in
}
- /** Check bounds of AppliedTypeTrees and TypeApplys.
- * Replace type trees with TypeTree nodes.
- * Replace constant expressions with Literal nodes.
- * Note: Demanding idempotency instead of purity in literalize is strictly speaking too loose.
- * Example
- *
- * object O { final val x = 42; println("43") }
- * O.x
- *
- * Strictly speaking we can't replace `O.x` with `42`. But this would make
- * most expressions non-constant. Maybe we can change the spec to accept this
- * kind of eliding behavior. Or else enforce true purity in the compiler.
- * The choice will be affected by what we will do with `inline` and with
- * Singleton type bounds (see SIP 23). Presumably
- *
- * object O1 { val x: Singleton = 42; println("43") }
- * object O2 { inline val x = 42; println("43") }
- *
- * should behave differently.
- *
- * O1.x should have the same effect as { println("43"); 42 }
- *
- * whereas
- *
- * O2.x = 42
- *
- * Revisit this issue once we have implemented `inline`. Then we can demand
- * purity of the prefix unless the selection goes to an inline val.
- */
- private def normalizeTree(tree: Tree)(implicit ctx: Context): Tree = tree match {
- case _: TypeTree | _: TypeApply => tree
- case _ =>
- if (tree.isType) {
- Checking.typeChecker.traverse(tree)
- TypeTree(tree.tpe).withPos(tree.pos)
- }
- else tree.tpe.widenTermRefExpr match {
- case ConstantType(value) if isIdempotentExpr(tree) => Literal(value)
- case _ => tree
- }
- }
-
/** If the type of `tree` is a TermRefWithSignature with an underdefined
* signature, narrow the type by re-computing the signature (which should
* be fully-defined by now).
@@ -159,7 +120,11 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
case pkg: PackageClassDenotation if !tree.symbol.maybeOwner.is(Package) =>
transformSelect(cpy.Select(tree)(qual select pkg.packageObj.symbol, tree.name), targs)
case _ =>
- superAcc.transformSelect(super.transform(tree), targs)
+ val tree1 = super.transform(tree)
+ constToLiteral(tree1) match {
+ case _: Literal => tree1
+ case _ => superAcc.transformSelect(tree1, targs)
+ }
}
}
@@ -199,14 +164,19 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
}
override def transform(tree: Tree)(implicit ctx: Context): Tree =
- try normalizeTree(tree) match {
- case tree: Ident =>
+ try tree match {
+ case tree: Ident if !tree.isType =>
tree.tpe match {
case tpe: ThisType => This(tpe.cls).withPos(tree.pos)
case _ => paramFwd.adaptRef(fixSignature(tree))
}
- case tree: Select =>
- transformSelect(paramFwd.adaptRef(fixSignature(tree)), Nil)
+ case tree @ Select(qual, name) =>
+ if (name.isTypeName) {
+ Checking.checkRealizable(qual.tpe, qual.pos.focus)
+ super.transform(tree)
+ }
+ else
+ transformSelect(paramFwd.adaptRef(fixSignature(tree)), Nil)
case tree: Super =>
if (ctx.owner.enclosingMethod.isInlineMethod)
ctx.error(em"super not allowed in inline ${ctx.owner}", tree.pos)
@@ -224,6 +194,19 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
}
case tree @ Assign(sel: Select, _) =>
superAcc.transformAssign(super.transform(tree))
+ case Inlined(call, bindings, expansion) =>
+ // Leave only a call trace consisting of
+ // - a reference to the top-level class from which the call was inlined,
+ // - the call's position
+ // in the call field of an Inlined node.
+ // The trace has enough info to completely reconstruct positions.
+ // The minimization is done for two reasons:
+ // 1. To save space (calls might contain large inline arguments, which would otherwise
+ // be duplicated
+ // 2. To enable correct pickling (calls can share symbols with the inlined code, which
+ // would trigger an assertion when pickling).
+ val callTrace = Ident(call.symbol.topLevelClass.typeRef).withPos(call.pos)
+ cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion))
case tree: Template =>
val saved = parentNews
parentNews ++= tree.parents.flatMap(newPart)
@@ -240,26 +223,23 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
case tree: TypeDef =>
transformMemberDef(tree)
val sym = tree.symbol
- val tree1 =
- if (sym.isClass) {
- if (sym.owner.is(Package) &&
- ctx.compilationUnit.source.exists &&
- sym != defn.SourceFileAnnot)
- sym.addAnnotation(Annotation.makeSourceFile(ctx.compilationUnit.source.file.path))
+ if (sym.isClass) {
+ // Add SourceFile annotation to top-level classes
+ if (sym.owner.is(Package) &&
+ ctx.compilationUnit.source.exists &&
+ sym != defn.SourceFileAnnot)
+ sym.addAnnotation(Annotation.makeSourceFile(ctx.compilationUnit.source.file.path))
- if (!sym.isAnonymousClass) // ignore anonymous class
- for (parent <- sym.asClass.classInfo.classParents) {
- val pclazz = parent.classSymbol
- if (pclazz.is(Sealed)) pclazz.addAnnotation(Annotation.makeChild(sym))
- }
+ // Add Child annotation to sealed parents unless current class is anonymous
+ if (!sym.isAnonymousClass) // ignore anonymous class
+ for (parent <- sym.asClass.classInfo.classParents) {
+ val pclazz = parent.classSymbol
+ if (pclazz.is(Sealed)) pclazz.addAnnotation(Annotation.makeChild(sym))
+ }
- tree
- }
- else {
- Checking.typeChecker.traverse(tree.rhs)
- cpy.TypeDef(tree)(rhs = TypeTree(tree.symbol.info))
- }
- super.transform(tree1)
+ tree
+ }
+ super.transform(tree)
case tree: MemberDef =>
transformMemberDef(tree)
super.transform(tree)
@@ -268,6 +248,12 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
super.transform(tree)
case tree @ Annotated(annotated, annot) =>
cpy.Annotated(tree)(transform(annotated), transformAnnot(annot))
+ case tree: AppliedTypeTree =>
+ Checking.checkAppliedType(tree)
+ super.transform(tree)
+ case SingletonTypeTree(ref) =>
+ Checking.checkRealizable(ref.tpe, ref.pos.focus)
+ super.transform(tree)
case tree: TypeTree =>
tree.withType(
tree.tpe match {
diff --git a/src/dotty/tools/dotc/transform/TailRec.scala b/src/dotty/tools/dotc/transform/TailRec.scala
index fde4db811..dc4454439 100644
--- a/src/dotty/tools/dotc/transform/TailRec.scala
+++ b/src/dotty/tools/dotc/transform/TailRec.scala
@@ -354,7 +354,7 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
t // todo: could improve to handle DefDef's with a label flag calls to which are in tail position
case ValDef(_, _, _) | EmptyTree | Super(_, _) | This(_) |
- Literal(_) | TypeTree(_) | TypeDef(_, _) =>
+ Literal(_) | TypeTree() | TypeDef(_, _) =>
tree
case Return(expr, from) =>
diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala
index 45fa3d607..a1ccf0e63 100644
--- a/src/dotty/tools/dotc/transform/TreeTransform.scala
+++ b/src/dotty/tools/dotc/transform/TreeTransform.scala
@@ -1122,10 +1122,7 @@ object TreeTransforms {
case tree: TypeTree =>
implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTypeTree, info.nx.nxPrepTypeTree, tree, cur)
if (mutatedInfo eq null) tree
- else {
- val original = transform(tree.original, mutatedInfo, cur)
- goTypeTree(cpy.TypeTree(tree)(original), mutatedInfo.nx.nxTransTypeTree(cur))
- }
+ else goTypeTree(tree, mutatedInfo.nx.nxTransTypeTree(cur))
case tree: Alternative =>
implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForAlternative, info.nx.nxPrepAlternative, tree, cur)
if (mutatedInfo eq null) tree
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 3ebae733f..dbfc89f6c 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -55,58 +55,45 @@ object Checking {
def checkBounds(args: List[tpd.Tree], poly: PolyType)(implicit ctx: Context): Unit =
checkBounds(args, poly.paramBounds, _.substParams(poly, _))
- /** If type is a higher-kinded application with wildcard arguments,
- * check that it or one of its supertypes can be reduced to a normal application.
- * Unreducible applications correspond to general existentials, and we
- * cannot handle those.
+ /** Check applied type trees for well-formedness. This means
+ * - all arguments are within their corresponding bounds
+ * - if type is a higher-kinded application with wildcard arguments,
+ * check that it or one of its supertypes can be reduced to a normal application.
+ * Unreducible applications correspond to general existentials, and we
+ * cannot handle those.
*/
- def checkWildcardHKApply(tp: Type, pos: Position)(implicit ctx: Context): Unit = tp match {
- case tp @ HKApply(tycon, args) if args.exists(_.isInstanceOf[TypeBounds]) =>
- tycon match {
- case tycon: PolyType =>
- ctx.errorOrMigrationWarning(
- ex"unreducible application of higher-kinded type $tycon to wildcard arguments",
- pos)
- case _ =>
- checkWildcardHKApply(tp.superType, pos)
- }
- case _ =>
- }
-
- /** Traverse type tree, performing the following checks:
- * 1. All arguments of applied type trees must conform to their bounds.
- * 2. Prefixes of type selections and singleton types must be realizable.
- */
- val typeChecker = new TreeTraverser {
- def traverse(tree: Tree)(implicit ctx: Context) = {
- tree match {
- case AppliedTypeTree(tycon, args) =>
- // If `args` is a list of named arguments, return corresponding type parameters,
- // otherwise return type parameters unchanged
- val tparams = tycon.tpe.typeParams
- def argNamed(tparam: TypeParamInfo) = args.find {
- case NamedArg(name, _) => name == tparam.paramName
- case _ => false
- }.getOrElse(TypeTree(tparam.paramRef))
- val orderedArgs = if (hasNamedArg(args)) tparams.map(argNamed) else args
- val bounds = tparams.map(_.paramBoundsAsSeenFrom(tycon.tpe))
- def instantiate(bound: Type, args: List[Type]) =
- bound.LambdaAbstract(tparams).appliedTo(args)
- checkBounds(orderedArgs, bounds, instantiate)
-
- def checkValidIfHKApply(implicit ctx: Context): Unit =
- checkWildcardHKApply(tycon.tpe.appliedTo(args.map(_.tpe)), tree.pos)
- checkValidIfHKApply(ctx.addMode(Mode.AllowLambdaWildcardApply))
- case Select(qual, name) if name.isTypeName =>
- checkRealizable(qual.tpe, qual.pos.focus)
- case SingletonTypeTree(ref) =>
- checkRealizable(ref.tpe, ref.pos.focus)
- case _ =>
- }
- traverseChildren(tree)
- }
+ def checkAppliedType(tree: AppliedTypeTree)(implicit ctx: Context) = {
+ val AppliedTypeTree(tycon, args) = tree
+ // If `args` is a list of named arguments, return corresponding type parameters,
+ // otherwise return type parameters unchanged
+ val tparams = tycon.tpe.typeParams
+ def argNamed(tparam: TypeParamInfo) = args.find {
+ case NamedArg(name, _) => name == tparam.paramName
+ case _ => false
+ }.getOrElse(TypeTree(tparam.paramRef))
+ val orderedArgs = if (hasNamedArg(args)) tparams.map(argNamed) else args
+ val bounds = tparams.map(_.paramBoundsAsSeenFrom(tycon.tpe))
+ def instantiate(bound: Type, args: List[Type]) =
+ bound.LambdaAbstract(tparams).appliedTo(args)
+ checkBounds(orderedArgs, bounds, instantiate)
+
+ def checkWildcardHKApply(tp: Type, pos: Position): Unit = tp match {
+ case tp @ HKApply(tycon, args) if args.exists(_.isInstanceOf[TypeBounds]) =>
+ tycon match {
+ case tycon: PolyType =>
+ ctx.errorOrMigrationWarning(
+ ex"unreducible application of higher-kinded type $tycon to wildcard arguments",
+ pos)
+ case _ =>
+ checkWildcardHKApply(tp.superType, pos)
+ }
+ case _ =>
+ }
+ def checkValidIfHKApply(implicit ctx: Context): Unit =
+ checkWildcardHKApply(tycon.tpe.appliedTo(args.map(_.tpe)), tree.pos)
+ checkValidIfHKApply(ctx.addMode(Mode.AllowLambdaWildcardApply))
}
-
+
/** Check that `tp` refers to a nonAbstract class
* and that the instance conforms to the self type of the created class.
*/
diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala
index 397b6d95b..c390ae808 100644
--- a/src/dotty/tools/dotc/typer/EtaExpansion.scala
+++ b/src/dotty/tools/dotc/typer/EtaExpansion.scala
@@ -138,7 +138,7 @@ object EtaExpansion {
if (mt.paramTypes.length == xarity) mt.paramTypes map (_ => TypeTree())
else mt.paramTypes map TypeTree
val params = (mt.paramNames, paramTypes).zipped.map((name, tpe) =>
- ValDef(name, TypeTree(tpe), EmptyTree).withFlags(Synthetic | Param).withPos(tree.pos))
+ ValDef(name, tpe, EmptyTree).withFlags(Synthetic | Param).withPos(tree.pos))
var ids: List[Tree] = mt.paramNames map (name => Ident(name).withPos(tree.pos))
if (mt.paramTypes.nonEmpty && mt.paramTypes.last.isRepeatedParam)
ids = ids.init :+ repeated(ids.last)
diff --git a/src/dotty/tools/dotc/typer/Inliner.scala b/src/dotty/tools/dotc/typer/Inliner.scala
index 55008c0c5..40c1ca350 100644
--- a/src/dotty/tools/dotc/typer/Inliner.scala
+++ b/src/dotty/tools/dotc/typer/Inliner.scala
@@ -244,8 +244,9 @@ object Inliner {
/** Replace `Inlined` node by a block that contains its bindings and expansion */
def dropInlined(inlined: tpd.Inlined)(implicit ctx: Context): Tree = {
val reposition = new TreeMap {
- override def transform(tree: Tree)(implicit ctx: Context): Tree =
- tree.withPos(inlined.call.pos)
+ override def transform(tree: Tree)(implicit ctx: Context): Tree = {
+ super.transform(tree).withPos(inlined.call.pos)
+ }
}
tpd.seq(inlined.bindings, reposition.transform(inlined.expansion))
}
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 00e92cbfb..9da0e2edc 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -927,7 +927,7 @@ class Namer { typer: Typer =>
val tptProto = mdef.tpt match {
case _: untpd.DerivedTypeTree =>
WildcardType
- case TypeTree(untpd.EmptyTree) =>
+ case TypeTree() =>
inferredType
case TypedSplice(tpt: TypeTree) if !isFullyDefined(tpt.tpe, ForceDegree.none) =>
val rhsType = typedAheadExpr(mdef.rhs, tpt.tpe).tpe
diff --git a/src/dotty/tools/dotc/typer/RefChecks.scala b/src/dotty/tools/dotc/typer/RefChecks.scala
index 834bb37a8..026015d1d 100644
--- a/src/dotty/tools/dotc/typer/RefChecks.scala
+++ b/src/dotty/tools/dotc/typer/RefChecks.scala
@@ -851,15 +851,6 @@ class RefChecks extends MiniPhase { thisTransformer =>
tree
}
- override def transformTypeTree(tree: TypeTree)(implicit ctx: Context, info: TransformerInfo) = {
- if (!tree.original.isEmpty)
- tree.tpe.foreachPart {
- case tp: NamedType => checkUndesiredProperties(tp.symbol, tree.pos)
- case _ =>
- }
- tree
- }
-
override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo) = {
checkUndesiredProperties(tree.symbol, tree.pos)
currentLevel.enterReference(tree.symbol, tree.pos)
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 56c04c063..c283f43cf 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -953,28 +953,23 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = track("typedTypeTree") {
- if (tree.original.isEmpty)
- tree match {
- case tree: untpd.DerivedTypeTree =>
- tree.ensureCompletions
- try
- TypeTree(tree.derivedType(tree.attachment(untpd.OriginalSymbol))) withPos tree.pos
- // btw, no need to remove the attachment. The typed
- // tree is different from the untyped one, so the
- // untyped tree is no longer accessed after all
- // accesses with typedTypeTree are done.
- catch {
- case ex: NoSuchElementException =>
- println(s"missing OriginalSymbol for ${ctx.owner.ownersIterator.toList}")
- throw ex
- }
- case _ =>
- assert(isFullyDefined(pt, ForceDegree.none))
- tree.withType(pt)
- }
- else {
- val original1 = typed(tree.original)
- cpy.TypeTree(tree)(original1).withType(original1.tpe)
+ tree match {
+ case tree: untpd.DerivedTypeTree =>
+ tree.ensureCompletions
+ try
+ TypeTree(tree.derivedType(tree.attachment(untpd.OriginalSymbol))) withPos tree.pos
+ // btw, no need to remove the attachment. The typed
+ // tree is different from the untyped one, so the
+ // untyped tree is no longer accessed after all
+ // accesses with typedTypeTree are done.
+ catch {
+ case ex: NoSuchElementException =>
+ println(s"missing OriginalSymbol for ${ctx.owner.ownersIterator.toList}")
+ throw ex
+ }
+ case _ =>
+ assert(isFullyDefined(pt, ForceDegree.none))
+ tree.withType(pt)
}
}
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index 94b74d786..01539aa5a 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -28,7 +28,7 @@ class tests extends CompilerTest {
else List("-Ycheck:tailrec,resolveSuper,mixin,restoreScopes,labelDef")
}
- val testPickling = List("-Xprint-types", "-Ytest-pickler", "-Ystop-after:pickler")
+ val testPickling = List("-Xprint-types", "-Ytest-pickler", "-Ystop-after:pickler", "-Yprintpos")
val twice = List("#runs", "2")
val staleSymbolError: List[String] = List()