From 2d4f4b9bb5ceb091a7bd57b72737d5dead79d1a8 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Fri, 8 Mar 2024 10:07:23 +0000 Subject: [PATCH] [FIR] Disallow operators not on functions Introduce `NOT_FUNCTION_AS_OPERATOR` and use it instead of `PROPERTY_AS_OPERATOR` ^KT-65881 Fixed Merge-request: KT-MR-14547 --- .../diagnostics/KtFirDataClassConverters.kt | 7 +- .../api/fir/diagnostics/KtFirDiagnostics.kt | 7 +- .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 7 +- ...CompilerTestFE10TestdataTestGenerated.java | 6 + ...sticCompilerFE10TestDataTestGenerated.java | 6 + ...eeOldFrontendDiagnosticsTestGenerated.java | 6 + ...siOldFrontendDiagnosticsTestGenerated.java | 6 + .../diagnostics/FirDiagnosticsList.kt | 5 +- .../fir/analysis/diagnostics/FirErrors.kt | 2 +- .../FirNonSuppressibleErrorNames.kt | 2 +- .../FirConventionFunctionCallChecker.kt | 42 ++++-- .../checkers/expression/FirForLoopChecker.kt | 1 - .../diagnostics/FirErrorsDefaultMessages.kt | 7 +- .../fir/resolve/calls/CandidateFactory.kt | 13 +- .../tower/FirInvokeResolveTowerExtension.kt | 24 ++-- ...rCallCompletionResultsWriterTransformer.kt | 6 +- .../fir/resolve/calls/ResolutionDiagnostic.kt | 3 +- .../resolve/diagnostics/ConeDiagnostics.kt | 4 +- .../calls/tower/CandidateApplicability.kt | 4 +- .../tests/OperatorConventions.fir.kt | 130 ++++++++++++++++++ .../diagnostics/tests/OperatorConventions.kt | 130 ++++++++++++++++++ .../delegatedProperty/withInvokes.fir.kt | 4 +- .../testData/diagnostics/tests/kt34857.fir.kt | 6 + .../testData/diagnostics/tests/kt34857.kt | 2 - .../PropertyInvoke.fir.kt | 44 +++--- .../destructuringDeclarationWithInvoke.fir.kt | 23 ++++ .../destructuringDeclarationWithInvoke.kt | 1 - .../test/runners/DiagnosticTestGenerated.java | 6 + .../operator-call/p-4/neg/1.1.fir.kt | 30 ++-- .../operator-call/p-4/pos/1.1.fir.kt | 2 +- .../p-5/neg/1.1.fir.kt | 4 +- 31 files changed, 440 insertions(+), 100 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/OperatorConventions.fir.kt create mode 100644 compiler/testData/diagnostics/tests/OperatorConventions.kt create mode 100644 compiler/testData/diagnostics/tests/kt34857.fir.kt create mode 100644 compiler/testData/diagnostics/tests/operatorsOverloading/destructuringDeclarationWithInvoke.fir.kt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 940cfac4949..cc5a2bee939 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -4529,9 +4529,10 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } - add(FirErrors.PROPERTY_AS_OPERATOR) { firDiagnostic -> - PropertyAsOperatorImpl( - firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firDiagnostic.a), + add(FirErrors.NOT_FUNCTION_AS_OPERATOR) { firDiagnostic -> + NotFunctionAsOperatorImpl( + firDiagnostic.a, + firSymbolBuilder.buildSymbol(firDiagnostic.b), firDiagnostic as KtPsiDiagnostic, token, ) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index df0e0243c62..1c8403467e9 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -3156,9 +3156,10 @@ sealed interface KtFirDiagnostic : KtDiagnosticWithPsi { val operator: String } - interface PropertyAsOperator : KtFirDiagnostic { - override val diagnosticClass get() = PropertyAsOperator::class - val property: KtVariableSymbol + interface NotFunctionAsOperator : KtFirDiagnostic { + override val diagnosticClass get() = NotFunctionAsOperator::class + val elementName: String + val elementSymbol: KtSymbol } interface DslScopeViolation : KtFirDiagnostic { diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index bebc86343b8..81693a99474 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -3800,11 +3800,12 @@ internal class AssignmentOperatorShouldReturnUnitImpl( token: KtLifetimeToken, ) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.AssignmentOperatorShouldReturnUnit -internal class PropertyAsOperatorImpl( - override val property: KtVariableSymbol, +internal class NotFunctionAsOperatorImpl( + override val elementName: String, + override val elementSymbol: KtSymbol, firDiagnostic: KtPsiDiagnostic, token: KtLifetimeToken, -) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.PropertyAsOperator +) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.NotFunctionAsOperator internal class DslScopeViolationImpl( override val calleeSymbol: KtSymbol, diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java index f2b616f99d6..0e71c460fa7 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java @@ -1023,6 +1023,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt"); } + @Test + @TestMetadata("OperatorConventions.kt") + public void testOperatorConventions() { + runTest("compiler/testData/diagnostics/tests/OperatorConventions.kt"); + } + @Test @TestMetadata("Operators.kt") public void testOperators() { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java index 668bb1e07e3..83277bce76f 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java @@ -1023,6 +1023,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt"); } + @Test + @TestMetadata("OperatorConventions.kt") + public void testOperatorConventions() { + runTest("compiler/testData/diagnostics/tests/OperatorConventions.kt"); + } + @Test @TestMetadata("Operators.kt") public void testOperators() { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java index 709f98965e3..1b0e6f85308 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java @@ -1023,6 +1023,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt"); } + @Test + @TestMetadata("OperatorConventions.kt") + public void testOperatorConventions() { + runTest("compiler/testData/diagnostics/tests/OperatorConventions.kt"); + } + @Test @TestMetadata("Operators.kt") public void testOperators() { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index 5c59834d62c..034468bd741 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -1023,6 +1023,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt"); } + @Test + @TestMetadata("OperatorConventions.kt") + public void testOperatorConventions() { + runTest("compiler/testData/diagnostics/tests/OperatorConventions.kt"); + } + @Test @TestMetadata("Operators.kt") public void testOperators() { 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 d0b1fa27dd1..0a8c6d6d9e1 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 @@ -1585,8 +1585,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { parameter("functionSymbol") parameter("operator") } - val PROPERTY_AS_OPERATOR by error(PositioningStrategy.OPERATOR) { - parameter("property") + val NOT_FUNCTION_AS_OPERATOR by error(PositioningStrategy.OPERATOR) { + parameter("elementName") + parameter>("elementSymbol") } val DSL_SCOPE_VIOLATION by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) { parameter>("calleeSymbol") 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 c23ef35ec7e..085352b9dad 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 @@ -796,7 +796,7 @@ object FirErrors { val IMPLICIT_BOXING_IN_IDENTITY_EQUALS: KtDiagnosticFactory2 by warning2() val INC_DEC_SHOULD_NOT_RETURN_UNIT: KtDiagnosticFactory0 by error0(SourceElementPositioningStrategies.OPERATOR) val ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT: KtDiagnosticFactory2 by error2(SourceElementPositioningStrategies.OPERATOR) - val PROPERTY_AS_OPERATOR: KtDiagnosticFactory1 by error1(SourceElementPositioningStrategies.OPERATOR) + val NOT_FUNCTION_AS_OPERATOR: KtDiagnosticFactory2> by error2>(SourceElementPositioningStrategies.OPERATOR) val DSL_SCOPE_VIOLATION: KtDiagnosticFactory1> by error1>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) // Type alias diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt index 6595e511517..0089069ac79 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt @@ -533,7 +533,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set = setOf( "FORBIDDEN_IDENTITY_EQUALS", "INC_DEC_SHOULD_NOT_RETURN_UNIT", "ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT", - "PROPERTY_AS_OPERATOR", + "NOT_FUNCTION_AS_OPERATOR", "DSL_SCOPE_VIOLATION", "TOPLEVEL_TYPEALIASES_ONLY", "RECURSIVE_TYPEALIAS_EXPANSION", diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConventionFunctionCallChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConventionFunctionCallChecker.kt index 83be205f334..c5ab499f120 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConventionFunctionCallChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConventionFunctionCallChecker.kt @@ -11,23 +11,21 @@ import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors -import org.jetbrains.kotlin.fir.expressions.FirExpression -import org.jetbrains.kotlin.fir.expressions.FirFunctionCall -import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression -import org.jetbrains.kotlin.fir.expressions.unwrapSmartcastExpression +import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.references.FirErrorNamedReference -import org.jetbrains.kotlin.fir.resolve.diagnostics.ConePropertyAsOperator +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeNotFunctionAsOperator import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError +import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.types.ConeDynamicType +import org.jetbrains.kotlin.fir.types.classId import org.jetbrains.kotlin.fir.types.resolvedType import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull object FirConventionFunctionCallChecker : FirFunctionCallChecker(MppCheckerKind.Common) { override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) { - // PROPERTY_AS_OPERATOR can only happen for function calls and it's reported on the receiver expression. - checkPropertyAsOperator(expression, expression.dispatchReceiver, context, reporter) - checkPropertyAsOperator(expression, expression.extensionReceiver, context, reporter) + checkNotFunctionAsOperator(expression, expression.dispatchReceiver, context, reporter) + checkNotFunctionAsOperator(expression, expression.extensionReceiver, context, reporter) val calleeReference = expression.calleeReference as? FirErrorNamedReference ?: return val diagnostic = calleeReference.diagnostic as? ConeUnresolvedNameError ?: return @@ -39,7 +37,7 @@ object FirConventionFunctionCallChecker : FirFunctionCallChecker(MppCheckerKind. } } - private fun checkPropertyAsOperator( + private fun checkNotFunctionAsOperator( callExpression: FirFunctionCall, receiver: FirExpression?, context: CheckerContext, @@ -47,9 +45,27 @@ object FirConventionFunctionCallChecker : FirFunctionCallChecker(MppCheckerKind. ) { if (callExpression.dispatchReceiver?.resolvedType is ConeDynamicType) return // KT-61905: TODO: Return also in case of error type. - val unwrapped = receiver?.unwrapSmartcastExpression() - if (unwrapped !is FirPropertyAccessExpression) return - val diagnostic = unwrapped.nonFatalDiagnostics.firstIsInstanceOrNull() ?: return - reporter.reportOn(callExpression.calleeReference.source, FirErrors.PROPERTY_AS_OPERATOR, diagnostic.symbol, context) + val unwrapped = receiver?.unwrapSmartcastExpression() ?: return + val nonFatalDiagnostics = when (unwrapped) { + is FirQualifiedAccessExpression -> unwrapped.nonFatalDiagnostics + is FirResolvedQualifier -> unwrapped.nonFatalDiagnostics + else -> return + } + val diagnosticSymbol = nonFatalDiagnostics.firstIsInstanceOrNull()?.symbol ?: return + when { + unwrapped.resolvedType.classId!!.shortClassName == OperatorNameConventions.ITERATOR -> { + reporter.reportOn(unwrapped.source, FirErrors.ITERATOR_MISSING, context) + } + else -> { + // NOT_FUNCTION_AS_OPERATOR can only happen for function calls and it's reported on the receiver expression. + reporter.reportOn( + callExpression.calleeReference.source, + FirErrors.NOT_FUNCTION_AS_OPERATOR, + if (diagnosticSymbol is FirPropertySymbol) "Property" else "Object", + diagnosticSymbol, + context + ) + } + } } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirForLoopChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirForLoopChecker.kt index 5589e54362b..4e19841429c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirForLoopChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirForLoopChecker.kt @@ -37,7 +37,6 @@ import org.jetbrains.kotlin.fir.resolve.calls.UnsafeCall import org.jetbrains.kotlin.fir.resolve.diagnostics.* import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol -import org.jetbrains.kotlin.resolve.calls.tower.isSuccess import org.jetbrains.kotlin.util.OperatorNameConventions object FirForLoopChecker : FirBlockChecker(MppCheckerKind.Common) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index 2b09c651d0c..f7c40d33258 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -451,6 +451,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_FUNCTION_LA import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_LOOP_LABEL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_MULTIPLATFORM_COMPILATION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_SUPERTYPE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_FUNCTION_AS_OPERATOR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_SUPPORTED_INLINE_PARAMETER_IN_INLINE_PARAMETER_DEFAULT_VALUE @@ -521,7 +522,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIVATE_SETTER_FO import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIVATE_SETTER_FOR_OPEN_PROPERTY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_AS_OPERATOR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_FIELD_DECLARATION_MISSING_INITIALIZER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_IN_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_NO_BACKING_FIELD @@ -2410,8 +2410,9 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { TO_STRING ) map.put( - PROPERTY_AS_OPERATOR, - "Property ''{0}'' cannot be used as operator.", + NOT_FUNCTION_AS_OPERATOR, + "{0} ''{1}'' cannot be used as operator.", + STRING, SYMBOL ) map.put( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt index bb0d2ba743d..e5546223de9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt @@ -124,15 +124,12 @@ class CandidateFactory private constructor( result.addDiagnostic(NoCompanionObject) } if (callInfo.origin == FirFunctionCallOrigin.Operator) { - val propertySymbol = when { - symbol is FirPropertySymbol -> symbol - callInfo.candidateForCommonInvokeReceiver != null -> callInfo.candidateForCommonInvokeReceiver.symbol as? FirPropertySymbol - else -> null - } - if (propertySymbol != null) { - // Flag all property references that are resolved from an convention operator call. - result.addDiagnostic(PropertyAsOperator(propertySymbol)) + val normalizedSymbol = when (symbol) { + !is FirFunctionSymbol -> symbol + else -> callInfo.candidateForCommonInvokeReceiver?.symbol?.takeIf { it !is FirFunctionSymbol } } + // Flag all references that are resolved from an convention operator call. + normalizedSymbol?.let { result.addDiagnostic(NotFunctionAsOperator(normalizedSymbol)) } } if (symbol is FirPropertySymbol && !context.session.languageVersionSettings.supportsFeature(LanguageFeature.PrioritizedEnumEntries) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt index 9b4cefa0f6c..e1df43736e5 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier import org.jetbrains.kotlin.fir.expressions.builder.FirPropertyAccessExpressionBuilder import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.* -import org.jetbrains.kotlin.fir.resolve.diagnostics.ConePropertyAsOperator +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeNotFunctionAsOperator import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.TypeApproximatorConfiguration import org.jetbrains.kotlin.util.OperatorNameConventions +import org.jetbrains.kotlin.utils.addToStdlib.runIf internal class FirInvokeResolveTowerExtension( private val context: ResolutionContext, @@ -288,18 +289,26 @@ private fun BodyResolveComponents.createExplicitReceiverForInvoke( invokeBuiltinExtensionMode: Boolean, extensionReceiverExpression: FirExpression? ): FirExpression? { + val notFunctionAsOperatorDiagnostics = runIf (candidate.currentApplicability == CandidateApplicability.K2_NOT_FUNCTION_AS_OPERATOR) { + candidate.diagnostics.filterIsInstance().map { ConeNotFunctionAsOperator(it.symbol) } + } ?: emptyList() return when (val symbol = candidate.symbol) { is FirCallableSymbol<*> -> createExplicitReceiverForInvokeByCallable( - candidate, info, invokeBuiltinExtensionMode, extensionReceiverExpression, symbol + candidate, info, invokeBuiltinExtensionMode, extensionReceiverExpression, symbol, notFunctionAsOperatorDiagnostics ) is FirRegularClassSymbol -> buildResolvedQualifierForClass( symbol, - sourceElement = info.fakeSourceForImplicitInvokeCallReceiver + sourceElement = info.fakeSourceForImplicitInvokeCallReceiver, + nonFatalDiagnostics = notFunctionAsOperatorDiagnostics, ) is FirTypeAliasSymbol -> { val type = symbol.fir.expandedTypeRef.coneTypeUnsafe().fullyExpandedType(session) val expansionRegularClassSymbol = type.lookupTag.toSymbol(session) ?: return null - buildResolvedQualifierForClass(expansionRegularClassSymbol, sourceElement = symbol.fir.source) + buildResolvedQualifierForClass( + expansionRegularClassSymbol, + sourceElement = symbol.fir.source, + nonFatalDiagnostics = notFunctionAsOperatorDiagnostics, + ) } else -> throw AssertionError() } @@ -310,7 +319,8 @@ private fun BodyResolveComponents.createExplicitReceiverForInvokeByCallable( info: CallInfo, invokeBuiltinExtensionMode: Boolean, extensionReceiverExpression: FirExpression?, - symbol: FirCallableSymbol<*> + symbol: FirCallableSymbol<*>, + nonFatalDiagnostics: List, ): FirExpression { return FirPropertyAccessExpressionBuilder().apply { val fakeSource = info.fakeSourceForImplicitInvokeCallReceiver @@ -337,9 +347,7 @@ private fun BodyResolveComponents.createExplicitReceiverForInvokeByCallable( explicitReceiver = info.explicitReceiver } - if (candidate.currentApplicability == CandidateApplicability.K2_PROPERTY_AS_OPERATOR) { - nonFatalDiagnostics.add(ConePropertyAsOperator(candidate.symbol as FirPropertySymbol)) - } + this.nonFatalDiagnostics.addAll(nonFatalDiagnostics) candidate.updateSourcesOfReceivers() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt index 7e1561b0836..aa6cc6f4763 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt @@ -170,11 +170,11 @@ class FirCallCompletionResultsWriterTransformer( qualifiedAccessExpression.replaceContextReceiverArguments(subCandidate.contextReceiverArguments()) - subCandidate.diagnostics.firstIsInstanceOrNull()?.let { propertyAsOperator -> - val conePropertyAsOperator = ConePropertyAsOperator(propertyAsOperator.propertySymbol) + subCandidate.diagnostics.firstIsInstanceOrNull()?.let { propertyAsOperator -> + val coneNotFunctionAsOperator = ConeNotFunctionAsOperator(propertyAsOperator.symbol) val nonFatalDiagnostics: List = buildList { addAll(qualifiedAccessExpression.nonFatalDiagnostics) - add(conePropertyAsOperator) + add(coneNotFunctionAsOperator) } qualifiedAccessExpression.replaceNonFatalDiagnostics(nonFatalDiagnostics) } diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt index 3ab694c0dd7..db8a37c4779 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionDiagnostic.kt @@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeTypeVariable import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget @@ -136,7 +135,7 @@ class OperatorCallOfConstructor(val constructor: FirConstructorSymbol) : Resolut class InferenceError(val constraintError: ConstraintSystemError) : ResolutionDiagnostic(constraintError.applicability) class Unsupported(val message: String, val source: KtSourceElement?) : ResolutionDiagnostic(K2_UNSUPPORTED) -class PropertyAsOperator(val propertySymbol: FirPropertySymbol) : ResolutionDiagnostic(K2_PROPERTY_AS_OPERATOR) +class NotFunctionAsOperator(val symbol: FirBasedSymbol<*>) : ResolutionDiagnostic(K2_NOT_FUNCTION_AS_OPERATOR) class DslScopeViolation(val calleeSymbol: FirBasedSymbol<*>) : ResolutionDiagnostic(RESOLVED_WITH_ERROR) diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt index b598fbe4b7b..f44377df252 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt @@ -350,8 +350,8 @@ class ConeLocalVariableNoTypeOrInitializer(val variable: FirVariable) : ConeDiag override val reason: String get() = "Cannot infer variable type without initializer / getter / delegate" } -class ConePropertyAsOperator(val symbol: FirPropertySymbol) : ConeDiagnostic { - override val reason: String get() = "Cannot use a property as an operator" +class ConeNotFunctionAsOperator(val symbol: FirBasedSymbol<*>) : ConeDiagnostic { + override val reason: String get() = "Cannot use not function as an operator" } class ConeUnknownLambdaParameterTypeDiagnostic : ConeDiagnostic { diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt index 795b5a8f13d..91f4b17bb77 100644 --- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt +++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/tower/CandidateApplicability.kt @@ -89,10 +89,10 @@ enum class CandidateApplicability { RESOLVED_LOW_PRIORITY, /** - * Candidate is successful but uses property of functional type as an operator. + * Candidate is successful but uses property or object of functional type as an operator. * Tower resolve proceeds to next levels. */ - K2_PROPERTY_AS_OPERATOR, + K2_NOT_FUNCTION_AS_OPERATOR, /** * Candidate is successful but uses new features that change resolve. diff --git a/compiler/testData/diagnostics/tests/OperatorConventions.fir.kt b/compiler/testData/diagnostics/tests/OperatorConventions.fir.kt new file mode 100644 index 00000000000..405268a25f5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/OperatorConventions.fir.kt @@ -0,0 +1,130 @@ +// ISSUE: KT-65881, KT-65760 + +class I: Iterator { + override fun hasNext(): Boolean = false + override fun next(): Int = 0 +} + +object A { + object plusAssign { + operator fun invoke(x: Int): A = A + } + object minusAssign { + operator fun invoke(x: Int): A = A + } + object timesAssign { + operator fun invoke(x: Int): A = A + } + object divAssign { + operator fun invoke(x: Int): A = A + } + object remAssign { + operator fun invoke(x: Int): A = A + } + object unaryPlus { + operator fun invoke(): A = A + } + object unaryMinus { + operator fun invoke(): A = A + } + object not { + operator fun invoke(): A = A + } + object plus { + operator fun invoke(x: Int): A = A + } + object minus { + operator fun invoke(x: Int): A = A + } + object times { + operator fun invoke(x: Int): A = A + } + object div { + operator fun invoke(x: Int): A = A + } + object rem { + operator fun invoke(x: Int): A = A + } + object get { + operator fun invoke(x: Int): A = A + } + object set { + operator fun invoke(x: Int, y: Int): A = A + } + object contains { + operator fun invoke(x: Int): A = A + } + object invoke { + operator fun invoke(): A = A + } + object rangeTo { + operator fun invoke(x: Int): A = A + } + object rangeUntil { + operator fun invoke(x: Int): A = A + } + object compareTo { + operator fun invoke(x: Int): A = A + } + object iterator { + operator fun invoke(): I = I() + } + object component1 { + operator fun invoke(): A = A + } + object component2 { + operator fun invoke(): A = A + } +} + +fun usePlusAssign() { A += 1 } +fun useMinusAssign() { A -= 1 } +fun useTimesAssign() { A *= 1 } +fun useDivAssign() { A /= 1 } +fun useRemAssign() { A %= 1 } +val useUnaryPlus = +A +val useUnaryMinus = -A +val useNot = !A +val usePlus = A + 1 +val useMinus = A - 1 +val useTimes = A * 1 +val useDiv = A / 1 +val useRem = A % 1 +val useGet = A[1] +fun useSet() { A[1] = 3 } +val useContains = 1 in A +val useNotContains = 1 !in A +val useInvoke = A() +val useRangeTo = A .. 3 +val useRangeUntil = A ..< 3 +val useCompareTo = A > 2 +fun useIterator() { + for (x in A) { } +} +fun useComponentN() { + val (x, y) = A +} + +object D { + object getValue { + operator fun invoke(thisRef: Any?, property: Any?): Int = 0 + } + object setValue { + operator fun invoke(thisRef: Any?, property: Any?, newValue: Int) { } + } +} + +class X { + val component1 = { "UwU" } +} + +operator fun X.component1(): String = "Not UwU" + +fun useDelegate() { + val m by D + var n by D +} + +fun resolveToExtension() { + val (uwu) = X() // KT-65760 +} diff --git a/compiler/testData/diagnostics/tests/OperatorConventions.kt b/compiler/testData/diagnostics/tests/OperatorConventions.kt new file mode 100644 index 00000000000..a7391df9bd7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/OperatorConventions.kt @@ -0,0 +1,130 @@ +// ISSUE: KT-65881, KT-65760 + +class I: Iterator { + override fun hasNext(): Boolean = false + override fun next(): Int = 0 +} + +object A { + object plusAssign { + operator fun invoke(x: Int): A = A + } + object minusAssign { + operator fun invoke(x: Int): A = A + } + object timesAssign { + operator fun invoke(x: Int): A = A + } + object divAssign { + operator fun invoke(x: Int): A = A + } + object remAssign { + operator fun invoke(x: Int): A = A + } + object unaryPlus { + operator fun invoke(): A = A + } + object unaryMinus { + operator fun invoke(): A = A + } + object not { + operator fun invoke(): A = A + } + object plus { + operator fun invoke(x: Int): A = A + } + object minus { + operator fun invoke(x: Int): A = A + } + object times { + operator fun invoke(x: Int): A = A + } + object div { + operator fun invoke(x: Int): A = A + } + object rem { + operator fun invoke(x: Int): A = A + } + object get { + operator fun invoke(x: Int): A = A + } + object set { + operator fun invoke(x: Int, y: Int): A = A + } + object contains { + operator fun invoke(x: Int): A = A + } + object invoke { + operator fun invoke(): A = A + } + object rangeTo { + operator fun invoke(x: Int): A = A + } + object rangeUntil { + operator fun invoke(x: Int): A = A + } + object compareTo { + operator fun invoke(x: Int): A = A + } + object iterator { + operator fun invoke(): I = I() + } + object component1 { + operator fun invoke(): A = A + } + object component2 { + operator fun invoke(): A = A + } +} + +fun usePlusAssign() { A += 1 } +fun useMinusAssign() { A -= 1 } +fun useTimesAssign() { A *= 1 } +fun useDivAssign() { A /= 1 } +fun useRemAssign() { A %= 1 } +val useUnaryPlus = +A +val useUnaryMinus = -A +val useNot = !A +val usePlus = A + 1 +val useMinus = A - 1 +val useTimes = A * 1 +val useDiv = A / 1 +val useRem = A % 1 +val useGet = A[1] +fun useSet() { A[1] = 3 } +val useContains = 1 in A +val useNotContains = 1 !in A +val useInvoke = A() +val useRangeTo = A .. 3 +val useRangeUntil = A ..< 3 +val useCompareTo = A > 2 +fun useIterator() { + for (x in A) { } +} +fun useComponentN() { + val (x, y) = A +} + +object D { + object getValue { + operator fun invoke(thisRef: Any?, property: Any?): Int = 0 + } + object setValue { + operator fun invoke(thisRef: Any?, property: Any?, newValue: Int) { } + } +} + +class X { + val component1 = { "UwU" } +} + +operator fun X.component1(): String = "Not UwU" + +fun useDelegate() { + val m by D + var n by D +} + +fun resolveToExtension() { + val (uwu) = X() // KT-65760 +} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.fir.kt b/compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.fir.kt index 966f0cbd448..3c51ac11243 100644 --- a/compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.fir.kt +++ b/compiler/testData/diagnostics/tests/delegatedProperty/withInvokes.fir.kt @@ -12,11 +12,11 @@ val C.getValue: D get() = TODO() operator fun D.invoke(x: Any?, y: Any?): X4 = TODO() fun foo(a: A, c: C) { - val x1 by a + val x1 by a x1 x1.length - val y1 by c + val y1 by c y1 y1.length } diff --git a/compiler/testData/diagnostics/tests/kt34857.fir.kt b/compiler/testData/diagnostics/tests/kt34857.fir.kt new file mode 100644 index 00000000000..eb34554d654 --- /dev/null +++ b/compiler/testData/diagnostics/tests/kt34857.fir.kt @@ -0,0 +1,6 @@ +val Int.plusAssign: (Int) -> Unit + get() = {} + +fun main() { + 1 += 2 +} diff --git a/compiler/testData/diagnostics/tests/kt34857.kt b/compiler/testData/diagnostics/tests/kt34857.kt index f05bd9cd6ad..01bf14738ec 100644 --- a/compiler/testData/diagnostics/tests/kt34857.kt +++ b/compiler/testData/diagnostics/tests/kt34857.kt @@ -1,5 +1,3 @@ -// FIR_IDENTICAL - val Int.plusAssign: (Int) -> Unit get() = {} diff --git a/compiler/testData/diagnostics/tests/operatorsOverloading/PropertyInvoke.fir.kt b/compiler/testData/diagnostics/tests/operatorsOverloading/PropertyInvoke.fir.kt index 34ca9571eb2..8f6225639b1 100644 --- a/compiler/testData/diagnostics/tests/operatorsOverloading/PropertyInvoke.fir.kt +++ b/compiler/testData/diagnostics/tests/operatorsOverloading/PropertyInvoke.fir.kt @@ -10,25 +10,25 @@ class A { } var a = A() val A.inc: I get() = I() -fun useInc() { a++ } +fun useInc() { a++ } val A.dec: I get() = I() -fun useDec() { a-- } +fun useDec() { a-- } val A.plusAssign: I get() = I() -fun usePlusAssign() { a += 1 } +fun usePlusAssign() { a += 1 } val A.minusAssign: I get() = I() -fun useMinusAssign() { a -= 1 } +fun useMinusAssign() { a -= 1 } val A.timesAssign: I get() = I() -fun useTimesAssign() { a *= 1 } +fun useTimesAssign() { a *= 1 } val A.divAssign: I get() = I() -fun useDivAssign() { a /= 1 } +fun useDivAssign() { a /= 1 } val A.remAssign: I get() = I() -fun useRemAssign() { a %= 1 } +fun useRemAssign() { a %= 1 } // operators over values @@ -36,47 +36,47 @@ class E { } val e = E() val E.unaryPlus: I get() = I() -val useUnaryPlus = +e +val useUnaryPlus = +e val E.unaryMinus: I get() = I() -val useUnaryMinus = -e +val useUnaryMinus = -e val E.not: I get() = I() -val useNot = !e +val useNot = !e val E.plus: I get() = I() -val usePlus = e + 1 +val usePlus = e + 1 val E.minus: I get() = I() -val useMinus = e - 1 +val useMinus = e - 1 val E.times: I get() = I() -val useTimes = e * 1 +val useTimes = e * 1 val E.div: I get() = I() -val useDiv = e / 1 +val useDiv = e / 1 val E.rem: I get() = I() -val useRem = e % 1 +val useRem = e % 1 val E.get: I get() = I() -val useGet = e[1] +val useGet = e[1] val E.set: I get() = I() -fun useSet() { e[1] = 3 } +fun useSet() { e[1] = 3 } val E.contains: I get() = I() -val useContains = 1 in e -val useNotContains = 1 !in e +val useContains = 1 in e +val useNotContains = 1 !in e val E.invoke: I get() = I() val useInvoke = e() val E.rangeTo: I get() = I() -val useRangeTo = e .. 3 +val useRangeTo = e .. 3 val E.rangeUntil: I get() = I() -val useRangeUntil = e ..< 3 +val useRangeUntil = e ..< 3 val E.compareTo: I get() = I() -val useCompareTo = e > 2 +val useCompareTo = e > 2 diff --git a/compiler/testData/diagnostics/tests/operatorsOverloading/destructuringDeclarationWithInvoke.fir.kt b/compiler/testData/diagnostics/tests/operatorsOverloading/destructuringDeclarationWithInvoke.fir.kt new file mode 100644 index 00000000000..5d1cfa57975 --- /dev/null +++ b/compiler/testData/diagnostics/tests/operatorsOverloading/destructuringDeclarationWithInvoke.fir.kt @@ -0,0 +1,23 @@ +// ISSUE: KT-59715 + +class FunctionComponent { + val component1: () -> String = { "hello" } +} + +class I { + operator fun invoke(): String = "hello" +} + +class InvokeComponent { + val component1: I = I() +} + +fun test_1(c: FunctionComponent) { + val (x) = FunctionComponent() + val (y) = c +} + +fun test_2(c: InvokeComponent) { + val (x) = FunctionComponent() + val (y) = c +} diff --git a/compiler/testData/diagnostics/tests/operatorsOverloading/destructuringDeclarationWithInvoke.kt b/compiler/testData/diagnostics/tests/operatorsOverloading/destructuringDeclarationWithInvoke.kt index 2d8eae14a9d..a76f018146d 100644 --- a/compiler/testData/diagnostics/tests/operatorsOverloading/destructuringDeclarationWithInvoke.kt +++ b/compiler/testData/diagnostics/tests/operatorsOverloading/destructuringDeclarationWithInvoke.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // ISSUE: KT-59715 class FunctionComponent { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index baa16123f5f..87709c6b2bf 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -1023,6 +1023,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt"); } + @Test + @TestMetadata("OperatorConventions.kt") + public void testOperatorConventions() { + runTest("compiler/testData/diagnostics/tests/OperatorConventions.kt"); + } + @Test @TestMetadata("Operators.kt") public void testOperators() { diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.fir.kt index 24d9c3534e2..0d7f5a9772d 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.fir.kt @@ -25,7 +25,7 @@ fun case1() { } class B() { - val p: String by Delegate() // DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE expected + val p: String by Delegate() // DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE expected } class Delegate { @@ -50,7 +50,7 @@ fun case2() { } class B() { - var p: String by Delegate() // DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE expected + var p: String by Delegate() // DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE expected } class Delegate { @@ -109,14 +109,14 @@ class B() { fun case3() { var b = B() - b + 5 - b - 5 - b < 5 - b >= 5 - 1 in b - b[2] - b[3] = 4 - +b + b + 5 + b - 5 + b < 5 + b >= 5 + 1 in b + b[2] + b[3] = 4 + +b } // FILE: TestCase4.kt @@ -135,8 +135,8 @@ class B(val minusAssign: Assign = Assign()) { fun case3() { var b = B() - b += 2 - b -= 3 + b += 2 + b -= 3 } // FILE: TestCase5.kt @@ -175,7 +175,7 @@ class B(var a: Int = 0) { val plus :E =TODO() fun foo(b: B){ - this + 1 + this + 1 } operator fun invoke(value: Int) = B() @@ -193,7 +193,7 @@ package testPackCase7 fun case7 () { val iterable: Iterable = Iterable(Inv('s')) - for (i in iterable) { + for (i in iterable) { println(i) } } @@ -226,7 +226,7 @@ package testPackCase8 fun case8 () { val iterable: Iterable = Iterable() - for (i in iterable) { + for (i in iterable) { println(i) } } diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/pos/1.1.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/pos/1.1.fir.kt index 0fb22161b71..40ba31d22eb 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/pos/1.1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/pos/1.1.fir.kt @@ -29,7 +29,7 @@ class B() { fun case7(){ var b =B() b+=1 //ASSIGN_OPERATOR_AMBIGUITY - this += 1 //ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT, PROPERTY_AS_OPERATOR + this += 1 //ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT, PROPERTY_AS_OPERATOR } } diff --git a/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-cast-sink-stability/p-5/neg/1.1.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-cast-sink-stability/p-5/neg/1.1.fir.kt index b3e506a6197..215d8344b8d 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-cast-sink-stability/p-5/neg/1.1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/type-inference/smart-casts/smart-cast-sink-stability/p-5/neg/1.1.fir.kt @@ -25,7 +25,7 @@ class Case1() { fun foo(e: E) { if (e.plus != null) { - run { e + 1 } + run { e + 1 } /* [PROPERTY_AS_OPERATOR] (ok) @@ -33,7 +33,7 @@ class Case1() { [UNSAFE_OPERATOR_CALL] (nok) Operator call corresponds to a dot-qualified call 'e.plus(1)' which is not allowed on a nullable receiver 'e'. */ - e + 1 + e + 1 e.plus.invoke(1) //ok }