[FIR] Report ARGUMENT_TYPE_MISMATCH for nested array literals
^KT-61843 Fixed
This commit is contained in:
committed by
Space Team
parent
aecf05c4ac
commit
2be9a341ca
@@ -573,33 +573,48 @@ class FirCallResolver(
|
|||||||
// We want to "desugar" array literal arguments to arrayOf, intArrayOf, floatArrayOf and other *arrayOf* calls
|
// We want to "desugar" array literal arguments to arrayOf, intArrayOf, floatArrayOf and other *arrayOf* calls
|
||||||
// so that we can properly complete them eventually.
|
// so that we can properly complete them eventually.
|
||||||
// In order to find out what the expected type is, we need to run argument mapping.
|
// In order to find out what the expected type is, we need to run argument mapping.
|
||||||
|
// Array literals can be nested despite the fact they are not supported in annotation arguments.
|
||||||
|
// But we should traverse them all recursively to report type mismatches.
|
||||||
|
// For nested array literal, we need a new expected type obtained from the previous expected type (extract type of array element).
|
||||||
// We don't want to force full completion before the whole call is completed so that type variables are preserved.
|
// We don't want to force full completion before the whole call is completed so that type variables are preserved.
|
||||||
// But we need to pass expectType to figure out the correct *arrayOf* function (because Array<T> and primitive arrays can't be matched).
|
// But we need to pass expectType to figure out the correct *arrayOf* function (because Array<T> and primitive arrays can't be matched).
|
||||||
val mapping = transformer.resolutionContext.bodyResolveComponents.mapArguments(
|
val mapping = transformer.resolutionContext.bodyResolveComponents.mapArguments(
|
||||||
annotation.arguments, constructorSymbol.fir, originScope = null, callSiteIsOperatorCall = false,
|
annotation.arguments, constructorSymbol.fir, originScope = null, callSiteIsOperatorCall = false,
|
||||||
)
|
)
|
||||||
val argumentsToParameters = mapping.toArgumentToParameterMapping()
|
val argumentsToParameters = mapping.toArgumentToParameterMapping()
|
||||||
annotation.replaceArgumentList(buildArgumentList {
|
|
||||||
source = annotation.argumentList.source
|
|
||||||
annotation.arguments.mapTo(arguments) { arg ->
|
|
||||||
val resolutionMode = if (arg.unwrapArgument() is FirArrayLiteral) {
|
|
||||||
(argumentsToParameters[arg]?.returnTypeRef as? FirResolvedTypeRef)?.let {
|
|
||||||
// Enabling expectedTypeMismatchIsReportedInChecker clarifies error messages:
|
|
||||||
// It will be reported single ARGUMENT_TYPE_MISMATCH on the array literal in checkApplicabilityForArgumentType
|
|
||||||
// instead of several TYPE_MISMATCH for every mismatched argument.
|
|
||||||
ResolutionMode.WithExpectedType(
|
|
||||||
it,
|
|
||||||
forceFullCompletion = false,
|
|
||||||
expectedTypeMismatchIsReportedInChecker = true
|
|
||||||
)
|
|
||||||
} ?: ResolutionMode.ContextDependent.Default
|
|
||||||
} else {
|
|
||||||
ResolutionMode.ContextDependent
|
|
||||||
}
|
|
||||||
|
|
||||||
arg.transformSingle(transformer, resolutionMode)
|
fun FirCall.transformArgumentList(getExpectedType: (FirExpression) -> FirTypeRef?) {
|
||||||
}
|
replaceArgumentList(
|
||||||
})
|
buildArgumentList {
|
||||||
|
source = argumentList.source
|
||||||
|
argumentList.arguments.mapTo(arguments) { arg ->
|
||||||
|
val unwrappedArgument = arg.unwrapArgument()
|
||||||
|
val expectedType = getExpectedType(arg)
|
||||||
|
val resolutionMode = if (unwrappedArgument is FirArrayLiteral && expectedType is FirResolvedTypeRef) {
|
||||||
|
unwrappedArgument.transformArgumentList {
|
||||||
|
// Trying to extract expected type for the next nested array literal
|
||||||
|
expectedType.coneType.arrayElementType()?.toFirResolvedTypeRef()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enabling expectedTypeMismatchIsReportedInChecker clarifies error messages:
|
||||||
|
// It will be reported single ARGUMENT_TYPE_MISMATCH on the array literal in checkApplicabilityForArgumentType
|
||||||
|
// instead of several TYPE_MISMATCH for every mismatched argument.
|
||||||
|
ResolutionMode.WithExpectedType(
|
||||||
|
expectedType,
|
||||||
|
forceFullCompletion = false,
|
||||||
|
expectedTypeMismatchIsReportedInChecker = true
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ResolutionMode.ContextDependent
|
||||||
|
}
|
||||||
|
|
||||||
|
return@mapTo arg.transformSingle(transformer, resolutionMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
annotation.transformArgumentList { argumentsToParameters[it]?.returnTypeRef }
|
||||||
} else {
|
} else {
|
||||||
annotation.replaceArgumentList(annotation.argumentList.transform(transformer, ResolutionMode.ContextDependent.Default))
|
annotation.replaceArgumentList(annotation.argumentList.transform(transformer, ResolutionMode.ContextDependent.Default))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ fun Candidate.resolvePlainExpressionArgument(
|
|||||||
|
|
||||||
if (expectedType == null) return
|
if (expectedType == null) return
|
||||||
|
|
||||||
// TODO Remove when KT-61843 is fixed
|
// TODO: this check should be eliminated, KT-65085
|
||||||
if (argument is FirArrayLiteral && !argument.isResolved) return
|
if (argument is FirArrayLiteral && !argument.isResolved) return
|
||||||
|
|
||||||
val argumentType = argument.resolvedType
|
val argumentType = argument.resolvedType
|
||||||
|
|||||||
+4
-1
@@ -1,9 +1,12 @@
|
|||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
annotation class Anno(vararg val x: String, val y: String)
|
annotation class Anno(vararg val x: String, val y: String)
|
||||||
|
|
||||||
@Anno(x = [["a", "b"], ["a", "b"]], y = "a")
|
@Anno(x = <!ARGUMENT_TYPE_MISMATCH!>[["a", "b"], ["a", "b"]]<!>, y = "a")
|
||||||
fun foo1() {}
|
fun foo1() {}
|
||||||
|
|
||||||
|
@Anno(x = <!ARGUMENT_TYPE_MISMATCH!>[[<!UNSUPPORTED!>["a"]<!>]]<!>, y = "b")
|
||||||
|
fun foo11() {}
|
||||||
|
|
||||||
@Anno(x = ["a", "b"], y = "a")
|
@Anno(x = ["a", "b"], y = "a")
|
||||||
fun foo2() {}
|
fun foo2() {}
|
||||||
|
|
||||||
|
|||||||
+3
@@ -4,6 +4,9 @@ annotation class Anno(vararg val x: String, val y: String)
|
|||||||
@Anno(x = [<!TYPE_MISMATCH, TYPE_MISMATCH!>["a", "b"]<!>, <!TYPE_MISMATCH, TYPE_MISMATCH!>["a", "b"]<!>], y = "a")
|
@Anno(x = [<!TYPE_MISMATCH, TYPE_MISMATCH!>["a", "b"]<!>, <!TYPE_MISMATCH, TYPE_MISMATCH!>["a", "b"]<!>], y = "a")
|
||||||
fun foo1() {}
|
fun foo1() {}
|
||||||
|
|
||||||
|
@Anno(x = [<!TYPE_MISMATCH, TYPE_MISMATCH!>[["a"]]<!>], y = "b")
|
||||||
|
fun foo11() {}
|
||||||
|
|
||||||
@Anno(x = ["a", "b"], y = "a")
|
@Anno(x = ["a", "b"], y = "a")
|
||||||
fun foo2() {}
|
fun foo2() {}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -1,6 +1,7 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
@Anno(x = {{"a", "b"}, {"a", "b"}}, y = "a") public fun foo1(): kotlin.Unit
|
@Anno(x = {{"a", "b"}, {"a", "b"}}, y = "a") public fun foo1(): kotlin.Unit
|
||||||
|
@Anno(x = {{{"a"}}}, y = "b") public fun foo11(): kotlin.Unit
|
||||||
@Anno(x = {"a", "b"}, y = "a") public fun foo2(): kotlin.Unit
|
@Anno(x = {"a", "b"}, y = "a") public fun foo2(): kotlin.Unit
|
||||||
@Anno(x = {{"a"}, {"b"}}, y = "a") public fun foo3(): kotlin.Unit
|
@Anno(x = {{"a"}, {"b"}}, y = "a") public fun foo3(): kotlin.Unit
|
||||||
@Anno(x = {"a", "b"}, y = "a") public fun foo4(): kotlin.Unit
|
@Anno(x = {"a", "b"}, y = "a") public fun foo4(): kotlin.Unit
|
||||||
|
|||||||
Reference in New Issue
Block a user