Skip to content

Commit 8291928

Browse files
committed
User-defined case companion apply: unlink default getters
When a synthetic case companion `apply` method is unlinked because there's a matching user-defined method (see PR 5730), we also have to unlink the default getters to avoid clashes. Fixes scala/bug#10389
1 parent e72ab5a commit 8291928

File tree

3 files changed

+30
-0
lines changed

3 files changed

+30
-0
lines changed

src/compiler/scala/tools/nsc/typechecker/Namers.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,14 @@ trait Namers extends MethodSynthesis {
678678
// which could upset other code paths)
679679
if (!scopePartiallyCompleted)
680680
companionContext.scope.unlink(sym)
681+
682+
for (a <- sym.attachments.get[CaseApplyDefaultGetters]; defaultGetter <- a.defaultGetters) {
683+
companionContext.unit.synthetics -= defaultGetter
684+
companionContext.scope.unlink(defaultGetter)
685+
}
681686
}
687+
688+
sym.removeAttachment[CaseApplyDefaultGetters] // no longer needed once the completer is done
682689
}
683690
}
684691

@@ -1544,6 +1551,14 @@ trait Namers extends MethodSynthesis {
15441551
if (!isConstr)
15451552
methOwner.resetFlag(INTERFACE) // there's a concrete member now
15461553
val default = parentNamer.enterSyntheticSym(defaultTree)
1554+
if (meth.name == nme.apply && meth.hasAllFlags(CASE | SYNTHETIC)) {
1555+
val att = meth.attachments.get[CaseApplyDefaultGetters].getOrElse({
1556+
val a = new CaseApplyDefaultGetters()
1557+
meth.updateAttachment(a)
1558+
a
1559+
})
1560+
att.defaultGetters += default
1561+
}
15471562
if (default.owner.isTerm)
15481563
saveDefaultGetter(meth, default)
15491564
}

src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ trait NamesDefaults { self: Analyzer =>
2929
// as an attachment in the companion module symbol
3030
class ConstructorDefaultsAttachment(val classWithDefault: ClassDef, var companionModuleClassNamer: Namer)
3131

32+
// Attached to the synthetic companion `apply` method symbol generated for case classes, holds
33+
// the set contains all default getters for that method. If the synthetic `apply` is unlinked in
34+
// its completer because there's a user-defined matching method (PR #5730), we have to unlink the
35+
// default getters as well. For cleanliness, the attachment is removed at the end of the completer
36+
// of the synthetic `apply`, as it's no longer needed.
37+
class CaseApplyDefaultGetters(val defaultGetters: mutable.Set[Symbol] = mutable.Set.empty)
38+
3239
// To attach the default getters of local (term-owned) methods to the method symbol.
3340
// Used in Namer.enterExistingSym: it needs to re-enter the method symbol and also
3441
// default getters, which could not be found otherwise.

test/files/run/t10389.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
case class C(x: Int = 1)
2+
object C {
3+
def apply(x: Int = 2) = new C(x)
4+
}
5+
object Test extends App {
6+
assert(new C().x == 1)
7+
assert(C().x == 2)
8+
}

0 commit comments

Comments
 (0)