@@ -118,7 +118,7 @@ object Semantic:
118118 end Warm
119119
120120 /** A function value */
121- case class Fun (expr : Tree , thisV : Ref , klass : ClassSymbol , env : Env ) extends Value
121+ case class Fun (expr : Tree , thisV : Ref , klass : ClassSymbol ) extends Value
122122
123123 /** A value which represents a set of addresses
124124 *
@@ -144,7 +144,7 @@ object Semantic:
144144
145145 def hasField (f : Symbol ) = fields.contains(f)
146146
147- /** The environment for method parameters
147+ /** The environment stores values for constructor parameters
148148 *
149149 * For performance and usability, we restrict parameters to be either `Cold`
150150 * or `Hot`.
@@ -162,6 +162,9 @@ object Semantic:
162162 * key. The reason is that given the same receiver, a method or function may
163163 * be called with different arguments -- they are not decided by the receiver
164164 * anymore.
165+ *
166+ * TODO: remove Env as it is only used to pass value from `callConstructor` -> `eval` -> `init`.
167+ * It goes through `eval` for caching (termination) purposes.
165168 */
166169 object Env :
167170 opaque type Env = Map [Symbol , Value ]
@@ -588,15 +591,15 @@ object Semantic:
588591 Hot
589592
590593 case fun : Fun =>
591- report.error(" unexpected tree in selecting a function, fun = " + fun.expr.show, fun.expr)
594+ report.error(" [Internal error] unexpected tree in selecting a function, fun = " + fun.expr.show, fun.expr)
592595 Hot
593596
594597 case RefSet (refs) =>
595598 refs.map(_.select(field)).join
596599 }
597600 }
598601
599- def call (meth : Symbol , args : List [ArgInfo ], receiver : Type , superType : Type , needResolve : Boolean = true ): Contextual [Value ] = log(" call " + meth.show + " , args = " + args, printer, (_ : Value ).show) {
602+ def call (meth : Symbol , args : List [ArgInfo ], receiver : Type , superType : Type , needResolve : Boolean = true ): Contextual [Value ] = log(" call " + meth.show + " , args = " + args.map(_.value.show) , printer, (_ : Value ).show) {
600603 def promoteArgs (): Contextual [Unit ] = args.foreach(_.promote)
601604
602605 def isSyntheticApply (meth : Symbol ) =
@@ -704,21 +707,19 @@ object Semantic:
704707 else
705708 value.select(target, needResolve = false )
706709
707- case Fun (body, thisV, klass, env ) =>
710+ case Fun (body, thisV, klass) =>
708711 // meth == NoSymbol for poly functions
709712 if meth.name.toString == " tupled" then value // a call like `fun.tupled`
710713 else
711714 promoteArgs()
712- withEnv(env) {
713- eval(body, thisV, klass, cacheResult = true )
714- }
715+ eval(body, thisV, klass, cacheResult = true )
715716
716717 case RefSet (refs) =>
717718 refs.map(_.call(meth, args, receiver, superType)).join
718719 }
719720 }
720721
721- def callConstructor (ctor : Symbol , args : List [ArgInfo ]): Contextual [Value ] = log(" call " + ctor.show + " , args = " + args, printer, (_ : Value ).show) {
722+ def callConstructor (ctor : Symbol , args : List [ArgInfo ]): Contextual [Value ] = log(" call " + ctor.show + " , args = " + args.map(_.value.show) , printer, (_ : Value ).show) {
722723 // init "fake" param fields for the secondary constructor
723724 def addParamsAsFields (env : Env , ref : Ref , ctorDef : DefDef ) = {
724725 val paramSyms = ctorDef.termParamss.flatten.map(_.symbol)
@@ -775,7 +776,27 @@ object Semantic:
775776 }
776777
777778 /** Handle a new expression `new p.C` where `p` is abstracted by `value` */
778- def instantiate (klass : ClassSymbol , ctor : Symbol , args : List [ArgInfo ]): Contextual [Value ] = log(" instantiating " + klass.show + " , value = " + value + " , args = " + args, printer, (_ : Value ).show) {
779+ def instantiate (klass : ClassSymbol , ctor : Symbol , args : List [ArgInfo ]): Contextual [Value ] = log(" instantiating " + klass.show + " , value = " + value + " , args = " + args.map(_.value.show), printer, (_ : Value ).show) {
780+ def tryLeak (warm : Warm , nonHotOuterClass : Symbol , argValues : List [Value ]): Contextual [Value ] =
781+ val argInfos2 = args.zip(argValues).map { (argInfo, v) => argInfo.copy(value = v) }
782+ val errors = Reporter .stopEarly {
783+ given Trace = Trace .empty
784+ warm.callConstructor(ctor, argInfos2)
785+ }
786+ if errors.nonEmpty then
787+ val indices =
788+ for
789+ (arg, i) <- argValues.zipWithIndex
790+ if arg.isCold
791+ yield
792+ i + 1
793+
794+ val error = UnsafeLeaking (trace.toVector, errors.head, nonHotOuterClass, indices)
795+ reporter.report(error)
796+ Hot
797+ else
798+ warm
799+
779800 if promoted.isCurrentObjectPromoted then Hot
780801 else value match {
781802 case Hot =>
@@ -792,9 +813,7 @@ object Semantic:
792813 else
793814 val outer = Hot
794815 val warm = Warm (klass, outer, ctor, args2).ensureObjectExists()
795- val argInfos2 = args.zip(args2).map { (argInfo, v) => argInfo.copy(value = v) }
796- warm.callConstructor(ctor, argInfos2)
797- warm
816+ tryLeak(warm, NoSymbol , args2)
798817
799818 case Cold =>
800819 val error = CallCold (ctor, trace.toVector)
@@ -810,13 +829,16 @@ object Semantic:
810829 case _ => ref
811830
812831 val argsWidened = args.map(_.value).widenArgs
813- val argInfos2 = args.zip(argsWidened).map { (argInfo, v) => argInfo.copy(value = v) }
814832 val warm = Warm (klass, outer, ctor, argsWidened).ensureObjectExists()
815- warm.callConstructor(ctor, argInfos2)
816- warm
833+ if argsWidened.exists(_.isCold) then
834+ tryLeak(warm, klass.owner.lexicallyEnclosingClass, argsWidened)
835+ else
836+ val argInfos2 = args.zip(argsWidened).map { (argInfo, v) => argInfo.copy(value = v) }
837+ warm.callConstructor(ctor, argInfos2)
838+ warm
817839
818- case Fun (body, thisV, klass, env ) =>
819- report.error(" unexpected tree in instantiating a function, fun = " + body.show, trace.toVector.last)
840+ case Fun (body, thisV, klass) =>
841+ report.error(" [Internal error] unexpected tree in instantiating a function, fun = " + body.show, trace.toVector.last)
820842 Hot
821843
822844 case RefSet (refs) =>
@@ -830,21 +852,14 @@ object Semantic:
830852 val sym = tmref.symbol
831853
832854 if sym.is(Flags .Param ) && sym.owner.isConstructor then
833- // if we can get the field from the Ref (which can only possibly be
834- // a secondary constructor parameter), then use it.
835- if (ref.objekt.hasField(sym))
836- ref.objekt.field(sym)
837- // instances of local classes inside secondary constructors cannot
838- // reach here, as those values are abstracted by Cold instead of Warm.
839- // This enables us to simplify the domain without sacrificing
840- // expressiveness nor soundess, as local classes inside secondary
841- // constructors are uncommon.
842- else if sym.isContainedIn(klass) then
843- env.lookup(sym)
844- else
845- // We don't know much about secondary constructor parameters in outer scope.
846- // It's always safe to approximate them with `Cold`.
847- Cold
855+ val enclosingClass = sym.owner.enclosingClass.asClass
856+ val thisValue2 = resolveThis(enclosingClass, ref, klass)
857+ thisValue2 match
858+ case Hot => Hot
859+ case ref : Ref => ref.objekt.field(sym)
860+ case _ =>
861+ report.error(" [Internal error] unexpected this value accessing local variable, sym = " + sym.show + " , thisValue = " + thisValue2.show, trace.toVector.last)
862+ Hot
848863 else if sym.is(Flags .Param ) then
849864 Hot
850865 else
@@ -861,7 +876,7 @@ object Semantic:
861876 case ref : Ref => eval(vdef.rhs, ref, enclosingClass)
862877
863878 case _ =>
864- report.error(" unexpected defTree when accessing local variable, sym = " + sym.show + " , defTree = " + sym.defTree .show, trace.toVector.last)
879+ report.error(" [Internal error] unexpected this value when accessing local variable, sym = " + sym.show + " , thisValue = " + thisValue2 .show, trace.toVector.last)
865880 Hot
866881 end match
867882
@@ -932,10 +947,10 @@ object Semantic:
932947 if errors.nonEmpty then promoted.remove(warm)
933948 reporter.reportAll(errors)
934949
935- case fun @ Fun (body, thisV, klass, env ) =>
950+ case fun @ Fun (body, thisV, klass) =>
936951 if ! promoted.contains(fun) then
937952 val errors = Reporter .stopEarly {
938- val res = withEnv(env) {
953+ val res = {
939954 given Trace = Trace .empty
940955 eval(body, thisV, klass)
941956 }
@@ -1120,7 +1135,7 @@ object Semantic:
11201135 args.foreach { arg =>
11211136 val res =
11221137 if arg.isByName then
1123- Fun (arg.tree, thisV, klass, env )
1138+ Fun (arg.tree, thisV, klass)
11241139 else
11251140 eval(arg.tree, thisV, klass)
11261141
@@ -1226,10 +1241,10 @@ object Semantic:
12261241 }
12271242
12281243 case closureDef(ddef) =>
1229- Fun (ddef.rhs, thisV, klass, env )
1244+ Fun (ddef.rhs, thisV, klass)
12301245
12311246 case PolyFun (body) =>
1232- Fun (body, thisV, klass, env )
1247+ Fun (body, thisV, klass)
12331248
12341249 case Block (stats, expr) =>
12351250 eval(stats, thisV, klass)
@@ -1302,8 +1317,8 @@ object Semantic:
13021317 Hot
13031318
13041319 case _ =>
1305- throw new Exception ( " unexpected tree: " + expr.show )
1306-
1320+ report.error( " [Internal error] unexpected tree" , expr)
1321+ Hot
13071322
13081323 /** Handle semantics of leaf nodes */
13091324 def cases (tp : Type , thisV : Ref , klass : ClassSymbol ): Contextual [Value ] = log(" evaluating " + tp.show, printer, (_ : Value ).show) {
@@ -1331,7 +1346,8 @@ object Semantic:
13311346 Hot
13321347
13331348 case _ =>
1334- throw new Exception (" unexpected type: " + tp)
1349+ report.error(" [Internal error] unexpected type " + tp, trace.toVector.last)
1350+ Hot
13351351 }
13361352
13371353 /** Resolve C.this that appear in `klass` */
@@ -1345,15 +1361,15 @@ object Semantic:
13451361 val obj = ref.objekt
13461362 val outerCls = klass.owner.lexicallyEnclosingClass.asClass
13471363 if ! obj.hasOuter(klass) then
1348- val error = PromoteError (" outer not yet initialized, target = " + target + " , klass = " + klass + " , object = " + obj, trace.toVector)
1349- report.error(error.show + error.stacktrace , trace.toVector.last)
1364+ val error = PromoteError (" [Internal error] outer not yet initialized, target = " + target + " , klass = " + klass + " , object = " + obj, trace.toVector)
1365+ report.error(error.show, trace.toVector.last)
13501366 Hot
13511367 else
13521368 resolveThis(target, obj.outer(klass), outerCls)
13531369 case RefSet (refs) =>
13541370 refs.map(ref => resolveThis(target, ref, klass)).join
13551371 case fun : Fun =>
1356- report.warning( " unexpected thisV = " + thisV + " , target = " + target.show + " , klass = " + klass.show, trace.toVector.last)
1372+ report.error( " [Internal error] unexpected thisV = " + thisV + " , target = " + target.show + " , klass = " + klass.show, trace.toVector.last)
13571373 Cold
13581374 case Cold => Cold
13591375
@@ -1381,14 +1397,15 @@ object Semantic:
13811397 resolveThis(target, thisV, cur)
13821398
13831399 case None =>
1384- report.warning(" unexpected outerSelect, thisV = " + thisV + " , target = " + target.show + " , hops = " + hops, trace.toVector.last.srcPos)
1400+ // TODO: use error once we fix https://github.com/lampepfl/dotty/issues/15465
1401+ report.warning(" [Internal error] unexpected outerSelect, thisV = " + thisV + " , target = " + target.show + " , hops = " + hops, trace.toVector.last.srcPos)
13851402 Cold
13861403
13871404 case RefSet (refs) =>
13881405 refs.map(ref => resolveOuterSelect(target, ref, hops)).join
13891406
13901407 case fun : Fun =>
1391- report.warning( " unexpected thisV = " + thisV + " , target = " + target.show + " , hops = " + hops, trace.toVector.last.srcPos)
1408+ report.error( " [Internal error] unexpected thisV = " + thisV + " , target = " + target.show + " , hops = " + hops, trace.toVector.last.srcPos)
13921409 Cold
13931410
13941411 case Cold => Cold
@@ -1516,6 +1533,10 @@ object Semantic:
15161533 eval(tree, thisV, klass)
15171534 }
15181535
1536+ // ensure we try promotion once even if class body is empty
1537+ if fieldsChanged && thisV.isThisRef then
1538+ thisV.asInstanceOf [ThisRef ].tryPromoteCurrentObject()
1539+
15191540 // The result value is ignored, use Hot to avoid futile fixed point computation
15201541 Hot
15211542 }
0 commit comments