@@ -493,25 +493,31 @@ class Semantic {
493
493
end extension
494
494
495
495
// ----- Promotion ----------------------------------------------------
496
+ extension (addr : Addr )
497
+ def isFullyInitialized : Contextual [Boolean ] = log(" isFullyInitialized " + addr, printer) {
498
+ val obj = heap(addr)
499
+ addr.klass.baseClasses.forall { klass =>
500
+ ! klass.hasSource || {
501
+ val nonInits = klass.info.decls.filter { member =>
502
+ ! member.isOneOf(Flags .Method | Flags .Lazy | Flags .Deferred )
503
+ && ! member.isType
504
+ && ! obj.fields.contains(member)
505
+ }
506
+ printer.println(" nonInits = " + nonInits)
507
+ nonInits.isEmpty
508
+ }
509
+ }
510
+ }
511
+
496
512
extension (thisRef : ThisRef )
497
513
def tryPromoteCurrentObject : Contextual [Boolean ] = log(" tryPromoteCurrentObject " , printer) {
498
514
promoted.isCurrentObjectPromoted || {
499
515
val obj = heap(thisRef)
500
516
// If we have all fields initialized, then we can promote This to hot.
501
- val allFieldsInitialized = thisRef.klass.baseClasses.forall { klass =>
502
- if klass.hasSource then
503
- val nonInits = klass.info.decls.filter { member =>
504
- ! member.isOneOf(Flags .Method | Flags .Lazy | Flags .Deferred )
505
- && ! member.isType
506
- && ! obj.fields.contains(member)
507
- }
508
- nonInits.isEmpty
509
- else
510
- true
517
+ thisRef.isFullyInitialized && {
518
+ promoted.promoteCurrent(thisRef)
519
+ true
511
520
}
512
-
513
- if allFieldsInitialized then promoted.promoteCurrent(thisRef)
514
- allFieldsInitialized
515
521
}
516
522
}
517
523
@@ -574,7 +580,7 @@ class Semantic {
574
580
*/
575
581
def tryPromote (msg : String , source : Tree ): Contextual [List [Error ]] = log(" promote " + warm.show + " , promoted = " + promoted, printer) {
576
582
val classRef = warm.klass.appliedRef
577
- if classRef.memberClasses.nonEmpty then
583
+ if classRef.memberClasses.nonEmpty || ! warm.isFullyInitialized then
578
584
return PromoteError (msg, source, trace.toVector) :: Nil
579
585
580
586
val fields = classRef.fields
@@ -941,7 +947,8 @@ class Semantic {
941
947
printer.println(acc.show + " initialized with " + value)
942
948
}
943
949
944
- def superCall (tref : TypeRef , ctor : Symbol , args : List [ArgInfo ], source : Tree )(using Env ): Unit =
950
+ type Handler = (() => Unit ) => Unit
951
+ def superCall (tref : TypeRef , ctor : Symbol , args : List [ArgInfo ], source : Tree , handler : Handler )(using Env ): Unit =
945
952
val cls = tref.classSymbol.asClass
946
953
// update outer for super class
947
954
val res = outerValue(tref, thisV, klass, source)
@@ -950,44 +957,51 @@ class Semantic {
950
957
951
958
// follow constructor
952
959
if cls.hasSource then
953
- printer.println(" init super class " + cls.show)
954
- val res2 = thisV.call(ctor, args, superType = NoType , source)
955
- errorBuffer ++= res2.errors
960
+ handler { () =>
961
+ printer.println(" init super class " + cls.show)
962
+ val res2 = thisV.call(ctor, args, superType = NoType , source)
963
+ errorBuffer ++= res2.errors
964
+ }
956
965
957
966
// parents
958
- def initParent (parent : Tree )(using Env ) = parent match {
967
+ def initParent (parent : Tree , handler : Handler )(using Env ) = parent match {
959
968
case tree @ Block (stats, NewExpr (tref, New (tpt), ctor, argss)) => // can happen
960
969
eval(stats, thisV, klass).foreach { res => errorBuffer ++= res.errors }
961
970
val (erros, args) = evalArgs(argss.flatten, thisV, klass)
962
971
errorBuffer ++= erros
963
- superCall(tref, ctor, args, tree)
972
+ superCall(tref, ctor, args, tree, handler )
964
973
965
974
case tree @ NewExpr (tref, New (tpt), ctor, argss) => // extends A(args)
966
975
val (erros, args) = evalArgs(argss.flatten, thisV, klass)
967
976
errorBuffer ++= erros
968
- superCall(tref, ctor, args, tree)
977
+ superCall(tref, ctor, args, tree, handler )
969
978
970
979
case _ => // extends A or extends A[T]
971
980
val tref = typeRefOf(parent.tpe)
972
- superCall(tref, tref.classSymbol.primaryConstructor, Nil , parent)
981
+ superCall(tref, tref.classSymbol.primaryConstructor, Nil , parent, handler )
973
982
}
974
983
975
984
// see spec 5.1 about "Template Evaluation".
976
985
// https://www.scala-lang.org/files/archive/spec/2.13/05-classes-and-objects.html
977
986
if ! klass.is(Flags .Trait ) then
978
987
given Env = Env .empty
979
988
989
+ // outers are set first
990
+ val tasks = new mutable.ArrayBuffer [() => Unit ]
991
+ val handler : Handler = task => tasks.append(task)
992
+
980
993
// 1. first init parent class recursively
981
994
// 2. initialize traits according to linearization order
982
995
val superParent = tpl.parents.head
983
996
val superCls = superParent.tpe.classSymbol.asClass
984
- initParent(superParent)
997
+ initParent(superParent, handler )
985
998
986
999
val parents = tpl.parents.tail
987
1000
val mixins = klass.baseClasses.tail.takeWhile(_ != superCls)
1001
+
988
1002
mixins.reverse.foreach { mixin =>
989
1003
parents.find(_.tpe.classSymbol == mixin) match
990
- case Some (parent) => initParent(parent)
1004
+ case Some (parent) => initParent(parent, handler )
991
1005
case None =>
992
1006
// According to the language spec, if the mixin trait requires
993
1007
// arguments, then the class must provide arguments to it explicitly
@@ -998,9 +1012,12 @@ class Semantic {
998
1012
// term arguments to B. That can only be done in a concrete class.
999
1013
val tref = typeRefOf(klass.typeRef.baseType(mixin).typeConstructor)
1000
1014
val ctor = tref.classSymbol.primaryConstructor
1001
- if ctor.exists then superCall(tref, ctor, Nil , superParent)
1015
+ if ctor.exists then superCall(tref, ctor, Nil , superParent, handler )
1002
1016
}
1003
1017
1018
+ // initialize super classes after outers are set
1019
+ tasks.foreach(task => task())
1020
+
1004
1021
var fieldsChanged = true
1005
1022
1006
1023
// class body
0 commit comments