Skip to content

Commit 11254b3

Browse files
committed
Fix #2099: Make param forwarders override the param they forward to
Previously, in the following code: class A(val member: Int) class SubA(member: Int) extends A(member) We created a forwarder in SubA like this: private[this] def member: Int = super.member Since a private method cannot have the same name as an inherited non-private one, we subsequently name-mangled the forwarder in ExpandPrivate. However, this was only done in the TreeTransformer, not in the DenotTransformer, this lead to separate compilation issues (see added testcase). Since we cannot detect that a ParamAccessor is a forwarder in a DenotTransformer, we cannot fix the problem locally in ExpandPrivate. Instead, we change ParamForwarding so that the forwarder now looks like: override def member: Int = super.member To make this work we restrict ParamForwarding to only create forwarders for non-final fields.
1 parent c7acb7b commit 11254b3

File tree

4 files changed

+22
-25
lines changed

4 files changed

+22
-25
lines changed

compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ package transform
33

44
import core._
55
import dotty.tools.dotc.ast.tpd
6-
import dotty.tools.dotc.core.DenotTransformers.{SymTransformer, IdentityDenotTransformer}
6+
import dotty.tools.dotc.core.DenotTransformers.{SymTransformer, DenotTransformer}
77
import Contexts.Context
88
import Symbols._
99
import Scopes._
1010
import Flags._
1111
import StdNames._
12+
import Denotations._
1213
import SymDenotations._
1314
import Types._
1415
import collection.mutable
@@ -25,15 +26,10 @@ import ValueClasses._
2526
* Make private accessor in value class not-private. Ihis is necessary to unbox
2627
* the value class when accessing it from separate compilation units
2728
*
28-
* Also, make non-private any private parameter forwarders that forward to an inherited
29-
* public or protected parameter accessor with the same name as the forwarder.
30-
* This is necessary since private methods are not allowed to have the same name
31-
* as inherited public ones.
32-
*
3329
* See discussion in https://github.com/lampepfl/dotty/pull/784
3430
* and https://github.com/lampepfl/dotty/issues/783
3531
*/
36-
class ExpandPrivate extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
32+
class ExpandPrivate extends MiniPhaseTransform with DenotTransformer { thisTransform =>
3733
import ast.tpd._
3834

3935
override def phaseName: String = "expandPrivate"
@@ -56,6 +52,15 @@ class ExpandPrivate extends MiniPhaseTransform with IdentityDenotTransformer { t
5652
}
5753
}
5854

55+
override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation =
56+
ref match {
57+
case ref: SymDenotation if isVCPrivateParamAccessor(ref) =>
58+
ref.ensureNotPrivate
59+
case _ =>
60+
ref
61+
}
62+
63+
5964
private def isVCPrivateParamAccessor(d: SymDenotation)(implicit ctx: Context) =
6065
d.isTerm && d.is(PrivateParamAccessor) && isDerivedValueClass(d.owner)
6166

@@ -65,9 +70,7 @@ class ExpandPrivate extends MiniPhaseTransform with IdentityDenotTransformer { t
6570
* static members of the companion class, we should tighten the condition below.
6671
*/
6772
private def ensurePrivateAccessible(d: SymDenotation)(implicit ctx: Context) =
68-
if (isVCPrivateParamAccessor(d))
69-
d.ensureNotPrivate.installAfter(thisTransform)
70-
else if (d.is(PrivateTerm) && d.owner != ctx.owner.enclosingClass) {
73+
if (d.is(PrivateTerm) && d.owner != ctx.owner.enclosingClass) {
7174
// Paths `p1` and `p2` are similar if they have a common suffix that follows
7275
// possibly different directory paths. That is, their common suffix extends
7376
// in both cases either to the start of the path or to a file separator character.
@@ -95,17 +98,4 @@ class ExpandPrivate extends MiniPhaseTransform with IdentityDenotTransformer { t
9598
ensurePrivateAccessible(tree.symbol)
9699
tree
97100
}
98-
99-
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo) = {
100-
val sym = tree.symbol
101-
tree.rhs match {
102-
case Apply(sel @ Select(_: Super, _), _)
103-
if sym.is(PrivateParamAccessor) && sel.symbol.is(ParamAccessor) && sym.name == sel.symbol.name =>
104-
sym.ensureNotPrivate.installAfter(thisTransform)
105-
case _ =>
106-
if (isVCPrivateParamAccessor(sym))
107-
sym.ensureNotPrivate.installAfter(thisTransform)
108-
}
109-
tree
110-
}
111101
}

compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class ParamForwarding(thisTransformer: DenotTransformer) {
4646
* }
4747
*/
4848
val candidate = sym.owner.asClass.superClass
49-
.info.decl(sym.name).suchThat(_ is (ParamAccessor, butNot = Mutable)).symbol
49+
.info.decl(sym.name).suchThat(_ is (ParamAccessor, butNot = (Mutable | Final))).symbol
5050
if (candidate.isAccessibleFrom(currentClass.thisType, superAccess = true)) candidate
5151
else if (candidate is Method) inheritedAccessor(candidate)
5252
else NoSymbol
@@ -63,7 +63,10 @@ class ParamForwarding(thisTransformer: DenotTransformer) {
6363
val alias = inheritedAccessor(sym)
6464
if (alias.exists) {
6565
def forwarder(implicit ctx: Context) = {
66-
sym.copySymDenotation(initFlags = sym.flags | Method | Stable, info = sym.info.ensureMethodic)
66+
// A private method cannot have the same name as an inherited non-private one,
67+
// so the forwarder should have the same access flags as the alias.
68+
val flags = (sym.flags &~ Private) | (alias.flags & AccessFlags) | Override | Method | Stable
69+
sym.copySymDenotation(initFlags = flags, info = sym.info.ensureMethodic)
6770
.installAfter(thisTransformer)
6871
val superAcc =
6972
Super(This(currentClass), tpnme.EMPTY, inConstrCall = false).select(alias)

tests/pos/i2099/A_1.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class A(val member: Int)
2+
3+
class SubA(member: Int) extends A(member)

tests/pos/i2099/B_2.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
class B(member: Int) extends SubA(member)

0 commit comments

Comments
 (0)