[FIR] Resolve ambiguities in Java static scopes

This commit is contained in:
Mikhail Glukhikh
2020-01-28 19:28:35 +03:00
parent 4c8905b00f
commit 2bb5740f47
16 changed files with 130 additions and 53 deletions
@@ -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( private fun buildUseSiteMemberScopeWithJavaTypes(
regularClass: FirRegularClass, regularClass: FirRegularClass,
useSiteSession: FirSession, useSiteSession: FirSession,
@@ -57,11 +65,7 @@ class JavaScopeProvider(
visitedSymbols: MutableSet<FirClassLikeSymbol<*>> visitedSymbols: MutableSet<FirClassLikeSymbol<*>>
): JavaClassUseSiteMemberScope { ): JavaClassUseSiteMemberScope {
return scopeSession.getOrBuild(regularClass.symbol, JAVA_USE_SITE) { return scopeSession.getOrBuild(regularClass.symbol, JAVA_USE_SITE) {
val declaredScope = if (regularClass is FirJavaClass) declaredMemberScopeWithLazyNestedScope( val declaredScope = buildDeclaredMemberScope(regularClass)
regularClass,
existingNames = regularClass.existingNestedClassifierNames,
symbolProvider = symbolProvider
) else declaredMemberScope(regularClass)
val wrappedDeclaredScope = declaredMemberScopeDecorator(regularClass, declaredScope, useSiteSession, scopeSession) val wrappedDeclaredScope = declaredMemberScopeDecorator(regularClass, declaredScope, useSiteSession, scopeSession)
val superTypeEnhancementScopes = val superTypeEnhancementScopes =
lookupSuperTypes(regularClass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession) lookupSuperTypes(regularClass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
@@ -97,10 +101,20 @@ class JavaScopeProvider(
useSiteSession: FirSession, useSiteSession: FirSession,
scopeSession: ScopeSession scopeSession: ScopeSession
): FirScope? { ): 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<FirRegularClassSymbol, JavaClassEnhancementScope>()
private val JAVA_ENHANCEMENT = scopeSessionKey<FirRegularClassSymbol, JavaClassEnhancementScope>() private val JAVA_ENHANCEMENT = scopeSessionKey<FirRegularClassSymbol, JavaClassEnhancementScope>()
private val JAVA_USE_SITE = scopeSessionKey<FirRegularClassSymbol, JavaClassUseSiteMemberScope>() private val JAVA_USE_SITE = scopeSessionKey<FirRegularClassSymbol, JavaClassUseSiteMemberScope>()
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.resolve.calls package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.FirSession 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.FirTypeParametersOwner
import org.jetbrains.kotlin.fir.declarations.expandedConeType import org.jetbrains.kotlin.fir.declarations.expandedConeType
import org.jetbrains.kotlin.fir.declarations.impl.FirClassImpl 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.renderWithType
import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.scopes.FirScope 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.scopes.impl.*
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.* 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.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import java.util.ArrayDeque
interface Receiver { interface Receiver {
fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirScope? fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirScope?
@@ -68,31 +71,81 @@ abstract class AbstractExplicitReceiverValue<E : FirExpression> : AbstractExplic
} }
class QualifierReceiver(override val explicitReceiver: FirResolvedQualifier) : AbstractExplicitReceiver<FirResolvedQualifier>() { class QualifierReceiver(override val explicitReceiver: FirResolvedQualifier) : AbstractExplicitReceiver<FirResolvedQualifier>() {
private fun getClassSymbolWithCallablesScope( private fun collectSuperTypeScopesComposedByDepth(
klass: FirClass<*>,
useSiteSession: FirSession,
scopeSession: ScopeSession
): List<FirScope> {
val result = mutableListOf<FirScope>()
val provider = klass.scopeProvider
val levelScopes = mutableListOf<FirScope>()
var currentDepth = 1
val queue = ArrayDeque<Pair<ConeClassLikeType, Int>>()
queue.addAll(
lookupSuperTypes(klass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession).map { it to 1 }
)
val visitedSymbols = mutableSetOf<FirRegularClassSymbol>()
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, classId: ClassId,
useSiteSession: FirSession, useSiteSession: FirSession,
scopeSession: ScopeSession scopeSession: ScopeSession
): Pair<FirClassSymbol<*>?, FirScope?> { ): Pair<FirClassSymbol<*>?, List<FirScope>> {
val symbol = useSiteSession.firSymbolProvider.getClassLikeSymbolByFqName(classId) ?: return null to null val symbol = useSiteSession.firSymbolProvider.getClassLikeSymbolByFqName(classId) ?: return null to emptyList()
if (symbol is FirTypeAliasSymbol) { if (symbol is FirTypeAliasSymbol) {
val expansionSymbol = symbol.fir.expandedConeType?.lookupTag?.toSymbol(useSiteSession) val expansionSymbol = symbol.fir.expandedConeType?.lookupTag?.toSymbol(useSiteSession)
if (expansionSymbol != null) { if (expansionSymbol != null) {
return getClassSymbolWithCallablesScope(expansionSymbol.classId, useSiteSession, scopeSession) return getClassSymbolWithCallableScopes(expansionSymbol.classId, useSiteSession, scopeSession)
} }
} else { } else {
return (symbol as? FirClassSymbol<*>)?.let { klassSymbol -> return (symbol as? FirClassSymbol<*>)?.let { klassSymbol ->
val klass = klassSymbol.fir val klass = klassSymbol.fir
klassSymbol to klass.scopeProvider.getStaticMemberScopeForCallables(klass, useSiteSession, scopeSession) klassSymbol to run {
} ?: (null to null) val result = mutableListOf<FirScope>()
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? { fun qualifierScopes(useSiteSession: FirSession, scopeSession: ScopeSession): List<FirScope> {
val classId = explicitReceiver.classId ?: return null val classId = explicitReceiver.classId ?: return emptyList()
val (classSymbol, callablesScope) = getClassSymbolWithCallablesScope(classId, useSiteSession, scopeSession) val (classSymbol, callableScopes) = getClassSymbolWithCallableScopes(classId, useSiteSession, scopeSession)
if (classSymbol != null) { if (classSymbol != null) {
val klass = classSymbol.fir val klass = classSymbol.fir
val classifierScope = if (klass is FirClassImpl || klass is FirSealedClassImpl) { val classifierScope = if (klass is FirClassImpl || klass is FirSealedClassImpl) {
@@ -101,13 +154,24 @@ class QualifierReceiver(override val explicitReceiver: FirResolvedQualifier) : A
useSiteSession.firSymbolProvider.getNestedClassifierScope(classId) 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? { override fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirScope? {
return qualifierScope(useSiteSession, scopeSession) return FirCompositeScope(qualifierScopes(useSiteSession, scopeSession).toMutableList())
} }
} }
@@ -82,23 +82,25 @@ class FirTowerResolver(
resolvedQualifier: FirResolvedQualifier, resolvedQualifier: FirResolvedQualifier,
manager: TowerResolveManager manager: TowerResolveManager
): CandidateCollector { ): CandidateCollector {
val qualifierScope = if (resolvedQualifier.classId == null) { val qualifierScopes = if (resolvedQualifier.classId == null) {
FirExplicitSimpleImportingScope( listOf(
listOf( FirExplicitSimpleImportingScope(
FirResolvedImportImpl( listOf(
FirImportImpl(source = null, importedFqName = FqName.topLevel(info.name), isAllUnder = false, aliasName = null), FirResolvedImportImpl(
resolvedQualifier.packageFqName, FirImportImpl(source = null, importedFqName = FqName.topLevel(info.name), isAllUnder = false, aliasName = null),
relativeClassName = null resolvedQualifier.packageFqName,
) relativeClassName = null
), session, components.scopeSession )
), session, components.scopeSession
)
) )
} else { } else {
QualifierReceiver(resolvedQualifier).qualifierScope(session, components.scopeSession) QualifierReceiver(resolvedQualifier).qualifierScopes(session, components.scopeSession)
} }
if (qualifierScope != null) { for ((depth, qualifierScope) in qualifierScopes.withIndex()) {
manager.processLevel( manager.processLevel(
ScopeTowerLevel(session, components, qualifierScope), info.noStubReceiver(), TowerGroup.Qualifier ScopeTowerLevel(session, components, qualifierScope), info.noStubReceiver(), TowerGroup.Qualifier(depth)
) )
if (collector.isSuccess()) return collector if (collector.isSuccess()) return collector
} }
@@ -12,7 +12,7 @@ sealed class TowerGroupKind(private val index: Int) : Comparable<TowerGroupKind>
class Weakened(depth: Int) : WithDepth(-10, depth) 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) class TopPrioritized(depth: Int) : WithDepth(1, depth)
@@ -47,7 +47,7 @@ class TowerGroup private constructor(private val list: List<TowerGroupKind>) : C
val Start = kindOf(TowerGroupKind.Start) val Start = kindOf(TowerGroupKind.Start)
val Qualifier = kindOf(TowerGroupKind.Qualifier) fun Qualifier(depth: Int) = kindOf(TowerGroupKind.Qualifier(depth))
val Member = kindOf(TowerGroupKind.Member) val Member = kindOf(TowerGroupKind.Member)
@@ -68,8 +68,6 @@ class TowerGroup private constructor(private val list: List<TowerGroupKind>) : C
fun Weakened(depth: Int) = kindOf(TowerGroupKind.Weakened(depth)) fun Weakened(depth: Int) = kindOf(TowerGroupKind.Weakened(depth))
val Qualifier get() = kindOf(TowerGroupKind.Qualifier)
val Member get() = kindOf(TowerGroupKind.Member) val Member get() = kindOf(TowerGroupKind.Member)
fun Local(depth: Int) = kindOf(TowerGroupKind.Local(depth)) fun Local(depth: Int) = kindOf(TowerGroupKind.Local(depth))
@@ -13,5 +13,5 @@ class B extends A {
// FILE: main.kt // FILE: main.kt
fun main() { fun main() {
val b = B.<!AMBIGUITY!>VALUE<!> // <- should be B val b = B.VALUE // <- should be B
} }
@@ -1,4 +1,4 @@
FILE: main.kt FILE: main.kt
public final fun main(): R|kotlin/Unit| { public final fun main(): R|kotlin/Unit| {
lval b: <ERROR TYPE REF: Ambiguity: VALUE, [/B.VALUE, /A.VALUE]> = Q|B|.<Ambiguity: VALUE, [/B.VALUE, /A.VALUE]># lval b: R|ft<B, B?>!| = Q|B|.R|/B.VALUE|
} }
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: Child.java // FILE: Child.java
@@ -44,7 +44,7 @@ fun use(a: A, b: B, c: C) {
c.f() c.f()
A.D A.D
B.<!AMBIGUITY!>D<!> B.D
C.D C.D
A.bar() A.bar()
@@ -13,4 +13,4 @@ public class Bbb extends Aaa {
// FILE: b.kt // FILE: b.kt
fun foo() = Bbb.<!AMBIGUITY!>i<!> fun foo() = Bbb.i
@@ -4,9 +4,9 @@ import aa.B
fun use() { fun use() {
// checking that CONST is of platform type // checking that CONST is of platform type
B.<!AMBIGUITY!>CONST<!> = null B.CONST = null
B.<!AMBIGUITY!>CONST<!>?.<!UNRESOLVED_REFERENCE!>length<!> B.CONST?.length
B.<!AMBIGUITY!>CONST<!>.<!UNRESOLVED_REFERENCE!>length<!> B.CONST.length
} }
// FILE: aa/A.java // FILE: aa/A.java
@@ -30,7 +30,7 @@ fun test() {
B.a B.a
B.foo() B.foo()
B.foo(1) B.foo(1)
B.<!AMBIGUITY!>b<!> B.b
B.bar() B.bar()
B.bar(1) B.bar(1)
} }
@@ -28,5 +28,5 @@ fun test() {
B.field B.field
E.<!AMBIGUITY!>field<!> E.<!AMBIGUITY!>field<!>
O.<!AMBIGUITY!>field<!> O.field
} }
@@ -25,8 +25,8 @@ public class O implements A, B {
fun test() { fun test() {
A.field A.field
B.<!AMBIGUITY!>field<!> B.field
E.<!AMBIGUITY!>field<!> E.<!AMBIGUITY!>field<!>
O.<!AMBIGUITY!>field<!> O.field
} }
@@ -57,10 +57,10 @@ fun test() {
D.field D.field
E.<!AMBIGUITY!>field<!> E.<!AMBIGUITY!>field<!>
O.<!AMBIGUITY!>field<!> O.field
EE.<!AMBIGUITY!>field<!> EE.<!AMBIGUITY!>field<!>
EO.<!AMBIGUITY!>field<!> EO.field
OO.<!AMBIGUITY!>field<!> OO.field
} }
@@ -47,7 +47,7 @@ fun test() {
D.bar() D.bar()
D.baz() D.baz()
E.<!AMBIGUITY!>a<!> E.a
E.b E.b
E.c E.c
E.bar() E.bar()
@@ -26,5 +26,5 @@ public class StaticOverrides {
fun test() { fun test() {
StaticOverrides.A.<!AMBIGUITY!>foo<!> {} <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><Boolean>() } StaticOverrides.A.<!AMBIGUITY!>foo<!> {} <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><Boolean>() }
StaticOverrides.B.foo {} checkType { <!UNRESOLVED_REFERENCE!>_<!><String>() } StaticOverrides.B.foo {} checkType { <!UNRESOLVED_REFERENCE!>_<!><String>() }
StaticOverrides.C.<!AMBIGUITY!>foo<!> {} <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><Boolean>() } StaticOverrides.C.foo {} checkType { <!UNRESOLVED_REFERENCE!>_<!><Boolean>() }
} }