From dd9edbce288afde3b7c967e3b818d2cd1a07a49d Mon Sep 17 00:00:00 2001 From: Matt Bovel Date: Tue, 5 Mar 2024 15:11:30 +0100 Subject: [PATCH 1/2] Refactor hasOnlyLocalInstantiation to use isLocalToCompilationUnit --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- .../src/dotty/tools/dotc/transform/ExplicitOuter.scala | 9 ++++----- .../generic-java-signatures/outer-ref-elimination.check | 1 + .../generic-java-signatures/outer-ref-elimination.scala | 3 +++ 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index b3fe5757720e..77849e1f0624 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1208,7 +1208,7 @@ object SymDenotations { final def isLocalToCompilationUnit(using Context): Boolean = is(Private) - || owner.ownersIterator.exists(_.isTerm) + || owner.ownersIterator.takeWhile(!_.isStaticOwner).exists(_.isTerm) || accessBoundary(defn.RootClass).isContainedIn(symbol.topLevelClass) final def isTransparentClass(using Context): Boolean = diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index e34dbfe3e1d8..b976dfaa2f9f 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -218,18 +218,17 @@ object ExplicitOuter { */ private def needsOuterAlways(cls: ClassSymbol)(using Context): Boolean = needsOuterIfReferenced(cls) && - (!hasLocalInstantiation(cls) || // needs outer because we might not know whether outer is referenced or not + (!hasOnlyLocalInstantiation(cls) || // needs outer because we might not know whether outer is referenced or not cls.mixins.exists(needsOuterIfReferenced) || // needs outer for parent traits cls.info.parents.exists(parent => // needs outer to potentially pass along to parent needsOuterIfReferenced(parent.classSymbol.asClass))) /** Class is only instantiated in the compilation unit where it is defined */ - private def hasLocalInstantiation(cls: ClassSymbol)(using Context): Boolean = + private def hasOnlyLocalInstantiation(cls: ClassSymbol)(using Context): Boolean = // Modules are normally locally instantiated, except if they are declared in a trait, // in which case they will be instantiated in the classes that mix in the trait. - cls.owner.ownersIterator.takeWhile(!_.isStaticOwner).exists(_.isTerm) - || cls.is(Private, butNot = Module) - || cls.is(Module) && !cls.owner.is(Trait) + if cls.is(Module) then !cls.owner.is(Trait) + else cls.isLocalToCompilationUnit /** The outer parameter accessor of cass `cls` */ private def outerParamAccessor(cls: ClassSymbol)(using Context): TermSymbol = diff --git a/tests/generic-java-signatures/outer-ref-elimination.check b/tests/generic-java-signatures/outer-ref-elimination.check index f8437b1a40b7..7dd664e5d766 100644 --- a/tests/generic-java-signatures/outer-ref-elimination.check +++ b/tests/generic-java-signatures/outer-ref-elimination.check @@ -7,3 +7,4 @@ List(public T6$$anon$3$C6()) List(public T7$C7$1()) List(public T8$$anon$4$C8()) List(public T9$C9$1(T9)) +List(public T10$C10()) diff --git a/tests/generic-java-signatures/outer-ref-elimination.scala b/tests/generic-java-signatures/outer-ref-elimination.scala index 09dec07ff59c..6e4e8218c535 100644 --- a/tests/generic-java-signatures/outer-ref-elimination.scala +++ b/tests/generic-java-signatures/outer-ref-elimination.scala @@ -26,6 +26,8 @@ class T8 { def t8(): Unit = new AnyRef { class C8; test(classOf[C8]) } } // the field x. class T9 { var x = 451; def t9(): Unit = { class C9 {def getX = x}; test(classOf[C9])} } +class T10 { private[T10] class C10; test(classOf[C10]) } + object Test { def main(args: Array[String]): Unit = { T1 @@ -37,5 +39,6 @@ object Test { new T7().t7() new T8().t8() new T9().t9() + new T10() } } From f8a5583c023ef6d51850a5b713bf17522041bec0 Mon Sep 17 00:00:00 2001 From: Matt Bovel Date: Sat, 16 Mar 2024 01:34:06 +0100 Subject: [PATCH 2/2] Symbol with top-level access boundary is not local to compilation unit Co-Authored-By: Dale Wijnand --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- tests/generic-java-signatures/outer-ref-elimination.check | 3 ++- tests/generic-java-signatures/outer-ref-elimination.scala | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 77849e1f0624..14ba05568735 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1209,7 +1209,7 @@ object SymDenotations { final def isLocalToCompilationUnit(using Context): Boolean = is(Private) || owner.ownersIterator.takeWhile(!_.isStaticOwner).exists(_.isTerm) - || accessBoundary(defn.RootClass).isContainedIn(symbol.topLevelClass) + || accessBoundary(defn.RootClass).isProperlyContainedIn(symbol.topLevelClass) final def isTransparentClass(using Context): Boolean = is(TransparentType) diff --git a/tests/generic-java-signatures/outer-ref-elimination.check b/tests/generic-java-signatures/outer-ref-elimination.check index 7dd664e5d766..60fb5e63b11a 100644 --- a/tests/generic-java-signatures/outer-ref-elimination.check +++ b/tests/generic-java-signatures/outer-ref-elimination.check @@ -7,4 +7,5 @@ List(public T6$$anon$3$C6()) List(public T7$C7$1()) List(public T8$$anon$4$C8()) List(public T9$C9$1(T9)) -List(public T10$C10()) +List(public T10$C10(T10)) +List(public T11$D11$C11()) diff --git a/tests/generic-java-signatures/outer-ref-elimination.scala b/tests/generic-java-signatures/outer-ref-elimination.scala index 6e4e8218c535..6a10544cdb08 100644 --- a/tests/generic-java-signatures/outer-ref-elimination.scala +++ b/tests/generic-java-signatures/outer-ref-elimination.scala @@ -28,6 +28,8 @@ class T9 { var x = 451; def t9(): Unit = { class C9 {def getX = x}; test(classOf class T10 { private[T10] class C10; test(classOf[C10]) } +class T11 { class D11 { private[D11] class C11; test(classOf[C11]) } } + object Test { def main(args: Array[String]): Unit = { T1 @@ -40,5 +42,6 @@ object Test { new T8().t8() new T9().t9() new T10() + val t11 = new T11(); new t11.D11() } }