From 05fbed68e2220d8465d3e90f7e956bc752195f4a Mon Sep 17 00:00:00 2001 From: Tianyu Geng Date: Tue, 31 Aug 2021 16:57:18 -0700 Subject: [PATCH] FIR checker: report PROPERTY_AS_OPERATOR --- .../diagnostics/FirDiagnosticsList.kt | 3 ++ .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../FirConventionFunctionCallChecker.kt | 29 ++++++++++++++ .../diagnostics/FirDefaultErrorMessages.kt | 6 +++ .../jetbrains/kotlin/fir/FirCallResolver.kt | 8 ++-- .../kotlin/fir/resolve/calls/Candidate.kt | 4 +- .../fir/resolve/calls/CandidateFactory.kt | 4 ++ .../fir/resolve/calls/ResolutionDiagnostic.kt | 4 +- .../tower/FirInvokeResolveTowerExtension.kt | 11 ++++-- .../fir/resolve/diagnostics/FirDiagnostics.kt | 4 ++ ...rCallCompletionResultsWriterTransformer.kt | 7 ++++ .../calls/tower/CandidateApplicability.kt | 1 + .../testData/diagnostics/tests/kt34857.fir.kt | 8 ---- .../testData/diagnostics/tests/kt34857.kt | 1 + .../operator-call/p-4/neg/1.1.fir.kt | 39 +++++++++++++++---- .../operator-call/p-4/neg/1.1.kt | 25 ++++++++++++ .../operator-call/p-4/pos/1.1.fir.kt | 2 +- .../p-5/neg/1.1.fir.kt | 4 +- .../diagnostics/KtFirDataClassConverters.kt | 7 ++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 5 +++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 8 ++++ 21 files changed, 154 insertions(+), 27 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/kt34857.fir.kt 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 b9ac3edd237..00035535dca 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 @@ -1145,6 +1145,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { parameter("functionSymbol") parameter("operator") } + val PROPERTY_AS_OPERATOR by error(PositioningStrategy.OPERATOR) { + parameter("property") + } } val TYPE_ALIAS by object : DiagnosticGroup("Type alias") { 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 7573c37cdfc..f91f018db98 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 @@ -596,6 +596,7 @@ object FirErrors { val INCOMPATIBLE_ENUM_COMPARISON_ERROR by error2() val INC_DEC_SHOULD_NOT_RETURN_UNIT by error0(SourceElementPositioningStrategies.OPERATOR) val ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT by error2(SourceElementPositioningStrategies.OPERATOR) + val PROPERTY_AS_OPERATOR by error1(SourceElementPositioningStrategies.OPERATOR) // Type alias val TOPLEVEL_TYPEALIASES_ONLY by error0() 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 a1c61322773..e8019bb59f7 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 @@ -6,17 +6,26 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression import org.jetbrains.kotlin.fir.FirFakeSourceElementKind +import org.jetbrains.kotlin.fir.FirRealSourceElementKind import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast import org.jetbrains.kotlin.fir.expressions.FirFunctionCall +import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression import org.jetbrains.kotlin.fir.references.FirErrorNamedReference +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConePropertyAsOperator import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError import org.jetbrains.kotlin.util.OperatorNameConventions +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull object FirConventionFunctionCallChecker : FirFunctionCallChecker() { 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) val calleeReference = expression.calleeReference as? FirErrorNamedReference ?: return val diagnostic = calleeReference.diagnostic as? ConeUnresolvedNameError ?: return @@ -27,4 +36,24 @@ object FirConventionFunctionCallChecker : FirFunctionCallChecker() { } } } + + private fun checkPropertyAsOperator( + callExpression: FirFunctionCall, + receiver: FirExpression, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + val sourceKind = callExpression.source?.kind + if (sourceKind !is FirRealSourceElementKind && + sourceKind !is FirFakeSourceElementKind.GeneratedComparisonExpression && + sourceKind !is FirFakeSourceElementKind.DesugaredCompoundAssignment + ) return + val unwrapped = when (receiver) { + is FirExpressionWithSmartcast -> receiver.originalExpression + else -> receiver + } + if (unwrapped !is FirPropertyAccessExpression) return + val diagnostic = unwrapped.nonFatalDiagnostics.firstIsInstanceOrNull() ?: return + reporter.reportOn(callExpression.calleeReference.source, FirErrors.PROPERTY_AS_OPERATOR, diagnostic.symbol, context) + } } 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 933e24b33b1..0492d566bd2 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 @@ -332,6 +332,7 @@ 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_INITIALIZER_IN_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_NO_BACKING_FIELD import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_TYPE_MISMATCH_BY_DELEGATION @@ -1515,6 +1516,11 @@ class FirDefaultErrorMessages { SYMBOL, TO_STRING ) + map.put( + PROPERTY_AS_OPERATOR, + "Property ''{0}'' cannot be used as an operator.", + SYMBOL + ) // Type alias map.put(TOPLEVEL_TYPEALIASES_ONLY, "Nested and local type aliases are not supported") diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 62b531d0b36..841802f1f93 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -84,11 +84,11 @@ class FirCallResolver( return components.context.withIncrementedQualifierPartIndex { val name = functionCall.calleeReference.name - val result = collectCandidates(functionCall, name) + val result = collectCandidates(functionCall, name, origin = functionCall.origin) var forceCandidates: Collection? = null if (result.candidates.isEmpty()) { - val newResult = collectCandidates(functionCall, name, CallKind.VariableAccess) + val newResult = collectCandidates(functionCall, name, CallKind.VariableAccess, origin = functionCall.origin) if (newResult.candidates.isNotEmpty()) { forceCandidates = newResult.candidates } @@ -152,7 +152,8 @@ class FirCallResolver( private fun collectCandidates( qualifiedAccess: T, name: Name, - forceCallKind: CallKind? = null + forceCallKind: CallKind? = null, + origin: FirFunctionCallOrigin = FirFunctionCallOrigin.Regular ): ResolutionResult { val explicitReceiver = qualifiedAccess.explicitReceiver val argumentList = (qualifiedAccess as? FirFunctionCall)?.argumentList ?: FirEmptyArgumentList @@ -172,6 +173,7 @@ class FirCallResolver( session, components.file, transformer.components.containingDeclarations, + origin = origin ) towerResolver.reset() val result = towerResolver.runResolver(info, transformer.resolutionContext) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt index f1725de1062..fcb598fa040 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.expressions.FirArgumentList import org.jetbrains.kotlin.fir.expressions.FirEmptyArgumentList import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.FirFunctionCallOrigin import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression @@ -55,7 +56,8 @@ data class CallInfo( // Four properties for callable references only val expectedType: ConeKotlinType? = null, val outerCSBuilder: ConstraintSystemBuilder? = null, - val lhs: DoubleColonLHS? = null + val lhs: DoubleColonLHS? = null, + val origin: FirFunctionCallOrigin = FirFunctionCallOrigin.Regular, ) { val arguments: List get() = argumentList.arguments 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 a5d72c992c7..0e008d9c4e7 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 @@ -82,6 +82,10 @@ class CandidateFactory private constructor( ) { result.addDiagnostic(NoCompanionObject) } + if (callInfo.origin == FirFunctionCallOrigin.Operator && symbol is FirPropertySymbol) { + // Flag all property references that are resolved from an convention operator call. + result.addDiagnostic(PropertyAsOperator) + } return result } 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 a2360c2b676..b4347a4afb8 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 @@ -98,4 +98,6 @@ class ManyLambdaExpressionArguments( class InfixCallOfNonInfixFunction(val function: FirNamedFunctionSymbol) : ResolutionDiagnostic(INAPPLICABLE_MODIFIER) class OperatorCallOfNonOperatorFunction(val function: FirNamedFunctionSymbol) : ResolutionDiagnostic(INAPPLICABLE_MODIFIER) -class Unsupported(val message: String, val source: FirSourceElement? = null) : ResolutionDiagnostic(UNSUPPORTED) \ No newline at end of file +class Unsupported(val message: String, val source: FirSourceElement? = null) : ResolutionDiagnostic(UNSUPPORTED) + +object PropertyAsOperator : ResolutionDiagnostic(PROPERTY_AS_OPERATOR) \ No newline at end of file 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 4915ac9d3ad..c1c78a37922 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 @@ -11,14 +11,13 @@ 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.symbols.impl.FirCallableSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConePropertyAsOperator +import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.coneTypeUnsafe import org.jetbrains.kotlin.fir.types.isExtensionFunctionType import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.util.OperatorNameConventions internal class FirInvokeResolveTowerExtension( @@ -291,6 +290,10 @@ private fun BodyResolveComponents.createExplicitReceiverForInvokeByCallable( // NB: this should fix problem in DFA (KT-36014) explicitReceiver = info.explicitReceiver } + + if (candidate.currentApplicability == CandidateApplicability.PROPERTY_AS_OPERATOR) { + nonFatalDiagnostics.add(ConePropertyAsOperator(candidate.symbol as FirPropertySymbol)) + } }.build().let(::transformQualifiedAccessUsingSmartcastInfo) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt index b1005f1bc65..9279ae0a831 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt @@ -206,6 +206,10 @@ 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" +} + private fun describeSymbol(symbol: FirBasedSymbol<*>): String { return when (symbol) { is FirClassLikeSymbol<*> -> symbol.classId.asString() 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 c2d8dc639db..87ec8a0f1ad 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 @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isSuspend import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.expressions.impl.FirPropertyAccessExpressionImpl import org.jetbrains.kotlin.fir.references.FirNamedReference import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference import org.jetbrains.kotlin.fir.references.builder.buildResolvedCallableReference @@ -26,6 +27,7 @@ import org.jetbrains.kotlin.fir.resolve.createFunctionalType import org.jetbrains.kotlin.fir.resolve.dfa.FirDataFlowAnalyzer import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeConstraintSystemHasContradiction import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConePropertyAsOperator import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeTypeParameterInQualifiedAccess import org.jetbrains.kotlin.fir.resolve.firProvider import org.jetbrains.kotlin.fir.resolve.inference.* @@ -39,6 +41,7 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall 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.* import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef @@ -48,6 +51,7 @@ import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.transformSingle +import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.resolve.calls.tower.isSuccess import org.jetbrains.kotlin.types.TypeApproximatorConfiguration import org.jetbrains.kotlin.types.Variance @@ -126,6 +130,9 @@ class FirCallCompletionResultsWriterTransformer( ) .transformDispatchReceiver(StoreReceiver, subCandidate.dispatchReceiverExpression()) .transformExtensionReceiver(StoreReceiver, subCandidate.extensionReceiverExpression()) as T + if (result is FirPropertyAccessExpressionImpl && calleeReference.candidate.currentApplicability == CandidateApplicability.PROPERTY_AS_OPERATOR) { + result.nonFatalDiagnostics.add(ConePropertyAsOperator(calleeReference.candidate.symbol as FirPropertySymbol)) + } if (result is FirQualifiedAccessExpression) { result.replaceTypeRef(typeRef) 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 4ae77c63086..c81d1f33e36 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 @@ -20,6 +20,7 @@ enum class CandidateApplicability { UNSTABLE_SMARTCAST, // unstable smart cast CONVENTION_ERROR, // missing infix, operator etc RESOLVED_LOW_PRIORITY, + PROPERTY_AS_OPERATOR, // using property of functional type as an operator. From resolution perspective, this is considered successful. RESOLVED_NEED_PRESERVE_COMPATIBILITY, // call resolved successfully, but using new features that changes resolve RESOLVED_WITH_ERROR, // call has error, but it is still successful from resolution perspective RESOLVED, // call success or has uncompleted inference or in other words possible successful candidate diff --git a/compiler/testData/diagnostics/tests/kt34857.fir.kt b/compiler/testData/diagnostics/tests/kt34857.fir.kt deleted file mode 100644 index 8dfdc63b29b..00000000000 --- a/compiler/testData/diagnostics/tests/kt34857.fir.kt +++ /dev/null @@ -1,8 +0,0 @@ -// !LANGUAGE: +NewInference - -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 a71121f8a49..3aed427fd0b 100644 --- a/compiler/testData/diagnostics/tests/kt34857.kt +++ b/compiler/testData/diagnostics/tests/kt34857.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +NewInference val Int.plusAssign: (Int) -> Unit 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 44e1bf2e480..2296bc7cf31 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 @@ -73,19 +73,44 @@ class Arifm() { operator fun invoke(i: Int) {} } +class Contains() { + operator fun invoke(i: Int): Boolean = true +} + +class Getter() { + operator fun invoke(i: Int): Int = 1 +} + +class Setter() { + operator fun invoke(i: Int, j: Int) {} +} + +class Unary() { + operator fun invoke(): B = TODO() +} + class B() { val plus = Arifm() val minus = Arifm() val compareTo = Comp() + val contains = Contains() + val get = Getter() + val set = Setter() + val unaryPlus = Unary() } fun case3() { var b = B() - b + 5 - b - 5 - b < 5 - b >= 5 + b + 5 + b - 5 + b < 5 + b >= 5 + 1 in b + b[2] + b[3] = 4 + +b } + // FILE: TestCase4.kt /* * TESTCASE NUMBER: 4 @@ -102,8 +127,8 @@ class B(val minusAssign: Assign = Assign()) { fun case3() { var b = B() - b += 2 - b -= 3 + b += 2 + b -= 3 } // FILE: TestCase5.kt @@ -142,7 +167,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() diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.kt index 7f182460a76..519e16397b7 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-4/neg/1.1.kt @@ -82,10 +82,30 @@ class Arifm() { operator fun invoke(i: Int) {} } +class Contains() { + operator fun invoke(i: Int): Boolean = true +} + +class Getter() { + operator fun invoke(i: Int): Int = 1 +} + +class Setter() { + operator fun invoke(i: Int, j: Int) {} +} + +class Unary() { + operator fun invoke(): B = TODO() +} + class B() { val plus = Arifm() val minus = Arifm() val compareTo = Comp() + val contains = Contains() + val get = Getter() + val set = Setter() + val unaryPlus = Unary() } fun case3() { @@ -94,7 +114,12 @@ fun case3() { b - 5 b < 5 b >= 5 + 1 in b + b[2] + b[3] = 4 + +b } + // FILE: TestCase4.kt /* * TESTCASE NUMBER: 4 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 225c4466912..89339c58e49 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 @@ -21,7 +21,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 a01a89109b5..1eb3b12d652 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 @@ -14,7 +14,7 @@ class Case1() { fun foo(e: E) { if (e.plus != null) { - run { e + 1 } + run { e + 1 } /* [PROPERTY_AS_OPERATOR] (ok) @@ -22,7 +22,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 } 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 3cc4bfb97fe..d98f383a8a9 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 @@ -3131,6 +3131,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.PROPERTY_AS_OPERATOR) { firDiagnostic -> + PropertyAsOperatorImpl( + firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firDiagnostic.a.fir), + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.TOPLEVEL_TYPEALIASES_ONLY) { firDiagnostic -> ToplevelTypealiasesOnlyImpl( 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 d6d573203dc..2bda53b9ab8 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 @@ -2186,6 +2186,11 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val operator: String } + abstract class PropertyAsOperator : KtFirDiagnostic() { + override val diagnosticClass get() = PropertyAsOperator::class + abstract val property: KtVariableSymbol + } + abstract class ToplevelTypealiasesOnly : KtFirDiagnostic() { override val diagnosticClass get() = ToplevelTypealiasesOnly::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 f0ffc5bc926..62481d3ed33 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 @@ -3522,6 +3522,14 @@ internal class AssignmentOperatorShouldReturnUnitImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class PropertyAsOperatorImpl( + override val property: KtVariableSymbol, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.PropertyAsOperator(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class ToplevelTypealiasesOnlyImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken,