Skip to content

Commit 4eb3cdf

Browse files
committed
Fix environment for local class
1 parent 535e4b2 commit 4eb3cdf

File tree

1 file changed

+17
-14
lines changed

1 file changed

+17
-14
lines changed

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

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ object Objects:
162162
val joinedTrace = data.pendingTraces.slice(index + 1, data.checkingObjects.size).foldLeft(pendingTrace) { (a, acc) => acc ++ a }
163163
val callTrace = Trace.buildStacktrace(joinedTrace, "Calling trace:\n")
164164
val cycle = data.checkingObjects.slice(index, data.checkingObjects.size)
165-
val pos = clazz.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template].constr
165+
val pos = clazz.defTree
166166
report.warning("Cyclic initialization: " + cycle.map(_.show).mkString(" -> ") + " -> " + clazz.show + ". " + callTrace, pos)
167167
else if index == -1 && data.checkedObjects.indexOf(clazz) == -1 then
168168
data.pendingTraces += pendingTrace
@@ -186,12 +186,15 @@ object Objects:
186186

187187
def show(using Context): String
188188

189-
/** Local environments can be deeply nested, therefore we need `outer`. */
190-
private case class LocalEnv(private[Env] val params: Map[Symbol, Value], owner: Symbol, outer: Data)(using Context) extends Data:
189+
/** Local environments can be deeply nested, therefore we need `outer`.
190+
*
191+
* For local variables in rhs of class field definitions, the `meth` is the primary constructor.
192+
*/
193+
private case class LocalEnv(private[Env] val params: Map[Symbol, Value], meth: Symbol, outer: Data)(using Context) extends Data:
191194
val level = outer.level + 1
192195

193196
if (level > 3)
194-
report.warning("[Internal error] Deeply nested environemnt, level = " + level + ", " + owner.show + " in " + owner.enclosingClass.show, owner.defTree)
197+
report.warning("[Internal error] Deeply nested environemnt, level = " + level + ", " + meth.show + " in " + meth.enclosingClass.show, meth.defTree)
195198

196199
private[Env] val locals: mutable.Map[Symbol, Value] = mutable.Map.empty
197200

@@ -203,10 +206,10 @@ object Objects:
203206
params.contains(x) || locals.contains(x)
204207

205208
def widen(height: Int)(using Context): Data =
206-
new LocalEnv(params.map(_ -> _.widen(height)), owner, outer.widen(height))
209+
new LocalEnv(params.map(_ -> _.widen(height)), meth, outer.widen(height))
207210

208211
def show(using Context) =
209-
"owner: " + owner.show + "\n" +
212+
"owner: " + meth.show + "\n" +
210213
"params: " + params.map(_.show + " ->" + _.show).mkString("{", ", ", "}") + "\n" +
211214
"locals: " + locals.map(_.show + " ->" + _.show).mkString("{", ", ", "}") + "\n" +
212215
"outer = {\n" + outer.show + "\n}"
@@ -265,19 +268,19 @@ object Objects:
265268
* @param thisV The value for `this` of the enclosing class where the local variable is referenced.
266269
* @param env The local environment where the local variable is referenced.
267270
*/
268-
def resolveEnv(owner: Symbol, thisV: Value, env: Data)(using Context): Option[(Value, Data)] =
271+
def resolveEnv(meth: Symbol, thisV: Value, env: Data)(using Context): Option[(Value, Data)] = log("Resolving env for " + meth.show + ", this = " + thisV.show + ", env = " + env.show, printer) {
269272
env match
270273
case localEnv: LocalEnv =>
271-
if localEnv.owner == owner then Some(thisV -> env)
272-
else resolveEnv(owner, thisV, localEnv.outer)
274+
if localEnv.meth == meth then Some(thisV -> env)
275+
else resolveEnv(meth, thisV, localEnv.outer)
273276
case NoEnv =>
274277
// TODO: handle RefSet
275278
thisV match
276279
case ref: OfClass =>
277-
resolveEnv(owner, ref.outer, ref.env)
280+
resolveEnv(meth, ref.outer, ref.env)
278281
case _ =>
279282
None
280-
end resolveEnv
283+
}
281284

282285
def withEnv[T](env: Data)(fn: Data ?=> T): T = fn(using env)
283286
end Env
@@ -587,7 +590,8 @@ object Objects:
587590
if klass.owner.isClass then
588591
(outer.widen(1), Env.NoEnv)
589592
else
590-
Env.resolveEnv(klass.enclosingMethod, outer, summon[Env.Data]).getOrElse(Cold -> Env.NoEnv)
593+
// klass.enclosingMethod returns its primary constructor
594+
Env.resolveEnv(klass.owner.enclosingMethod, outer, summon[Env.Data]).getOrElse(Cold -> Env.NoEnv)
591595

592596
val instance = OfClass(klass, outerWidened, ctor, args.map(_.value), envWidened, State.currentObject)
593597
callConstructor(instance, ctor, args)
@@ -631,7 +635,6 @@ object Objects:
631635
def writeLocal(thisV: Value, sym: Symbol, value: Value): Contextual[Value] = log("write local " + sym.show + " with " + value.show, printer, (_: Value).show) {
632636

633637
assert(sym.is(Flags.Mutable), "Writing to immutable variable " + sym.show)
634-
635638
Env.resolveEnv(sym.enclosingMethod, thisV, summon[Env.Data]) match
636639
case Some(thisV -> env) =>
637640
thisV match
@@ -660,7 +663,7 @@ object Objects:
660663
def iterate()(using Context): Unit =
661664
count += 1
662665

663-
given Trace = Trace.empty.add(tpl.constr)
666+
given Trace = Trace.empty.add(classSym.defTree)
664667
given env: Env.Data = Env.emptyEnv(tpl.constr.symbol)
665668

666669
log("Iteration " + count) {

0 commit comments

Comments
 (0)