[FIR] Add new ARGUMENT_TYPE_MISMATCH diagnostics and related classes, throw it in corresponding cases
This commit is contained in:
committed by
TeamCityServer
parent
7e03f8ea80
commit
a09b836334
+5
@@ -216,6 +216,11 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
parameter<AbstractFirBasedSymbol<*>>("candidate")
|
||||
}
|
||||
|
||||
val ARGUMENT_TYPE_MISMATCH by error<FirSourceElement, PsiElement> {
|
||||
parameter<ConeKotlinType>("expectedType")
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
}
|
||||
|
||||
val INAPPLICABLE_LATEINIT_MODIFIER by error<FirSourceElement, KtModifierListOwner>(PositioningStrategy.LATEINIT_MODIFIER) {
|
||||
parameter<String>("reason")
|
||||
}
|
||||
|
||||
@@ -187,6 +187,7 @@ object FirErrors {
|
||||
// Applicability
|
||||
val NONE_APPLICABLE by error1<FirSourceElement, PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val INAPPLICABLE_CANDIDATE by error1<FirSourceElement, PsiElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val ARGUMENT_TYPE_MISMATCH by error2<FirSourceElement, PsiElement, ConeKotlinType, ConeKotlinType>()
|
||||
val INAPPLICABLE_LATEINIT_MODIFIER by error1<FirSourceElement, KtModifierListOwner, String>(SourceElementPositioningStrategies.LATEINIT_MODIFIER)
|
||||
val VARARG_OUTSIDE_PARENTHESES by error0<FirSourceElement, KtExpression>()
|
||||
val NAMED_ARGUMENTS_NOT_ALLOWED by error1<FirSourceElement, KtValueArgument, ForbiddenNamedArgumentsTarget>(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT)
|
||||
|
||||
+3
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_CLASS_
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ANONYMOUS_FUNCTION_PARAMETER_WITH_DEFAULT_VALUE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARGUMENT_PASSED_TWICE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARGUMENT_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNED_VALUE_IS_NEVER_READ
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGN_OPERATOR_AMBIGUITY
|
||||
@@ -413,6 +414,8 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
map.put(NO_VALUE_FOR_PARAMETER, "No value passed for parameter ''{0}''", NAME)
|
||||
map.put(NAMED_PARAMETER_NOT_FOUND, "Cannot find a parameter with this name: {0}", TO_STRING)
|
||||
|
||||
map.put(ARGUMENT_TYPE_MISMATCH, "Argument type mismatch: actual type is {1} but {0} was expected", TO_STRING, TO_STRING)
|
||||
|
||||
// Ambiguity
|
||||
map.put(OVERLOAD_RESOLUTION_AMBIGUITY, "Overload resolution ambiguity between candidates: {0}", SYMBOLS)
|
||||
map.put(ASSIGN_OPERATOR_AMBIGUITY, "Ambiguity between assign operator candidates: {0}", SYMBOLS)
|
||||
|
||||
+5
@@ -137,6 +137,11 @@ private fun mapInapplicableCandidateError(
|
||||
rootCause.argument.source,
|
||||
rootCause.forbiddenNamedArgumentsTarget
|
||||
)
|
||||
is ArgumentTypeMismatch -> FirErrors.ARGUMENT_TYPE_MISMATCH.on(
|
||||
rootCause.argument.source ?: source,
|
||||
rootCause.expectedType,
|
||||
rootCause.actualType
|
||||
)
|
||||
is NonVarargSpread -> FirErrors.NON_VARARG_SPREAD.on(rootCause.argument.source?.getChild(KtTokens.MUL, depth = 1)!!)
|
||||
is ArgumentPassedTwice -> FirErrors.ARGUMENT_PASSED_TWICE.on(rootCause.argument.source)
|
||||
is TooManyArguments -> FirErrors.TOO_MANY_ARGUMENTS.on(rootCause.argument.source ?: source, rootCause.function)
|
||||
|
||||
@@ -17,9 +17,11 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedTypeDeclaration
|
||||
import org.jetbrains.kotlin.fir.returnExpressions
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
@@ -217,6 +219,7 @@ fun Candidate.resolvePlainExpressionArgument(
|
||||
isDispatch: Boolean,
|
||||
useNullableArgumentType: Boolean = false
|
||||
) {
|
||||
|
||||
if (expectedType == null) return
|
||||
val argumentType = argument.typeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
||||
resolvePlainArgumentType(
|
||||
@@ -343,24 +346,32 @@ private fun checkApplicabilityForArgumentType(
|
||||
unstableType: ConeKotlinType?,
|
||||
actualExpectedType: ConeKotlinType,
|
||||
position: ConstraintPosition
|
||||
): ResolutionDiagnostic? {
|
||||
): ResolutionDiagnostic {
|
||||
if (unstableType != null) {
|
||||
if (csBuilder.addSubtypeConstraintIfCompatible(unstableType, actualExpectedType, position)) {
|
||||
return UnstableSmartCast.ResolutionError(argument, unstableType)
|
||||
}
|
||||
}
|
||||
if (argumentType.isMarkedNullable) {
|
||||
if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, actualExpectedType, position)) return null
|
||||
if (csBuilder.addSubtypeConstraintIfCompatible(
|
||||
argumentType.withNullability(ConeNullability.NOT_NULL),
|
||||
actualExpectedType,
|
||||
position
|
||||
)
|
||||
) return ArgumentTypeMismatch(actualExpectedType, argumentType, argument)
|
||||
|
||||
fun tryGetConeTypeThatCompatibleWithKtType(type: ConeKotlinType): ConeKotlinType {
|
||||
if (type is ConeTypeVariableType) {
|
||||
val originalTypeParameter =
|
||||
(type.lookupTag as? ConeTypeVariableTypeConstructor)?.originalTypeParameter as? ConeTypeParameterLookupTag
|
||||
|
||||
if (originalTypeParameter != null)
|
||||
return ConeTypeParameterTypeImpl(originalTypeParameter, type.isNullable, type.attributes)
|
||||
} else if (type is ConeIntegerLiteralType) {
|
||||
return type.possibleTypes.firstOrNull() ?: type
|
||||
}
|
||||
|
||||
return type
|
||||
}
|
||||
|
||||
csBuilder.addSubtypeConstraint(argumentType, actualExpectedType, position)
|
||||
return null
|
||||
return ArgumentTypeMismatch(
|
||||
tryGetConeTypeThatCompatibleWithKtType(actualExpectedType),
|
||||
tryGetConeTypeThatCompatibleWithKtType(argumentType),
|
||||
argument
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -91,4 +91,4 @@ class ArgumentTypeMismatch(
|
||||
val expectedType: ConeKotlinType,
|
||||
val actualType: ConeKotlinType,
|
||||
val argument: FirExpression
|
||||
) : ResolutionDiagnostic(MAY_THROW_RUNTIME_ERROR)
|
||||
) : ResolutionDiagnostic(INAPPLICABLE)
|
||||
|
||||
@@ -151,10 +151,9 @@ internal object CheckArguments : CheckerStage() {
|
||||
sink = sink,
|
||||
context = context
|
||||
)
|
||||
if (candidate.system.hasContradiction) {
|
||||
sink.yieldDiagnostic(InapplicableCandidate)
|
||||
}
|
||||
sink.yieldIfNeed()
|
||||
}
|
||||
if (candidate.system.hasContradiction && callInfo.arguments.isNotEmpty()) {
|
||||
sink.yieldDiagnostic(InapplicableCandidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -48,6 +48,13 @@ class ConeInapplicableCandidateError(
|
||||
override val reason: String get() = "Inapplicable($applicability): ${describeSymbol(candidate.symbol)}"
|
||||
}
|
||||
|
||||
class ConeArgumentTypeMismatchCandidateError(
|
||||
val expectedType: ConeKotlinType, val actualType: ConeKotlinType
|
||||
) : ConeDiagnostic() {
|
||||
override val reason: String
|
||||
get() = "Type mismatch. Expected: $expectedType, Actual: $actualType"
|
||||
}
|
||||
|
||||
class ConeAmbiguityError(val name: Name, val applicability: CandidateApplicability, val candidates: Collection<AbstractFirBasedSymbol<*>>) : ConeDiagnostic() {
|
||||
override val reason: String get() = "Ambiguity: $name, ${candidates.map { describeSymbol(it) }}"
|
||||
}
|
||||
|
||||
+8
@@ -706,6 +706,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.ARGUMENT_TYPE_MISMATCH) { firDiagnostic ->
|
||||
ArgumentTypeMismatchImpl(
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.INAPPLICABLE_LATEINIT_MODIFIER) { firDiagnostic ->
|
||||
InapplicableLateinitModifierImpl(
|
||||
firDiagnostic.a,
|
||||
|
||||
+6
@@ -510,6 +510,12 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val candidate: KtSymbol
|
||||
}
|
||||
|
||||
abstract class ArgumentTypeMismatch : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = ArgumentTypeMismatch::class
|
||||
abstract val expectedType: KtType
|
||||
abstract val actualType: KtType
|
||||
}
|
||||
|
||||
abstract class InapplicableLateinitModifier : KtFirDiagnostic<KtModifierListOwner>() {
|
||||
override val diagnosticClass get() = InapplicableLateinitModifier::class
|
||||
abstract val reason: String
|
||||
|
||||
+9
@@ -814,6 +814,15 @@ internal class InapplicableCandidateImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ArgumentTypeMismatchImpl(
|
||||
override val expectedType: KtType,
|
||||
override val actualType: KtType,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ArgumentTypeMismatch(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class InapplicableLateinitModifierImpl(
|
||||
override val reason: String,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
|
||||
Reference in New Issue
Block a user