diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt index 02a434ca55c..012242ef464 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt @@ -19,9 +19,9 @@ import org.jetbrains.kotlin.fir.java.declarations.FirJavaField import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod import org.jetbrains.kotlin.fir.java.scopes.JavaClassEnhancementScope import org.jetbrains.kotlin.fir.java.scopes.JavaClassUseSiteMemberScope +import org.jetbrains.kotlin.fir.java.scopes.JavaSuperTypeScope import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.scopes.FirScope -import org.jetbrains.kotlin.fir.scopes.impl.FirSuperTypeScope import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.impl.* @@ -109,7 +109,7 @@ class JavaSymbolProvider( } JavaClassUseSiteMemberScope( regularClass, useSiteSession, - FirSuperTypeScope(useSiteSession, superTypeEnhancementScopes), declaredScope + JavaSuperTypeScope(regularClass, useSiteSession, superTypeEnhancementScopes), declaredScope ) } } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt index abb4e60b5dd..82ec3fb996c 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt @@ -5,24 +5,18 @@ package org.jetbrains.kotlin.fir.java.scopes -import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass -import org.jetbrains.kotlin.fir.java.enhancement.readOnlyToMutable -import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType -import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor -import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.ProcessorAction -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.scopes.impl.AbstractFirUseSiteMemberScope import org.jetbrains.kotlin.fir.scopes.impl.FirSuperTypeScope -import org.jetbrains.kotlin.fir.symbols.* +import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.impl.* -import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.name.Name class JavaClassUseSiteMemberScope( @@ -30,84 +24,14 @@ class JavaClassUseSiteMemberScope( session: FirSession, superTypesScope: FirSuperTypeScope, declaredMemberScope: FirScope -) : AbstractFirUseSiteMemberScope(session, superTypesScope, declaredMemberScope) { +) : AbstractFirUseSiteMemberScope( + session, + JavaOverrideChecker(session, if (klass is FirJavaClass) klass.javaTypeParameterStack else JavaTypeParameterStack.EMPTY), + superTypesScope, + declaredMemberScope +) { internal val symbol = klass.symbol - private val javaTypeParameterStack: JavaTypeParameterStack = - if (klass is FirJavaClass) klass.javaTypeParameterStack else JavaTypeParameterStack.EMPTY - - private fun isEqualTypes(a: ConeKotlinType, b: ConeKotlinType, substitutor: ConeSubstitutor): Boolean { - if (a is ConeFlexibleType) return isEqualTypes(a.lowerBound, b, substitutor) - if (b is ConeFlexibleType) return isEqualTypes(a, b.lowerBound, substitutor) - return if (a is ConeClassType && b is ConeClassType) { - a.lookupTag.classId.let { it.readOnlyToMutable() ?: it } == b.lookupTag.classId.let { it.readOnlyToMutable() ?: it } - } else { - with(context) { - isEqualTypeConstructors( - substitutor.substituteOrSelf(a).typeConstructor(), - substitutor.substituteOrSelf(b).typeConstructor() - ) - } - } - } - - private fun isEqualTypes(a: FirTypeRef, b: FirTypeRef, substitutor: ConeSubstitutor) = - isEqualTypes( - a.toNotNullConeKotlinType(session, javaTypeParameterStack), - b.toNotNullConeKotlinType(session, javaTypeParameterStack), - substitutor - ) - - override fun isOverriddenFunCheck(overrideCandidate: FirSimpleFunction, baseDeclaration: FirSimpleFunction): Boolean { - // NB: overrideCandidate is from Java and has no receiver - val receiverTypeRef = baseDeclaration.receiverTypeRef - val baseParameterTypes = listOfNotNull(receiverTypeRef) + baseDeclaration.valueParameters.map { it.returnTypeRef } - - if (overrideCandidate.valueParameters.size != baseParameterTypes.size) return false - if (overrideCandidate.typeParameters.size != baseDeclaration.typeParameters.size) return false - - val types = baseDeclaration.typeParameters.map { - ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) - } - val substitution = substitutorByMap(overrideCandidate.typeParameters.map { it.symbol }.zip(types).toMap()) - if (!overrideCandidate.typeParameters.zip(baseDeclaration.typeParameters).all { (a, b) -> - a.bounds.size == b.bounds.size && a.bounds.zip(b.bounds).all { (aBound, bBound) -> - isEqualTypes(aBound, bBound, substitution) - } - } - ) return false - - - return overrideCandidate.valueParameters.zip(baseParameterTypes).all { (paramFromJava, baseType) -> - isEqualTypes(paramFromJava.returnTypeRef, baseType, substitution) - } - } - - override fun isOverriddenPropertyCheck(overrideCandidate: FirCallableMemberDeclaration<*>, baseDeclaration: FirProperty): Boolean { - if (baseDeclaration.modality == Modality.FINAL) return false - val receiverTypeRef = baseDeclaration.receiverTypeRef - return when (overrideCandidate) { - is FirSimpleFunction -> { - if (receiverTypeRef == null) { - // TODO: setters - return overrideCandidate.valueParameters.isEmpty() - } else { - if (overrideCandidate.valueParameters.size != 1) return false - return isEqualTypes(receiverTypeRef, overrideCandidate.valueParameters.single().returnTypeRef, ConeSubstitutor.Empty) - } - } - is FirProperty -> { - val overrideReceiverTypeRef = overrideCandidate.receiverTypeRef - return when { - receiverTypeRef == null -> overrideReceiverTypeRef == null - overrideReceiverTypeRef == null -> false - else -> isEqualTypes(receiverTypeRef, overrideReceiverTypeRef, ConeSubstitutor.Empty) - } - } - else -> false - } - } - internal fun bindOverrides(name: Name) { val overrideCandidates = mutableSetOf>() declaredMemberScope.processFunctionsByName(name) { diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaOverrideChecker.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaOverrideChecker.kt new file mode 100644 index 00000000000..ab862017138 --- /dev/null +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaOverrideChecker.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.java.scopes + +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration +import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.declarations.modality +import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack +import org.jetbrains.kotlin.fir.java.enhancement.readOnlyToMutable +import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor +import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractOverrideChecker +import org.jetbrains.kotlin.fir.typeContext +import org.jetbrains.kotlin.fir.types.* + +class JavaOverrideChecker internal constructor( + private val session: FirSession, + private val javaTypeParameterStack: JavaTypeParameterStack +) : FirAbstractOverrideChecker() { + private val context: ConeTypeContext = session.typeContext + + private fun isEqualTypes(candidateType: ConeKotlinType, baseType: ConeKotlinType, substitutor: ConeSubstitutor): Boolean { + if (candidateType is ConeFlexibleType) return isEqualTypes(candidateType.lowerBound, baseType, substitutor) + if (baseType is ConeFlexibleType) return isEqualTypes(candidateType, baseType.lowerBound, substitutor) + return if (candidateType is ConeClassType && baseType is ConeClassType) { + candidateType.lookupTag.classId.let { it.readOnlyToMutable() ?: it } == baseType.lookupTag.classId.let { it.readOnlyToMutable() ?: it } + } else { + with(context) { + isEqualTypeConstructors( + substitutor.substituteOrSelf(candidateType).typeConstructor(), + substitutor.substituteOrSelf(baseType).typeConstructor() + ) + } + } + } + + override fun isEqualTypes(candidateTypeRef: FirTypeRef, baseTypeRef: FirTypeRef, substitutor: ConeSubstitutor) = + isEqualTypes( + candidateTypeRef.toNotNullConeKotlinType(session, javaTypeParameterStack), + baseTypeRef.toNotNullConeKotlinType(session, javaTypeParameterStack), + substitutor + ) + + override fun isOverriddenFunction(overrideCandidate: FirSimpleFunction, baseDeclaration: FirSimpleFunction): Boolean { + // NB: overrideCandidate is from Java and has no receiver + val receiverTypeRef = baseDeclaration.receiverTypeRef + val baseParameterTypes = listOfNotNull(receiverTypeRef) + baseDeclaration.valueParameters.map { it.returnTypeRef } + + if (overrideCandidate.valueParameters.size != baseParameterTypes.size) return false + val substitutor = getSubstitutorIfTypeParametersAreCompatible(overrideCandidate, baseDeclaration) ?: return false + + return overrideCandidate.valueParameters.zip(baseParameterTypes).all { (paramFromJava, baseType) -> + isEqualTypes(paramFromJava.returnTypeRef, baseType, substitutor) + } + } + + override fun isOverriddenProperty(overrideCandidate: FirCallableMemberDeclaration<*>, baseDeclaration: FirProperty): Boolean { + if (baseDeclaration.modality == Modality.FINAL) return false + val receiverTypeRef = baseDeclaration.receiverTypeRef + return when (overrideCandidate) { + is FirSimpleFunction -> { + if (receiverTypeRef == null) { + // TODO: setters + return overrideCandidate.valueParameters.isEmpty() + } else { + if (overrideCandidate.valueParameters.size != 1) return false + return isEqualTypes(receiverTypeRef, overrideCandidate.valueParameters.single().returnTypeRef, ConeSubstitutor.Empty) + } + } + is FirProperty -> { + val overrideReceiverTypeRef = overrideCandidate.receiverTypeRef + return when { + receiverTypeRef == null -> overrideReceiverTypeRef == null + overrideReceiverTypeRef == null -> false + else -> isEqualTypes(receiverTypeRef, overrideReceiverTypeRef, ConeSubstitutor.Empty) + } + } + else -> false + } + } + +} \ No newline at end of file diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaSuperTypeScope.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaSuperTypeScope.kt new file mode 100644 index 00000000000..5c61813a309 --- /dev/null +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaSuperTypeScope.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.java.scopes + +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack +import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass +import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.scopes.impl.FirSuperTypeScope + +class JavaSuperTypeScope( + klass: FirRegularClass, + session: FirSession, + scopes: List +) : FirSuperTypeScope( + session, + JavaOverrideChecker(session, if (klass is FirJavaClass) klass.javaTypeParameterStack else JavaTypeParameterStack.EMPTY), + scopes +) \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt index 5cb219118c4..b72f8f7770d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt @@ -9,10 +9,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind 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.impl.FirClassSubstitutionScope -import org.jetbrains.kotlin.fir.scopes.impl.FirClassUseSiteMemberScope -import org.jetbrains.kotlin.fir.scopes.impl.FirSuperTypeScope -import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope +import org.jetbrains.kotlin.fir.scopes.impl.* import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* @@ -86,7 +83,11 @@ fun FirClass<*>.buildDefaultUseSiteMemberScope(useSiteSession: FirSession, build null } } - FirClassUseSiteMemberScope(useSiteSession, FirSuperTypeScope(useSiteSession, scopes), declaredScope) + FirClassUseSiteMemberScope( + useSiteSession, + FirSuperTypeScope(useSiteSession, FirStandardOverrideChecker(useSiteSession), scopes), + declaredScope + ) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/FirOverrideChecker.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/FirOverrideChecker.kt new file mode 100644 index 00000000000..3bcb2944871 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/FirOverrideChecker.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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 + +import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration +import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction + +interface FirOverrideChecker { + fun isOverriddenFunction( + overrideCandidate: FirSimpleFunction, + baseDeclaration: FirSimpleFunction + ): Boolean + + fun isOverriddenProperty( + overrideCandidate: FirCallableMemberDeclaration<*>, // NB: in Java it can be a function which overrides accessor + baseDeclaration: FirProperty + ): Boolean +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirOverrideScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirOverrideScope.kt index b7066783c9b..a2897aaf6da 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirOverrideScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirOverrideScope.kt @@ -8,63 +8,21 @@ 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.resolve.substitution.ConeSubstitutor -import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap +import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol -import org.jetbrains.kotlin.fir.typeContext -import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl -import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker -import org.jetbrains.kotlin.utils.addToStdlib.cast -abstract class AbstractFirOverrideScope(val session: FirSession) : FirScope() { +abstract class AbstractFirOverrideScope(val session: FirSession, private val overrideChecker: FirOverrideChecker) : FirScope() { //base symbol as key, overridden as value val overrideByBase = mutableMapOf, FirCallableSymbol<*>?>() - protected val context: ConeTypeContext = session.typeContext - - private fun isEqualTypes(a: ConeKotlinType, b: ConeKotlinType, substitution: ConeSubstitutor) = - AbstractStrictEqualityTypeChecker.strictEqualTypes(context, substitution.substituteOrSelf(a), substitution.substituteOrSelf(b)) - - private fun isEqualTypes(a: FirTypeRef, b: FirTypeRef, substitution: ConeSubstitutor) = - isEqualTypes(a.cast().type, b.cast().type, substitution) - - protected open fun isOverriddenFunCheck(overrideCandidate: FirSimpleFunction, baseDeclaration: FirSimpleFunction): Boolean { - if (overrideCandidate.valueParameters.size != baseDeclaration.valueParameters.size) return false - if (overrideCandidate.typeParameters.size != baseDeclaration.typeParameters.size) return false - - val types = baseDeclaration.typeParameters.map { - ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) - } - val substitution = substitutorByMap(overrideCandidate.typeParameters.map { it.symbol }.zip(types).toMap()) - if (!overrideCandidate.typeParameters.zip(baseDeclaration.typeParameters).all { (a, b) -> - a.bounds.size == b.bounds.size && - a.bounds.zip(b.bounds).all { (aBound, bBound) -> isEqualTypes(aBound, bBound, substitution) } - } - ) return false - if (!sameReceivers(overrideCandidate.receiverTypeRef, baseDeclaration.receiverTypeRef, substitution)) return false - - return overrideCandidate.valueParameters.zip(baseDeclaration.valueParameters).all { (memberParam, selfParam) -> - isEqualTypes(memberParam.returnTypeRef, selfParam.returnTypeRef, substitution) - } + private fun isOverriddenFunction(overrideCandidate: FirSimpleFunction, baseDeclaration: FirSimpleFunction): Boolean { + return overrideChecker.isOverriddenFunction(overrideCandidate, baseDeclaration) } - protected open fun isOverriddenPropertyCheck( - overrideCandidate: FirCallableMemberDeclaration<*>, // NB: in Java it can be a function which overrides accessor - baseDeclaration: FirProperty - ): Boolean { - // TODO: substitutor - return overrideCandidate is FirProperty && - sameReceivers(overrideCandidate.receiverTypeRef, baseDeclaration.receiverTypeRef, ConeSubstitutor.Empty) - } - - private fun sameReceivers(memberTypeRef: FirTypeRef?, selfTypeRef: FirTypeRef?, substitution: ConeSubstitutor): Boolean { - return when { - memberTypeRef != null && selfTypeRef != null -> isEqualTypes(memberTypeRef, selfTypeRef, substitution) - else -> memberTypeRef == null && selfTypeRef == null - } + private fun isOverriddenProperty(overrideCandidate: FirCallableMemberDeclaration<*>, baseDeclaration: FirProperty): Boolean { + return overrideChecker.isOverriddenProperty(overrideCandidate, baseDeclaration) } private fun similarFunctionsOrBothProperties( @@ -73,12 +31,12 @@ abstract class AbstractFirOverrideScope(val session: FirSession) : FirScope() { ): Boolean { return when (overrideCandidate) { is FirSimpleFunction -> when (baseDeclaration) { - is FirSimpleFunction -> isOverriddenFunCheck(overrideCandidate, baseDeclaration) - is FirProperty -> isOverriddenPropertyCheck(overrideCandidate, baseDeclaration) + is FirSimpleFunction -> isOverriddenFunction(overrideCandidate, baseDeclaration) + is FirProperty -> isOverriddenProperty(overrideCandidate, baseDeclaration) else -> false } is FirConstructor -> false - is FirProperty -> baseDeclaration is FirProperty && isOverriddenPropertyCheck(overrideCandidate, baseDeclaration) + is FirProperty -> baseDeclaration is FirProperty && isOverriddenProperty(overrideCandidate, baseDeclaration) is FirField -> false else -> error("Unknown fir callable type: $overrideCandidate, $baseDeclaration") } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt index 7e71e1832d7..ec4a8aab653 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/AbstractFirUseSiteMemberScope.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.scopes.impl import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol @@ -14,9 +15,10 @@ import org.jetbrains.kotlin.name.Name abstract class AbstractFirUseSiteMemberScope( session: FirSession, + overrideChecker: FirOverrideChecker, protected val superTypesScope: FirSuperTypeScope, protected val declaredMemberScope: FirScope -) : AbstractFirOverrideScope(session) { +) : AbstractFirOverrideScope(session, overrideChecker) { override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction { val overrideCandidates = mutableSetOf>() if (!declaredMemberScope.processFunctionsByName(name) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractOverrideChecker.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractOverrideChecker.kt new file mode 100644 index 00000000000..c79e27633a9 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractOverrideChecker.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor +import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap +import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl + +abstract class FirAbstractOverrideChecker : FirOverrideChecker { + + protected abstract fun isEqualTypes(candidateTypeRef: FirTypeRef, baseTypeRef: FirTypeRef, substitutor: ConeSubstitutor): Boolean + + protected fun getSubstitutorIfTypeParametersAreCompatible( + overrideCandidate: FirSimpleFunction, + baseDeclaration: FirSimpleFunction + ): ConeSubstitutor? { + if (overrideCandidate.typeParameters.size != baseDeclaration.typeParameters.size) return null + + val types = baseDeclaration.typeParameters.map { + ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) + } + val substitutor = substitutorByMap(overrideCandidate.typeParameters.map { it.symbol }.zip(types).toMap()) + if (!overrideCandidate.typeParameters.zip(baseDeclaration.typeParameters).all { (a, b) -> + a.bounds.size == b.bounds.size && a.bounds.zip(b.bounds).all { (aBound, bBound) -> + isEqualTypes(aBound, bBound, substitutor) + } + } + ) return null + return substitutor + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassUseSiteMemberScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassUseSiteMemberScope.kt index bbf64e01ee2..e41dfa2022d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassUseSiteMemberScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassUseSiteMemberScope.kt @@ -17,7 +17,7 @@ class FirClassUseSiteMemberScope( session: FirSession, superTypesScope: FirSuperTypeScope, declaredMemberScope: FirScope -) : AbstractFirUseSiteMemberScope(session, superTypesScope, declaredMemberScope) { +) : AbstractFirUseSiteMemberScope(session, FirStandardOverrideChecker(session), superTypesScope, declaredMemberScope) { override fun processPropertiesByName(name: Name, processor: (FirCallableSymbol<*>) -> ProcessorAction): ProcessorAction { val seen = mutableSetOf>() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirStandardOverrideChecker.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirStandardOverrideChecker.kt new file mode 100644 index 00000000000..9e581068225 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirStandardOverrideChecker.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.declarations.FirCallableMemberDeclaration +import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor +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.strictEqualTypes + +class FirStandardOverrideChecker(session: FirSession) : FirAbstractOverrideChecker() { + + private val context: ConeTypeContext = session.typeContext + + private fun isEqualTypes(candidateType: ConeKotlinType, baseType: ConeKotlinType, substitutor: ConeSubstitutor) = + strictEqualTypes(context, substitutor.substituteOrSelf(candidateType), substitutor.substituteOrSelf(baseType)) + + override fun isEqualTypes(candidateTypeRef: FirTypeRef, baseTypeRef: FirTypeRef, substitutor: ConeSubstitutor) = + isEqualTypes((candidateTypeRef as FirResolvedTypeRef).type, (baseTypeRef as FirResolvedTypeRef).type, substitutor) + + private fun isEqualReceiverTypes(candidateTypeRef: FirTypeRef?, baseTypeRef: FirTypeRef?, substitutor: ConeSubstitutor): Boolean { + return when { + candidateTypeRef != null && baseTypeRef != null -> isEqualTypes(candidateTypeRef, baseTypeRef, substitutor) + else -> candidateTypeRef == null && baseTypeRef == null + } + } + + override fun isOverriddenFunction(overrideCandidate: FirSimpleFunction, baseDeclaration: FirSimpleFunction): Boolean { + if (overrideCandidate.valueParameters.size != baseDeclaration.valueParameters.size) return false + + val substitutor = getSubstitutorIfTypeParametersAreCompatible(overrideCandidate, baseDeclaration) ?: return false + + if (!isEqualReceiverTypes(overrideCandidate.receiverTypeRef, baseDeclaration.receiverTypeRef, substitutor)) return false + + return overrideCandidate.valueParameters.zip(baseDeclaration.valueParameters).all { (memberParam, selfParam) -> + isEqualTypes(memberParam.returnTypeRef, selfParam.returnTypeRef, substitutor) + } + + } + + override fun isOverriddenProperty( + overrideCandidate: FirCallableMemberDeclaration<*>, + baseDeclaration: FirProperty + ): Boolean { + // TODO: substitutor + return overrideCandidate is FirProperty && + isEqualReceiverTypes(overrideCandidate.receiverTypeRef, baseDeclaration.receiverTypeRef, ConeSubstitutor.Empty) + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirSuperTypeScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirSuperTypeScope.kt index 3ac7bba1035..39fa7dad159 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirSuperTypeScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirSuperTypeScope.kt @@ -6,16 +6,18 @@ package org.jetbrains.kotlin.fir.scopes.impl import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.name.Name -class FirSuperTypeScope( +open class FirSuperTypeScope( session: FirSession, + overrideChecker: FirOverrideChecker, val scopes: List -) : AbstractFirOverrideScope(session) { +) : AbstractFirOverrideScope(session, overrideChecker) { private val absentFunctions = mutableSetOf() diff --git a/compiler/fir/resolve/testData/resolve/stdlib/addAllOnJavaCollection.kt b/compiler/fir/resolve/testData/resolve/stdlib/addAllOnJavaCollection.kt index 60675bf6d11..4b90adb717b 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/addAllOnJavaCollection.kt +++ b/compiler/fir/resolve/testData/resolve/stdlib/addAllOnJavaCollection.kt @@ -3,7 +3,7 @@ fun foo() { val y = listOf("Alpha", "Beta") val x = LinkedHashSet().apply { - addAll(y) + addAll(y) } val z = ArrayList() diff --git a/compiler/fir/resolve/testData/resolve/stdlib/addAllOnJavaCollection.txt b/compiler/fir/resolve/testData/resolve/stdlib/addAllOnJavaCollection.txt index 0eece7ce126..f6ba06b724f 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/addAllOnJavaCollection.txt +++ b/compiler/fir/resolve/testData/resolve/stdlib/addAllOnJavaCollection.txt @@ -2,7 +2,7 @@ FILE: addAllOnJavaCollection.kt public final fun foo(): R|kotlin/Unit| { lval y: R|kotlin/collections/List| = R|kotlin/collections/listOf|(String(Alpha), String(Beta)) lval x: R|java/util/LinkedHashSet| = R|java/util/LinkedHashSet.LinkedHashSet|().R|kotlin/apply||>( = apply@fun R|java/util/LinkedHashSet|.(): R|kotlin/Unit| { - #(R|/y|) + this@R|java/util/AbstractCollection|.R|FakeOverride|(R|/y|) } ) lval z: R|java/util/ArrayList| = R|java/util/ArrayList.ArrayList|()