@@ -118,7 +118,7 @@ object Semantic:
118
118
end Warm
119
119
120
120
/** 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
122
122
123
123
/** A value which represents a set of addresses
124
124
*
@@ -144,7 +144,7 @@ object Semantic:
144
144
145
145
def hasField (f : Symbol ) = fields.contains(f)
146
146
147
- /** The environment for method parameters
147
+ /** The environment stores values for constructor parameters
148
148
*
149
149
* For performance and usability, we restrict parameters to be either `Cold`
150
150
* or `Hot`.
@@ -162,6 +162,9 @@ object Semantic:
162
162
* key. The reason is that given the same receiver, a method or function may
163
163
* be called with different arguments -- they are not decided by the receiver
164
164
* 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.
165
168
*/
166
169
object Env :
167
170
opaque type Env = Map [Symbol , Value ]
@@ -588,15 +591,15 @@ object Semantic:
588
591
Hot
589
592
590
593
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)
592
595
Hot
593
596
594
597
case RefSet (refs) =>
595
598
refs.map(_.select(field)).join
596
599
}
597
600
}
598
601
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) {
600
603
def promoteArgs (): Contextual [Unit ] = args.foreach(_.promote)
601
604
602
605
def isSyntheticApply (meth : Symbol ) =
@@ -704,21 +707,19 @@ object Semantic:
704
707
else
705
708
value.select(target, needResolve = false )
706
709
707
- case Fun (body, thisV, klass, env ) =>
710
+ case Fun (body, thisV, klass) =>
708
711
// meth == NoSymbol for poly functions
709
712
if meth.name.toString == " tupled" then value // a call like `fun.tupled`
710
713
else
711
714
promoteArgs()
712
- withEnv(env) {
713
- eval(body, thisV, klass, cacheResult = true )
714
- }
715
+ eval(body, thisV, klass, cacheResult = true )
715
716
716
717
case RefSet (refs) =>
717
718
refs.map(_.call(meth, args, receiver, superType)).join
718
719
}
719
720
}
720
721
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) {
722
723
// init "fake" param fields for the secondary constructor
723
724
def addParamsAsFields (env : Env , ref : Ref , ctorDef : DefDef ) = {
724
725
val paramSyms = ctorDef.termParamss.flatten.map(_.symbol)
@@ -775,7 +776,27 @@ object Semantic:
775
776
}
776
777
777
778
/** 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
+
779
800
if promoted.isCurrentObjectPromoted then Hot
780
801
else value match {
781
802
case Hot =>
@@ -792,9 +813,7 @@ object Semantic:
792
813
else
793
814
val outer = Hot
794
815
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)
798
817
799
818
case Cold =>
800
819
val error = CallCold (ctor, trace.toVector)
@@ -810,13 +829,16 @@ object Semantic:
810
829
case _ => ref
811
830
812
831
val argsWidened = args.map(_.value).widenArgs
813
- val argInfos2 = args.zip(argsWidened).map { (argInfo, v) => argInfo.copy(value = v) }
814
832
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
817
839
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)
820
842
Hot
821
843
822
844
case RefSet (refs) =>
@@ -830,21 +852,14 @@ object Semantic:
830
852
val sym = tmref.symbol
831
853
832
854
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
848
863
else if sym.is(Flags .Param ) then
849
864
Hot
850
865
else
@@ -861,7 +876,7 @@ object Semantic:
861
876
case ref : Ref => eval(vdef.rhs, ref, enclosingClass)
862
877
863
878
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)
865
880
Hot
866
881
end match
867
882
@@ -932,10 +947,10 @@ object Semantic:
932
947
if errors.nonEmpty then promoted.remove(warm)
933
948
reporter.reportAll(errors)
934
949
935
- case fun @ Fun (body, thisV, klass, env ) =>
950
+ case fun @ Fun (body, thisV, klass) =>
936
951
if ! promoted.contains(fun) then
937
952
val errors = Reporter .stopEarly {
938
- val res = withEnv(env) {
953
+ val res = {
939
954
given Trace = Trace .empty
940
955
eval(body, thisV, klass)
941
956
}
@@ -1120,7 +1135,7 @@ object Semantic:
1120
1135
args.foreach { arg =>
1121
1136
val res =
1122
1137
if arg.isByName then
1123
- Fun (arg.tree, thisV, klass, env )
1138
+ Fun (arg.tree, thisV, klass)
1124
1139
else
1125
1140
eval(arg.tree, thisV, klass)
1126
1141
@@ -1226,10 +1241,10 @@ object Semantic:
1226
1241
}
1227
1242
1228
1243
case closureDef(ddef) =>
1229
- Fun (ddef.rhs, thisV, klass, env )
1244
+ Fun (ddef.rhs, thisV, klass)
1230
1245
1231
1246
case PolyFun (body) =>
1232
- Fun (body, thisV, klass, env )
1247
+ Fun (body, thisV, klass)
1233
1248
1234
1249
case Block (stats, expr) =>
1235
1250
eval(stats, thisV, klass)
@@ -1302,8 +1317,8 @@ object Semantic:
1302
1317
Hot
1303
1318
1304
1319
case _ =>
1305
- throw new Exception ( " unexpected tree: " + expr.show )
1306
-
1320
+ report.error( " [Internal error] unexpected tree" , expr)
1321
+ Hot
1307
1322
1308
1323
/** Handle semantics of leaf nodes */
1309
1324
def cases (tp : Type , thisV : Ref , klass : ClassSymbol ): Contextual [Value ] = log(" evaluating " + tp.show, printer, (_ : Value ).show) {
@@ -1331,7 +1346,8 @@ object Semantic:
1331
1346
Hot
1332
1347
1333
1348
case _ =>
1334
- throw new Exception (" unexpected type: " + tp)
1349
+ report.error(" [Internal error] unexpected type " + tp, trace.toVector.last)
1350
+ Hot
1335
1351
}
1336
1352
1337
1353
/** Resolve C.this that appear in `klass` */
@@ -1345,15 +1361,15 @@ object Semantic:
1345
1361
val obj = ref.objekt
1346
1362
val outerCls = klass.owner.lexicallyEnclosingClass.asClass
1347
1363
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)
1350
1366
Hot
1351
1367
else
1352
1368
resolveThis(target, obj.outer(klass), outerCls)
1353
1369
case RefSet (refs) =>
1354
1370
refs.map(ref => resolveThis(target, ref, klass)).join
1355
1371
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)
1357
1373
Cold
1358
1374
case Cold => Cold
1359
1375
@@ -1381,14 +1397,15 @@ object Semantic:
1381
1397
resolveThis(target, thisV, cur)
1382
1398
1383
1399
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)
1385
1402
Cold
1386
1403
1387
1404
case RefSet (refs) =>
1388
1405
refs.map(ref => resolveOuterSelect(target, ref, hops)).join
1389
1406
1390
1407
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)
1392
1409
Cold
1393
1410
1394
1411
case Cold => Cold
@@ -1516,6 +1533,10 @@ object Semantic:
1516
1533
eval(tree, thisV, klass)
1517
1534
}
1518
1535
1536
+ // ensure we try promotion once even if class body is empty
1537
+ if fieldsChanged && thisV.isThisRef then
1538
+ thisV.asInstanceOf [ThisRef ].tryPromoteCurrentObject()
1539
+
1519
1540
// The result value is ignored, use Hot to avoid futile fixed point computation
1520
1541
Hot
1521
1542
}
0 commit comments