@@ -18,6 +18,7 @@ import util.{ SourcePosition, NoSourcePosition }
18
18
import config .Printers .init as printer
19
19
import reporting .StoreReporter
20
20
import reporting .trace as log
21
+ import reporting .trace .force as forcelog
21
22
import typer .Applications .*
22
23
23
24
import Errors .*
@@ -91,6 +92,7 @@ class Objects(using Context @constructorOnly):
91
92
* ve ::= ObjectRef(class) // global object
92
93
* | OfClass(class, vs[outer], ctor, args, env) // instance of a class
93
94
* | OfArray(object[owner], regions)
95
+ * | BaseOrUnknownValue // Int, String, etc., and values without source
94
96
* | Fun(..., env) // value elements that can be contained in ValueSet
95
97
* vs ::= ValueSet(ve) // set of abstract values
96
98
* Bottom ::= ValueSet(Empty)
@@ -233,6 +235,11 @@ class Objects(using Context @constructorOnly):
233
235
case class ValueSet (values : ListSet [ValueElement ]) extends Value :
234
236
def show (using Context ) = values.map(_.show).mkString(" [" , " ," , " ]" )
235
237
238
+ // Represents common base values like Int, String, etc.
239
+ // and also values loaded without source
240
+ case object BaseOrUnknownValue extends ValueElement :
241
+ def show (using Context ): String = " BaseOrUnknownValue"
242
+
236
243
/** A cold alias which should not be used during initialization.
237
244
*
238
245
* Cold is not ValueElement since RefSet containing Cold is equivalent to Cold
@@ -636,12 +643,15 @@ class Objects(using Context @constructorOnly):
636
643
if baseClasses.isEmpty then a
637
644
else filterClass(baseClasses.head) // could have called ClassSymbol, but it does not handle OrType and AndType
638
645
646
+ // Filter the value according to a class symbol, and only leaves the sub-values
647
+ // which could represent an object of the given class
639
648
def filterClass (sym : Symbol )(using Context ): Value =
640
649
if ! sym.isClass then a
641
650
else
642
651
val klass = sym.asClass
643
652
a match
644
653
case Cold => Cold
654
+ case BaseOrUnknownValue => BaseOrUnknownValue
645
655
case ref : Ref => if ref.klass.isSubClass(klass) then ref else Bottom
646
656
case ValueSet (values) => values.map(v => v.filterClass(klass)).join
647
657
case arr : OfArray => if defn.ArrayClass .isSubClass(klass) then arr else Bottom
@@ -674,6 +684,13 @@ class Objects(using Context @constructorOnly):
674
684
case Bottom =>
675
685
Bottom
676
686
687
+ // Bottom arguments mean unreachable call
688
+ case _ if args.map(_.value).contains(Bottom ) =>
689
+ Bottom
690
+
691
+ case BaseOrUnknownValue =>
692
+ BaseOrUnknownValue
693
+
677
694
case arr : OfArray =>
678
695
val target = resolve(defn.ArrayClass , meth)
679
696
@@ -692,7 +709,7 @@ class Objects(using Context @constructorOnly):
692
709
Bottom
693
710
else
694
711
// Array.length is OK
695
- Bottom
712
+ BaseOrUnknownValue
696
713
697
714
case ref : Ref =>
698
715
val isLocal = ! meth.owner.isClass
@@ -713,7 +730,7 @@ class Objects(using Context @constructorOnly):
713
730
arr
714
731
else if target.equals(defn.Predef_classOf ) then
715
732
// Predef.classOf is a stub method in tasty and is replaced in backend
716
- Bottom
733
+ BaseOrUnknownValue
717
734
else if target.hasSource then
718
735
val cls = target.owner.enclosingClass.asClass
719
736
val ddef = target.defTree.asInstanceOf [DefDef ]
@@ -736,7 +753,7 @@ class Objects(using Context @constructorOnly):
736
753
}
737
754
}
738
755
else
739
- Bottom
756
+ BaseOrUnknownValue
740
757
else if target.exists then
741
758
select(ref, target, receiver, needResolve = false )
742
759
else
@@ -804,7 +821,7 @@ class Objects(using Context @constructorOnly):
804
821
}
805
822
else
806
823
// no source code available
807
- Bottom
824
+ BaseOrUnknownValue
808
825
809
826
case _ =>
810
827
report.warning(" [Internal error] unexpected constructor call, meth = " + ctor + " , this = " + value + Trace .show, Trace .position)
@@ -824,6 +841,9 @@ class Objects(using Context @constructorOnly):
824
841
report.warning(" Using cold alias" , Trace .position)
825
842
Bottom
826
843
844
+ case BaseOrUnknownValue =>
845
+ BaseOrUnknownValue
846
+
827
847
case ref : Ref =>
828
848
val target = if needResolve then resolve(ref.klass, field) else field
829
849
if target.is(Flags .Lazy ) then
@@ -832,7 +852,7 @@ class Objects(using Context @constructorOnly):
832
852
val rhs = target.defTree.asInstanceOf [ValDef ].rhs
833
853
eval(rhs, ref, target.owner.asClass, cacheResult = true )
834
854
else
835
- Bottom
855
+ BaseOrUnknownValue
836
856
else if target.exists then
837
857
def isNextFieldOfColonColon : Boolean = ref.klass == defn.ConsClass && target.name.toString == " next"
838
858
if target.isOneOf(Flags .Mutable ) && ! isNextFieldOfColonColon then
@@ -848,24 +868,24 @@ class Objects(using Context @constructorOnly):
848
868
Bottom
849
869
else
850
870
// initialization error, reported by the initialization checker
851
- Bottom
871
+ BaseOrUnknownValue
852
872
else if ref.hasVal(target) then
853
873
ref.valValue(target)
854
874
else if ref.isObjectRef && ref.klass.hasSource then
855
875
report.warning(" Access uninitialized field " + field.show + " . " + Trace .show, Trace .position)
856
876
Bottom
857
877
else
858
878
// initialization error, reported by the initialization checker
859
- Bottom
879
+ BaseOrUnknownValue
860
880
861
881
else
862
882
if ref.klass.isSubClass(receiver.widenSingleton.classSymbol) then
863
883
report.warning(" [Internal error] Unexpected resolution failure: ref.klass = " + ref.klass.show + " , field = " + field.show + Trace .show, Trace .position)
864
884
Bottom
865
885
else
866
- // This is possible due to incorrect type cast.
867
- // See tests/init/pos/Type.scala
868
- Bottom
886
+ // This is possible due to incorrect type cast or accessing standard library objects
887
+ // See tests/init/pos/Type.scala / tests/init/warn/unapplySeq-implicit-arg2.scala
888
+ BaseOrUnknownValue
869
889
870
890
case fun : Fun =>
871
891
report.warning(" [Internal error] unexpected tree in selecting a function, fun = " + fun.code.show + Trace .show, fun.code)
@@ -875,7 +895,7 @@ class Objects(using Context @constructorOnly):
875
895
report.warning(" [Internal error] unexpected tree in selecting an array, array = " + arr.show + Trace .show, Trace .position)
876
896
Bottom
877
897
878
- case Bottom =>
898
+ case Bottom => // TODO: add a value for packages?
879
899
if field.isStaticObject then accessObject(field.moduleClass.asClass)
880
900
else Bottom
881
901
@@ -901,7 +921,7 @@ class Objects(using Context @constructorOnly):
901
921
case Cold =>
902
922
report.warning(" Assigning to cold aliases is forbidden. " + Trace .show, Trace .position)
903
923
904
- case Bottom =>
924
+ case BaseOrUnknownValue | Bottom =>
905
925
906
926
case ValueSet (values) =>
907
927
values.foreach(ref => assign(ref, field, rhs, rhsTyp))
@@ -936,6 +956,9 @@ class Objects(using Context @constructorOnly):
936
956
report.warning(" [Internal error] unexpected outer in instantiating a class, outer = " + outer.show + " , class = " + klass.show + " , " + Trace .show, Trace .position)
937
957
Bottom
938
958
959
+ case BaseOrUnknownValue =>
960
+ BaseOrUnknownValue
961
+
939
962
case outer : (Ref | Cold .type | Bottom .type ) =>
940
963
if klass == defn.ArrayClass then
941
964
args.head.tree.tpe match
@@ -1024,6 +1047,7 @@ class Objects(using Context @constructorOnly):
1024
1047
case Cold =>
1025
1048
report.warning(" Calling cold by-name alias. " + Trace .show, Trace .position)
1026
1049
Bottom
1050
+ case BaseOrUnknownValue => BaseOrUnknownValue
1027
1051
case _ : ValueSet | _ : Ref | _ : OfArray =>
1028
1052
report.warning(" [Internal error] Unexpected by-name value " + value.show + " . " + Trace .show, Trace .position)
1029
1053
Bottom
@@ -1212,7 +1236,7 @@ class Objects(using Context @constructorOnly):
1212
1236
evalType(expr.tpe, thisV, klass)
1213
1237
1214
1238
case Literal (_) =>
1215
- Bottom
1239
+ BaseOrUnknownValue
1216
1240
1217
1241
case Typed (expr, tpt) =>
1218
1242
if tpt.tpe.hasAnnotation(defn.UncheckedAnnot ) then
@@ -1354,7 +1378,7 @@ class Objects(using Context @constructorOnly):
1354
1378
*
1355
1379
* Currently, we assume all cases are reachable, thus all patterns are assumed to match.
1356
1380
*/
1357
- def evalPattern (scrutinee : Value , pat : Tree ): (Type , Value ) = log (" match " + scrutinee.show + " against " + pat.show, printer, (_ : (Type , Value ))._2.show):
1381
+ def evalPattern (scrutinee : Value , pat : Tree ): (Type , Value ) = forcelog (" match " + scrutinee.show + " against " + pat.show, printer, (_ : (Type , Value ))._2.show):
1358
1382
val trace2 = Trace .trace.add(pat)
1359
1383
pat match
1360
1384
case Alternative (pats) =>
@@ -1466,7 +1490,9 @@ class Objects(using Context @constructorOnly):
1466
1490
end if
1467
1491
end if
1468
1492
end if
1469
- (receiverType, scrutinee.filterType(receiverType))
1493
+ // TODO: receiverType is the companion object type, not the class itself;
1494
+ // cannot filter scritunee by this type
1495
+ (receiverType, scrutinee)
1470
1496
1471
1497
case Ident (nme.WILDCARD ) | Ident (nme.WILDCARD_STAR ) =>
1472
1498
(defn.ThrowableType , scrutinee)
@@ -1488,15 +1514,15 @@ class Objects(using Context @constructorOnly):
1488
1514
// call .lengthCompare or .length
1489
1515
val lengthCompareDenot = getMemberMethod(scrutineeType, nme.lengthCompare, lengthCompareType)
1490
1516
if lengthCompareDenot.exists then
1491
- call(scrutinee, lengthCompareDenot.symbol, ArgInfo (Bottom , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1517
+ call(scrutinee, lengthCompareDenot.symbol, ArgInfo (BaseOrUnknownValue , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1492
1518
else
1493
1519
val lengthDenot = getMemberMethod(scrutineeType, nme.length, lengthType)
1494
1520
call(scrutinee, lengthDenot.symbol, Nil , scrutineeType, superType = NoType , needResolve = true )
1495
1521
end if
1496
1522
1497
1523
// call .apply
1498
1524
val applyDenot = getMemberMethod(scrutineeType, nme.apply, applyType(elemType))
1499
- val applyRes = call(scrutinee, applyDenot.symbol, ArgInfo (Bottom , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1525
+ val applyRes = call(scrutinee, applyDenot.symbol, ArgInfo (BaseOrUnknownValue , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1500
1526
1501
1527
if isWildcardStarArgList(pats) then
1502
1528
if pats.size == 1 then
@@ -1507,7 +1533,7 @@ class Objects(using Context @constructorOnly):
1507
1533
else
1508
1534
// call .drop
1509
1535
val dropDenot = getMemberMethod(scrutineeType, nme.drop, applyType(elemType))
1510
- val dropRes = call(scrutinee, dropDenot.symbol, ArgInfo (Bottom , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1536
+ val dropRes = call(scrutinee, dropDenot.symbol, ArgInfo (BaseOrUnknownValue , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1511
1537
for pat <- pats.init do evalPattern(applyRes, pat)
1512
1538
evalPattern(dropRes, pats.last)
1513
1539
end if
@@ -1530,7 +1556,7 @@ class Objects(using Context @constructorOnly):
1530
1556
caseResults.addOne(eval(caseDef.body, thisV, klass))
1531
1557
if catchesAllOf(caseDef, tpe) then
1532
1558
remainingScrutinee = remainingScrutinee.remove(value)
1533
-
1559
+
1534
1560
caseResults.join
1535
1561
end patternMatch
1536
1562
@@ -1549,12 +1575,12 @@ class Objects(using Context @constructorOnly):
1549
1575
def evalType (tp : Type , thisV : ThisValue , klass : ClassSymbol , elideObjectAccess : Boolean = false ): Contextual [Value ] = log(" evaluating " + tp.show, printer, (_ : Value ).show) {
1550
1576
tp match
1551
1577
case _ : ConstantType =>
1552
- Bottom
1578
+ BaseOrUnknownValue
1553
1579
1554
1580
case tmref : TermRef if tmref.prefix == NoPrefix =>
1555
1581
val sym = tmref.symbol
1556
1582
if sym.is(Flags .Package ) then
1557
- Bottom
1583
+ Bottom // TODO: package value?
1558
1584
else if sym.owner.isClass then
1559
1585
// The typer incorrectly assigns a TermRef with NoPrefix for `config`,
1560
1586
// while the actual denotation points to the symbol of the class member
@@ -1788,6 +1814,7 @@ class Objects(using Context @constructorOnly):
1788
1814
else
1789
1815
thisV match
1790
1816
case Bottom => Bottom
1817
+ case BaseOrUnknownValue => BaseOrUnknownValue
1791
1818
case Cold => Cold
1792
1819
case ref : Ref =>
1793
1820
val outerCls = klass.owner.lexicallyEnclosingClass.asClass
0 commit comments