diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java index d9403b67808..702b16ee41b 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java @@ -1083,6 +1083,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/extensionInvokeAfterSafeCall.kt"); } + @Test + @TestMetadata("incorrectPlusOperatorFromJava.kt") + public void testIncorrectPlusOperatorFromJava() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/incorrectPlusOperatorFromJava.kt"); + } + @Test @TestMetadata("invokeAmbiguity.kt") public void testInvokeAmbiguity() throws Exception { diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index 2e14b330d35..ec31a923992 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -933,6 +933,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/extensionInvokeAfterSafeCall.kt"); } + @TestMetadata("incorrectPlusOperatorFromJava.kt") + public void testIncorrectPlusOperatorFromJava() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/incorrectPlusOperatorFromJava.kt"); + } + @TestMetadata("invokeAmbiguity.kt") public void testInvokeAmbiguity() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/invokeAmbiguity.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/callResolution/incorrectPlusOperatorFromJava.fir.txt b/compiler/fir/analysis-tests/testData/resolve/callResolution/incorrectPlusOperatorFromJava.fir.txt new file mode 100644 index 00000000000..90a31707c26 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/callResolution/incorrectPlusOperatorFromJava.fir.txt @@ -0,0 +1,20 @@ +FILE: main.kt + public final operator fun R|Base|.plus(s: R|kotlin/String|): R|kotlin/Int| { + ^plus Int(0) + } + public final class Derived : R|Base| { + public constructor(): R|Derived| { + super() + } + + public final fun test_1(x: R|Base|): R|kotlin/Unit| { + lval y: R|kotlin/Int| = R|/x|.R|/plus|(String()) + R|/y|.R|kotlin/Int.inc|() + } + + public final fun test_2(x: R|Base|): R|kotlin/Unit| { + lval y: R|kotlin/String!| = R|/x|.R|/Base.plus|(vararg(String())) + R|/y|.R|kotlin/String.length| + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/callResolution/incorrectPlusOperatorFromJava.kt b/compiler/fir/analysis-tests/testData/resolve/callResolution/incorrectPlusOperatorFromJava.kt new file mode 100644 index 00000000000..e7f71210095 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/callResolution/incorrectPlusOperatorFromJava.kt @@ -0,0 +1,22 @@ +// ISSUE: KT-56875 +// FILE: Base.java +public class Base { + public String plus(String... strings) { // (1) + return ""; + } +} + +// FILE: main.kt +operator fun Base.plus(s: String): Int = 0 // (2) + +class Derived : Base() { + fun test_1(x: Base) { + val y = x + "" // should resolve to (2) + y.inc() // should be ok + } + + fun test_2(x: Base) { + val y = x.plus("") // should resolve to (1) + y.length // should be ok + } +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java index 91619d30583..8cf933e6fe6 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java @@ -1083,6 +1083,12 @@ public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDi runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/extensionInvokeAfterSafeCall.kt"); } + @Test + @TestMetadata("incorrectPlusOperatorFromJava.kt") + public void testIncorrectPlusOperatorFromJava() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/incorrectPlusOperatorFromJava.kt"); + } + @Test @TestMetadata("invokeAmbiguity.kt") public void testInvokeAmbiguity() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java index 049ba02f714..67618dd82ea 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java @@ -1083,6 +1083,12 @@ public class FirPsiDiagnosticTestGenerated extends AbstractFirPsiDiagnosticTest runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/extensionInvokeAfterSafeCall.kt"); } + @Test + @TestMetadata("incorrectPlusOperatorFromJava.kt") + public void testIncorrectPlusOperatorFromJava() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/incorrectPlusOperatorFromJava.kt"); + } + @Test @TestMetadata("invokeAmbiguity.kt") public void testInvokeAmbiguity() throws Exception { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt index 563231b1f94..bb4a1a0fe81 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt @@ -189,20 +189,7 @@ fun FirNamedFunctionSymbol.overriddenFunctions( containingClass: FirClassSymbol<*>, context: CheckerContext ): List> { - val firTypeScope = containingClass.unsubstitutedScope( - context.sessionHolder.session, - context.sessionHolder.scopeSession, - withForcedTypeCalculator = true - ) - - val overriddenFunctions = mutableListOf>() - firTypeScope.processFunctionsByName(callableId.callableName) { } - firTypeScope.processOverriddenFunctions(this) { - overriddenFunctions.add(it) - ProcessorAction.NEXT - } - - return overriddenFunctions + return overriddenFunctions(containingClass, context.session, context.scopeSession) } fun FirClass.collectSupertypesWithDelegates(): Map { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt index aa03929928f..08099aeb133 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/context/CheckerContext.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.resolve.ImplicitReceiverStack +import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.SessionHolder import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator @@ -47,6 +48,9 @@ abstract class CheckerContext : DiagnosticContext { val session: FirSession get() = sessionHolder.session + val scopeSession: ScopeSession + get() = sessionHolder.scopeSession + override fun isDiagnosticSuppressed(diagnostic: KtDiagnostic): Boolean { val factory = diagnostic.factory val name = factory.name diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOperatorModifierChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOperatorModifierChecker.kt index 67610e6fc9c..f6559a2d9c4 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOperatorModifierChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirOperatorModifierChecker.kt @@ -9,49 +9,16 @@ import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext -import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.Returns -import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.ValueParametersCount -import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.isKProperty -import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.member -import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.memberOrExtension -import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.noDefaultAndVarargs import org.jetbrains.kotlin.fir.analysis.checkers.hasModifier -import org.jetbrains.kotlin.fir.analysis.checkers.isSupertypeOf -import org.jetbrains.kotlin.fir.analysis.checkers.overriddenFunctions import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors -import org.jetbrains.kotlin.fir.containingClassLookupTag +import org.jetbrains.kotlin.fir.declarations.CheckResult import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction -import org.jetbrains.kotlin.fir.declarations.utils.isInline +import org.jetbrains.kotlin.fir.declarations.OperatorFunctionChecks import org.jetbrains.kotlin.fir.declarations.utils.isOperator -import org.jetbrains.kotlin.fir.resolve.defaultType -import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol -import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.name.isSubpackageOf import org.jetbrains.kotlin.util.OperatorNameConventions -import org.jetbrains.kotlin.util.OperatorNameConventions.ASSIGNMENT_OPERATIONS -import org.jetbrains.kotlin.util.OperatorNameConventions.BINARY_OPERATION_NAMES -import org.jetbrains.kotlin.util.OperatorNameConventions.COMPARE_TO -import org.jetbrains.kotlin.util.OperatorNameConventions.COMPONENT_REGEX -import org.jetbrains.kotlin.util.OperatorNameConventions.CONTAINS -import org.jetbrains.kotlin.util.OperatorNameConventions.DEC -import org.jetbrains.kotlin.util.OperatorNameConventions.EQUALS -import org.jetbrains.kotlin.util.OperatorNameConventions.GET -import org.jetbrains.kotlin.util.OperatorNameConventions.GET_VALUE -import org.jetbrains.kotlin.util.OperatorNameConventions.HAS_NEXT -import org.jetbrains.kotlin.util.OperatorNameConventions.INC -import org.jetbrains.kotlin.util.OperatorNameConventions.INVOKE -import org.jetbrains.kotlin.util.OperatorNameConventions.ITERATOR -import org.jetbrains.kotlin.util.OperatorNameConventions.NEXT -import org.jetbrains.kotlin.util.OperatorNameConventions.PROVIDE_DELEGATE -import org.jetbrains.kotlin.util.OperatorNameConventions.RANGE_TO -import org.jetbrains.kotlin.util.OperatorNameConventions.RANGE_UNTIL -import org.jetbrains.kotlin.util.OperatorNameConventions.SET -import org.jetbrains.kotlin.util.OperatorNameConventions.SET_VALUE -import org.jetbrains.kotlin.util.OperatorNameConventions.SIMPLE_UNARY_OPERATION_NAMES object FirOperatorModifierChecker : FirSimpleFunctionChecker() { @@ -61,18 +28,14 @@ object FirOperatorModifierChecker : FirSimpleFunctionChecker() { //we are not interested in implicit operators from override if (!declaration.hasModifier(KtTokens.OPERATOR_KEYWORD)) return - val checks = OperatorFunctionChecks.checksByName.getOrElse(declaration.name) { - OperatorFunctionChecks.regexChecks.find { it.first.matches(declaration.name.asString()) }?.second - } - - if (checks == null) { - reporter.reportOn(declaration.source, FirErrors.INAPPLICABLE_OPERATOR_MODIFIER, "illegal function name", context) - return - } - - for (check in checks) { - check.check(context, declaration)?.let { error -> - reporter.reportOn(declaration.source, FirErrors.INAPPLICABLE_OPERATOR_MODIFIER, error, context) + when (val checkResult = OperatorFunctionChecks.isOperator(declaration, context.session, context.scopeSession)) { + CheckResult.SuccessCheck -> {} + CheckResult.IllegalFunctionName -> { + reporter.reportOn(declaration.source, FirErrors.INAPPLICABLE_OPERATOR_MODIFIER, "illegal function name", context) + return + } + is CheckResult.IllegalSignature -> { + reporter.reportOn(declaration.source, FirErrors.INAPPLICABLE_OPERATOR_MODIFIER, checkResult.error, context) return } } @@ -95,159 +58,3 @@ object FirOperatorModifierChecker : FirSimpleFunctionChecker() { reporter.reportOn(declaration.source, diagnostic, declaration.symbol, replacement.asString(), context) } } - -private interface Check : (CheckerContext, FirSimpleFunction) -> String? { - override fun invoke(p1: CheckerContext, p2: FirSimpleFunction): String? { - return check(p1, p2) - } - - fun check(context: CheckerContext, function: FirSimpleFunction): String? -} - -private object Checks { - fun simple(message: String, predicate: (FirSimpleFunction) -> Boolean) = object : Check { - override fun check(context: CheckerContext, function: FirSimpleFunction): String? = message.takeIf { !predicate(function) } - } - - fun full(message: String, predicate: (CheckerContext, FirSimpleFunction) -> Boolean) = object : Check { - override fun check(context: CheckerContext, function: FirSimpleFunction): String? = message.takeIf { !predicate(context, function) } - } - - val memberOrExtension = simple("must be a member or an extension function") { - it.dispatchReceiverType != null || it.receiverParameter != null - } - - val member = simple("must be a member function") { - it.dispatchReceiverType != null - } - - object ValueParametersCount { - fun atLeast(n: Int) = simple("must have at least $n value parameter" + (if (n > 1) "s" else "")) { - it.valueParameters.size >= n - } - - fun exactly(n: Int) = simple("must have exactly $n value parameters") { - it.valueParameters.size == n - } - - val single = simple("must have a single value parameter") { - it.valueParameters.size == 1 - } - val none = simple("must have no value parameters") { - it.valueParameters.isEmpty() - } - } - - object Returns { - val boolean = simple("must return Boolean") { - it.returnTypeRef.isBoolean - } - - val int = simple("must return Int") { - it.returnTypeRef.isInt - } - - val unit = simple("must return Unit") { - it.returnTypeRef.isUnit - } - } - - val noDefaultAndVarargs = simple("should not have varargs or parameters with default values") { - it.valueParameters.all { param -> - param.defaultValue == null && !param.isVararg - } - } - - val isKProperty = full("second parameter must be of type KProperty<*> or its supertype") { ctx, function -> - val paramType = function.valueParameters[1].returnTypeRef.coneType - paramType.isSupertypeOf( - ctx.session.typeContext, - ConeClassLikeTypeImpl( - StandardClassIds.KProperty.toLookupTag(), - arrayOf(ConeStarProjection), - isNullable = false - ) - ) - } - -} - -private object OperatorFunctionChecks { - - //reimplementation of org.jetbrains.kotlin.util.OperatorChecks for FIR - val checksByName: Map> = buildMap { - checkFor(GET, memberOrExtension, ValueParametersCount.atLeast(1)) - checkFor( - SET, - memberOrExtension, ValueParametersCount.atLeast(2), - Checks.simple("last parameter should not have a default value or be a vararg") { - it.valueParameters.lastOrNull()?.let { param -> - param.defaultValue == null && !param.isVararg - } == true - } - ) - checkFor(GET_VALUE, memberOrExtension, noDefaultAndVarargs, ValueParametersCount.atLeast(2), isKProperty) - checkFor(SET_VALUE, memberOrExtension, noDefaultAndVarargs, ValueParametersCount.atLeast(3), isKProperty) - checkFor(PROVIDE_DELEGATE, memberOrExtension, noDefaultAndVarargs, ValueParametersCount.exactly(2), isKProperty) - checkFor(INVOKE, memberOrExtension) - checkFor(CONTAINS, memberOrExtension, ValueParametersCount.single, noDefaultAndVarargs, Returns.boolean) - checkFor(ITERATOR, memberOrExtension, ValueParametersCount.none) - checkFor(NEXT, memberOrExtension, ValueParametersCount.none) - checkFor(HAS_NEXT, memberOrExtension, ValueParametersCount.none, Returns.boolean) - checkFor(RANGE_TO, memberOrExtension, ValueParametersCount.single, noDefaultAndVarargs) - checkFor(RANGE_UNTIL, memberOrExtension, ValueParametersCount.single, noDefaultAndVarargs) - checkFor( - EQUALS, - member, - object : Check { - override fun check(context: CheckerContext, function: FirSimpleFunction): String? { - val containingClassSymbol = function.containingClassLookupTag()?.toFirRegularClassSymbol(context.session) ?: return null - val customEqualsSupported = context.languageVersionSettings.supportsFeature(LanguageFeature.CustomEqualsInValueClasses) - - if (function.overriddenFunctions(containingClassSymbol, context) - .any { it.containingClassLookupTag()?.classId == StandardClassIds.Any } - || (customEqualsSupported && function.isTypedEqualsInValueClass(context.session)) - ) { - return null - } - return buildString { - append("must override ''equals()'' in Any") - if (customEqualsSupported && containingClassSymbol.isInline) { - val expectedParameterTypeRendered = - containingClassSymbol.defaultType().replaceArgumentsWithStarProjections().renderReadable(); - append(" or define ''equals(other: ${expectedParameterTypeRendered}): Boolean''") - } - } - } - } - ) - checkFor(COMPARE_TO, memberOrExtension, Returns.int, ValueParametersCount.single, noDefaultAndVarargs) - checkFor(BINARY_OPERATION_NAMES, memberOrExtension, ValueParametersCount.single, noDefaultAndVarargs) - checkFor(SIMPLE_UNARY_OPERATION_NAMES, memberOrExtension, ValueParametersCount.none) - checkFor( - setOf(INC, DEC), - memberOrExtension, - Checks.full("receiver must be a supertype of the return type") { ctx, function -> - val receiver = function.dispatchReceiverType ?: function.receiverParameter?.typeRef?.coneType ?: return@full false - function.returnTypeRef.coneType.isSubtypeOf(ctx.session.typeContext, receiver) - } - ) - checkFor(ASSIGNMENT_OPERATIONS, memberOrExtension, Returns.unit, ValueParametersCount.single, noDefaultAndVarargs) - } - - val regexChecks: List>> = buildList { - checkFor(COMPONENT_REGEX, memberOrExtension, ValueParametersCount.none) - } - - private fun MutableMap>.checkFor(name: Name, vararg checks: Check) { - put(name, checks.asList()) - } - - private fun MutableMap>.checkFor(names: Set, vararg checks: Check) { - names.forEach { put(it, checks.asList()) } - } - - private fun MutableList>>.checkFor(regex: Regex, vararg checks: Check) { - add(regex to checks.asList()) - } -} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/declarationUtils.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/declarationUtils.kt index d751bc3510b..f99722bb00a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/declarationUtils.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/declarationUtils.kt @@ -10,17 +10,12 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.modality -import org.jetbrains.kotlin.fir.containingClassForStaticMemberAttr -import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.* -import org.jetbrains.kotlin.fir.resolve.defaultType -import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.impl.FirImplicitUnitTypeRef -import org.jetbrains.kotlin.util.OperatorNameConventions internal fun isInsideExpectClass(containingClass: FirClass, context: CheckerContext): Boolean { return isInsideSpecificClass(containingClass, context) { klass -> klass is FirRegularClass && klass.isExpect } @@ -110,18 +105,6 @@ fun FirClassSymbol<*>.primaryConstructorSymbol(): FirConstructorSymbol? { return null } -fun FirSimpleFunction.isTypedEqualsInValueClass(session: FirSession): Boolean = - containingClassLookupTag()?.toFirRegularClassSymbol(session)?.run { - val valueClassStarProjection = this@run.defaultType().replaceArgumentsWithStarProjections() - with(this@isTypedEqualsInValueClass) { - contextReceivers.isEmpty() && receiverParameter == null - && name == OperatorNameConventions.EQUALS - && this@run.isInline && valueParameters.size == 1 - && (returnTypeRef.isBoolean || returnTypeRef.isNothing) - && valueParameters[0].returnTypeRef.coneType.let { it is ConeClassLikeType && it.replaceArgumentsWithStarProjections() == valueClassStarProjection } - } - } ?: false - fun FirTypeRef.needsMultiFieldValueClassFlattening(session: FirSession) = with(session.typeContext) { coneType.typeConstructor().isMultiFieldValueClass() && !coneType.isNullable } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt index 611ce865210..b6e35e8c0fa 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt @@ -569,9 +569,6 @@ abstract class FirJavaFacade( javaMethod.visibility.toEffectiveVisibility(dispatchReceiver.lookupTag) ).apply { isStatic = javaMethod.isStatic - // Approximation: all Java methods with name that allows to use it in operator form are considered operators - // We need here more detailed checks (see modifierChecks.kt) - isOperator = name in ALL_JAVA_OPERATION_NAMES || OperatorNameConventions.COMPONENT_REGEX.matches(name.asString()) hasStableParameterNames = false } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt index cd8045c668f..132c4c12443 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt @@ -25,8 +25,8 @@ import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirConstExpression import org.jetbrains.kotlin.fir.expressions.unexpandedClassId +import org.jetbrains.kotlin.fir.java.* import org.jetbrains.kotlin.fir.java.FirJavaTypeConversionMode -import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack import org.jetbrains.kotlin.fir.java.declarations.* import org.jetbrains.kotlin.fir.java.resolveIfJavaType import org.jetbrains.kotlin.fir.java.symbols.FirJavaOverriddenSyntheticPropertySymbol @@ -339,11 +339,20 @@ class FirSignatureEnhancement( if (isJavaRecordComponent) { this.isJavaRecordComponent = true } + updateIsOperatorFlagIfNeeded(this) } return function.symbol } + private fun updateIsOperatorFlagIfNeeded(function: FirFunction) { + if (function !is FirSimpleFunction) return + val isOperator = OperatorFunctionChecks.isOperator(function, session, scopeSession = null).isSuccess + if (!isOperator) return + val newStatus = function.status.copy(isOperator = true) + function.replaceStatus(newStatus) + } + /** * Perform first time initialization of bounds with FirResolvedTypeRef instances * But after that bounds are still not enhanced and more over might have not totally correct raw types bounds diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/OperatorFunctionChecks.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/OperatorFunctionChecks.kt new file mode 100644 index 00000000000..5c908538d2e --- /dev/null +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/OperatorFunctionChecks.kt @@ -0,0 +1,226 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.declarations + +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.containingClassLookupTag +import org.jetbrains.kotlin.fir.declarations.utils.isInline +import org.jetbrains.kotlin.fir.languageVersionSettings +import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.defaultType +import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol +import org.jetbrains.kotlin.fir.scopes.overriddenFunctions +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.StandardClassIds +import org.jetbrains.kotlin.util.OperatorNameConventions + +sealed class CheckResult(val isSuccess: Boolean) { + class IllegalSignature(val error: String) : CheckResult(false) + object IllegalFunctionName : CheckResult(false) + object SuccessCheck : CheckResult(true) +} + +object OperatorFunctionChecks { + fun isOperator(function: FirSimpleFunction, session: FirSession, scopeSession: ScopeSession?): CheckResult { + val checks = checksByName.getOrElse(function.name) { + regexChecks.find { it.first.matches(function.name.asString()) }?.second + } ?: return CheckResult.IllegalFunctionName + + for (check in checks) { + check.check(function, session, scopeSession)?.let { return CheckResult.IllegalSignature(it) } + } + return CheckResult.SuccessCheck + } + + //reimplementation of org.jetbrains.kotlin.util.OperatorChecks for FIR + private val checksByName: Map> = buildMap { + checkFor(OperatorNameConventions.GET, Checks.memberOrExtension, Checks.ValueParametersCount.atLeast(1)) + checkFor( + OperatorNameConventions.SET, + Checks.memberOrExtension, Checks.ValueParametersCount.atLeast(2), + Checks.simple("last parameter should not have a default value or be a vararg") { + it.valueParameters.lastOrNull()?.let { param -> + param.defaultValue == null && !param.isVararg + } == true + } + ) + checkFor( + OperatorNameConventions.GET_VALUE, + Checks.memberOrExtension, + Checks.noDefaultAndVarargs, Checks.ValueParametersCount.atLeast(2), + Checks.isKProperty + ) + checkFor( + OperatorNameConventions.SET_VALUE, + Checks.memberOrExtension, + Checks.noDefaultAndVarargs, Checks.ValueParametersCount.atLeast(3), + Checks.isKProperty + ) + checkFor( + OperatorNameConventions.PROVIDE_DELEGATE, + Checks.memberOrExtension, + Checks.noDefaultAndVarargs, Checks.ValueParametersCount.exactly(2), + Checks.isKProperty + ) + checkFor(OperatorNameConventions.INVOKE, Checks.memberOrExtension) + checkFor( + OperatorNameConventions.CONTAINS, + Checks.memberOrExtension, Checks.ValueParametersCount.single, + Checks.noDefaultAndVarargs, Checks.Returns.boolean + ) + checkFor(OperatorNameConventions.ITERATOR, Checks.memberOrExtension, Checks.ValueParametersCount.none) + checkFor(OperatorNameConventions.NEXT, Checks.memberOrExtension, Checks.ValueParametersCount.none) + checkFor(OperatorNameConventions.HAS_NEXT, Checks.memberOrExtension, Checks.ValueParametersCount.none, Checks.Returns.boolean) + checkFor(OperatorNameConventions.RANGE_TO, Checks.memberOrExtension, Checks.ValueParametersCount.single, Checks.noDefaultAndVarargs) + checkFor( + OperatorNameConventions.RANGE_UNTIL, + Checks.memberOrExtension, Checks.ValueParametersCount.single, + Checks.noDefaultAndVarargs + ) + checkFor( + OperatorNameConventions.EQUALS, + Checks.member, + object : Check() { + override fun check(function: FirSimpleFunction, session: FirSession, scopeSession: ScopeSession?): String? { + if (scopeSession == null) return null + val containingClassSymbol = function.containingClassLookupTag()?.toFirRegularClassSymbol(session) ?: return null + val customEqualsSupported = session.languageVersionSettings.supportsFeature(LanguageFeature.CustomEqualsInValueClasses) + + if (function.symbol.overriddenFunctions(containingClassSymbol, session, scopeSession) + .any { it.containingClassLookupTag()?.classId == StandardClassIds.Any } + || (customEqualsSupported && function.isTypedEqualsInValueClass(session)) + ) { + return null + } + return buildString { + append("must override ''equals()'' in Any") + if (customEqualsSupported && containingClassSymbol.isInline) { + val expectedParameterTypeRendered = + containingClassSymbol.defaultType().replaceArgumentsWithStarProjections().renderReadable() + append(" or define ''equals(other: ${expectedParameterTypeRendered}): Boolean''") + } + } + } + } + ) + checkFor( + OperatorNameConventions.COMPARE_TO, + Checks.memberOrExtension, Checks.Returns.int, Checks.ValueParametersCount.single, + Checks.noDefaultAndVarargs + ) + checkFor( + OperatorNameConventions.BINARY_OPERATION_NAMES, + Checks.memberOrExtension, Checks.ValueParametersCount.single, + Checks.noDefaultAndVarargs + ) + checkFor(OperatorNameConventions.SIMPLE_UNARY_OPERATION_NAMES, Checks.memberOrExtension, Checks.ValueParametersCount.none) + checkFor( + setOf(OperatorNameConventions.INC, OperatorNameConventions.DEC), + Checks.memberOrExtension, + Checks.full("receiver must be a supertype of the return type") { session, function -> + val receiver = function.dispatchReceiverType ?: function.receiverParameter?.typeRef?.coneType ?: return@full false + function.returnTypeRef.coneType.isSubtypeOf(session.typeContext, receiver) + } + ) + checkFor( + OperatorNameConventions.ASSIGNMENT_OPERATIONS, + Checks.memberOrExtension, Checks.Returns.unit, Checks.ValueParametersCount.single, + Checks.noDefaultAndVarargs + ) + } + + private val regexChecks: List>> = buildList { + checkFor(OperatorNameConventions.COMPONENT_REGEX, Checks.memberOrExtension, Checks.ValueParametersCount.none) + } + + private fun MutableMap>.checkFor(name: Name, vararg checks: Check) { + put(name, checks.asList()) + } + + private fun MutableMap>.checkFor(names: Set, vararg checks: Check) { + names.forEach { put(it, checks.asList()) } + } + + private fun MutableList>>.checkFor(regex: Regex, vararg checks: Check) { + add(regex to checks.asList()) + } +} + +private abstract class Check { + abstract fun check(function: FirSimpleFunction, session: FirSession, scopeSession: ScopeSession?): String? +} + +private object Checks { + fun simple(message: String, predicate: (FirSimpleFunction) -> Boolean) = object : Check() { + override fun check(function: FirSimpleFunction, session: FirSession, scopeSession: ScopeSession?): String? = + message.takeIf { !predicate(function) } + } + + fun full(message: String, predicate: (FirSession, FirSimpleFunction) -> Boolean) = object : Check() { + override fun check(function: FirSimpleFunction, session: FirSession, scopeSession: ScopeSession?): String? = + message.takeIf { !predicate(session, function) } + } + + val memberOrExtension = simple("must be a member or an extension function") { + it.dispatchReceiverType != null || it.receiverParameter != null + } + + val member = simple("must be a member function") { + it.dispatchReceiverType != null + } + + object ValueParametersCount { + fun atLeast(n: Int) = simple("must have at least $n value parameter" + (if (n > 1) "s" else "")) { + it.valueParameters.size >= n + } + + fun exactly(n: Int) = simple("must have exactly $n value parameters") { + it.valueParameters.size == n + } + + val single = simple("must have a single value parameter") { + it.valueParameters.size == 1 + } + + val none = simple("must have no value parameters") { + it.valueParameters.isEmpty() + } + } + + object Returns { + val boolean = simple("must return Boolean") { + it.returnTypeRef.isBoolean + } + + val int = simple("must return Int") { + it.returnTypeRef.isInt + } + + val unit = simple("must return Unit") { + it.returnTypeRef.isUnit + } + } + + val noDefaultAndVarargs = simple("should not have varargs or parameters with default values") { + it.valueParameters.all { param -> + param.defaultValue == null && !param.isVararg + } + } + + private val kPropertyType = ConeClassLikeTypeImpl( + StandardClassIds.KProperty.toLookupTag(), + arrayOf(ConeStarProjection), + isNullable = false + ) + + val isKProperty = full("second parameter must be of type KProperty<*> or its supertype") { session, function -> + val paramType = function.valueParameters.getOrNull(1)?.returnTypeRef?.coneType ?: return@full false + kPropertyType.isSubtypeOf(paramType, session, errorTypesEqualToAnything = true) + } +} diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt index 62f7d1c60bf..b67cbb615ba 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt @@ -9,16 +9,19 @@ import org.jetbrains.kotlin.descriptors.InlineClassRepresentation import org.jetbrains.kotlin.descriptors.ValueClassRepresentation import org.jetbrains.kotlin.descriptors.createValueClassRepresentation import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.declarations.utils.isInline +import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByTypeConstructor +import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.model.typeConstructor +import org.jetbrains.kotlin.util.OperatorNameConventions internal fun ConeKotlinType.substitutedUnderlyingTypeForInlineClass(session: FirSession, context: ConeTypeContext): ConeKotlinType? { val unsubstitutedType = unsubstitutedUnderlyingTypeForInlineClass(session) ?: return null @@ -77,3 +80,15 @@ private fun ConeSimpleKotlinType.valueClassRepresentationTypeMarkersList(session .onEach { it.lazyResolveToPhase(FirResolvePhase.TYPES) } .map { it.name to it.resolvedReturnType as ConeSimpleKotlinType } } + +fun FirSimpleFunction.isTypedEqualsInValueClass(session: FirSession): Boolean = + containingClassLookupTag()?.toFirRegularClassSymbol(session)?.run { + val valueClassStarProjection = this@run.defaultType().replaceArgumentsWithStarProjections() + with(this@isTypedEqualsInValueClass) { + contextReceivers.isEmpty() && receiverParameter == null + && name == OperatorNameConventions.EQUALS + && this@run.isInline && valueParameters.size == 1 + && (returnTypeRef.isBoolean || returnTypeRef.isNothing) + && valueParameters[0].returnTypeRef.coneType.let { it is ConeClassLikeType && it.replaceArgumentsWithStarProjections() == valueClassStarProjection } + } + } ?: false diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/Scopes.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/Scopes.kt index a11daafb474..5ad0564efe9 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/Scopes.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/Scopes.kt @@ -13,9 +13,7 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.scope import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag -import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol +import org.jetbrains.kotlin.fir.symbols.impl.* fun ConeClassLikeLookupTag.getNestedClassifierScope(session: FirSession, scopeSession: ScopeSession): FirContainingNamesAwareScope? { val klass = toSymbol(session)?.fir as? FirRegularClass ?: return null @@ -56,3 +54,24 @@ fun debugCollectOverrides(symbol: FirCallableSymbol<*>, scope: FirTypeScope): Ma } return process(scope, symbol) } + +fun FirNamedFunctionSymbol.overriddenFunctions( + containingClass: FirClassSymbol<*>, + session: FirSession, + scopeSession: ScopeSession +): List> { + val firTypeScope = containingClass.unsubstitutedScope( + session, + scopeSession, + withForcedTypeCalculator = true + ) + + val overriddenFunctions = mutableListOf>() + firTypeScope.processFunctionsByName(callableId.callableName) { } + firTypeScope.processOverriddenFunctions(this) { + overriddenFunctions.add(it) + ProcessorAction.NEXT + } + + return overriddenFunctions +} diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt index d74a5f307ed..379d1a1d5a2 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt @@ -516,9 +516,9 @@ private class CapturedArguments(val capturedArguments: Array fileName:/kt43217.kt BLOCK_BODY DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in .DoubleExpression' INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name: modality:FINAL visibility:local superTypes:[.DoubleExpression]' - FUN name:get visibility:public modality:OPEN <> ($this:.A.b.) returnType:kotlin.Double [operator] + FUN name:get visibility:public modality:OPEN <> ($this:.A.b.) returnType:kotlin.Double overridden: - public abstract fun get (): @[EnhancedNullability] kotlin.Double [fake_override,operator] declared in .DoubleExpression + public abstract fun get (): @[EnhancedNullability] kotlin.Double [fake_override] declared in .DoubleExpression $this: VALUE_PARAMETER name: type:.A.b. BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun get (): kotlin.Double [operator] declared in .A.b.' + RETURN type=kotlin.Nothing from='public open fun get (): kotlin.Double declared in .A.b.' CONST Double type=kotlin.Double value=0.0 FUN FAKE_OVERRIDE name:isEqualTo visibility:public modality:OPEN <> ($this:.DoubleExpression, value:kotlin.Double) returnType:@[EnhancedNullability] kotlin.Any [fake_override] annotations: @@ -79,12 +79,12 @@ FILE fqName: fileName:/kt43217.kt BLOCK_BODY DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in .DoubleExpression' INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:C modality:FINAL visibility:public superTypes:[.DoubleExpression]' - FUN name:get visibility:public modality:OPEN <> ($this:.C) returnType:kotlin.Double [operator] + FUN name:get visibility:public modality:OPEN <> ($this:.C) returnType:kotlin.Double overridden: - public abstract fun get (): @[EnhancedNullability] kotlin.Double [fake_override,operator] declared in .DoubleExpression + public abstract fun get (): @[EnhancedNullability] kotlin.Double [fake_override] declared in .DoubleExpression $this: VALUE_PARAMETER name: type:.C BLOCK_BODY - RETURN type=kotlin.Nothing from='public open fun get (): kotlin.Double [operator] declared in .C' + RETURN type=kotlin.Nothing from='public open fun get (): kotlin.Double declared in .C' CONST Double type=kotlin.Double value=0.0 FUN FAKE_OVERRIDE name:isEqualTo visibility:public modality:OPEN <> ($this:.DoubleExpression, value:kotlin.Double) returnType:@[EnhancedNullability] kotlin.Any [fake_override] annotations: diff --git a/compiler/testData/ir/irText/classes/kt43217.fir.kt.txt b/compiler/testData/ir/irText/classes/kt43217.fir.kt.txt index 239b95026ed..b06efa5b888 100644 --- a/compiler/testData/ir/irText/classes/kt43217.fir.kt.txt +++ b/compiler/testData/ir/irText/classes/kt43217.fir.kt.txt @@ -14,7 +14,7 @@ class A { } - override operator fun get(): Double { + override fun get(): Double { return 0.0 } @@ -33,7 +33,7 @@ class C : DoubleExpression { } - override operator fun get(): Double { + override fun get(): Double { return 0.0 } diff --git a/compiler/testData/ir/irText/expressions/exclExclOnPlatformType.fir.ir.txt b/compiler/testData/ir/irText/expressions/exclExclOnPlatformType.fir.ir.txt index e5e77ddb6d7..82e133d8af7 100644 --- a/compiler/testData/ir/irText/expressions/exclExclOnPlatformType.fir.ir.txt +++ b/compiler/testData/ir/irText/expressions/exclExclOnPlatformType.fir.ir.txt @@ -7,7 +7,7 @@ FILE fqName: fileName:/exclExclOnPlatformType.kt CALL 'public final fun use (a: kotlin.Any): kotlin.Unit declared in ' type=kotlin.Unit origin=null a: CALL 'public final fun CHECK_NOT_NULL (arg0: T0 of kotlin.internal.ir.CHECK_NOT_NULL?): {T0 of kotlin.internal.ir.CHECK_NOT_NULL & Any} declared in kotlin.internal.ir' type=kotlin.String origin=EXCLEXCL : kotlin.String - arg0: CALL 'public open fun get (): T of java.lang.ref.WeakReference? [fake_override,operator] declared in java.lang.ref.WeakReference' type=kotlin.String? origin=null + arg0: CALL 'public open fun get (): T of java.lang.ref.WeakReference? [fake_override] declared in java.lang.ref.WeakReference' type=kotlin.String? origin=null $this: CONSTRUCTOR_CALL 'public constructor (p0: @[FlexibleNullability] T of java.lang.ref.WeakReference?) declared in java.lang.ref.WeakReference' type=java.lang.ref.WeakReference<@[FlexibleNullability] kotlin.String?> origin=null : @[FlexibleNullability] kotlin.String? p0: CONST String type=kotlin.String value="" diff --git a/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/SubclassOfMapEntry.fir.txt b/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/SubclassOfMapEntry.fir.txt index 3bfde2cb823..2a506da0e53 100644 --- a/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/SubclassOfMapEntry.fir.txt +++ b/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/SubclassOfMapEntry.fir.txt @@ -1,4 +1,4 @@ public abstract interface SubclassOfMapEntry : R|kotlin/collections/MutableMap.MutableEntry, ft>| { - public abstract operator fun setValue(value: R|ft|): R|ft| + public abstract fun setValue(value: R|ft|): R|ft| } diff --git a/compiler/testData/loadJava/compiledJava/signaturePropagation/ReturnInnerSubclassOfSupersInner.fir.txt b/compiler/testData/loadJava/compiledJava/signaturePropagation/ReturnInnerSubclassOfSupersInner.fir.txt index 208f2c4c8b3..1b99af53447 100644 --- a/compiler/testData/loadJava/compiledJava/signaturePropagation/ReturnInnerSubclassOfSupersInner.fir.txt +++ b/compiler/testData/loadJava/compiledJava/signaturePropagation/ReturnInnerSubclassOfSupersInner.fir.txt @@ -3,7 +3,7 @@ public abstract interface ReturnInnerSubclassOfSupersInner : R|kotlin/Any| { public constructor(): R|test/ReturnInnerSubclassOfSupersInner.Sub| public/*package*/ open inner class Inner : R|test/ReturnInnerSubclassOfSupersInner.Super.Inner>| { - public/*package*/ open operator fun get(): R|ft>, test/ReturnInnerSubclassOfSupersInner.Sub>?>| + public/*package*/ open fun get(): R|ft>, test/ReturnInnerSubclassOfSupersInner.Sub>?>| public/*package*/ test/ReturnInnerSubclassOfSupersInner.Sub.constructor(): R|test/ReturnInnerSubclassOfSupersInner.Sub.Inner| @@ -13,7 +13,7 @@ public abstract interface ReturnInnerSubclassOfSupersInner : R|kotlin/Any| { public constructor(): R|test/ReturnInnerSubclassOfSupersInner.Super| public/*package*/ open inner class Inner : R|kotlin/Any| { - public/*package*/ open operator fun get(): R|ft>, test/ReturnInnerSubclassOfSupersInner.Super>?>| + public/*package*/ open fun get(): R|ft>, test/ReturnInnerSubclassOfSupersInner.Super>?>| public/*package*/ test/ReturnInnerSubclassOfSupersInner.Super.constructor(): R|test/ReturnInnerSubclassOfSupersInner.Super.Inner|