K2: Use deserialized type annotation for lambda type resolution.

This commit adds code to check whether a deserialized cone type is a
special function type kind or not when resolving the type of a lambda
expression (anonymous function). If it is a special function kind, it
sets the type of lambda based on the special function kind.

^KT-64994 Fixed
This commit is contained in:
Jaebaek Seo
2024-02-12 16:58:43 -08:00
committed by Space Cloud
parent 10a422180a
commit 171ea3571c
19 changed files with 406 additions and 5 deletions
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2024 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.analysis.api.fir.test.cases.generated.cases.components.compilerFacility;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.analysis.api.fir.test.configurators.AnalysisApiFirTestConfiguratorFactory;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfiguratorFactoryData;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisSessionMode;
import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiMode;
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.compilerFacility.AbstractFirPluginPrototypeMultiBinaryModuleCompilerFacilityTest;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("analysis/analysis-api/testData/components/compilerFacility/firPluginPrototypeMultiBinaryModule")
@TestDataPath("$PROJECT_ROOT")
public class FirIdeNormalAnalysisLibraryBinaryModuleFirPluginPrototypeMultiBinaryModuleCompilerFacilityTestGenerated extends AbstractFirPluginPrototypeMultiBinaryModuleCompilerFacilityTest {
@NotNull
@Override
public AnalysisApiTestConfigurator getConfigurator() {
return AnalysisApiFirTestConfiguratorFactory.INSTANCE.createConfigurator(
new AnalysisApiTestConfiguratorFactoryData(
FrontendKind.Fir,
TestModuleKind.LibraryBinary,
AnalysisSessionMode.Normal,
AnalysisApiMode.Ide
)
);
}
@Test
public void testAllFilesPresentInFirPluginPrototypeMultiBinaryModule() {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/compilerFacility/firPluginPrototypeMultiBinaryModule"), Pattern.compile("^(.+)\\.(kt)$"), null, true);
}
@Test
@TestMetadata("composableFunctionMultiModules.kt")
public void testComposableFunctionMultiModules() {
runTest("analysis/analysis-api/testData/components/compilerFacility/firPluginPrototypeMultiBinaryModule/composableFunctionMultiModules.kt");
}
@Test
@TestMetadata("composableFunctionMultiModules2.kt")
public void testComposableFunctionMultiModules2() {
runTest("analysis/analysis-api/testData/components/compilerFacility/firPluginPrototypeMultiBinaryModule/composableFunctionMultiModules2.kt");
}
}
@@ -24,6 +24,7 @@ dependencies {
testImplementation(projectTests(":compiler:tests-common"))
testApi(projectTests(":compiler:test-infrastructure-utils"))
testApi(projectTests(":compiler:test-infrastructure"))
testImplementation(projectTests(":plugins:fir-plugin-prototype"))
testImplementation(projectTests(":compiler:tests-common-new"))
testImplementation(projectTests(":analysis:analysis-api-impl-barebone"))
testImplementation(project(":analysis:symbol-light-classes"))
@@ -26,19 +26,19 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.plugin.services.PluginRuntimeAnnotationsProvider
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.DumpIrTreeOptions
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.ConfigurationDirectives
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
import org.jetbrains.kotlin.test.services.*
import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
@@ -48,6 +48,11 @@ import kotlin.test.assertFalse
abstract class AbstractMultiModuleCompilerFacilityTest : AbstractCompilerFacilityTest()
abstract class AbstractFirPluginPrototypeMultiBinaryModuleCompilerFacilityTest : AbstractCompilerFacilityTest() {
override fun extraCustomRuntimeClasspathProviders(): Array<Constructor<RuntimeClasspathProvider>> =
arrayOf(::PluginRuntimeAnnotationsProvider)
}
abstract class AbstractCompilerFacilityTest : AbstractAnalysisApiBasedTest() {
private companion object {
private val ALLOWED_ERRORS = listOf(
@@ -107,6 +112,8 @@ abstract class AbstractCompilerFacilityTest : AbstractAnalysisApiBasedTest() {
}
}
open fun extraCustomRuntimeClasspathProviders(): Array<Constructor<RuntimeClasspathProvider>> = emptyArray()
override fun configureTest(builder: TestConfigurationBuilder) {
super.configureTest(builder)
with(builder) {
@@ -116,6 +123,7 @@ abstract class AbstractCompilerFacilityTest : AbstractAnalysisApiBasedTest() {
+ConfigurationDirectives.WITH_STDLIB
+JvmEnvironmentConfigurationDirectives.FULL_JDK
}
useCustomRuntimeClasspathProviders(*extraCustomRuntimeClasspathProviders())
}
}
@@ -0,0 +1,14 @@
MODULE_FRAGMENT
FILE fqName:<root> fileName:main.kt
FUN name:Bar visibility:public modality:FINAL <> () returnType:kotlin.Unit
annotations:
MyComposable
BLOCK_BODY
CALL 'public final fun Foo (text: @[MyComposable] kotlin.Function0<kotlin.Unit>): kotlin.Unit declared in p3' type=kotlin.Unit origin=null
text: FUN_EXPR type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Unit
annotations:
MyComposable
BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <anonymous> (): kotlin.Unit declared in <root>.Bar'
GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
@@ -0,0 +1,28 @@
// WITH_FIR_TEST_COMPILER_PLUGIN
// DUMP_IR
// MODULE: lib
// FILE: p3/foo.kt
package p3;
import org.jetbrains.kotlin.fir.plugin.MyComposable
@MyComposable
public fun Foo(
text: @MyComposable () -> Unit,
) {}
// MODULE: main(lib)
// MODULE_KIND: Source
// FILE: main.kt
import org.jetbrains.kotlin.fir.plugin.MyComposable
import p3.Foo
@MyComposable
public fun Bar() {
Foo(
text = {}, // @Composable invocations can only happen from the context of a @Composable function
)
}
@@ -0,0 +1,16 @@
final class MainKt$Bar$1 {
// source: 'main.kt'
enclosing method MainKt.Bar()V
public final static field INSTANCE: MainKt$Bar$1
inner (anonymous) class MainKt$Bar$1
static method <clinit>(): void
method <init>(): void
public synthetic bridge method invoke(): java.lang.Object
public final method invoke(): void
}
public final class MainKt {
// source: 'main.kt'
inner (anonymous) class MainKt$Bar$1
public final static method Bar(): void
}
@@ -0,0 +1,26 @@
MODULE_FRAGMENT
FILE fqName:<root> fileName:main.kt
FUN name:Greeting visibility:public modality:FINAL <> (name:kotlin.String) returnType:kotlin.Unit
annotations:
MyComposable
VALUE_PARAMETER name:name index:0 type:kotlin.String
BLOCK_BODY
CALL 'public final fun show (str: kotlin.String): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
str: STRING_CONCATENATION type=kotlin.String
CONST String type=kotlin.String value="hi "
GET_VAR 'name: kotlin.String declared in <root>.Greeting' type=kotlin.String origin=null
CONST String type=kotlin.String value="!"
FUN name:show visibility:public modality:FINAL <> (str:kotlin.String) returnType:kotlin.Unit
VALUE_PARAMETER name:str index:0 type:kotlin.String
BLOCK_BODY
FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test (): kotlin.Int declared in <root>'
CALL 'public final fun setContent (content: @[MyComposable] kotlin.Function0<kotlin.Unit>): kotlin.Int declared in p3' type=kotlin.Int origin=null
content: FUN_EXPR type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Unit
annotations:
MyComposable
BLOCK_BODY
CALL 'public final fun Greeting (name: kotlin.String): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
name: CONST String type=kotlin.String value="test"
@@ -0,0 +1,34 @@
// WITH_FIR_TEST_COMPILER_PLUGIN
// DUMP_IR
// MODULE: lib
// FILE: p3/foo.kt
package p3;
import org.jetbrains.kotlin.fir.plugin.MyComposable
fun setContent(content: @MyComposable () -> Unit): Int {
content()
return 3
}
// MODULE: main(lib)
// MODULE_KIND: Source
// FILE: main.kt
import org.jetbrains.kotlin.fir.plugin.MyComposable
import p3.setContent
fun test(): Int {
return setContent {
Greeting("test")
}
}
@MyComposable
fun Greeting(name: String) {
show("hi $name!")
}
fun show(str: String) {}
@@ -0,0 +1,18 @@
final class MainKt$test$1 {
// source: 'main.kt'
enclosing method MainKt.test()I
public final static field INSTANCE: MainKt$test$1
inner (anonymous) class MainKt$test$1
static method <clinit>(): void
method <init>(): void
public synthetic bridge method invoke(): java.lang.Object
public final method invoke(): void
}
public final class MainKt {
// source: 'main.kt'
inner (anonymous) class MainKt$test$1
public final static method Greeting(p0: java.lang.String): void
public final static method show(p0: java.lang.String): void
public final static method test(): int
}
@@ -48,7 +48,7 @@ private typealias ModulesByName = Map<String, KtModuleWithFiles>
* - For [TestModule] A and B, where A has dependency on B, A will never appears earlier than B in the result list.
*/
private fun sortInDependencyPostOrder(testModules: List<TestModule>): List<TestModule> {
val namesToModules = buildMap { testModules.forEach { put(it.name, it) } }
val namesToModules = testModules.associateBy { it.name }
val notVisited = testModules.toMutableSet()
val sortedModules = mutableListOf<TestModule>()