@@ -194,16 +194,22 @@ class Semantic {
194194 import Env ._
195195
196196 object Promoted {
197+ class PromotionInfo {
198+ var isCurrentObjectPromoted : Boolean = false
199+ val values = mutable.Set .empty[Value ]
200+ }
197201 /** Values that have been safely promoted */
198- opaque type Promoted = mutable. Set [ Value ]
202+ opaque type Promoted = PromotionInfo
199203
200204 /** Note: don't use `val` to avoid incorrect sharing */
201- def empty : Promoted = mutable. Set .empty
205+ def empty : Promoted = new PromotionInfo
202206
203207 extension (promoted : Promoted )
204- def contains (value : Value ): Boolean = promoted.contains(value)
205- def add (value : Value ): Unit = promoted += value
206- def remove (value : Value ): Unit = promoted -= value
208+ def isCurrentObjectPromoted : Boolean = promoted.isCurrentObjectPromoted
209+ def promoteCurrent (thisRef : ThisRef ): Unit = promoted.isCurrentObjectPromoted = true
210+ def contains (value : Value ): Boolean = promoted.values.contains(value)
211+ def add (value : Value ): Unit = promoted.values += value
212+ def remove (value : Value ): Unit = promoted.values -= value
207213 end extension
208214 }
209215 type Promoted = Promoted .Promoted
@@ -374,6 +380,9 @@ class Semantic {
374380 def call (meth : Symbol , args : List [Value ], superType : Type , source : Tree , needResolve : Boolean = true ): Contextual [Result ] =
375381 def checkArgs = args.flatMap { arg => arg.promote(" May only use initialized value as arguments" , arg.source) }
376382
383+ // fast track if the current object is already initialized
384+ if promoted.isCurrentObjectPromoted then return Result (Hot , Nil )
385+
377386 value match {
378387 case Hot =>
379388 Result (Hot , checkArgs)
@@ -402,7 +411,7 @@ class Semantic {
402411 if target.isPrimaryConstructor then
403412 given Env = env2
404413 val tpl = cls.defTree.asInstanceOf [TypeDef ].rhs.asInstanceOf [Template ]
405- val res = eval(tpl, addr, cls, cacheResult = true )
414+ val res = use(trace.add(cls.defTree)) { eval(tpl, addr, cls, cacheResult = true ) }
406415 Result (addr, res.errors)
407416 else if target.isConstructor then
408417 given Env = env2
@@ -451,6 +460,7 @@ class Semantic {
451460 if errors.isEmpty then Hot
452461 else arg.widen
453462 }
463+
454464 if buffer.isEmpty then Result (Hot , Errors .empty)
455465 else
456466 val value = Warm (klass, Hot , ctor, args2)
@@ -496,64 +506,37 @@ class Semantic {
496506 end extension
497507
498508// ----- Promotion ----------------------------------------------------
499-
500- extension (value : Value )
501- /** Can we promote the value by checking the extrinsic values?
502- *
503- * The extrinsic values are environment values, e.g. outers for `Warm`
504- * and `thisV` captured in functions.
505- *
506- * This is a fast track for early promotion of values.
507- */
508- def canPromoteExtrinsic : Contextual [Boolean ] = log(" canPromoteExtrinsic " + value + " , promoted = " + promoted, printer) {
509- value match
510- case Hot => true
511- case Cold => false
512-
513- case warm : Warm =>
514- (warm.outer :: warm.args).forall(_.canPromoteExtrinsic) && {
515- promoted.add(warm)
516- true
517- }
518-
519- case thisRef : ThisRef =>
520- promoted.contains(thisRef) || {
521- val obj = heap(thisRef)
522- // If we have all fields initialized, then we can promote This to hot.
523- val allFieldsInitialized = thisRef.klass.appliedRef.fields.forall { denot =>
524- val sym = denot.symbol
525- sym.isOneOf(Flags .Lazy | Flags .Deferred ) || obj.fields.contains(sym)
526- }
527- if allFieldsInitialized then promoted.add(thisRef)
528- allFieldsInitialized
529- }
530-
531- case fun : Fun =>
532- fun.thisV.canPromoteExtrinsic && {
533- promoted.add(fun)
534- true
509+ extension (thisRef : ThisRef )
510+ def tryPromoteCurrentObject : Contextual [Boolean ] = log(" tryPromoteCurrentObject " , printer) {
511+ promoted.isCurrentObjectPromoted || {
512+ val obj = heap(thisRef)
513+ // If we have all fields initialized, then we can promote This to hot.
514+ val allFieldsInitialized = thisRef.klass.appliedRef.fields.forall { denot =>
515+ val sym = denot.symbol
516+ sym.isOneOf(Flags .Lazy | Flags .Deferred ) || obj.fields.contains(sym)
535517 }
536-
537- case RefSet (refs) =>
538- refs.forall(_.canPromoteExtrinsic)
539-
518+ if allFieldsInitialized then promoted.promoteCurrent(thisRef)
519+ allFieldsInitialized
520+ }
540521 }
541522
523+ extension (value : Value )
542524 /** Promotion of values to hot */
543525 def promote (msg : String , source : Tree ): Contextual [List [Error ]] = log(" promoting " + value + " , promoted = " + promoted, printer) {
544- value match
526+ if promoted.isCurrentObjectPromoted then Nil else
527+
528+ value.match
545529 case Hot => Nil
546530
547531 case Cold => PromoteError (msg, source, trace.toVector) :: Nil
548532
549533 case thisRef : ThisRef =>
550534 if promoted.contains(thisRef) then Nil
551- else if thisRef.canPromoteExtrinsic then Nil
535+ else if thisRef.tryPromoteCurrentObject then Nil
552536 else PromoteError (msg, source, trace.toVector) :: Nil
553537
554538 case warm : Warm =>
555539 if promoted.contains(warm) then Nil
556- else if warm.canPromoteExtrinsic then Nil
557540 else {
558541 promoted.add(warm)
559542 val errors = warm.tryPromote(msg, source)
@@ -902,7 +885,7 @@ class Semantic {
902885 /** Resolve C.this that appear in `klass` */
903886 def resolveThis (target : ClassSymbol , thisV : Value , klass : ClassSymbol , source : Tree ): Contextual [Value ] = log(" resolving " + target.show + " , this = " + thisV.show + " in " + klass.show, printer, res => res.asInstanceOf [Value ].show) {
904887 if target == klass then thisV
905- else if target.is(Flags .Package ) || target.isStaticOwner then Hot
888+ else if target.is(Flags .Package ) then Hot
906889 else
907890 thisV match
908891 case Hot => Hot
@@ -1005,6 +988,7 @@ class Semantic {
1005988 if ctor.exists then superCall(tref, ctor, Nil , superParent)
1006989 }
1007990
991+ var fieldsChanged = true
1008992
1009993 // class body
1010994 tpl.body.foreach {
@@ -1013,10 +997,17 @@ class Semantic {
1013997 val res = eval(vdef.rhs, thisV, klass, cacheResult = true )
1014998 errorBuffer ++= res.errors
1015999 thisV.updateField(vdef.symbol, res.value)
1000+ fieldsChanged = true
10161001
10171002 case _ : MemberDef =>
10181003
10191004 case tree =>
1005+ thisV match
1006+ case thisRef : ThisRef =>
1007+ if fieldsChanged then thisRef.tryPromoteCurrentObject
1008+ fieldsChanged = false
1009+ case _ =>
1010+
10201011 given Env = Env .empty
10211012 errorBuffer ++= eval(tree, thisV, klass).errors
10221013 }
0 commit comments