@@ -7,6 +7,7 @@ import Contexts._
7
7
import Symbols ._
8
8
import Types ._
9
9
import StdNames ._
10
+ import NameKinds .OuterSelectName
10
11
11
12
import ast .tpd ._
12
13
import util .EqHashMap
@@ -27,24 +28,20 @@ class Semantic {
27
28
* Value = Hot | Cold | Warm | ThisRef | Fun | RefSet
28
29
*
29
30
* Cold
30
- * ┌──────► ▲ ◄ ──┐ ◄────┐
31
- * │ │ │ │
32
- * │ │ │ │
33
- * ThisRef(C) │ │ │
34
- * ▲ │ │ │
35
- * │ Warm(D) Fun RefSet
36
- * │ ▲ ▲ ▲
37
- * │ │ │ │
38
- * Warm(C) │ │ │
39
- * ▲ │ │ │
40
- * │ │ │ │
41
- * └─────────┴──────┴───────┘
31
+ * ┌──────► ▲ ◄── ──┐ ◄────┐
32
+ * │ │ │ │
33
+ * │ │ │ │
34
+ * | │ │ │
35
+ * | │ │ │
36
+ * ThisRef(C) Warm(D) Fun RefSet
37
+ * │ ▲ ▲ ▲
38
+ * │ │ │ │
39
+ * | │ │ │
40
+ * ▲ │ │ │
41
+ * │ │ │ │
42
+ * └─────────┴─────── ┴───────┘
42
43
* Hot
43
44
*
44
- * The most important ordering is the following:
45
- *
46
- * Hot ⊑ Warm(C) ⊑ ThisRef(C) ⊑ Cold
47
- *
48
45
* The diagram above does not reflect relationship between `RefSet`
49
46
* and other values. `RefSet` represents a set of values which could
50
47
* be `ThisRef`, `Warm` or `Fun`. The following ordering applies for
@@ -194,6 +191,7 @@ class Semantic {
194
191
class PromotionInfo {
195
192
var isCurrentObjectPromoted : Boolean = false
196
193
val values = mutable.Set .empty[Value ]
194
+ override def toString (): String = values.toString()
197
195
}
198
196
/** Values that have been safely promoted */
199
197
opaque type Promoted = PromotionInfo
@@ -300,9 +298,6 @@ class Semantic {
300
298
case (Cold , _) => Cold
301
299
case (_, Cold ) => Cold
302
300
303
- case (a : Warm , b : ThisRef ) if a.klass == b.klass => b
304
- case (a : ThisRef , b : Warm ) if a.klass == b.klass => a
305
-
306
301
case (a : (Fun | Warm | ThisRef ), b : (Fun | Warm | ThisRef )) => RefSet (a :: b :: Nil )
307
302
308
303
case (a : (Fun | Warm | ThisRef ), RefSet (refs)) => RefSet (a :: refs)
@@ -495,6 +490,46 @@ class Semantic {
495
490
Result (value2, errors)
496
491
}
497
492
}
493
+
494
+ def accessLocal (tmref : TermRef , klass : ClassSymbol , source : Tree ): Contextual [Result ] =
495
+ val sym = tmref.symbol
496
+
497
+ def default () = Result (Hot , Nil )
498
+
499
+ if sym.is(Flags .Param ) && sym.owner.isConstructor then
500
+ // instances of local classes inside secondary constructors cannot
501
+ // reach here, as those values are abstracted by Cold instead of Warm.
502
+ // This enables us to simplify the domain without sacrificing
503
+ // expressiveness nor soundess, as local classes inside secondary
504
+ // constructors are uncommon.
505
+ if sym.isContainedIn(klass) then
506
+ Result (env.lookup(sym), Nil )
507
+ else
508
+ // We don't know much about secondary constructor parameters in outer scope.
509
+ // It's always safe to approximate them with `Cold`.
510
+ Result (Cold , Nil )
511
+ else if sym.is(Flags .Param ) then
512
+ default()
513
+ else
514
+ sym.defTree match {
515
+ case vdef : ValDef =>
516
+ // resolve this for local variable
517
+ val enclosingClass = sym.owner.enclosingClass.asClass
518
+ val thisValue2 = resolveThis(enclosingClass, value, klass, source)
519
+ thisValue2 match {
520
+ case Hot => Result (Hot , Errors .empty)
521
+
522
+ case Cold => Result (Cold , Nil )
523
+
524
+ case addr : Addr => eval(vdef.rhs, addr, klass)
525
+
526
+ case _ =>
527
+ report.error(" unexpected defTree when accessing local variable, sym = " + sym.show + " , defTree = " + sym.defTree.show, source)
528
+ default()
529
+ }
530
+
531
+ case _ => default()
532
+ }
498
533
end extension
499
534
500
535
// ----- Promotion ----------------------------------------------------
@@ -756,7 +791,15 @@ class Semantic {
756
791
res.call(id.symbol, args, superType = NoType , source = expr)
757
792
758
793
case Select (qualifier, name) =>
759
- eval(qualifier, thisV, klass).select(expr.symbol, expr)
794
+ val qualRes = eval(qualifier, thisV, klass)
795
+
796
+ name match
797
+ case OuterSelectName (_, hops) =>
798
+ val SkolemType (tp) = expr.tpe
799
+ val outer = resolveOuterSelect(tp.classSymbol.asClass, qualRes.value, hops, source = expr)
800
+ Result (outer, qualRes.errors)
801
+ case _ =>
802
+ qualRes.select(expr.symbol, expr)
760
803
761
804
case _ : This =>
762
805
cases(expr.tpe, thisV, klass, expr)
@@ -846,7 +889,7 @@ class Semantic {
846
889
case vdef : ValDef =>
847
890
// local val definition
848
891
// TODO: support explicit @cold annotation for local definitions
849
- eval(vdef.rhs, thisV, klass).ensureHot( " Local definitions may only hold initialized values " , vdef )
892
+ eval(vdef.rhs, thisV, klass, cacheResult = true )
850
893
851
894
case ddef : DefDef =>
852
895
// local method
@@ -874,24 +917,7 @@ class Semantic {
874
917
Result (Hot , Errors .empty)
875
918
876
919
case tmref : TermRef if tmref.prefix == NoPrefix =>
877
- val sym = tmref.symbol
878
-
879
- def default () = Result (Hot , Nil )
880
-
881
- if sym.is(Flags .Param ) && sym.owner.isConstructor then
882
- // instances of local classes inside secondary constructors cannot
883
- // reach here, as those values are abstracted by Cold instead of Warm.
884
- // This enables us to simplify the domain without sacrificing
885
- // expressiveness nor soundess, as local classes inside secondary
886
- // constructors are uncommon.
887
- if sym.isContainedIn(klass) then
888
- Result (env.lookup(sym), Nil )
889
- else
890
- // We don't know much about secondary constructor parameters in outer scope.
891
- // It's always safe to approximate them with `Cold`.
892
- Result (Cold , Nil )
893
- else
894
- default()
920
+ thisV.accessLocal(tmref, klass, source)
895
921
896
922
case tmref : TermRef =>
897
923
cases(tmref.prefix, thisV, klass, source).select(tmref.symbol, source)
@@ -939,6 +965,40 @@ class Semantic {
939
965
940
966
}
941
967
968
+ /** Resolve outer select introduced during inlining.
969
+ *
970
+ * See `tpd.outerSelect` and `ElimOuterSelect`.
971
+ */
972
+ def resolveOuterSelect (target : ClassSymbol , thisV : Value , hops : Int , source : Tree ): Contextual [Value ] = log(" resolving outer " + target.show + " , this = " + thisV.show + " , hops = " + hops, printer, res => res.asInstanceOf [Value ].show) {
973
+ // Is `target` reachable from `cls` with the given `hops`?
974
+ def reachable (cls : ClassSymbol , hops : Int ): Boolean =
975
+ if hops == 0 then cls == target
976
+ else reachable(cls.lexicallyEnclosingClass.asClass, hops - 1 )
977
+
978
+ thisV match
979
+ case Hot => Hot
980
+
981
+ case addr : Addr =>
982
+ val obj = heap(addr)
983
+ val curOpt = obj.klass.baseClasses.find(cls => reachable(cls, hops))
984
+ curOpt match
985
+ case Some (cur) =>
986
+ resolveThis(target, thisV, cur, source)
987
+
988
+ case None =>
989
+ report.warning(" unexpected outerSelect, thisV = " + thisV + " , target = " + target.show + " , hops = " + hops, source.srcPos)
990
+ Cold
991
+
992
+ case RefSet (refs) =>
993
+ refs.map(ref => resolveOuterSelect(target, ref, hops, source)).join
994
+
995
+ case fun : Fun =>
996
+ report.warning(" unexpected thisV = " + thisV + " , target = " + target.show + " , hops = " + hops, source.srcPos)
997
+ Cold
998
+
999
+ case Cold => Cold
1000
+ }
1001
+
942
1002
/** Compute the outer value that correspond to `tref.prefix` */
943
1003
def outerValue (tref : TypeRef , thisV : Addr , klass : ClassSymbol , source : Tree ): Contextual [Result ] =
944
1004
val cls = tref.classSymbol.asClass
0 commit comments