FIR Java: implement correct type matching in SuperTypeScope

This commit is contained in:
Mikhail Glukhikh
2019-11-06 18:52:40 +03:00
parent 7fffd3d0f2
commit 30679ebfaf
14 changed files with 264 additions and 149 deletions
@@ -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.declarations.FirJavaMethod
import org.jetbrains.kotlin.fir.java.scopes.JavaClassEnhancementScope import org.jetbrains.kotlin.fir.java.scopes.JavaClassEnhancementScope
import org.jetbrains.kotlin.fir.java.scopes.JavaClassUseSiteMemberScope 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.resolve.*
import org.jetbrains.kotlin.fir.scopes.FirScope 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.scopes.impl.declaredMemberScope
import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
@@ -109,7 +109,7 @@ class JavaSymbolProvider(
} }
JavaClassUseSiteMemberScope( JavaClassUseSiteMemberScope(
regularClass, useSiteSession, regularClass, useSiteSession,
FirSuperTypeScope(useSiteSession, superTypeEnhancementScopes), declaredScope JavaSuperTypeScope(regularClass, useSiteSession, superTypeEnhancementScopes), declaredScope
) )
} }
} }
@@ -5,24 +5,18 @@
package org.jetbrains.kotlin.fir.java.scopes package org.jetbrains.kotlin.fir.java.scopes
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass 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.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction 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.AbstractFirUseSiteMemberScope
import org.jetbrains.kotlin.fir.scopes.impl.FirSuperTypeScope 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.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
class JavaClassUseSiteMemberScope( class JavaClassUseSiteMemberScope(
@@ -30,84 +24,14 @@ class JavaClassUseSiteMemberScope(
session: FirSession, session: FirSession,
superTypesScope: FirSuperTypeScope, superTypesScope: FirSuperTypeScope,
declaredMemberScope: FirScope 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 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) { internal fun bindOverrides(name: Name) {
val overrideCandidates = mutableSetOf<FirFunctionSymbol<*>>() val overrideCandidates = mutableSetOf<FirFunctionSymbol<*>>()
declaredMemberScope.processFunctionsByName(name) { declaredMemberScope.processFunctionsByName(name) {
@@ -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
}
}
}
@@ -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<FirScope>
) : FirSuperTypeScope(
session,
JavaOverrideChecker(session, if (klass is FirJavaClass) klass.javaTypeParameterStack else JavaTypeParameterStack.EMPTY),
scopes
)
@@ -9,10 +9,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirClassSubstitutionScope import org.jetbrains.kotlin.fir.scopes.impl.*
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.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
@@ -86,7 +83,11 @@ fun FirClass<*>.buildDefaultUseSiteMemberScope(useSiteSession: FirSession, build
null null
} }
} }
FirClassUseSiteMemberScope(useSiteSession, FirSuperTypeScope(useSiteSession, scopes), declaredScope) FirClassUseSiteMemberScope(
useSiteSession,
FirSuperTypeScope(useSiteSession, FirStandardOverrideChecker(useSiteSession), scopes),
declaredScope
)
} }
} }
@@ -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
}
@@ -8,63 +8,21 @@ package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol 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 //base symbol as key, overridden as value
val overrideByBase = mutableMapOf<FirCallableSymbol<*>, FirCallableSymbol<*>?>() val overrideByBase = mutableMapOf<FirCallableSymbol<*>, FirCallableSymbol<*>?>()
protected val context: ConeTypeContext = session.typeContext private fun isOverriddenFunction(overrideCandidate: FirSimpleFunction, baseDeclaration: FirSimpleFunction): Boolean {
return overrideChecker.isOverriddenFunction(overrideCandidate, baseDeclaration)
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<FirResolvedTypeRef>().type, b.cast<FirResolvedTypeRef>().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)
}
} }
protected open fun isOverriddenPropertyCheck( private fun isOverriddenProperty(overrideCandidate: FirCallableMemberDeclaration<*>, baseDeclaration: FirProperty): Boolean {
overrideCandidate: FirCallableMemberDeclaration<*>, // NB: in Java it can be a function which overrides accessor return overrideChecker.isOverriddenProperty(overrideCandidate, baseDeclaration)
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 similarFunctionsOrBothProperties( private fun similarFunctionsOrBothProperties(
@@ -73,12 +31,12 @@ abstract class AbstractFirOverrideScope(val session: FirSession) : FirScope() {
): Boolean { ): Boolean {
return when (overrideCandidate) { return when (overrideCandidate) {
is FirSimpleFunction -> when (baseDeclaration) { is FirSimpleFunction -> when (baseDeclaration) {
is FirSimpleFunction -> isOverriddenFunCheck(overrideCandidate, baseDeclaration) is FirSimpleFunction -> isOverriddenFunction(overrideCandidate, baseDeclaration)
is FirProperty -> isOverriddenPropertyCheck(overrideCandidate, baseDeclaration) is FirProperty -> isOverriddenProperty(overrideCandidate, baseDeclaration)
else -> false else -> false
} }
is FirConstructor -> false is FirConstructor -> false
is FirProperty -> baseDeclaration is FirProperty && isOverriddenPropertyCheck(overrideCandidate, baseDeclaration) is FirProperty -> baseDeclaration is FirProperty && isOverriddenProperty(overrideCandidate, baseDeclaration)
is FirField -> false is FirField -> false
else -> error("Unknown fir callable type: $overrideCandidate, $baseDeclaration") else -> error("Unknown fir callable type: $overrideCandidate, $baseDeclaration")
} }
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.scopes.impl package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.fir.FirSession 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.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
@@ -14,9 +15,10 @@ import org.jetbrains.kotlin.name.Name
abstract class AbstractFirUseSiteMemberScope( abstract class AbstractFirUseSiteMemberScope(
session: FirSession, session: FirSession,
overrideChecker: FirOverrideChecker,
protected val superTypesScope: FirSuperTypeScope, protected val superTypesScope: FirSuperTypeScope,
protected val declaredMemberScope: FirScope protected val declaredMemberScope: FirScope
) : AbstractFirOverrideScope(session) { ) : AbstractFirOverrideScope(session, overrideChecker) {
override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction { override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction {
val overrideCandidates = mutableSetOf<FirFunctionSymbol<*>>() val overrideCandidates = mutableSetOf<FirFunctionSymbol<*>>()
if (!declaredMemberScope.processFunctionsByName(name) { if (!declaredMemberScope.processFunctionsByName(name) {
@@ -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
}
}
@@ -17,7 +17,7 @@ class FirClassUseSiteMemberScope(
session: FirSession, session: FirSession,
superTypesScope: FirSuperTypeScope, superTypesScope: FirSuperTypeScope,
declaredMemberScope: FirScope declaredMemberScope: FirScope
) : AbstractFirUseSiteMemberScope(session, superTypesScope, declaredMemberScope) { ) : AbstractFirUseSiteMemberScope(session, FirStandardOverrideChecker(session), superTypesScope, declaredMemberScope) {
override fun processPropertiesByName(name: Name, processor: (FirCallableSymbol<*>) -> ProcessorAction): ProcessorAction { override fun processPropertiesByName(name: Name, processor: (FirCallableSymbol<*>) -> ProcessorAction): ProcessorAction {
val seen = mutableSetOf<FirCallableSymbol<*>>() val seen = mutableSetOf<FirCallableSymbol<*>>()
@@ -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)
}
}
@@ -6,16 +6,18 @@
package org.jetbrains.kotlin.fir.scopes.impl package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.fir.FirSession 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.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
class FirSuperTypeScope( open class FirSuperTypeScope(
session: FirSession, session: FirSession,
overrideChecker: FirOverrideChecker,
val scopes: List<FirScope> val scopes: List<FirScope>
) : AbstractFirOverrideScope(session) { ) : AbstractFirOverrideScope(session, overrideChecker) {
private val absentFunctions = mutableSetOf<Name>() private val absentFunctions = mutableSetOf<Name>()
@@ -3,7 +3,7 @@
fun foo() { fun foo() {
val y = listOf("Alpha", "Beta") val y = listOf("Alpha", "Beta")
val x = LinkedHashSet<String>().apply { val x = LinkedHashSet<String>().apply {
<!AMBIGUITY!>addAll<!>(y) addAll(y)
} }
val z = ArrayList<String>() val z = ArrayList<String>()
@@ -2,7 +2,7 @@ FILE: addAllOnJavaCollection.kt
public final fun foo(): R|kotlin/Unit| { public final fun foo(): R|kotlin/Unit| {
lval y: R|kotlin/collections/List<kotlin/String>| = R|kotlin/collections/listOf|<R|kotlin/String|>(String(Alpha), String(Beta)) lval y: R|kotlin/collections/List<kotlin/String>| = R|kotlin/collections/listOf|<R|kotlin/String|>(String(Alpha), String(Beta))
lval x: R|java/util/LinkedHashSet<kotlin/String>| = R|java/util/LinkedHashSet.LinkedHashSet|<R|kotlin/String|>().R|kotlin/apply|<R|java/util/LinkedHashSet<kotlin/String>|>(<L> = apply@fun R|java/util/LinkedHashSet<kotlin/String>|.<anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> { lval x: R|java/util/LinkedHashSet<kotlin/String>| = R|java/util/LinkedHashSet.LinkedHashSet|<R|kotlin/String|>().R|kotlin/apply|<R|java/util/LinkedHashSet<kotlin/String>|>(<L> = apply@fun R|java/util/LinkedHashSet<kotlin/String>|.<anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
<Ambiguity: addAll, [java/util/AbstractCollection.addAll, kotlin/collections/MutableSet.addAll]>#(R|<local>/y|) this@R|java/util/AbstractCollection|.R|FakeOverride<java/util/AbstractCollection.addAll: R|kotlin/Boolean|>|(R|<local>/y|)
} }
) )
lval z: R|java/util/ArrayList<kotlin/String>| = R|java/util/ArrayList.ArrayList|<R|kotlin/String|>() lval z: R|java/util/ArrayList<kotlin/String>| = R|java/util/ArrayList.ArrayList|<R|kotlin/String|>()