From 525cc6df971e1806102e7ef829a842e887c7c208 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Tue, 27 Apr 2021 19:51:01 +0300 Subject: [PATCH] [FIR] Implement MANY_LAMBDA_EXPRESSION_ARGUMENTS diagnostics, fix tests --- .../diagnostics/FirDiagnosticsList.kt | 2 ++ .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../diagnostics/FirDefaultErrorMessages.kt | 2 ++ .../coneDiagnosticToFirDiagnostic.kt | 1 + .../calls/FirArgumentsToParametersMapper.kt | 27 +++++++++++++---- .../fir/resolve/calls/ResolutionDiagnostic.kt | 6 +++- .../kt1897_diagnostic_part.fir.kt | 2 +- .../checkArguments/twoLambdasFunction.fir.kt | 6 ++-- .../tests/resolve/newLineLambda.fir.kt | 30 +++++++++---------- .../diagnostics/KtFirDataClassConverters.kt | 6 ++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 4 +++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 7 +++++ 12 files changed, 68 insertions(+), 26 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 09caf3c1e0f..9d2c6ef1bb0 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 @@ -255,6 +255,8 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val NAMED_PARAMETER_NOT_FOUND by error(PositioningStrategy.NAME_OF_NAMED_ARGUMENT) { parameter("name") } + + val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error() } val AMBIGUITY by object : DiagnosticGroup("Ambiguity") { 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 ef74fe6e4f4..67678f07df0 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 @@ -212,6 +212,7 @@ object FirErrors { val TOO_MANY_ARGUMENTS by error1>() val NO_VALUE_FOR_PARAMETER by error1(SourceElementPositioningStrategies.VALUE_ARGUMENTS) val NAMED_PARAMETER_NOT_FOUND by error1(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT) + val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0() // Ambiguity val OVERLOAD_RESOLUTION_AMBIGUITY by error1>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) 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 004e8754a45..93f85b28dbc 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 @@ -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) 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 2873a69b4d3..d93d904049b 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 @@ -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)) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirArgumentsToParametersMapper.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirArgumentsToParametersMapper.kt index 1d5b52b75ba..9c9d523949d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirArgumentsToParametersMapper.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/FirArgumentsToParametersMapper.kt @@ -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 = if (externalArgument == null) { - arguments - } else { - arguments.subList(0, arguments.size - 1) + + val argumentsInParenthesis: MutableList = mutableListOf() + val excessLambdaArguments: MutableList = 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) { + excessLambdaArguments.forEach { arg -> addDiagnostic(ManyLambdaExpressionArguments(arg)) } + } + fun processDefaultsAndRunChecks() { for ((parameter, resolvedArgument) in result) { if (!parameter.isVararg) { 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 d1649c64168..71e8b0de09c 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 @@ -97,4 +97,8 @@ class ArgumentTypeMismatch( class NullForNotNullType( val argument: FirExpression -) : ResolutionDiagnostic(INAPPLICABLE) \ No newline at end of file +) : ResolutionDiagnostic(INAPPLICABLE) + +class ManyLambdaExpressionArguments( + val argument: FirExpression +) : ResolutionDiagnostic(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR) \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/checkArguments/kt1897_diagnostic_part.fir.kt b/compiler/testData/diagnostics/tests/checkArguments/kt1897_diagnostic_part.fir.kt index 443337ad83c..607f0b4265b 100644 --- a/compiler/testData/diagnostics/tests/checkArguments/kt1897_diagnostic_part.fir.kt +++ b/compiler/testData/diagnostics/tests/checkArguments/kt1897_diagnostic_part.fir.kt @@ -25,5 +25,5 @@ fun test() { foo("", 1) {} - foo("", 1) {} {} + foo("", 1) {} {} } diff --git a/compiler/testData/diagnostics/tests/checkArguments/twoLambdasFunction.fir.kt b/compiler/testData/diagnostics/tests/checkArguments/twoLambdasFunction.fir.kt index c1957d10528..63edc50e3de 100644 --- a/compiler/testData/diagnostics/tests/checkArguments/twoLambdasFunction.fir.kt +++ b/compiler/testData/diagnostics/tests/checkArguments/twoLambdasFunction.fir.kt @@ -6,9 +6,9 @@ fun test(x: () -> Unit, y: () -> Unit) { } fun main() { - test { + test { 1 - } { + } { 2 - } + } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/resolve/newLineLambda.fir.kt b/compiler/testData/diagnostics/tests/resolve/newLineLambda.fir.kt index ce6a7af112c..c29c5f54f67 100644 --- a/compiler/testData/diagnostics/tests/resolve/newLineLambda.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/newLineLambda.fir.kt @@ -23,9 +23,9 @@ fun testNoArgs() { noArgs() // comment // comment {} - noArgs() {} {} + noArgs() {} {} noArgs() {} - {} + {} } fun testLambdaArg() { @@ -35,7 +35,7 @@ fun testLambdaArg() { {} oneLambdaArg() {} - {} + {} oneLambdaArg( {}, {} @@ -52,19 +52,19 @@ fun testLambdaArg() { {} oneLambdaArg() {}/* block comment, no new line - */ {} + */ {} oneLambdaArg() {}/* block comment with new line */ - {} + {} oneLambdaArg() {}// comment // comment - {} - oneLambdaArg() {} {} + {} + oneLambdaArg() {} {} oneLambdaArg() {} - {} + {} oneLambdaArg() {} // comment - {} + {} } fun testVararg() { @@ -83,9 +83,9 @@ fun testVararg() { varargFn(1,2,3) // comment // comment {} - varargFn(1,2,3) {} {} - varargFn(1,2,3) {} - {} + varargFn(1,2,3) {} {} + varargFn(1,2,3) {} + {} } fun testTwoLambdas() { @@ -96,14 +96,14 @@ fun testTwoLambdas() { ) fun bar(): () -> Unit { - twoLambdaArgs() - {} + twoLambdaArgs() {} + {} return if (true) { twoLambdaArgs({}) {} - {} + {} } else { {} } 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 af3950f269a..c47d19c20f2 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 @@ -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 -> 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 66d19844129..e7f6849aba5 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 @@ -595,6 +595,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val name: String } + abstract class ManyLambdaExpressionArguments : KtFirDiagnostic() { + override val diagnosticClass get() = ManyLambdaExpressionArguments::class + } + abstract class OverloadResolutionAmbiguity : KtFirDiagnostic() { override val diagnosticClass get() = OverloadResolutionAmbiguity::class abstract val candidates: List 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 936a348a9ba..d732ed33b3a 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 @@ -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 { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class OverloadResolutionAmbiguityImpl( override val candidates: List, firDiagnostic: FirPsiDiagnostic<*>,