[FIR plugin prototype] Implement Composable-like extension

This commit is contained in:
Dmitriy Novozhilov
2023-01-18 17:29:50 +02:00
committed by Space Team
parent 1c8587f82d
commit f268ab8858
8 changed files with 164 additions and 0 deletions
@@ -33,3 +33,7 @@ enum class Visibility {
annotation class SupertypeWithTypeArgument(val kClass: KClass<*>)
annotation class MetaSupertype
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE, AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
annotation class MyComposable
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
import org.jetbrains.kotlin.fir.plugin.generators.*
import org.jetbrains.kotlin.fir.plugin.types.FirNumberSignAttributeExtension
import org.jetbrains.kotlin.fir.plugin.types.ComposableLikeFunctionalTypeKindExtension
import org.jetbrains.kotlin.ir.plugin.GeneratedDeclarationsIrBodyFiller
class FirPluginPrototypeExtensionRegistrar : FirExtensionRegistrar() {
@@ -23,6 +24,7 @@ class FirPluginPrototypeExtensionRegistrar : FirExtensionRegistrar() {
+::PluginAdditionalCheckers
+::FirNumberSignAttributeExtension
+::AlgebraReceiverInjector
+::ComposableLikeFunctionalTypeKindExtension
// Declaration generators
+::TopLevelDeclarationsGenerator
@@ -0,0 +1,44 @@
/*
* 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.plugin.types
import org.jetbrains.kotlin.builtins.functions.FunctionalTypeKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.extensions.FirFunctionalTypeKindExtension
import org.jetbrains.kotlin.fir.plugin.fqn
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class ComposableLikeFunctionalTypeKindExtension(session: FirSession) : FirFunctionalTypeKindExtension(session) {
override fun FunctionalTypeKindRegistrar.registerKinds() {
registerKind(ComposableFunction, KComposableFunction)
}
}
private val COMPOSABLE_PACKAGE_FQN = FqName.topLevel(Name.identifier("some"))
private val MY_COMPOSABLE_ANNOTATION_CLASS_ID = ClassId.topLevel("MyComposable".fqn())
object ComposableFunction : FunctionalTypeKind(
COMPOSABLE_PACKAGE_FQN,
"MyComposableFunction",
MY_COMPOSABLE_ANNOTATION_CLASS_ID,
isReflectType = false
) {
override val prefixForTypeRender: String
get() = "@MyComposable"
override fun reflectKind(): FunctionalTypeKind = KComposableFunction
}
object KComposableFunction : FunctionalTypeKind(
COMPOSABLE_PACKAGE_FQN,
"KMyComposableFunction",
MY_COMPOSABLE_ANNOTATION_CLASS_ID,
isReflectType = true
) {
override fun nonReflectKind(): FunctionalTypeKind = ComposableFunction
}
@@ -0,0 +1,3 @@
FILE: ambigousKinds.kt
public final fun incorrect(block: <ERROR TYPE REF: There are multiple functional kinds for functional type ref>): R|kotlin/Unit| {
}
@@ -0,0 +1,3 @@
import org.jetbrains.kotlin.fir.plugin.MyComposable
fun incorrect(block: <!AMBIGUOUS_FUNCTIONAL_TYPE_KIND!>@MyComposable suspend () -> Unit<!>) {}
@@ -0,0 +1,55 @@
FILE: simple.kt
public final fun runUsual(block: R|() -> kotlin/Unit|): R|kotlin/Unit| {
}
public final fun runComposable(block: R|@R|org/jetbrains/kotlin/fir/plugin/MyComposable|() some/MyComposableFunction0<kotlin/Unit>|): R|kotlin/Unit| {
}
public final fun test_1(): R|kotlin/Unit| {
lval l0: R|() -> kotlin/Unit| = fun <anonymous>(): R|kotlin/Unit| <inline=Unknown> {
^ Unit
}
lval l1: R|some/MyComposableFunction0<kotlin/Unit>| = fun <anonymous>(): R|kotlin/Unit| <inline=Unknown> {
^ Unit
}
lval l2: R|@R|org/jetbrains/kotlin/fir/plugin/MyComposable|() some/MyComposableFunction0<kotlin/Unit>| = fun <anonymous>(): R|kotlin/Unit| <inline=Unknown> {
^ Unit
}
lval l3: R|some/MyComposableFunction0<kotlin/Unit>| = @R|org/jetbrains/kotlin/fir/plugin/MyComposable|() fun <anonymous>(): R|kotlin/Unit| <inline=Unknown> {
^ Unit
}
R|/runUsual|(R|<local>/l0|)
R|/runUsual<Inapplicable(INAPPLICABLE): /runUsual>#|(R|<local>/l1|)
R|/runUsual<Inapplicable(INAPPLICABLE): /runUsual>#|(R|<local>/l2|)
R|/runUsual<Inapplicable(INAPPLICABLE): /runUsual>#|(R|<local>/l3|)
R|/runUsual|(<L> = runUsual@fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
^@runUsual Unit
}
)
R|/runUsual<Inapplicable(INAPPLICABLE): /runUsual>#|(<L> = @R|org/jetbrains/kotlin/fir/plugin/MyComposable|() runUsual@fun <anonymous>(): R|kotlin/Unit| <inline=Unknown> {
^@runUsual Unit
}
)
R|/runComposable|(R|<local>/l0|)
R|/runComposable|(R|<local>/l1|)
R|/runComposable|(R|<local>/l2|)
R|/runComposable|(R|<local>/l3|)
R|/runComposable|(<L> = runComposable@fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
^@runComposable Unit
}
)
R|/runComposable|(<L> = @R|org/jetbrains/kotlin/fir/plugin/MyComposable|() runComposable@fun <anonymous>(): R|kotlin/Unit| <inline=NoInline> {
^@runComposable Unit
}
)
}
public final fun runComposable2(block: R|some/MyComposableFunction1<kotlin/String, kotlin/Int>|): R|kotlin/Unit| {
}
public final fun test_2(): R|kotlin/Unit| {
R|/runComposable2|(<L> = runComposable2@fun <anonymous>(it: R|kotlin/String|): R|kotlin/Int| <inline=NoInline> {
^ R|<local>/it|.R|kotlin/String.length|
}
)
}
@@ -0,0 +1,31 @@
import org.jetbrains.kotlin.fir.plugin.MyComposable
fun runUsual(block: () -> Unit) {}
fun runComposable(block: @MyComposable () -> Unit) {}
fun test_1() {
val l0 = {}
val l1: some.MyComposableFunction0<Unit> = {}
val l2: @MyComposable (() -> Unit) = {}
val l3 = @MyComposable {}
runUsual(l0) // ok
runUsual(<!ARGUMENT_TYPE_MISMATCH!>l1<!>) // error
runUsual(<!ARGUMENT_TYPE_MISMATCH!>l2<!>) // error
runUsual(<!ARGUMENT_TYPE_MISMATCH!>l3<!>) // error
runUsual {} // ok
runUsual @MyComposable <!ARGUMENT_TYPE_MISMATCH!>{}<!> // error
runComposable(l0) // ok
runComposable(l1) // ok
runComposable(l2) // ok
runComposable(l3) // ok
runComposable {} // ok
runComposable @MyComposable {} // ok
}
fun runComposable2(block: some.MyComposableFunction1<String, Int>) {}
fun test_2() {
runComposable2 { it.length }
}
@@ -46,6 +46,28 @@ public class FirPluginDiagnosticTestGenerated extends AbstractFirPluginDiagnosti
}
}
@Nested
@TestMetadata("plugins/fir-plugin-prototype/testData/diagnostics/functionalTypes")
@TestDataPath("$PROJECT_ROOT")
public class FunctionalTypes {
@Test
public void testAllFilesPresentInFunctionalTypes() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/fir-plugin-prototype/testData/diagnostics/functionalTypes"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("ambigousKinds.kt")
public void testAmbigousKinds() throws Exception {
runTest("plugins/fir-plugin-prototype/testData/diagnostics/functionalTypes/ambigousKinds.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("plugins/fir-plugin-prototype/testData/diagnostics/functionalTypes/simple.kt");
}
}
@Nested
@TestMetadata("plugins/fir-plugin-prototype/testData/diagnostics/memberGen")
@TestDataPath("$PROJECT_ROOT")