@@ -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
@@ -643,12 +650,15 @@ class Objects(using Context @constructorOnly):
643
650
if baseClasses.isEmpty then a
644
651
else filterClass(baseClasses.head) // could have called ClassSymbol, but it does not handle OrType and AndType
645
652
653
+ // Filter the value according to a class symbol, and only leaves the sub-values
654
+ // which could represent an object of the given class
646
655
def filterClass (sym : Symbol )(using Context ): Value =
647
656
if ! sym.isClass then a
648
657
else
649
658
val klass = sym.asClass
650
659
a match
651
660
case Cold => Cold
661
+ case BaseOrUnknownValue => BaseOrUnknownValue
652
662
case ref : Ref => if ref.klass.isSubClass(klass) then ref else Bottom
653
663
case ValueSet (values) => values.map(v => v.filterClass(klass)).join
654
664
case arr : OfArray => if defn.ArrayClass .isSubClass(klass) then arr else Bottom
@@ -681,6 +691,13 @@ class Objects(using Context @constructorOnly):
681
691
case Bottom =>
682
692
Bottom
683
693
694
+ // Bottom arguments mean unreachable call
695
+ case _ if args.map(_.value).contains(Bottom ) =>
696
+ Bottom
697
+
698
+ case BaseOrUnknownValue =>
699
+ BaseOrUnknownValue
700
+
684
701
case arr : OfArray =>
685
702
val target = resolve(defn.ArrayClass , meth)
686
703
@@ -699,7 +716,7 @@ class Objects(using Context @constructorOnly):
699
716
Bottom
700
717
else
701
718
// Array.length is OK
702
- Bottom
719
+ BaseOrUnknownValue
703
720
704
721
case ref : Ref =>
705
722
val isLocal = ! meth.owner.isClass
@@ -720,7 +737,7 @@ class Objects(using Context @constructorOnly):
720
737
arr
721
738
else if target.equals(defn.Predef_classOf ) then
722
739
// Predef.classOf is a stub method in tasty and is replaced in backend
723
- Bottom
740
+ BaseOrUnknownValue
724
741
else if target.hasSource then
725
742
val cls = target.owner.enclosingClass.asClass
726
743
val ddef = target.defTree.asInstanceOf [DefDef ]
@@ -743,7 +760,7 @@ class Objects(using Context @constructorOnly):
743
760
}
744
761
}
745
762
else
746
- Bottom
763
+ BaseOrUnknownValue
747
764
else if target.exists then
748
765
select(ref, target, receiver, needResolve = false )
749
766
else
@@ -811,7 +828,7 @@ class Objects(using Context @constructorOnly):
811
828
}
812
829
else
813
830
// no source code available
814
- Bottom
831
+ BaseOrUnknownValue
815
832
816
833
case _ =>
817
834
report.warning(" [Internal error] unexpected constructor call, meth = " + ctor + " , this = " + value + Trace .show, Trace .position)
@@ -831,6 +848,9 @@ class Objects(using Context @constructorOnly):
831
848
report.warning(" Using cold alias" , Trace .position)
832
849
Bottom
833
850
851
+ case BaseOrUnknownValue =>
852
+ BaseOrUnknownValue
853
+
834
854
case ref : Ref =>
835
855
val target = if needResolve then resolve(ref.klass, field) else field
836
856
if target.is(Flags .Lazy ) then
@@ -839,7 +859,7 @@ class Objects(using Context @constructorOnly):
839
859
val rhs = target.defTree.asInstanceOf [ValDef ].rhs
840
860
eval(rhs, ref, target.owner.asClass, cacheResult = true )
841
861
else
842
- Bottom
862
+ BaseOrUnknownValue
843
863
else if target.exists then
844
864
def isNextFieldOfColonColon : Boolean = ref.klass == defn.ConsClass && target.name.toString == " next"
845
865
if target.isOneOf(Flags .Mutable ) && ! isNextFieldOfColonColon then
@@ -855,24 +875,24 @@ class Objects(using Context @constructorOnly):
855
875
Bottom
856
876
else
857
877
// initialization error, reported by the initialization checker
858
- Bottom
878
+ BaseOrUnknownValue
859
879
else if ref.hasVal(target) then
860
880
ref.valValue(target)
861
881
else if ref.isObjectRef && ref.klass.hasSource then
862
882
report.warning(" Access uninitialized field " + field.show + " . " + Trace .show, Trace .position)
863
883
Bottom
864
884
else
865
885
// initialization error, reported by the initialization checker
866
- Bottom
886
+ BaseOrUnknownValue
867
887
868
888
else
869
889
if ref.klass.isSubClass(receiver.widenSingleton.classSymbol) then
870
890
report.warning(" [Internal error] Unexpected resolution failure: ref.klass = " + ref.klass.show + " , field = " + field.show + Trace .show, Trace .position)
871
891
Bottom
872
892
else
873
- // This is possible due to incorrect type cast.
874
- // See tests/init/pos/Type.scala
875
- Bottom
893
+ // This is possible due to incorrect type cast or accessing standard library objects
894
+ // See tests/init/pos/Type.scala / tests/init/warn/unapplySeq-implicit-arg2.scala
895
+ BaseOrUnknownValue
876
896
877
897
case fun : Fun =>
878
898
report.warning(" [Internal error] unexpected tree in selecting a function, fun = " + fun.code.show + Trace .show, fun.code)
@@ -882,7 +902,7 @@ class Objects(using Context @constructorOnly):
882
902
report.warning(" [Internal error] unexpected tree in selecting an array, array = " + arr.show + Trace .show, Trace .position)
883
903
Bottom
884
904
885
- case Bottom =>
905
+ case Bottom => // TODO: add a value for packages?
886
906
if field.isStaticObject then accessObject(field.moduleClass.asClass)
887
907
else Bottom
888
908
@@ -908,7 +928,7 @@ class Objects(using Context @constructorOnly):
908
928
case Cold =>
909
929
report.warning(" Assigning to cold aliases is forbidden. " + Trace .show, Trace .position)
910
930
911
- case Bottom =>
931
+ case BaseOrUnknownValue | Bottom =>
912
932
913
933
case ValueSet (values) =>
914
934
values.foreach(ref => assign(ref, field, rhs, rhsTyp))
@@ -943,6 +963,9 @@ class Objects(using Context @constructorOnly):
943
963
report.warning(" [Internal error] unexpected outer in instantiating a class, outer = " + outer.show + " , class = " + klass.show + " , " + Trace .show, Trace .position)
944
964
Bottom
945
965
966
+ case BaseOrUnknownValue =>
967
+ BaseOrUnknownValue
968
+
946
969
case outer : (Ref | Cold .type | Bottom .type ) =>
947
970
if klass == defn.ArrayClass then
948
971
args.head.tree.tpe match
@@ -1031,6 +1054,7 @@ class Objects(using Context @constructorOnly):
1031
1054
case Cold =>
1032
1055
report.warning(" Calling cold by-name alias. " + Trace .show, Trace .position)
1033
1056
Bottom
1057
+ case BaseOrUnknownValue => BaseOrUnknownValue
1034
1058
case _ : ValueSet | _ : Ref | _ : OfArray =>
1035
1059
report.warning(" [Internal error] Unexpected by-name value " + value.show + " . " + Trace .show, Trace .position)
1036
1060
Bottom
@@ -1219,7 +1243,7 @@ class Objects(using Context @constructorOnly):
1219
1243
evalType(expr.tpe, thisV, klass)
1220
1244
1221
1245
case Literal (_) =>
1222
- Bottom
1246
+ BaseOrUnknownValue
1223
1247
1224
1248
case Typed (expr, tpt) =>
1225
1249
if tpt.tpe.hasAnnotation(defn.UncheckedAnnot ) then
@@ -1473,7 +1497,9 @@ class Objects(using Context @constructorOnly):
1473
1497
end if
1474
1498
end if
1475
1499
end if
1476
- (receiverType, scrutinee.filterType(receiverType))
1500
+ // TODO: receiverType is the companion object type, not the class itself;
1501
+ // cannot filter scritunee by this type
1502
+ (receiverType, scrutinee)
1477
1503
1478
1504
case Ident (nme.WILDCARD ) | Ident (nme.WILDCARD_STAR ) =>
1479
1505
(defn.ThrowableType , scrutinee)
@@ -1495,26 +1521,26 @@ class Objects(using Context @constructorOnly):
1495
1521
// call .lengthCompare or .length
1496
1522
val lengthCompareDenot = getMemberMethod(scrutineeType, nme.lengthCompare, lengthCompareType)
1497
1523
if lengthCompareDenot.exists then
1498
- call(scrutinee, lengthCompareDenot.symbol, ArgInfo (Bottom , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1524
+ call(scrutinee, lengthCompareDenot.symbol, ArgInfo (BaseOrUnknownValue , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1499
1525
else
1500
1526
val lengthDenot = getMemberMethod(scrutineeType, nme.length, lengthType)
1501
1527
call(scrutinee, lengthDenot.symbol, Nil , scrutineeType, superType = NoType , needResolve = true )
1502
1528
end if
1503
1529
1504
1530
// call .apply
1505
1531
val applyDenot = getMemberMethod(scrutineeType, nme.apply, applyType(elemType))
1506
- val applyRes = call(scrutinee, applyDenot.symbol, ArgInfo (Bottom , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1532
+ val applyRes = call(scrutinee, applyDenot.symbol, ArgInfo (BaseOrUnknownValue , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1507
1533
1508
1534
if isWildcardStarArgList(pats) then
1509
1535
if pats.size == 1 then
1510
1536
// call .toSeq
1511
- val toSeqDenot = scrutineeType.member( nme.toSeq).suchThat(_.info.isParameterless )
1537
+ val toSeqDenot = getMemberMethod(scrutineeType, nme.toSeq, toSeqType(elemType) )
1512
1538
val toSeqRes = call(scrutinee, toSeqDenot.symbol, Nil , scrutineeType, superType = NoType , needResolve = true )
1513
1539
evalPattern(toSeqRes, pats.head)
1514
1540
else
1515
1541
// call .drop
1516
- val dropDenot = getMemberMethod(scrutineeType, nme.drop, applyType (elemType))
1517
- val dropRes = call(scrutinee, dropDenot.symbol, ArgInfo (Bottom , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1542
+ val dropDenot = getMemberMethod(scrutineeType, nme.drop, dropType (elemType))
1543
+ val dropRes = call(scrutinee, dropDenot.symbol, ArgInfo (BaseOrUnknownValue , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1518
1544
for pat <- pats.init do evalPattern(applyRes, pat)
1519
1545
evalPattern(dropRes, pats.last)
1520
1546
end if
@@ -1537,7 +1563,7 @@ class Objects(using Context @constructorOnly):
1537
1563
caseResults.addOne(eval(caseDef.body, thisV, klass))
1538
1564
if catchesAllOf(caseDef, tpe) then
1539
1565
remainingScrutinee = remainingScrutinee.remove(value)
1540
-
1566
+
1541
1567
caseResults.join
1542
1568
end patternMatch
1543
1569
@@ -1556,12 +1582,12 @@ class Objects(using Context @constructorOnly):
1556
1582
def evalType (tp : Type , thisV : ThisValue , klass : ClassSymbol , elideObjectAccess : Boolean = false ): Contextual [Value ] = log(" evaluating " + tp.show, printer, (_ : Value ).show) {
1557
1583
tp match
1558
1584
case _ : ConstantType =>
1559
- Bottom
1585
+ BaseOrUnknownValue
1560
1586
1561
1587
case tmref : TermRef if tmref.prefix == NoPrefix =>
1562
1588
val sym = tmref.symbol
1563
1589
if sym.is(Flags .Package ) then
1564
- Bottom
1590
+ Bottom // TODO: package value?
1565
1591
else if sym.owner.isClass then
1566
1592
// The typer incorrectly assigns a TermRef with NoPrefix for `config`,
1567
1593
// while the actual denotation points to the symbol of the class member
@@ -1795,6 +1821,7 @@ class Objects(using Context @constructorOnly):
1795
1821
else
1796
1822
thisV match
1797
1823
case Bottom => Bottom
1824
+ case BaseOrUnknownValue => BaseOrUnknownValue
1798
1825
case Cold => Cold
1799
1826
case ref : Ref =>
1800
1827
val outerCls = klass.owner.lexicallyEnclosingClass.asClass
0 commit comments