diff options
author | Martin Odersky <odersky@gmail.com> | 2013-12-11 11:56:31 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-12-11 11:56:31 +0100 |
commit | c4675594fd25779641c55ccfc0392f03b5ca8207 (patch) | |
tree | 4389a82fce894f7b7e7431668ab84078c20a8b79 /src | |
parent | 710e0f9615772c6b64f3e511e6def6d4f1c68b3f (diff) | |
download | dotty-c4675594fd25779641c55ccfc0392f03b5ca8207.tar.gz dotty-c4675594fd25779641c55ccfc0392f03b5ca8207.tar.bz2 dotty-c4675594fd25779641c55ccfc0392f03b5ca8207.zip |
Skipping TypedSplices in TreeInfo methods.
Before, TreeInfo would mis-predict whenever trees were inserted with TypedSplice. We should make sure the rest of the compiler also takes TypedSplices into account when matching on trees. It's a systemic risk. Not sure we can avoid it with a better design.
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeInfo.scala | 47 |
1 files changed, 28 insertions, 19 deletions
diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index c2877a814..a04b7b2da 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -9,7 +9,12 @@ import util.HashSet trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => - def isDeclarationOrTypeDef(tree: Tree): Boolean = tree match { + def unsplice[T >: Untyped](tree: Trees.Tree[T]): Trees.Tree[T] = tree.asInstanceOf[untpd.Tree] match { + case untpd.TypedSplice(tree1) => tree1.asInstanceOf[Trees.Tree[T]] + case _ => tree + } + + def isDeclarationOrTypeDef(tree: Tree): Boolean = unsplice(tree) match { case DefDef(_, _, _, _, _, EmptyTree) | ValDef(_, _, _, EmptyTree) | TypeDef(_, _, _) => true @@ -18,7 +23,7 @@ trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => /** Is tree legal as a member definition of an interface? */ - def isInterfaceMember(tree: Tree): Boolean = tree match { + def isInterfaceMember(tree: Tree): Boolean = unsplice(tree) match { case EmptyTree => true case Import(_, _) => true case TypeDef(_, _, _) => true @@ -27,8 +32,12 @@ trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => case _ => false } - def isOpAssign(tree: Tree) = tree match { - case Apply(Select(_, name), _ :: Nil) if name.isOpAssignmentName => true + def isOpAssign(tree: Tree) = unsplice(tree) match { + case Apply(fn, _ :: Nil) => + unsplice(fn) match { + case Select(_, name) if name.isOpAssignmentName => true + case _ => false + } case _ => false } @@ -77,13 +86,13 @@ trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => /** If this is an application, its function part, stripping all * Apply nodes (but leaving TypeApply nodes in). Otherwise the tree itself. */ - def stripApply(tree: Tree): Tree = tree match { + def stripApply(tree: Tree): Tree = unsplice(tree) match { case Apply(fn, _) => stripApply(fn) case _ => tree } /** The number of arguments in an application */ - def numArgs(tree: Tree): Int = tree match { + def numArgs(tree: Tree): Int = unsplice(tree) match { case Apply(fn, args) => numArgs(fn) + args.length case TypeApply(fn, args) => numArgs(fn) + args.length case AppliedTypeTree(fn, args) => numArgs(fn) + args.length @@ -106,7 +115,7 @@ trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => case _ => false } - def isSuperSelection(tree: untpd.Tree) = tree match { + def isSuperSelection(tree: untpd.Tree) = unsplice(tree) match { case Select(Super(_, _), _) => true case _ => false } @@ -119,7 +128,7 @@ trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => } /** Is tree a variable pattern? */ - def isVarPattern(pat: untpd.Tree): Boolean = pat match { + def isVarPattern(pat: untpd.Tree): Boolean = unsplice(pat) match { case x: BackquotedIdent => false case x: Ident => x.name.isVariableName case _ => false @@ -144,12 +153,12 @@ trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => def isEarlyDef(tree: Tree) = isEarlyValDef(tree) || isEarlyTypeDef(tree) - def isEarlyValDef(tree: Tree) = tree match { + def isEarlyValDef(tree: Tree) = unsplice(tree) match { case ValDef(mods, _, _, _) => mods is Scala2PreSuper case _ => false } - def isEarlyTypeDef(tree: Tree) = tree match { + def isEarlyTypeDef(tree: Tree) = unsplice(tree) match { case TypeDef(mods, _, _) => mods is Scala2PreSuper case _ => false } @@ -173,7 +182,7 @@ trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => def isLeftAssoc(operator: Name) = operator.nonEmpty && (operator.last != ':') /** can this type be a type pattern? */ - def mayBeTypePat(tree: untpd.Tree): Boolean = tree match { + def mayBeTypePat(tree: untpd.Tree): Boolean = unsplice(tree) match { case AndTypeTree(tpt1, tpt2) => mayBeTypePat(tpt1) || mayBeTypePat(tpt2) case OrTypeTree(tpt1, tpt2) => mayBeTypePat(tpt1) || mayBeTypePat(tpt2) case RefinedTypeTree(tpt, refinements) => mayBeTypePat(tpt) || refinements.exists(_.isInstanceOf[Bind]) @@ -185,7 +194,7 @@ trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => /** Is this argument node of the form <expr> : _* ? */ - def isWildcardStarArg(tree: untpd.Tree): Boolean = tree match { + def isWildcardStarArg(tree: untpd.Tree): Boolean = unsplice(tree) match { case Typed(_, Ident(tpnme.WILDCARD_STAR)) => true case _ => false } @@ -217,7 +226,7 @@ trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => /** Is this pattern node a synthetic catch-all case, added during PartialFuction synthesis before we know * whether the user provided cases are exhaustive. */ - def isSyntheticDefaultCase(cdef: CaseDef) = cdef match { + def isSyntheticDefaultCase(cdef: CaseDef) = unsplice(cdef) match { case CaseDef(Bind(nme.DEFAULT_CASE, _), EmptyTree, _) => true case _ => false } @@ -240,7 +249,7 @@ trait TreeInfo[T >: Untyped] { self: Trees.Instance[T] => def isGuardedCase(cdef: CaseDef) = cdef.guard ne EmptyTree /** The underlying pattern ignoring any bindings */ - def unbind(x: Tree): Tree = x match { + def unbind(x: Tree): Tree = unsplice(x) match { case Bind(_, y) => unbind(y) case y => y } @@ -251,7 +260,7 @@ trait TypedTreeInfo extends TreeInfo[Type] {self: Trees.Instance[Type] => /** Is tree a definition that has no side effects when * evaluated as part of a block after the first time? */ - def isIdempotentDef(tree: tpd.Tree)(implicit ctx: Context): Boolean = tree match { + def isIdempotentDef(tree: tpd.Tree)(implicit ctx: Context): Boolean = unsplice(tree) match { case EmptyTree | TypeDef(_, _, _) | Import(_, _) @@ -271,7 +280,7 @@ trait TypedTreeInfo extends TreeInfo[Type] {self: Trees.Instance[Type] => * takes a different code path than all to follow; but they are safe to inline * because the expression result from evaluating them is always the same. */ - def isIdempotentExpr(tree: tpd.Tree)(implicit ctx: Context): Boolean = tree match { + def isIdempotentExpr(tree: tpd.Tree)(implicit ctx: Context): Boolean = unsplice(tree) match { case EmptyTree | This(_) | Super(_, _) @@ -328,7 +337,7 @@ trait TypedTreeInfo extends TreeInfo[Type] {self: Trees.Instance[Type] => def isGetter = mayBeVarGetter(sym) && sym.owner.info.member(sym.name.asTermName.setterName).exists - tree match { + unsplice(tree) match { case Ident(_) => isVar case Select(_, _) => isVar || isGetter case Apply(_, _) => @@ -341,7 +350,7 @@ trait TypedTreeInfo extends TreeInfo[Type] {self: Trees.Instance[Type] => } /** Is tree a `this` node which belongs to `enclClass`? */ - def isSelf(tree: Tree, enclClass: Symbol)(implicit ctx: Context): Boolean = tree match { + def isSelf(tree: Tree, enclClass: Symbol)(implicit ctx: Context): Boolean = unsplice(tree) match { case This(_) => tree.symbol == enclClass case _ => false } @@ -349,7 +358,7 @@ 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) = defn.asInstanceOfMethods contains sel.symbol - tree match { + unsplice(tree) match { case TypeApply(sel @ Select(inner, _), _) if isCast(sel) => stripCast(inner) case Apply(TypeApply(sel @ Select(inner, _), _), Nil) if isCast(sel) => |