From 2bb5740f470034f9aeac711d0d69f7f04f37bc1f Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 28 Jan 2020 19:28:35 +0300 Subject: [PATCH] [FIR] Resolve ambiguities in Java static scopes --- .../kotlin/fir/java/JavaScopeProvider.kt | 28 ++++-- .../kotlin/fir/resolve/calls/FirReceivers.kt | 90 ++++++++++++++++--- .../fir/resolve/calls/FirTowerResolver.kt | 26 +++--- .../kotlin/fir/resolve/calls/TowerGroup.kt | 6 +- .../problems/javaStaticScopeInheritance.kt | 2 +- .../problems/javaStaticScopeInheritance.txt | 2 +- .../testData/codegen/box/statics/fields.kt | 1 - .../javaDeprecatedInheritance.fir.kt | 2 +- .../j+k/StaticMembersFromSuperclasses.fir.kt | 2 +- .../j+k/shadowingPrimitiveStaticField.fir.kt | 6 +- .../statics/hidePrivateByPublic.fir.kt | 2 +- .../inheritance/statics/nameClash0.fir.kt | 2 +- .../inheritance/statics/nameClash1.fir.kt | 4 +- .../inheritance/statics/nameClash2.fir.kt | 6 +- .../statics/oneInterfaceManyTimes.fir.kt | 2 +- .../resolve/samAgainstFunctionalType.fir.kt | 2 +- 16 files changed, 130 insertions(+), 53 deletions(-) diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaScopeProvider.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaScopeProvider.kt index 511d41e5580..7ae56d0ed1a 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaScopeProvider.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaScopeProvider.kt @@ -50,6 +50,14 @@ class JavaScopeProvider( } } + private fun buildDeclaredMemberScope(regularClass: FirRegularClass): FirScope { + return if (regularClass is FirJavaClass) declaredMemberScopeWithLazyNestedScope( + regularClass, + existingNames = regularClass.existingNestedClassifierNames, + symbolProvider = symbolProvider + ) else declaredMemberScope(regularClass) + } + private fun buildUseSiteMemberScopeWithJavaTypes( regularClass: FirRegularClass, useSiteSession: FirSession, @@ -57,11 +65,7 @@ class JavaScopeProvider( visitedSymbols: MutableSet> ): JavaClassUseSiteMemberScope { return scopeSession.getOrBuild(regularClass.symbol, JAVA_USE_SITE) { - val declaredScope = if (regularClass is FirJavaClass) declaredMemberScopeWithLazyNestedScope( - regularClass, - existingNames = regularClass.existingNestedClassifierNames, - symbolProvider = symbolProvider - ) else declaredMemberScope(regularClass) + val declaredScope = buildDeclaredMemberScope(regularClass) val wrappedDeclaredScope = declaredMemberScopeDecorator(regularClass, declaredScope, useSiteSession, scopeSession) val superTypeEnhancementScopes = lookupSuperTypes(regularClass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession) @@ -97,10 +101,20 @@ class JavaScopeProvider( useSiteSession: FirSession, scopeSession: ScopeSession ): FirScope? { - return FirStaticScope(getUseSiteMemberScope(klass, useSiteSession, scopeSession)) + if (klass !is FirRegularClass) return null + val enhancementScope = scopeSession.getOrBuild(klass.symbol, JAVA_ENHANCEMENT_FOR_STATIC) { + val declaredScope = buildDeclaredMemberScope(klass) + val wrappedDeclaredScope = declaredMemberScopeDecorator(klass, declaredScope, useSiteSession, scopeSession) + JavaClassEnhancementScope( + useSiteSession, JavaClassUseSiteMemberScope( + klass, useSiteSession, superTypesScope = object : FirScope() {}, declaredMemberScope = wrappedDeclaredScope + ) + ) + } + return FirStaticScope(enhancementScope) } } - +private val JAVA_ENHANCEMENT_FOR_STATIC = scopeSessionKey() private val JAVA_ENHANCEMENT = scopeSessionKey() private val JAVA_USE_SITE = scopeSessionKey() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt index e9811ec0a7a..85bf24a4f61 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.resolve.calls import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirTypeParametersOwner import org.jetbrains.kotlin.fir.declarations.expandedConeType import org.jetbrains.kotlin.fir.declarations.impl.FirClassImpl @@ -17,6 +18,7 @@ import org.jetbrains.kotlin.fir.references.impl.FirImplicitThisReference import org.jetbrains.kotlin.fir.renderWithType import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.scopes.KotlinScopeProvider import org.jetbrains.kotlin.fir.scopes.impl.* import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* @@ -24,6 +26,7 @@ import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl import org.jetbrains.kotlin.name.ClassId +import java.util.ArrayDeque interface Receiver { fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirScope? @@ -68,31 +71,81 @@ abstract class AbstractExplicitReceiverValue : AbstractExplic } class QualifierReceiver(override val explicitReceiver: FirResolvedQualifier) : AbstractExplicitReceiver() { - private fun getClassSymbolWithCallablesScope( + private fun collectSuperTypeScopesComposedByDepth( + klass: FirClass<*>, + useSiteSession: FirSession, + scopeSession: ScopeSession + ): List { + val result = mutableListOf() + val provider = klass.scopeProvider + val levelScopes = mutableListOf() + var currentDepth = 1 + val queue = ArrayDeque>() + queue.addAll( + lookupSuperTypes(klass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession).map { it to 1 } + ) + val visitedSymbols = mutableSetOf() + while (queue.isNotEmpty()) { + val (useSiteSuperType, depth) = queue.poll() + if (depth > currentDepth) { + currentDepth = depth + result += FirCompositeScope(levelScopes.toMutableList()) + levelScopes.clear() + } + if (useSiteSuperType is ConeClassErrorType) continue + val superTypeSymbol = useSiteSuperType.lookupTag.toSymbol(useSiteSession) as? FirRegularClassSymbol + ?: continue + if (!visitedSymbols.add(superTypeSymbol)) continue + val superTypeScope = provider.getStaticMemberScopeForCallables( + superTypeSymbol.fir, useSiteSession, scopeSession + ) + if (superTypeScope != null) { + levelScopes += superTypeScope + } + queue.addAll( + lookupSuperTypes( + superTypeSymbol.fir, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession + ).map { it to currentDepth + 1 } + ) + } + return result + } + + private fun getClassSymbolWithCallableScopes( classId: ClassId, useSiteSession: FirSession, scopeSession: ScopeSession - ): Pair?, FirScope?> { - val symbol = useSiteSession.firSymbolProvider.getClassLikeSymbolByFqName(classId) ?: return null to null + ): Pair?, List> { + val symbol = useSiteSession.firSymbolProvider.getClassLikeSymbolByFqName(classId) ?: return null to emptyList() if (symbol is FirTypeAliasSymbol) { val expansionSymbol = symbol.fir.expandedConeType?.lookupTag?.toSymbol(useSiteSession) if (expansionSymbol != null) { - return getClassSymbolWithCallablesScope(expansionSymbol.classId, useSiteSession, scopeSession) + return getClassSymbolWithCallableScopes(expansionSymbol.classId, useSiteSession, scopeSession) } } else { return (symbol as? FirClassSymbol<*>)?.let { klassSymbol -> val klass = klassSymbol.fir - klassSymbol to klass.scopeProvider.getStaticMemberScopeForCallables(klass, useSiteSession, scopeSession) - } ?: (null to null) + klassSymbol to run { + val result = mutableListOf() + val provider = klass.scopeProvider + val klassScope = provider.getStaticMemberScopeForCallables(klass, useSiteSession, scopeSession) + if (klassScope != null) { + result += klassScope + if (provider is KotlinScopeProvider) return@run result + result += collectSuperTypeScopesComposedByDepth(klass, useSiteSession, scopeSession) + } + result + } + } ?: (null to emptyList()) } - return null to null + return null to emptyList() } - fun qualifierScope(useSiteSession: FirSession, scopeSession: ScopeSession): FirScope? { - val classId = explicitReceiver.classId ?: return null + fun qualifierScopes(useSiteSession: FirSession, scopeSession: ScopeSession): List { + val classId = explicitReceiver.classId ?: return emptyList() - val (classSymbol, callablesScope) = getClassSymbolWithCallablesScope(classId, useSiteSession, scopeSession) + val (classSymbol, callableScopes) = getClassSymbolWithCallableScopes(classId, useSiteSession, scopeSession) if (classSymbol != null) { val klass = classSymbol.fir val classifierScope = if (klass is FirClassImpl || klass is FirSealedClassImpl) { @@ -101,13 +154,24 @@ class QualifierReceiver(override val explicitReceiver: FirResolvedQualifier) : A useSiteSession.firSymbolProvider.getNestedClassifierScope(classId) } - return FirQualifierScope(callablesScope, classifierScope) + return when { + classifierScope == null -> { + callableScopes.map { FirQualifierScope(it, null) } + } + callableScopes.isEmpty() -> { + listOf(FirQualifierScope(null, classifierScope)) + } + else -> { + listOf(FirQualifierScope(callableScopes.first(), classifierScope)) + + callableScopes.drop(1).map { FirQualifierScope(it, null) } + } + } } - return null + return emptyList() } override fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirScope? { - return qualifierScope(useSiteSession, scopeSession) + return FirCompositeScope(qualifierScopes(useSiteSession, scopeSession).toMutableList()) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirTowerResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirTowerResolver.kt index 4ca09b7dea0..1ffefe07961 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirTowerResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirTowerResolver.kt @@ -82,23 +82,25 @@ class FirTowerResolver( resolvedQualifier: FirResolvedQualifier, manager: TowerResolveManager ): CandidateCollector { - val qualifierScope = if (resolvedQualifier.classId == null) { - FirExplicitSimpleImportingScope( - listOf( - FirResolvedImportImpl( - FirImportImpl(source = null, importedFqName = FqName.topLevel(info.name), isAllUnder = false, aliasName = null), - resolvedQualifier.packageFqName, - relativeClassName = null - ) - ), session, components.scopeSession + val qualifierScopes = if (resolvedQualifier.classId == null) { + listOf( + FirExplicitSimpleImportingScope( + listOf( + FirResolvedImportImpl( + FirImportImpl(source = null, importedFqName = FqName.topLevel(info.name), isAllUnder = false, aliasName = null), + resolvedQualifier.packageFqName, + relativeClassName = null + ) + ), session, components.scopeSession + ) ) } else { - QualifierReceiver(resolvedQualifier).qualifierScope(session, components.scopeSession) + QualifierReceiver(resolvedQualifier).qualifierScopes(session, components.scopeSession) } - if (qualifierScope != null) { + for ((depth, qualifierScope) in qualifierScopes.withIndex()) { manager.processLevel( - ScopeTowerLevel(session, components, qualifierScope), info.noStubReceiver(), TowerGroup.Qualifier + ScopeTowerLevel(session, components, qualifierScope), info.noStubReceiver(), TowerGroup.Qualifier(depth) ) if (collector.isSuccess()) return collector } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerGroup.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerGroup.kt index 954855c7f2e..54d07082655 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerGroup.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TowerGroup.kt @@ -12,7 +12,7 @@ sealed class TowerGroupKind(private val index: Int) : Comparable class Weakened(depth: Int) : WithDepth(-10, depth) - object Qualifier : TowerGroupKind(0) + class Qualifier(depth: Int) : WithDepth(0, depth) class TopPrioritized(depth: Int) : WithDepth(1, depth) @@ -47,7 +47,7 @@ class TowerGroup private constructor(private val list: List) : C val Start = kindOf(TowerGroupKind.Start) - val Qualifier = kindOf(TowerGroupKind.Qualifier) + fun Qualifier(depth: Int) = kindOf(TowerGroupKind.Qualifier(depth)) val Member = kindOf(TowerGroupKind.Member) @@ -68,8 +68,6 @@ class TowerGroup private constructor(private val list: List) : C fun Weakened(depth: Int) = kindOf(TowerGroupKind.Weakened(depth)) - val Qualifier get() = kindOf(TowerGroupKind.Qualifier) - val Member get() = kindOf(TowerGroupKind.Member) fun Local(depth: Int) = kindOf(TowerGroupKind.Local(depth)) diff --git a/compiler/fir/resolve/testData/resolve/problems/javaStaticScopeInheritance.kt b/compiler/fir/resolve/testData/resolve/problems/javaStaticScopeInheritance.kt index e23765ceb2e..79cd68b9035 100644 --- a/compiler/fir/resolve/testData/resolve/problems/javaStaticScopeInheritance.kt +++ b/compiler/fir/resolve/testData/resolve/problems/javaStaticScopeInheritance.kt @@ -13,5 +13,5 @@ class B extends A { // FILE: main.kt fun main() { - val b = B.VALUE // <- should be B + val b = B.VALUE // <- should be B } diff --git a/compiler/fir/resolve/testData/resolve/problems/javaStaticScopeInheritance.txt b/compiler/fir/resolve/testData/resolve/problems/javaStaticScopeInheritance.txt index d8cd5ce8392..242b737e00b 100644 --- a/compiler/fir/resolve/testData/resolve/problems/javaStaticScopeInheritance.txt +++ b/compiler/fir/resolve/testData/resolve/problems/javaStaticScopeInheritance.txt @@ -1,4 +1,4 @@ FILE: main.kt public final fun main(): R|kotlin/Unit| { - lval b: = Q|B|.# + lval b: R|ft!| = Q|B|.R|/B.VALUE| } diff --git a/compiler/testData/codegen/box/statics/fields.kt b/compiler/testData/codegen/box/statics/fields.kt index c3a475af001..aac3d842f87 100644 --- a/compiler/testData/codegen/box/statics/fields.kt +++ b/compiler/testData/codegen/box/statics/fields.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // FILE: Child.java diff --git a/compiler/testData/diagnostics/tests/deprecated/javaDeprecatedInheritance.fir.kt b/compiler/testData/diagnostics/tests/deprecated/javaDeprecatedInheritance.fir.kt index a3cf0deac2e..f4c1c237fa3 100644 --- a/compiler/testData/diagnostics/tests/deprecated/javaDeprecatedInheritance.fir.kt +++ b/compiler/testData/diagnostics/tests/deprecated/javaDeprecatedInheritance.fir.kt @@ -44,7 +44,7 @@ fun use(a: A, b: B, c: C) { c.f() A.D - B.D + B.D C.D A.bar() diff --git a/compiler/testData/diagnostics/tests/j+k/StaticMembersFromSuperclasses.fir.kt b/compiler/testData/diagnostics/tests/j+k/StaticMembersFromSuperclasses.fir.kt index de425b2100f..0f3bd459335 100644 --- a/compiler/testData/diagnostics/tests/j+k/StaticMembersFromSuperclasses.fir.kt +++ b/compiler/testData/diagnostics/tests/j+k/StaticMembersFromSuperclasses.fir.kt @@ -13,4 +13,4 @@ public class Bbb extends Aaa { // FILE: b.kt -fun foo() = Bbb.i +fun foo() = Bbb.i diff --git a/compiler/testData/diagnostics/tests/j+k/shadowingPrimitiveStaticField.fir.kt b/compiler/testData/diagnostics/tests/j+k/shadowingPrimitiveStaticField.fir.kt index 54cb9615d6f..e5d912fd599 100644 --- a/compiler/testData/diagnostics/tests/j+k/shadowingPrimitiveStaticField.fir.kt +++ b/compiler/testData/diagnostics/tests/j+k/shadowingPrimitiveStaticField.fir.kt @@ -4,9 +4,9 @@ import aa.B fun use() { // checking that CONST is of platform type - B.CONST = null - B.CONST?.length - B.CONST.length + B.CONST = null + B.CONST?.length + B.CONST.length } // FILE: aa/A.java diff --git a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/hidePrivateByPublic.fir.kt b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/hidePrivateByPublic.fir.kt index 1c704061339..0b98742efd6 100644 --- a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/hidePrivateByPublic.fir.kt +++ b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/hidePrivateByPublic.fir.kt @@ -30,7 +30,7 @@ fun test() { B.a B.foo() B.foo(1) - B.b + B.b B.bar() B.bar(1) } diff --git a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/nameClash0.fir.kt b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/nameClash0.fir.kt index 679562e8170..a4d5d41458c 100644 --- a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/nameClash0.fir.kt +++ b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/nameClash0.fir.kt @@ -28,5 +28,5 @@ fun test() { B.field E.field - O.field + O.field } diff --git a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/nameClash1.fir.kt b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/nameClash1.fir.kt index 5738aa2bdd8..e8bcee6dce8 100644 --- a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/nameClash1.fir.kt +++ b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/nameClash1.fir.kt @@ -25,8 +25,8 @@ public class O implements A, B { fun test() { A.field - B.field + B.field E.field - O.field + O.field } diff --git a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/nameClash2.fir.kt b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/nameClash2.fir.kt index ed9da65f567..cd844de6e74 100644 --- a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/nameClash2.fir.kt +++ b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/nameClash2.fir.kt @@ -57,10 +57,10 @@ fun test() { D.field E.field - O.field + O.field EE.field - EO.field + EO.field - OO.field + OO.field } diff --git a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/oneInterfaceManyTimes.fir.kt b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/oneInterfaceManyTimes.fir.kt index 203bcb04899..c8de65ef916 100644 --- a/compiler/testData/diagnostics/tests/scopes/inheritance/statics/oneInterfaceManyTimes.fir.kt +++ b/compiler/testData/diagnostics/tests/scopes/inheritance/statics/oneInterfaceManyTimes.fir.kt @@ -47,7 +47,7 @@ fun test() { D.bar() D.baz() - E.a + E.a E.b E.c E.bar() diff --git a/compiler/testData/diagnostics/testsWithStdLib/resolve/samAgainstFunctionalType.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/resolve/samAgainstFunctionalType.fir.kt index 16c870e7f15..c4068183517 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/resolve/samAgainstFunctionalType.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/resolve/samAgainstFunctionalType.fir.kt @@ -26,5 +26,5 @@ public class StaticOverrides { fun test() { StaticOverrides.A.foo {} checkType { _() } StaticOverrides.B.foo {} checkType { _() } - StaticOverrides.C.foo {} checkType { _() } + StaticOverrides.C.foo {} checkType { _() } } \ No newline at end of file