Skip to content

Commit 16ecedd

Browse files
author
EnzeXing
committed
Add supports for type cast and filtering type for field and method owners
1 parent 1716bcd commit 16ecedd

File tree

4 files changed

+64
-7
lines changed

4 files changed

+64
-7
lines changed

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

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,22 @@ object Objects:
599599

600600
case _ => a
601601

602+
def filterType(tpe: Type)(using Context): Value =
603+
val baseClasses = tpe.baseClasses
604+
if baseClasses.isEmpty then a
605+
else filterClass(baseClasses.head)
606+
607+
def filterClass(sym: Symbol)(using Context): Value =
608+
if !sym.isClass then a
609+
else
610+
val klass = sym.asClass
611+
a match
612+
case Cold => Cold
613+
case ref: Ref if ref.klass.isSubClass(klass) => ref
614+
case ref: Ref => Bottom
615+
case ValueSet(values) => values.map(v => v.filterClass(klass)).join
616+
case _ => a // TODO: could be more precise for OfArray; possibly add class information for Fun
617+
602618
extension (value: Ref | Cold.type)
603619
def widenRefOrCold(height : Int)(using Context) : Ref | Cold.type = value.widen(height).asInstanceOf[ThisValue]
604620

@@ -617,7 +633,7 @@ object Objects:
617633
* @param needResolve Whether the target of the call needs resolution?
618634
*/
619635
def call(value: Value, meth: Symbol, args: List[ArgInfo], receiver: Type, superType: Type, needResolve: Boolean = true): Contextual[Value] = log("call " + meth.show + ", this = " + value.show + ", args = " + args.map(_.value.show), printer, (_: Value).show) {
620-
value match
636+
value.filterClass(meth.owner) match
621637
case Cold =>
622638
report.warning("Using cold alias. " + Trace.show, Trace.position)
623639
Bottom
@@ -733,7 +749,6 @@ object Objects:
733749
* @param args Arguments of the constructor call (all parameter blocks flatten to a list).
734750
*/
735751
def callConstructor(value: Value, ctor: Symbol, args: List[ArgInfo]): Contextual[Value] = log("call " + ctor.show + ", args = " + args.map(_.value.show), printer, (_: Value).show) {
736-
737752
value match
738753
case ref: Ref =>
739754
if ctor.hasSource then
@@ -768,7 +783,7 @@ object Objects:
768783
* @param needResolve Whether the target of the selection needs resolution?
769784
*/
770785
def select(value: Value, field: Symbol, receiver: Type, needResolve: Boolean = true): Contextual[Value] = log("select " + field.show + ", this = " + value.show, printer, (_: Value).show) {
771-
value match
786+
value.filterClass(field.owner) match
772787
case Cold =>
773788
report.warning("Using cold alias", Trace.position)
774789
Bottom
@@ -839,12 +854,12 @@ object Objects:
839854
* @param rhsTyp The type of the right-hand side.
840855
*/
841856
def assign(lhs: Value, field: Symbol, rhs: Value, rhsTyp: Type): Contextual[Value] = log("Assign" + field.show + " of " + lhs.show + ", rhs = " + rhs.show, printer, (_: Value).show) {
842-
lhs match
857+
lhs.filterClass(field.owner) match
843858
case fun: Fun =>
844859
report.warning("[Internal error] unexpected tree in assignment, fun = " + fun.code.show + Trace.show, Trace.position)
845860

846861
case arr: OfArray =>
847-
report.warning("[Internal error] unexpected tree in assignment, array = " + arr.show + Trace.show, Trace.position)
862+
report.warning("[Internal error] unexpected tree in assignment, array = " + arr.show + s", owner = ${field.owner}\n" + Trace.show, Trace.position)
848863

849864
case Cold =>
850865
report.warning("Assigning to cold aliases is forbidden. " + Trace.show, Trace.position)
@@ -876,8 +891,7 @@ object Objects:
876891
* @param args The arguments passsed to the constructor.
877892
*/
878893
def instantiate(outer: Value, klass: ClassSymbol, ctor: Symbol, args: List[ArgInfo]): Contextual[Value] = log("instantiating " + klass.show + ", outer = " + outer + ", args = " + args.map(_.value.show), printer, (_: Value).show) {
879-
outer match
880-
894+
outer.filterClass(klass.owner) match
881895
case _ : Fun | _: OfArray =>
882896
report.warning("[Internal error] unexpected outer in instantiating a class, outer = " + outer.show + ", class = " + klass.show + ", " + Trace.show, Trace.position)
883897
Bottom
@@ -1091,6 +1105,9 @@ object Objects:
10911105
instantiate(outer, cls, ctor, args)
10921106
}
10931107

1108+
case TypeCast(elem, tpe) =>
1109+
eval(elem, thisV, klass).filterType(tpe)
1110+
10941111
case Apply(ref, arg :: Nil) if ref.symbol == defn.InitRegionMethod =>
10951112
val regions2 = Regions.extend(expr.sourcePos)
10961113
if Regions.exists(expr.sourcePos) then

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ object Util:
7878
case _ =>
7979
None
8080

81+
object TypeCast:
82+
def unapply(tree: Tree)(using Context): Option[(Tree, Type)] =
83+
tree match
84+
case TypeApply(Select(qual, _), typeArg) if tree.symbol.isTypeCast =>
85+
Some(qual, typeArg.head.tpe)
86+
case _ => None
87+
8188
def resolve(cls: ClassSymbol, sym: Symbol)(using Context): Symbol = log("resove " + cls + ", " + sym, printer, (_: Symbol).show):
8289
if sym.isEffectivelyFinal then sym
8390
else sym.matchingMember(cls.appliedRef)

tests/init-global/neg/TypeCast.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
object A {
2+
val f: Int = 10
3+
def m() = f
4+
}
5+
object B {
6+
val f: Int = g()
7+
def g(): Int = f // error
8+
}
9+
object C {
10+
val a: A.type | B.type = if ??? then A else B
11+
def cast[T](a: Any): T = a.asInstanceOf[T]
12+
val c: A.type = cast[A.type](a) // abstraction for c is {A, B}
13+
val d = c.f // treat as c.asInstanceOf[owner of f].f
14+
val e = c.m() // treat as c.asInstanceOf[owner of f].m()
15+
val c2: B.type = cast[B.type](a)
16+
val g = c2.f // no error here
17+
}
18+

tests/init-global/pos/i18882.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class A:
2+
var a = 20
3+
4+
class B:
5+
var b = 20
6+
7+
object O:
8+
val o: A | B = new A
9+
if o.isInstanceOf[A] then
10+
o.asInstanceOf[A].a += 1
11+
else
12+
o.asInstanceOf[B].b += 1 // o.asInstanceOf[B] is treated as bottom
13+
o match
14+
case o: A => o.a += 1
15+
case o: B => o.b += 1

0 commit comments

Comments
 (0)