diff --git a/compiler/fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/AbstractRawFirBuilderTestCase.kt b/compiler/fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/AbstractRawFirBuilderTestCase.kt index d20f5dbadd4..ea38eaccf6c 100644 --- a/compiler/fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/AbstractRawFirBuilderTestCase.kt +++ b/compiler/fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/AbstractRawFirBuilderTestCase.kt @@ -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().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 transformElement(element: E, data: Unit): CompositeTransformResult { 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") } 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 2b76e7855f9..11c8d38a2f8 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt @@ -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(".") } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirQualifiedAccess.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirQualifiedAccess.kt index 561d488d924..3b0feeb52ba 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirQualifiedAccess.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirQualifiedAccess.kt @@ -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 transformCalleeReference(transformer: FirTransformer, data: D): FirQualifiedAccess override fun accept(visitor: FirVisitor, data: D): R = @@ -21,6 +26,8 @@ interface FirQualifiedAccess : FirResolvable { override fun acceptChildren(visitor: FirVisitor, data: D) { calleeReference.accept(visitor, data) explicitReceiver?.accept(visitor, data) + dispatchReceiver.accept(visitor, data) + extensionReceiver.accept(visitor, data) super.acceptChildren(visitor, data) } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirQualifiedAccessExpression.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirQualifiedAccessExpression.kt index 0ad7c2db471..4de93736a01 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirQualifiedAccessExpression.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirQualifiedAccessExpression.kt @@ -19,6 +19,8 @@ abstract class FirQualifiedAccessExpression( override fun acceptChildren(visitor: FirVisitor, data: D) { calleeReference.accept(visitor, data) explicitReceiver?.accept(visitor, data) + dispatchReceiver.accept(visitor, data) + extensionReceiver.accept(visitor, data) super.acceptChildren(visitor, data) } } \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirAbstractQualifiedAccess.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirAbstractQualifiedAccess.kt index f53e258ccd1..263fd1ef066 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirAbstractQualifiedAccess.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirAbstractQualifiedAccess.kt @@ -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 transformChildren(transformer: FirTransformer, 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.transformChildren(transformer, data) } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirFunctionCallImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirFunctionCallImpl.kt index 35a438a8bd2..563870470f6 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirFunctionCallImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirFunctionCallImpl.kt @@ -23,10 +23,17 @@ class FirFunctionCallImpl( override var explicitReceiver: FirExpression? = null + override var dispatchReceiver: FirExpression = FirNoReceiverExpression + + override var extensionReceiver: FirExpression = FirNoReceiverExpression + override fun transformChildren(transformer: FirTransformer, 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.transformChildren(transformer, data) } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirNoReceiverExpression.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirNoReceiverExpression.kt new file mode 100644 index 00000000000..350cb02781c --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirNoReceiverExpression.kt @@ -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 acceptChildren(visitor: FirVisitor, data: D) {} +} \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirQualifiedAccessExpressionImpl.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirQualifiedAccessExpressionImpl.kt index 526e1820efb..fd4c2a7d357 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirQualifiedAccessExpressionImpl.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirQualifiedAccessExpressionImpl.kt @@ -21,9 +21,15 @@ class FirQualifiedAccessExpressionImpl( override var explicitReceiver: FirExpression? = null + override var dispatchReceiver: FirExpression = FirNoReceiverExpression + + override var extensionReceiver: FirExpression = FirNoReceiverExpression + override fun transformChildren(transformer: FirTransformer, 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.transformChildren(transformer, data) }