From fff536ffc63e15749e9515387424a99fb997f63d Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Wed, 17 Sep 2025 15:09:56 +0200 Subject: [PATCH] When unpickling, do not incorrectly set PureInterface flags Previously, the behavior for setting `NoInits` and `PureInterface` flags for class symbols in `TreeInfo.defKind` (when compiling from a source) and in `TreeUnpickler` (when reading Tasty) was inconsistent. This was problematic, as the `PureInterface` flag dictated whether outer accessors were generated in `ExplicitOuter` phase (in the `needsOuterIfReferenced` method), so in the issue minimization, the inherited trait would have the outer accessors defined, and the inheriting object would then not implement them. This lead to runtime `MethodNotFound` errors. The problem was specifically with lazy vals, which were treated as if they did not have an rhs. --- .../dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- tests/run/i23863-a/BaseTest_1.scala | 13 +++++++++++++ tests/run/i23863-a/Test_2.scala | 4 ++++ tests/run/i23863-b/NestedObject_1.scala | 3 +++ tests/run/i23863-b/Test_2.scala | 3 +++ 5 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 tests/run/i23863-a/BaseTest_1.scala create mode 100644 tests/run/i23863-a/Test_2.scala create mode 100644 tests/run/i23863-b/NestedObject_1.scala create mode 100644 tests/run/i23863-b/Test_2.scala diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 95c9731a0679..c491f15055fa 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -813,7 +813,7 @@ class TreeUnpickler(reader: TastyReader, if (sym.isTerm && !sym.isOneOf(DeferredOrLazyOrMethod)) initsFlags = EmptyFlags else if (sym.isClass || - sym.is(Method, butNot = Deferred) && !sym.isConstructor) + sym.isOneOf(Method | Lazy, butNot = Deferred) && !sym.isConstructor) initsFlags &= NoInits case IMPORT | EXPORT => skipTree() diff --git a/tests/run/i23863-a/BaseTest_1.scala b/tests/run/i23863-a/BaseTest_1.scala new file mode 100644 index 000000000000..4a23904cb4eb --- /dev/null +++ b/tests/run/i23863-a/BaseTest_1.scala @@ -0,0 +1,13 @@ +abstract class BaseTest { + def genName(): String = "outerAccess" + trait Fixture { + lazy val service: Service = new Service { + val a = genName() + def doIt(a: String): Int = 0 + } + } +} + +trait Service { + def doIt(a: String): Int +} diff --git a/tests/run/i23863-a/Test_2.scala b/tests/run/i23863-a/Test_2.scala new file mode 100644 index 000000000000..9169e6668433 --- /dev/null +++ b/tests/run/i23863-a/Test_2.scala @@ -0,0 +1,4 @@ +object Test extends BaseTest { + def main(args: Array[String]): Unit = + new Fixture { service.doIt("test") } +} diff --git a/tests/run/i23863-b/NestedObject_1.scala b/tests/run/i23863-b/NestedObject_1.scala new file mode 100644 index 000000000000..c792f59894a6 --- /dev/null +++ b/tests/run/i23863-b/NestedObject_1.scala @@ -0,0 +1,3 @@ +trait NestedObject { + case class A() +} diff --git a/tests/run/i23863-b/Test_2.scala b/tests/run/i23863-b/Test_2.scala new file mode 100644 index 000000000000..99e6b8851200 --- /dev/null +++ b/tests/run/i23863-b/Test_2.scala @@ -0,0 +1,3 @@ +object Test extends NestedObject { + def main(args: Array[String]): Unit = () +}