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:
Tianyu Geng
2021-03-29 17:23:37 -07:00
committed by Dmitriy Novozhilov
parent bd64237519
commit d7cae63cb0
11 changed files with 36 additions and 33 deletions
@@ -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> {
@@ -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<*>>()
@@ -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)
}
}
@@ -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,
@@ -772,8 +772,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
}
add(FirErrors.UPPER_BOUND_VIOLATED) { firDiagnostic ->
UpperBoundViolatedImpl(
firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol(firDiagnostic.a.fir),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
@@ -553,8 +553,7 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract class UpperBoundViolated : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = UpperBoundViolated::class
abstract val typeParameter: KtTypeParameterSymbol
abstract val violatedType: KtType
abstract val upperBound: KtType
}
abstract class TypeArgumentsNotAllowed : KtFirDiagnostic<PsiElement>() {
@@ -883,8 +883,7 @@ internal class ProjectionOnNonClassTypeArgumentImpl(
}
internal class UpperBoundViolatedImpl(
override val typeParameter: KtTypeParameterSymbol,
override val violatedType: KtType,
override val upperBound: KtType,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.UpperBoundViolated(), KtAbstractFirDiagnostic<PsiElement> {
+1 -1
View File
@@ -4,7 +4,7 @@
class Pair<A, B>
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>
}
+3 -3
View File
@@ -1,10 +1,10 @@
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>()
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 '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 'kotlin/Int?'">Double</error>>()
1.<error descr="[INAPPLICABLE_CANDIDATE] Inapplicable candidate(s): /buzz">buzz</error><Double>()
}
+3 -3
View File
@@ -6,10 +6,10 @@
class C : A<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>()
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 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 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 'A<C>'">X<A<C>, String></error>>()
+2 -2
View File
@@ -30,8 +30,8 @@ class Test1<T>()
}
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 '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)'">B</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>()
}