From 3dd4c6df7db4a9fbc788afea01649162e91fff6e Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Tue, 6 Sep 2022 23:19:24 +0200 Subject: [PATCH 1/5] Fix #15883: Interpret inner static object access as this access --- .../tools/dotc/transform/init/Semantic.scala | 19 +++++++++++-------- tests/init/neg/i15883.scala | 2 ++ 2 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 tests/init/neg/i15883.scala diff --git a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala index 4cb08312b0c9..c6ae00d7e248 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala @@ -156,7 +156,7 @@ object Semantic: def hasField(f: Symbol) = fields.contains(f) object Promoted: - class PromotionInfo: + class PromotionInfo(val entryClass: ClassSymbol): var isCurrentObjectPromoted: Boolean = false val values = mutable.Set.empty[Value] override def toString(): String = values.toString() @@ -165,7 +165,7 @@ object Semantic: opaque type Promoted = PromotionInfo /** Note: don't use `val` to avoid incorrect sharing */ - def empty: Promoted = new PromotionInfo + def empty(entryClass: ClassSymbol): Promoted = new PromotionInfo(entryClass) extension (promoted: Promoted) def isCurrentObjectPromoted: Boolean = promoted.isCurrentObjectPromoted @@ -173,6 +173,7 @@ object Semantic: def contains(value: Value): Boolean = promoted.values.contains(value) def add(value: Value): Unit = promoted.values += value def remove(value: Value): Unit = promoted.values -= value + def entryClass: ClassSymbol = promoted.entryClass end extension end Promoted type Promoted = Promoted.Promoted @@ -658,7 +659,7 @@ object Semantic: 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 match case Hot => Hot @@ -710,7 +711,6 @@ object Semantic: case RefSet(refs) => refs.map(_.select(field, receiver)).join - } } def call(meth: Symbol, args: List[ArgInfo], receiver: Type, superType: Type, needResolve: Boolean = true): Contextual[Value] = log("call " + meth.show + ", args = " + args.map(_.value.show), printer, (_: Value).show) { @@ -1230,7 +1230,7 @@ object Semantic: @tailrec def iterate(): Unit = { - given Promoted = Promoted.empty + given Promoted = Promoted.empty(thisRef.klass) given Trace = Trace.empty.add(thisRef.klass.defTree) given reporter: Reporter.BufferedReporter = new Reporter.BufferedReporter @@ -1513,7 +1513,11 @@ object Semantic: thisV.accessLocal(tmref, klass) case tmref: TermRef => - cases(tmref.prefix, thisV, klass).select(tmref.symbol, receiver = tmref.prefix) + val cls = tmref.widenSingleton.classSymbol.asClass + if cls.isStaticOwner && !cls.isContainedIn(promoted.entryClass) then + Hot + else + cases(tmref.prefix, thisV, klass).select(tmref.symbol, receiver = tmref.prefix) case tp @ ThisType(tref) => val cls = tref.classSymbol.asClass @@ -1521,8 +1525,7 @@ object Semantic: // O.this outside the body of the object O Hot else - val value = resolveThis(cls, thisV, klass) - value + resolveThis(cls, thisV, klass) case _: TermParamRef | _: RecThis => // possible from checking effects of types diff --git a/tests/init/neg/i15883.scala b/tests/init/neg/i15883.scala new file mode 100644 index 000000000000..6f6e3066a878 --- /dev/null +++ b/tests/init/neg/i15883.scala @@ -0,0 +1,2 @@ +val a = b +val b = 1 // error From fe235e93535e62e7358f9ea532fda79f3ca864c4 Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Tue, 6 Sep 2022 23:43:18 +0200 Subject: [PATCH 2/5] Avoid shoing trace in debugging logs --- .../tools/dotc/transform/init/Errors.scala | 18 +++++------ .../tools/dotc/transform/init/Semantic.scala | 30 ++++++++++--------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/init/Errors.scala b/compiler/src/dotty/tools/dotc/transform/init/Errors.scala index 38d2263b54c3..7d92d2b2a921 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Errors.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Errors.scala @@ -79,7 +79,7 @@ object Errors: override def toString() = this.getClass.getName.nn /** Access non-initialized field */ - case class AccessNonInit(field: Symbol, trace: Seq[Tree]) extends Error: + case class AccessNonInit(field: Symbol)(val trace: Seq[Tree]) extends Error: def source: Tree = trace.last def show(using Context): String = "Access non-initialized " + field.show + "." + stacktrace @@ -87,27 +87,27 @@ object Errors: override def pos(using Context): SourcePosition = field.sourcePos /** Promote a value under initialization to fully-initialized */ - case class PromoteError(msg: String, trace: Seq[Tree]) extends Error: + case class PromoteError(msg: String)(val trace: Seq[Tree]) extends Error: def show(using Context): String = msg + stacktrace - case class AccessCold(field: Symbol, trace: Seq[Tree]) extends Error: + case class AccessCold(field: Symbol)(val trace: Seq[Tree]) extends Error: def show(using Context): String = "Access field " + field.show + " on a cold object." + stacktrace - case class CallCold(meth: Symbol, trace: Seq[Tree]) extends Error: + case class CallCold(meth: Symbol)(val trace: Seq[Tree]) extends Error: def show(using Context): String = "Call method " + meth.show + " on a cold object." + stacktrace - case class CallUnknown(meth: Symbol, trace: Seq[Tree]) extends Error: + case class CallUnknown(meth: Symbol)(val trace: Seq[Tree]) extends Error: def show(using Context): String = val prefix = if meth.is(Flags.Method) then "Calling the external method " else "Accessing the external field" prefix + meth.show + " may cause initialization errors." + stacktrace /** Promote a value under initialization to fully-initialized */ - case class UnsafePromotion(msg: String, trace: Seq[Tree], error: Error) extends Error: + case class UnsafePromotion(msg: String, error: Error)(val trace: Seq[Tree]) extends Error: def show(using Context): String = msg + stacktrace + "\n" + - "Promoting the value to hot failed due to the following problem:\n" + { + "Promoting the value to hot (transitively initialized) failed due to the following problem:\n" + { val ctx2 = ctx.withProperty(IsFromPromotion, Some(true)) error.show(using ctx2) } @@ -116,7 +116,7 @@ object Errors: * * Invariant: argsIndices.nonEmpty */ - case class UnsafeLeaking(trace: Seq[Tree], error: Error, nonHotOuterClass: Symbol, argsIndices: List[Int]) extends Error: + case class UnsafeLeaking(error: Error, nonHotOuterClass: Symbol, argsIndices: List[Int])(val trace: Seq[Tree]) extends Error: def show(using Context): String = "Problematic object instantiation: " + argumentInfo() + stacktrace + "\n" + "It leads to the following error during object initialization:\n" + @@ -141,5 +141,5 @@ object Errors: acc + text2 } val verb = if multiple then " are " else " is " - val adjective = "not hot." + val adjective = "not hot (transitively initialized)." subject + verb + adjective diff --git a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala index c6ae00d7e248..7805657fb9ea 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala @@ -12,7 +12,7 @@ import NameKinds.SuperAccessorName import ast.tpd.* import config.Printers.init as printer -import reporting.trace as log +import reporting.trace.force as log import Errors.* @@ -664,7 +664,7 @@ object Semantic: Hot case Cold => - val error = AccessCold(field, trace.toVector) + val error = AccessCold(field)(trace.toVector) reporter.report(error) Hot @@ -689,11 +689,11 @@ object Semantic: val rhs = target.defTree.asInstanceOf[ValOrDefDef].rhs eval(rhs, ref, target.owner.asClass, cacheResult = true) else - val error = CallUnknown(field, trace.toVector) + val error = CallUnknown(field)(trace.toVector) reporter.report(error) Hot else - val error = AccessNonInit(target, trace.toVector) + val error = AccessNonInit(target)(trace.toVector) reporter.report(error) Hot else @@ -779,7 +779,7 @@ object Semantic: case Cold => promoteArgs() - val error = CallCold(meth, trace.toVector) + val error = CallCold(meth)(trace.toVector) reporter.report(error) Hot @@ -820,7 +820,7 @@ object Semantic: // try promoting the receiver as last resort val hasErrors = Reporter.hasErrors { ref.promote("try promote value to hot") } if hasErrors then - val error = CallUnknown(target, trace.toVector) + val error = CallUnknown(target)(trace.toVector) reporter.report(error) Hot else if target.exists then @@ -899,7 +899,7 @@ object Semantic: Hot else // no source code available - val error = CallUnknown(ctor, trace.toVector) + val error = CallUnknown(ctor)(trace.toVector) reporter.report(error) Hot } @@ -922,7 +922,7 @@ object Semantic: yield i + 1 - val error = UnsafeLeaking(trace.toVector, errors.head, nonHotOuterClass, indices) + val error = UnsafeLeaking(errors.head, nonHotOuterClass, indices)(trace.toVector) reporter.report(error) Hot else @@ -947,7 +947,7 @@ object Semantic: tryLeak(warm, NoSymbol, args2) case Cold => - val error = CallCold(ctor, trace.toVector) + val error = CallCold(ctor)(trace.toVector) reporter.report(error) Hot @@ -1078,7 +1078,7 @@ object Semantic: case Hot => case Cold => - reporter.report(PromoteError(msg, trace.toVector)) + reporter.report(PromoteError(msg)(trace.toVector)) case thisRef: ThisRef => val emptyFields = thisRef.nonInitFields() @@ -1086,7 +1086,7 @@ object Semantic: promoted.promoteCurrent(thisRef) else val fields = "Non initialized field(s): " + emptyFields.map(_.show).mkString(", ") + "." - reporter.report(PromoteError(msg + "\n" + fields, trace.toVector)) + reporter.report(PromoteError(msg + "\n" + fields)(trace.toVector)) case warm: Warm => if !promoted.contains(warm) then @@ -1106,7 +1106,7 @@ object Semantic: res.promote("The function return value is not hot. Found = " + res.show + ".") } if errors.nonEmpty then - reporter.report(UnsafePromotion(msg, trace.toVector, errors.head)) + reporter.report(UnsafePromotion(msg, errors.head)(trace.toVector)) else promoted.add(fun) @@ -1156,7 +1156,7 @@ object Semantic: if !isHotSegment then for member <- klass.info.decls do if member.isClass then - val error = PromoteError("Promotion cancelled as the value contains inner " + member.show + ".", Vector.empty) + val error = PromoteError("Promotion cancelled as the value contains inner " + member.show + ".")(Vector.empty) reporter.report(error) else if !member.isType && !member.isConstructor && !member.is(Flags.Deferred) then given Trace = Trace.empty @@ -1189,7 +1189,7 @@ object Semantic: } if errors.isEmpty then Nil - else UnsafePromotion(msg, trace.toVector, errors.head) :: Nil + else UnsafePromotion(msg, errors.head)(trace.toVector) :: Nil } end extension @@ -1516,6 +1516,8 @@ object Semantic: val cls = tmref.widenSingleton.classSymbol.asClass if cls.isStaticOwner && !cls.isContainedIn(promoted.entryClass) then Hot + else if cls.isStaticOwner && klass.isContainedIn(cls) then + resolveThis(cls, thisV, klass) else cases(tmref.prefix, thisV, klass).select(tmref.symbol, receiver = tmref.prefix) From d02edc7215ce84ee20db8b30510b02c4cbe5b1c8 Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Wed, 7 Sep 2022 00:03:52 +0200 Subject: [PATCH 3/5] Update check files --- .../tools/dotc/transform/init/Semantic.scala | 13 +++++-- tests/init/neg/closureLeak.check | 2 +- tests/init/neg/cycle-structure.check | 4 +-- tests/init/neg/i15363.check | 2 +- tests/init/neg/inherit-non-hot.check | 2 +- tests/init/neg/promotion-loop.check | 2 +- tests/init/neg/promotion-segment3.check | 2 +- tests/init/neg/secondary-ctor4.check | 36 +++++++++---------- tests/init/neg/t3273.check | 4 +-- 9 files changed, 38 insertions(+), 29 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala index 7805657fb9ea..e28664536de1 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala @@ -12,7 +12,7 @@ import NameKinds.SuperAccessorName import ast.tpd.* import config.Printers.init as printer -import reporting.trace.force as log +import reporting.trace as log import Errors.* @@ -1669,7 +1669,16 @@ object Semantic: if thisV.isThisRef || !thisV.asInstanceOf[Warm].isPopulatingParams then tpl.body.foreach { case vdef : ValDef if !vdef.symbol.is(Flags.Lazy) && !vdef.rhs.isEmpty => val res = eval(vdef.rhs, thisV, klass) - thisV.updateField(vdef.symbol, res) + // TODO: Improve promotion to avoid handling enum initialization specially + // + // The failing case is tests/init/pos/i12544.scala due to promotion failure. + if vdef.symbol.name == nme.DOLLAR_VALUES + && vdef.symbol.is(Flags.Synthetic) + && vdef.symbol.owner.companionClass.isAllOf(Flags.Enum) + then + thisV.updateField(vdef.symbol, Hot) + else + thisV.updateField(vdef.symbol, res) fieldsChanged = true case _: MemberDef => diff --git a/tests/init/neg/closureLeak.check b/tests/init/neg/closureLeak.check index db3ed8eea37b..7019f2274ab6 100644 --- a/tests/init/neg/closureLeak.check +++ b/tests/init/neg/closureLeak.check @@ -8,7 +8,7 @@ | -> l.foreach(a => a.addX(this)) // error [ closureLeak.scala:11 ] | ^^^^^^^^^^^^^^^^^ | - | Promoting the value to hot failed due to the following problem: + | Promoting the value to hot (transitively initialized) failed due to the following problem: | Cannot prove the method argument is hot. Only hot values are safe to leak. | Found = ThisRef[class Outer]. | Non initialized field(s): value p. Promotion trace: diff --git a/tests/init/neg/cycle-structure.check b/tests/init/neg/cycle-structure.check index 79eab40be867..fb7b54c7cac2 100644 --- a/tests/init/neg/cycle-structure.check +++ b/tests/init/neg/cycle-structure.check @@ -1,7 +1,7 @@ -- Error: tests/init/neg/cycle-structure.scala:3:13 -------------------------------------------------------------------- 3 | val x = B(this) // error | ^^^^^^^ - | Problematic object instantiation: arg 1 is not hot. Calling trace: + | Problematic object instantiation: arg 1 is not hot (transitively initialized). Calling trace: | -> case class A(b: B) { [ cycle-structure.scala:1 ] | ^ | -> val x = B(this) // error [ cycle-structure.scala:3 ] @@ -16,7 +16,7 @@ -- Error: tests/init/neg/cycle-structure.scala:9:13 -------------------------------------------------------------------- 9 | val x = A(this) // error | ^^^^^^^ - | Problematic object instantiation: arg 1 is not hot. Calling trace: + | Problematic object instantiation: arg 1 is not hot (transitively initialized). Calling trace: | -> case class B(a: A) { [ cycle-structure.scala:7 ] | ^ | -> val x = A(this) // error [ cycle-structure.scala:9 ] diff --git a/tests/init/neg/i15363.check b/tests/init/neg/i15363.check index e6d0d74e9618..84cf268ef8a1 100644 --- a/tests/init/neg/i15363.check +++ b/tests/init/neg/i15363.check @@ -1,7 +1,7 @@ -- Error: tests/init/neg/i15363.scala:3:10 ----------------------------------------------------------------------------- 3 | val b = new B(this) // error | ^^^^^^^^^^^ - | Problematic object instantiation: arg 1 is not hot. Calling trace: + | Problematic object instantiation: arg 1 is not hot (transitively initialized). Calling trace: | -> class A: [ i15363.scala:1 ] | ^ | -> val b = new B(this) // error [ i15363.scala:3 ] diff --git a/tests/init/neg/inherit-non-hot.check b/tests/init/neg/inherit-non-hot.check index fd25876cb38e..408196333a27 100644 --- a/tests/init/neg/inherit-non-hot.check +++ b/tests/init/neg/inherit-non-hot.check @@ -11,7 +11,7 @@ | -> if b == null then b = new B(this) // error [ inherit-non-hot.scala:6 ] | ^^^^^^^^^^^^^^^ | - | Promoting the value to hot failed due to the following problem: + | Promoting the value to hot (transitively initialized) failed due to the following problem: | Cannot prove that the field value a is hot. Found = Cold. Promotion trace: | -> class B(a: A) { [ inherit-non-hot.scala:10 ] | ^^^^ diff --git a/tests/init/neg/promotion-loop.check b/tests/init/neg/promotion-loop.check index 5d23841192b8..3d1eb7e74aec 100644 --- a/tests/init/neg/promotion-loop.check +++ b/tests/init/neg/promotion-loop.check @@ -8,7 +8,7 @@ | -> println(b) // error [ promotion-loop.scala:16 ] | ^ | - | Promoting the value to hot failed due to the following problem: + | Promoting the value to hot (transitively initialized) failed due to the following problem: | Cannot prove that the field value outer is hot. Found = ThisRef[class Test]. | Non initialized field(s): value n. Promotion trace: | -> val outer = test [ promotion-loop.scala:12 ] diff --git a/tests/init/neg/promotion-segment3.check b/tests/init/neg/promotion-segment3.check index 97b20022a2b2..220af18bd29a 100644 --- a/tests/init/neg/promotion-segment3.check +++ b/tests/init/neg/promotion-segment3.check @@ -8,5 +8,5 @@ | -> bar(new B) // error [ promotion-segment3.scala:9 ] | ^^^^^ | - | Promoting the value to hot failed due to the following problem: + | Promoting the value to hot (transitively initialized) failed due to the following problem: | Promotion cancelled as the value contains inner class C. diff --git a/tests/init/neg/secondary-ctor4.check b/tests/init/neg/secondary-ctor4.check index ce3dc3e6886d..1bf1a7286357 100644 --- a/tests/init/neg/secondary-ctor4.check +++ b/tests/init/neg/secondary-ctor4.check @@ -1,7 +1,7 @@ -- Error: tests/init/neg/secondary-ctor4.scala:54:14 ------------------------------------------------------------------- 54 | val c = new C(b, 5) // error | ^^^^^^^^^^^ - | Problematic object instantiation: arg 1 is not hot. Calling trace: + | Problematic object instantiation: arg 1 is not hot (transitively initialized). Calling trace: | -> class D { [ secondary-ctor4.scala:52 ] | ^ | -> val c = new C(b, 5) // error [ secondary-ctor4.scala:54 ] @@ -24,21 +24,21 @@ -- Error: tests/init/neg/secondary-ctor4.scala:42:4 -------------------------------------------------------------------- 42 | new A(new B(new D)) // error | ^^^^^^^^^^^^^^^^^^^ - | Problematic object instantiation: the outer M.this and arg 1 are not hot. Calling trace: - | -> class N(d: D) extends M(d) { [ secondary-ctor4.scala:59 ] - | ^ - | -> def this(d: D) = { [ secondary-ctor4.scala:7 ] - | ^ - | -> new A(new B(new D)) // error [ secondary-ctor4.scala:42 ] - | ^^^^^^^^^^^^^^^^^^^ + |Problematic object instantiation: the outer M.this and arg 1 are not hot (transitively initialized). Calling trace: + |-> class N(d: D) extends M(d) { [ secondary-ctor4.scala:59 ] + | ^ + |-> def this(d: D) = { [ secondary-ctor4.scala:7 ] + | ^ + |-> new A(new B(new D)) // error [ secondary-ctor4.scala:42 ] + | ^^^^^^^^^^^^^^^^^^^ | - | It leads to the following error during object initialization: - | Access field value n on a cold object. Calling trace: - | -> def this(b: B) = { [ secondary-ctor4.scala:17 ] - | ^ - | -> Inner().foo() [ secondary-ctor4.scala:26 ] - | ^^^^^^^ - | -> class Inner() { [ secondary-ctor4.scala:21 ] - | ^ - | -> println(b.n) [ secondary-ctor4.scala:23 ] - | ^^^ + |It leads to the following error during object initialization: + |Access field value n on a cold object. Calling trace: + |-> def this(b: B) = { [ secondary-ctor4.scala:17 ] + | ^ + |-> Inner().foo() [ secondary-ctor4.scala:26 ] + | ^^^^^^^ + |-> class Inner() { [ secondary-ctor4.scala:21 ] + | ^ + |-> println(b.n) [ secondary-ctor4.scala:23 ] + | ^^^ diff --git a/tests/init/neg/t3273.check b/tests/init/neg/t3273.check index 4ca79220c550..e548a5964cac 100644 --- a/tests/init/neg/t3273.check +++ b/tests/init/neg/t3273.check @@ -8,7 +8,7 @@ | -> val num1: LazyList[Int] = 1 #:: num1.map(_ + 1) // error [ t3273.scala:4 ] | ^^^^^^^^^^^^^^^ | - | Promoting the value to hot failed due to the following problem: + | Promoting the value to hot (transitively initialized) failed due to the following problem: | Access non-initialized value num1. Promotion trace: | -> val num1: LazyList[Int] = 1 #:: num1.map(_ + 1) // error [ t3273.scala:4 ] | ^^^^ @@ -22,7 +22,7 @@ | -> val num2: LazyList[Int] = 1 #:: num2.iterator.map(_ + 1).to(LazyList) // error [ t3273.scala:5 ] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - | Promoting the value to hot failed due to the following problem: + | Promoting the value to hot (transitively initialized) failed due to the following problem: | Access non-initialized value num2. Promotion trace: | -> val num2: LazyList[Int] = 1 #:: num2.iterator.map(_ + 1).to(LazyList) // error [ t3273.scala:5 ] | ^^^^ From d6a422165577fc90e86df03bdcc07c0c514dbc0a Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Wed, 7 Sep 2022 00:09:12 +0200 Subject: [PATCH 4/5] Small improvement --- compiler/src/dotty/tools/dotc/transform/init/Semantic.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala index e28664536de1..0b92d533955f 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala @@ -1674,7 +1674,7 @@ object Semantic: // The failing case is tests/init/pos/i12544.scala due to promotion failure. if vdef.symbol.name == nme.DOLLAR_VALUES && vdef.symbol.is(Flags.Synthetic) - && vdef.symbol.owner.companionClass.isAllOf(Flags.Enum) + && vdef.symbol.owner.companionClass.is(Flags.Enum) then thisV.updateField(vdef.symbol, Hot) else From 9dec67f6e1e4838fce3f1e24ec6cea795bf60f4b Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Wed, 7 Sep 2022 00:28:32 +0200 Subject: [PATCH 5/5] Fix exception for NoSymbol --- .../dotty/tools/dotc/transform/init/Semantic.scala | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala index 0b92d533955f..e4f6832f7695 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala @@ -1513,11 +1513,14 @@ object Semantic: thisV.accessLocal(tmref, klass) case tmref: TermRef => - val cls = tmref.widenSingleton.classSymbol.asClass - if cls.isStaticOwner && !cls.isContainedIn(promoted.entryClass) then - Hot - else if cls.isStaticOwner && klass.isContainedIn(cls) then - resolveThis(cls, thisV, klass) + val cls = tmref.widenSingleton.classSymbol + if cls.exists && cls.isStaticOwner then + if klass.isContainedIn(cls) then + resolveThis(cls.asClass, thisV, klass) + else if cls.isContainedIn(promoted.entryClass) then + cases(tmref.prefix, thisV, klass).select(tmref.symbol, receiver = tmref.prefix) + else + Hot else cases(tmref.prefix, thisV, klass).select(tmref.symbol, receiver = tmref.prefix)