From 9396ad87b49693afc78f37c5068721788e4c0262 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Sun, 7 Jun 2020 23:16:56 +0200 Subject: [PATCH] Avoid cycle between Java static class and outer class Real world usecase is https://www.javadoc.io/doc/software.amazon.awssdk/cloudwatchlogs/2.13.28/software/amazon/awssdk/services/cloudwatchlogs/model/GetLogEventsRequest.html - When parsing a Java classfile, set the info of the companion (where inner static classes will be looked up) before reading the generic signature of the class. - When looking for a companion, do not unnecessarily force denotations --- .../src/dotty/tools/dotc/core/SymDenotations.scala | 5 ++++- .../tools/dotc/core/classfile/ClassfileParser.scala | 12 +++++++----- .../pos-java-interop-separate/static-cycle/A_1.java | 5 +++++ .../pos-java-interop-separate/static-cycle/B_2.scala | 3 +++ 4 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 tests/pos-java-interop-separate/static-cycle/A_1.java create mode 100644 tests/pos-java-interop-separate/static-cycle/B_2.scala diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index f51aec15c45d..07a68779ae9e 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -2199,7 +2199,10 @@ object SymDenotations { if (companion.isClass && !isAbsent(canForce = false) && !companion.isAbsent(canForce = false)) myCompanion = companion - override def registeredCompanion(implicit ctx: Context) = { ensureCompleted(); myCompanion } + override def registeredCompanion(implicit ctx: Context) = + if !myCompanion.exists then + ensureCompleted() + myCompanion override def registeredCompanion_=(c: Symbol) = { myCompanion = c } private var myNestingLevel = -1 diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 6e55be500bf2..e90fa093e377 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -180,17 +180,19 @@ class ClassfileParser( for (i <- 0 until in.nextChar) parseMember(method = false) for (i <- 0 until in.nextChar) parseMember(method = true) + + classRoot.registerCompanion(moduleRoot.symbol) + moduleRoot.registerCompanion(classRoot.symbol) + + setClassInfo(moduleRoot, staticInfo, fromScala2 = false) + classInfo = parseAttributes(classRoot.symbol, classInfo) if (isAnnotation) // classInfo must be a TempClassInfoType and not a TempPolyType, // because Java annotations cannot have type parameters. addAnnotationConstructor(classInfo.asInstanceOf[TempClassInfoType]) - classRoot.registerCompanion(moduleRoot.symbol) - moduleRoot.registerCompanion(classRoot.symbol) - setClassInfo(classRoot, classInfo, fromScala2 = false) - setClassInfo(moduleRoot, staticInfo, fromScala2 = false) } else if (result == Some(NoEmbedded)) for (sym <- List(moduleRoot.sourceModule, moduleRoot.symbol, classRoot.symbol)) { @@ -916,7 +918,7 @@ class ClassfileParser( } /** Return the class symbol for `entry`. It looks it up in its outer class. - * Forces all outer class symbols to be completed. + * This might force outer class symbols. */ def classSymbol(entry: InnerClassEntry)(implicit ctx: Context): Symbol = { def getMember(sym: Symbol, name: Name)(implicit ctx: Context): Symbol = diff --git a/tests/pos-java-interop-separate/static-cycle/A_1.java b/tests/pos-java-interop-separate/static-cycle/A_1.java new file mode 100644 index 000000000000..895c7d56bf92 --- /dev/null +++ b/tests/pos-java-interop-separate/static-cycle/A_1.java @@ -0,0 +1,5 @@ +class Foo> {} + +public class A_1 extends Foo { + public static class InnerClass extends Foo {} +} diff --git a/tests/pos-java-interop-separate/static-cycle/B_2.scala b/tests/pos-java-interop-separate/static-cycle/B_2.scala new file mode 100644 index 000000000000..8b53f6c12fce --- /dev/null +++ b/tests/pos-java-interop-separate/static-cycle/B_2.scala @@ -0,0 +1,3 @@ +object B { + val a = new A_1 +}