Skip to content

Commit 7717c5b

Browse files
committed
Handle constructor call effects on warm objects
1 parent 3fccd63 commit 7717c5b

File tree

4 files changed

+33
-17
lines changed

4 files changed

+33
-17
lines changed

compiler/src/dotty/tools/dotc/transform/init/Checker.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ class Checker extends MiniPhase {
6262
// Checking.checkClassBody(tree)
6363

6464
import semantic._
65+
val tpl = tree.rhs.asInstanceOf[Template]
6566
val thisRef = ThisRef(cls)(fields = mutable.Map.empty)
66-
val res = semantic.init(cls, thisRef)(using ctx, Vector.empty)
67+
val res = eval(tpl, thisRef, cls)(using ctx, Vector.empty)
6768
res.errors.foreach(_.issue)
6869
}
6970

compiler/src/dotty/tools/dotc/transform/init/Semantic.scala

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,15 @@ class Semantic {
195195
resolveSuper(thisRef.klass, superType.classSymbol.asClass, meth)
196196
else
197197
resolve(thisRef.klass, meth)
198-
if target.isPrimaryConstructor then
199-
init(target.owner.asClass, thisRef)
200-
else if target.isOneOf(Flags.Method | Flags.Lazy) then
198+
if target.isOneOf(Flags.Method | Flags.Lazy) then
201199
if target.hasSource then
202-
val rhs = target.defTree.asInstanceOf[ValOrDefDef].rhs
203-
eval(rhs, thisRef, target.owner.asClass, cacheResult = true)
200+
if target.isPrimaryConstructor then
201+
val cls = target.owner.asClass
202+
val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
203+
eval(tpl, thisRef, cls, cacheResult = true)
204+
else
205+
val rhs = target.defTree.asInstanceOf[ValOrDefDef].rhs
206+
eval(rhs, thisRef, target.owner.asClass, cacheResult = true)
204207
else
205208
val error = CallUnknown(target, source, trace)
206209
Result(Hot, error :: Nil)
@@ -220,8 +223,13 @@ class Semantic {
220223
if target.is(Flags.Param) then
221224
Result(Hot, Nil)
222225
else if target.hasSource then
223-
val rhs = target.defTree.asInstanceOf[ValOrDefDef].rhs
224-
eval(rhs, warm, target.owner.asClass, cacheResult = true)
226+
if target.isPrimaryConstructor then
227+
val cls = target.owner.asClass
228+
val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
229+
eval(tpl, warm, cls, cacheResult = true)
230+
else
231+
val rhs = target.defTree.asInstanceOf[ValOrDefDef].rhs
232+
eval(rhs, warm, target.owner.asClass, cacheResult = true)
225233
else
226234
val error = CallUnknown(target, source, trace)
227235
Result(Hot, error :: Nil)
@@ -248,12 +256,16 @@ class Semantic {
248256
Result(Hot, error :: Nil)
249257

250258
case thisRef: ThisRef =>
251-
Result(Warm(klass, outer = thisRef), noErrors)
259+
val value = Warm(klass, outer = thisRef)
260+
val res = value.call(ctor, superType = NoType, source)
261+
Result(value, res.errors)
252262

253263
case warm: Warm =>
254264
// widen the outer to finitize addresses
255265
val outer = if warm.outer.isInstanceOf[Warm] then warm.copy(outer = Cold) else warm
256-
Result(Warm(klass, outer), noErrors)
266+
val value = Warm(klass, outer)
267+
val res = value.call(ctor, superType = NoType, source)
268+
Result(value, res.errors)
257269

258270
case Fun(body, thisV, klass) =>
259271
??? // impossible
@@ -333,7 +345,7 @@ class Semantic {
333345
*
334346
* This method only handles cache logic and delegates the work to `cases`.
335347
*/
336-
def eval(expr: Tree, thisV: Value, klass: ClassSymbol, cacheResult: Boolean = false)(using Context, Trace): Result = log("evaluating " + expr.show, printer, res => res.asInstanceOf[Result].show) {
348+
def eval(expr: Tree, thisV: Value, klass: ClassSymbol, cacheResult: Boolean = false)(using Context, Trace): Result = log("evaluating " + expr.show + ", this = " + thisV.show, printer, res => res.asInstanceOf[Result].show) {
337349
val cfg = Config(thisV, expr.sourcePos)
338350
if (cache.contains(cfg)) Result(cache(cfg), noErrors)
339351
else {
@@ -512,6 +524,11 @@ class Semantic {
512524
// local type definition
513525
Result(Hot, noErrors)
514526

527+
case tpl: Template =>
528+
thisV match
529+
case value: (ThisRef | Warm) => init(tpl, value, klass)
530+
case _ => ??? // impossible
531+
515532
case _: Import | _: Export =>
516533
Result(Hot, noErrors)
517534

@@ -578,11 +595,9 @@ class Semantic {
578595
cases(tref.prefix, thisV, klass, source)
579596

580597
/** Initialize part of an abstract object in `klass` of the inheritance chain */
581-
def init(klass: ClassSymbol, thisV: ThisRef)(using Context, Trace): Result = log("init " + klass.show, printer, res => res.asInstanceOf[Result].show) {
598+
def init(tpl: Template, thisV: ThisRef | Warm, klass: ClassSymbol)(using Context, Trace): Result = log("init " + klass.show, printer, res => res.asInstanceOf[Result].show) {
582599
val errorBuffer = new mutable.ArrayBuffer[Error]
583600

584-
val tpl = klass.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
585-
586601
// init param fields
587602
klass.paramAccessors.foreach { acc =>
588603
if (!acc.is(Flags.Method)) {

tests/init/neg/hybrid2.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class Y {
1313
}
1414

1515
val x = new X
16-
x.b.g // error
16+
x.b.g
1717

18-
val n = 10
18+
val n = 10 // error
1919
}

tests/init/neg/inner-loop.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
class Outer { outer =>
22
class Inner extends Outer {
3-
val x = 5 + outer.n // error
3+
val x = 5 + outer.n
44
}
55
val inner = new Inner
66
val n = 6 // error

0 commit comments

Comments
 (0)