summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Namers.scala
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan@lightbend.com>2017-04-12 11:31:54 -0700
committerAdriaan Moors <adriaan@lightbend.com>2017-04-12 14:02:21 -0700
commit77917e94c70759602be0dae833e798e894999254 (patch)
tree7d7cec3c558bb89db482863c3573cfe049f0affb /src/compiler/scala/tools/nsc/typechecker/Namers.scala
parent5167b691bbc6eccc671ef3a49c7ecaf3343c0baa (diff)
downloadscala-77917e94c70759602be0dae833e798e894999254.tar.gz
scala-77917e94c70759602be0dae833e798e894999254.tar.bz2
scala-77917e94c70759602be0dae833e798e894999254.zip
Actually retract clashing synthetic apply/unapply [backport]
Also make this whole retraction of apply/unapply in case of a clashing user-defined member conditional on `-Xsource:2.12`. It turns out, as explained by lrytz, that the retraction mechanism was fragile because it relied on the order in which completers are run. We now cover both the case that: - the completer was run, the `IS_ERROR` flag was set, and the symbol was unlinked from its scope before `addSynthetics` in `typedStat` iterates over the scope (since the symbol is already unlinked, the tree is not added, irrespective of its flags). For this case, we also remove the symbol from the synthetics in its unit (for cleanliness). - the completer is triggered during the iteration in `addSynthetics`, which needs the check for the `IS_ERROR` flag during the iteration. Before, the completer just unlinked the symbol and set the IS_ERROR flag, and I assumed the typer dropped a synthetic tree with a symbol with that flag, because the tree was not shown in -Xprint output. In reality, the completer just always happened to run before the addSynthetics loop and unlinked the symbol from its scope in the test cases I came up with (including the 2.11 community build). Thankfully, the 2.12 community build caught my mistake, and lrytz provided a good analysis and review. Fix scala/bug#10261
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Namers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala17
1 files changed, 15 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index b755ee3ebd..81299dc425 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -691,8 +691,21 @@ trait Namers extends MethodSynthesis {
if (suppress) {
sym setInfo ErrorType
+ // There are two ways in which we exclude the symbol from being added in typedStats::addSynthetics,
+ // because we don't know when the completer runs with respect to this loop in addSynthetics
+ // for (sym <- scope)
+ // for (tree <- context.unit.synthetics.get(sym) if shouldAdd(sym)) {
+ // if (!sym.initialize.hasFlag(IS_ERROR))
+ // newStats += typedStat(tree)
+ // (1) If we're already in the loop, set the IS_ERROR flag and trigger the condition
+ // `sym.initialize.hasFlag(IS_ERROR)` in typedStats::addSynthetics,
+ // (2) Or, if we are not yet in the addSynthetics loop (and we're not going to emit an error anyway),
+ // we unlink the symbol from its scope.
sym setFlag IS_ERROR
+ // For good measure. Removing it from its owner's scope and setting the IS_ERROR flag is enough to exclude it from addSynthetics
+ companionContext.unit.synthetics -= sym
+
// Don't unlink in an error situation to generate less confusing error messages.
// Ideally, our error reporting would distinguish overloaded from recursive user-defined apply methods without signature,
// but this would require some form of partial-completion of method signatures, so that we can
@@ -702,7 +715,7 @@ trait Namers extends MethodSynthesis {
// I hesitate to provide more info, because it would involve a WildCard or something for its result type,
// which could upset other code paths)
if (!scopePartiallyCompleted)
- companionContext.scope.unlink(sym)
+ companionContext.scope.unlink(sym) // (2)
}
}
}
@@ -770,7 +783,7 @@ trait Namers extends MethodSynthesis {
val completer =
if (sym hasFlag SYNTHETIC) {
if (name == nme.copy) copyMethodCompleter(tree)
- else if (sym hasFlag CASE) applyUnapplyMethodCompleter(tree, context)
+ else if (settings.isScala212 && (sym hasFlag CASE)) applyUnapplyMethodCompleter(tree, context)
else completerOf(tree)
} else completerOf(tree)