[FIR] Add new ARGUMENT_TYPE_MISMATCH diagnostics and related classes, throw it in corresponding cases

This commit is contained in:
Ivan Kochurkin
2021-03-30 15:24:16 +03:00
committed by TeamCityServer
parent 7e03f8ea80
commit a09b836334
11 changed files with 70 additions and 16 deletions
@@ -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)
@@ -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)
@@ -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
)
}
@@ -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)
}
}
}
@@ -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) }}"
}
@@ -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,
@@ -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
@@ -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<*>,