[FIR] Get rid of unnecessary creation of error expression for LightTree, other minor simplifications

This commit is contained in:
Ivan Kochurkin
2021-06-25 17:29:26 +03:00
parent 9f7a8c3948
commit 9b71175902
4 changed files with 122 additions and 73 deletions
@@ -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) {
@@ -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<FirVariable?>()
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<FirField>): 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<TypeModifier>()
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<FirAnnotationCall>) += modifierList.annotations
val calculatedFirType = firType ?: buildErrorTypeRef {
source = typeRefSource
diagnostic = ConeSimpleDiagnostic("Incomplete code", DiagnosticKind.Syntax)
}
return firType
for (modifierList in allTypeModifiers) {
(calculatedFirType.annotations as MutableList<FirAnnotationCall>) += modifierList.annotations
}
return calculatedFirType
}
private fun Collection<TypeModifier>.hasSuspend() = any { it.hasSuspend() }
@@ -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<FirWhenExpression>?): FirExpression {
var firExpression: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic("No expression in condition with expression", DiagnosticKind.Syntax))
private fun convertWhenConditionExpression(
whenCondition: LighterASTNode,
whenRefWithSubject: FirExpressionRef<FirWhenExpression>?
): 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<FirWhenExpression>?): FirExpression {
private fun convertWhenConditionInRange(
whenCondition: LighterASTNode,
whenRefWithSubject: FirExpressionRef<FirWhenExpression>?
): 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<FirWhenExpression>?): FirExpression {
private fun convertWhenConditionIsPattern(
whenCondition: LighterASTNode,
whenRefWithSubject: FirExpressionRef<FirWhenExpression>?
): 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<FirExpression> = 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
}
}
}
@@ -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())
}
}
}