From 8cac3f654cf389aad9ec70cf7466571b1ea7963d Mon Sep 17 00:00:00 2001 From: Mark Punzalan Date: Fri, 18 Sep 2020 22:42:29 -0700 Subject: [PATCH] [FIR] Handle pre/postfix dec/increment of labeled expression --- .../fir/lightTree/converter/BaseConverter.kt | 21 ++++++--- .../kotlin/fir/builder/RawFirBuilder.kt | 4 ++ .../kotlin/fir/builder/BaseFirBuilder.kt | 43 ++++++++++--------- .../codegen/box/intrinsics/incWithLabel.kt | 1 - .../diagnostics/tests/LValueAssignment.fir.kt | 6 +-- 5 files changed, 44 insertions(+), 31 deletions(-) diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt index 73f829ade1b..f24a93bb760 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt @@ -62,20 +62,29 @@ open class BaseConverter( return null } - override fun LighterASTNode.getExpressionInParentheses(): LighterASTNode? { - this.forEachChildren { + override fun LighterASTNode.getExpressionInParentheses() = getFirstChildExpression() + + override fun LighterASTNode.getAnnotatedExpression() = getFirstChildExpression() + + override fun LighterASTNode.getLabeledExpression() = getLastChildExpression() + + private fun LighterASTNode.getFirstChildExpression(): LighterASTNode? { + forEachChildren { if (it.isExpression()) return it } return null } - override fun LighterASTNode.getAnnotatedExpression(): LighterASTNode? { - this.forEachChildren { - if (it.isExpression()) return it + private fun LighterASTNode.getLastChildExpression(): LighterASTNode? { + var result: LighterASTNode? = null + forEachChildren { + if (it.isExpression()) { + result = it + } } - return null + return result } override fun LighterASTNode.getChildNodeByType(type: IElementType): LighterASTNode? { 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 5d08b6d9626..b8c472d58d3 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 @@ -122,6 +122,10 @@ class RawFirBuilder( return (this as KtAnnotatedExpression).baseExpression } + override fun PsiElement.getLabeledExpression(): PsiElement? { + return (this as KtLabeledExpression).baseExpression + } + override val PsiElement?.receiverExpression: PsiElement? get() = (this as? KtQualifiedExpression)?.receiverExpression diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt index 917320ed62f..70d71f8f653 100644 --- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt @@ -51,6 +51,7 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte abstract fun T.getLabelName(): String? abstract fun T.getExpressionInParentheses(): T? abstract fun T.getAnnotatedExpression(): T? + abstract fun T.getLabeledExpression(): T? abstract fun T.getChildNodeByType(type: IElementType): T? abstract val T?.receiverExpression: T? abstract val T?.selectorExpression: T? @@ -405,29 +406,29 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte prefix: Boolean, convert: T.() -> FirExpression ): FirExpression { - if (argument == null) { + // NOTE: By removing surrounding parentheses and labels, FirLabels will NOT be created for those labels. + // This should be fine since the label is meaningless and unusable for a ++/-- argument. + var unwrappedArgument = argument + while (true) { + unwrappedArgument = when (unwrappedArgument?.elementType) { + PARENTHESIZED -> unwrappedArgument?.getExpressionInParentheses() + LABELED_EXPRESSION -> unwrappedArgument?.getLabeledExpression() + else -> break + } + } + + if (unwrappedArgument == null) { return buildErrorExpression { - source = argument + source = unwrappedArgument diagnostic = ConeSimpleDiagnostic("Inc/dec without operand", DiagnosticKind.Syntax) } } - if (argument.elementType == PARENTHESIZED) { - return generateIncrementOrDecrementBlock( - baseExpression, - operationReference, - argument.getExpressionInParentheses(), - callName, - prefix, - convert - ) - } - - if (argument.elementType == DOT_QUALIFIED_EXPRESSION) { + if (unwrappedArgument.elementType == DOT_QUALIFIED_EXPRESSION) { return generateIncrementOrDecrementBlockForQualifiedAccess( baseExpression, operationReference, - argument, + unwrappedArgument, callName, prefix, convert @@ -444,7 +445,7 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte this@BaseFirBuilder.baseSession, desugaredSource, Name.special(""), - argument.convert() + unwrappedArgument.convert() ) // resultInitializer is the expression for `argument.inc()` @@ -455,7 +456,7 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte name = callName } explicitReceiver = if (prefix) { - argument.convert() + unwrappedArgument.convert() } else { generateResolvedAccessExpression(desugaredSource, initialValueVar) } @@ -469,10 +470,10 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte resultInitializer ) - val assignment = argument.generateAssignment( + val assignment = unwrappedArgument.generateAssignment( desugaredSource, null, - if (prefix && argument.elementType != REFERENCE_EXPRESSION) + if (prefix && unwrappedArgument.elementType != REFERENCE_EXPRESSION) generateResolvedAccessExpression(source, resultVar) else resultInitializer, @@ -488,13 +489,13 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte } if (prefix) { - if (argument.elementType != REFERENCE_EXPRESSION) { + if (unwrappedArgument.elementType != REFERENCE_EXPRESSION) { statements += resultVar appendAssignment() statements += generateResolvedAccessExpression(desugaredSource, resultVar) } else { appendAssignment() - statements += generateAccessExpression(desugaredSource, argument.getReferencedNameAsName()) + statements += generateAccessExpression(desugaredSource, unwrappedArgument.getReferencedNameAsName()) } } else { statements += initialValueVar diff --git a/compiler/testData/codegen/box/intrinsics/incWithLabel.kt b/compiler/testData/codegen/box/intrinsics/incWithLabel.kt index bd36b600966..fff72ffb135 100644 --- a/compiler/testData/codegen/box/intrinsics/incWithLabel.kt +++ b/compiler/testData/codegen/box/intrinsics/incWithLabel.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR fun box(): String { var x = 1 (foo@ x)++ diff --git a/compiler/testData/diagnostics/tests/LValueAssignment.fir.kt b/compiler/testData/diagnostics/tests/LValueAssignment.fir.kt index b1fcd991b3a..ef18c4e661c 100644 --- a/compiler/testData/diagnostics/tests/LValueAssignment.fir.kt +++ b/compiler/testData/diagnostics/tests/LValueAssignment.fir.kt @@ -78,10 +78,10 @@ class Test() { (f@ getInt()) += 343 1++ - (r@ 1)++ + (r@ 1)++ getInt()++ - (m@ getInt())++ + (m@ getInt())++ this++ @@ -106,7 +106,7 @@ class Test() { b += 34 a++ - (l@ a)++ + (l@ a)++ (a)++ }