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 INFERENCE_ERROR by error<FirSourceElement, PsiElement>()
|
||||||
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error<FirSourceElement, PsiElement>()
|
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error<FirSourceElement, PsiElement>()
|
||||||
val UPPER_BOUND_VIOLATED by error<FirSourceElement, PsiElement> {
|
val UPPER_BOUND_VIOLATED by error<FirSourceElement, PsiElement> {
|
||||||
parameter<FirTypeParameterSymbol>("typeParameter")
|
parameter<ConeKotlinType>("upperBound")
|
||||||
parameter<ConeKotlinType>("violatedType")
|
|
||||||
}
|
}
|
||||||
val TYPE_ARGUMENTS_NOT_ALLOWED by error<FirSourceElement, PsiElement>()
|
val TYPE_ARGUMENTS_NOT_ALLOWED by error<FirSourceElement, PsiElement>()
|
||||||
val WRONG_NUMBER_OF_TYPE_ARGUMENTS 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 RECURSION_IN_IMPLICIT_TYPES by error0<FirSourceElement, PsiElement>()
|
||||||
val INFERENCE_ERROR by error0<FirSourceElement, PsiElement>()
|
val INFERENCE_ERROR by error0<FirSourceElement, PsiElement>()
|
||||||
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT 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 TYPE_ARGUMENTS_NOT_ALLOWED by error0<FirSourceElement, PsiElement>()
|
||||||
val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error2<FirSourceElement, PsiElement, Int, FirClassLikeSymbol<*>>()
|
val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error2<FirSourceElement, PsiElement, Int, FirClassLikeSymbol<*>>()
|
||||||
val NO_TYPE_ARGUMENTS_ON_RHS 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
|
return@forEach
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!satisfiesBounds(proto, actual.coneType, substitutor, context.session.typeContext)) {
|
val upperBound = getSubstitutedUpperBound(proto, substitutor, context.session.typeContext)
|
||||||
reporter.reportOn(actual.source, proto, actual.coneType, context)
|
if (upperBound != null && !satisfiesBounds(upperBound, actual.coneType, context.session.typeContext)) {
|
||||||
|
reporter.reportOn(actual.source, upperBound, context)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +165,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
|
|||||||
val satisfiesBounds = AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, intersection)
|
val satisfiesBounds = AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, intersection)
|
||||||
|
|
||||||
if (!satisfiesBounds) {
|
if (!satisfiesBounds) {
|
||||||
reporter.reportOn(functionCall.source, proto, actual, context)
|
reporter.reportOn(functionCall.source, intersection, context)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,9 +213,10 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
parameterPairs.forEach { (proto, actual) ->
|
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!
|
// should report on the parameter instead!
|
||||||
reporter.reportOn(reportTarget, proto, actual, context)
|
reporter.reportOn(reportTarget, upperBound, context)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,25 +235,30 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
|
|||||||
* bounds of the prototypeSymbol.
|
* bounds of the prototypeSymbol.
|
||||||
*/
|
*/
|
||||||
private fun satisfiesBounds(
|
private fun satisfiesBounds(
|
||||||
prototypeSymbol: FirTypeParameterSymbol,
|
upperBound: ConeKotlinType,
|
||||||
target: ConeKotlinType,
|
target: ConeKotlinType,
|
||||||
substitutor: ConeSubstitutor,
|
|
||||||
typeSystemContext: ConeTypeContext
|
typeSystemContext: ConeTypeContext
|
||||||
): Boolean {
|
): Boolean {
|
||||||
var intersection = typeSystemContext.intersectTypes(
|
return AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, upperBound, stubTypesEqualToAnything = false)
|
||||||
prototypeSymbol.fir.bounds.map { it.coneType }
|
}
|
||||||
).safeAs<ConeKotlinType>() ?: return true
|
|
||||||
|
|
||||||
intersection = substitutor.substituteOrSelf(intersection)
|
private fun getSubstitutedUpperBound(
|
||||||
return AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, intersection, stubTypesEqualToAnything = false)
|
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(
|
private fun DiagnosticReporter.reportOn(
|
||||||
source: FirSourceElement?,
|
source: FirSourceElement?,
|
||||||
proto: FirTypeParameterSymbol,
|
|
||||||
actual: ConeKotlinType,
|
actual: ConeKotlinType,
|
||||||
context: CheckerContext
|
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(RECURSION_IN_IMPLICIT_TYPES, "Recursion in implicit types")
|
||||||
map.put(INFERENCE_ERROR, "Inference error")
|
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(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(TYPE_ARGUMENTS_NOT_ALLOWED, "Type arguments are not allowed for type parameters") // *
|
||||||
map.put(
|
map.put(
|
||||||
WRONG_NUMBER_OF_TYPE_ARGUMENTS,
|
WRONG_NUMBER_OF_TYPE_ARGUMENTS,
|
||||||
|
|||||||
+1
-2
@@ -772,8 +772,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
}
|
}
|
||||||
add(FirErrors.UPPER_BOUND_VIOLATED) { firDiagnostic ->
|
add(FirErrors.UPPER_BOUND_VIOLATED) { firDiagnostic ->
|
||||||
UpperBoundViolatedImpl(
|
UpperBoundViolatedImpl(
|
||||||
firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol(firDiagnostic.a.fir),
|
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
|
|
||||||
firDiagnostic as FirPsiDiagnostic<*>,
|
firDiagnostic as FirPsiDiagnostic<*>,
|
||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-2
@@ -553,8 +553,7 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
|
|
||||||
abstract class UpperBoundViolated : KtFirDiagnostic<PsiElement>() {
|
abstract class UpperBoundViolated : KtFirDiagnostic<PsiElement>() {
|
||||||
override val diagnosticClass get() = UpperBoundViolated::class
|
override val diagnosticClass get() = UpperBoundViolated::class
|
||||||
abstract val typeParameter: KtTypeParameterSymbol
|
abstract val upperBound: KtType
|
||||||
abstract val violatedType: KtType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class TypeArgumentsNotAllowed : KtFirDiagnostic<PsiElement>() {
|
abstract class TypeArgumentsNotAllowed : KtFirDiagnostic<PsiElement>() {
|
||||||
|
|||||||
+1
-2
@@ -883,8 +883,7 @@ internal class ProjectionOnNonClassTypeArgumentImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class UpperBoundViolatedImpl(
|
internal class UpperBoundViolatedImpl(
|
||||||
override val typeParameter: KtTypeParameterSymbol,
|
override val upperBound: KtType,
|
||||||
override val violatedType: KtType,
|
|
||||||
firDiagnostic: FirPsiDiagnostic<*>,
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
) : KtFirDiagnostic.UpperBoundViolated(), KtAbstractFirDiagnostic<PsiElement> {
|
) : KtFirDiagnostic.UpperBoundViolated(), KtAbstractFirDiagnostic<PsiElement> {
|
||||||
|
|||||||
Vendored
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
class Pair<A, B>
|
class Pair<A, B>
|
||||||
|
|
||||||
abstract class C<T : B<Int>, X : (B<Char>) -> Pair<B<Any>, B<A>>>() : B<Any>() { // 2 errors
|
abstract class C<T : B<Int>, X : (B<Char>) -> Pair<B<Any>, B<A>>>() : B<Any>() { // 2 errors
|
||||||
val a = B<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol@1f33f4d4'">Char</error>>() // error
|
val a = B<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'A'">Char</error>>() // error
|
||||||
|
|
||||||
abstract val x : (B<Char>) -> B<Any>
|
abstract val x : (B<Char>) -> B<Any>
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
fun test() {
|
fun test() {
|
||||||
foo<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol@23ae790a'">Int?</error>>()
|
foo<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'kotlin/Any'">Int?</error>>()
|
||||||
foo<Int>()
|
foo<Int>()
|
||||||
bar<Int?>()
|
bar<Int?>()
|
||||||
bar<Int>()
|
bar<Int>()
|
||||||
bar<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol@ca50b2f'">Double?</error>>()
|
bar<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'kotlin/Int?'">Double?</error>>()
|
||||||
bar<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol@ca50b2f'">Double</error>>()
|
bar<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'kotlin/Int?'">Double</error>>()
|
||||||
1.<error descr="[INAPPLICABLE_CANDIDATE] Inapplicable candidate(s): /buzz">buzz</error><Double>()
|
1.<error descr="[INAPPLICABLE_CANDIDATE] Inapplicable candidate(s): /buzz">buzz</error><Double>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -6,10 +6,10 @@
|
|||||||
class C : A<C>()
|
class C : A<C>()
|
||||||
|
|
||||||
val a = B<C>()
|
val a = B<C>()
|
||||||
val a1 = B<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol@29263cc3'">Int</error>>()
|
val a1 = B<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'A<kotlin/Int>'">Int</error>>()
|
||||||
|
|
||||||
class X<A, B : A>()
|
class X<A, B : A>()
|
||||||
|
|
||||||
val b = X<Any, X<A<C>, C>>()
|
val b = X<Any, X<A<C>, C>>()
|
||||||
val b0 = X<Any, <error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol@2826285f'">Any?</error>>()
|
val b0 = X<Any, <error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'kotlin/Any'">Any?</error>>()
|
||||||
val b1 = X<Any, <error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol@2826285f'">X<A<C>, String></error>>()
|
val b1 = X<Any, <error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'A<C>'">X<A<C>, String></error>>()
|
||||||
|
|||||||
+2
-2
@@ -30,8 +30,8 @@ class Test1<T>()
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
Test1<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol@4c663d20'">B</error>>()
|
Test1<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'it(Jet87/A & Jet87/B)'">B</error>>()
|
||||||
Test1<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol@4c663d20'">A</error>>()
|
Test1<<error descr="[UPPER_BOUND_VIOLATED] Type argument is not within its bounds: should be subtype of 'it(Jet87/A & Jet87/B)'">A</error>>()
|
||||||
Test1<C>()
|
Test1<C>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user