@@ -56,16 +56,9 @@ import dotty.tools.dotc.util.SrcPos
56
56
* This principle not only put initialization of static objects on a solid foundation, but also
57
57
* avoids whole-program analysis.
58
58
*
59
- * 2. The design is based on the concept of "Top" --- a Top value may not be actively
60
- * used during initialization, i.e., it's forbidden to call methods or access fields of a Top.
61
- * Method arguments are widened to Top by default unless specified to be sensitive.
62
- * Method parameters captured in lambdas or inner classes are always widened to Top.
59
+ * 2. It is inter-procedural and flow-sensitive.
63
60
*
64
- * 3. It is inter-procedural and flow-sensitive.
65
- *
66
- * 4. It is object-sensitive by default and parameter-sensitive on-demand.
67
- *
68
- * 5. The check is modular in the sense that each object is checked separately and there is no
61
+ * 3. The check is modular in the sense that each object is checked separately and there is no
69
62
* whole-program analysis. However, the check is not modular in terms of project boundaries.
70
63
*
71
64
*/
@@ -91,30 +84,24 @@ class Objects(using Context @constructorOnly):
91
84
/** Syntax for the data structure abstraction used in abstract domain:
92
85
*
93
86
* ve ::= ObjectRef(class) // global object
94
- * | OfClass(class, vs[outer] , ctor, args, env) // instance of a class
95
- * | OfArray(object[owner] , regions)
96
- * | Fun(... , env) // value elements that can be contained in ValueSet
87
+ * | OfClass(class, ownerObject , ctor) // instance of a class
88
+ * | OfArray(ownerObject , regions) // represents values of native array class in Array.scala
89
+ * | Fun(code , env) // value elements that can be contained in ValueSet
97
90
* | SafeValue // values on which method calls and field accesses won't cause warnings. Int, String, etc.
91
+
10000
* | UnknownValue // values whose source are unknown at compile time
92
+ * | Package // represets a package
98
93
* vs ::= ValueSet(ve) // set of abstract values
99
94
* Bottom ::= ValueSet(Empty)
100
- * val ::= ve | Top | UnknownValue | vs | Package // all possible abstract values in domain
101
- * Ref ::= ObjectRef | OfClass // values that represent a reference to some (global or instance) object
102
- * ThisValue ::= Ref | Top // possible values for 'this'
103
- *
104
- * refMap = Ref -> ( valsMap, varsMap, outersMap ) // refMap stores field informations of an object or instance
105
- * valsMap = valsym -> val // maps immutable fields to their values
106
- * varsMap = valsym -> addr // each mutable field has an abstract address
107
- * outersMap = class -> val // maps outer objects to their values
108
- *
109
- * arrayMap = OfArray -> addr // an array has one address that stores the join value of every element
95
+ * val ::= ve | vs
96
+ * Ref ::= ObjectRef | OfClass | OfArray // values that represent a reference to some (global or instance) object
97
+ * ThisValue ::= Ref | vs // possible values for 'this'
98
+ * LocalEnv(meth, ownerObject) // represents environments for methods or functions
99
+ * Scope ::= Ref | LocalEnv
100
+ * ScopeSet ::= Set(Scope)
110
101
*
111
- * heap = addr -> val // heap is mutable
112
- *
113
- * env = (valsMap, Option[env]) // stores local variables in the residing method, and possibly outer environments
114
- *
115
- * addr ::= localVarAddr(regions, valsym, owner)
116
- * | fieldVarAddr(regions, valsym, owner) // independent of OfClass/ObjectRef
117
- * | arrayAddr(regions, owner) // independent of array element type
102
+ * valsMap = sym -> val // maps variables to their values
103
+ * outersMap = classSym -> ScopeSEt // maps the possible outer scopes for a corresponding (parent) class
104
+ * heap.MutableData = Scope -> (valsMap, outersMap) // heap is mutable
118
105
*
119
106
* regions ::= List(sourcePosition)
120
107
*/
@@ -289,6 +276,13 @@ class Objects(using Context @constructorOnly):
289
276
assert(typeSymbol.isDefined, " Invalid creation of SafeValue with type " + tpe)
290
277
new SafeValue (typeSymbol.get)
291
278
279
+ /** Represents values unknown to the checker, such as values loaded without source
280
+ * UnknownValue is not ValueElement since RefSet containing UnknownValue
281
+ * is equivalent to UnknownValue
282
+ */
283
+ case object UnknownValue extends ValueElement :
284
+ def show (using Context ): String = " UnknownValue"
285
+
292
286
/**
293
287
* Represents a set of values
294
288
*
@@ -310,29 +304,10 @@ class Objects(using Context @constructorOnly):
310
304
assert(packageSym.is(Flags .Package ), " Invalid symbol to create Package!" )
311
305
Package (packageSym.moduleClass.asClass)
312
306
313
- /** Represents values unknown to the checker, such as values loaded without source
314
- * UnknownValue is not ValueElement since RefSet containing UnknownValue
315
- * is equivalent to UnknownValue
316
- */
317
- case object UnknownValue extends Value :
318
- def show (using Context ): String = " UnknownValue"
319
-
320
- /** Represents values lost due to widening
321
- *
322
- * This is the top of the abstract domain lattice, which should not
323
- * be used during initialization.
324
- *
325
- * Top is not ValueElement since RefSet containing Top
326
- * is equivalent to Top
327
- */
328
-
329
- case object Top extends Value :
330
- def show (using Context ): String = " Top"
331
-
332
307
val Bottom = ValueSet (ListSet .empty)
333
308
334
309
/** Possible types for 'this' */
335
- type ThisValue = Ref | Top . type | ValueSet
310
+ type ThisValue = Ref | ValueSet
336
311
337
312
/** Checking state */
338
313
object State :
@@ -572,18 +547,6 @@ class Objects(using Context @constructorOnly):
572
547
/** Abstract heap for mutable fields
573
548
*/
574
549
object Heap :
575
- abstract class Addr :
576
- /** The static object which owns the mutable slot */
577
- def owner : ClassSymbol
578
- def getTrace : Trace = Trace .empty
579
-
580
- /** The address for mutable fields of objects. */
581
- private case class FieldAddr (regions : Regions .Data , field : Symbol , owner : ClassSymbol )(trace : Trace ) extends Addr :
582
- override def getTrace : Trace = trace
583
-
584
- /** The address for mutable local variables . */
585
- private case class LocalVarAddr (regions : Regions .Data , sym : Symbol , owner : ClassSymbol ) extends Addr
586
-
587
550
private case class ScopeBody (
588
551
paramsMap : Map [Symbol , Value ],
589
552
valsMap : Map [Symbol , Value ],
@@ -690,15 +653,6 @@ class Objects(using Context @constructorOnly):
690
653
def writeJoinOuter (scope : Scope , outer : Symbol , outerScope : ScopeSet )(using mutable : MutableData ): Unit =
691
654
mutable.writeJoinOuter(scope, outer, outerScope)
692
655
693
- def localVarAddr (regions : Regions .Data , sym : Symbol , owner : ClassSymbol ): Addr =
694
- LocalVarAddr (regions, sym, owner)
695
-
696
- def fieldVarAddr (regions : Regions .Data , sym : Symbol , owner : ClassSymbol )(using Trace ): Addr =
697
- FieldAddr (regions, sym, owner)(summon[Trace ])
698
-
699
- def arrayAddr (regions : Regions .Data , owner : ClassSymbol )(using Trace , Context ): Addr =
700
- FieldAddr (regions, defn.ArrayClass , owner)(summon[Trace ])
701
-
702
656
def getHeapData ()(using mutable : MutableData ): Data = mutable.heap
703
657
704
658
def setHeap (newHeap : Data )(using mutable : MutableData ): Unit = mutable.heap = newHeap
@@ -777,10 +731,6 @@ class Objects(using Context @constructorOnly):
777
731
def join (b : Value ): Value =
778
732
assert(! a.isInstanceOf [Package ] && ! b.isInstanceOf [Package ], " Unexpected join between " + a + " and " + b)
779
733
(a, b) match
780
- case (Top , _) => Top
781
- case (_, Top ) => Top
782
- case (UnknownValue , _) => UnknownValue
783
- case (_, UnknownValue ) => UnknownValue
784
734
case (Bottom , b) => b
785
735
case (a, Bottom ) => a
786
736
case (ValueSet (values1), ValueSet (values2)) => ValueSet (values1 ++ values2)
@@ -813,7 +763,7 @@ class Objects(using Context @constructorOnly):
813
763
else
814
764
val klass = sym.asClass
815
765
a match
816
- case UnknownValue | Top => a
766
+ case UnknownValue => a
817
767
case Package (packageModuleClass) =>
818
768
// the typer might mistakenly set the receiver to be a package instead of package object.
819
769
// See pos/packageObjectStringInterpolator.scala
@@ -844,8 +794,6 @@ class Objects(using Context @constructorOnly):
844
794
else
845
795
scopes.reduce { (s1, s2) => s1.join(s2) }
846
796
847
- // def widen(height: Int): Contextual[List[V]] = values.map(_.widen(height)).toList
848
-
849
797
extension [V : Join ](map : Map [Symbol , V ])
850
798
def join (sym : Symbol , value : V ): Map [Symbol , V ] =
851
799
if ! map.contains(sym) then map.updated(sym, value)
@@ -873,9 +821,6 @@ class Objects(using Context @constructorOnly):
873
821
*/
874
822
def call (value : Value , meth : Symbol , args : List [ArgInfo ], receiver : Type , superType : Type , needResolve : Boolean = true ): Contextual [Value ] = log(" call " + meth.show + " , this = " + value.show + " , args = " + args.map(_.value.show), printer, (_ : Value ).show) {
875
823
value.filterClass(meth.owner) match
876
- case Top =>
877
- report.warning(" Value is unknown to the checker due to widening. " + Trace .show, Trace .position)
878
- Bottom
879
824
case UnknownValue =>
880
825
reportWarningForUnknownValue(" Using unknown value. " + Trace .show, Trace .position)
881
826
@@ -1084,9 +1029,6 @@ class Objects(using Context @constructorOnly):
1084
1029
*/
1085
1030
def select (value : Value , field : Symbol , receiver : Type , needResolve : Boolean = true ): Contextual [Value ] = log(" select " + field.show + " , this = " + value.show, printer, (_ : Value ).show) {
1086
1031
value.filterClass(field.owner) match
1087
- case Top =>
1088
- report.warning(" Value is unknown to the checker due to widening. " + Trace .show, Trace .position)
1089
- Bottom
1090
1032
case UnknownValue =>
1091
1033
reportWarningForUnknownValue(" Using unknown value. " + Trace .show, Trace .position)
1092
1034
@@ -1171,8 +1113,6 @@ class Objects(using Context @constructorOnly):
1171
1113
*/
1172
1114
def assign (lhs : Value , field : Symbol , rhs : Value , rhsTyp : Type ): Contextual [Value ] = log(" Assign" + field.show + " of " + lhs.show + " , rhs = " + rhs.show, printer, (_ : Value ).show) {
1173
1115
lhs.filterClass(field.owner) match
1174
- case Top =>
1175
- report.warning(" Value is unknown to the checker due to widening. " + Trace .show, Trace .position)
1176
1116
case UnknownValue =>
1177
1117
val _ = reportWarningForUnknownValue(" Assigning to unknown value. " + Trace .show, Trace .position)
1178
1118
case p : Package =>
@@ -1220,7 +1160,7 @@ class Objects(using Context @constructorOnly):
1220
1160
case UnknownValue =>
1221
1161
reportWarningForUnknownValue(" Instantiating when outer is unknown. " + Trace .show, Trace .position)
1222
1162
1223
- case outer : (Ref | Top . type | Package ) =>
1163
+ case outer : (Ref | Package ) =>
1224
1164
if klass == defn.ArrayClass then
1225
1165
args.head.tree.tpe match
1226
1166
case ConstantType (Constants .Constant (0 )) =>
@@ -1246,7 +1186,7 @@ class Objects(using Context @constructorOnly):
1246
1186
if enclosingMethod == outerCls.primaryConstructor then
1247
1187
ScopeSet (Set (thisV.asInstanceOf [Ref ]))
1248
1188
else
1249
- Env .resolveEnvByMethod(klass.owner.enclosingMethod, thisV, summon[Scope ]).getOrElse(Top -> Env .NoEnv )._2
1189
+ Env .resolveEnvByMethod(klass.owner.enclosingMethod, thisV, summon[Scope ]).getOrElse(UnknownValue -> Env .NoEnv )._2
1250
1190
1251
1191
val instance = OfClass (klass, envWidened, ctor)
1252
1192
callConstructor(instance, ctor, args)
@@ -1280,9 +1220,6 @@ class Objects(using Context @constructorOnly):
1280
1220
eval(fun.code, fun.thisV, fun.klass)
1281
1221
case UnknownValue =>
1282
1222
reportWarningForUnknownValue(" Calling on unknown value. " + Trace .show, Trace .position)
1283
- case Top =>
1284
- report.warning(" Calling on value lost due to widening. " + Trace .show, Trace .position)
1285
- Bottom
1286
1223
case Bottom => Bottom
1287
1224
case ValueSet (values) if values.size == 1 =>
1288
1225
evalByNameParam(values.head)
@@ -2073,7 +2010,6 @@ class Objects(using Context @constructorOnly):
2073
2010
else accessObject(target)
2074
2011
else
2075
2012
thisV match
2076
- case Top => Top
2077
2013
case Bottom => Bottom
2078
2014
case ref : Ref =>
2079
2015
recur(ScopeSet (Set (ref)))
0 commit comments