FIR: Support context receiver in FIR building
This commit is contained in:
+6
@@ -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 {
|
||||
|
||||
+29
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -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 {
|
||||
|
||||
+11
@@ -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) {}
|
||||
Vendored
+15
@@ -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 }
|
||||
+20
@@ -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| {
|
||||
}
|
||||
+5
@@ -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");
|
||||
|
||||
+5
@@ -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) {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user