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 94d727fedbe..2b15d06040d 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 @@ -119,6 +119,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { parameter("hasValueParameters") } val ILLEGAL_SELECTOR by error() + val NO_RECEIVER_ALLOWED by error() } val SUPER by object : DiagnosticGroup("Super") { 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 2ecce319a56..ae2bb53afd6 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 @@ -132,6 +132,7 @@ object FirErrors { val CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS by error0() val FUNCTION_CALL_EXPECTED by error2(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val ILLEGAL_SELECTOR by error0() + val NO_RECEIVER_ALLOWED by error0() // Super val SUPER_IS_NOT_AN_EXPRESSION by error0(SourceElementPositioningStrategies.REFERENCED_NAME_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 36aa6c048eb..acae26948c3 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 @@ -272,6 +272,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_FOR_EXP import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_COMPANION_OBJECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ELSE_IN_WHEN import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_GET_METHOD +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_RECEIVER_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_SET_METHOD import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_THIS @@ -496,6 +497,7 @@ class FirDefaultErrorMessages { map.put(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, "Cannot create an instance of an abstract class") map.put(FUNCTION_CALL_EXPECTED, "Function invocation ''{0}({1})'' expected", TO_STRING, FUNCTION_PARAMETERS) map.put(ILLEGAL_SELECTOR, "The expression cannot be a selector (occur after a dot)") + map.put(NO_RECEIVER_ALLOWED, "No receiver can be passed to this function or property") // Supertypes map.put(NOT_A_SUPERTYPE, "Not an immediate supertype") 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 3ca9dd403af..289e66b18d8 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 @@ -363,6 +363,7 @@ private fun ConeSimpleDiagnostic.getFactory(source: FirSourceElement): FirDiagno DiagnosticKind.RecursiveTypealiasExpansion -> FirErrors.RECURSIVE_TYPEALIAS_EXPANSION DiagnosticKind.LoopInSupertype -> FirErrors.CYCLIC_INHERITANCE_HIERARCHY DiagnosticKind.IllegalSelector -> FirErrors.ILLEGAL_SELECTOR + DiagnosticKind.NoReceiverAllowed -> FirErrors.NO_RECEIVER_ALLOWED DiagnosticKind.IsEnumEntry -> FirErrors.IS_ENUM_ENTRY DiagnosticKind.EnumEntryAsType -> FirErrors.ENUM_ENTRY_AS_TYPE DiagnosticKind.UnresolvedSupertype, diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt index 839545ae339..5113f9c192f 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.fir.lightTree.converter import com.intellij.lang.LighterASTNode import com.intellij.psi.TokenType import com.intellij.util.diff.FlyweightCapableTreeStructure -import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes.* import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities @@ -504,15 +503,18 @@ class ExpressionsConverter( val firExpression = getAsFirExpression(it, "Incorrect ${if (isEffectiveSelector) "selector" else "receiver"} expression") if (isEffectiveSelector) { + val callExpressionCallee = if (it.tokenType == CALL_EXPRESSION) it.getFirstChildExpressionUnwrapped() else null firSelector = - if (it.tokenType is KtNameReferenceExpressionElementType || it.tokenType == KtNodeTypes.CALL_EXPRESSION) { + if (it.tokenType is KtNameReferenceExpressionElementType || + (it.tokenType == CALL_EXPRESSION && callExpressionCallee?.tokenType != LAMBDA_EXPRESSION) + ) { firExpression } else { buildErrorExpression { - source = it.toFirSourceElement() + source = callExpressionCallee?.toFirSourceElement() ?: it.toFirSourceElement() diagnostic = ConeSimpleDiagnostic( "The expression cannot be a selector (occur after a dot)", - DiagnosticKind.IllegalSelector + if (callExpressionCallee == null) DiagnosticKind.IllegalSelector else DiagnosticKind.NoReceiverAllowed ) expression = firExpression } diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index 5aa9540648a..218d8dde519 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -211,25 +211,31 @@ open class RawFirBuilder( return buildExpressionStub() } else { val result = this.convertSafe() + if (result != null) { - if (this != null && - this !is KtNameReferenceExpression && - this !is KtCallExpression && - this !is KtConstantExpression && - getQualifiedExpressionForSelector() != null - ) { - return buildErrorExpression { - source = toFirSourceElement() - diagnostic = - ConeSimpleDiagnostic( - "The expression cannot be a selector (occur after a dot)", - DiagnosticKind.IllegalSelector - ) - expression = result - } + if (this == null) { + return result } - return result + val callExpressionCallee = (this as? KtCallExpression)?.calleeExpression?.unwrapParenthesesLabelsAndAnnotations() + + if (this is KtNameReferenceExpression || + this is KtConstantExpression || + (this is KtCallExpression && callExpressionCallee !is KtLambdaExpression) || + getQualifiedExpressionForSelector() == null + ) { + return result + } + + return buildErrorExpression { + source = callExpressionCallee?.toFirSourceElement() ?: toFirSourceElement() + diagnostic = + ConeSimpleDiagnostic( + "The expression cannot be a selector (occur after a dot)", + if (callExpressionCallee == null) DiagnosticKind.IllegalSelector else DiagnosticKind.NoReceiverAllowed + ) + expression = result + } } return buildErrorExpression( diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt index 080e59f1866..59bdd1e2b3c 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/diagnostics/ConeSimpleDiagnostic.kt @@ -23,6 +23,7 @@ enum class DiagnosticKind { NoThis, IllegalConstExpression, IllegalSelector, + NoReceiverAllowed, IllegalUnderscore, DeserializationError, InferenceError, diff --git a/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt b/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt index 4d6b87cc625..1543a100c0f 100644 --- a/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt +++ b/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt @@ -83,5 +83,5 @@ fun test() { i.(fun Int.() = 1)(); {}() 1?.(fun Int.() = 1)() - 1.{}() + 1.{}() } 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 b1e4a1a3b0d..20d2642e12b 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 @@ -321,6 +321,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.NO_RECEIVER_ALLOWED) { firDiagnostic -> + NoReceiverAllowedImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.SUPER_IS_NOT_AN_EXPRESSION) { firDiagnostic -> SuperIsNotAnExpressionImpl( firDiagnostic as FirPsiDiagnostic, 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 40f62aae7a1..ca6c15e87ea 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 @@ -253,6 +253,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = IllegalSelector::class } + abstract class NoReceiverAllowed : KtFirDiagnostic() { + override val diagnosticClass get() = NoReceiverAllowed::class + } + abstract class SuperIsNotAnExpression : KtFirDiagnostic() { override val diagnosticClass get() = SuperIsNotAnExpression::class } 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 eda09529934..e316a77c30b 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 @@ -374,6 +374,13 @@ internal class IllegalSelectorImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class NoReceiverAllowedImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.NoReceiverAllowed(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class SuperIsNotAnExpressionImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken,