From 8ab198d95a90b4a160e0ee18d322ef968111dbaf Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Mon, 10 Jun 2024 22:26:12 +0200 Subject: [PATCH 1/3] Filter values by class before member selection --- .../tools/dotc/transform/init/Semantic.scala | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala index caf3435608d2..85b2764ff0f3 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala @@ -548,9 +548,23 @@ object Semantic: value.promote(msg) value + def filterClass(sym: Symbol)(using Context): Value = + if !sym.isClass then value + else + val klass = sym.asClass + value match + case Cold => Cold + case Hot => Hot + case ref: Ref => if ref.klass.isSubClass(klass) then ref else Hot + case RefSet(values) => values.map(v => v.filterClass(klass)).join + case fun: Fun => + if klass.isOneOf(Flags.AbstractOrTrait) && klass.baseClasses.exists(defn.isFunctionClass) + then fun + else Hot + def select(field: Symbol, receiver: Type, needResolve: Boolean = true): Contextual[Value] = log("select " + field.show + ", this = " + value, printer, (_: Value).show) { if promoted.isCurrentObjectPromoted then Hot - else value match + else value.filterClass(field.owner) match case Hot => Hot @@ -588,13 +602,8 @@ object Semantic: reporter.report(error) Hot else - if ref.klass.isSubClass(receiver.widenSingleton.classSymbol) then - report.warning("[Internal error] Unexpected resolution failure: ref.klass = " + ref.klass.show + ", field = " + field.show + Trace.show, Trace.position) - Hot - else - // This is possible due to incorrect type cast. - // See tests/init/pos/Type.scala - Hot + report.warning("[Internal error] Unexpected resolution failure: ref.klass = " + ref.klass.show + ", field = " + field.show + Trace.show, Trace.position) + Hot case fun: Fun => report.warning("[Internal error] unexpected tree in selecting a function, fun = " + fun.expr.show + Trace.show, fun.expr) @@ -645,11 +654,16 @@ object Semantic: } (errors, allArgsHot) + def filterValue(value: Value): Value = + // methods of polyfun does not have denotation + if !meth.exists then value + else value.filterClass(meth.owner) + // fast track if the current object is already initialized if promoted.isCurrentObjectPromoted then Hot else if isAlwaysSafe(meth) then Hot else if meth eq defn.Any_asInstanceOf then value - else value match { + else filterValue(value) match { case Hot => if isSyntheticApply(meth) && meth.hasSource then val klass = meth.owner.companionClass.asClass @@ -724,13 +738,8 @@ object Semantic: else value.select(target, receiver, needResolve = false) else - if ref.klass.isSubClass(receiver.widenSingleton.classSymbol) then - report.warning("[Internal error] Unexpected resolution failure: ref.klass = " + ref.klass.show + ", meth = " + meth.show + Trace.show, Trace.position) - Hot - else - // This is possible due to incorrect type cast. - // See tests/init/pos/Type.scala - Hot + report.warning("[Internal error] Unexpected resolution failure: ref.klass = " + ref.klass.show + ", meth = " + meth.show + Trace.show, Trace.position) + Hot case Fun(body, thisV, klass) => // meth == NoSymbol for poly functions @@ -822,7 +831,7 @@ object Semantic: warm if promoted.isCurrentObjectPromoted then Hot - else value match { + else value.filterClass(klass.owner) match { case Hot => var allHot = true val args2 = args.map { arg => From f75f6dc211081715cc6abb54e83c602b5c6f1cbb Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Mon, 10 Jun 2024 22:27:12 +0200 Subject: [PATCH 2/3] Add test --- tests/init/warn/type-filter.scala | 15 +++++++++++++++ tests/init/warn/type-filter2.scala | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/init/warn/type-filter.scala create mode 100644 tests/init/warn/type-filter2.scala diff --git a/tests/init/warn/type-filter.scala b/tests/init/warn/type-filter.scala new file mode 100644 index 000000000000..1d25454992fe --- /dev/null +++ b/tests/init/warn/type-filter.scala @@ -0,0 +1,15 @@ +class A(o: O): + var a = 20 + +class B(o: O): + var b = 20 + +class O: + val o: A | B = new A(this) + if o.isInstanceOf[A] then + o.asInstanceOf[A].a += 1 + else + o.asInstanceOf[B].b += 1 // o.asInstanceOf[B] is treated as bottom + + // prevent early promotion + val x = 10 diff --git a/tests/init/warn/type-filter2.scala b/tests/init/warn/type-filter2.scala new file mode 100644 index 000000000000..65f5be8f4b53 --- /dev/null +++ b/tests/init/warn/type-filter2.scala @@ -0,0 +1,19 @@ +class A(c: C): + val f: Int = 10 + def m() = f + +class B(c: C): + val f: Int = g() // warn + def g(): Int = f + +class C(x: Int): + val a: A | B = if x > 0 then new A(this) else new B(this) + + def cast[T](a: Any): T = a.asInstanceOf[T] + + val c: A = a.asInstanceOf[A] // abstraction for c is {A, B} + val d = c.f // treat as c.asInstanceOf[owner of f].f + val e = c.m() // treat as c.asInstanceOf[owner of f].m() + val c2: B = a.asInstanceOf[B] + val g = c2.f // no error here + From 8e4aa195e630475af71a007309040da06bcfa7b2 Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Fri, 14 Jun 2024 22:16:45 +0200 Subject: [PATCH 3/3] Fix typo in comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ondřej Lhoták --- tests/init/warn/type-filter2.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/init/warn/type-filter2.scala b/tests/init/warn/type-filter2.scala index 65f5be8f4b53..cc9a8f8b00d0 100644 --- a/tests/init/warn/type-filter2.scala +++ b/tests/init/warn/type-filter2.scala @@ -13,7 +13,7 @@ class C(x: Int): val c: A = a.asInstanceOf[A] // abstraction for c is {A, B} val d = c.f // treat as c.asInstanceOf[owner of f].f - val e = c.m() // treat as c.asInstanceOf[owner of f].m() + val e = c.m() // treat as c.asInstanceOf[owner of m].m() val c2: B = a.asInstanceOf[B] val g = c2.f // no error here