Skip to content

Commit 6d040c5

Browse files
KacperFKorbandwijnandmbovel
authored
fix: Drop copied parent refinements before generating bytecode (#21733)
Refinements are copied over from parents, because they might be needed for tracked members that should have more specific types in the child. These members are generated without an implementation and should not be used in runtime. possible fix for #21213 --------- Co-authored-by: Dale Wijnand <[email protected]> Co-authored-by: Matt Bovel <[email protected]>
1 parent c50a69f commit 6d040c5

File tree

11 files changed

+68
-8
lines changed

11 files changed

+68
-8
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

+1
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ class Compiler {
132132
new ElimStaticThis, // Replace `this` references to static objects by global identifiers
133133
new CountOuterAccesses) :: // Identify outer accessors that can be dropped
134134
List(new DropOuterAccessors, // Drop unused outer accessors
135+
new DropParentRefinements, // Drop parent refinements from a template
135136
new CheckNoSuperThis, // Check that supercalls don't contain references to `this`
136137
new Flatten, // Lift all inner classes to package scope
137138
new TransformWildcards, // Replace wildcards with default values
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package dotty.tools.dotc.transform
2+
3+
import dotty.tools.dotc.transform.MegaPhase.MiniPhase
4+
import dotty.tools.dotc.ast.tpd
5+
import dotty.tools.dotc.core.Contexts.Context
6+
import dotty.tools.dotc.core.DenotTransformers.IdentityDenotTransformer
7+
import dotty.tools.dotc.typer.Typer
8+
9+
object DropParentRefinements:
10+
val name: String = "dropParentRefinements"
11+
val description: String = "drop parent refinements from a template"
12+
13+
/** Drop parent refinements from a template, as they are generated without
14+
* an implementation. These refinements are unusally required for tracked
15+
* members with more specific types.
16+
*/
17+
class DropParentRefinements extends MiniPhase with IdentityDenotTransformer:
18+
thisPhase =>
19+
import tpd.*
20+
21+
override def phaseName: String = DropParentRefinements.name
22+
23+
override def description: String = DropParentRefinements.description
24+
25+
override def runsAfterGroupsOf: Set[String] = Set(CountOuterAccesses.name)
26+
27+
override def changesMembers: Boolean = true // the phase drops parent refinements
28+
29+
override def transformTemplate(tree: tpd.Template)(using Context): tpd.Tree =
30+
val newBody = tree.body.filter(!_.hasAttachment(Typer.RefinementFromParent))
31+
tree.body.foreach { member =>
32+
if member.hasAttachment(Typer.RefinementFromParent) then
33+
member.symbol.dropAfter(thisPhase)
34+
}
35+
cpy.Template(tree)(body = newBody)

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ class Getters extends MiniPhase with SymTransformer { thisPhase =>
103103
override def transformValDef(tree: ValDef)(using Context): Tree =
104104
val sym = tree.symbol
105105
if !sym.is(Method) then return tree
106-
val getterDef = DefDef(sym.asTerm, tree.rhs).withSpan(tree.span)
106+
val getterDef = DefDef(sym.asTerm, tree.rhs).withSpan(tree.span).withAttachmentsFrom(tree)
107107
if !sym.is(Mutable) then return getterDef
108108
ensureSetter(sym.asTerm)
109109
if !newSetters.contains(sym.setter) then return getterDef

compiler/src/dotty/tools/dotc/typer/Namer.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -877,16 +877,16 @@ class Namer { typer: Typer =>
877877
protected def addAnnotations(sym: Symbol): Unit = original match {
878878
case original: untpd.MemberDef =>
879879
lazy val annotCtx = annotContext(original, sym)
880-
original.setMods:
880+
original.setMods:
881881
original.mods.withAnnotations :
882-
original.mods.annotations.mapConserve: annotTree =>
882+
original.mods.annotations.mapConserve: annotTree =>
883883
val cls = typedAheadAnnotationClass(annotTree)(using annotCtx)
884884
if (cls eq sym)
885885
report.error(em"An annotation class cannot be annotated with iself", annotTree.srcPos)
886886
annotTree
887887
else
888-
val ann =
889-
if cls.is(JavaDefined) then Checking.checkNamedArgumentForJavaAnnotation(annotTree, cls.asClass)
888+
val ann =
889+
if cls.is(JavaDefined) then Checking.checkNamedArgumentForJavaAnnotation(annotTree, cls.asClass)
890890
else annotTree
891891
val ann1 = Annotation.deferred(cls)(typedAheadExpr(ann)(using annotCtx))
892892
sym.addAnnotation(ann1)

compiler/src/dotty/tools/dotc/typer/Typer.scala

+4-1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ object Typer {
7878
/** An attachment for GADT constraints that were inferred for a pattern. */
7979
val InferredGadtConstraints = new Property.StickyKey[core.GadtConstraint]
8080

81+
/** Indicates that a definition was copied over from the parent refinements */
82+
val RefinementFromParent = new Property.StickyKey[Unit]
83+
8184
/** An attachment on a Select node with an `apply` field indicating that the `apply`
8285
* was inserted by the Typer.
8386
*/
@@ -3071,7 +3074,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
30713074
( if sym.isType then TypeDef(sym.asType)
30723075
else if sym.is(Method) then DefDef(sym.asTerm)
30733076
else ValDef(sym.asTerm)
3074-
).withSpan(impl.span.startPos)
3077+
).withSpan(impl.span.startPos).withAttachment(RefinementFromParent, ())
30753078
body ++ refinements
30763079
case None =>
30773080
body

tests/printing/transformed/lazy-vals-legacy.check

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[[syntax trees at end of MegaPhase{dropOuterAccessors, checkNoSuperThis, flatten, transformWildcards, moveStatic, expandPrivate, restoreScopes, selectStatic, Collect entry points, collectSuperCalls, repeatableAnnotations}]] // tests/printing/transformed/lazy-vals-legacy.scala
1+
[[syntax trees at end of MegaPhase{dropOuterAccessors, dropParentRefinements, checkNoSuperThis, flatten, transformWildcards, moveStatic, expandPrivate, restoreScopes, selectStatic, Collect entry points, collectSuperCalls, repeatableAnnotations}]] // tests/printing/transformed/lazy-vals-legacy.scala
22
package <empty> {
33
@SourceFile("tests/printing/transformed/lazy-vals-legacy.scala") final module
44
class A extends Object {

tests/printing/transformed/lazy-vals-new.check

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[[syntax trees at end of MegaPhase{dropOuterAccessors, checkNoSuperThis, flatten, transformWildcards, moveStatic, expandPrivate, restoreScopes, selectStatic, Collect entry points, collectSuperCalls, repeatableAnnotations}]] // tests/printing/transformed/lazy-vals-new.scala
1+
[[syntax trees at end of MegaPhase{dropOuterAccessors, dropParentRefinements, checkNoSuperThis, flatten, transformWildcards, moveStatic, expandPrivate, restoreScopes, selectStatic, Collect entry points, collectSuperCalls, repeatableAnnotations}]] // tests/printing/transformed/lazy-vals-new.scala
22
package <empty> {
33
@SourceFile("tests/printing/transformed/lazy-vals-new.scala") final module
44
class A extends Object {

tests/run/i21213-min.check

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bar

tests/run/i21213-min.scala

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import scala.language.experimental.modularity
2+
import scala.language.future
3+
4+
sealed abstract class Foo(tracked val discriminator: String)
5+
class Bar extends Foo("bar")
6+
7+
val bar: Foo = Bar()
8+
object Test extends App:
9+
println(bar.discriminator)

tests/run/i21213.check

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bar

tests/run/i21213.scala

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import scala.language.experimental.modularity
2+
import scala.language.future
3+
4+
enum Foo(tracked val discriminator: String):
5+
case Bar() extends Foo("bar")
6+
case Baz() extends Foo("baz")
7+
8+
val bar: Foo = Foo.Bar()
9+
object Test extends App:
10+
println(bar.discriminator)

0 commit comments

Comments
 (0)