Skip to content

Commit 7db959e

Browse files
author
EnzeXing
committed
Add BaseOrUnknownValue
1 parent 637a5f6 commit 7db959e

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
@@ -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

Comments
 (0)