[SAM with receiver] Add implementation for K2

This commit is contained in:
Dmitriy Novozhilov
2022-06-22 15:24:15 +03:00
committed by teamcity
parent 49c836e706
commit 65ac82ee46
20 changed files with 306 additions and 39 deletions
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.container.StorageComponentContainer
import org.jetbrains.kotlin.container.useInstance
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.samWithReceiver.SamWithReceiverPluginNames.SUPPORTED_PRESETS
@@ -21,6 +22,7 @@ import org.jetbrains.kotlin.samWithReceiver.SamWithReceiverConfigurationKeys.PRE
import org.jetbrains.kotlin.samWithReceiver.SamWithReceiverPluginNames.ANNOTATION_OPTION_NAME
import org.jetbrains.kotlin.samWithReceiver.SamWithReceiverPluginNames.PLUGIN_ID
import org.jetbrains.kotlin.samWithReceiver.SamWithReceiverPluginNames.PRESET_OPTION_NAME
import org.jetbrains.kotlin.samWithReceiver.k2.FirSamWithReceiverExtensionRegistrar
object SamWithReceiverConfigurationKeys {
val ANNOTATION: CompilerConfigurationKey<List<String>> = CompilerConfigurationKey.create("annotation qualified name")
@@ -60,6 +62,7 @@ class SamWithReceiverComponentRegistrar : ComponentRegistrar {
if (annotations.isEmpty()) return
StorageComponentContainerContributor.registerExtension(project, CliSamWithReceiverComponentContributor(annotations))
FirExtensionRegistrarAdapter.registerExtension(project, FirSamWithReceiverExtensionRegistrar(annotations))
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2022 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.samWithReceiver.k2
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
import org.jetbrains.kotlin.fir.resolve.FirSamConversionTransformerExtension
import org.jetbrains.kotlin.fir.resolve.createFunctionalType
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.utils.addToStdlib.runIf
class FirSamWithReceiverConventionTransformer(
private val annotations: List<String>,
session: FirSession
) : FirSamConversionTransformerExtension(session) {
override fun getCustomFunctionalTypeForSamConversion(function: FirSimpleFunction): ConeLookupTagBasedType? {
val containingClassSymbol = function.containingClass()?.toFirRegularClassSymbol(session) ?: return null
return runIf(containingClassSymbol.resolvedAnnotationClassIds.any { it.asSingleFqName().asString() in annotations }) {
val parameterTypes = function.valueParameters.map { it.returnTypeRef.coneType }
if (parameterTypes.isEmpty()) return null
createFunctionalType(
parameters = parameterTypes.subList(1, parameterTypes.size),
receiverType = parameterTypes[0],
rawReturnType = function.returnTypeRef.coneType,
isSuspend = function.isSuspend
)
}
}
}
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2022 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.samWithReceiver.k2
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
class FirSamWithReceiverExtensionRegistrar(private val annotations: List<String>) : FirExtensionRegistrar() {
override fun ExtensionRegistrarContext.configurePlugin() {
+::FirSamWithReceiverConventionTransformer.bind(annotations)
}
}
@@ -8,14 +8,19 @@ package org.jetbrains.kotlin.samWithReceiver
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
import org.jetbrains.kotlin.samWithReceiver.k2.FirSamWithReceiverExtensionRegistrar
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.DIAGNOSTICS
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.runners.AbstractDiagnosticTest
import org.jetbrains.kotlin.test.runners.AbstractFirDiagnosticTest
import org.jetbrains.kotlin.test.runners.codegen.AbstractFirBlackBoxCodegenTest
import org.jetbrains.kotlin.test.runners.codegen.AbstractIrBlackBoxCodegenTest
import org.jetbrains.kotlin.test.services.EnvironmentConfigurator
import org.jetbrains.kotlin.test.services.TestServices
// ------------------------ diagnostics ------------------------
abstract class AbstractSamWithReceiverTest : AbstractDiagnosticTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
@@ -23,6 +28,29 @@ abstract class AbstractSamWithReceiverTest : AbstractDiagnosticTest() {
}
}
abstract class AbstractFirSamWithReceiverTest : AbstractFirDiagnosticTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.configurePlugin()
}
}
// ------------------------ codegen ------------------------
open class AbstractIrBlackBoxCodegenTestForSamWithReceiver : AbstractIrBlackBoxCodegenTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.configurePlugin()
}
}
open class AbstractFirBlackBoxCodegenTestForSamWithReceiver : AbstractFirBlackBoxCodegenTest() {
override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder)
builder.configurePlugin()
}
}
fun TestConfigurationBuilder.configurePlugin() {
useConfigurators(::SamWithReceiverEnvironmentConfigurator)
}
@@ -37,5 +65,7 @@ class SamWithReceiverEnvironmentConfigurator(testServices: TestServices) : Envir
project,
CliSamWithReceiverComponentContributor(TEST_ANNOTATIONS)
)
FirExtensionRegistrarAdapter.registerExtension(project, FirSamWithReceiverExtensionRegistrar(TEST_ANNOTATIONS))
}
}
@@ -0,0 +1,17 @@
// FILE: Sam.java
@SamWithReceiver
public interface Sam {
String run(String argument);
}
// FILE: test.kt
annotation class SamWithReceiver
fun takeSam(argument: String, sam: Sam): String {
return sam.run(argument)
}
fun box(): String {
val sam = Sam { this }
return takeSam("OK", sam)
}
@@ -0,0 +1,16 @@
// FILE: Sam.java
@SamWithReceiver
public interface Sam {
String run(String argument);
}
// FILE: test.kt
annotation class SamWithReceiver
fun takeSam(argument: String, sam: Sam): String {
return sam.run(argument)
}
fun box(): String {
return takeSam("OK") { this }
}
@@ -1,6 +1,6 @@
// FIR_IDENTICAL
// FILE: Sam.java
// FILE: SamConstructor.kt
@SamWithReceiver
public interface Sam {
void run();
@@ -1,6 +1,4 @@
// FIR_IDENTICAL
// FILE: Sam.java
// FILE: SamConstructor.kt
@SamWithReceiver
public interface Sam {
void run(String a, String b);
@@ -10,7 +8,7 @@ public interface Sam {
annotation class SamWithReceiver
fun test() {
Sam <!TYPE_MISMATCH!>{ <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>a, <!CANNOT_INFER_PARAMETER_TYPE!>b<!><!> ->
Sam <!ARGUMENT_TYPE_MISMATCH!>{ a, <!CANNOT_INFER_PARAMETER_TYPE!>b<!> ->
System.out.println(a)
}<!>
@@ -1,6 +1,6 @@
// FIR_IDENTICAL
// FILE: Sam.java
// FILE: SamConstructor.kt
@SamWithReceiver
public interface Sam {
void run();
@@ -1,6 +1,4 @@
// FIR_IDENTICAL
// FILE: Sam.java
// FILE: SamConstructor.kt
@SamWithReceiver
public interface Sam {
void run(String a);
@@ -17,6 +15,6 @@ annotation class SamWithReceiver
fun test() {
val e = Exec()
e.exec <!TYPE_MISMATCH!>{ <!CANNOT_INFER_PARAMETER_TYPE, EXPECTED_PARAMETERS_NUMBER_MISMATCH!>a<!> -> System.out.<!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!>) }<!>
e.exec <!ARGUMENT_TYPE_MISMATCH!>{ <!CANNOT_INFER_PARAMETER_TYPE!>a<!> -> System.out.<!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(a) }<!>
e.exec { System.out.println(this) }
}
@@ -1,6 +1,4 @@
// FIR_IDENTICAL
// FILE: Sam.java
// FILE: SamConstructor.kt
public interface Sam {
void run(String a);
}
@@ -15,5 +13,5 @@ fun test() {
val e = Exec()
e.exec { a -> System.out.println(a) }
e.exec { System.out.println(<!NO_THIS!>this<!>) }
e.exec { System.out.<!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(<!NO_THIS!>this<!>) }
}
@@ -1,6 +1,4 @@
// FIR_IDENTICAL
// FILE: Sam.java
// FILE: SamConstructor.kt
@SamWithReceiver
public interface Sam {
String run(String a, String b);
@@ -10,7 +8,7 @@ public interface Sam {
annotation class SamWithReceiver
fun test() {
Sam <!TYPE_MISMATCH!>{ <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>a, <!CANNOT_INFER_PARAMETER_TYPE!>b<!><!> ->
Sam <!ARGUMENT_TYPE_MISMATCH!>{ a, <!CANNOT_INFER_PARAMETER_TYPE!>b<!> ->
System.out.println(a)
""
}<!>
@@ -1,6 +1,4 @@
// FIR_IDENTICAL
// FILE: Sam.java
// FILE: SamConstructor.kt
public interface Sam {
String run(String a, String b);
}
@@ -12,9 +10,9 @@ fun test() {
""
}
Sam <!TYPE_MISMATCH!>{ <!EXPECTED_PARAMETERS_NUMBER_MISMATCH!>b<!> ->
val a = <!NO_THIS!>this@Sam<!>
System.out.<!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!>)
Sam <!ARGUMENT_TYPE_MISMATCH!>{ b ->
val a = this<!UNRESOLVED_LABEL!>@Sam<!>
System.out.<!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(a)
""
}<!>
}
@@ -1,6 +1,4 @@
// FIR_IDENTICAL
// FILE: Sam.java
// FILE: SamConstructor.kt
@SamWithReceiver
public interface Sam {
void run(String a);
@@ -10,8 +8,8 @@ public interface Sam {
annotation class SamWithReceiver
fun test() {
Sam <!TYPE_MISMATCH!>{ <!CANNOT_INFER_PARAMETER_TYPE, EXPECTED_PARAMETERS_NUMBER_MISMATCH!>a<!> ->
System.out.<!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!>)
Sam <!ARGUMENT_TYPE_MISMATCH!>{ <!CANNOT_INFER_PARAMETER_TYPE!>a<!> ->
System.out.<!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(a)
}<!>
Sam {
@@ -1,6 +1,4 @@
// FIR_IDENTICAL
// FILE: Sam.java
// FILE: SamConstructor.kt
public interface Sam {
void run(String a);
}
@@ -13,6 +11,6 @@ fun test() {
Sam {
val a = <!NO_THIS!>this<!>
System.out.<!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!>)
System.out.<!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(a)
}
}
@@ -8,7 +8,7 @@ import java.lang.annotation.RetentionPolicy;
public @interface SamWithReceiver1 {
}
// FILE: Sam.java
// FILE: SamConstructor.kt
@SamWithReceiver1
public interface Sam {
void run(String a, String b);
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2021 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.samWithReceiver;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
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 GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("plugins/sam-with-receiver/testData/codegen")
@TestDataPath("$PROJECT_ROOT")
public class FirBlackBoxCodegenTestForSamWithReceiverGenerated extends AbstractFirBlackBoxCodegenTestForSamWithReceiver {
@Test
public void testAllFilesPresentInCodegen() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/sam-with-receiver/testData/codegen"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("SamConstructor.kt")
public void testSamConstructor() throws Exception {
runTest("plugins/sam-with-receiver/testData/codegen/SamConstructor.kt");
}
@Test
@TestMetadata("SamConversion.kt")
public void testSamConversion() throws Exception {
runTest("plugins/sam-with-receiver/testData/codegen/SamConversion.kt");
}
}
@@ -0,0 +1,80 @@
/*
* Copyright 2010-2021 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.samWithReceiver;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
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 GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("plugins/sam-with-receiver/testData/diagnostics")
@TestDataPath("$PROJECT_ROOT")
public class FirSamWithReceiverTestGenerated extends AbstractFirSamWithReceiverTest {
@Test
public void testAllFilesPresentInDiagnostics() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/sam-with-receiver/testData/diagnostics"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("noParameters.kt")
public void testNoParameters() throws Exception {
runTest("plugins/sam-with-receiver/testData/diagnostics/noParameters.kt");
}
@Test
@TestMetadata("noReturnType.kt")
public void testNoReturnType() throws Exception {
runTest("plugins/sam-with-receiver/testData/diagnostics/noReturnType.kt");
}
@Test
@TestMetadata("samConversionNoParameters.kt")
public void testSamConversionNoParameters() throws Exception {
runTest("plugins/sam-with-receiver/testData/diagnostics/samConversionNoParameters.kt");
}
@Test
@TestMetadata("samConversionSimple.kt")
public void testSamConversionSimple() throws Exception {
runTest("plugins/sam-with-receiver/testData/diagnostics/samConversionSimple.kt");
}
@Test
@TestMetadata("samConversionSimpleWithoutAnnotation.kt")
public void testSamConversionSimpleWithoutAnnotation() throws Exception {
runTest("plugins/sam-with-receiver/testData/diagnostics/samConversionSimpleWithoutAnnotation.kt");
}
@Test
@TestMetadata("samWithAnnotation.kt")
public void testSamWithAnnotation() throws Exception {
runTest("plugins/sam-with-receiver/testData/diagnostics/samWithAnnotation.kt");
}
@Test
@TestMetadata("samWithoutAnnotation.kt")
public void testSamWithoutAnnotation() throws Exception {
runTest("plugins/sam-with-receiver/testData/diagnostics/samWithoutAnnotation.kt");
}
@Test
@TestMetadata("singleParameter.kt")
public void testSingleParameter() throws Exception {
runTest("plugins/sam-with-receiver/testData/diagnostics/singleParameter.kt");
}
@Test
@TestMetadata("singleParameterWithoutAnnotation.kt")
public void testSingleParameterWithoutAnnotation() throws Exception {
runTest("plugins/sam-with-receiver/testData/diagnostics/singleParameterWithoutAnnotation.kt");
}
}
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2021 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.samWithReceiver;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TargetBackend;
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 GenerateNewCompilerTests.kt}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("plugins/sam-with-receiver/testData/codegen")
@TestDataPath("$PROJECT_ROOT")
public class IrBlackBoxCodegenTestForSamWithReceiverGenerated extends AbstractIrBlackBoxCodegenTestForSamWithReceiver {
@Test
public void testAllFilesPresentInCodegen() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/sam-with-receiver/testData/codegen"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("SamConstructor.kt")
public void testSamConstructor() throws Exception {
runTest("plugins/sam-with-receiver/testData/codegen/SamConstructor.kt");
}
@Test
@TestMetadata("SamConversion.kt")
public void testSamConversion() throws Exception {
runTest("plugins/sam-with-receiver/testData/codegen/SamConversion.kt");
}
}