From 54c3e7e7c51253463352dbaf7a1d5a3f88e1b90c Mon Sep 17 00:00:00 2001 From: "Denis.Zharkov" Date: Thu, 17 Feb 2022 14:01:58 +0300 Subject: [PATCH] FIR: Support context receiver in FIR building --- .../FirLazyBodiesCalculatorTestGenerated.java | 6 ++++ .../converter/DeclarationsConverter.kt | 29 +++++++++++++++++++ ...ghtTree2FirConverterTestCaseGenerated.java | 5 ++++ .../kotlin/fir/builder/RawFirBuilder.kt | 24 +++++++++++++++ .../declarations/contextReceivers.kt | 11 +++++++ .../contextReceivers.lazyBodies.txt | 15 ++++++++++ .../declarations/contextReceivers.txt | 20 +++++++++++++ ...FirBuilderLazyBodiesTestCaseGenerated.java | 5 ++++ .../RawFirBuilderTestCaseGenerated.java | 5 ++++ .../org/jetbrains/kotlin/fir/FirRenderer.kt | 25 ++++++++++++++++ .../FirVisualizerForRawFirDataGenerated.java | 6 ++++ .../PsiVisualizerForRawFirDataGenerated.java | 6 ++++ 12 files changed, 157 insertions(+) create mode 100644 compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.kt create mode 100644 compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.lazyBodies.txt create mode 100644 compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.txt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirLazyBodiesCalculatorTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirLazyBodiesCalculatorTestGenerated.java index fd2329d5470..6822bda9625 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirLazyBodiesCalculatorTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirLazyBodiesCalculatorTestGenerated.java @@ -69,6 +69,12 @@ public class FirLazyBodiesCalculatorTestGenerated extends AbstractFirLazyBodiesC runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/constructorOfAnonymousObject.kt"); } + @Test + @TestMetadata("contextReceivers.kt") + public void testContextReceivers() throws Exception { + runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.kt"); + } + @Test @TestMetadata("delegates.kt") public void testDelegates() throws Exception { diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt index dafeaec01f0..6c8a56579f6 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt @@ -591,6 +591,8 @@ class DeclarationsConverter( ) } initCompanionObjectSymbolAttr() + + contextReceivers.addAll(convertContextReceivers(classNode)) }.also { it.delegateFieldsMap = delegatedFieldsMap } @@ -1234,6 +1236,8 @@ class DeclarationsConverter( it.useSiteTarget != PROPERTY_GETTER && (!isVar || it.useSiteTarget != SETTER_PARAMETER && it.useSiteTarget != PROPERTY_SETTER) } + + contextReceivers.addAll(convertContextReceivers(property)) }.also { fillDanglingConstraintsTo(firTypeParameters, typeConstraints, it) } @@ -1615,6 +1619,7 @@ class DeclarationsConverter( symbol = functionSymbol dispatchReceiverType = currentDispatchReceiverType() + contextReceivers.addAll(convertContextReceivers(functionDeclaration)) } } @@ -2160,6 +2165,11 @@ class DeclarationsConverter( annotations += extensionFunctionAnnotation } this.isSuspend = isSuspend + this.contextReceiverTypeRefs.addAll( + functionType.getChildNodeByType(CONTEXT_RECEIVER_LIST)?.getChildNodesByType(CONTEXT_RECEIVER)?.mapNotNull { + it.getChildNodeByType(TYPE_REFERENCE)?.let(::convertType) + }.orEmpty() + ) } } @@ -2259,4 +2269,23 @@ class DeclarationsConverter( to.danglingTypeConstraints = result } } + + private fun convertContextReceivers(container: LighterASTNode): List { + val receivers = container.getChildNodeByType(CONTEXT_RECEIVER_LIST)?.getChildNodesByType(CONTEXT_RECEIVER) ?: emptyList() + return receivers.map { contextReceiverElement -> + buildContextReceiver { + this.source = contextReceiverElement.toFirSourceElement() + this.labelName = + contextReceiverElement + .getChildNodeByType(LABEL_QUALIFIER) + ?.getChildNodeByType(LABEL) + ?.getChildNodeByType(IDENTIFIER) + ?.getReferencedNameAsName() + + contextReceiverElement.getChildNodeByType(TYPE_REFERENCE)?.let { + this.typeRef = convertType(it) + } + } + } + } } diff --git a/compiler/fir/raw-fir/light-tree2fir/tests-gen/org/jetbrains/kotlin/fir/lightTree/LightTree2FirConverterTestCaseGenerated.java b/compiler/fir/raw-fir/light-tree2fir/tests-gen/org/jetbrains/kotlin/fir/lightTree/LightTree2FirConverterTestCaseGenerated.java index cf19fcfb272..20d1b4c32f2 100644 --- a/compiler/fir/raw-fir/light-tree2fir/tests-gen/org/jetbrains/kotlin/fir/lightTree/LightTree2FirConverterTestCaseGenerated.java +++ b/compiler/fir/raw-fir/light-tree2fir/tests-gen/org/jetbrains/kotlin/fir/lightTree/LightTree2FirConverterTestCaseGenerated.java @@ -71,6 +71,11 @@ public class LightTree2FirConverterTestCaseGenerated extends AbstractLightTree2F runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/constructorOfAnonymousObject.kt"); } + @TestMetadata("contextReceivers.kt") + public void testContextReceivers() throws Exception { + runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.kt"); + } + @TestMetadata("delegates.kt") public void testDelegates() throws Exception { runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/delegates.kt"); diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index 0b7c9443474..e68413b347d 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -1024,6 +1024,19 @@ open class RawFirBuilder( } } + private fun convertContextReceivers(receivers: List): List { + return receivers.map { contextReceiverElement -> + buildContextReceiver { + this.source = contextReceiverElement.toFirSourceElement() + this.labelName = contextReceiverElement.labelNameAsName() + + contextReceiverElement.typeReference().convertSafe()?.let { + this.typeRef = it + } + } + } + } + override fun visitClassOrObject(classOrObject: KtClassOrObject, data: Unit): FirElement { // NB: enum entry nested classes are considered local by FIR design (see discussion in KT-45115) val isLocal = classOrObject.isLocal || classOrObject.getStrictParentOfType() != null @@ -1151,6 +1164,7 @@ open class RawFirBuilder( initCompanionObjectSymbolAttr() context.popFirTypeParameters() + contextReceivers.addAll(convertContextReceivers(classOrObject.contextReceivers)) }.also { it.delegateFieldsMap = delegatedFieldsMap } @@ -1267,6 +1281,8 @@ open class RawFirBuilder( isExternal = function.hasModifier(EXTERNAL_KEYWORD) isSuspend = function.hasModifier(SUSPEND_KEYWORD) } + + contextReceivers.addAll(convertContextReceivers(function.contextReceivers)) } } @@ -1646,6 +1662,8 @@ open class RawFirBuilder( it.useSiteTarget != PROPERTY_GETTER && (!isVar || it.useSiteTarget != SETTER_PARAMETER && it.useSiteTarget != PROPERTY_SETTER) } + + contextReceivers.addAll(convertContextReceivers(this@toFirProperty.contextReceivers)) }.also { if (!isLocal) { fillDanglingConstraintsTo(it) @@ -1756,6 +1774,12 @@ open class RawFirBuilder( if (receiverTypeRef != null) { annotations += extensionFunctionAnnotation } + + contextReceiverTypeRefs.addAll( + unwrappedElement.contextReceiversTypeReferences.mapNotNull { + it.convertSafe() + } + ) } } is KtIntersectionType -> FirIntersectionTypeRefBuilder().apply { diff --git a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.kt b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.kt new file mode 100644 index 00000000000..34a3dfd84e4 --- /dev/null +++ b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.kt @@ -0,0 +1,11 @@ +context(A, b@B) +fun foo() {} + +context(A, b@B) +val x: Int get() = 1 + +context(A, b@B) +class C + +fun bar1(x: context(A, B)() -> Unit) {} +fun bar2(x: context(A, B) C.() -> Unit) {} diff --git a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.lazyBodies.txt b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.lazyBodies.txt new file mode 100644 index 00000000000..3b789ebfcb3 --- /dev/null +++ b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.lazyBodies.txt @@ -0,0 +1,15 @@ +FILE: contextReceivers.kt + context(A, b@B) + public? final? fun foo(): R|kotlin/Unit| { LAZY_BLOCK } + context(A, b@B) + public? final? val x: Int + public? get(): Int { LAZY_BLOCK } + context(A, b@B) + public? final? class C : R|kotlin/Any| { + public? constructor(): R|C| { + super() + } + + } + public? final? fun bar1(x: context(A, B)( () -> Unit )): R|kotlin/Unit| { LAZY_BLOCK } + public? final? fun bar2(x: context(A, B)( C.() -> Unit )): R|kotlin/Unit| { LAZY_BLOCK } diff --git a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.txt b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.txt new file mode 100644 index 00000000000..f4939814b6d --- /dev/null +++ b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.txt @@ -0,0 +1,20 @@ +FILE: contextReceivers.kt + context(A, b@B) + public? final? fun foo(): R|kotlin/Unit| { + } + context(A, b@B) + public? final? val x: Int + public? get(): Int { + ^ IntegerLiteral(1) + } + context(A, b@B) + public? final? class C : R|kotlin/Any| { + public? [ContainingClassKey=C] constructor(): R|C| { + super() + } + + } + public? final? fun bar1(x: context(A, B)( () -> Unit )): R|kotlin/Unit| { + } + public? final? fun bar2(x: context(A, B)( C.() -> Unit )): R|kotlin/Unit| { + } diff --git a/compiler/fir/raw-fir/psi2fir/tests-gen/org/jetbrains/kotlin/fir/builder/RawFirBuilderLazyBodiesTestCaseGenerated.java b/compiler/fir/raw-fir/psi2fir/tests-gen/org/jetbrains/kotlin/fir/builder/RawFirBuilderLazyBodiesTestCaseGenerated.java index 7cbe29ffb4c..3836398456e 100644 --- a/compiler/fir/raw-fir/psi2fir/tests-gen/org/jetbrains/kotlin/fir/builder/RawFirBuilderLazyBodiesTestCaseGenerated.java +++ b/compiler/fir/raw-fir/psi2fir/tests-gen/org/jetbrains/kotlin/fir/builder/RawFirBuilderLazyBodiesTestCaseGenerated.java @@ -71,6 +71,11 @@ public class RawFirBuilderLazyBodiesTestCaseGenerated extends AbstractRawFirBuil runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/constructorOfAnonymousObject.kt"); } + @TestMetadata("contextReceivers.kt") + public void testContextReceivers() throws Exception { + runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.kt"); + } + @TestMetadata("delegates.kt") public void testDelegates() throws Exception { runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/delegates.kt"); diff --git a/compiler/fir/raw-fir/psi2fir/tests-gen/org/jetbrains/kotlin/fir/builder/RawFirBuilderTestCaseGenerated.java b/compiler/fir/raw-fir/psi2fir/tests-gen/org/jetbrains/kotlin/fir/builder/RawFirBuilderTestCaseGenerated.java index b1d63e1eda6..e7e4567fe95 100644 --- a/compiler/fir/raw-fir/psi2fir/tests-gen/org/jetbrains/kotlin/fir/builder/RawFirBuilderTestCaseGenerated.java +++ b/compiler/fir/raw-fir/psi2fir/tests-gen/org/jetbrains/kotlin/fir/builder/RawFirBuilderTestCaseGenerated.java @@ -71,6 +71,11 @@ public class RawFirBuilderTestCaseGenerated extends AbstractRawFirBuilderTestCas runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/constructorOfAnonymousObject.kt"); } + @TestMetadata("contextReceivers.kt") + public void testContextReceivers() throws Exception { + runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.kt"); + } + @TestMetadata("delegates.kt") public void testDelegates() throws Exception { runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/delegates.kt"); diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt index 3c127e382e9..54484e64152 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt @@ -235,6 +235,8 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode = } override fun visitCallableDeclaration(callableDeclaration: FirCallableDeclaration) { + renderContexts(callableDeclaration.contextReceivers) + callableDeclaration.contextReceivers callableDeclaration.annotations.renderAnnotations() visitMemberDeclaration(callableDeclaration) val receiverType = callableDeclaration.receiverTypeRef @@ -269,6 +271,22 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode = callableDeclaration.renderContractDescription() } + private fun renderContexts(contextReceivers: List) { + if (contextReceivers.isEmpty()) return + print("context(") + contextReceivers.renderSeparated() + print(")") + newLine() + } + + override fun visitContextReceiver(contextReceiver: FirContextReceiver) { + contextReceiver.labelName?.let { + print(it.asString() + "@") + } + + contextReceiver.typeRef.accept(this) + } + private fun FirDeclaration.renderContractDescription() { val contractDescription = (this as? FirContractDescriptionOwner)?.contractDescription ?: return pushIndent() @@ -487,6 +505,7 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode = } override fun visitRegularClass(regularClass: FirRegularClass) { + renderContexts(regularClass.contextReceivers) regularClass.annotations.renderAnnotations() visitMemberDeclaration(regularClass) renderSupertypes(regularClass) @@ -1082,6 +1101,12 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode = } override fun visitFunctionTypeRef(functionTypeRef: FirFunctionTypeRef) { + if (functionTypeRef.contextReceiverTypeRefs.isNotEmpty()) { + print("context(") + functionTypeRef.contextReceiverTypeRefs.renderSeparated() + print(")") + } + functionTypeRef.annotations.dropExtensionFunctionAnnotation().renderAnnotations() print("( ") if (functionTypeRef.isSuspend) { diff --git a/compiler/visualizer/tests-gen/org/jetbrains/kotlin/visualizer/fir/FirVisualizerForRawFirDataGenerated.java b/compiler/visualizer/tests-gen/org/jetbrains/kotlin/visualizer/fir/FirVisualizerForRawFirDataGenerated.java index 971684c5da2..2bb8fa16f53 100644 --- a/compiler/visualizer/tests-gen/org/jetbrains/kotlin/visualizer/fir/FirVisualizerForRawFirDataGenerated.java +++ b/compiler/visualizer/tests-gen/org/jetbrains/kotlin/visualizer/fir/FirVisualizerForRawFirDataGenerated.java @@ -69,6 +69,12 @@ public class FirVisualizerForRawFirDataGenerated extends AbstractFirVisualizerTe runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/constructorOfAnonymousObject.kt"); } + @Test + @TestMetadata("contextReceivers.kt") + public void testContextReceivers() throws Exception { + runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.kt"); + } + @Test @TestMetadata("delegates.kt") public void testDelegates() throws Exception { diff --git a/compiler/visualizer/tests-gen/org/jetbrains/kotlin/visualizer/psi/PsiVisualizerForRawFirDataGenerated.java b/compiler/visualizer/tests-gen/org/jetbrains/kotlin/visualizer/psi/PsiVisualizerForRawFirDataGenerated.java index a61152ff5a8..eb023be0d1a 100644 --- a/compiler/visualizer/tests-gen/org/jetbrains/kotlin/visualizer/psi/PsiVisualizerForRawFirDataGenerated.java +++ b/compiler/visualizer/tests-gen/org/jetbrains/kotlin/visualizer/psi/PsiVisualizerForRawFirDataGenerated.java @@ -69,6 +69,12 @@ public class PsiVisualizerForRawFirDataGenerated extends AbstractPsiVisualizerTe runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/constructorOfAnonymousObject.kt"); } + @Test + @TestMetadata("contextReceivers.kt") + public void testContextReceivers() throws Exception { + runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/contextReceivers.kt"); + } + @Test @TestMetadata("delegates.kt") public void testDelegates() throws Exception {