@@ -45,10 +45,10 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
45
45
// to more symbols being retained as parameters. Test case in run/capturing.scala.
46
46
47
47
/** The private vals that are known to be retained as class fields */
48
- private val retainedPrivateVals = mutable.Set [Symbol ]()
48
+ private val retainedPrivateVals = mutable.Set .empty [Symbol ]
49
49
50
50
/** The private vals whose definition comes before the current focus */
51
- private val seenPrivateVals = mutable.Set [Symbol ]()
51
+ private val seenPrivateVals = mutable.Set .empty [Symbol ]
52
52
53
53
// Collect all private parameter accessors and value definitions that need
54
54
// to be retained. There are several reasons why a parameter accessor or
@@ -57,31 +57,37 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
57
57
// 2. It is accessed before it is defined
58
58
// 3. It is accessed on an object other than `this`
59
59
// 4. It is a mutable parameter accessor
60
- // 5. It is has a wildcard initializer `_`
61
- private def markUsedPrivateSymbols (tree : RefTree )(using Context ): Unit = {
60
+ // 5. It has a wildcard initializer `_`
61
+ private def markUsedPrivateSymbols (tree : RefTree )(using Context ): Unit =
62
62
63
63
val sym = tree.symbol
64
64
def retain () = retainedPrivateVals.add(sym)
65
65
66
- if (sym.exists && sym.owner.isClass && mightBeDropped(sym)) {
67
- val owner = sym.owner.asClass
68
-
69
- tree match {
70
- case Ident (_) | Select (This (_), _) =>
71
- def inConstructor = {
72
- val method = ctx.owner.enclosingMethod
73
- method.isPrimaryConstructor && ctx.owner.enclosingClass == owner
74
- }
75
- if (inConstructor &&
76
- (sym.is(ParamAccessor ) || seenPrivateVals.contains(sym))) {
77
- // used inside constructor, accessed on this,
78
- // could use constructor argument instead, no need to retain field
79
- }
80
- else retain()
81
- case _ => retain()
82
- }
83
- }
84
- }
66
+ if sym.exists && sym.owner.isClass && mightBeDropped(sym) then
67
+ tree match
68
+ case Ident (_) | Select (This (_), _) =>
69
+ val method = ctx.owner.enclosingMethod
70
+ // template exprs are moved (below) to constructor, where lifted anonfun will take its captured env as an arg
71
+ inline def inAnonFunInCtor =
72
+ method.isAnonymousFunction
73
+ && (
74
+ method.owner.isLocalDummy
75
+ ||
76
+ method.owner.owner == sym.owner && ! method.owner.isOneOf(MethodOrLazy )
77
+ )
78
+ && ! sym.owner.is(Module ) // lambdalift doesn't transform correctly (to do)
79
+ val inConstructor =
80
+ (method.isPrimaryConstructor || inAnonFunInCtor)
81
+ && ctx.owner.enclosingClass == sym.owner
82
+ val noField =
83
+ inConstructor
84
+ && (sym.is(ParamAccessor ) || seenPrivateVals.contains(sym))
85
+ // used inside constructor, accessed on this,
86
+ // could use constructor argument instead, no need to retain field
87
+ if ! noField then
88
+ retain()
89
+ case _ =>
90
+ retain()
85
91
86
92
override def transformIdent (tree : tpd.Ident )(using Context ): tpd.Tree = {
87
93
markUsedPrivateSymbols(tree)
@@ -184,6 +190,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
184
190
transform(tree).changeOwnerAfter(prevOwner, constr.symbol, thisPhase)
185
191
}
186
192
193
+ // mightBeDropped is trivially false for NoSymbol -> NoSymbol isRetained
187
194
def isRetained (acc : Symbol ) =
188
195
! mightBeDropped(acc) || retainedPrivateVals(acc)
189
196
@@ -209,30 +216,28 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
209
216
}
210
217
}
211
218
212
- val dropped = mutable.Set [Symbol ]()
219
+ val dropped = mutable.Set .empty [Symbol ]
213
220
214
221
// Split class body into statements that go into constructor and
215
222
// definitions that are kept as members of the class.
216
- def splitStats (stats : List [Tree ]): Unit = stats match {
217
- case stat :: stats1 =>
223
+ def splitStats (stats : List [Tree ]): Unit = stats match
224
+ case stat :: stats =>
225
+ val sym = stat.symbol
218
226
stat match {
219
- case stat @ ValDef (name, tpt, _) if ! stat.symbol.is(Lazy ) && ! stat.symbol.hasAnnotation(defn.ScalaStaticAnnot ) =>
220
- val sym = stat.symbol
227
+ case stat @ ValDef (name, tpt, _) if ! sym.is(Lazy ) && ! sym.hasAnnotation(defn.ScalaStaticAnnot ) =>
221
228
if (isRetained(sym)) {
222
229
if (! stat.rhs.isEmpty && ! isWildcardArg(stat.rhs))
223
230
constrStats += Assign (ref(sym), intoConstr(stat.rhs, sym)).withSpan(stat.span)
224
231
clsStats += cpy.ValDef (stat)(rhs = EmptyTree )
225
232
}
226
- else if (! stat.rhs.isEmpty) {
227
- dropped += sym
228
- sym.copySymDenotation(
229
- initFlags = sym.flags &~ Private ,
230
- owner = constr.symbol).installAfter(thisPhase)
231
- constrStats += intoConstr(stat, sym)
232
- } else
233
+ else
233
234
dropped += sym
235
+ if ! stat.rhs.isEmpty then
236
+ sym.copySymDenotation(
237
+ initFlags = sym.flags &~ Private ,
238
+ owner = constr.symbol).installAfter(thisPhase)
239
+ constrStats += intoConstr(stat, sym)
234
240
case stat @ DefDef (name, _, tpt, _) if stat.symbol.isGetter && ! stat.symbol.is(Lazy ) =>
235
- val sym = stat.symbol
236
241
assert(isRetained(sym), sym)
237
242
if sym.isConstExprFinalVal then
238
243
if stat.rhs.isInstanceOf [Literal ] then
@@ -271,9 +276,9 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
271
276
case _ =>
272
277
constrStats += intoConstr(stat, tree.symbol)
273
278
}
274
- splitStats(stats1 )
279
+ splitStats(stats )
275
280
case Nil =>
276
- }
281
+ end splitStats
277
282
278
283
/** Check that we do not have both a private field with name `x` and a private field
279
284
* with name `FieldName(x)`. These will map to the same JVM name and therefore cause
@@ -303,14 +308,15 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
303
308
dropped += acc
304
309
Nil
305
310
}
306
- else if (! isRetained(acc.field)) { // It may happen for unit fields, tests/run/i6987.scala
311
+ else if (acc.field.exists && ! isRetained(acc.field)) { // It may happen for unit fields, tests/run/i6987.scala
307
312
dropped += acc.field
308
313
Nil
309
314
}
310
315
else {
311
316
val param = acc.subst(accessors, paramSyms)
312
- if (param.hasAnnotation(defn.ConstructorOnlyAnnot ))
313
- report.error(em " ${acc.name} is marked `@constructorOnly` but it is retained as a field in ${acc.owner}" , acc.srcPos)
317
+ if param.hasAnnotation(defn.ConstructorOnlyAnnot ) then
318
+ val msg = em " ${acc.name} is marked `@constructorOnly` but it is retained as a field in ${acc.owner}"
319
+ report.error(msg, acc.srcPos)
314
320
val target = if (acc.is(Method )) acc.field else acc
315
321
if (! target.exists) Nil // this case arises when the parameter accessor is an alias
316
322
else {
0 commit comments