diff options
Diffstat (limited to 'src/dotty/tools/dotc/ast')
-rw-r--r-- | src/dotty/tools/dotc/ast/Positioned.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeInfo.scala | 69 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/Trees.scala | 39 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/tpd.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/untpd.scala | 5 |
5 files changed, 88 insertions, 38 deletions
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) |