From a09b836334faa3d7b178a5dca718fd60e6a5d6ae Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Tue, 30 Mar 2021 15:24:16 +0300 Subject: [PATCH] [FIR] Add new ARGUMENT_TYPE_MISMATCH diagnostics and related classes, throw it in corresponding cases --- .../diagnostics/FirDiagnosticsList.kt | 5 +++ .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../diagnostics/FirDefaultErrorMessages.kt | 3 ++ .../coneDiagnosticToFirDiagnostic.kt | 5 +++ .../kotlin/fir/resolve/calls/Arguments.kt | 33 ++++++++++++------- .../fir/resolve/calls/ResolutionDiagnostic.kt | 2 +- .../fir/resolve/calls/ResolutionStages.kt | 7 ++-- .../fir/resolve/diagnostics/FirDiagnostics.kt | 7 ++++ .../diagnostics/KtFirDataClassConverters.kt | 8 +++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 6 ++++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 9 +++++ 11 files changed, 70 insertions(+), 16 deletions(-) diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 2d316ad4403..db93536ccd6 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -216,6 +216,11 @@ object DIAGNOSTICS_LIST : DiagnosticList() { parameter>("candidate") } + val ARGUMENT_TYPE_MISMATCH by error { + parameter("expectedType") + parameter("actualType") + } + val INAPPLICABLE_LATEINIT_MODIFIER by error(PositioningStrategy.LATEINIT_MODIFIER) { parameter("reason") } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 6b02d38c8f5..d19827ce419 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -187,6 +187,7 @@ object FirErrors { // Applicability val NONE_APPLICABLE by error1>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val INAPPLICABLE_CANDIDATE by error1>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) + val ARGUMENT_TYPE_MISMATCH by error2() val INAPPLICABLE_LATEINIT_MODIFIER by error1(SourceElementPositioningStrategies.LATEINIT_MODIFIER) val VARARG_OUTSIDE_PARENTHESES by error0() val NAMED_ARGUMENTS_NOT_ALLOWED by error1(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 44177fe9744..34763f77b66 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -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) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index 0be28b11cee..004f305faff 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -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) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index ae1fb7d8373..6c82221fb0c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -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() ?: 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 + ) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt index cf2296ab974..274598ee84f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt @@ -91,4 +91,4 @@ class ArgumentTypeMismatch( val expectedType: ConeKotlinType, val actualType: ConeKotlinType, val argument: FirExpression -) : ResolutionDiagnostic(MAY_THROW_RUNTIME_ERROR) +) : ResolutionDiagnostic(INAPPLICABLE) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt index 661cf478097..327cfb992a4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt @@ -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) } } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt index fcd0ae809dd..6489e299c81 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt @@ -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>) : ConeDiagnostic() { override val reason: String get() = "Ambiguity: $name, ${candidates.map { describeSymbol(it) }}" } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index f1d6be22a54..e837d2872e3 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -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, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index dbdb8953e22..1f9ce10744b 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -510,6 +510,12 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val candidate: KtSymbol } + abstract class ArgumentTypeMismatch : KtFirDiagnostic() { + override val diagnosticClass get() = ArgumentTypeMismatch::class + abstract val expectedType: KtType + abstract val actualType: KtType + } + abstract class InapplicableLateinitModifier : KtFirDiagnostic() { override val diagnosticClass get() = InapplicableLateinitModifier::class abstract val reason: String diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 9edc330ed87..8e52491ee4c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -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 { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class InapplicableLateinitModifierImpl( override val reason: String, firDiagnostic: FirPsiDiagnostic<*>,