@@ -30,7 +30,7 @@ object Checking {
3030 *
3131 */
3232 case class State (
33- visited : mutable.Set [Effect ], // effects that have been expanded
33+ visited : mutable.Set [Effect ], // effects that have been checked
3434 path : Vector [Tree ], // the path that leads to the current effect
3535 thisClass : ClassSymbol , // the concrete class of `this`
3636 fieldsInited : mutable.Set [Symbol ],
@@ -41,6 +41,8 @@ object Checking {
4141 visited += eff
4242 copy(path = this .path :+ eff.source)
4343 }
44+
45+ def withOwner (sym : Symbol ): State = copy(env = env.withOwner(sym))
4446 }
4547
4648 private implicit def theEnv (implicit state : State ): Env = state.env
@@ -51,17 +53,19 @@ object Checking {
5153 * However, summarization can be done lazily on-demand to improve
5254 * performance.
5355 */
54- def checkClassBody (cdef : TypeDef )(implicit state : State ): Unit = traceOp(" checking " + cdef.symbol.show, init) {
56+ def checkClassBody (cdef : TypeDef )(implicit state : State ): Unit = {
57+ traceIndented(" \n\n >>>> checking " + cdef.symbol.show, init)
58+
5559 val cls = cdef.symbol.asClass
5660 val tpl = cdef.rhs.asInstanceOf [Template ]
5761
5862 // mark current class as initialized, required for linearization
5963 state.parentsInited += cls
6064
61- def checkClassBodyStat (tree : Tree )(using Context ): Unit = traceOp(" checking " + tree.show, init) {
65+ def checkClassBodyStat (tree : Tree )(implicit state : State ): Unit = traceOp(" checking " + tree.show, init) {
6266 tree match {
6367 case vdef : ValDef =>
64- val (pots, effs) = Summarization .analyze(vdef.rhs)(theEnv.withOwner(vdef.symbol))
68+ val (pots, effs) = Summarization .analyze(vdef.rhs)
6569 theEnv.summaryOf(cls).cacheFor(vdef.symbol, (pots, effs))
6670 if (! vdef.symbol.is(Flags .Lazy )) {
6771 checkEffectsIn(effs, cls)
@@ -79,15 +83,31 @@ object Checking {
7983 // see spec 5.1 about "Template Evaluation".
8084 // https://www.scala-lang.org/files/archive/spec/2.13/05-classes-and-objects.html
8185
82- def checkCtor (ctor : Symbol , tp : Type , source : Tree )(using Context ): Unit = {
86+ def checkConstructor (ctor : Symbol , tp : Type , source : Tree )(implicit state : State ): Unit = traceOp( " checking " + ctor.show, init) {
8387 val cls = ctor.owner
8488 val classDef = cls.defTree
8589 if (! classDef.isEmpty) {
86- if (ctor.isPrimaryConstructor) checkClassBody(classDef.asInstanceOf [TypeDef ])
87- else checkSecondaryConstructor(ctor)
90+ if (ctor.isPrimaryConstructor) checkClassBody(classDef.asInstanceOf [TypeDef ])(state.withOwner(cls))
91+ else checkSecondaryConstructor(ctor)(state.withOwner(cls))
92+ }
93+ }
94+
95+ def checkSecondaryConstructor (ctor : Symbol )(implicit state : State ): Unit = traceOp(" checking " + ctor.show, init) {
96+ val Block (ctorCall :: stats, expr) = ctor.defTree.asInstanceOf [DefDef ].rhs
97+ val cls = ctor.owner.asClass
98+
99+ traceOp(" check ctor: " + ctorCall.show, init) {
100+ val ctor = ctorCall.symbol
101+ if (ctor.isPrimaryConstructor)
102+ checkClassBody(cls.defTree.asInstanceOf [TypeDef ])
103+ else
104+ checkSecondaryConstructor(ctor)
105+ }
106+
107+ (stats :+ expr).foreach { stat =>
108+ val (_, effs) = Summarization .analyze(stat)(theEnv.withOwner(ctor))
109+ checkEffectsIn(effs, cls)
88110 }
89- else if (! cls.isOneOf(Flags .EffectivelyOpenFlags ))
90- report.warning(" Inheriting non-open class may cause initialization errors" , source.srcPos)
91111 }
92112
93113 cls.paramAccessors.foreach { acc =>
@@ -100,61 +120,42 @@ object Checking {
100120 tpl.parents.foreach {
101121 case tree @ Block (_, parent) =>
102122 val (ctor, _, _) = decomposeCall(parent)
103- checkCtor (ctor.symbol, parent.tpe, tree)
123+ checkConstructor (ctor.symbol, parent.tpe, tree)
104124
105125 case tree @ Apply (Block (_, parent), _) =>
106126 val (ctor, _, _) = decomposeCall(parent)
107- checkCtor (ctor.symbol, tree.tpe, tree)
127+ checkConstructor (ctor.symbol, tree.tpe, tree)
108128
109129 case parent : Apply =>
110130 val (ctor, _, argss) = decomposeCall(parent)
111- checkCtor (ctor.symbol, parent.tpe, parent)
131+ checkConstructor (ctor.symbol, parent.tpe, parent)
112132
113133 case ref =>
114134 val cls = ref.tpe.classSymbol.asClass
115135 if (! state.parentsInited.contains(cls) && cls.primaryConstructor.exists)
116- checkCtor (cls.primaryConstructor, ref.tpe, ref)
136+ checkConstructor (cls.primaryConstructor, ref.tpe, ref)
117137 }
118138
119139 // check class body
120140 tpl.body.foreach { checkClassBodyStat(_) }
121141 }
122142
123- def checkSecondaryConstructor (ctor : Symbol )(implicit state : State ): Unit = traceOp(" checking " + ctor.show, init) {
124- val Block (ctorCall :: stats, expr) = ctor.defTree.asInstanceOf [DefDef ].rhs
125- val cls = ctor.owner.asClass
126-
127- traceOp(" check ctor: " + ctorCall.show, init) {
128- val ctor = ctorCall.symbol
129- if (ctor.isPrimaryConstructor)
130- checkClassBody(cls.defTree.asInstanceOf [TypeDef ])
131- else
132- checkSecondaryConstructor(ctor)
133- }
134-
135- (stats :+ expr).foreach { stat =>
136- val (_, effs) = Summarization .analyze(stat)(theEnv.withOwner(ctor))
137- checkEffectsIn(effs, cls)
138- }
139- }
140-
141143 private def checkEffectsIn (effs : Effects , cls : ClassSymbol )(implicit state : State ): Unit = traceOp(" checking effects " + Effects .show(effs), init) {
142- val rebased = Effects .asSeenFrom(effs, ThisRef (state.thisClass)(null ), cls, Potentials .empty)
143144 for {
144- eff <- rebased
145+ eff <- effs
145146 error <- check(eff)
146147 } error.issue
147148 }
148149
149150 private def check (eff : Effect )(implicit state : State ): Errors =
150- if (state.visited.contains(eff)) Errors .empty else trace(" checking effect " + eff.show, init, errs => Errors .show(errs.asInstanceOf [Errors ])) {
151+ if (state.visited.contains(eff)) Errors .empty
152+ else trace(" checking effect " + eff.show, init, errs => Errors .show(errs.asInstanceOf [Errors ])) {
151153 implicit val state2 : State = state.withVisited(eff)
152154
153155 eff match {
154156 case Promote (pot) =>
155157 pot match {
156- case pot @ ThisRef (cls) =>
157- assert(cls == state.thisClass, " unexpected potential " + pot.show)
158+ case pot : ThisRef =>
158159 PromoteThis (pot, eff.source, state2.path).toErrors
159160
160161 case _ : Cold =>
@@ -180,18 +181,14 @@ object Checking {
180181 case FieldAccess (pot, field) =>
181182
182183 pot match {
183- case ThisRef (cls) =>
184- assert(cls == state.thisClass, " unexpected potential " + pot.show)
185-
186- val target = resolve(cls, field)
184+ case _ : ThisRef =>
185+ val target = resolve(state.thisClass, field)
187186 if (target.is(Flags .Lazy )) check(MethodCall (pot, target)(eff.source))
188187 else if (! state.fieldsInited.contains(target)) AccessNonInit (target, state2.path).toErrors
189188 else Errors .empty
190189
191- case SuperRef (ThisRef (cls), supercls) =>
192- assert(cls == state.thisClass, " unexpected potential " + pot.show)
193-
194- val target = resolveSuper(cls, supercls, field)
190+ case SuperRef (_ : ThisRef , supercls) =>
191+ val target = resolveSuper(state.thisClass, supercls, field)
195192 if (target.is(Flags .Lazy )) check(MethodCall (pot, target)(eff.source))
196193 else if (! state.fieldsInited.contains(target)) AccessNonInit (target, state2.path).toErrors
197194 else Errors .empty
@@ -217,10 +214,8 @@ object Checking {
217214
218215 case MethodCall (pot, sym) =>
219216 pot match {
220- case thisRef @ ThisRef (cls) =>
221- assert(cls == state.thisClass, " unexpected potential " + pot.show)
222-
223- val target = resolve(cls, sym)
217+ case thisRef : ThisRef =>
218+ val target = resolve(state.thisClass, sym)
224219 if (! target.isOneOf(Flags .Method | Flags .Lazy ))
225220 check(FieldAccess (pot, target)(eff.source))
226221 else if (target.isInternal) {
@@ -229,10 +224,8 @@ object Checking {
229224 }
230225 else CallUnknown (target, eff.source, state2.path).toErrors
231226
232- case SuperRef (thisRef @ ThisRef (cls), supercls) =>
233- assert(cls == state.thisClass, " unexpected potential " + pot.show)
234-
235- val target = resolveSuper(cls, supercls, sym)
227+ case SuperRef (thisRef : ThisRef , supercls) =>
228+ val target = resolveSuper(state.thisClass, supercls, sym)
236229 if (! target.is(Flags .Method ))
237230 check(FieldAccess (pot, target)(eff.source))
238231 else if (target.isInternal) {
@@ -272,17 +265,13 @@ object Checking {
272265 pot match {
273266 case MethodReturn (pot1, sym) =>
274267 pot1 match {
275- case thisRef @ ThisRef (cls) =>
276- assert(cls == state.thisClass, " unexpected potential " + pot.show)
277-
278- val target = resolve(cls, sym)
268+ case thisRef : ThisRef =>
269+ val target = resolve(state.thisClass, sym)
279270 if (target.isInternal) (thisRef.potentialsOf(target), Effects .empty)
280271 else Summary .empty // warning already issued in call effect
281272
282- case SuperRef (thisRef @ ThisRef (cls), supercls) =>
283- assert(cls == state.thisClass, " unexpected potential " + pot.show)
284-
285- val target = resolveSuper(cls, supercls, sym)
273+ case SuperRef (thisRef : ThisRef , supercls) =>
274+ val target = resolveSuper(state.thisClass, supercls, sym)
286275 if (target.isInternal) (thisRef.potentialsOf(target), Effects .empty)
287276 else Summary .empty // warning already issued in call effect
288277
@@ -314,17 +303,13 @@ object Checking {
314303
315304 case FieldReturn (pot1, sym) =>
316305 pot1 match {
317- case thisRef @ ThisRef (cls) =>
318- assert(cls == state.thisClass, " unexpected potential " + pot.show)
319-
320- val target = resolve(cls, sym)
306+ case thisRef : ThisRef =>
307+ val target = resolve(state.thisClass, sym)
321308 if (sym.isInternal) (thisRef.potentialsOf(target), Effects .empty)
322309 else (Cold ()(pot.source).toPots, Effects .empty)
323310
324- case SuperRef (thisRef @ ThisRef (cls), supercls) =>
325- assert(cls == state.thisClass, " unexpected potential " + pot.show)
326-
327- val target = resolveSuper(cls, supercls, sym)
311+ case SuperRef (thisRef : ThisRef , supercls) =>
312+ val target = resolveSuper(state.thisClass, supercls, sym)
328313 if (target.isInternal) (thisRef.potentialsOf(target), Effects .empty)
329314 else (Cold ()(pot.source).toPots, Effects .empty)
330315
@@ -347,19 +332,15 @@ object Checking {
347332
348333 case Outer (pot1, cls) =>
349334 pot1 match {
350- case ThisRef (cls) =>
351- assert(cls == state.thisClass, " unexpected potential " + pot.show)
352-
335+ case _ : ThisRef =>
336+ // all outers for `this` are assumed to be hot
353337 Summary .empty
354338
355339 case _ : Fun =>
356340 throw new Exception (" Unexpected code reached" )
357341
358342 case warm : Warm =>
359- (warm.outerFor(cls), Effects .empty)
360-
361- case _ : Cold =>
362- throw new Exception (" Unexpected code reached" )
343+ (warm.resolveOuter(cls), Effects .empty)
363344
364345 case _ =>
365346 val (pots, effs) = expand(pot1)
0 commit comments