FIR checker: fix UPPER_BOUND_VIOLATED
The diagnostics accepts one parameter for the expected upper bound for the type parameter.
This commit is contained in:
committed by
Dmitriy Novozhilov
parent
bd64237519
commit
d7cae63cb0
+1
-2
@@ -253,8 +253,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val INFERENCE_ERROR by error<FirSourceElement, PsiElement>()
|
||||
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error<FirSourceElement, PsiElement>()
|
||||
val UPPER_BOUND_VIOLATED by error<FirSourceElement, PsiElement> {
|
||||
parameter<FirTypeParameterSymbol>("typeParameter")
|
||||
parameter<ConeKotlinType>("violatedType")
|
||||
parameter<ConeKotlinType>("upperBound")
|
||||
}
|
||||
val TYPE_ARGUMENTS_NOT_ALLOWED by error<FirSourceElement, PsiElement>()
|
||||
val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error<FirSourceElement, PsiElement> {
|
||||
|
||||
+1
-1
@@ -197,7 +197,7 @@ object FirErrors {
|
||||
val RECURSION_IN_IMPLICIT_TYPES by error0<FirSourceElement, PsiElement>()
|
||||
val INFERENCE_ERROR by error0<FirSourceElement, PsiElement>()
|
||||
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error0<FirSourceElement, PsiElement>()
|
||||
val UPPER_BOUND_VIOLATED by error2<FirSourceElement, PsiElement, FirTypeParameterSymbol, ConeKotlinType>()
|
||||
val UPPER_BOUND_VIOLATED by error1<FirSourceElement, PsiElement, ConeKotlinType>()
|
||||
val TYPE_ARGUMENTS_NOT_ALLOWED by error0<FirSourceElement, PsiElement>()
|
||||
val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error2<FirSourceElement, PsiElement, Int, FirClassLikeSymbol<*>>()
|
||||
val NO_TYPE_ARGUMENTS_ON_RHS by error2<FirSourceElement, PsiElement, Int, FirClassLikeSymbol<*>>()
|
||||
|
||||
+21
-14
@@ -68,8 +68,9 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
if (!satisfiesBounds(proto, actual.coneType, substitutor, context.session.typeContext)) {
|
||||
reporter.reportOn(actual.source, proto, actual.coneType, context)
|
||||
val upperBound = getSubstitutedUpperBound(proto, substitutor, context.session.typeContext)
|
||||
if (upperBound != null && !satisfiesBounds(upperBound, actual.coneType, context.session.typeContext)) {
|
||||
reporter.reportOn(actual.source, upperBound, context)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -164,7 +165,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
|
||||
val satisfiesBounds = AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, intersection)
|
||||
|
||||
if (!satisfiesBounds) {
|
||||
reporter.reportOn(functionCall.source, proto, actual, context)
|
||||
reporter.reportOn(functionCall.source, intersection, context)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -212,9 +213,10 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
|
||||
)
|
||||
|
||||
parameterPairs.forEach { (proto, actual) ->
|
||||
if (!satisfiesBounds(proto, actual.type, substitutor, typeSystemContext)) {
|
||||
val upperBound = getSubstitutedUpperBound(proto, substitutor, typeSystemContext)
|
||||
if (upperBound != null && !satisfiesBounds(upperBound, actual.type, typeSystemContext)) {
|
||||
// should report on the parameter instead!
|
||||
reporter.reportOn(reportTarget, proto, actual, context)
|
||||
reporter.reportOn(reportTarget, upperBound, context)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -233,25 +235,30 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
|
||||
* bounds of the prototypeSymbol.
|
||||
*/
|
||||
private fun satisfiesBounds(
|
||||
prototypeSymbol: FirTypeParameterSymbol,
|
||||
upperBound: ConeKotlinType,
|
||||
target: ConeKotlinType,
|
||||
substitutor: ConeSubstitutor,
|
||||
typeSystemContext: ConeTypeContext
|
||||
): Boolean {
|
||||
var intersection = typeSystemContext.intersectTypes(
|
||||
prototypeSymbol.fir.bounds.map { it.coneType }
|
||||
).safeAs<ConeKotlinType>() ?: return true
|
||||
return AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, upperBound, stubTypesEqualToAnything = false)
|
||||
}
|
||||
|
||||
intersection = substitutor.substituteOrSelf(intersection)
|
||||
return AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, intersection, stubTypesEqualToAnything = false)
|
||||
private fun getSubstitutedUpperBound(
|
||||
prototypeSymbol: FirTypeParameterSymbol,
|
||||
substitutor: ConeSubstitutor,
|
||||
typeSystemContext: ConeTypeContext
|
||||
): ConeKotlinType? {
|
||||
val intersection = typeSystemContext.intersectTypes(
|
||||
prototypeSymbol.fir.bounds.map { it.coneType }
|
||||
).safeAs<ConeKotlinType>() ?: return null
|
||||
|
||||
return substitutor.substituteOrSelf(intersection)
|
||||
}
|
||||
|
||||
private fun DiagnosticReporter.reportOn(
|
||||
source: FirSourceElement?,
|
||||
proto: FirTypeParameterSymbol,
|
||||
actual: ConeKotlinType,
|
||||
context: CheckerContext
|
||||
) {
|
||||
reportOn(source, FirErrors.UPPER_BOUND_VIOLATED, proto, actual, context)
|
||||
reportOn(source, FirErrors.UPPER_BOUND_VIOLATED, actual, context)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -404,7 +404,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
map.put(RECURSION_IN_IMPLICIT_TYPES, "Recursion in implicit types")
|
||||
map.put(INFERENCE_ERROR, "Inference error")
|
||||
map.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties")
|
||||
map.put(UPPER_BOUND_VIOLATED, "Type argument is not within its bounds: should be subtype of ''{0}''", TO_STRING, TO_STRING)
|
||||
map.put(UPPER_BOUND_VIOLATED, "Type argument is not within its bounds: should be subtype of ''{0}''", RENDER_TYPE)
|
||||
map.put(TYPE_ARGUMENTS_NOT_ALLOWED, "Type arguments are not allowed for type parameters") // *
|
||||
map.put(
|
||||
WRONG_NUMBER_OF_TYPE_ARGUMENTS,
|
||||
|
||||
Reference in New Issue
Block a user