Skip to content

Commit 183ec08

Browse files
Merge pull request #12096 from dotty-staging/split-uninitialized-from-erased-defs-logic
Split uninitialized logic from erased definition logic
2 parents a66cb8d + 073c656 commit 183ec08

File tree

3 files changed

+58
-31
lines changed

3 files changed

+58
-31
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class Compiler {
8383
new ElimByName, // Expand by-name parameter references
8484
new StringInterpolatorOpt) :: // Optimizes raw and s string interpolators by rewriting them to string concatenations
8585
List(new PruneErasedDefs, // Drop erased definitions from scopes and simplify erased expressions
86+
new UninitializedDefs, // Replaces `compiletime.uninitialized` by `_`
8687
new InlinePatterns, // Remove placeholders of inlined patterns
8788
new VCInlineMethods, // Inlines calls to value class methods
8889
new SeqLiterals, // Express vararg arguments as arrays

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

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ import ast.tpd
1919
* The phase also replaces all expressions that appear in an erased context by
2020
* default values. This is necessary so that subsequent checking phases such
2121
* as IsInstanceOfChecker don't give false negatives.
22-
* Finally, the phase replaces `compiletime.uninitialized` on the right hand side
23-
* of a mutable field definition by `_`. This avoids a "is declared erased, but is
24-
* in fact used" error in Erasure and communicates to Constructors that the
25-
* variable does not have an initializer.
2622
*/
2723
class PruneErasedDefs extends MiniPhase with SymTransformer { thisTransform =>
2824
import tpd._
@@ -34,39 +30,20 @@ class PruneErasedDefs extends MiniPhase with SymTransformer { thisTransform =>
3430
override def runsAfterGroupsOf: Set[String] = Set(RefChecks.name, ExplicitOuter.name)
3531

3632
override def transformSym(sym: SymDenotation)(using Context): SymDenotation =
37-
if (sym.isEffectivelyErased && sym.isTerm && !sym.is(Private) && sym.owner.isClass)
38-
sym.copySymDenotation(initFlags = sym.flags | Private)
39-
else sym
33+
if !sym.isEffectivelyErased || !sym.isTerm || sym.is(Private) || !sym.owner.isClass then sym
34+
else sym.copySymDenotation(initFlags = sym.flags | Private)
4035

4136
override def transformApply(tree: Apply)(using Context): Tree =
42-
if (tree.fun.tpe.widen.isErasedMethod)
43-
cpy.Apply(tree)(tree.fun, tree.args.map(trivialErasedTree))
44-
else tree
45-
46-
private def hasUninitializedRHS(tree: ValOrDefDef)(using Context): Boolean =
47-
def recur(rhs: Tree): Boolean = rhs match
48-
case rhs: RefTree =>
49-
rhs.symbol == defn.Compiletime_uninitialized
50-
&& tree.symbol.is(Mutable) && tree.symbol.owner.isClass
51-
case closureDef(ddef) if defn.isContextFunctionType(tree.tpt.tpe.dealias) =>
52-
recur(ddef.rhs)
53-
case _ =>
54-
false
55-
recur(tree.rhs)
37+
if !tree.fun.tpe.widen.isErasedMethod then tree
38+
else cpy.Apply(tree)(tree.fun, tree.args.map(trivialErasedTree))
5639

5740
override def transformValDef(tree: ValDef)(using Context): Tree =
58-
val sym = tree.symbol
59-
if tree.symbol.isEffectivelyErased && !tree.rhs.isEmpty then
60-
cpy.ValDef(tree)(rhs = trivialErasedTree(tree))
61-
else if hasUninitializedRHS(tree) then
62-
cpy.ValDef(tree)(rhs = cpy.Ident(tree.rhs)(nme.WILDCARD).withType(tree.tpt.tpe))
63-
else
64-
tree
41+
if !tree.symbol.isEffectivelyErased || tree.rhs.isEmpty then tree
42+
else cpy.ValDef(tree)(rhs = trivialErasedTree(tree))
6543

6644
override def transformDefDef(tree: DefDef)(using Context): Tree =
67-
if (tree.symbol.isEffectivelyErased && !tree.rhs.isEmpty)
68-
cpy.DefDef(tree)(rhs = trivialErasedTree(tree))
69-
else tree
45+
if !tree.symbol.isEffectivelyErased || tree.rhs.isEmpty then tree
46+
else cpy.DefDef(tree)(rhs = trivialErasedTree(tree))
7047

7148
private def trivialErasedTree(tree: Tree)(using Context): Tree =
7249
tree.tpe.widenTermRefExpr.dealias.normalized match
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import Contexts._
6+
import DenotTransformers.SymTransformer
7+
import Flags._
8+
import SymDenotations._
9+
import Symbols._
10+
import Types._
11+
import typer.RefChecks
12+
import MegaPhase.MiniPhase
13+
import StdNames.nme
14+
import ast.tpd
15+
16+
/** This phase replaces `compiletime.uninitialized` on the right hand side of a mutable field definition by `_`.
17+
* This avoids a
18+
* ```scala
19+
* "@compileTimeOnly("`uninitialized` can only be used as the right hand side of a mutable field definition")`
20+
* ```
21+
* error in Erasure and communicates to Constructors that the variable does not have an initializer.
22+
*
23+
* @syntax markdown
24+
*/
25+
class UninitializedDefs extends MiniPhase:
26+
import tpd._
27+
28+
override def phaseName: String = UninitializedDefs.name
29+
30+
override def transformValDef(tree: ValDef)(using Context): Tree =
31+
if !hasUninitializedRHS(tree) then tree
32+
else cpy.ValDef(tree)(rhs = cpy.Ident(tree.rhs)(nme.WILDCARD).withType(tree.tpt.tpe))
33+
34+
private def hasUninitializedRHS(tree: ValOrDefDef)(using Context): Boolean =
35+
def recur(rhs: Tree): Boolean = rhs match
36+
case rhs: RefTree =>
37+
rhs.symbol == defn.Compiletime_uninitialized
38+
&& tree.symbol.is(Mutable) && tree.symbol.owner.isClass
39+
case closureDef(ddef) if defn.isContextFunctionType(tree.tpt.tpe.dealias) =>
40+
recur(ddef.rhs)
41+
case _ =>
42+
false
43+
recur(tree.rhs)
44+
45+
end UninitializedDefs
46+
47+
object UninitializedDefs:
48+
val name: String = "uninitializedDefs"
49+
end UninitializedDefs

0 commit comments

Comments
 (0)