From 9b71175902db45836e48476e83cea93e3667171e Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Fri, 25 Jun 2021 17:29:26 +0300 Subject: [PATCH] [FIR] Get rid of unnecessary creation of error expression for LightTree, other minor simplifications --- .../fir/lightTree/converter/ConverterUtil.kt | 9 +- .../converter/DeclarationsConverter.kt | 61 +++++---- .../converter/ExpressionsConverter.kt | 116 ++++++++++++------ .../kotlin/fir/builder/ConversionUtils.kt | 9 +- 4 files changed, 122 insertions(+), 73 deletions(-) diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt index 271c1dc6f78..89fb54357f9 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt @@ -83,16 +83,17 @@ inline fun isClassLocal(classNode: LighterASTNode, getParent: LighterASTNode.() while (currentNode != null) { val tokenType = currentNode.tokenType val parent = currentNode.getParent() + val parentTokenType = parent?.tokenType if (tokenType == PROPERTY || tokenType == FUN) { val grandParent = parent?.getParent() when { - parent?.tokenType == KT_FILE -> return true - parent?.tokenType == CLASS_BODY && !(grandParent?.tokenType == OBJECT_DECLARATION && grandParent?.getParent()?.tokenType == OBJECT_LITERAL) -> return true - parent?.tokenType == BLOCK && grandParent?.tokenType == SCRIPT -> return true + parentTokenType == KT_FILE -> return true + parentTokenType == CLASS_BODY && !(grandParent?.tokenType == OBJECT_DECLARATION && grandParent?.getParent()?.tokenType == OBJECT_LITERAL) -> return true + parentTokenType == BLOCK && grandParent?.tokenType == SCRIPT -> return true } } // NB: enum entry nested classes are considered local by FIR design (see discussion in KT-45115) - if (parent?.tokenType == ENUM_ENTRY) { + if (parentTokenType == ENUM_ENTRY) { return true } if (tokenType == BLOCK) { diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt index 64347654384..a882f0d22b1 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt @@ -226,30 +226,30 @@ class DeclarationsConverter( * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeModifierList */ private fun convertTypeModifierList(modifiers: LighterASTNode): TypeModifier { - val typeModifierList = TypeModifier() + val typeModifier = TypeModifier() modifiers.forEachChildren { when (it.tokenType) { - ANNOTATION -> typeModifierList.annotations += convertAnnotation(it) - ANNOTATION_ENTRY -> typeModifierList.annotations += convertAnnotationEntry(it) - is KtModifierKeywordToken -> typeModifierList.addModifier(it) + ANNOTATION -> typeModifier.annotations += convertAnnotation(it) + ANNOTATION_ENTRY -> typeModifier.annotations += convertAnnotationEntry(it) + is KtModifierKeywordToken -> typeModifier.addModifier(it) } } - return typeModifierList + return typeModifier } /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeArgumentModifierList */ private fun convertTypeArgumentModifierList(modifiers: LighterASTNode): TypeProjectionModifier { - val typeArgumentModifierList = TypeProjectionModifier() + val typeArgumentModifier = TypeProjectionModifier() modifiers.forEachChildren { when (it.tokenType) { - ANNOTATION -> typeArgumentModifierList.annotations += convertAnnotation(it) - ANNOTATION_ENTRY -> typeArgumentModifierList.annotations += convertAnnotationEntry(it) - is KtModifierKeywordToken -> typeArgumentModifierList.addModifier(it) + ANNOTATION -> typeArgumentModifier.annotations += convertAnnotation(it) + ANNOTATION_ENTRY -> typeArgumentModifier.annotations += convertAnnotationEntry(it) + is KtModifierKeywordToken -> typeArgumentModifier.addModifier(it) } } - return typeArgumentModifierList + return typeArgumentModifier } /** @@ -1143,8 +1143,7 @@ class DeclarationsConverter( var isVar = false val entries = mutableListOf() val source = destructingDeclaration.toFirSourceElement() - var firExpression: FirExpression = - buildErrorExpression(null, ConeSimpleDiagnostic("Initializer required for destructuring declaration", DiagnosticKind.Syntax)) + var firExpression: FirExpression? = null destructingDeclaration.forEachChildren { when (it.tokenType) { VAR_KEYWORD -> isVar = true @@ -1154,7 +1153,15 @@ class DeclarationsConverter( } } - return DestructuringDeclaration(isVar, entries, firExpression, source) + return DestructuringDeclaration( + isVar, + entries, + firExpression ?: buildErrorExpression( + null, + ConeSimpleDiagnostic("Initializer required for destructuring declaration", DiagnosticKind.Syntax) + ), + source + ) } /** @@ -1583,9 +1590,7 @@ class DeclarationsConverter( */ private fun convertExplicitDelegation(explicitDelegation: LighterASTNode, delegateFields: MutableList): FirTypeRef { lateinit var firTypeRef: FirTypeRef - var firExpression: FirExpression? = buildErrorExpression( - explicitDelegation.toFirSourceElement(), ConeSimpleDiagnostic("Should have delegate", DiagnosticKind.Syntax) - ) + var firExpression: FirExpression? = null explicitDelegation.forEachChildren { when (it.tokenType) { TYPE_REFERENCE -> firTypeRef = convertType(it) @@ -1593,10 +1598,14 @@ class DeclarationsConverter( } } + val calculatedFirExpression = firExpression ?: buildErrorExpression( + explicitDelegation.toFirSourceElement(), ConeSimpleDiagnostic("Should have delegate", DiagnosticKind.Syntax) + ) + val delegateName = Name.special("<\$\$delegate_${delegateFields.size}>") delegateFields.add( buildField { - source = firExpression!!.source?.fakeElement(FirFakeSourceElementKind.ClassDelegationField) + source = calculatedFirExpression.source?.fakeElement(FirFakeSourceElementKind.ClassDelegationField) moduleData = baseModuleData origin = FirDeclarationOrigin.Synthetic name = delegateName @@ -1604,7 +1613,7 @@ class DeclarationsConverter( symbol = FirFieldSymbol(CallableId(name)) isVar = false status = FirDeclarationStatusImpl(Visibilities.Local, Modality.FINAL) - initializer = firExpression + initializer = calculatedFirExpression } ) return firTypeRef @@ -1719,10 +1728,7 @@ class DeclarationsConverter( // TODO: Report MODIFIER_LIST_NOT_ALLOWED error when there are multiple modifier lists. How do we report on each of them? val allTypeModifiers = mutableListOf() - var firType: FirTypeRef = buildErrorTypeRef { - source = typeRefSource - diagnostic = ConeSimpleDiagnostic("Incomplete code", DiagnosticKind.Syntax) - } + var firType: FirTypeRef? = null type.forEachChildren { when (it.tokenType) { TYPE_REFERENCE -> firType = convertType(it) @@ -1743,10 +1749,15 @@ class DeclarationsConverter( } } - for (modifierList in allTypeModifiers) { - (firType.annotations as MutableList) += modifierList.annotations + val calculatedFirType = firType ?: buildErrorTypeRef { + source = typeRefSource + diagnostic = ConeSimpleDiagnostic("Incomplete code", DiagnosticKind.Syntax) } - return firType + + for (modifierList in allTypeModifiers) { + (calculatedFirType.annotations as MutableList) += modifierList.annotations + } + return calculatedFirType } private fun Collection.hasSuspend() = any { it.hasSuspend() } diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt index 4cd5826035b..9ce92d585b7 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt @@ -278,7 +278,12 @@ class ExpressionsConverter( } else { val firOperation = operationToken.toFirOperation() if (firOperation in FirOperation.ASSIGNMENTS) { - return leftArgNode.generateAssignment(binaryExpression.toFirSourceElement(), rightArg, rightArgAsFir, firOperation) { getAsFirExpression(this) } + return leftArgNode.generateAssignment( + binaryExpression.toFirSourceElement(), + rightArg, + rightArgAsFir, + firOperation + ) { getAsFirExpression(this) } } else { buildEqualityOperatorCall { source = binaryExpression.toFirSourceElement() @@ -299,7 +304,7 @@ class ExpressionsConverter( toFirOperation: String.() -> FirOperation ): FirTypeOperatorCall { lateinit var operationTokenName: String - var leftArgAsFir: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic("No left operand", DiagnosticKind.Syntax)) + var leftArgAsFir: FirExpression? = null lateinit var firType: FirTypeRef binaryExpression.forEachChildren { when (it.tokenType) { @@ -313,7 +318,9 @@ class ExpressionsConverter( source = binaryExpression.toFirSourceElement() operation = operationTokenName.toFirOperation() conversionTypeRef = firType - argumentList = buildUnaryArgumentList(leftArgAsFir) + argumentList = buildUnaryArgumentList( + leftArgAsFir ?: buildErrorExpression(null, ConeSimpleDiagnostic("No left operand", DiagnosticKind.Syntax)) + ) } } @@ -431,14 +438,17 @@ class ExpressionsConverter( * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitClassLiteralExpression */ private fun convertClassLiteralExpression(classLiteralExpression: LighterASTNode): FirExpression { - var firReceiverExpression: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic("No receiver in class literal", DiagnosticKind.Syntax)) + var firReceiverExpression: FirExpression? = null classLiteralExpression.forEachChildren { if (it.isExpression()) firReceiverExpression = getAsFirExpression(it, "No receiver in class literal") } return buildGetClassCall { source = classLiteralExpression.toFirSourceElement() - argumentList = buildUnaryArgumentList(firReceiverExpression) + argumentList = buildUnaryArgumentList( + firReceiverExpression + ?: buildErrorExpression(null, ConeSimpleDiagnostic("No receiver in class literal", DiagnosticKind.Syntax)) + ) } } @@ -643,11 +653,11 @@ class ExpressionsConverter( } private fun LighterASTNode?.convertShortOrLongStringTemplate(errorReason: String): FirExpression { - var firExpression: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic(errorReason, DiagnosticKind.Syntax)) + var firExpression: FirExpression? = null this?.forEachChildren(LONG_TEMPLATE_ENTRY_START, LONG_TEMPLATE_ENTRY_END) { firExpression = getAsFirExpression(it, errorReason) } - return firExpression + return firExpression ?: buildErrorExpression(null, ConeSimpleDiagnostic(errorReason, DiagnosticKind.Syntax)) } /** @@ -756,13 +766,22 @@ class ExpressionsConverter( return WhenEntry(conditions, firBlock, whenEntry, isElse) } - private fun convertWhenConditionExpression(whenCondition: LighterASTNode, whenRefWithSubject: FirExpressionRef?): FirExpression { - var firExpression: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic("No expression in condition with expression", DiagnosticKind.Syntax)) + private fun convertWhenConditionExpression( + whenCondition: LighterASTNode, + whenRefWithSubject: FirExpressionRef? + ): FirExpression { + var firExpression: FirExpression? = null whenCondition.forEachChildren { when (it.tokenType) { else -> if (it.isExpression()) firExpression = getAsFirExpression(it, "No expression in condition with expression") } } + + val calculatedFirExpression = firExpression ?: buildErrorExpression( + null, + ConeSimpleDiagnostic("No expression in condition with expression", DiagnosticKind.Syntax) + ) + return if (whenRefWithSubject != null) { buildEqualityOperatorCall { source = whenCondition.toFirSourceElement(FirFakeSourceElementKind.WhenCondition) @@ -770,18 +789,20 @@ class ExpressionsConverter( argumentList = buildBinaryArgumentList( buildWhenSubjectExpression { whenRef = whenRefWithSubject - }, firExpression + }, calculatedFirExpression ) } - } else { - firExpression + calculatedFirExpression } } - private fun convertWhenConditionInRange(whenCondition: LighterASTNode, whenRefWithSubject: FirExpressionRef?): FirExpression { + private fun convertWhenConditionInRange( + whenCondition: LighterASTNode, + whenRefWithSubject: FirExpressionRef? + ): FirExpression { var isNegate = false - var firExpression: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic("No range in condition with range", DiagnosticKind.Syntax)) + var firExpression: FirExpression? = null var conditionSource: FirLightSourceElement? = null whenCondition.forEachChildren { when { @@ -808,7 +829,12 @@ class ExpressionsConverter( } } - return firExpression.generateContainsOperation( + val calculatedFirExpression = firExpression ?: buildErrorExpression( + null, + ConeSimpleDiagnostic("No range in condition with range", DiagnosticKind.Syntax) + ) + + return calculatedFirExpression.generateContainsOperation( subjectExpression, inverted = isNegate, baseSource = whenCondition.toFirSourceElement(), @@ -816,7 +842,10 @@ class ExpressionsConverter( ) } - private fun convertWhenConditionIsPattern(whenCondition: LighterASTNode, whenRefWithSubject: FirExpressionRef?): FirExpression { + private fun convertWhenConditionIsPattern( + whenCondition: LighterASTNode, + whenRefWithSubject: FirExpressionRef? + ): FirExpression { lateinit var firOperation: FirOperation lateinit var firType: FirTypeRef whenCondition.forEachChildren { @@ -851,7 +880,7 @@ class ExpressionsConverter( * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitArrayAccessExpression */ private fun convertArrayAccessExpression(arrayAccess: LighterASTNode): FirFunctionCall { - var firExpression: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic("No array expression", DiagnosticKind.Syntax)) + var firExpression: FirExpression? = null val indices: MutableList = mutableListOf() arrayAccess.forEachChildren { when (it.tokenType) { @@ -867,7 +896,8 @@ class ExpressionsConverter( source = arrayAccess.toFirSourceElement().fakeElement(FirFakeSourceElementKind.ArrayAccessNameReference) name = if (isGet) OperatorNameConventions.GET else OperatorNameConventions.SET } - explicitReceiver = firExpression + explicitReceiver = + firExpression ?: buildErrorExpression(null, ConeSimpleDiagnostic("No array expression", DiagnosticKind.Syntax)) argumentList = buildArgumentList { arguments += indices getArgument?.let { arguments += it } @@ -925,8 +955,7 @@ class ExpressionsConverter( */ private fun convertDoWhile(doWhileLoop: LighterASTNode): FirElement { var block: LighterASTNode? = null - var firCondition: FirExpression = - buildErrorExpression(null, ConeSimpleDiagnostic("No condition in do-while loop", DiagnosticKind.Syntax)) + var firCondition: FirExpression? = null val target: FirLoopTarget return FirDoWhileLoopBuilder().apply { @@ -939,7 +968,8 @@ class ExpressionsConverter( CONDITION -> firCondition = getAsFirExpression(it, "No condition in do-while loop") } } - condition = firCondition + condition = + firCondition ?: buildErrorExpression(null, ConeSimpleDiagnostic("No condition in do-while loop", DiagnosticKind.Syntax)) }.configure(target) { convertLoopBody(block) } } @@ -949,7 +979,7 @@ class ExpressionsConverter( */ private fun convertWhile(whileLoop: LighterASTNode): FirElement { var block: LighterASTNode? = null - var firCondition: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic("No condition in while loop", DiagnosticKind.Syntax)) + var firCondition: FirExpression? = null whileLoop.forEachChildren { when (it.tokenType) { BODY -> block = it @@ -960,7 +990,8 @@ class ExpressionsConverter( val target: FirLoopTarget return FirWhileLoopBuilder().apply { source = whileLoop.toFirSourceElement() - condition = firCondition + condition = + firCondition ?: buildErrorExpression(null, ConeSimpleDiagnostic("No condition in while loop", DiagnosticKind.Syntax)) // break/continue in the while loop condition will refer to an outer loop if any. // So, prepare the loop target after building the condition. target = prepareTarget() @@ -973,7 +1004,7 @@ class ExpressionsConverter( */ private fun convertFor(forLoop: LighterASTNode): FirElement { var parameter: ValueParameter? = null - var rangeExpression: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic("No range in for loop", DiagnosticKind.Syntax)) + var rangeExpression: FirExpression? = null var blockNode: LighterASTNode? = null forLoop.forEachChildren { when (it.tokenType) { @@ -983,6 +1014,8 @@ class ExpressionsConverter( } } + val calculatedRangeExpression = + rangeExpression ?: buildErrorExpression(null, ConeSimpleDiagnostic("No range in for loop", DiagnosticKind.Syntax)) val fakeSource = forLoop.toFirSourceElement(FirFakeSourceElementKind.DesugaredForLoop) val target: FirLoopTarget // NB: FirForLoopChecker relies on this block existence and structure @@ -990,7 +1023,7 @@ class ExpressionsConverter( source = fakeSource val iteratorVal = generateTemporaryVariable( baseModuleData, - rangeExpression.source?.fakeElement(FirFakeSourceElementKind.DesugaredForLoop), + calculatedRangeExpression.source?.fakeElement(FirFakeSourceElementKind.DesugaredForLoop), ITERATOR_NAME, buildFunctionCall { source = fakeSource @@ -998,7 +1031,7 @@ class ExpressionsConverter( source = fakeSource name = OperatorNameConventions.ITERATOR } - explicitReceiver = rangeExpression + explicitReceiver = calculatedRangeExpression } ) statements += iteratorVal @@ -1047,7 +1080,6 @@ class ExpressionsConverter( } else { statements.add(0, firLoopParameter) } - } } } @@ -1138,7 +1170,7 @@ class ExpressionsConverter( * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitIfExpression */ private fun convertIfExpression(ifExpression: LighterASTNode): FirExpression { - var firCondition: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic("If statement should have condition", DiagnosticKind.Syntax)) + var firCondition: FirExpression? = null var thenBlock: LighterASTNode? = null var elseBlock: LighterASTNode? = null ifExpression.forEachChildren { @@ -1154,7 +1186,10 @@ class ExpressionsConverter( val trueBranch = convertLoopBody(thenBlock) branches += buildWhenBranch { source = thenBlock?.toFirSourceElement() - condition = firCondition + condition = firCondition ?: buildErrorExpression( + null, + ConeSimpleDiagnostic("If statement should have condition", DiagnosticKind.Syntax) + ) result = trueBranch } if (elseBlock != null) { @@ -1212,9 +1247,7 @@ class ExpressionsConverter( */ private fun convertReturn(returnExpression: LighterASTNode): FirExpression { var labelName: String? = null - var firExpression: FirExpression = buildUnitExpression { - source = returnExpression.toFirSourceElement(FirFakeSourceElementKind.ImplicitUnit) - } + var firExpression: FirExpression? = null returnExpression.forEachChildren { when (it.tokenType) { LABEL_QUALIFIER -> labelName = it.getAsStringWithoutBacktick().replace("@", "") @@ -1222,7 +1255,10 @@ class ExpressionsConverter( } } - return firExpression.toReturn( + val calculatedFirExpression = firExpression ?: buildUnitExpression { + source = returnExpression.toFirSourceElement(FirFakeSourceElementKind.ImplicitUnit) + } + return calculatedFirExpression.toReturn( baseSource = returnExpression.toFirSourceElement(), labelName = labelName, fromKtReturnExpression = true @@ -1234,14 +1270,14 @@ class ExpressionsConverter( * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitThrowExpression */ private fun convertThrow(throwExpression: LighterASTNode): FirExpression { - var firExpression: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic("Nothing to throw", DiagnosticKind.Syntax)) + var firExpression: FirExpression? = null throwExpression.forEachChildren { if (it.isExpression()) firExpression = getAsFirExpression(it, "Nothing to throw") } return buildThrowExpression { source = throwExpression.toFirSourceElement() - exception = firExpression + exception = firExpression ?: buildErrorExpression(null, ConeSimpleDiagnostic("Nothing to throw", DiagnosticKind.Syntax)) } } @@ -1303,7 +1339,7 @@ class ExpressionsConverter( private fun convertValueArgument(valueArgument: LighterASTNode): FirExpression { var identifier: String? = null var isSpread = false - var firExpression: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic("Argument is absent", DiagnosticKind.Syntax)) + var firExpression: FirExpression? = null valueArgument.forEachChildren { when (it.tokenType) { VALUE_ARGUMENT_NAME -> identifier = it.asText @@ -1313,18 +1349,20 @@ class ExpressionsConverter( else -> if (it.isExpression()) firExpression = getAsFirExpression(it, "Argument is absent") } } + val calculatedFirExpression = + firExpression ?: buildErrorExpression(null, ConeSimpleDiagnostic("Argument is absent", DiagnosticKind.Syntax)) return when { identifier != null -> buildNamedArgumentExpression { source = valueArgument.toFirSourceElement() - expression = firExpression + expression = calculatedFirExpression this.isSpread = isSpread name = identifier.nameAsSafeName() } isSpread -> buildSpreadArgumentExpression { source = valueArgument.toFirSourceElement() - expression = firExpression + expression = calculatedFirExpression } - else -> firExpression + else -> calculatedFirExpression } } } diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt index 2f84efb7fea..38040d496b9 100644 --- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt @@ -81,11 +81,10 @@ fun escapedStringToCharacter(text: String): CharacterWithDiagnostic { 5 -> { // unicode escape if (escape[0] == 'u') { - try { - val intValue = Integer.valueOf(escape.substring(1), 16) - return CharacterWithDiagnostic(intValue.toInt().toChar()) - } catch (e: NumberFormatException) { - // Will be reported below + val intValue = escape.substring(1).toIntOrNull(16) + // If error occurs it will be reported below + if (intValue != null) { + return CharacterWithDiagnostic(intValue.toChar()) } } }