[FIR] Implement MANY_LAMBDA_EXPRESSION_ARGUMENTS diagnostics, fix tests

This commit is contained in:
Ivan Kochurkin
2021-04-27 19:51:01 +03:00
committed by TeamCityServer
parent b8002cb54f
commit 525cc6df97
12 changed files with 68 additions and 26 deletions
@@ -255,6 +255,8 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val NAMED_PARAMETER_NOT_FOUND by error<KtValueArgument>(PositioningStrategy.NAME_OF_NAMED_ARGUMENT) {
parameter<String>("name")
}
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error<KtValueArgument>()
}
val AMBIGUITY by object : DiagnosticGroup("Ambiguity") {
@@ -212,6 +212,7 @@ object FirErrors {
val TOO_MANY_ARGUMENTS by error1<PsiElement, FirCallableDeclaration<*>>()
val NO_VALUE_FOR_PARAMETER by error1<KtElement, FirValueParameter>(SourceElementPositioningStrategies.VALUE_ARGUMENTS)
val NAMED_PARAMETER_NOT_FOUND by error1<KtValueArgument, String>(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT)
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>()
// Ambiguity
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -155,6 +155,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_OBJECT_NOT_
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_COMPANION_OBJECTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MANY_LAMBDA_EXPRESSION_ARGUMENTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISPLACED_TYPE_PARAMETER_CONSTRAINTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER
@@ -461,6 +462,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(ARGUMENT_PASSED_TWICE, "An argument is already passed for this parameter")
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(MANY_LAMBDA_EXPRESSION_ARGUMENTS, "Only one lambda expression is allowed outside a parenthesized argument list")
map.put(ARGUMENT_TYPE_MISMATCH, "Argument type mismatch: actual type is {1} but {0} was expected", TO_STRING, TO_STRING)
@@ -142,6 +142,7 @@ private fun mapInapplicableCandidateError(
rootCause.argument.name.asString()
)
is UnsafeCall -> mapUnsafeCallError(diagnostic.candidate, rootCause, source, qualifiedAccessSource)
is ManyLambdaExpressionArguments -> FirErrors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(rootCause.argument.source ?: source)
else -> null
}
}.ifEmpty { listOf(FirErrors.INAPPLICABLE_CANDIDATE.on(source, diagnostic.candidate.symbol)) }
@@ -61,11 +61,20 @@ fun BodyResolveComponents.mapArguments(
if (arguments.isEmpty() && function.valueParameters.isEmpty()) {
return EmptyArgumentMapping
}
val externalArgument: FirExpression? = arguments.lastOrNull { it is FirLambdaArgumentExpression }
var argumentsInParenthesis: List<FirExpression> = if (externalArgument == null) {
arguments
} else {
arguments.subList(0, arguments.size - 1)
val argumentsInParenthesis: MutableList<FirExpression> = mutableListOf()
val excessLambdaArguments: MutableList<FirExpression> = mutableListOf()
var externalArgument: FirExpression? = null
for (argument in arguments) {
if (argument is FirLambdaArgumentExpression) {
if (externalArgument == null) {
externalArgument = argument
} else {
excessLambdaArguments.add(argument)
}
} else {
argumentsInParenthesis.add(argument)
}
}
// If this is an overloading indexed access operator, it could have default values or a vararg parameter in the middle.
@@ -82,7 +91,8 @@ fun BodyResolveComponents.mapArguments(
isSpread = false
name = function.valueParameters.last().name
}
argumentsInParenthesis = argumentsInParenthesis.dropLast(1) + listOf(namedV)
argumentsInParenthesis.removeAt(argumentsInParenthesis.size - 1)
argumentsInParenthesis.add(namedV)
}
}
@@ -91,6 +101,7 @@ fun BodyResolveComponents.mapArguments(
if (externalArgument != null) {
processor.processExternalArgument(externalArgument)
}
processor.processExcessLambdaArguments(excessLambdaArguments)
processor.processDefaultsAndRunChecks()
return ArgumentMapping(processor.result, processor.diagnostics ?: emptyList())
@@ -212,6 +223,10 @@ private class FirCallArgumentsProcessor(
result[lastParameter] = ResolvedCallArgument.SimpleArgument(externalArgument)
}
fun processExcessLambdaArguments(excessLambdaArguments: List<FirExpression>) {
excessLambdaArguments.forEach { arg -> addDiagnostic(ManyLambdaExpressionArguments(arg)) }
}
fun processDefaultsAndRunChecks() {
for ((parameter, resolvedArgument) in result) {
if (!parameter.isVararg) {
@@ -97,4 +97,8 @@ class ArgumentTypeMismatch(
class NullForNotNullType(
val argument: FirExpression
) : ResolutionDiagnostic(INAPPLICABLE)
) : ResolutionDiagnostic(INAPPLICABLE)
class ManyLambdaExpressionArguments(
val argument: FirExpression
) : ResolutionDiagnostic(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR)
@@ -25,5 +25,5 @@ fun test() {
foo("", 1) <!TOO_MANY_ARGUMENTS!>{}<!>
foo("", 1) <!TOO_MANY_ARGUMENTS!>{}<!> <!TOO_MANY_ARGUMENTS!>{}<!>
foo("", 1) <!TOO_MANY_ARGUMENTS!>{}<!> <!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
}
@@ -6,9 +6,9 @@ fun test(x: () -> Unit, y: () -> Unit) {
}
fun main() {
test {
<!NO_VALUE_FOR_PARAMETER!>test {
1
} {
} <!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{
2
}
}<!><!>
}
@@ -23,9 +23,9 @@ fun testNoArgs() {
noArgs() // comment
// comment
<!TOO_MANY_ARGUMENTS!>{}<!>
noArgs() <!TOO_MANY_ARGUMENTS!>{}<!> <!TOO_MANY_ARGUMENTS!>{}<!>
noArgs() <!TOO_MANY_ARGUMENTS!>{}<!> <!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
noArgs() <!TOO_MANY_ARGUMENTS!>{}<!>
<!TOO_MANY_ARGUMENTS!>{}<!>
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
}
fun testLambdaArg() {
@@ -35,7 +35,7 @@ fun testLambdaArg() {
{}
oneLambdaArg()
{}
<!TOO_MANY_ARGUMENTS!>{}<!>
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
oneLambdaArg(
{},
<!TOO_MANY_ARGUMENTS!>{}<!>
@@ -52,19 +52,19 @@ fun testLambdaArg() {
{}
oneLambdaArg() {}/*
block comment, no new line
*/ <!TOO_MANY_ARGUMENTS!>{}<!>
*/ <!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
oneLambdaArg() {}/*
block comment with new line
*/
<!TOO_MANY_ARGUMENTS!>{}<!>
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
oneLambdaArg() {}// comment
// comment
<!TOO_MANY_ARGUMENTS!>{}<!>
oneLambdaArg() {} <!TOO_MANY_ARGUMENTS!>{}<!>
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
oneLambdaArg() {} <!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
oneLambdaArg() {}
<!TOO_MANY_ARGUMENTS!>{}<!>
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
oneLambdaArg() {} // comment
<!TOO_MANY_ARGUMENTS!>{}<!>
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
}
fun testVararg() {
@@ -83,9 +83,9 @@ fun testVararg() {
varargFn(1,2,3) // comment
// comment
<!VARARG_OUTSIDE_PARENTHESES!>{}<!>
varargFn(1,2,3) <!ARGUMENT_TYPE_MISMATCH!>{}<!> <!ARGUMENT_TYPE_MISMATCH, VARARG_OUTSIDE_PARENTHESES!>{}<!>
varargFn(1,2,3) <!ARGUMENT_TYPE_MISMATCH!>{}<!>
<!ARGUMENT_TYPE_MISMATCH, VARARG_OUTSIDE_PARENTHESES!>{}<!>
varargFn(1,2,3) {} <!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
varargFn(1,2,3) {}
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
}
fun testTwoLambdas() {
@@ -96,14 +96,14 @@ fun testTwoLambdas() {
)
fun bar(): () -> Unit {
twoLambdaArgs()
{}
twoLambdaArgs(<!NO_VALUE_FOR_PARAMETER!>)<!>
{}
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
return if (true) {
twoLambdaArgs({})
{}
<!TOO_MANY_ARGUMENTS!>{}<!>
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
} else {
{}
}
@@ -828,6 +828,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.MANY_LAMBDA_EXPRESSION_ARGUMENTS) { firDiagnostic ->
ManyLambdaExpressionArgumentsImpl(
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY) { firDiagnostic ->
OverloadResolutionAmbiguityImpl(
firDiagnostic.a.map { abstractFirBasedSymbol ->
@@ -595,6 +595,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val name: String
}
abstract class ManyLambdaExpressionArguments : KtFirDiagnostic<KtValueArgument>() {
override val diagnosticClass get() = ManyLambdaExpressionArguments::class
}
abstract class OverloadResolutionAmbiguity : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = OverloadResolutionAmbiguity::class
abstract val candidates: List<KtSymbol>
@@ -953,6 +953,13 @@ internal class NamedParameterNotFoundImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ManyLambdaExpressionArgumentsImpl(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.ManyLambdaExpressionArguments(), KtAbstractFirDiagnostic<KtValueArgument> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class OverloadResolutionAmbiguityImpl(
override val candidates: List<KtSymbol>,
firDiagnostic: FirPsiDiagnostic<*>,