Skip to content

Commit 6fc0a0f

Browse files
committed
Merge pull request #456 from dotty-staging/patmat-eqeq
Fix #453, patternMatcher should use ==
2 parents b8ffaf8 + 673842f commit 6fc0a0f

File tree

6 files changed

+49
-11
lines changed

6 files changed

+49
-11
lines changed

src/dotty/tools/dotc/ast/TreeTypeMap.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import dotty.tools.dotc.transform.SymUtils._
3030
* have two substitutons S1 = [outer#1 := outer#3], S2 = [inner#2 := inner#4] where
3131
* hashtags precede symbol ids. If we do S1 first, we get outer#2.inner#3. If we then
3232
* do S2 we get outer#2.inner#4. But that means that the named type outer#2.inner
33-
* gets two different denotations in the same period. Hence, if -YnoDoubleBindings is
33+
* gets two different denotations in the same period. Hence, if -Yno-double-bindings is
3434
* set, we would get a data race assertion error.
3535
*/
3636
final class TreeTypeMap(

src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -588,63 +588,97 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
588588
tree
589589
}
590590

591+
/** A select node with the given selector name and a computed type */
591592
def select(name: Name)(implicit ctx: Context): Select =
592593
Select(tree, name)
593594

595+
/** A select node with the given type */
594596
def select(tp: NamedType)(implicit ctx: Context): Select =
595597
untpd.Select(tree, tp.name).withType(tp)
596598

599+
/** A select node that selects the given symbol. Note: Need to make sure this
600+
* is in fact the symbol you would get when you select with the symbol's name,
601+
* otherwise a data race may occur which would be flagged by -Yno-double-bindings.
602+
*/
597603
def select(sym: Symbol)(implicit ctx: Context): Select =
598604
untpd.Select(tree, sym.name).withType(
599605
TermRef.withSigAndDenot(tree.tpe, sym.name.asTermName, sym.signature, sym.denot.asSeenFrom(tree.tpe)))
600606

601-
def selectWithSig(name: Name, sig: Signature)(implicit ctx: Context) =
607+
/** A select node with the given selector name and signature and a computed type */
608+
def selectWithSig(name: Name, sig: Signature)(implicit ctx: Context): Tree =
602609
untpd.SelectWithSig(tree, name, sig)
603610
.withType(TermRef.withSig(tree.tpe, name.asTermName, sig))
604611

612+
/** A select node with selector name and signature taken from `sym`.
613+
* Note: Use this method instead of select(sym) if the referenced symbol
614+
* might be overridden in the type of the qualifier prefix. See note
615+
* on select(sym: Symbol).
616+
*/
617+
def selectWithSig(sym: Symbol)(implicit ctx: Context): Tree =
618+
selectWithSig(sym.name, sym.signature)
619+
620+
/** A unary apply node with given argument: `tree(arg)` */
605621
def appliedTo(arg: Tree)(implicit ctx: Context): Tree =
606622
appliedToArgs(arg :: Nil)
607623

624+
/** An apply node with given arguments: `tree(arg, args0, ..., argsN)` */
608625
def appliedTo(arg: Tree, args: Tree*)(implicit ctx: Context): Tree =
609626
appliedToArgs(arg :: args.toList)
610627

628+
/** An apply node with given argument list `tree(args(0), ..., args(args.length - 1))` */
611629
def appliedToArgs(args: List[Tree])(implicit ctx: Context): Apply =
612630
Apply(tree, args)
613631

632+
/** The current tree applied to given argument lists:
633+
* `tree (argss(0)) ... (argss(argss.length -1))`
634+
*/
614635
def appliedToArgss(argss: List[List[Tree]])(implicit ctx: Context): Tree =
615636
((tree: Tree) /: argss)(Apply(_, _))
616637

638+
/** The current tree applied to (): `tree()` */
617639
def appliedToNone(implicit ctx: Context): Apply = appliedToArgs(Nil)
618640

641+
/** The current tree applied to given type argument: `tree[targ]` */
619642
def appliedToType(targ: Type)(implicit ctx: Context): Tree =
620643
appliedToTypes(targ :: Nil)
621644

645+
/** The current tree applied to given type arguments: `tree[targ0, ..., targN]` */
622646
def appliedToTypes(targs: List[Type])(implicit ctx: Context): Tree =
623647
appliedToTypeTrees(targs map (TypeTree(_)))
624648

649+
/** The current tree applied to given type argument list: `tree[targs(0), ..., targs(targs.length - 1)]` */
625650
def appliedToTypeTrees(targs: List[Tree])(implicit ctx: Context): Tree =
626651
if (targs.isEmpty) tree else TypeApply(tree, targs)
627652

653+
/** Apply to `()` unless tree's widened type is parameterless */
628654
def ensureApplied(implicit ctx: Context): Tree =
629655
if (tree.tpe.widen.isParameterless) tree else tree.appliedToNone
630656

657+
/** `tree.isInstanceOf[tp]` */
631658
def isInstance(tp: Type)(implicit ctx: Context): Tree =
632659
tree.select(defn.Any_isInstanceOf).appliedToType(tp)
633660

661+
/** tree.asInstanceOf[`tp`] */
634662
def asInstance(tp: Type)(implicit ctx: Context): Tree = {
635663
assert(tp.isValueType, i"bad cast: $tree.asInstanceOf[$tp]")
636664
tree.select(defn.Any_asInstanceOf).appliedToType(tp)
637665
}
638666

667+
/** `tree.asInstanceOf[tp]` unless tree's type already conforms to `tp` */
639668
def ensureConforms(tp: Type)(implicit ctx: Context): Tree =
640669
if (tree.tpe <:< tp) tree else asInstance(tp)
641670

671+
/** `this && that`, for boolean trees `this`, `that` */
642672
def and(that: Tree)(implicit ctx: Context): Tree =
643673
tree.select(defn.Boolean_&&).appliedTo(that)
644674

675+
/** `this || that`, for boolean trees `this`, `that` */
645676
def or(that: Tree)(implicit ctx: Context): Tree =
646677
tree.select(defn.Boolean_||).appliedTo(that)
647678

679+
/** The translation of `tree = rhs`.
680+
* This is either the tree as an assignment, to a setter call.
681+
*/
648682
def becomes(rhs: Tree)(implicit ctx: Context): Tree =
649683
if (tree.symbol is Method) {
650684
val setr = tree match {
@@ -660,20 +694,23 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
660694

661695
// --- Higher order traversal methods -------------------------------
662696

663-
def foreachSubTree(f: Tree => Unit)(implicit ctx: Context): Unit = { //TODO should go in tpd.
697+
/** Apply `f` to each subtree of this tree */
698+
def foreachSubTree(f: Tree => Unit)(implicit ctx: Context): Unit = {
664699
val traverser = new TreeTraverser {
665700
def traverse(tree: Tree)(implicit ctx: Context) = foldOver(f(tree), tree)
666701
}
667702
traverser.traverse(tree)
668703
}
669704

705+
/** Is there a subtree of this tree that satisfies predicate `p`? */
670706
def existsSubTree(p: Tree => Boolean)(implicit ctx: Context): Boolean = {
671707
val acc = new TreeAccumulator[Boolean] {
672708
def apply(x: Boolean, t: Tree)(implicit ctx: Context) = x || p(t) || foldOver(x, t)
673709
}
674710
acc(false, tree)
675711
}
676712

713+
/** All subtrees of this tree that satisfy predicate `p`. */
677714
def filterSubTrees(f: Tree => Boolean)(implicit ctx: Context): List[Tree] = {
678715
val buf = new mutable.ListBuffer[Tree]
679716
foreachSubTree { tree => if (f(tree)) buf += tree }

src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ class ScalaSettings extends Settings.SettingGroup {
170170
val Ytyperdebug = BooleanSetting("-Ytyper-debug", "Trace all type assignments.")
171171
val Ypatmatdebug = BooleanSetting("-Ypatmat-debug", "Trace pattern matching translation.")
172172
val Yexplainlowlevel = BooleanSetting("-Yexplain-lowlevel", "When explaining type errors, show types at a lower level.")
173-
val YnoDoubleBindings = BooleanSetting("-YnoDoubleBindings", "Assert no namedtype is bound twice (should be enabled only if program is error-free).")
173+
val YnoDoubleBindings = BooleanSetting("-Yno-double-bindings", "Assert no namedtype is bound twice (should be enabled only if program is error-free).")
174174

175175
val optimise = BooleanSetting("-optimise", "Generates faster bytecode by applying optimisations to the program") withAbbreviation "-optimize"
176176

src/dotty/tools/dotc/transform/InterceptedMethods.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ class InterceptedMethods extends MiniPhaseTransform { thisTransform =>
111111
poundPoundValue(qual)
112112
} else if (Any_comparisons contains tree.fun.symbol.asTerm) {
113113
if (tree.fun.symbol eq defn.Any_==) {
114-
qual.select(defn.Any_equals).appliedToArgs(tree.args)
114+
qual.selectWithSig(defn.Any_equals).appliedToArgs(tree.args)
115115
} else if (tree.fun.symbol eq defn.Any_!=) {
116-
qual.select(defn.Any_equals).appliedToArgs(tree.args).select(defn.Boolean_!)
116+
qual.selectWithSig(defn.Any_equals).appliedToArgs(tree.args).select(defn.Boolean_!)
117117
} else unknown
118118
} /* else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) {
119119
// todo: this is needed to support value classes
@@ -130,7 +130,7 @@ class InterceptedMethods extends MiniPhaseTransform { thisTransform =>
130130
// we get a primitive form of _getClass trying to target a boxed value
131131
// so we need replace that method name with Object_getClass to get correct behavior.
132132
// See SI-5568.
133-
qual.select(defn.Any_getClass).appliedToNone
133+
qual.selectWithSig(defn.Any_getClass).appliedToNone
134134
} else {
135135
unknown
136136
}

src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
141141
}
142142

143143
// NOTE: checker must be the target of the ==, that's the patmat semantics for ya
144-
def _equals(checker: Tree, binder: Symbol): Tree = checker.select(nme.equals_).appliedTo(ref(binder))
144+
def _equals(checker: Tree, binder: Symbol): Tree =
145+
tpd.applyOverloaded(checker, nme.EQ, List(ref(binder)), List.empty, defn.BooleanType)
145146

146147
// 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)
147148
def _asInstanceOf(b: Symbol, tp: Type): Tree = ref(b).ensureConforms(tp) // andType here breaks t1048

test/dotc/tests.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class tests extends CompilerTest {
2525
val testPickling = List("-Xprint-types", "-Ytest-pickler", "-Ystop-after:pickler")
2626

2727
val failedOther = List("-Ystop-before:collectEntryPoints") // some non-obvious reason. need to look deeper
28-
val twice = List("#runs", "2", "-YnoDoubleBindings")
28+
val twice = List("#runs", "2", "-Yno-double-bindings")
2929
val staleSymbolError: List[String] = List()
3030

3131
val allowDeepSubtypes = defaultOptions diff List("-Yno-deep-subtypes")
@@ -130,8 +130,8 @@ class tests extends CompilerTest {
130130
@Test def dotc = compileDir(dotcDir + "tools/dotc", failedOther)(allowDeepSubtypes ++ twice) // see dotc_core
131131
@Test def dotc_ast = compileDir(dotcDir + "tools/dotc/ast", failedOther ++ twice)
132132
//similar to dotc_core_pickling but for another anon class. Still during firstTransform
133-
@Test def dotc_config = compileDir(dotcDir + "tools/dotc/config", twice)
134-
@Test def dotc_core = compileDir(dotcDir + "tools/dotc/core", failedOther)(allowDeepSubtypes) // !!!twice gives "data race?" error in InterceptedMethods
133+
@Test def dotc_config = compileDir(dotcDir + "tools/dotc/config")
134+
@Test def dotc_core = compileDir(dotcDir + "tools/dotc/core", failedOther)("-Yno-double-bindings" :: allowDeepSubtypes)// twice omitted to make tests run faster
135135
// error: error while loading ConstraintHandling$$anon$1$,
136136
// class file 'target/scala-2.11/dotty_2.11-0.1-SNAPSHOT.jar(dotty/tools/dotc/core/ConstraintHandling$$anon$1.class)'
137137
// has location not matching its contents: contains class $anon

0 commit comments

Comments
 (0)