@@ -18,6 +18,7 @@ import util.{ SourcePosition, NoSourcePosition }
1818import config .Printers .init as printer
1919import reporting .StoreReporter
2020import reporting .trace as log
21+ import reporting .trace .force as forcelog
2122import typer .Applications .*
2223
2324import Errors .*
@@ -91,6 +92,7 @@ class Objects(using Context @constructorOnly):
9192 * ve ::= ObjectRef(class) // global object
9293 * | OfClass(class, vs[outer], ctor, args, env) // instance of a class
9394 * | OfArray(object[owner], regions)
95+ * | BaseOrUnknownValue // Int, String, etc., and values without source
9496 * | Fun(..., env) // value elements that can be contained in ValueSet
9597 * vs ::= ValueSet(ve) // set of abstract values
9698 * Bottom ::= ValueSet(Empty)
@@ -233,6 +235,11 @@ class Objects(using Context @constructorOnly):
233235 case class ValueSet (values : ListSet [ValueElement ]) extends Value :
234236 def show (using Context ) = values.map(_.show).mkString(" [" , " ," , " ]" )
235237
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+
236243 /** A cold alias which should not be used during initialization.
237244 *
238245 * Cold is not ValueElement since RefSet containing Cold is equivalent to Cold
@@ -643,12 +650,15 @@ class Objects(using Context @constructorOnly):
643650 if baseClasses.isEmpty then a
644651 else filterClass(baseClasses.head) // could have called ClassSymbol, but it does not handle OrType and AndType
645652
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
646655 def filterClass (sym : Symbol )(using Context ): Value =
647656 if ! sym.isClass then a
648657 else
649658 val klass = sym.asClass
650659 a match
651660 case Cold => Cold
661+ case BaseOrUnknownValue => BaseOrUnknownValue
652662 case ref : Ref => if ref.klass.isSubClass(klass) then ref else Bottom
653663 case ValueSet (values) => values.map(v => v.filterClass(klass)).join
654664 case arr : OfArray => if defn.ArrayClass .isSubClass(klass) then arr else Bottom
@@ -681,6 +691,13 @@ class Objects(using Context @constructorOnly):
681691 case Bottom =>
682692 Bottom
683693
694+ // Bottom arguments mean unreachable call
695+ case _ if args.map(_.value).contains(Bottom ) =>
696+ Bottom
697+
698+ case BaseOrUnknownValue =>
699+ BaseOrUnknownValue
700+
684701 case arr : OfArray =>
685702 val target = resolve(defn.ArrayClass , meth)
686703
@@ -699,7 +716,7 @@ class Objects(using Context @constructorOnly):
699716 Bottom
700717 else
701718 // Array.length is OK
702- Bottom
719+ BaseOrUnknownValue
703720
704721 case ref : Ref =>
705722 val isLocal = ! meth.owner.isClass
@@ -720,7 +737,7 @@ class Objects(using Context @constructorOnly):
720737 arr
721738 else if target.equals(defn.Predef_classOf ) then
722739 // Predef.classOf is a stub method in tasty and is replaced in backend
723- Bottom
740+ BaseOrUnknownValue
724741 else if target.hasSource then
725742 val cls = target.owner.enclosingClass.asClass
726743 val ddef = target.defTree.asInstanceOf [DefDef ]
@@ -743,7 +760,7 @@ class Objects(using Context @constructorOnly):
743760 }
744761 }
745762 else
746- Bottom
763+ BaseOrUnknownValue
747764 else if target.exists then
748765 select(ref, target, receiver, needResolve = false )
749766 else
@@ -811,7 +828,7 @@ class Objects(using Context @constructorOnly):
811828 }
812829 else
813830 // no source code available
814- Bottom
831+ BaseOrUnknownValue
815832
816833 case _ =>
817834 report.warning(" [Internal error] unexpected constructor call, meth = " + ctor + " , this = " + value + Trace .show, Trace .position)
@@ -831,6 +848,9 @@ class Objects(using Context @constructorOnly):
831848 report.warning(" Using cold alias" , Trace .position)
832849 Bottom
833850
851+ case BaseOrUnknownValue =>
852+ BaseOrUnknownValue
853+
834854 case ref : Ref =>
835855 val target = if needResolve then resolve(ref.klass, field) else field
836856 if target.is(Flags .Lazy ) then
@@ -839,7 +859,7 @@ class Objects(using Context @constructorOnly):
839859 val rhs = target.defTree.asInstanceOf [ValDef ].rhs
840860 eval(rhs, ref, target.owner.asClass, cacheResult = true )
841861 else
842- Bottom
862+ BaseOrUnknownValue
843863 else if target.exists then
844864 def isNextFieldOfColonColon : Boolean = ref.klass == defn.ConsClass && target.name.toString == " next"
845865 if target.isOneOf(Flags .Mutable ) && ! isNextFieldOfColonColon then
@@ -855,24 +875,24 @@ class Objects(using Context @constructorOnly):
855875 Bottom
856876 else
857877 // initialization error, reported by the initialization checker
858- Bottom
878+ BaseOrUnknownValue
859879 else if ref.hasVal(target) then
860880 ref.valValue(target)
861881 else if ref.isObjectRef && ref.klass.hasSource then
862882 report.warning(" Access uninitialized field " + field.show + " . " + Trace .show, Trace .position)
863883 Bottom
864884 else
865885 // initialization error, reported by the initialization checker
866- Bottom
886+ BaseOrUnknownValue
867887
868888 else
869889 if ref.klass.isSubClass(receiver.widenSingleton.classSymbol) then
870890 report.warning(" [Internal error] Unexpected resolution failure: ref.klass = " + ref.klass.show + " , field = " + field.show + Trace .show, Trace .position)
871891 Bottom
872892 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
876896
877897 case fun : Fun =>
878898 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):
882902 report.warning(" [Internal error] unexpected tree in selecting an array, array = " + arr.show + Trace .show, Trace .position)
883903 Bottom
884904
885- case Bottom =>
905+ case Bottom => // TODO: add a value for packages?
886906 if field.isStaticObject then accessObject(field.moduleClass.asClass)
887907 else Bottom
888908
@@ -908,7 +928,7 @@ class Objects(using Context @constructorOnly):
908928 case Cold =>
909929 report.warning(" Assigning to cold aliases is forbidden. " + Trace .show, Trace .position)
910930
911- case Bottom =>
931+ case BaseOrUnknownValue | Bottom =>
912932
913933 case ValueSet (values) =>
914934 values.foreach(ref => assign(ref, field, rhs, rhsTyp))
@@ -943,6 +963,9 @@ class Objects(using Context @constructorOnly):
943963 report.warning(" [Internal error] unexpected outer in instantiating a class, outer = " + outer.show + " , class = " + klass.show + " , " + Trace .show, Trace .position)
944964 Bottom
945965
966+ case BaseOrUnknownValue =>
967+ BaseOrUnknownValue
968+
946969 case outer : (Ref | Cold .type | Bottom .type ) =>
947970 if klass == defn.ArrayClass then
948971 args.head.tree.tpe match
@@ -1031,6 +1054,7 @@ class Objects(using Context @constructorOnly):
10311054 case Cold =>
10321055 report.warning(" Calling cold by-name alias. " + Trace .show, Trace .position)
10331056 Bottom
1057+ case BaseOrUnknownValue => BaseOrUnknownValue
10341058 case _ : ValueSet | _ : Ref | _ : OfArray =>
10351059 report.warning(" [Internal error] Unexpected by-name value " + value.show + " . " + Trace .show, Trace .position)
10361060 Bottom
@@ -1219,7 +1243,7 @@ class Objects(using Context @constructorOnly):
12191243 evalType(expr.tpe, thisV, klass)
12201244
12211245 case Literal (_) =>
1222- Bottom
1246+ BaseOrUnknownValue
12231247
12241248 case Typed (expr, tpt) =>
12251249 if tpt.tpe.hasAnnotation(defn.UncheckedAnnot ) then
@@ -1473,7 +1497,9 @@ class Objects(using Context @constructorOnly):
14731497 end if
14741498 end if
14751499 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)
14771503
14781504 case Ident (nme.WILDCARD ) | Ident (nme.WILDCARD_STAR ) =>
14791505 (defn.ThrowableType , scrutinee)
@@ -1495,26 +1521,26 @@ class Objects(using Context @constructorOnly):
14951521 // call .lengthCompare or .length
14961522 val lengthCompareDenot = getMemberMethod(scrutineeType, nme.lengthCompare, lengthCompareType)
14971523 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 )
14991525 else
15001526 val lengthDenot = getMemberMethod(scrutineeType, nme.length, lengthType)
15011527 call(scrutinee, lengthDenot.symbol, Nil , scrutineeType, superType = NoType , needResolve = true )
15021528 end if
15031529
15041530 // call .apply
15051531 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 )
15071533
15081534 if isWildcardStarArgList(pats) then
15091535 if pats.size == 1 then
15101536 // call .toSeq
1511- val toSeqDenot = scrutineeType.member( nme.toSeq).suchThat(_.info.isParameterless )
1537+ val toSeqDenot = getMemberMethod(scrutineeType, nme.toSeq, toSeqType(elemType) )
15121538 val toSeqRes = call(scrutinee, toSeqDenot.symbol, Nil , scrutineeType, superType = NoType , needResolve = true )
15131539 evalPattern(toSeqRes, pats.head)
15141540 else
15151541 // 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 )
15181544 for pat <- pats.init do evalPattern(applyRes, pat)
15191545 evalPattern(dropRes, pats.last)
15201546 end if
@@ -1537,7 +1563,7 @@ class Objects(using Context @constructorOnly):
15371563 caseResults.addOne(eval(caseDef.body, thisV, klass))
15381564 if catchesAllOf(caseDef, tpe) then
15391565 remainingScrutinee = remainingScrutinee.remove(value)
1540-
1566+
15411567 caseResults.join
15421568 end patternMatch
15431569
@@ -1556,12 +1582,12 @@ class Objects(using Context @constructorOnly):
15561582 def evalType (tp : Type , thisV : ThisValue , klass : ClassSymbol , elideObjectAccess : Boolean = false ): Contextual [Value ] = log(" evaluating " + tp.show, printer, (_ : Value ).show) {
15571583 tp match
15581584 case _ : ConstantType =>
1559- Bottom
1585+ BaseOrUnknownValue
15601586
15611587 case tmref : TermRef if tmref.prefix == NoPrefix =>
15621588 val sym = tmref.symbol
15631589 if sym.is(Flags .Package ) then
1564- Bottom
1590+ Bottom // TODO: package value?
15651591 else if sym.owner.isClass then
15661592 // The typer incorrectly assigns a TermRef with NoPrefix for `config`,
15671593 // while the actual denotation points to the symbol of the class member
@@ -1795,6 +1821,7 @@ class Objects(using Context @constructorOnly):
17951821 else
17961822 thisV match
17971823 case Bottom => Bottom
1824+ case BaseOrUnknownValue => BaseOrUnknownValue
17981825 case Cold => Cold
17991826 case ref : Ref =>
18001827 val outerCls = klass.owner.lexicallyEnclosingClass.asClass
0 commit comments