@@ -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
@@ -678,12 +685,15 @@ class Objects(using Context @constructorOnly):
678685 if baseClasses.isEmpty then a
679686 else filterClass(baseClasses.head) // could have called ClassSymbol, but it does not handle OrType and AndType
680687
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
681690 def filterClass (sym : Symbol )(using Context ): Value =
682691 if ! sym.isClass then a
683692 else
684693 val klass = sym.asClass
685694 a match
686695 case Cold => Cold
696+ case BaseOrUnknownValue => BaseOrUnknownValue
687697 case ref : Ref => if ref.klass.isSubClass(klass) then ref else Bottom
688698 case ValueSet (values) => values.map(v => v.filterClass(klass)).join
689699 case arr : OfArray => if defn.ArrayClass .isSubClass(klass) then arr else Bottom
@@ -716,6 +726,13 @@ class Objects(using Context @constructorOnly):
716726 case Bottom =>
717727 Bottom
718728
729+ // Bottom arguments mean unreachable call
730+ case _ if args.map(_.value).contains(Bottom ) =>
731+ Bottom
732+
733+ case BaseOrUnknownValue =>
734+ BaseOrUnknownValue
735+
719736 case arr : OfArray =>
720737 val target = resolve(defn.ArrayClass , meth)
721738
@@ -734,7 +751,7 @@ class Objects(using Context @constructorOnly):
734751 Bottom
735752 else
736753 // Array.length is OK
737- Bottom
754+ BaseOrUnknownValue
738755
739756 case ref : Ref =>
740757 val isLocal = ! meth.owner.isClass
@@ -755,7 +772,7 @@ class Objects(using Context @constructorOnly):
755772 arr
756773 else if target.equals(defn.Predef_classOf ) then
757774 // Predef.classOf is a stub method in tasty and is replaced in backend
758- Bottom
775+ BaseOrUnknownValue
759776 else if target.hasSource then
760777 val cls = target.owner.enclosingClass.asClass
761778 val ddef = target.defTree.asInstanceOf [DefDef ]
@@ -778,7 +795,7 @@ class Objects(using Context @constructorOnly):
778795 }
779796 }
780797 else
781- Bottom
798+ BaseOrUnknownValue
782799 else if target.exists then
783800 select(ref, target, receiver, needResolve = false )
784801 else
@@ -846,7 +863,7 @@ class Objects(using Context @constructorOnly):
846863 }
847864 else
848865 // no source code available
849- Bottom
866+ BaseOrUnknownValue
850867
851868 case _ =>
852869 report.warning(" [Internal error] unexpected constructor call, meth = " + ctor + " , this = " + value + Trace .show, Trace .position)
@@ -866,6 +883,9 @@ class Objects(using Context @constructorOnly):
866883 report.warning(" Using cold alias" , Trace .position)
867884 Bottom
868885
886+ case BaseOrUnknownValue =>
887+ BaseOrUnknownValue
888+
869889 case ref : Ref =>
870890 val target = if needResolve then resolve(ref.klass, field) else field
871891 if target.is(Flags .Lazy ) then
@@ -874,7 +894,7 @@ class Objects(using Context @constructorOnly):
874894 val rhs = target.defTree.asInstanceOf [ValDef ].rhs
875895 eval(rhs, ref, target.owner.asClass, cacheResult = true )
876896 else
877- Bottom
897+ BaseOrUnknownValue
878898 else if target.exists then
879899 def isNextFieldOfColonColon : Boolean = ref.klass == defn.ConsClass && target.name.toString == " next"
880900 if target.isOneOf(Flags .Mutable ) && ! isNextFieldOfColonColon then
@@ -890,24 +910,24 @@ class Objects(using Context @constructorOnly):
890910 Bottom
891911 else
892912 // initialization error, reported by the initialization checker
893- Bottom
913+ BaseOrUnknownValue
894914 else if ref.hasVal(target) then
895915 ref.valValue(target)
896916 else if ref.isObjectRef && ref.klass.hasSource then
897917 report.warning(" Access uninitialized field " + field.show + " . " + Trace .show, Trace .position)
898918 Bottom
899919 else
900920 // initialization error, reported by the initialization checker
901- Bottom
921+ BaseOrUnknownValue
902922
903923 else
904924 if ref.klass.isSubClass(receiver.widenSingleton.classSymbol) then
905925 report.warning(" [Internal error] Unexpected resolution failure: ref.klass = " + ref.klass.show + " , field = " + field.show + Trace .show, Trace .position)
906926 Bottom
907927 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
911931
912932 case fun : Fun =>
913933 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):
917937 report.warning(" [Internal error] unexpected tree in selecting an array, array = " + arr.show + Trace .show, Trace .position)
918938 Bottom
919939
920- case Bottom =>
940+ case Bottom => // TODO: add a value for packages?
921941 if field.isStaticObject then accessObject(field.moduleClass.asClass)
922942 else Bottom
923943
@@ -943,7 +963,7 @@ class Objects(using Context @constructorOnly):
943963 case Cold =>
944964 report.warning(" Assigning to cold aliases is forbidden. " + Trace .show, Trace .position)
945965
946- case Bottom =>
966+ case BaseOrUnknownValue | Bottom =>
947967
948968 case ValueSet (values) =>
949969 values.foreach(ref => assign(ref, field, rhs, rhsTyp))
@@ -978,6 +998,9 @@ class Objects(using Context @constructorOnly):
978998 report.warning(" [Internal error] unexpected outer in instantiating a class, outer = " + outer.show + " , class = " + klass.show + " , " + Trace .show, Trace .position)
979999 Bottom
9801000
1001+ case BaseOrUnknownValue =>
1002+ BaseOrUnknownValue
1003+
9811004 case outer : (Ref | Cold .type | Bottom .type ) =>
9821005 if klass == defn.ArrayClass then
9831006 args.head.tree.tpe match
@@ -1068,6 +1091,7 @@ class Objects(using Context @constructorOnly):
10681091 case Cold =>
10691092 report.warning(" Calling cold by-name alias. " + Trace .show, Trace .position)
10701093 Bottom
1094+ case BaseOrUnknownValue => BaseOrUnknownValue
10711095 case _ : ValueSet | _ : Ref | _ : OfArray =>
10721096 report.warning(" [Internal error] Unexpected by-name value " + value.show + " . " + Trace .show, Trace .position)
10731097 Bottom
@@ -1257,7 +1281,7 @@ class Objects(using Context @constructorOnly):
12571281 evalType(expr.tpe, thisV, klass)
12581282
12591283 case Literal (_) =>
1260- Bottom
1284+ BaseOrUnknownValue
12611285
12621286 case Typed (expr, tpt) =>
12631287 if tpt.tpe.hasAnnotation(defn.UncheckedAnnot ) then
@@ -1511,7 +1535,9 @@ class Objects(using Context @constructorOnly):
15111535 end if
15121536 end if
15131537 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)
15151541
15161542 case Ident (nme.WILDCARD ) | Ident (nme.WILDCARD_STAR ) =>
15171543 (defn.ThrowableType , scrutinee)
@@ -1533,26 +1559,26 @@ class Objects(using Context @constructorOnly):
15331559 // call .lengthCompare or .length
15341560 val lengthCompareDenot = getMemberMethod(scrutineeType, nme.lengthCompare, lengthCompareType)
15351561 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 )
15371563 else
15381564 val lengthDenot = getMemberMethod(scrutineeType, nme.length, lengthType)
15391565 call(scrutinee, lengthDenot.symbol, Nil , scrutineeType, superType = NoType , needResolve = true )
15401566 end if
15411567
15421568 // call .apply
15431569 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 )
15451571
15461572 if isWildcardStarArgList(pats) then
15471573 if pats.size == 1 then
15481574 // call .toSeq
1549- val toSeqDenot = scrutineeType.member( nme.toSeq).suchThat(_.info.isParameterless )
1575+ val toSeqDenot = getMemberMethod(scrutineeType, nme.toSeq, toSeqType(elemType) )
15501576 val toSeqRes = call(scrutinee, toSeqDenot.symbol, Nil , scrutineeType, superType = NoType , needResolve = true )
15511577 evalPattern(toSeqRes, pats.head)
15521578 else
15531579 // 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 )
15561582 for pat <- pats.init do evalPattern(applyRes, pat)
15571583 evalPattern(dropRes, pats.last)
15581584 end if
@@ -1575,7 +1601,7 @@ class Objects(using Context @constructorOnly):
15751601 caseResults.addOne(eval(caseDef.body, thisV, klass))
15761602 if catchesAllOf(caseDef, tpe) then
15771603 remainingScrutinee = remainingScrutinee.remove(value)
1578-
1604+
15791605 caseResults.join
15801606 end patternMatch
15811607
@@ -1594,12 +1620,12 @@ class Objects(using Context @constructorOnly):
15941620 def evalType (tp : Type , thisV : ThisValue , klass : ClassSymbol , elideObjectAccess : Boolean = false ): Contextual [Value ] = log(" evaluating " + tp.show, printer, (_ : Value ).show) {
15951621 tp match
15961622 case _ : ConstantType =>
1597- Bottom
1623+ BaseOrUnknownValue
15981624
15991625 case tmref : TermRef if tmref.prefix == NoPrefix =>
16001626 val sym = tmref.symbol
16011627 if sym.is(Flags .Package ) then
1602- Bottom
1628+ Bottom // TODO: package value?
16031629 else if sym.owner.isClass then
16041630 // The typer incorrectly assigns a TermRef with NoPrefix for `config`,
16051631 // while the actual denotation points to the symbol of the class member
@@ -1833,6 +1859,7 @@ class Objects(using Context @constructorOnly):
18331859 else
18341860 thisV match
18351861 case Bottom => Bottom
1862+ case BaseOrUnknownValue => BaseOrUnknownValue
18361863 case Cold => Cold
18371864 case ref : Ref =>
18381865 val outerCls = klass.owner.lexicallyEnclosingClass.asClass
0 commit comments