Skip to content

Fix #8602: Do not create mixins for constant-expression final vals. #10496

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/Constructors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
} else
dropped += sym
case stat @ DefDef(name, _, _, tpt, _)
if stat.symbol.isGetter && stat.symbol.owner.is(Trait) && !stat.symbol.is(Lazy) =>
if stat.symbol.isGetter && stat.symbol.owner.is(Trait) && !stat.symbol.is(Lazy) && !stat.symbol.isConstExprFinalVal =>
val sym = stat.symbol
assert(isRetained(sym), sym)
if !stat.rhs.isEmpty && !isWildcardArg(stat.rhs) then
Expand Down
10 changes: 6 additions & 4 deletions compiler/src/dotty/tools/dotc/transform/Mixin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>

if (sym.is(Accessor, butNot = Deferred) && ownerIsTrait) {
val sym1 =
if (sym.is(Lazy)) sym
if (sym.is(Lazy) || sym.symbol.isConstExprFinalVal) sym
else sym.copySymDenotation(initFlags = sym.flags &~ (ParamAccessor | Inline) | Deferred)
sym1.ensureNotPrivate
}
Expand Down Expand Up @@ -166,7 +166,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
private def needsTraitSetter(sym: Symbol)(using Context): Boolean =
sym.isGetter && !wasOneOf(sym, DeferredOrLazy | ParamAccessor)
&& atPhase(thisPhase) { !sym.setter.exists }
&& !sym.info.resultType.isInstanceOf[ConstantType]
&& !sym.isConstExprFinalVal

private def makeTraitSetter(getter: TermSymbol)(using Context): Symbol =
getter.copy(
Expand Down Expand Up @@ -251,7 +251,10 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
cls.srcPos)
EmptyTree

for (getter <- mixin.info.decls.toList if getter.isGetter && !wasOneOf(getter, Deferred)) yield {
for
getter <- mixin.info.decls.toList
if getter.isGetter && !wasOneOf(getter, Deferred) && !getter.isConstExprFinalVal
yield
if (isCurrent(getter) || getter.name.is(ExpandedName)) {
val rhs =
if (wasOneOf(getter, ParamAccessor))
Expand All @@ -266,7 +269,6 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
transformFollowing(DefDef(mkForwarderSym(getter.asTerm), rhs))
}
else EmptyTree
}
}

def setters(mixin: ClassSymbol): List[Tree] =
Expand Down
8 changes: 7 additions & 1 deletion compiler/src/dotty/tools/dotc/transform/SymUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import ValueClasses.isDerivedValueClass
import Decorators._
import Constants.Constant
import Annotations.Annotation
import Phases._
import ast.tpd.Literal

import language.implicitConversions
Expand Down Expand Up @@ -167,6 +168,11 @@ object SymUtils:
self.owner.info.decl(fieldName).suchThat(!_.is(Method)).symbol
}

def isConstExprFinalVal(using Context): Boolean =
atPhaseNoLater(erasurePhase) {
self.is(Final) && self.info.resultType.isInstanceOf[ConstantType]
}

def isField(using Context): Boolean =
self.isTerm && !self.is(Method)

Expand Down Expand Up @@ -268,4 +274,4 @@ object SymUtils:
Annotation(defn.TargetNameAnnot,
Literal(Constant(nameFn(original.targetName).toString)).withSpan(original.span)))
end extension
end SymUtils
end SymUtils
5 changes: 5 additions & 0 deletions tests/run/i8602/ChildClass_2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
public class ChildClass_2 extends Object implements ParentTrait {
public int getFoo() {
return foo();
}
}
3 changes: 3 additions & 0 deletions tests/run/i8602/ParentTrait_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
trait ParentTrait {
final val foo = 5
}
8 changes: 8 additions & 0 deletions tests/run/i8602/Test_3.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
object Test {
def main(args: Array[String]): Unit =
val child = new ChildClass_2()
assert(child.foo == 5)
assert(child.getFoo() == 5)
val parent: ParentTrait = child
assert(parent.foo == 5)
}