FIR tree: add dispatch & extension receivers

This commit is contained in:
Mikhail Glukhikh
2019-08-27 13:25:38 +03:00
parent da22898a19
commit c63919f224
8 changed files with 70 additions and 7 deletions
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.expressions.FirWrappedDelegateExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirWrappedDelegateExpressionImpl
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
@@ -80,6 +81,7 @@ abstract class AbstractRawFirBuilderTestCase : KtParsingTestCase(
val childElement = property.getter.apply { isAccessible = true }.call(this)
when (childElement) {
is FirNoReceiverExpression -> continue@propertyLoop
is FirElement -> childElement.traverseChildren(result)
is List<*> -> childElement.filterIsInstance<FirElement>().forEach { it.traverseChildren(result) }
else -> continue@propertyLoop
@@ -129,7 +131,7 @@ abstract class AbstractRawFirBuilderTestCase : KtParsingTestCase(
override fun visitElement(element: FirElement) {
// NB: types are reused sometimes (e.g. in accessors)
if (!result.add(element)) {
if (element !is FirTypeRef) {
if (element !is FirTypeRef && element !is FirNoReceiverExpression) {
val elementDump = StringBuilder().also { element.accept(FirRenderer(it)) }.toString()
throw AssertionError("FirElement ${element.javaClass} is visited twice: $elementDump")
}
@@ -146,7 +148,7 @@ abstract class AbstractRawFirBuilderTestCase : KtParsingTestCase(
override fun <E : FirElement> transformElement(element: E, data: Unit): CompositeTransformResult<E> {
if (!result.add(element)) {
if (element !is FirTypeRef) {
if (element !is FirTypeRef && element !is FirNoReceiverExpression) {
val elementDump = StringBuilder().also { element.accept(FirRenderer(it)) }.toString()
throw AssertionError("FirElement ${element.javaClass} is visited twice: $elementDump")
}
@@ -10,10 +10,7 @@ import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub
import org.jetbrains.kotlin.fir.expressions.impl.FirLoopJump
import org.jetbrains.kotlin.fir.expressions.impl.FirUnitExpression
import org.jetbrains.kotlin.fir.expressions.impl.*
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
@@ -827,13 +824,29 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
override fun visitQualifiedAccess(qualifiedAccess: FirQualifiedAccess) {
val explicitReceiver = qualifiedAccess.explicitReceiver
val dispatchReceiver = qualifiedAccess.dispatchReceiver
val extensionReceiver = qualifiedAccess.extensionReceiver
if (dispatchReceiver !is FirNoReceiverExpression) {
print("D|")
dispatchReceiver.accept(this)
print("|")
}
if (extensionReceiver !is FirNoReceiverExpression) {
print("E|")
extensionReceiver.accept(this)
print("|")
}
if (explicitReceiver != null) {
explicitReceiver.accept(this)
if (explicitReceiver !== dispatchReceiver && explicitReceiver !== extensionReceiver) {
explicitReceiver.accept(this)
}
if (qualifiedAccess.safe) {
print("?.")
} else {
print(".")
}
} else if (dispatchReceiver !is FirNoReceiverExpression || extensionReceiver !is FirNoReceiverExpression) {
print(".")
}
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.expressions
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitor
@@ -13,6 +14,10 @@ interface FirQualifiedAccess : FirResolvable {
val explicitReceiver: FirExpression? get() = null
val dispatchReceiver: FirExpression get() = FirNoReceiverExpression
val extensionReceiver: FirExpression get() = FirNoReceiverExpression
fun <D> transformCalleeReference(transformer: FirTransformer<D>, data: D): FirQualifiedAccess
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
@@ -21,6 +26,8 @@ interface FirQualifiedAccess : FirResolvable {
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
calleeReference.accept(visitor, data)
explicitReceiver?.accept(visitor, data)
dispatchReceiver.accept(visitor, data)
extensionReceiver.accept(visitor, data)
super.acceptChildren(visitor, data)
}
@@ -19,6 +19,8 @@ abstract class FirQualifiedAccessExpression(
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
calleeReference.accept(visitor, data)
explicitReceiver?.accept(visitor, data)
dispatchReceiver.accept(visitor, data)
extensionReceiver.accept(visitor, data)
super<FirUnknownTypeExpression>.acceptChildren(visitor, data)
}
}
@@ -19,9 +19,16 @@ abstract class FirAbstractQualifiedAccess(
final override var explicitReceiver: FirExpression? = null
override var dispatchReceiver: FirExpression = FirNoReceiverExpression
override var extensionReceiver: FirExpression = FirNoReceiverExpression
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement {
calleeReference = calleeReference.transformSingle(transformer, data)
explicitReceiver = explicitReceiver?.transformSingle(transformer, data)
dispatchReceiver = dispatchReceiver.transformSingle(transformer, data)
extensionReceiver = extensionReceiver.transformSingle(transformer, data)
return super<FirAnnotatedStatement>.transformChildren(transformer, data)
}
@@ -23,10 +23,17 @@ class FirFunctionCallImpl(
override var explicitReceiver: FirExpression? = null
override var dispatchReceiver: FirExpression = FirNoReceiverExpression
override var extensionReceiver: FirExpression = FirNoReceiverExpression
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement {
typeArguments.transformInplace(transformer, data)
calleeReference = calleeReference.transformSingle(transformer, data)
explicitReceiver = explicitReceiver?.transformSingle(transformer, data)
dispatchReceiver = dispatchReceiver.transformSingle(transformer, data)
extensionReceiver = extensionReceiver.transformSingle(transformer, data)
return super<FirFunctionCall>.transformChildren(transformer, data)
}
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2019 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.expressions.impl
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl
import org.jetbrains.kotlin.fir.visitors.FirVisitor
object FirNoReceiverExpression : FirExpression(null) {
override val typeRef: FirTypeRef = FirImplicitTypeRefImpl(null)
override fun replaceTypeRef(newTypeRef: FirTypeRef) {}
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {}
}
@@ -21,9 +21,15 @@ class FirQualifiedAccessExpressionImpl(
override var explicitReceiver: FirExpression? = null
override var dispatchReceiver: FirExpression = FirNoReceiverExpression
override var extensionReceiver: FirExpression = FirNoReceiverExpression
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement {
calleeReference = calleeReference.transformSingle(transformer, data)
explicitReceiver = explicitReceiver?.transformSingle(transformer, data)
dispatchReceiver = dispatchReceiver.transformSingle(transformer, data)
extensionReceiver = extensionReceiver.transformSingle(transformer, data)
return super<FirQualifiedAccessExpression>.transformChildren(transformer, data)
}