FIR: introduce separate THROWABLE_TYPE_MISMATCH

This commit is contained in:
Mikhail Glukhikh
2021-05-18 12:59:00 +03:00
parent f0ce311fc6
commit e85d97b894
10 changed files with 92 additions and 40 deletions
@@ -9,15 +9,15 @@ fun <T : Throwable> test() {
try {} catch (<!TYPE_PARAMETER_IN_CATCH_CLAUSE!>e: T<!>) {}
try {} catch (<!TYPE_MISMATCH!>e: () -> Int<!>) {}
try {} catch (<!THROWABLE_TYPE_MISMATCH!>e: () -> Int<!>) {}
try {} catch (<!TYPE_MISMATCH!>e: StringType<!>) {}
try {} catch (<!THROWABLE_TYPE_MISMATCH!>e: StringType<!>) {}
try {} catch (<!CATCH_PARAMETER_WITH_DEFAULT_VALUE, TYPE_MISMATCH!>e: Int = 5<!>) {}
try {} catch (<!CATCH_PARAMETER_WITH_DEFAULT_VALUE, THROWABLE_TYPE_MISMATCH!>e: Int = 5<!>) {}
try {} catch (e: Throwable) {}
}
inline fun <reified T> anotherTest() {
try {} catch (<!REIFIED_TYPE_IN_CATCH_CLAUSE, TYPE_MISMATCH!>e: T<!>) {}
try {} catch (<!REIFIED_TYPE_IN_CATCH_CLAUSE, THROWABLE_TYPE_MISMATCH!>e: T<!>) {}
}
@@ -242,6 +242,19 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
parameter<Symbol>("candidate")
}
val TYPE_MISMATCH by error<PsiElement> {
parameter<ConeKotlinType>("expectedType")
parameter<ConeKotlinType>("actualType")
}
val THROWABLE_TYPE_MISMATCH by error<PsiElement> {
parameter<ConeKotlinType>("actualType")
}
val CONDITION_TYPE_MISMATCH by error<PsiElement> {
parameter<ConeKotlinType>("actualType")
}
val ARGUMENT_TYPE_MISMATCH by error<PsiElement> {
parameter<ConeKotlinType>("expectedType")
parameter<ConeKotlinType>("actualType")
@@ -304,10 +317,6 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
}
val TYPES_AND_TYPE_PARAMETERS by object : DiagnosticGroup("Types & type parameters") {
val TYPE_MISMATCH by error<PsiElement> {
parameter<ConeKotlinType>("expectedType")
parameter<ConeKotlinType>("actualType")
}
val RECURSION_IN_IMPLICIT_TYPES by error<PsiElement>()
val INFERENCE_ERROR by error<PsiElement>()
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error<PsiElement>()
@@ -216,6 +216,9 @@ object FirErrors {
// Applicability
val NONE_APPLICABLE by error1<PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val INAPPLICABLE_CANDIDATE by error1<PsiElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val TYPE_MISMATCH by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
val THROWABLE_TYPE_MISMATCH by error1<PsiElement, ConeKotlinType>()
val CONDITION_TYPE_MISMATCH by error1<PsiElement, ConeKotlinType>()
val ARGUMENT_TYPE_MISMATCH by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
val NULL_FOR_NONNULL_TYPE by error0<PsiElement>()
val INAPPLICABLE_LATEINIT_MODIFIER by error1<KtModifierListOwner, String>(SourceElementPositioningStrategies.LATEINIT_MODIFIER)
@@ -238,7 +241,6 @@ object FirErrors {
val NEXT_AMBIGUITY by error1<PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
// Types & type parameters
val TYPE_MISMATCH by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
val RECURSION_IN_IMPLICIT_TYPES by error0<PsiElement>()
val INFERENCE_ERROR by error0<PsiElement>()
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error0<PsiElement>()
@@ -292,10 +292,8 @@ fun FirClass<*>.findNonInterfaceSupertype(context: CheckerContext): FirTypeRef?
val FirFunctionCall.isIterator
get() = this.calleeReference.name.asString() == "<iterator>"
internal fun throwableClassLikeType(session: FirSession) = session.builtinTypes.throwableType.type
fun ConeKotlinType.isSubtypeOfThrowable(session: FirSession) =
throwableClassLikeType(session).isSupertypeOf(session.typeContext, this.fullyExpandedType(session))
session.builtinTypes.throwableType.type.isSupertypeOf(session.typeContext, this.fullyExpandedType(session))
val FirValueParameter.hasValOrVar: Boolean
get() {
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeOfThrowable
import org.jetbrains.kotlin.fir.analysis.checkers.throwableClassLikeType
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
@@ -37,7 +36,7 @@ object FirCatchParameterChecker : FirTryExpressionChecker() {
val session = context.session
if (!coneType.isSubtypeOfThrowable(session)) {
reporter.reportOn(catchParameter.source, FirErrors.TYPE_MISMATCH, throwableClassLikeType(session), coneType, context)
reporter.reportOn(catchParameter.source, FirErrors.THROWABLE_TYPE_MISMATCH, coneType, context)
}
}
}
@@ -63,6 +63,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPONENT_FUNCTIO
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPONENT_FUNCTION_MISSING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPONENT_FUNCTION_ON_NULLABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONDITION_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_OVERLOADS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_PROJECTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_UPPER_BOUNDS
@@ -272,6 +273,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPER_CALL_FROM_P
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPER_IS_NOT_AN_EXPRESSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPER_NOT_AVAILABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SYNTAX
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.THROWABLE_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOO_MANY_ARGUMENTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOPLEVEL_TYPEALIASES_ONLY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED
@@ -524,6 +526,9 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(NAMED_PARAMETER_NOT_FOUND, "Cannot find a parameter with this name: {0}", TO_STRING)
map.put(MANY_LAMBDA_EXPRESSION_ARGUMENTS, "Only one lambda expression is allowed outside a parenthesized argument list")
map.put(TYPE_MISMATCH, "Type mismatch: inferred type is {1} but {0} was expected", TO_STRING, TO_STRING)
map.put(THROWABLE_TYPE_MISMATCH, "Throwable type mismatch: actual type is {0}", TO_STRING)
map.put(CONDITION_TYPE_MISMATCH, "Condition type mismatch: inferred type is {0} but Boolean was expected", TO_STRING)
map.put(ARGUMENT_TYPE_MISMATCH, "Argument type mismatch: actual type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE)
map.put(ASSIGNMENT_TYPE_MISMATCH, "Assignment type mismatch: actual type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE)
map.put(
@@ -541,7 +546,6 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(NEXT_AMBIGUITY, "Method ''next()'' is ambiguous for this expression: {0}", SYMBOLS)
// Types & type parameters
map.put(TYPE_MISMATCH, "Type mismatch: inferred type is {1} but {0} was expected", TO_STRING, TO_STRING)
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")
@@ -109,7 +109,7 @@ fun t7() : Int {
return 1
2
}
catch (<!TYPE_MISMATCH!>e : Any<!>) {
catch (<!THROWABLE_TYPE_MISMATCH!>e : Any<!>) {
2
}
return 1 // this is OK, like in Java
@@ -120,7 +120,7 @@ fun t8() : Int {
return 1
2
}
catch (<!TYPE_MISMATCH!>e : Any<!>) {
catch (<!THROWABLE_TYPE_MISMATCH!>e : Any<!>) {
return 1
2
}
@@ -841,6 +841,28 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.TYPE_MISMATCH) { firDiagnostic ->
TypeMismatchImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.THROWABLE_TYPE_MISMATCH) { firDiagnostic ->
ThrowableTypeMismatchImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.CONDITION_TYPE_MISMATCH) { firDiagnostic ->
ConditionTypeMismatchImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.ARGUMENT_TYPE_MISMATCH) { firDiagnostic ->
ArgumentTypeMismatchImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
@@ -975,14 +997,6 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.TYPE_MISMATCH) { firDiagnostic ->
TypeMismatchImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.RECURSION_IN_IMPLICIT_TYPES) { firDiagnostic ->
RecursionInImplicitTypesImpl(
firDiagnostic as FirPsiDiagnostic<*>,
@@ -602,6 +602,22 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val candidate: KtSymbol
}
abstract class TypeMismatch : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = TypeMismatch::class
abstract val expectedType: KtType
abstract val actualType: KtType
}
abstract class ThrowableTypeMismatch : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = ThrowableTypeMismatch::class
abstract val actualType: KtType
}
abstract class ConditionTypeMismatch : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = ConditionTypeMismatch::class
abstract val actualType: KtType
}
abstract class ArgumentTypeMismatch : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = ArgumentTypeMismatch::class
abstract val expectedType: KtType
@@ -690,12 +706,6 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val candidates: List<KtSymbol>
}
abstract class TypeMismatch : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = TypeMismatch::class
abstract val expectedType: KtType
abstract val actualType: KtType
}
abstract class RecursionInImplicitTypes : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = RecursionInImplicitTypes::class
}
@@ -969,6 +969,31 @@ internal class InapplicableCandidateImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class TypeMismatchImpl(
override val expectedType: KtType,
override val actualType: KtType,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.TypeMismatch(), KtAbstractFirDiagnostic<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ThrowableTypeMismatchImpl(
override val actualType: KtType,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.ThrowableTypeMismatch(), KtAbstractFirDiagnostic<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ConditionTypeMismatchImpl(
override val actualType: KtType,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.ConditionTypeMismatch(), KtAbstractFirDiagnostic<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ArgumentTypeMismatchImpl(
override val expectedType: KtType,
override val actualType: KtType,
@@ -1111,15 +1136,6 @@ internal class NextAmbiguityImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class TypeMismatchImpl(
override val expectedType: KtType,
override val actualType: KtType,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.TypeMismatch(), KtAbstractFirDiagnostic<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class RecursionInImplicitTypesImpl(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,