@@ -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
@@ -678,12 +685,15 @@ class Objects(using Context @constructorOnly):
678
685
if baseClasses.isEmpty then a
679
686
else filterClass(baseClasses.head) // could have called ClassSymbol, but it does not handle OrType and AndType
680
687
688
+ // Filter the value according to a class symbol, and only leaves the sub-values
689
+ // which could represent an object of the given class
681
690
def filterClass (sym : Symbol )(using Context ): Value =
682
691
if ! sym.isClass then a
683
692
else
684
693
val klass = sym.asClass
685
694
a match
686
695
case Cold => Cold
696
+ case BaseOrUnknownValue => BaseOrUnknownValue
687
697
case ref : Ref => if ref.klass.isSubClass(klass) then ref else Bottom
688
698
case ValueSet (values) => values.map(v => v.filterClass(klass)).join
689
699
case arr : OfArray => if defn.ArrayClass .isSubClass(klass) then arr else Bottom
@@ -716,6 +726,13 @@ class Objects(using Context @constructorOnly):
716
726
case Bottom =>
717
727
Bottom
718
728
729
+ // Bottom arguments mean unreachable call
730
+ case _ if args.map(_.value).contains(Bottom ) =>
731
+ Bottom
732
+
733
+ case BaseOrUnknownValue =>
734
+ BaseOrUnknownValue
735
+
719
736
case arr : OfArray =>
720
737
val target = resolve(defn.ArrayClass , meth)
721
738
@@ -734,7 +751,7 @@ class Objects(using Context @constructorOnly):
734
751
Bottom
735
752
else
736
753
// Array.length is OK
737
- Bottom
754
+ BaseOrUnknownValue
738
755
739
756
case ref : Ref =>
740
757
val isLocal = ! meth.owner.isClass
@@ -755,7 +772,7 @@ class Objects(using Context @constructorOnly):
755
772
arr
756
773
else if target.equals(defn.Predef_classOf ) then
757
774
// Predef.classOf is a stub method in tasty and is replaced in backend
758
- Bottom
775
+ BaseOrUnknownValue
759
776
else if target.hasSource then
760
777
val cls = target.owner.enclosingClass.asClass
761
778
val ddef = target.defTree.asInstanceOf [DefDef ]
@@ -778,7 +795,7 @@ class Objects(using Context @constructorOnly):
778
795
}
779
796
}
780
797
else
781
- Bottom
798
+ BaseOrUnknownValue
782
799
else if target.exists then
783
800
select(ref, target, receiver, needResolve = false )
784
801
else
@@ -846,7 +863,7 @@ class Objects(using Context @constructorOnly):
846
863
}
847
864
else
848
865
// no source code available
849
- Bottom
866
+ BaseOrUnknownValue
850
867
851
868
case _ =>
852
869
report.warning(" [Internal error] unexpected constructor call, meth = " + ctor + " , this = " + value + Trace .show, Trace .position)
@@ -866,6 +883,9 @@ class Objects(using Context @constructorOnly):
866
883
report.warning(" Using cold alias" , Trace .position)
867
884
Bottom
868
885
886
+ case BaseOrUnknownValue =>
887
+ BaseOrUnknownValue
888
+
869
889
case ref : Ref =>
870
890
val target = if needResolve then resolve(ref.klass, field) else field
871
891
if target.is(Flags .Lazy ) then
@@ -874,7 +894,7 @@ class Objects(using Context @constructorOnly):
874
894
val rhs = target.defTree.asInstanceOf [ValDef ].rhs
875
895
eval(rhs, ref, target.owner.asClass, cacheResult = true )
876
896
else
877
- Bottom
897
+ BaseOrUnknownValue
878
898
else if target.exists then
879
899
def isNextFieldOfColonColon : Boolean = ref.klass == defn.ConsClass && target.name.toString == " next"
880
900
if target.isOneOf(Flags .Mutable ) && ! isNextFieldOfColonColon then
@@ -890,24 +910,24 @@ class Objects(using Context @constructorOnly):
890
910
Bottom
891
911
else
892
912
// initialization error, reported by the initialization checker
893
- Bottom
913
+ BaseOrUnknownValue
894
914
else if ref.hasVal(target) then
895
915
ref.valValue(target)
896
916
else if ref.isObjectRef && ref.klass.hasSource then
897
917
report.warning(" Access uninitialized field " + field.show + " . " + Trace .show, Trace .position)
898
918
Bottom
899
919
else
900
920
// initialization error, reported by the initialization checker
901
- Bottom
921
+ BaseOrUnknownValue
902
922
903
923
else
904
924
if ref.klass.isSubClass(receiver.widenSingleton.classSymbol) then
905
925
report.warning(" [Internal error] Unexpected resolution failure: ref.klass = " + ref.klass.show + " , field = " + field.show + Trace .show, Trace .position)
906
926
Bottom
907
927
else
908
- // This is possible due to incorrect type cast.
909
- // See tests/init/pos/Type.scala
910
- Bottom
928
+ // This is possible due to incorrect type cast or accessing standard library objects
929
+ // See tests/init/pos/Type.scala / tests/init/warn/unapplySeq-implicit-arg2.scala
930
+ BaseOrUnknownValue
911
931
912
932
case fun : Fun =>
913
933
report.warning(" [Internal error] unexpected tree in selecting a function, fun = " + fun.code.show + Trace .show, fun.code)
@@ -917,7 +937,7 @@ class Objects(using Context @constructorOnly):
917
937
report.warning(" [Internal error] unexpected tree in selecting an array, array = " + arr.show + Trace .show, Trace .position)
918
938
Bottom
919
939
920
- case Bottom =>
940
+ case Bottom => // TODO: add a value for packages?
921
941
if field.isStaticObject then accessObject(field.moduleClass.asClass)
922
942
else Bottom
923
943
@@ -943,7 +963,7 @@ class Objects(using Context @constructorOnly):
943
963
case Cold =>
944
964
report.warning(" Assigning to cold aliases is forbidden. " + Trace .show, Trace .position)
945
965
946
- case Bottom =>
966
+ case BaseOrUnknownValue | Bottom =>
947
967
948
968
case ValueSet (values) =>
949
969
values.foreach(ref => assign(ref, field, rhs, rhsTyp))
@@ -978,6 +998,9 @@ class Objects(using Context @constructorOnly):
978
998
report.warning(" [Internal error] unexpected outer in instantiating a class, outer = " + outer.show + " , class = " + klass.show + " , " + Trace .show, Trace .position)
979
999
Bottom
980
1000
1001
+ case BaseOrUnknownValue =>
1002
+ BaseOrUnknownValue
1003
+
981
1004
case outer : (Ref | Cold .type | Bottom .type ) =>
982
1005
if klass == defn.ArrayClass then
983
1006
args.head.tree.tpe match
@@ -1068,6 +1091,7 @@ class Objects(using Context @constructorOnly):
1068
1091
case Cold =>
1069
1092
report.warning(" Calling cold by-name alias. " + Trace .show, Trace .position)
1070
1093
Bottom
1094
+ case BaseOrUnknownValue => BaseOrUnknownValue
1071
1095
case _ : ValueSet | _ : Ref | _ : OfArray =>
1072
1096
report.warning(" [Internal error] Unexpected by-name value " + value.show + " . " + Trace .show, Trace .position)
1073
1097
Bottom
@@ -1257,7 +1281,7 @@ class Objects(using Context @constructorOnly):
1257
1281
evalType(expr.tpe, thisV, klass)
1258
1282
1259
1283
case Literal (_) =>
1260
- Bottom
1284
+ BaseOrUnknownValue
1261
1285
1262
1286
case Typed (expr, tpt) =>
1263
1287
if tpt.tpe.hasAnnotation(defn.UncheckedAnnot ) then
@@ -1511,7 +1535,9 @@ class Objects(using Context @constructorOnly):
1511
1535
end if
1512
1536
end if
1513
1537
end if
1514
- (receiverType, scrutinee.filterType(receiverType))
1538
+ // TODO: receiverType is the companion object type, not the class itself;
1539
+ // cannot filter scritunee by this type
1540
+ (receiverType, scrutinee)
1515
1541
1516
1542
case Ident (nme.WILDCARD ) | Ident (nme.WILDCARD_STAR ) =>
1517
1543
(defn.ThrowableType , scrutinee)
@@ -1533,26 +1559,26 @@ class Objects(using Context @constructorOnly):
1533
1559
// call .lengthCompare or .length
1534
1560
val lengthCompareDenot = getMemberMethod(scrutineeType, nme.lengthCompare, lengthCompareType)
1535
1561
if lengthCompareDenot.exists then
1536
- call(scrutinee, lengthCompareDenot.symbol, ArgInfo (Bottom , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1562
+ call(scrutinee, lengthCompareDenot.symbol, ArgInfo (BaseOrUnknownValue , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1537
1563
else
1538
1564
val lengthDenot = getMemberMethod(scrutineeType, nme.length, lengthType)
1539
1565
call(scrutinee, lengthDenot.symbol, Nil , scrutineeType, superType = NoType , needResolve = true )
1540
1566
end if
1541
1567
1542
1568
// call .apply
1543
1569
val applyDenot = getMemberMethod(scrutineeType, nme.apply, applyType(elemType))
1544
- val applyRes = call(scrutinee, applyDenot.symbol, ArgInfo (Bottom , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1570
+ val applyRes = call(scrutinee, applyDenot.symbol, ArgInfo (BaseOrUnknownValue , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1545
1571
1546
1572
if isWildcardStarArgList(pats) then
1547
1573
if pats.size == 1 then
1548
1574
// call .toSeq
1549
- val toSeqDenot = scrutineeType.member( nme.toSeq).suchThat(_.info.isParameterless )
1575
+ val toSeqDenot = getMemberMethod(scrutineeType, nme.toSeq, toSeqType(elemType) )
1550
1576
val toSeqRes = call(scrutinee, toSeqDenot.symbol, Nil , scrutineeType, superType = NoType , needResolve = true )
1551
1577
evalPattern(toSeqRes, pats.head)
1552
1578
else
1553
1579
// call .drop
1554
- val dropDenot = getMemberMethod(scrutineeType, nme.drop, applyType (elemType))
1555
- val dropRes = call(scrutinee, dropDenot.symbol, ArgInfo (Bottom , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1580
+ val dropDenot = getMemberMethod(scrutineeType, nme.drop, dropType (elemType))
1581
+ val dropRes = call(scrutinee, dropDenot.symbol, ArgInfo (BaseOrUnknownValue , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1556
1582
for pat <- pats.init do evalPattern(applyRes, pat)
1557
1583
evalPattern(dropRes, pats.last)
1558
1584
end if
@@ -1575,7 +1601,7 @@ class Objects(using Context @constructorOnly):
1575
1601
caseResults.addOne(eval(caseDef.body, thisV, klass))
1576
1602
if catchesAllOf(caseDef, tpe) then
1577
1603
remainingScrutinee = remainingScrutinee.remove(value)
1578
-
1604
+
1579
1605
caseResults.join
1580
1606
end patternMatch
1581
1607
@@ -1594,12 +1620,12 @@ class Objects(using Context @constructorOnly):
1594
1620
def evalType (tp : Type , thisV : ThisValue , klass : ClassSymbol , elideObjectAccess : Boolean = false ): Contextual [Value ] = log(" evaluating " + tp.show, printer, (_ : Value ).show) {
1595
1621
tp match
1596
1622
case _ : ConstantType =>
1597
- Bottom
1623
+ BaseOrUnknownValue
1598
1624
1599
1625
case tmref : TermRef if tmref.prefix == NoPrefix =>
1600
1626
val sym = tmref.symbol
1601
1627
if sym.is(Flags .Package ) then
1602
- Bottom
1628
+ Bottom // TODO: package value?
1603
1629
else if sym.owner.isClass then
1604
1630
// The typer incorrectly assigns a TermRef with NoPrefix for `config`,
1605
1631
// while the actual denotation points to the symbol of the class member
@@ -1833,6 +1859,7 @@ class Objects(using Context @constructorOnly):
1833
1859
else
1834
1860
thisV match
1835
1861
case Bottom => Bottom
1862
+ case BaseOrUnknownValue => BaseOrUnknownValue
1836
1863
case Cold => Cold
1837
1864
case ref : Ref =>
1838
1865
val outerCls = klass.owner.lexicallyEnclosingClass.asClass
0 commit comments