diff options
author | Dmitry Petrashko <dark@d-d.me> | 2015-04-09 13:35:58 +0200 |
---|---|---|
committer | Dmitry Petrashko <dark@d-d.me> | 2015-04-09 13:35:58 +0200 |
commit | 6fc0a0ff71c0692ae7ed49c31bfc4533625b5764 (patch) | |
tree | 6e4770c45eb2ad58b70b25644463a3aaaa45e135 /src | |
parent | b8ffaf83984dd385fdab187ab83893a64b785519 (diff) | |
parent | 673842f94e68beb6f8bfa8136b37578464b0e55b (diff) | |
download | dotty-6fc0a0ff71c0692ae7ed49c31bfc4533625b5764.tar.gz dotty-6fc0a0ff71c0692ae7ed49c31bfc4533625b5764.tar.bz2 dotty-6fc0a0ff71c0692ae7ed49c31bfc4533625b5764.zip |
Merge pull request #456 from dotty-staging/patmat-eqeq
Fix #453, patternMatcher should use ==
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeTypeMap.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/tpd.scala | 41 | ||||
-rw-r--r-- | src/dotty/tools/dotc/config/ScalaSettings.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/InterceptedMethods.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/PatternMatcher.scala | 3 |
5 files changed, 46 insertions, 8 deletions
diff --git a/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/src/dotty/tools/dotc/ast/TreeTypeMap.scala index d2ec3ea10..ec66fcdb8 100644 --- a/src/dotty/tools/dotc/ast/TreeTypeMap.scala +++ b/src/dotty/tools/dotc/ast/TreeTypeMap.scala @@ -30,7 +30,7 @@ import dotty.tools.dotc.transform.SymUtils._ * have two substitutons S1 = [outer#1 := outer#3], S2 = [inner#2 := inner#4] where * hashtags precede symbol ids. If we do S1 first, we get outer#2.inner#3. If we then * do S2 we get outer#2.inner#4. But that means that the named type outer#2.inner - * gets two different denotations in the same period. Hence, if -YnoDoubleBindings is + * gets two different denotations in the same period. Hence, if -Yno-double-bindings is * set, we would get a data race assertion error. */ final class TreeTypeMap( 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/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala index 1c1f3e494..0d4034db2 100644 --- a/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -170,7 +170,7 @@ class ScalaSettings extends Settings.SettingGroup { val Ytyperdebug = BooleanSetting("-Ytyper-debug", "Trace all type assignments.") val Ypatmatdebug = BooleanSetting("-Ypatmat-debug", "Trace pattern matching translation.") val Yexplainlowlevel = BooleanSetting("-Yexplain-lowlevel", "When explaining type errors, show types at a lower level.") - val YnoDoubleBindings = BooleanSetting("-YnoDoubleBindings", "Assert no namedtype is bound twice (should be enabled only if program is error-free).") + val YnoDoubleBindings = BooleanSetting("-Yno-double-bindings", "Assert no namedtype is bound twice (should be enabled only if program is error-free).") val optimise = BooleanSetting("-optimise", "Generates faster bytecode by applying optimisations to the program") withAbbreviation "-optimize" 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 } diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala index 33e52e068..1336d39e4 100644 --- a/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -141,7 +141,8 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans } // NOTE: checker must be the target of the ==, that's the patmat semantics for ya - def _equals(checker: Tree, binder: Symbol): Tree = checker.select(nme.equals_).appliedTo(ref(binder)) + def _equals(checker: Tree, binder: Symbol): Tree = + tpd.applyOverloaded(checker, nme.EQ, List(ref(binder)), List.empty, defn.BooleanType) // the force is needed mainly to deal with the GADT typing hack (we can't detect it otherwise as tp nor pt need contain an abstract type, we're just casting wildly) def _asInstanceOf(b: Symbol, tp: Type): Tree = ref(b).ensureConforms(tp) // andType here breaks t1048 |