diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 5c5a1f96655..2d0d8d8e14c 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -17788,6 +17788,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.kt"); } + @Test + @TestMetadata("returnedAnonymousObjects_2.kt") + public void testReturnedAnonymousObjects_2() throws Exception { + runTest("compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects_2.kt"); + } + @Test @TestMetadata("returns.kt") public void testReturns() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index b1c074a88bd..64ba948aceb 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -17794,6 +17794,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.kt"); } + @Test + @TestMetadata("returnedAnonymousObjects_2.kt") + public void testReturnedAnonymousObjects_2() throws Exception { + runTest("compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects_2.kt"); + } + @Test @TestMetadata("returns.kt") public void testReturns() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index ede4a749fb1..93e79b941db 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -17788,6 +17788,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.kt"); } + @Test + @TestMetadata("returnedAnonymousObjects_2.kt") + public void testReturnedAnonymousObjects_2() throws Exception { + runTest("compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects_2.kt"); + } + @Test @TestMetadata("returns.kt") public void testReturns() throws Exception { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PrivateInlineFunctionsReturningAnonymousObjectsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PrivateInlineFunctionsReturningAnonymousObjectsChecker.kt index 884007277f0..88627c5c514 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PrivateInlineFunctionsReturningAnonymousObjectsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PrivateInlineFunctionsReturningAnonymousObjectsChecker.kt @@ -5,31 +5,39 @@ package org.jetbrains.kotlin.resolve.checkers -import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.descriptors.* +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny +import org.jetbrains.kotlin.types.KotlinType object PrivateInlineFunctionsReturningAnonymousObjectsChecker : DeclarationChecker { override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { - if (context.languageVersionSettings.supportsFeature(LanguageFeature.ApproximateAnonymousReturnTypesInPrivateInlineFunctions)) - return - if (descriptor !is SimpleFunctionDescriptor || !descriptor.isInline || !DescriptorVisibilities.isPrivate(descriptor.visibility) || declaration !is KtNamedFunction) return - val returnTypeConstructor = descriptor.returnType?.constructor ?: return - - if (returnTypeConstructor.supertypes.singleOrNull { it.isAnyOrNullableAny() } == null) return - val nameIdentifier = declaration.nameIdentifier ?: return - val returnTypeDeclarationDescriptor = returnTypeConstructor.declarationDescriptor ?: return + val returnType = descriptor.returnType ?: return + checkTypeAndArguments(returnType, nameIdentifier, context) + } + + private fun checkTypeAndArguments(type: KotlinType, reportOn: PsiElement, context: DeclarationCheckerContext) { + checkType(type, reportOn, context) + for (argument in type.arguments) { + checkTypeAndArguments(argument.type, reportOn, context) + } + } + + private fun checkType(type: KotlinType, reportOn: PsiElement, context: DeclarationCheckerContext) { + val returnTypeConstructor = type.constructor + val returnTypeDeclarationDescriptor = returnTypeConstructor.declarationDescriptor ?: return if (DescriptorUtils.isAnonymousObject(returnTypeDeclarationDescriptor)) { - context.trace.report(Errors.PRIVATE_INLINE_FUNCTIONS_RETURNING_ANONYMOUS_OBJECTS.on(nameIdentifier)) + context.trace.report(Errors.PRIVATE_INLINE_FUNCTIONS_RETURNING_ANONYMOUS_OBJECTS.on(reportOn)) } } } diff --git a/compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.kt b/compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.kt index 2dd860567d5..cb339a21397 100644 --- a/compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.kt +++ b/compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.kt @@ -11,7 +11,7 @@ private inline fun foo2(crossinline f: () -> Int) = object : I1 { fun bar(): Int = f() } -private inline fun foo3(crossinline f: () -> Int) = object : I1, I2 { +private inline fun foo3(crossinline f: () -> Int) = object : I1, I2 { fun bar(): Int = f() } diff --git a/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.kt b/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.kt index e709d8d6327..63234bcbb5f 100644 --- a/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.kt +++ b/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.kt @@ -7,11 +7,11 @@ private inline fun foo1< interface I1 interface I2 -private inline fun foo2(crossinline f: () -> Int) = object : I1 { +private inline fun foo2(crossinline f: () -> Int) = object : I1 { fun bar(): Int = f() } -private inline fun foo3(crossinline f: () -> Int) = object : I1, I2 { +private inline fun foo3(crossinline f: () -> Int) = object : I1, I2 { fun bar(): Int = f() } diff --git a/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects_2.fir.kt b/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects_2.fir.kt new file mode 100644 index 00000000000..e27dc11676c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects_2.fir.kt @@ -0,0 +1,159 @@ +// SKIP_TXT +// ISSUE: KT-33917 + +class Inv(val value: T) + +private inline fun foo10(crossinline f: () -> Int) = object { + fun bar(): Int = f() +} + +private inline fun foo11(crossinline f: () -> Int) = Inv(object { + fun bar(): Int = f() +}) + +private inline fun foo12(crossinline f: () -> Int) = Inv(Inv(object { + fun bar(): Int = f() +})) + +interface I1 +interface I2 + +private inline fun foo20(crossinline f: () -> Int) = object : I1 { + fun bar(): Int = f() +} + +private inline fun foo21(crossinline f: () -> Int) = Inv(object : I1 { + fun bar(): Int = f() +}) + +private inline fun foo22(crossinline f: () -> Int) = Inv(Inv(object : I1 { + fun bar(): Int = f() +})) + +private inline fun foo30(crossinline f: () -> Int) = object : I1, I2 { + fun bar(): Int = f() +} + +private inline fun foo31(crossinline f: () -> Int) = Inv(object : I1, I2 { + fun bar(): Int = f() +}) + +private inline fun foo32(crossinline f: () -> Int) = Inv(Inv(object : I1, I2 { + fun bar(): Int = f() +})) + +private fun foo40(f: () -> Int) = object { + fun bar(): Int = f() +} + +private fun foo41(f: () -> Int) = Inv(object { + fun bar(): Int = f() +}) + +private fun foo42(f: () -> Int) = Inv(Inv(object { + fun bar(): Int = f() +})) + +// ------------------------------------------------------------------------------------------------ + +fun test10(b: Boolean) { + var x = foo10 { 1 } + if (b) { + x = foo10 { 2 } + } + x.bar() +} + +fun test11(b: Boolean) { + var x = foo11 { 1 }.value + if (b) { + x = foo11 { 2 }.value + } + x.bar() +} + +fun test12(b: Boolean) { + var x = foo12 { 1 }.value.value + if (b) { + x = foo12 { 2 }.value.value + } + x.bar() +} + +// ------------------------------------------------------------------------------------------------ + +fun test20(b: Boolean) { + var x = foo20 { 1 } + if (b) { + x = foo20 { 2 } + } + x.bar() +} + +fun test21(b: Boolean) { + var x = foo21 { 1 }.value + if (b) { + x = foo21 { 2 }.value + } + x.bar() +} + +fun test22(b: Boolean) { + var x = foo22 { 1 }.value.value + if (b) { + x = foo22 { 2 }.value.value + } + x.bar() +} + +// ------------------------------------------------------------------------------------------------ + +fun test30(b: Boolean) { + var x = foo30 { 1 } + if (b) { + x = foo30 { 2 } + } + x.bar() +} + +fun test31(b: Boolean) { + var x = foo31 { 1 }.value + if (b) { + x = foo31 { 2 }.value + } + x.bar() +} + +fun test32(b: Boolean) { + var x = foo32 { 1 }.value.value + if (b) { + x = foo32 { 2 }.value.value + } + x.bar() +} + +// ------------------------------------------------------------------------------------------------ + +fun test40(b: Boolean) { + var x = ")!>foo40 { 1 } + if (b) { + x = ")!>foo40 { 2 } + } + x.bar() +} + +fun test41(b: Boolean) { + var x = ")!>foo41 { 1 }.value + if (b) { + x = ")!>foo41 { 2 }.value + } + x.bar() +} + +fun test42(b: Boolean) { + var x = ")!>foo42 { 1 }.value.value + if (b) { + x = ")!>foo42 { 2 }.value.value + } + x.bar() +} diff --git a/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects_2.kt b/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects_2.kt new file mode 100644 index 00000000000..38ea068c6d2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects_2.kt @@ -0,0 +1,159 @@ +// SKIP_TXT +// ISSUE: KT-33917 + +class Inv(val value: T) + +private inline fun foo10(crossinline f: () -> Int) = object { + fun bar(): Int = f() +} + +private inline fun foo11(crossinline f: () -> Int) = Inv(object { + fun bar(): Int = f() +}) + +private inline fun foo12(crossinline f: () -> Int) = Inv(Inv(object { + fun bar(): Int = f() +})) + +interface I1 +interface I2 + +private inline fun foo20(crossinline f: () -> Int) = object : I1 { + fun bar(): Int = f() +} + +private inline fun foo21(crossinline f: () -> Int) = Inv(object : I1 { + fun bar(): Int = f() +}) + +private inline fun foo22(crossinline f: () -> Int) = Inv(Inv(object : I1 { + fun bar(): Int = f() +})) + +private inline fun foo30(crossinline f: () -> Int) = object : I1, I2 { + fun bar(): Int = f() +} + +private inline fun foo31(crossinline f: () -> Int) = Inv(object : I1, I2 { + fun bar(): Int = f() +}) + +private inline fun foo32(crossinline f: () -> Int) = Inv(Inv(object : I1, I2 { + fun bar(): Int = f() +})) + +private fun foo40(f: () -> Int) = object { + fun bar(): Int = f() +} + +private fun foo41(f: () -> Int) = Inv(object { + fun bar(): Int = f() +}) + +private fun foo42(f: () -> Int) = Inv(Inv(object { + fun bar(): Int = f() +})) + +// ------------------------------------------------------------------------------------------------ + +fun test10(b: Boolean) { + var x = foo10 { 1 } + if (b) { + x = foo10 { 2 } + } + x.bar() +} + +fun test11(b: Boolean) { + var x = `")!>foo11 { 1 }.value + if (b) { + x = `")!>foo11 { 2 }.value + } + x.bar() +} + +fun test12(b: Boolean) { + var x = `")!>foo12 { 1 }.value.value + if (b) { + x = `")!>foo12 { 2 }.value.value + } + x.bar() +} + +// ------------------------------------------------------------------------------------------------ + +fun test20(b: Boolean) { + var x = foo20 { 1 } + if (b) { + x = foo20 { 2 } + } + x.bar() +} + +fun test21(b: Boolean) { + var x = `")!>foo21 { 1 }.value + if (b) { + x = `")!>foo21 { 2 }.value + } + x.bar() +} + +fun test22(b: Boolean) { + var x = `")!>foo22 { 1 }.value.value + if (b) { + x = `")!>foo22 { 2 }.value.value + } + x.bar() +} + +// ------------------------------------------------------------------------------------------------ + +fun test30(b: Boolean) { + var x = `")!>foo30 { 1 } + if (b) { + x = `")!>foo30 { 2 } + } + x.bar() +} + +fun test31(b: Boolean) { + var x = `")!>foo31 { 1 }.value + if (b) { + x = `")!>foo31 { 2 }.value + } + x.bar() +} + +fun test32(b: Boolean) { + var x = `")!>foo32 { 1 }.value.value + if (b) { + x = `")!>foo32 { 2 }.value.value + } + x.bar() +} + +// ------------------------------------------------------------------------------------------------ + +fun test40(b: Boolean) { + var x = `")!>foo40 { 1 } + if (b) { + x = `")!>foo40 { 2 } + } + x.bar() +} + +fun test41(b: Boolean) { + var x = `")!>foo41 { 1 }.value + if (b) { + x = `")!>foo41 { 2 }.value + } + x.bar() +} + +fun test42(b: Boolean) { + var x = `")!>foo42 { 1 }.value.value + if (b) { + x = `")!>foo42 { 2 }.value.value + } + x.bar() +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index dbc58907b8d..8555dbca32e 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -17794,6 +17794,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.kt"); } + @Test + @TestMetadata("returnedAnonymousObjects_2.kt") + public void testReturnedAnonymousObjects_2() throws Exception { + runTest("compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects_2.kt"); + } + @Test @TestMetadata("returns.kt") public void testReturns() throws Exception {