Skip to content

Commit 42b3405

Browse files
committed
Merge pull request #405 from dotty-staging/fix/class-field-initialization
Fixes to class field initialization
2 parents 8195baf + 72dd9ea commit 42b3405

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)