diff options
-rw-r--r-- | src/dotty/tools/dotc/ast/tpd.scala | 41 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/InterceptedMethods.scala | 6 |
2 files changed, 42 insertions, 5 deletions
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 9e799a8d3..0f4585a53 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -588,63 +588,97 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { tree } + /** A select node with the given selector name and a computed type */ def select(name: Name)(implicit ctx: Context): Select = Select(tree, name) + /** A select node with the given type */ def select(tp: NamedType)(implicit ctx: Context): Select = untpd.Select(tree, tp.name).withType(tp) + /** A select node that selects the given symbol. Note: Need to make sure this + * is in fact the symbol you would get when you select with the symbol's name, + * otherwise a data race may occur which would be flagged by -Yno-double-bindings. + */ def select(sym: Symbol)(implicit ctx: Context): Select = untpd.Select(tree, sym.name).withType( TermRef.withSigAndDenot(tree.tpe, sym.name.asTermName, sym.signature, sym.denot.asSeenFrom(tree.tpe))) - def selectWithSig(name: Name, sig: Signature)(implicit ctx: Context) = + /** A select node with the given selector name and signature and a computed type */ + def selectWithSig(name: Name, sig: Signature)(implicit ctx: Context): Tree = untpd.SelectWithSig(tree, name, sig) .withType(TermRef.withSig(tree.tpe, name.asTermName, sig)) + /** A select node with selector name and signature taken from `sym`. + * Note: Use this method instead of select(sym) if the referenced symbol + * might be overridden in the type of the qualifier prefix. See note + * on select(sym: Symbol). + */ + def selectWithSig(sym: Symbol)(implicit ctx: Context): Tree = + selectWithSig(sym.name, sym.signature) + + /** A unary apply node with given argument: `tree(arg)` */ def appliedTo(arg: Tree)(implicit ctx: Context): Tree = appliedToArgs(arg :: Nil) + /** An apply node with given arguments: `tree(arg, args0, ..., argsN)` */ def appliedTo(arg: Tree, args: Tree*)(implicit ctx: Context): Tree = appliedToArgs(arg :: args.toList) + /** An apply node with given argument list `tree(args(0), ..., args(args.length - 1))` */ def appliedToArgs(args: List[Tree])(implicit ctx: Context): Apply = Apply(tree, args) + /** The current tree applied to given argument lists: + * `tree (argss(0)) ... (argss(argss.length -1))` + */ def appliedToArgss(argss: List[List[Tree]])(implicit ctx: Context): Tree = ((tree: Tree) /: argss)(Apply(_, _)) + /** The current tree applied to (): `tree()` */ def appliedToNone(implicit ctx: Context): Apply = appliedToArgs(Nil) + /** The current tree applied to given type argument: `tree[targ]` */ def appliedToType(targ: Type)(implicit ctx: Context): Tree = appliedToTypes(targ :: Nil) + /** The current tree applied to given type arguments: `tree[targ0, ..., targN]` */ def appliedToTypes(targs: List[Type])(implicit ctx: Context): Tree = appliedToTypeTrees(targs map (TypeTree(_))) + /** The current tree applied to given type argument list: `tree[targs(0), ..., targs(targs.length - 1)]` */ def appliedToTypeTrees(targs: List[Tree])(implicit ctx: Context): Tree = if (targs.isEmpty) tree else TypeApply(tree, targs) + /** Apply to `()` unless tree's widened type is parameterless */ def ensureApplied(implicit ctx: Context): Tree = if (tree.tpe.widen.isParameterless) tree else tree.appliedToNone + /** `tree.isInstanceOf[tp]` */ def isInstance(tp: Type)(implicit ctx: Context): Tree = tree.select(defn.Any_isInstanceOf).appliedToType(tp) + /** tree.asInstanceOf[`tp`] */ def asInstance(tp: Type)(implicit ctx: Context): Tree = { assert(tp.isValueType, i"bad cast: $tree.asInstanceOf[$tp]") tree.select(defn.Any_asInstanceOf).appliedToType(tp) } + /** `tree.asInstanceOf[tp]` unless tree's type already conforms to `tp` */ def ensureConforms(tp: Type)(implicit ctx: Context): Tree = if (tree.tpe <:< tp) tree else asInstance(tp) + /** `this && that`, for boolean trees `this`, `that` */ def and(that: Tree)(implicit ctx: Context): Tree = tree.select(defn.Boolean_&&).appliedTo(that) + /** `this || that`, for boolean trees `this`, `that` */ def or(that: Tree)(implicit ctx: Context): Tree = tree.select(defn.Boolean_||).appliedTo(that) + /** The translation of `tree = rhs`. + * This is either the tree as an assignment, to a setter call. + */ def becomes(rhs: Tree)(implicit ctx: Context): Tree = if (tree.symbol is Method) { val setr = tree match { @@ -660,13 +694,15 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { // --- Higher order traversal methods ------------------------------- - def foreachSubTree(f: Tree => Unit)(implicit ctx: Context): Unit = { //TODO should go in tpd. + /** Apply `f` to each subtree of this tree */ + def foreachSubTree(f: Tree => Unit)(implicit ctx: Context): Unit = { val traverser = new TreeTraverser { def traverse(tree: Tree)(implicit ctx: Context) = foldOver(f(tree), tree) } traverser.traverse(tree) } + /** Is there a subtree of this tree that satisfies predicate `p`? */ def existsSubTree(p: Tree => Boolean)(implicit ctx: Context): Boolean = { val acc = new TreeAccumulator[Boolean] { def apply(x: Boolean, t: Tree)(implicit ctx: Context) = x || p(t) || foldOver(x, t) @@ -674,6 +710,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { acc(false, tree) } + /** All subtrees of this tree that satisfy predicate `p`. */ def filterSubTrees(f: Tree => Boolean)(implicit ctx: Context): List[Tree] = { val buf = new mutable.ListBuffer[Tree] foreachSubTree { tree => if (f(tree)) buf += tree } diff --git a/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/src/dotty/tools/dotc/transform/InterceptedMethods.scala index 87a5c1a4c..458527c46 100644 --- a/src/dotty/tools/dotc/transform/InterceptedMethods.scala +++ b/src/dotty/tools/dotc/transform/InterceptedMethods.scala @@ -111,9 +111,9 @@ class InterceptedMethods extends MiniPhaseTransform { thisTransform => poundPoundValue(qual) } else if (Any_comparisons contains tree.fun.symbol.asTerm) { if (tree.fun.symbol eq defn.Any_==) { - qual.select(defn.Any_equals).appliedToArgs(tree.args) + qual.selectWithSig(defn.Any_equals).appliedToArgs(tree.args) } else if (tree.fun.symbol eq defn.Any_!=) { - qual.select(defn.Any_equals).appliedToArgs(tree.args).select(defn.Boolean_!) + qual.selectWithSig(defn.Any_equals).appliedToArgs(tree.args).select(defn.Boolean_!) } else unknown } /* else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) { // todo: this is needed to support value classes @@ -130,7 +130,7 @@ class InterceptedMethods extends MiniPhaseTransform { thisTransform => // we get a primitive form of _getClass trying to target a boxed value // so we need replace that method name with Object_getClass to get correct behavior. // See SI-5568. - qual.select(defn.Any_getClass).appliedToNone + qual.selectWithSig(defn.Any_getClass).appliedToNone } else { unknown } |