Skip to content

Commit c64586b

Browse files
author
EnzeXing
committed
Add BaseOrUnknownValue
1 parent fcded74 commit c64586b

File tree

1 file changed

+48
-21
lines changed

1 file changed

+48
-21
lines changed

Diff for: compiler/src/dotty/tools/dotc/transform/init/Objects.scala

+48-21
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
@@ -636,12 +643,15 @@ class Objects(using Context @constructorOnly):
636643
if baseClasses.isEmpty then a
637644
else filterClass(baseClasses.head) // could have called ClassSymbol, but it does not handle OrType and AndType
638645

646+
// Filter the value according to a class symbol, and only leaves the sub-values
647+
// which could represent an object of the given class
639648
def filterClass(sym: Symbol)(using Context): Value =
640649
if !sym.isClass then a
641650
else
642651
val klass = sym.asClass
643652
a match
644653
case Cold => Cold
654+
case BaseOrUnknownValue => BaseOrUnknownValue
645655
case ref: Ref => if ref.klass.isSubClass(klass) then ref else Bottom
646656
case ValueSet(values) => values.map(v => v.filterClass(klass)).join
647657
case arr: OfArray => if defn.ArrayClass.isSubClass(klass) then arr else Bottom
@@ -674,6 +684,13 @@ class Objects(using Context @constructorOnly):
674684
case Bottom =>
675685
Bottom
676686

687+
// Bottom arguments mean unreachable call
688+
case _ if args.map(_.value).contains(Bottom) =>
689+
Bottom
690+
691+
case BaseOrUnknownValue =>
692+
BaseOrUnknownValue
693+
677694
case arr: OfArray =>
678695
val target = resolve(defn.ArrayClass, meth)
679696

@@ -692,7 +709,7 @@ class Objects(using Context @constructorOnly):
692709
Bottom
693710
else
694711
// Array.length is OK
695-
Bottom
712+
BaseOrUnknownValue
696713

697714
case ref: Ref =>
698715
val isLocal = !meth.owner.isClass
@@ -713,7 +730,7 @@ class Objects(using Context @constructorOnly):
713730
arr
714731
else if target.equals(defn.Predef_classOf) then
715732
// Predef.classOf is a stub method in tasty and is replaced in backend
716-
Bottom
733+
BaseOrUnknownValue
717734
else if target.hasSource then
718735
val cls = target.owner.enclosingClass.asClass
719736
val ddef = target.defTree.asInstanceOf[DefDef]
@@ -736,7 +753,7 @@ class Objects(using Context @constructorOnly):
736753
}
737754
}
738755
else
739-
Bottom
756+
BaseOrUnknownValue
740757
else if target.exists then
741758
select(ref, target, receiver, needResolve = false)
742759
else
@@ -804,7 +821,7 @@ class Objects(using Context @constructorOnly):
804821
}
805822
else
806823
// no source code available
807-
Bottom
824+
BaseOrUnknownValue
808825

809826
case _ =>
810827
report.warning("[Internal error] unexpected constructor call, meth = " + ctor + ", this = " + value + Trace.show, Trace.position)
@@ -824,6 +841,9 @@ class Objects(using Context @constructorOnly):
824841
report.warning("Using cold alias", Trace.position)
825842
Bottom
826843

844+
case BaseOrUnknownValue =>
845+
BaseOrUnknownValue
846+
827847
case ref: Ref =>
828848
val target = if needResolve then resolve(ref.klass, field) else field
829849
if target.is(Flags.Lazy) then
@@ -832,7 +852,7 @@ class Objects(using Context @constructorOnly):
832852
val rhs = target.defTree.asInstanceOf[ValDef].rhs
833853
eval(rhs, ref, target.owner.asClass, cacheResult = true)
834854
else
835-
Bottom
855+
BaseOrUnknownValue
836856
else if target.exists then
837857
def isNextFieldOfColonColon: Boolean = ref.klass == defn.ConsClass && target.name.toString == "next"
838858
if target.isOneOf(Flags.Mutable) && !isNextFieldOfColonColon then
@@ -848,24 +868,24 @@ class Objects(using Context @constructorOnly):
848868
Bottom
849869
else
850870
// initialization error, reported by the initialization checker
851-
Bottom
871+
BaseOrUnknownValue
852872
else if ref.hasVal(target) then
853873
ref.valValue(target)
854874
else if ref.isObjectRef && ref.klass.hasSource then
855875
report.warning("Access uninitialized field " + field.show + ". " + Trace.show, Trace.position)
856876
Bottom
857877
else
858878
// initialization error, reported by the initialization checker
859-
Bottom
879+
BaseOrUnknownValue
860880

861881
else
862882
if ref.klass.isSubClass(receiver.widenSingleton.classSymbol) then
863883
report.warning("[Internal error] Unexpected resolution failure: ref.klass = " + ref.klass.show + ", field = " + field.show + Trace.show, Trace.position)
864884
Bottom
865885
else
866-
// This is possible due to incorrect type cast.
867-
// See tests/init/pos/Type.scala
868-
Bottom
886+
// This is possible due to incorrect type cast or accessing standard library objects
887+
// See tests/init/pos/Type.scala / tests/init/warn/unapplySeq-implicit-arg2.scala
888+
BaseOrUnknownValue
869889

870890
case fun: Fun =>
871891
report.warning("[Internal error] unexpected tree in selecting a function, fun = " + fun.code.show + Trace.show, fun.code)
@@ -875,7 +895,7 @@ class Objects(using Context @constructorOnly):
875895
report.warning("[Internal error] unexpected tree in selecting an array, array = " + arr.show + Trace.show, Trace.position)
876896
Bottom
877897

878-
case Bottom =>
898+
case Bottom => // TODO: add a value for packages?
879899
if field.isStaticObject then accessObject(field.moduleClass.asClass)
880900
else Bottom
881901

@@ -901,7 +921,7 @@ class Objects(using Context @constructorOnly):
901921
case Cold =>
902922
report.warning("Assigning to cold aliases is forbidden. " + Trace.show, Trace.position)
903923

904-
case Bottom =>
924+
case BaseOrUnknownValue | Bottom =>
905925

906926
case ValueSet(values) =>
907927
values.foreach(ref => assign(ref, field, rhs, rhsTyp))
@@ -936,6 +956,9 @@ class Objects(using Context @constructorOnly):
936956
report.warning("[Internal error] unexpected outer in instantiating a class, outer = " + outer.show + ", class = " + klass.show + ", " + Trace.show, Trace.position)
937957
Bottom
938958

959+
case BaseOrUnknownValue =>
960+
BaseOrUnknownValue
961+
939962
case outer: (Ref | Cold.type | Bottom.type) =>
940963
if klass == defn.ArrayClass then
941964
args.head.tree.tpe match
@@ -1024,6 +1047,7 @@ class Objects(using Context @constructorOnly):
10241047
case Cold =>
10251048
report.warning("Calling cold by-name alias. " + Trace.show, Trace.position)
10261049
Bottom
1050+
case BaseOrUnknownValue => BaseOrUnknownValue
10271051
case _: ValueSet | _: Ref | _: OfArray =>
10281052
report.warning("[Internal error] Unexpected by-name value " + value.show + ". " + Trace.show, Trace.position)
10291053
Bottom
@@ -1212,7 +1236,7 @@ class Objects(using Context @constructorOnly):
12121236
evalType(expr.tpe, thisV, klass)
12131237

12141238
case Literal(_) =>
1215-
Bottom
1239+
BaseOrUnknownValue
12161240

12171241
case Typed(expr, tpt) =>
12181242
if tpt.tpe.hasAnnotation(defn.UncheckedAnnot) then
@@ -1354,7 +1378,7 @@ class Objects(using Context @constructorOnly):
13541378
*
13551379
* Currently, we assume all cases are reachable, thus all patterns are assumed to match.
13561380
*/
1357-
def evalPattern(scrutinee: Value, pat: Tree): (Type, Value) = log("match " + scrutinee.show + " against " + pat.show, printer, (_: (Type, Value))._2.show):
1381+
def evalPattern(scrutinee: Value, pat: Tree): (Type, Value) = forcelog("match " + scrutinee.show + " against " + pat.show, printer, (_: (Type, Value))._2.show):
13581382
val trace2 = Trace.trace.add(pat)
13591383
pat match
13601384
case Alternative(pats) =>
@@ -1466,7 +1490,9 @@ class Objects(using Context @constructorOnly):
14661490
end if
14671491
end if
14681492
end if
1469-
(receiverType, scrutinee.filterType(receiverType))
1493+
// TODO: receiverType is the companion object type, not the class itself;
1494+
// cannot filter scritunee by this type
1495+
(receiverType, scrutinee)
14701496

14711497
case Ident(nme.WILDCARD) | Ident(nme.WILDCARD_STAR) =>
14721498
(defn.ThrowableType, scrutinee)
@@ -1488,15 +1514,15 @@ class Objects(using Context @constructorOnly):
14881514
// call .lengthCompare or .length
14891515
val lengthCompareDenot = getMemberMethod(scrutineeType, nme.lengthCompare, lengthCompareType)
14901516
if lengthCompareDenot.exists then
1491-
call(scrutinee, lengthCompareDenot.symbol, ArgInfo(Bottom, summon[Trace], EmptyTree) :: Nil, scrutineeType, superType = NoType, needResolve = true)
1517+
call(scrutinee, lengthCompareDenot.symbol, ArgInfo(BaseOrUnknownValue, summon[Trace], EmptyTree) :: Nil, scrutineeType, superType = NoType, needResolve = true)
14921518
else
14931519
val lengthDenot = getMemberMethod(scrutineeType, nme.length, lengthType)
14941520
call(scrutinee, lengthDenot.symbol, Nil, scrutineeType, superType = NoType, needResolve = true)
14951521
end if
14961522

14971523
// call .apply
14981524
val applyDenot = getMemberMethod(scrutineeType, nme.apply, applyType(elemType))
1499-
val applyRes = call(scrutinee, applyDenot.symbol, ArgInfo(Bottom, summon[Trace], EmptyTree) :: Nil, scrutineeType, superType = NoType, needResolve = true)
1525+
val applyRes = call(scrutinee, applyDenot.symbol, ArgInfo(BaseOrUnknownValue, summon[Trace], EmptyTree) :: Nil, scrutineeType, superType = NoType, needResolve = true)
15001526

15011527
if isWildcardStarArgList(pats) then
15021528
if pats.size == 1 then
@@ -1507,7 +1533,7 @@ class Objects(using Context @constructorOnly):
15071533
else
15081534
// call .drop
15091535
val dropDenot = getMemberMethod(scrutineeType, nme.drop, applyType(elemType))
1510-
val dropRes = call(scrutinee, dropDenot.symbol, ArgInfo(Bottom, summon[Trace], EmptyTree) :: Nil, scrutineeType, superType = NoType, needResolve = true)
1536+
val dropRes = call(scrutinee, dropDenot.symbol, ArgInfo(BaseOrUnknownValue, summon[Trace], EmptyTree) :: Nil, scrutineeType, superType = NoType, needResolve = true)
15111537
for pat <- pats.init do evalPattern(applyRes, pat)
15121538
evalPattern(dropRes, pats.last)
15131539
end if
@@ -1530,7 +1556,7 @@ class Objects(using Context @constructorOnly):
15301556
caseResults.addOne(eval(caseDef.body, thisV, klass))
15311557
if catchesAllOf(caseDef, tpe) then
15321558
remainingScrutinee = remainingScrutinee.remove(value)
1533-
1559+
15341560
caseResults.join
15351561
end patternMatch
15361562

@@ -1549,12 +1575,12 @@ class Objects(using Context @constructorOnly):
15491575
def evalType(tp: Type, thisV: ThisValue, klass: ClassSymbol, elideObjectAccess: Boolean = false): Contextual[Value] = log("evaluating " + tp.show, printer, (_: Value).show) {
15501576
tp match
15511577
case _: ConstantType =>
1552-
Bottom
1578+
BaseOrUnknownValue
15531579

15541580
case tmref: TermRef if tmref.prefix == NoPrefix =>
15551581
val sym = tmref.symbol
15561582
if sym.is(Flags.Package) then
1557-
Bottom
1583+
Bottom // TODO: package value?
15581584
else if sym.owner.isClass then
15591585
// The typer incorrectly assigns a TermRef with NoPrefix for `config`,
15601586
// while the actual denotation points to the symbol of the class member
@@ -1788,6 +1814,7 @@ class Objects(using Context @constructorOnly):
17881814
else
17891815
thisV match
17901816
case Bottom => Bottom
1817+
case BaseOrUnknownValue => BaseOrUnknownValue
17911818
case Cold => Cold
17921819
case ref: Ref =>
17931820
val outerCls = klass.owner.lexicallyEnclosingClass.asClass

0 commit comments

Comments
 (0)