Skip to content

Commit 72dd9ea

Browse files
committed
Fixes to class field initialization
Class fields were not initialized from constructor parameters before. This is now fixed. The fix uncovered some problems with the treatement of outer parameters which are now also corrected.
1 parent 8195baf commit 72dd9ea

File tree

4 files changed

+38
-19
lines changed

4 files changed

+38
-19
lines changed

src/dotty/tools/dotc/transform/Constructors.scala

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Types._
1717
import Decorators._
1818
import DenotTransformers._
1919
import util.Positions._
20+
import Constants.Constant
2021
import collection.mutable
2122

2223
/** This transform
@@ -64,20 +65,13 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor
6465

6566
// Produce aligned accessors and constructor parameters. We have to adjust
6667
// for any outer parameters, which are last in the sequence of original
67-
// parameter accessors but should come first in the constructor parameter list.
68-
var accessors = cls.paramAccessors.filterNot(_.isSetter)
69-
var vparamsWithOuter = vparams
70-
if (!accessors.hasSameLengthAs(vparams)) {
71-
accessors.reverse match {
72-
case last :: _ if (last.name == nme.OUTER) =>
73-
accessors = last :: accessors.init // align wth calling convention
74-
vparamsWithOuter = ValDef(last.asTerm) :: vparams
75-
case _ =>
76-
}
77-
assert(accessors.hasSameLengthAs(vparamsWithOuter),
78-
i"lengths differ for $cls, param accs = $accessors, params = ($vparamsWithOuter%, %)")
68+
// parameter accessors but come first in the constructor parameter list.
69+
val accessors = cls.paramAccessors.filterNot(_.isSetter)
70+
val vparamsWithOuterLast = vparams match {
71+
case vparam :: rest if vparam.name == nme.OUTER => rest ::: vparam :: Nil
72+
case _ => vparams
7973
}
80-
val paramSyms = vparamsWithOuter map (_.symbol)
74+
val paramSyms = vparamsWithOuterLast map (_.symbol)
8175

8276
// Adjustments performed when moving code into the constructor:
8377
// (1) Replace references to param accessors by constructor parameters
@@ -179,11 +173,27 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor
179173
}
180174
splitStats(tree.body)
181175

182-
val accessorFields = accessors.filterNot(_ is Method)
183-
184176
// The initializers for the retained accessors */
185-
val copyParams = accessorFields.filter(isRetained).map(acc =>
186-
Assign(ref(acc), ref(acc.subst(accessors, paramSyms))).withPos(tree.pos))
177+
val copyParams = accessors flatMap { acc =>
178+
if (!isRetained(acc)) Nil
179+
else {
180+
val target = if (acc.is(Method)) acc.field else acc
181+
if (!target.exists) Nil // this case arises when the parameter accessor is an alias
182+
else {
183+
val param = acc.subst(accessors, paramSyms)
184+
val assigns = Assign(ref(target), ref(param)).withPos(tree.pos) :: Nil
185+
if (acc.name != nme.OUTER) assigns
186+
else {
187+
// insert test: if ($outer eq null) throw new NullPointerException
188+
val nullTest =
189+
If(ref(param).select(defn.Object_eq).appliedTo(Literal(Constant(null))),
190+
Throw(New(defn.NullPointerExceptionClass.typeRef, Nil)),
191+
unitLiteral)
192+
nullTest :: assigns
193+
}
194+
}
195+
}
196+
}
187197

188198
// Drop accessors that are not retained from class scope
189199
val dropped = usage.dropped

src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ object Erasure extends TypeTestsCasts{
419419
val restpe = sym.info.resultType
420420
val ddef1 = untpd.cpy.DefDef(ddef)(
421421
tparams = Nil,
422-
vparamss = ddef.vparamss.flatten :: Nil,
422+
vparamss = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil,
423423
tpt = untpd.TypedSplice(TypeTree(restpe).withPos(ddef.tpt.pos)),
424424
rhs = ddef.rhs match {
425425
case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe))

src/dotty/tools/dotc/transform/ExplicitOuter.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,5 +297,14 @@ object ExplicitOuter {
297297
case ex: ClassCastException =>
298298
throw new ClassCastException(i"no path exists from ${ctx.owner.enclosingClass} to $toCls")
299299
}
300+
301+
/** The outer parameter definition of a constructor if it needs one */
302+
def paramDefs(constr: Symbol): List[ValDef] =
303+
if (constr.isConstructor && hasOuterParam(constr.owner.asClass)) {
304+
val MethodType(outerName :: _, outerType :: _) = constr.info
305+
val outerSym = ctx.newSymbol(constr, outerName, Param, outerType)
306+
ValDef(outerSym) :: Nil
307+
}
308+
else Nil
300309
}
301310
}

src/dotty/tools/dotc/transform/Memoize.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import Decorators._
3636

3737
override def phaseName = "memoize"
3838

39-
/** Should to run after mixin so that fields get generated in the
39+
/** Should run after mixin so that fields get generated in the
4040
* class that contains the concrete getter rather than the trait
4141
* that defines it.
4242
*/

0 commit comments

Comments
 (0)