@@ -321,7 +321,7 @@ class Semantic {
321321
322322 case warm : Warm =>
323323 if warm.outer.canDirectlyPromote then Nil
324- else PromoteWarm (source, trace) :: Nil
324+ else warm.tryPromote(msg, source)
325325
326326 case Fun (body, thisV, klass) =>
327327 val res = eval(body, thisV, klass)
@@ -335,6 +335,48 @@ class Semantic {
335335 refs.flatMap(_.promote(msg, source))
336336 end extension
337337
338+ extension (warm : Warm )
339+ /** Try early promotion of warm objects
340+ *
341+ * Promotion is expensive and should only be performed for small classes.
342+ *
343+ * 1. for each concrete method `m` of the warm object:
344+ * call the method and promote the result
345+ *
346+ * 2. for each concrete field `f` of the warm object:
347+ * promote the field value
348+ *
349+ */
350+ def tryPromote (msg : String , source : Tree )(using Context , Trace ): List [Error ] =
351+ val classRef = warm.klass.appliedRef
352+ if classRef.memberClasses.nonEmpty then
353+ return PromoteWarm (source, trace) :: Nil
354+
355+ val fields = classRef.fields
356+ val methods = classRef.membersBasedOnFlags(Flags .Method , Flags .Deferred | Flags .Accessor )
357+ val buffer = new mutable.ArrayBuffer [Error ]
358+
359+ fields.exists { denot =>
360+ val f = denot.symbol
361+ if ! f.isOneOf(Flags .Deferred | Flags .Private | Flags .Protected ) && f.hasSource then
362+ val res = warm.select(f, source)
363+ buffer ++= res.ensureHot(msg, source).errors
364+ buffer.nonEmpty
365+ }
366+
367+ buffer.nonEmpty || methods.exists { denot =>
368+ val m = denot.symbol
369+ if ! m.isConstructor && m.hasSource then
370+ val res = warm.call(m, superType = m.owner.typeRef, source = source)
371+ buffer ++= res.ensureHot(msg, source).errors
372+ buffer.nonEmpty
373+ }
374+
375+ if buffer.isEmpty then Nil
376+ else UnsafePromotion (source, trace, buffer.toList) :: Nil
377+
378+ end extension
379+
338380 extension (ref : ThisRef | Warm )
339381 def updateField (field : Symbol , value : Value ): Unit =
340382 ref match
@@ -669,7 +711,7 @@ class Semantic {
669711 // class body
670712 tpl.body.foreach {
671713 case vdef : ValDef if ! vdef.symbol.is(Flags .Lazy ) =>
672- val res = eval(vdef.rhs, thisV, klass)
714+ val res = eval(vdef.rhs, thisV, klass, cacheResult = true )
673715 errorBuffer ++= res.errors
674716 thisV.updateField(vdef.symbol, res.value)
675717
0 commit comments