[FIR] Substitute type parameters in inheritance checker
This commit is contained in:
committed by
teamcityserver
parent
3f7d050f8f
commit
f4c8108ee0
+31
-8
@@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user