[FIR] Implement properties types mismatch on inheritence
PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, VAR_TYPE_MISMATCH_ON_INHERITANCE, PROPERTY_TYPE_MISMATCH_BY_DELEGATION
This commit is contained in:
committed by
teamcityserver
parent
8c7ee0b714
commit
c98cd3b190
+15
@@ -592,11 +592,26 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<FirCallableDeclaration<*>>("conflictingDeclaration2")
|
||||
}
|
||||
|
||||
val PROPERTY_TYPE_MISMATCH_ON_INHERITANCE by error<KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
|
||||
parameter<FirCallableDeclaration<*>>("conflictingDeclaration1")
|
||||
parameter<FirCallableDeclaration<*>>("conflictingDeclaration2")
|
||||
}
|
||||
|
||||
val VAR_TYPE_MISMATCH_ON_INHERITANCE by error<KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
|
||||
parameter<FirCallableDeclaration<*>>("conflictingDeclaration1")
|
||||
parameter<FirCallableDeclaration<*>>("conflictingDeclaration2")
|
||||
}
|
||||
|
||||
val RETURN_TYPE_MISMATCH_BY_DELEGATION by error<KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
|
||||
parameter<FirCallableDeclaration<*>>("delegateDeclaration")
|
||||
parameter<FirCallableDeclaration<*>>("baseDeclaration")
|
||||
}
|
||||
|
||||
val PROPERTY_TYPE_MISMATCH_BY_DELEGATION by error<KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
|
||||
parameter<FirCallableDeclaration<*>>("delegateDeclaration")
|
||||
parameter<FirCallableDeclaration<*>>("baseDeclaration")
|
||||
}
|
||||
|
||||
val ABSTRACT_MEMBER_NOT_IMPLEMENTED by error<KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
|
||||
parameter<FirClass>("classOrObject")
|
||||
parameter<FirCallableDeclaration>("missingDeclaration")
|
||||
|
||||
@@ -348,7 +348,10 @@ object FirErrors {
|
||||
val CANNOT_CHANGE_ACCESS_PRIVILEGE by error3<KtModifierListOwner, Visibility, FirCallableDeclaration, Name>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
|
||||
val OVERRIDING_FINAL_MEMBER by error2<KtNamedDeclaration, FirCallableDeclaration, Name>(SourceElementPositioningStrategies.OVERRIDE_MODIFIER)
|
||||
val RETURN_TYPE_MISMATCH_ON_INHERITANCE by error2<KtClassOrObject, FirCallableDeclaration<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val PROPERTY_TYPE_MISMATCH_ON_INHERITANCE by error2<KtClassOrObject, FirCallableDeclaration<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val VAR_TYPE_MISMATCH_ON_INHERITANCE by error2<KtClassOrObject, FirCallableDeclaration<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val RETURN_TYPE_MISMATCH_BY_DELEGATION by error2<KtClassOrObject, FirCallableDeclaration<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val PROPERTY_TYPE_MISMATCH_BY_DELEGATION by error2<KtClassOrObject, FirCallableDeclaration<*>, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val ABSTRACT_MEMBER_NOT_IMPLEMENTED by error2<KtClassOrObject, FirClass, FirCallableDeclaration>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED by error2<KtClassOrObject, FirClass, FirCallableDeclaration>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER by error2<KtClassOrObject, FirClass, FirCallableDeclaration>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
|
||||
+42
-16
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirIntersectionCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
|
||||
@@ -39,6 +40,30 @@ object FirImplementationMismatchChecker : FirClassChecker() {
|
||||
val classScope = declaration.unsubstitutedScope(context)
|
||||
val dedupReporter = reporter.deduplicating()
|
||||
|
||||
fun reportTypeMismatch(member1: FirCallableDeclaration<*>, member2: FirCallableDeclaration<*>, isDelegation: Boolean) {
|
||||
val error = if (member1 is FirProperty && member2 is FirProperty) {
|
||||
if (member1.isVar || member2.isVar) {
|
||||
FirErrors.VAR_TYPE_MISMATCH_ON_INHERITANCE
|
||||
} else {
|
||||
if (isDelegation) FirErrors.PROPERTY_TYPE_MISMATCH_BY_DELEGATION
|
||||
else FirErrors.PROPERTY_TYPE_MISMATCH_ON_INHERITANCE
|
||||
}
|
||||
} else {
|
||||
if (isDelegation) FirErrors.RETURN_TYPE_MISMATCH_BY_DELEGATION
|
||||
else FirErrors.RETURN_TYPE_MISMATCH_ON_INHERITANCE
|
||||
}
|
||||
dedupReporter.reportOn(source, error, member1, member2, context)
|
||||
}
|
||||
|
||||
fun canOverride(
|
||||
baseMember: FirCallableDeclaration<*>,
|
||||
inheritedType: ConeKotlinType,
|
||||
baseType: ConeKotlinType
|
||||
): Boolean =
|
||||
if (baseMember is FirProperty && baseMember.isVar) AbstractTypeChecker.equalTypes(typeCheckerContext, inheritedType, baseType)
|
||||
else AbstractTypeChecker.isSubtypeOf(typeCheckerContext, inheritedType, baseType)
|
||||
|
||||
|
||||
fun checkSymbol(symbol: FirCallableSymbol<*>) {
|
||||
if (symbol.callableId.classId != declaration.classId) return
|
||||
if (symbol !is FirIntersectionCallableSymbol) return
|
||||
@@ -62,37 +87,38 @@ object FirImplementationMismatchChecker : FirClassChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
if (delegation != null || implementations.isNotEmpty()) {
|
||||
//if there are more than one implementation we report nothing because it will be reported differently
|
||||
val method = delegation ?: implementations.singleOrNull() ?: return
|
||||
val methodType = context.returnTypeCalculator.tryCalculateReturnType(method).coneType
|
||||
val (conflict, _) = withTypes.find { (_, type) ->
|
||||
!AbstractTypeChecker.isSubtypeOf(typeCheckerContext, methodType, type)
|
||||
} ?: return
|
||||
val error =
|
||||
if (delegation != null) FirErrors.RETURN_TYPE_MISMATCH_BY_DELEGATION
|
||||
else FirErrors.RETURN_TYPE_MISMATCH_ON_INHERITANCE
|
||||
dedupReporter.reportOn(source, error, method, conflict, context)
|
||||
} else {
|
||||
//if there is no implementation, check that there can be any type compatible (subtype of) with all
|
||||
run {
|
||||
var clash: Pair<FirCallableDeclaration<*>, FirCallableDeclaration<*>>? = null
|
||||
val compatible = withTypes.any { (m1, type1) ->
|
||||
withTypes.all { (m2, type2) ->
|
||||
val result = AbstractTypeChecker.isSubtypeOf(typeCheckerContext, type1, type2)
|
||||
if (!result && clash == null && !AbstractTypeChecker.isSubtypeOf(typeCheckerContext, type2, type1)) {
|
||||
val result = canOverride(m2, type1, type2)
|
||||
if (!result && clash == null && !canOverride(m1, type2, type1)) {
|
||||
clash = m1 to m2
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
clash?.takeIf { !compatible }?.let { (m1, m2) ->
|
||||
dedupReporter.reportOn(source, FirErrors.RETURN_TYPE_MISMATCH_ON_INHERITANCE, m1, m2, context)
|
||||
reportTypeMismatch(m1, m2, false)
|
||||
return@checkSymbol
|
||||
}
|
||||
}
|
||||
|
||||
if (delegation != null || implementations.isNotEmpty()) {
|
||||
//if there are more than one implementation we report nothing because it will be reported differently
|
||||
val implementationMember = delegation ?: implementations.singleOrNull() ?: return
|
||||
val methodType = context.returnTypeCalculator.tryCalculateReturnType(implementationMember).coneType
|
||||
val (conflict, _) = withTypes.find { (baseMember, baseType) ->
|
||||
!canOverride(baseMember, methodType, baseType)
|
||||
} ?: return
|
||||
|
||||
reportTypeMismatch(implementationMember, conflict, delegation != null)
|
||||
}
|
||||
}
|
||||
|
||||
for (name in classScope.getCallableNames()) {
|
||||
classScope.processFunctionsByName(name, ::checkSymbol)
|
||||
classScope.processPropertiesByName(name, ::checkSymbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -267,6 +267,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROJECTION_IN_IMM
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_IN_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_NO_BACKING_FIELD
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_TYPE_MISMATCH_BY_DELEGATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_TYPE_MISMATCH_ON_INHERITANCE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_TYPE_MISMATCH_ON_OVERRIDE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_WITH_BACKING_FIELD_INSIDE_INLINE_CLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_WITH_NO_TYPE_NO_INITIALIZER
|
||||
@@ -384,6 +386,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VARIABLE_NEVER_RE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_ANNOTATION_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_OVERRIDDEN_BY_VAL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_TYPE_MISMATCH_ON_INHERITANCE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_TYPE_MISMATCH_ON_OVERRIDE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VIRTUAL_MEMBER_HIDDEN
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_ANNOTATION_TARGET
|
||||
@@ -944,6 +947,20 @@ class FirDefaultErrorMessages {
|
||||
NAME
|
||||
)
|
||||
|
||||
map.put(
|
||||
PROPERTY_TYPE_MISMATCH_ON_INHERITANCE,
|
||||
"''{0}'' clashes with ''{1}'': property types are incompatible",
|
||||
NAME,
|
||||
NAME
|
||||
)
|
||||
|
||||
map.put(
|
||||
VAR_TYPE_MISMATCH_ON_INHERITANCE,
|
||||
"''{0}'' clashes with ''{1}'': property types do not match",
|
||||
NAME,
|
||||
NAME
|
||||
)
|
||||
|
||||
map.put(
|
||||
RETURN_TYPE_MISMATCH_BY_DELEGATION,
|
||||
"Type of ''{0}'' is not a subtype of overridden by delegation ''{1}''",
|
||||
@@ -951,6 +968,13 @@ class FirDefaultErrorMessages {
|
||||
NAME
|
||||
)
|
||||
|
||||
map.put(
|
||||
PROPERTY_TYPE_MISMATCH_BY_DELEGATION,
|
||||
"Type of property ''{0}'' is not a subtype of overridden by delegation ''{1}''",
|
||||
NAME,
|
||||
NAME
|
||||
)
|
||||
|
||||
// Redeclarations
|
||||
map.put(MANY_COMPANION_OBJECTS, "Only one companion object is allowed per class")
|
||||
map.put(CONFLICTING_OVERLOADS, "Conflicting overloads: {0}", SYMBOLS) // *
|
||||
|
||||
+5
-1
@@ -345,7 +345,11 @@ class FirTypeIntersectionScope private constructor(
|
||||
newModality: Modality?,
|
||||
newVisibility: Visibility,
|
||||
): FirPropertySymbol {
|
||||
val newSymbol = FirIntersectionOverridePropertySymbol(mostSpecific.callableId, overrides)
|
||||
val callableId = CallableId(
|
||||
dispatchReceiverType.classId ?: mostSpecific.dispatchReceiverClassOrNull()?.classId!!,
|
||||
mostSpecific.fir.name
|
||||
)
|
||||
val newSymbol = FirIntersectionOverridePropertySymbol(callableId, overrides)
|
||||
val mostSpecificProperty = mostSpecific.fir
|
||||
FirFakeOverrideGenerator.createCopyForFirProperty(
|
||||
newSymbol, mostSpecificProperty, session, FirDeclarationOrigin.IntersectionOverride,
|
||||
|
||||
Reference in New Issue
Block a user