FIR: Support context receiver in FIR building

This commit is contained in:
Denis.Zharkov
2022-02-17 14:01:58 +03:00
committed by teamcity
parent 4379460177
commit 54c3e7e7c5
12 changed files with 157 additions and 0 deletions
@@ -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 {
@@ -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<FirContextReceiver> {
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)
}
}
}
}
}
@@ -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");
@@ -1024,6 +1024,19 @@ open class RawFirBuilder(
}
}
private fun convertContextReceivers(receivers: List<KtContextReceiver>): List<FirContextReceiver> {
return receivers.map { contextReceiverElement ->
buildContextReceiver {
this.source = contextReceiverElement.toFirSourceElement()
this.labelName = contextReceiverElement.labelNameAsName()
contextReceiverElement.typeReference().convertSafe<FirTypeRef>()?.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<KtEnumEntry>() != 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 {
@@ -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) {}
@@ -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<R|kotlin/Any|>()
}
}
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 }
@@ -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<R|kotlin/Any|>()
}
}
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| {
}
@@ -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");
@@ -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");
@@ -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<FirContextReceiver>) {
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) {
@@ -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 {
@@ -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 {