Skip to content

Commit

Permalink
fix: Drop copied parent refinements before generating bytecode (#21733)
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
3 people authored Oct 18, 2024
1 parent c50a69f commit 6d040c5
Show file tree
Hide file tree
Showing 11 changed files with 68 additions and 8 deletions.
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class Compiler {
new ElimStaticThis, // Replace `this` references to static objects by global identifiers
new CountOuterAccesses) :: // Identify outer accessors that can be dropped
List(new DropOuterAccessors, // Drop unused outer accessors
new DropParentRefinements, // Drop parent refinements from a template
new CheckNoSuperThis, // Check that supercalls don't contain references to `this`
new Flatten, // Lift all inner classes to package scope
new TransformWildcards, // Replace wildcards with default values
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package dotty.tools.dotc.transform

import dotty.tools.dotc.transform.MegaPhase.MiniPhase
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.core.DenotTransformers.IdentityDenotTransformer
import dotty.tools.dotc.typer.Typer

object DropParentRefinements:
val name: String = "dropParentRefinements"
val description: String = "drop parent refinements from a template"

/** Drop parent refinements from a template, as they are generated without
* an implementation. These refinements are unusally required for tracked
* members with more specific types.
*/
class DropParentRefinements extends MiniPhase with IdentityDenotTransformer:
thisPhase =>
import tpd.*

override def phaseName: String = DropParentRefinements.name

override def description: String = DropParentRefinements.description

override def runsAfterGroupsOf: Set[String] = Set(CountOuterAccesses.name)

override def changesMembers: Boolean = true // the phase drops parent refinements

override def transformTemplate(tree: tpd.Template)(using Context): tpd.Tree =
val newBody = tree.body.filter(!_.hasAttachment(Typer.RefinementFromParent))
tree.body.foreach { member =>
if member.hasAttachment(Typer.RefinementFromParent) then
member.symbol.dropAfter(thisPhase)
}
cpy.Template(tree)(body = newBody)
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/Getters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class Getters extends MiniPhase with SymTransformer { thisPhase =>
override def transformValDef(tree: ValDef)(using Context): Tree =
val sym = tree.symbol
if !sym.is(Method) then return tree
val getterDef = DefDef(sym.asTerm, tree.rhs).withSpan(tree.span)
val getterDef = DefDef(sym.asTerm, tree.rhs).withSpan(tree.span).withAttachmentsFrom(tree)
if !sym.is(Mutable) then return getterDef
ensureSetter(sym.asTerm)
if !newSetters.contains(sym.setter) then return getterDef
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -877,16 +877,16 @@ class Namer { typer: Typer =>
protected def addAnnotations(sym: Symbol): Unit = original match {
case original: untpd.MemberDef =>
lazy val annotCtx = annotContext(original, sym)
original.setMods:
original.setMods:
original.mods.withAnnotations :
original.mods.annotations.mapConserve: annotTree =>
original.mods.annotations.mapConserve: annotTree =>
val cls = typedAheadAnnotationClass(annotTree)(using annotCtx)
if (cls eq sym)
report.error(em"An annotation class cannot be annotated with iself", annotTree.srcPos)
annotTree
else
val ann =
if cls.is(JavaDefined) then Checking.checkNamedArgumentForJavaAnnotation(annotTree, cls.asClass)
val ann =
if cls.is(JavaDefined) then Checking.checkNamedArgumentForJavaAnnotation(annotTree, cls.asClass)
else annotTree
val ann1 = Annotation.deferred(cls)(typedAheadExpr(ann)(using annotCtx))
sym.addAnnotation(ann1)
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ object Typer {
/** An attachment for GADT constraints that were inferred for a pattern. */
val InferredGadtConstraints = new Property.StickyKey[core.GadtConstraint]

/** Indicates that a definition was copied over from the parent refinements */
val RefinementFromParent = new Property.StickyKey[Unit]

/** An attachment on a Select node with an `apply` field indicating that the `apply`
* was inserted by the Typer.
*/
Expand Down Expand Up @@ -3071,7 +3074,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
( if sym.isType then TypeDef(sym.asType)
else if sym.is(Method) then DefDef(sym.asTerm)
else ValDef(sym.asTerm)
).withSpan(impl.span.startPos)
).withSpan(impl.span.startPos).withAttachment(RefinementFromParent, ())
body ++ refinements
case None =>
body
Expand Down
2 changes: 1 addition & 1 deletion tests/printing/transformed/lazy-vals-legacy.check
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[[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
[[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
package <empty> {
@SourceFile("tests/printing/transformed/lazy-vals-legacy.scala") final module
class A extends Object {
Expand Down
2 changes: 1 addition & 1 deletion tests/printing/transformed/lazy-vals-new.check
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[[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
[[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
package <empty> {
@SourceFile("tests/printing/transformed/lazy-vals-new.scala") final module
class A extends Object {
Expand Down
1 change: 1 addition & 0 deletions tests/run/i21213-min.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bar
9 changes: 9 additions & 0 deletions tests/run/i21213-min.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import scala.language.experimental.modularity
import scala.language.future

sealed abstract class Foo(tracked val discriminator: String)
class Bar extends Foo("bar")

val bar: Foo = Bar()
object Test extends App:
println(bar.discriminator)
1 change: 1 addition & 0 deletions tests/run/i21213.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bar
10 changes: 10 additions & 0 deletions tests/run/i21213.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import scala.language.experimental.modularity
import scala.language.future

enum Foo(tracked val discriminator: String):
case Bar() extends Foo("bar")
case Baz() extends Foo("baz")

val bar: Foo = Foo.Bar()
object Test extends App:
println(bar.discriminator)

0 comments on commit 6d040c5

Please sign in to comment.