Skip to content

Commit e84dc7a

Browse files
author
EnzeXing
committed
Add BaseOrUnknownValue
1 parent ac5d1e5 commit e84dc7a

File tree

1 file changed

+49
-22
lines changed

1 file changed

+49
-22
lines changed

compiler/src/dotty/tools/dotc/transform/init/Objects.scala

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import util.{ SourcePosition, NoSourcePosition }
1818
import config.Printers.init as printer
1919
import reporting.StoreReporter
2020
import reporting.trace as log
21+
import reporting.trace.force as forcelog
2122
import typer.Applications.*
2223

2324
import 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

Comments
 (0)