[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
This commit is contained in:
Ivan Kochurkin
2024-03-08 10:07:23 +00:00
committed by Space Team
parent df9d59851d
commit 2d4f4b9bb5
31 changed files with 440 additions and 100 deletions
@@ -4529,9 +4529,10 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, token,
) )
} }
add(FirErrors.PROPERTY_AS_OPERATOR) { firDiagnostic -> add(FirErrors.NOT_FUNCTION_AS_OPERATOR) { firDiagnostic ->
PropertyAsOperatorImpl( NotFunctionAsOperatorImpl(
firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firDiagnostic.a), firDiagnostic.a,
firSymbolBuilder.buildSymbol(firDiagnostic.b),
firDiagnostic as KtPsiDiagnostic, firDiagnostic as KtPsiDiagnostic,
token, token,
) )
@@ -3156,9 +3156,10 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
val operator: String val operator: String
} }
interface PropertyAsOperator : KtFirDiagnostic<PsiElement> { interface NotFunctionAsOperator : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = PropertyAsOperator::class override val diagnosticClass get() = NotFunctionAsOperator::class
val property: KtVariableSymbol val elementName: String
val elementSymbol: KtSymbol
} }
interface DslScopeViolation : KtFirDiagnostic<PsiElement> { interface DslScopeViolation : KtFirDiagnostic<PsiElement> {
@@ -3800,11 +3800,12 @@ internal class AssignmentOperatorShouldReturnUnitImpl(
token: KtLifetimeToken, token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtExpression>(firDiagnostic, token), KtFirDiagnostic.AssignmentOperatorShouldReturnUnit ) : KtAbstractFirDiagnostic<KtExpression>(firDiagnostic, token), KtFirDiagnostic.AssignmentOperatorShouldReturnUnit
internal class PropertyAsOperatorImpl( internal class NotFunctionAsOperatorImpl(
override val property: KtVariableSymbol, override val elementName: String,
override val elementSymbol: KtSymbol,
firDiagnostic: KtPsiDiagnostic, firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken, token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.PropertyAsOperator ) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.NotFunctionAsOperator
internal class DslScopeViolationImpl( internal class DslScopeViolationImpl(
override val calleeSymbol: KtSymbol, override val calleeSymbol: KtSymbol,
@@ -1023,6 +1023,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt"); runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt");
} }
@Test
@TestMetadata("OperatorConventions.kt")
public void testOperatorConventions() {
runTest("compiler/testData/diagnostics/tests/OperatorConventions.kt");
}
@Test @Test
@TestMetadata("Operators.kt") @TestMetadata("Operators.kt")
public void testOperators() { public void testOperators() {
@@ -1023,6 +1023,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt"); runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt");
} }
@Test
@TestMetadata("OperatorConventions.kt")
public void testOperatorConventions() {
runTest("compiler/testData/diagnostics/tests/OperatorConventions.kt");
}
@Test @Test
@TestMetadata("Operators.kt") @TestMetadata("Operators.kt")
public void testOperators() { public void testOperators() {
@@ -1023,6 +1023,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt"); runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt");
} }
@Test
@TestMetadata("OperatorConventions.kt")
public void testOperatorConventions() {
runTest("compiler/testData/diagnostics/tests/OperatorConventions.kt");
}
@Test @Test
@TestMetadata("Operators.kt") @TestMetadata("Operators.kt")
public void testOperators() { public void testOperators() {
@@ -1023,6 +1023,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt"); runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt");
} }
@Test
@TestMetadata("OperatorConventions.kt")
public void testOperatorConventions() {
runTest("compiler/testData/diagnostics/tests/OperatorConventions.kt");
}
@Test @Test
@TestMetadata("Operators.kt") @TestMetadata("Operators.kt")
public void testOperators() { public void testOperators() {
@@ -1585,8 +1585,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<FirNamedFunctionSymbol>("functionSymbol") parameter<FirNamedFunctionSymbol>("functionSymbol")
parameter<String>("operator") parameter<String>("operator")
} }
val PROPERTY_AS_OPERATOR by error<PsiElement>(PositioningStrategy.OPERATOR) { val NOT_FUNCTION_AS_OPERATOR by error<PsiElement>(PositioningStrategy.OPERATOR) {
parameter<FirPropertySymbol>("property") parameter<String>("elementName")
parameter<FirBasedSymbol<*>>("elementSymbol")
} }
val DSL_SCOPE_VIOLATION by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) { val DSL_SCOPE_VIOLATION by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
parameter<FirBasedSymbol<*>>("calleeSymbol") parameter<FirBasedSymbol<*>>("calleeSymbol")
@@ -796,7 +796,7 @@ object FirErrors {
val IMPLICIT_BOXING_IN_IDENTITY_EQUALS: KtDiagnosticFactory2<ConeKotlinType, ConeKotlinType> by warning2<KtElement, ConeKotlinType, ConeKotlinType>() val IMPLICIT_BOXING_IN_IDENTITY_EQUALS: KtDiagnosticFactory2<ConeKotlinType, ConeKotlinType> by warning2<KtElement, ConeKotlinType, ConeKotlinType>()
val INC_DEC_SHOULD_NOT_RETURN_UNIT: KtDiagnosticFactory0 by error0<KtExpression>(SourceElementPositioningStrategies.OPERATOR) val INC_DEC_SHOULD_NOT_RETURN_UNIT: KtDiagnosticFactory0 by error0<KtExpression>(SourceElementPositioningStrategies.OPERATOR)
val ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT: KtDiagnosticFactory2<FirNamedFunctionSymbol, String> by error2<KtExpression, FirNamedFunctionSymbol, String>(SourceElementPositioningStrategies.OPERATOR) val ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT: KtDiagnosticFactory2<FirNamedFunctionSymbol, String> by error2<KtExpression, FirNamedFunctionSymbol, String>(SourceElementPositioningStrategies.OPERATOR)
val PROPERTY_AS_OPERATOR: KtDiagnosticFactory1<FirPropertySymbol> by error1<PsiElement, FirPropertySymbol>(SourceElementPositioningStrategies.OPERATOR) val NOT_FUNCTION_AS_OPERATOR: KtDiagnosticFactory2<String, FirBasedSymbol<*>> by error2<PsiElement, String, FirBasedSymbol<*>>(SourceElementPositioningStrategies.OPERATOR)
val DSL_SCOPE_VIOLATION: KtDiagnosticFactory1<FirBasedSymbol<*>> by error1<PsiElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val DSL_SCOPE_VIOLATION: KtDiagnosticFactory1<FirBasedSymbol<*>> by error1<PsiElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
// Type alias // Type alias
@@ -533,7 +533,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = setOf(
"FORBIDDEN_IDENTITY_EQUALS", "FORBIDDEN_IDENTITY_EQUALS",
"INC_DEC_SHOULD_NOT_RETURN_UNIT", "INC_DEC_SHOULD_NOT_RETURN_UNIT",
"ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT", "ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT",
"PROPERTY_AS_OPERATOR", "NOT_FUNCTION_AS_OPERATOR",
"DSL_SCOPE_VIOLATION", "DSL_SCOPE_VIOLATION",
"TOPLEVEL_TYPEALIASES_ONLY", "TOPLEVEL_TYPEALIASES_ONLY",
"RECURSIVE_TYPEALIAS_EXPANSION", "RECURSIVE_TYPEALIAS_EXPANSION",
@@ -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.MppCheckerKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.*
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.references.FirErrorNamedReference 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.resolve.diagnostics.ConeUnresolvedNameError
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.ConeDynamicType 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.fir.types.resolvedType
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
object FirConventionFunctionCallChecker : FirFunctionCallChecker(MppCheckerKind.Common) { object FirConventionFunctionCallChecker : FirFunctionCallChecker(MppCheckerKind.Common) {
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) { 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. checkNotFunctionAsOperator(expression, expression.dispatchReceiver, context, reporter)
checkPropertyAsOperator(expression, expression.dispatchReceiver, context, reporter) checkNotFunctionAsOperator(expression, expression.extensionReceiver, context, reporter)
checkPropertyAsOperator(expression, expression.extensionReceiver, context, reporter)
val calleeReference = expression.calleeReference as? FirErrorNamedReference ?: return val calleeReference = expression.calleeReference as? FirErrorNamedReference ?: return
val diagnostic = calleeReference.diagnostic as? ConeUnresolvedNameError ?: return val diagnostic = calleeReference.diagnostic as? ConeUnresolvedNameError ?: return
@@ -39,7 +37,7 @@ object FirConventionFunctionCallChecker : FirFunctionCallChecker(MppCheckerKind.
} }
} }
private fun checkPropertyAsOperator( private fun checkNotFunctionAsOperator(
callExpression: FirFunctionCall, callExpression: FirFunctionCall,
receiver: FirExpression?, receiver: FirExpression?,
context: CheckerContext, context: CheckerContext,
@@ -47,9 +45,27 @@ object FirConventionFunctionCallChecker : FirFunctionCallChecker(MppCheckerKind.
) { ) {
if (callExpression.dispatchReceiver?.resolvedType is ConeDynamicType) return if (callExpression.dispatchReceiver?.resolvedType is ConeDynamicType) return
// KT-61905: TODO: Return also in case of error type. // KT-61905: TODO: Return also in case of error type.
val unwrapped = receiver?.unwrapSmartcastExpression() val unwrapped = receiver?.unwrapSmartcastExpression() ?: return
if (unwrapped !is FirPropertyAccessExpression) return val nonFatalDiagnostics = when (unwrapped) {
val diagnostic = unwrapped.nonFatalDiagnostics.firstIsInstanceOrNull<ConePropertyAsOperator>() ?: return is FirQualifiedAccessExpression -> unwrapped.nonFatalDiagnostics
reporter.reportOn(callExpression.calleeReference.source, FirErrors.PROPERTY_AS_OPERATOR, diagnostic.symbol, context) is FirResolvedQualifier -> unwrapped.nonFatalDiagnostics
else -> return
}
val diagnosticSymbol = nonFatalDiagnostics.firstIsInstanceOrNull<ConeNotFunctionAsOperator>()?.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
)
}
}
} }
} }
@@ -37,7 +37,6 @@ import org.jetbrains.kotlin.fir.resolve.calls.UnsafeCall
import org.jetbrains.kotlin.fir.resolve.diagnostics.* import org.jetbrains.kotlin.fir.resolve.diagnostics.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
object FirForLoopChecker : FirBlockChecker(MppCheckerKind.Common) { object FirForLoopChecker : FirBlockChecker(MppCheckerKind.Common) {
@@ -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_LOOP_LABEL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_MULTIPLATFORM_COMPILATION 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_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_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_NULL_ASSERTION_ON_LAMBDA_EXPRESSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_SUPPORTED_INLINE_PARAMETER_IN_INLINE_PARAMETER_DEFAULT_VALUE 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.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_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.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_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_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_NO_BACKING_FIELD import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_NO_BACKING_FIELD
@@ -2410,8 +2410,9 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
TO_STRING TO_STRING
) )
map.put( map.put(
PROPERTY_AS_OPERATOR, NOT_FUNCTION_AS_OPERATOR,
"Property ''{0}'' cannot be used as operator.", "{0} ''{1}'' cannot be used as operator.",
STRING,
SYMBOL SYMBOL
) )
map.put( map.put(
@@ -124,15 +124,12 @@ class CandidateFactory private constructor(
result.addDiagnostic(NoCompanionObject) result.addDiagnostic(NoCompanionObject)
} }
if (callInfo.origin == FirFunctionCallOrigin.Operator) { if (callInfo.origin == FirFunctionCallOrigin.Operator) {
val propertySymbol = when { val normalizedSymbol = when (symbol) {
symbol is FirPropertySymbol -> symbol !is FirFunctionSymbol -> symbol
callInfo.candidateForCommonInvokeReceiver != null -> callInfo.candidateForCommonInvokeReceiver.symbol as? FirPropertySymbol else -> callInfo.candidateForCommonInvokeReceiver?.symbol?.takeIf { it !is FirFunctionSymbol }
else -> null
}
if (propertySymbol != null) {
// Flag all property references that are resolved from an convention operator call.
result.addDiagnostic(PropertyAsOperator(propertySymbol))
} }
// Flag all references that are resolved from an convention operator call.
normalizedSymbol?.let { result.addDiagnostic(NotFunctionAsOperator(normalizedSymbol)) }
} }
if (symbol is FirPropertySymbol && if (symbol is FirPropertySymbol &&
!context.session.languageVersionSettings.supportsFeature(LanguageFeature.PrioritizedEnumEntries) !context.session.languageVersionSettings.supportsFeature(LanguageFeature.PrioritizedEnumEntries)
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.expressions.builder.FirPropertyAccessExpressionBuilder import org.jetbrains.kotlin.fir.expressions.builder.FirPropertyAccessExpressionBuilder
import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.* 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.symbols.impl.*
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind 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.AbstractTypeChecker
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.runIf
internal class FirInvokeResolveTowerExtension( internal class FirInvokeResolveTowerExtension(
private val context: ResolutionContext, private val context: ResolutionContext,
@@ -288,18 +289,26 @@ private fun BodyResolveComponents.createExplicitReceiverForInvoke(
invokeBuiltinExtensionMode: Boolean, invokeBuiltinExtensionMode: Boolean,
extensionReceiverExpression: FirExpression? extensionReceiverExpression: FirExpression?
): FirExpression? { ): FirExpression? {
val notFunctionAsOperatorDiagnostics = runIf (candidate.currentApplicability == CandidateApplicability.K2_NOT_FUNCTION_AS_OPERATOR) {
candidate.diagnostics.filterIsInstance<NotFunctionAsOperator>().map { ConeNotFunctionAsOperator(it.symbol) }
} ?: emptyList()
return when (val symbol = candidate.symbol) { return when (val symbol = candidate.symbol) {
is FirCallableSymbol<*> -> createExplicitReceiverForInvokeByCallable( is FirCallableSymbol<*> -> createExplicitReceiverForInvokeByCallable(
candidate, info, invokeBuiltinExtensionMode, extensionReceiverExpression, symbol candidate, info, invokeBuiltinExtensionMode, extensionReceiverExpression, symbol, notFunctionAsOperatorDiagnostics
) )
is FirRegularClassSymbol -> buildResolvedQualifierForClass( is FirRegularClassSymbol -> buildResolvedQualifierForClass(
symbol, symbol,
sourceElement = info.fakeSourceForImplicitInvokeCallReceiver sourceElement = info.fakeSourceForImplicitInvokeCallReceiver,
nonFatalDiagnostics = notFunctionAsOperatorDiagnostics,
) )
is FirTypeAliasSymbol -> { is FirTypeAliasSymbol -> {
val type = symbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>().fullyExpandedType(session) val type = symbol.fir.expandedTypeRef.coneTypeUnsafe<ConeClassLikeType>().fullyExpandedType(session)
val expansionRegularClassSymbol = type.lookupTag.toSymbol(session) ?: return null 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() else -> throw AssertionError()
} }
@@ -310,7 +319,8 @@ private fun BodyResolveComponents.createExplicitReceiverForInvokeByCallable(
info: CallInfo, info: CallInfo,
invokeBuiltinExtensionMode: Boolean, invokeBuiltinExtensionMode: Boolean,
extensionReceiverExpression: FirExpression?, extensionReceiverExpression: FirExpression?,
symbol: FirCallableSymbol<*> symbol: FirCallableSymbol<*>,
nonFatalDiagnostics: List<ConeNotFunctionAsOperator>,
): FirExpression { ): FirExpression {
return FirPropertyAccessExpressionBuilder().apply { return FirPropertyAccessExpressionBuilder().apply {
val fakeSource = info.fakeSourceForImplicitInvokeCallReceiver val fakeSource = info.fakeSourceForImplicitInvokeCallReceiver
@@ -337,9 +347,7 @@ private fun BodyResolveComponents.createExplicitReceiverForInvokeByCallable(
explicitReceiver = info.explicitReceiver explicitReceiver = info.explicitReceiver
} }
if (candidate.currentApplicability == CandidateApplicability.K2_PROPERTY_AS_OPERATOR) { this.nonFatalDiagnostics.addAll(nonFatalDiagnostics)
nonFatalDiagnostics.add(ConePropertyAsOperator(candidate.symbol as FirPropertySymbol))
}
candidate.updateSourcesOfReceivers() candidate.updateSourcesOfReceivers()
@@ -170,11 +170,11 @@ class FirCallCompletionResultsWriterTransformer(
qualifiedAccessExpression.replaceContextReceiverArguments(subCandidate.contextReceiverArguments()) qualifiedAccessExpression.replaceContextReceiverArguments(subCandidate.contextReceiverArguments())
subCandidate.diagnostics.firstIsInstanceOrNull<PropertyAsOperator>()?.let { propertyAsOperator -> subCandidate.diagnostics.firstIsInstanceOrNull<NotFunctionAsOperator>()?.let { propertyAsOperator ->
val conePropertyAsOperator = ConePropertyAsOperator(propertyAsOperator.propertySymbol) val coneNotFunctionAsOperator = ConeNotFunctionAsOperator(propertyAsOperator.symbol)
val nonFatalDiagnostics: List<ConeDiagnostic> = buildList { val nonFatalDiagnostics: List<ConeDiagnostic> = buildList {
addAll(qualifiedAccessExpression.nonFatalDiagnostics) addAll(qualifiedAccessExpression.nonFatalDiagnostics)
add(conePropertyAsOperator) add(coneNotFunctionAsOperator)
} }
qualifiedAccessExpression.replaceNonFatalDiagnostics(nonFatalDiagnostics) qualifiedAccessExpression.replaceNonFatalDiagnostics(nonFatalDiagnostics)
} }
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol 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.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeTypeVariable import org.jetbrains.kotlin.fir.types.ConeTypeVariable
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget 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 InferenceError(val constraintError: ConstraintSystemError) : ResolutionDiagnostic(constraintError.applicability)
class Unsupported(val message: String, val source: KtSourceElement?) : ResolutionDiagnostic(K2_UNSUPPORTED) 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) class DslScopeViolation(val calleeSymbol: FirBasedSymbol<*>) : ResolutionDiagnostic(RESOLVED_WITH_ERROR)
@@ -350,8 +350,8 @@ class ConeLocalVariableNoTypeOrInitializer(val variable: FirVariable) : ConeDiag
override val reason: String get() = "Cannot infer variable type without initializer / getter / delegate" override val reason: String get() = "Cannot infer variable type without initializer / getter / delegate"
} }
class ConePropertyAsOperator(val symbol: FirPropertySymbol) : ConeDiagnostic { class ConeNotFunctionAsOperator(val symbol: FirBasedSymbol<*>) : ConeDiagnostic {
override val reason: String get() = "Cannot use a property as an operator" override val reason: String get() = "Cannot use not function as an operator"
} }
class ConeUnknownLambdaParameterTypeDiagnostic : ConeDiagnostic { class ConeUnknownLambdaParameterTypeDiagnostic : ConeDiagnostic {
@@ -89,10 +89,10 @@ enum class CandidateApplicability {
RESOLVED_LOW_PRIORITY, 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. * 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. * Candidate is successful but uses new features that change resolve.
@@ -0,0 +1,130 @@
// ISSUE: KT-65881, KT-65760
class I: Iterator<Int> {
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 <!NOT_FUNCTION_AS_OPERATOR!>+=<!> 1 }
fun useMinusAssign() { A <!NOT_FUNCTION_AS_OPERATOR!>-=<!> 1 }
fun useTimesAssign() { A <!NOT_FUNCTION_AS_OPERATOR!>*=<!> 1 }
fun useDivAssign() { A <!NOT_FUNCTION_AS_OPERATOR!>/=<!> 1 }
fun useRemAssign() { A <!NOT_FUNCTION_AS_OPERATOR!>%=<!> 1 }
val useUnaryPlus = <!NOT_FUNCTION_AS_OPERATOR!>+<!>A
val useUnaryMinus = <!NOT_FUNCTION_AS_OPERATOR!>-<!>A
val useNot = <!NOT_FUNCTION_AS_OPERATOR!>!<!>A
val usePlus = A <!NOT_FUNCTION_AS_OPERATOR!>+<!> 1
val useMinus = A <!NOT_FUNCTION_AS_OPERATOR!>-<!> 1
val useTimes = A <!NOT_FUNCTION_AS_OPERATOR!>*<!> 1
val useDiv = A <!NOT_FUNCTION_AS_OPERATOR!>/<!> 1
val useRem = A <!NOT_FUNCTION_AS_OPERATOR!>%<!> 1
val useGet = <!NOT_FUNCTION_AS_OPERATOR!>A[1]<!>
fun useSet() { <!NOT_FUNCTION_AS_OPERATOR!>A[1]<!> = 3 }
val useContains = 1 <!NOT_FUNCTION_AS_OPERATOR!>in<!> A
val useNotContains = 1 <!NOT_FUNCTION_AS_OPERATOR, UNRESOLVED_REFERENCE!>!in<!> A
val useInvoke = <!UNRESOLVED_REFERENCE!>A<!>()
val useRangeTo = A <!NOT_FUNCTION_AS_OPERATOR!>..<!> 3
val useRangeUntil = A <!NOT_FUNCTION_AS_OPERATOR!>..<<!> 3
val useCompareTo = A <!NOT_FUNCTION_AS_OPERATOR!>><!> 2
fun useIterator() {
for (x in <!ITERATOR_MISSING!>A<!>) { }
}
fun useComponentN() {
val (x, y) = <!COMPONENT_FUNCTION_MISSING, COMPONENT_FUNCTION_MISSING!>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 <!DELEGATE_SPECIAL_FUNCTION_MISSING!>D<!>
var n by <!DELEGATE_SPECIAL_FUNCTION_MISSING, DELEGATE_SPECIAL_FUNCTION_MISSING!>D<!>
}
fun resolveToExtension() {
val (uwu) = X() // KT-65760
}
@@ -0,0 +1,130 @@
// ISSUE: KT-65881, KT-65760
class I: Iterator<Int> {
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 <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>+=<!> 1 }
fun useMinusAssign() { A <!RESOLUTION_TO_CLASSIFIER!>-=<!> 1 }
fun useTimesAssign() { A <!RESOLUTION_TO_CLASSIFIER!>*=<!> 1 }
fun useDivAssign() { A <!RESOLUTION_TO_CLASSIFIER!>/=<!> 1 }
fun useRemAssign() { A <!RESOLUTION_TO_CLASSIFIER!>%=<!> 1 }
val useUnaryPlus = <!RESOLUTION_TO_CLASSIFIER!>+<!>A
val useUnaryMinus = <!RESOLUTION_TO_CLASSIFIER!>-<!>A
val useNot = <!RESOLUTION_TO_CLASSIFIER!>!<!>A
val usePlus = A <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>+<!> 1
val useMinus = A <!RESOLUTION_TO_CLASSIFIER!>-<!> 1
val useTimes = A <!RESOLUTION_TO_CLASSIFIER!>*<!> 1
val useDiv = A <!RESOLUTION_TO_CLASSIFIER!>/<!> 1
val useRem = A <!RESOLUTION_TO_CLASSIFIER!>%<!> 1
val useGet = <!RESOLUTION_TO_CLASSIFIER!>A<!NO_GET_METHOD!>[1]<!><!>
fun useSet() { <!RESOLUTION_TO_CLASSIFIER!>A<!NO_SET_METHOD!>[1]<!><!> = 3 }
val useContains = 1 <!RESOLUTION_TO_CLASSIFIER!>in<!> A
val useNotContains = 1 <!RESOLUTION_TO_CLASSIFIER!>!in<!> A
val useInvoke = <!FUNCTION_EXPECTED!>A<!>()
val useRangeTo = A <!RESOLUTION_TO_CLASSIFIER!>..<!> 3
val useRangeUntil = A <!RESOLUTION_TO_CLASSIFIER!>..<<!> 3
val useCompareTo = A <!RESOLUTION_TO_CLASSIFIER!>><!> 2
fun useIterator() {
for (x in <!ITERATOR_MISSING!>A<!>) { }
}
fun useComponentN() {
val (x, y) = <!COMPONENT_FUNCTION_MISSING, COMPONENT_FUNCTION_MISSING!>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.<!EXTENSION_FUNCTION_SHADOWED_BY_MEMBER_PROPERTY_WITH_INVOKE!>component1<!>(): String = "Not UwU"
fun useDelegate() {
val m by D
var n by <!DELEGATE_SPECIAL_FUNCTION_MISSING!>D<!>
}
fun resolveToExtension() {
val (<!PROPERTY_AS_OPERATOR!>uwu<!>) = X() // KT-65760
}
@@ -12,11 +12,11 @@ val <X3> C<X3>.getValue: D<X3> get() = TODO()
operator fun <X4> D<X4>.invoke(x: Any?, y: Any?): X4 = TODO() operator fun <X4> D<X4>.invoke(x: Any?, y: Any?): X4 = TODO()
fun foo(a: A<String>, c: C<String>) { fun foo(a: A<String>, c: C<String>) {
val x1 by <!PROPERTY_AS_OPERATOR!>a<!> val x1 by <!NOT_FUNCTION_AS_OPERATOR!>a<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>x1<!> <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>x1<!>
x1.length x1.length
val y1 by <!PROPERTY_AS_OPERATOR!>c<!> val y1 by <!NOT_FUNCTION_AS_OPERATOR!>c<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>y1<!> <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>y1<!>
y1.length y1.length
} }
+6
View File
@@ -0,0 +1,6 @@
val Int.plusAssign: (Int) -> Unit
get() = {}
fun main() {
1 <!NOT_FUNCTION_AS_OPERATOR!>+=<!> 2
}
-2
View File
@@ -1,5 +1,3 @@
// FIR_IDENTICAL
val Int.plusAssign: (Int) -> Unit val Int.plusAssign: (Int) -> Unit
get() = {} get() = {}
@@ -10,25 +10,25 @@ class A { }
var a = A() var a = A()
val A.inc: I get() = I() val A.inc: I get() = I()
fun useInc() { a<!PROPERTY_AS_OPERATOR, RESULT_TYPE_MISMATCH!>++<!> } fun useInc() { a<!NOT_FUNCTION_AS_OPERATOR, RESULT_TYPE_MISMATCH!>++<!> }
val A.dec: I get() = I() val A.dec: I get() = I()
fun useDec() { a<!PROPERTY_AS_OPERATOR, RESULT_TYPE_MISMATCH!>--<!> } fun useDec() { a<!NOT_FUNCTION_AS_OPERATOR, RESULT_TYPE_MISMATCH!>--<!> }
val A.plusAssign: I get() = I() val A.plusAssign: I get() = I()
fun usePlusAssign() { a <!PROPERTY_AS_OPERATOR!>+=<!> 1 } fun usePlusAssign() { a <!NOT_FUNCTION_AS_OPERATOR!>+=<!> 1 }
val A.minusAssign: I get() = I() val A.minusAssign: I get() = I()
fun useMinusAssign() { a <!PROPERTY_AS_OPERATOR!>-=<!> 1 } fun useMinusAssign() { a <!NOT_FUNCTION_AS_OPERATOR!>-=<!> 1 }
val A.timesAssign: I get() = I() val A.timesAssign: I get() = I()
fun useTimesAssign() { a <!PROPERTY_AS_OPERATOR!>*=<!> 1 } fun useTimesAssign() { a <!NOT_FUNCTION_AS_OPERATOR!>*=<!> 1 }
val A.divAssign: I get() = I() val A.divAssign: I get() = I()
fun useDivAssign() { a <!PROPERTY_AS_OPERATOR!>/=<!> 1 } fun useDivAssign() { a <!NOT_FUNCTION_AS_OPERATOR!>/=<!> 1 }
val A.remAssign: I get() = I() val A.remAssign: I get() = I()
fun useRemAssign() { a <!PROPERTY_AS_OPERATOR!>%=<!> 1 } fun useRemAssign() { a <!NOT_FUNCTION_AS_OPERATOR!>%=<!> 1 }
// operators over values // operators over values
@@ -36,47 +36,47 @@ class E { }
val e = E() val e = E()
val E.unaryPlus: I get() = I() val E.unaryPlus: I get() = I()
val useUnaryPlus = <!PROPERTY_AS_OPERATOR!>+<!>e val useUnaryPlus = <!NOT_FUNCTION_AS_OPERATOR!>+<!>e
val E.unaryMinus: I get() = I() val E.unaryMinus: I get() = I()
val useUnaryMinus = <!PROPERTY_AS_OPERATOR!>-<!>e val useUnaryMinus = <!NOT_FUNCTION_AS_OPERATOR!>-<!>e
val E.not: I get() = I() val E.not: I get() = I()
val useNot = <!PROPERTY_AS_OPERATOR!>!<!>e val useNot = <!NOT_FUNCTION_AS_OPERATOR!>!<!>e
val E.plus: I get() = I() val E.plus: I get() = I()
val usePlus = e <!PROPERTY_AS_OPERATOR!>+<!> 1 val usePlus = e <!NOT_FUNCTION_AS_OPERATOR!>+<!> 1
val E.minus: I get() = I() val E.minus: I get() = I()
val useMinus = e <!PROPERTY_AS_OPERATOR!>-<!> 1 val useMinus = e <!NOT_FUNCTION_AS_OPERATOR!>-<!> 1
val E.times: I get() = I() val E.times: I get() = I()
val useTimes = e <!PROPERTY_AS_OPERATOR!>*<!> 1 val useTimes = e <!NOT_FUNCTION_AS_OPERATOR!>*<!> 1
val E.div: I get() = I() val E.div: I get() = I()
val useDiv = e <!PROPERTY_AS_OPERATOR!>/<!> 1 val useDiv = e <!NOT_FUNCTION_AS_OPERATOR!>/<!> 1
val E.rem: I get() = I() val E.rem: I get() = I()
val useRem = e <!PROPERTY_AS_OPERATOR!>%<!> 1 val useRem = e <!NOT_FUNCTION_AS_OPERATOR!>%<!> 1
val E.get: I get() = I() val E.get: I get() = I()
val useGet = <!PROPERTY_AS_OPERATOR!>e[1]<!> val useGet = <!NOT_FUNCTION_AS_OPERATOR!>e[1]<!>
val E.set: I get() = I() val E.set: I get() = I()
fun useSet() { <!PROPERTY_AS_OPERATOR!>e[1]<!> = 3 } fun useSet() { <!NOT_FUNCTION_AS_OPERATOR!>e[1]<!> = 3 }
val E.contains: I get() = I() val E.contains: I get() = I()
val useContains = 1 <!PROPERTY_AS_OPERATOR!>in<!> e val useContains = 1 <!NOT_FUNCTION_AS_OPERATOR!>in<!> e
val useNotContains = 1 <!PROPERTY_AS_OPERATOR, PROPERTY_AS_OPERATOR!>!in<!> e val useNotContains = 1 <!NOT_FUNCTION_AS_OPERATOR, NOT_FUNCTION_AS_OPERATOR!>!in<!> e
val E.invoke: I get() = I() val E.invoke: I get() = I()
val useInvoke = <!NONE_APPLICABLE!>e<!>() val useInvoke = <!NONE_APPLICABLE!>e<!>()
val E.rangeTo: I get() = I() val E.rangeTo: I get() = I()
val useRangeTo = e <!PROPERTY_AS_OPERATOR!>..<!> 3 val useRangeTo = e <!NOT_FUNCTION_AS_OPERATOR!>..<!> 3
val E.rangeUntil: I get() = I() val E.rangeUntil: I get() = I()
val useRangeUntil = e <!PROPERTY_AS_OPERATOR!>..<<!> 3 val useRangeUntil = e <!NOT_FUNCTION_AS_OPERATOR!>..<<!> 3
val E.compareTo: I get() = I() val E.compareTo: I get() = I()
val useCompareTo = e <!PROPERTY_AS_OPERATOR!>><!> 2 val useCompareTo = e <!NOT_FUNCTION_AS_OPERATOR!>><!> 2
@@ -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 (<!NOT_FUNCTION_AS_OPERATOR!>x<!>) = FunctionComponent()
val (<!NOT_FUNCTION_AS_OPERATOR!>y<!>) = c
}
fun test_2(c: InvokeComponent) {
val (<!NOT_FUNCTION_AS_OPERATOR!>x<!>) = FunctionComponent()
val (<!NOT_FUNCTION_AS_OPERATOR!>y<!>) = c
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// ISSUE: KT-59715 // ISSUE: KT-59715
class FunctionComponent { class FunctionComponent {
@@ -1023,6 +1023,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt"); runTest("compiler/testData/diagnostics/tests/OperatorChecks.kt");
} }
@Test
@TestMetadata("OperatorConventions.kt")
public void testOperatorConventions() {
runTest("compiler/testData/diagnostics/tests/OperatorConventions.kt");
}
@Test @Test
@TestMetadata("Operators.kt") @TestMetadata("Operators.kt")
public void testOperators() { public void testOperators() {
@@ -25,7 +25,7 @@ fun case1() {
} }
class B() { class B() {
val p: String by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, PROPERTY_AS_OPERATOR!>Delegate()<!> // DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE expected val p: String by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, NOT_FUNCTION_AS_OPERATOR!>Delegate()<!> // DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE expected
} }
class Delegate { class Delegate {
@@ -50,7 +50,7 @@ fun case2() {
} }
class B() { class B() {
var p: String by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, PROPERTY_AS_OPERATOR, PROPERTY_AS_OPERATOR!>Delegate()<!> // DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE expected var p: String by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, NOT_FUNCTION_AS_OPERATOR, NOT_FUNCTION_AS_OPERATOR!>Delegate()<!> // DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE expected
} }
class Delegate { class Delegate {
@@ -109,14 +109,14 @@ class B() {
fun case3() { fun case3() {
var b = B() var b = B()
b <!PROPERTY_AS_OPERATOR!>+<!> 5 b <!NOT_FUNCTION_AS_OPERATOR!>+<!> 5
b <!PROPERTY_AS_OPERATOR!>-<!> 5 b <!NOT_FUNCTION_AS_OPERATOR!>-<!> 5
b <!PROPERTY_AS_OPERATOR!><<!> 5 b <!NOT_FUNCTION_AS_OPERATOR!><<!> 5
b <!PROPERTY_AS_OPERATOR!>>=<!> 5 b <!NOT_FUNCTION_AS_OPERATOR!>>=<!> 5
1 <!PROPERTY_AS_OPERATOR!>in<!> b 1 <!NOT_FUNCTION_AS_OPERATOR!>in<!> b
<!PROPERTY_AS_OPERATOR!>b[2]<!> <!NOT_FUNCTION_AS_OPERATOR!>b[2]<!>
<!PROPERTY_AS_OPERATOR!>b[3]<!> = 4 <!NOT_FUNCTION_AS_OPERATOR!>b[3]<!> = 4
<!PROPERTY_AS_OPERATOR!>+<!>b <!NOT_FUNCTION_AS_OPERATOR!>+<!>b
} }
// FILE: TestCase4.kt // FILE: TestCase4.kt
@@ -135,8 +135,8 @@ class B(val minusAssign: Assign = Assign()) {
fun case3() { fun case3() {
var b = B() var b = B()
b <!PROPERTY_AS_OPERATOR!>+=<!> 2 b <!NOT_FUNCTION_AS_OPERATOR!>+=<!> 2
b <!PROPERTY_AS_OPERATOR!>-=<!> 3 b <!NOT_FUNCTION_AS_OPERATOR!>-=<!> 3
} }
// FILE: TestCase5.kt // FILE: TestCase5.kt
@@ -175,7 +175,7 @@ class B(var a: Int = 0) {
val plus :E =TODO() val plus :E =TODO()
fun foo(b: B){ fun foo(b: B){
this <!PROPERTY_AS_OPERATOR!>+<!> 1 this <!NOT_FUNCTION_AS_OPERATOR!>+<!> 1
} }
operator fun invoke(value: Int) = B() operator fun invoke(value: Int) = B()
@@ -193,7 +193,7 @@ package testPackCase7
fun case7 () { fun case7 () {
val iterable: Iterable = Iterable(Inv('s')) val iterable: Iterable = Iterable(Inv('s'))
for (i in <!PROPERTY_AS_OPERATOR!>iterable<!>) { for (i in <!NOT_FUNCTION_AS_OPERATOR!>iterable<!>) {
println(i) println(i)
} }
} }
@@ -226,7 +226,7 @@ package testPackCase8
fun case8 () { fun case8 () {
val iterable: Iterable = Iterable() val iterable: Iterable = Iterable()
for (i in <!PROPERTY_AS_OPERATOR!>iterable<!>) { for (i in <!NOT_FUNCTION_AS_OPERATOR!>iterable<!>) {
println(i) println(i)
} }
} }
@@ -29,7 +29,7 @@ class B() {
fun case7(){ fun case7(){
var b =B() var b =B()
b<!ASSIGN_OPERATOR_AMBIGUITY!>+=<!>1 //ASSIGN_OPERATOR_AMBIGUITY b<!ASSIGN_OPERATOR_AMBIGUITY!>+=<!>1 //ASSIGN_OPERATOR_AMBIGUITY
this <!PROPERTY_AS_OPERATOR!>+=<!> 1 //ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT, PROPERTY_AS_OPERATOR this <!NOT_FUNCTION_AS_OPERATOR!>+=<!> 1 //ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT, PROPERTY_AS_OPERATOR
} }
} }
@@ -25,7 +25,7 @@ class Case1() {
fun foo(e: E) { fun foo(e: E) {
if (e.plus != null) { if (e.plus != null) {
run { e <!PROPERTY_AS_OPERATOR!>+<!> 1 } run { e <!NOT_FUNCTION_AS_OPERATOR!>+<!> 1 }
/* /*
[PROPERTY_AS_OPERATOR] (ok) [PROPERTY_AS_OPERATOR] (ok)
@@ -33,7 +33,7 @@ class Case1() {
[UNSAFE_OPERATOR_CALL] (nok) [UNSAFE_OPERATOR_CALL] (nok)
Operator call corresponds to a dot-qualified call 'e.plus(1)' which is not allowed on a nullable receiver 'e'. Operator call corresponds to a dot-qualified call 'e.plus(1)' which is not allowed on a nullable receiver 'e'.
*/ */
e <!PROPERTY_AS_OPERATOR!>+<!> 1 e <!NOT_FUNCTION_AS_OPERATOR!>+<!> 1
e.plus.invoke(1) //ok e.plus.invoke(1) //ok
} }