FIR: resolve conflicts on multiple inheritance of fun with same signature

This commit is contained in:
Simon Ogorodnik
2019-04-23 04:21:11 +03:00
committed by Mikhail Glukhikh
parent 84fbf4ec25
commit 6a0e3371ae
8 changed files with 155 additions and 78 deletions
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirClassDeclaredMemberScope
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
import org.jetbrains.kotlin.fir.scopes.impl.FirSuperTypeScope
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
@@ -86,20 +86,21 @@ class JavaSymbolProvider(
scopeSession: ScopeSession
): JavaClassUseSiteScope {
return scopeSession.getOrBuild(regularClass.symbol, JAVA_USE_SITE) {
val superTypeEnhancementScope = FirCompositeScope(mutableListOf())
val declaredScope = scopeSession.getOrBuild(regularClass.symbol, DECLARED) { FirClassDeclaredMemberScope(regularClass) }
lookupSuperTypes(regularClass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
.mapNotNullTo(superTypeEnhancementScope.scopes) { useSiteSuperType ->
if (useSiteSuperType is ConeClassErrorType) return@mapNotNullTo null
val symbol = useSiteSuperType.lookupTag.toSymbol(useSiteSession)
if (symbol is FirClassSymbol) {
// We need JavaClassEnhancementScope here to have already enhanced signatures from supertypes
buildJavaEnhancementScope(useSiteSession, symbol, scopeSession)
} else {
null
val superTypeEnhancementScopes =
lookupSuperTypes(regularClass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
.mapNotNull { useSiteSuperType ->
if (useSiteSuperType is ConeClassErrorType) return@mapNotNull null
val symbol = useSiteSuperType.lookupTag.toSymbol(useSiteSession)
if (symbol is FirClassSymbol) {
// We need JavaClassEnhancementScope here to have already enhanced signatures from supertypes
val scope = buildJavaEnhancementScope(useSiteSession, symbol, scopeSession)
useSiteSuperType.wrapSubstitutionScopeIfNeed(useSiteSession, scope, scopeSession)
} else {
null
}
}
}
JavaClassUseSiteScope(regularClass, useSiteSession, superTypeEnhancementScope, declaredScope)
JavaClassUseSiteScope(regularClass, useSiteSession, FirSuperTypeScope(session, superTypeEnhancementScopes), declaredScope)
}
}
@@ -45,7 +45,7 @@ fun ConeKotlinType.scope(useSiteSession: FirSession, scopeSession: ScopeSession)
}
}
private fun ConeClassLikeType.wrapSubstitutionScopeIfNeed(
fun ConeClassLikeType.wrapSubstitutionScopeIfNeed(
session: FirSession,
useSiteScope: FirScope,
builder: ScopeSession
@@ -65,11 +65,11 @@ fun FirTypeAlias.buildUseSiteScope(useSiteSession: FirSession, builder: ScopeSes
fun FirRegularClass.buildDefaultUseSiteScope(useSiteSession: FirSession, builder: ScopeSession): FirScope {
return builder.getOrBuild(symbol, USE_SITE) {
val superTypeScope = FirCompositeScope(mutableListOf())
val declaredScope = builder.getOrBuild(this.symbol, DECLARED) { FirClassDeclaredMemberScope(this) }
lookupSuperTypes(this, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
.mapNotNullTo(superTypeScope.scopes) { useSiteSuperType ->
if (useSiteSuperType is ConeClassErrorType) return@mapNotNullTo null
val scopes = lookupSuperTypes(this, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
.mapNotNull { useSiteSuperType ->
if (useSiteSuperType is ConeClassErrorType) return@mapNotNull null
val symbol = useSiteSuperType.lookupTag.toSymbol(useSiteSession)
if (symbol is FirClassSymbol) {
val useSiteScope = symbol.fir.buildUseSiteScope(useSiteSession, builder)
@@ -78,7 +78,7 @@ fun FirRegularClass.buildDefaultUseSiteScope(useSiteSession: FirSession, builder
null
}
}
FirClassUseSiteScope(useSiteSession, superTypeScope, declaredScope)
FirClassUseSiteScope(useSiteSession, FirSuperTypeScope(useSiteSession, scopes), declaredScope)
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypeContext
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker
import org.jetbrains.kotlin.utils.addToStdlib.cast
abstract class AbstractFirOverrideScope(val session: FirSession) : FirScope {
//base symbol as key
val overrides = mutableMapOf<ConeCallableSymbol, ConeCallableSymbol?>()
val context: ConeTypeContext = session.typeContext
private fun isEqualTypes(a: ConeKotlinType, b: ConeKotlinType) = AbstractStrictEqualityTypeChecker.strictEqualTypes(context, a, b)
private fun isEqualTypes(a: FirTypeRef, b: FirTypeRef) =
isEqualTypes(a.cast<FirResolvedTypeRef>().type, b.cast<FirResolvedTypeRef>().type)
private fun isOverriddenFunCheck(member: FirNamedFunction, self: FirNamedFunction): Boolean {
return member.valueParameters.size == self.valueParameters.size &&
member.valueParameters.zip(self.valueParameters).all { (memberParam, selfParam) ->
isEqualTypes(memberParam.returnTypeRef, selfParam.returnTypeRef)
}
}
protected fun ConeCallableSymbol.isOverridden(seen: Set<ConeCallableSymbol>): ConeCallableSymbol? {
if (overrides.containsKey(this)) return overrides[this]
fun sameReceivers(memberTypeRef: FirTypeRef?, selfTypeRef: FirTypeRef?): Boolean {
return when {
memberTypeRef != null && selfTypeRef != null -> isEqualTypes(memberTypeRef, selfTypeRef)
else -> memberTypeRef == null && selfTypeRef == null
}
}
fun similarFunctionsOrBothProperties(declaration: FirCallableDeclaration, self: FirCallableDeclaration): Boolean {
return when (declaration) {
is FirNamedFunction -> self is FirNamedFunction && isOverriddenFunCheck(declaration, self)
is FirConstructor -> false
is FirProperty -> self is FirProperty
else -> error("Unknown fir callable type: $declaration, $self")
}
}
val self = (this as AbstractFirBasedSymbol<*>).fir as FirCallableMemberDeclaration
val overriding = seen.firstOrNull {
val member = (it as AbstractFirBasedSymbol<*>).fir as FirCallableMemberDeclaration
self.modality != Modality.FINAL
&& sameReceivers(member.receiverTypeRef, self.receiverTypeRef)
&& similarFunctionsOrBothProperties(member, self)
} // TODO: two or more overrides for one fun?
overrides[this] = overriding
return overriding
}
}
@@ -5,74 +5,19 @@
package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.ProcessorAction.NEXT
import org.jetbrains.kotlin.fir.scopes.ProcessorAction.STOP
import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypeContext
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker
import org.jetbrains.kotlin.utils.addToStdlib.cast
class FirClassUseSiteScope(
session: FirSession,
private val superTypesScope: FirScope,
private val declaredMemberScope: FirScope
) : FirAbstractProviderBasedScope(session, lookupInFir = true) {
//base symbol as key
val overrides = mutableMapOf<ConeCallableSymbol, ConeCallableSymbol?>()
val context: ConeTypeContext = session.typeContext
private fun isEqualTypes(a: ConeKotlinType, b: ConeKotlinType) = AbstractStrictEqualityTypeChecker.strictEqualTypes(context, a, b)
private fun isEqualTypes(a: FirTypeRef, b: FirTypeRef) =
isEqualTypes(a.cast<FirResolvedTypeRef>().type, b.cast<FirResolvedTypeRef>().type)
private fun isOverriddenFunCheck(member: FirNamedFunction, self: FirNamedFunction): Boolean {
return member.valueParameters.size == self.valueParameters.size &&
member.valueParameters.zip(self.valueParameters).all { (memberParam, selfParam) ->
isEqualTypes(memberParam.returnTypeRef, selfParam.returnTypeRef)
}
}
private fun ConeCallableSymbol.isOverridden(seen: Set<ConeCallableSymbol>): ConeCallableSymbol? {
if (overrides.containsKey(this)) return overrides[this]
fun sameReceivers(memberTypeRef: FirTypeRef?, selfTypeRef: FirTypeRef?): Boolean {
return when {
memberTypeRef != null && selfTypeRef != null -> isEqualTypes(memberTypeRef, selfTypeRef)
else -> memberTypeRef == null && selfTypeRef == null
}
}
fun similarFunctionsOrBothProperties(declaration: FirCallableDeclaration, self: FirCallableDeclaration): Boolean {
return when (declaration) {
is FirNamedFunction -> self is FirNamedFunction && isOverriddenFunCheck(declaration, self)
is FirConstructor -> false
is FirProperty -> self is FirProperty
else -> error("Unknown fir callable type: $declaration, $self")
}
}
val self = (this as AbstractFirBasedSymbol<*>).fir as FirCallableMemberDeclaration
val overriding = seen.firstOrNull {
val member = (it as AbstractFirBasedSymbol<*>).fir as FirCallableMemberDeclaration
self.modality != Modality.FINAL
&& sameReceivers(member.receiverTypeRef, self.receiverTypeRef)
&& similarFunctionsOrBothProperties(member, self)
} // TODO: two or more overrides for one fun?
overrides[this] = overriding
return overriding
}
) : AbstractFirOverrideScope(session) {
override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction {
val seen = mutableSetOf<ConeCallableSymbol>()
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
import org.jetbrains.kotlin.fir.symbols.ConeFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.ConeVariableSymbol
import org.jetbrains.kotlin.name.Name
class FirSuperTypeScope(
session: FirSession,
val scopes: List<FirScope>
) : AbstractFirOverrideScope(session) {
override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction {
val accepted = mutableSetOf<ConeFunctionSymbol>()
val pending = mutableSetOf<ConeFunctionSymbol>()
for (scope in scopes) {
if (scope.processFunctionsByName(name) {
if (it !in accepted && it.isOverridden(accepted) == null) {
pending += it
processor(it)
} else {
ProcessorAction.NEXT
}
}.stop()
) {
return ProcessorAction.STOP
}
accepted += pending
pending.clear()
}
return super.processFunctionsByName(name, processor)
}
override fun processPropertiesByName(name: Name, processor: (ConeVariableSymbol) -> ProcessorAction): ProcessorAction {
val accepted = mutableSetOf<ConeCallableSymbol>()
val pending = mutableSetOf<ConeVariableSymbol>()
for (scope in scopes) {
if (scope.processPropertiesByName(name) {
if (it !in accepted && it.isOverridden(accepted) == null) {
pending += it
processor(it)
} else {
ProcessorAction.NEXT
}
}.stop()
) {
return ProcessorAction.STOP
}
accepted += pending
pending.clear()
}
return super.processPropertiesByName(name, processor)
}
}
@@ -1,5 +1,5 @@
FILE: typeAliasDeserialization.kt
public final fun main(): R|kotlin/Unit| {
lval a: R|java/util/LinkedHashSet<kotlin/String>| = R|java/util/LinkedHashSet.LinkedHashSet|<R|kotlin/String|>()
R|<local>/a|.<Inapplicable(INAPPLICABLE): [java/util/HashSet.add, java/util/AbstractCollection.add, java/util/Collection.add, java/util/Set.add]>#(String())
R|<local>/a|.R|FakeOverride<java/util/HashSet.add: R|kotlin/Boolean|>|(String())
}
@@ -1,6 +1,4 @@
public abstract interface SubclassOfMapEntry<K, V> : R|java/util/Map.Entry<K, V>| {
public abstract operator fun setValue(value: R|ft<V, V?>|!): R|ft<V, V?>|!
public abstract operator fun setValue(<anonymous Java parameter>: R|ft<V, V?>|!): R|ft<V, V?>|!
}