[FIR] Substitute type parameters in inheritance checker

This commit is contained in:
Andrey Zinovyev
2021-06-14 13:23:53 +03:00
committed by teamcityserver
parent 3f7d050f8f
commit f4c8108ee0
@@ -14,8 +14,10 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.impl.deduplicating import org.jetbrains.kotlin.fir.analysis.diagnostics.impl.deduplicating
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.scopes.FirTypeScope import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData
import org.jetbrains.kotlin.fir.scopes.impl.toConeType
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
@@ -75,12 +77,18 @@ object FirImplementationMismatchChecker : FirClassChecker() {
} }
fun canOverride( fun canOverride(
baseMember: FirCallableDeclaration<*>, inheritedMember: FirCallableDeclaration<*>,
inheritedType: ConeKotlinType, inheritedType: ConeKotlinType,
baseMember: FirCallableDeclaration<*>,
baseType: ConeKotlinType baseType: ConeKotlinType
): Boolean = ): Boolean {
if (baseMember is FirProperty && baseMember.isVar) AbstractTypeChecker.equalTypes(typeCheckerContext, inheritedType, baseType) val inheritedTypeSubstituted = inheritedType.substituteTypeParameters(inheritedMember, baseMember, context)
else AbstractTypeChecker.isSubtypeOf(typeCheckerContext, inheritedType, baseType) return if (baseMember is FirProperty && baseMember.isVar)
AbstractTypeChecker.equalTypes(typeCheckerContext, inheritedTypeSubstituted, baseType)
else
AbstractTypeChecker.isSubtypeOf(typeCheckerContext, inheritedTypeSubstituted, baseType)
}
if (symbol.callableId.classId != containingClass.classId) return if (symbol.callableId.classId != containingClass.classId) return
@@ -109,8 +117,8 @@ object FirImplementationMismatchChecker : FirClassChecker() {
var clash: Pair<FirCallableDeclaration<*>, FirCallableDeclaration<*>>? = null var clash: Pair<FirCallableDeclaration<*>, FirCallableDeclaration<*>>? = null
val compatible = withTypes.any { (m1, type1) -> val compatible = withTypes.any { (m1, type1) ->
withTypes.all { (m2, type2) -> withTypes.all { (m2, type2) ->
val result = canOverride(m2, type1, type2) val result = canOverride(m1, type1, m2, type2)
if (!result && clash == null && !canOverride(m1, type2, type1)) { if (!result && clash == null && !canOverride(m2, type2, m1, type1)) {
clash = m1 to m2 clash = m1 to m2
} }
result result
@@ -125,9 +133,9 @@ object FirImplementationMismatchChecker : FirClassChecker() {
if (delegation != null || implementations.isNotEmpty()) { if (delegation != null || implementations.isNotEmpty()) {
//if there are more than one implementation we report nothing because it will be reported differently //if there are more than one implementation we report nothing because it will be reported differently
val implementationMember = delegation ?: implementations.singleOrNull() ?: return val implementationMember = delegation ?: implementations.singleOrNull() ?: return
val methodType = context.returnTypeCalculator.tryCalculateReturnType(implementationMember).coneType val implementationType = context.returnTypeCalculator.tryCalculateReturnType(implementationMember).coneType
val (conflict, _) = withTypes.find { (baseMember, baseType) -> val (conflict, _) = withTypes.find { (baseMember, baseType) ->
!canOverride(baseMember, methodType, baseType) !canOverride(implementationMember, implementationType, baseMember, baseType)
} ?: return } ?: return
reportTypeMismatch(implementationMember, conflict, delegation != null) reportTypeMismatch(implementationMember, conflict, delegation != null)
@@ -187,4 +195,19 @@ object FirImplementationMismatchChecker : FirClassChecker() {
reporter.reportOn(containingClass.source, FirErrors.CONFLICTING_INHERITED_MEMBERS, clash.toList(), context) reporter.reportOn(containingClass.source, FirErrors.CONFLICTING_INHERITED_MEMBERS, clash.toList(), context)
} }
private fun ConeKotlinType.substituteTypeParameters(
fromDeclaration: FirCallableDeclaration<*>,
toDeclaration: FirCallableDeclaration<*>,
context: CheckerContext
): ConeKotlinType {
val fromParams = (fromDeclaration as? FirTypeParametersOwner)?.typeParameters ?: return this
val toParams = (toDeclaration as? FirTypeParametersOwner)?.typeParameters ?: return this
val substitutionMap = fromParams.zip(toParams) { from, to ->
from.symbol to to.toConeType()
}.toMap()
return substitutorByMap(substitutionMap, context.session).substituteOrSelf(this)
}
} }