From c253ff7953ca588219941271a31c272baa27942e Mon Sep 17 00:00:00 2001 From: Ivan Cilcic Date: Thu, 25 Jul 2019 16:28:29 +0300 Subject: [PATCH] Write syntactically incorrect constructions processing (light tree to FIR) --- .../fir/lightTree/converter/BaseConverter.kt | 4 +- .../fir/lightTree/converter/ConverterUtil.kt | 23 +- .../converter/DeclarationsConverter.kt | 173 +++++++++------ .../converter/ExpressionsConverter.kt | 209 +++++++++--------- .../converter/utils/ExpressionUtil.kt | 25 ++- .../kotlin/fir/lightTree/fir/ClassWrapper.kt | 6 +- .../lightTree/fir/DestructuringDeclaration.kt | 14 +- .../fir/lightTree/fir/ValueParameter.kt | 8 +- .../kotlin/fir/lightTree/fir/WhenEntry.kt | 6 +- .../fir/lightTree/fir/modifier/Modifier.kt | 67 ++++-- .../lightTree/fir/modifier/ModifierSets.kt | 2 +- .../fir/modifier/ModifiersEnumSet.kt | 82 ++----- .../lightTree/fir/modifier/TypeModifier.kt | 4 + .../fir/modifier/TypeParameterModifier.kt | 13 +- .../fir/modifier/TypeProjectionModifier.kt | 10 +- .../fir/lightTree/compare/TreesCompareTest.kt | 51 +++-- 16 files changed, 373 insertions(+), 324 deletions(-) diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt index 38642758b55..8d3ababed30 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt @@ -46,12 +46,12 @@ open class BaseConverter( return kidsRef.get() } - fun LighterASTNode.getExpressionInParentheses(): LighterASTNode { + fun LighterASTNode.getExpressionInParentheses(): LighterASTNode? { this.forEachChildren { if (it.isExpression()) return it } - throw Exception() + return null } protected inline fun LighterASTNode.forEachChildren(vararg skipTokens: KtToken, f: (LighterASTNode) -> Unit) { diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt index 432479be06b..99521bcff10 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt @@ -9,6 +9,7 @@ import com.intellij.lang.LighterASTNode import com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.KtNodeType import org.jetbrains.kotlin.KtNodeTypes +import org.jetbrains.kotlin.KtNodeTypes.* import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.FirFunctionTarget @@ -43,10 +44,10 @@ import org.jetbrains.kotlin.types.Variance object ConverterUtil { private val expressionSet = listOf( - KtNodeTypes.REFERENCE_EXPRESSION, - KtNodeTypes.DOT_QUALIFIED_EXPRESSION, - KtNodeTypes.LAMBDA_EXPRESSION, - KtNodeTypes.FUN + REFERENCE_EXPRESSION, + DOT_QUALIFIED_EXPRESSION, + LAMBDA_EXPRESSION, + FUN ) fun String?.nameAsSafeName(defaultName: String = ""): Name { @@ -157,10 +158,20 @@ object ConverterUtil { inline fun isClassLocal(classNode: LighterASTNode, getParent: LighterASTNode.() -> LighterASTNode?): Boolean { var currentNode: LighterASTNode? = classNode while (currentNode != null) { - if (currentNode.tokenType == KtNodeTypes.BLOCK) { + val tokenType = currentNode.tokenType + val parent = currentNode.getParent() + 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 + } + } + if (tokenType == BLOCK) { return true } - currentNode = currentNode.getParent() + currentNode = parent } return false } diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt index 1b792b00ae2..3c106af1377 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.lightTree.converter import com.intellij.lang.LighterASTNode +import com.intellij.psi.TokenType import com.intellij.psi.tree.IFileElementType import com.intellij.util.diff.FlyweightCapableTreeStructure import org.jetbrains.kotlin.KtNodeTypes.* @@ -49,6 +50,7 @@ import org.jetbrains.kotlin.fir.types.impl.* import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames class DeclarationsConverter( @@ -141,15 +143,14 @@ class DeclarationsConverter( return packageName } - private fun convertImportAlias(importAlias: LighterASTNode): String { + private fun convertImportAlias(importAlias: LighterASTNode): String? { importAlias.forEachChildren { when (it.tokenType) { IDENTIFIER -> return it.getAsString() } } - //TODO specify error - throw Exception() + return null } /** @@ -178,7 +179,7 @@ class DeclarationsConverter( null, importedFqName, isAllUnder, - aliasName.nameAsSafeName() + aliasName?.let { Name.identifier(it) } ) } @@ -332,7 +333,7 @@ class DeclarationsConverter( */ private fun convertClass(classNode: LighterASTNode): FirDeclaration { var modifiers = Modifier(session) - lateinit var classKind: ClassKind + var classKind: ClassKind = ClassKind.CLASS //TODO var identifier: String? = null val firTypeParameters = mutableListOf() var primaryConstructor: LighterASTNode? = null @@ -360,17 +361,20 @@ class DeclarationsConverter( } } - classKind = when { - modifiers.isEnum() -> ClassKind.ENUM_CLASS - modifiers.isAnnotation() -> ClassKind.ANNOTATION_CLASS - else -> classKind - } val defaultDelegatedSuperTypeRef = when { - modifiers.isEnum() -> implicitEnumType - modifiers.isAnnotation() -> implicitAnnotationType + modifiers.isEnum() && (classKind == ClassKind.CLASS || classKind == ClassKind.INTERFACE) -> implicitEnumType + modifiers.isAnnotation() && (classKind == ClassKind.CLASS || classKind == ClassKind.INTERFACE) -> implicitAnnotationType else -> implicitAnyType } + if (classKind == ClassKind.CLASS) { + classKind = when { + modifiers.isEnum() -> ClassKind.ENUM_CLASS + modifiers.isAnnotation() -> ClassKind.ANNOTATION_CLASS + else -> classKind + } + } + val className = identifier.nameAsSafeName(if (modifiers.isCompanion()) "Companion" else "") superTypeRefs.ifEmpty { superTypeRefs += defaultDelegatedSuperTypeRef } val isLocal = isClassLocal(classNode) { getParent() } @@ -387,8 +391,8 @@ class DeclarationsConverter( modifiers.hasActual(), classKind, isInner = modifiers.isInner(), - isCompanion = modifiers.isCompanion(), - isData = modifiers.isDataClass(), + isCompanion = modifiers.isCompanion() && classKind == ClassKind.OBJECT, + isData = modifiers.isDataClass() && classKind != ClassKind.OBJECT, isInline = modifiers.hasInline() ) firClass.annotations += modifiers.annotations @@ -406,13 +410,16 @@ class DeclarationsConverter( val firPrimaryConstructor = convertPrimaryConstructor(primaryConstructor, classWrapper) firPrimaryConstructor?.let { firClass.declarations += it } - //parse properties - val properties = primaryConstructor - .getChildNodesByType(VALUE_PARAMETER_LIST) - .flatMap { convertValueParameters(it) } - .filter { it.hasValOrVar() } - .map { it.toFirProperty() } - firClass.addDeclarations(properties) + val properties = mutableListOf() + if (primaryConstructor != null && firPrimaryConstructor != null) { + //parse properties + properties += primaryConstructor + .getChildNodesByType(VALUE_PARAMETER_LIST) + .flatMap { convertValueParameters(it) } + .filter { it.hasValOrVar() } + .map { it.toFirProperty() } + firClass.addDeclarations(properties) + } //parse declarations classBody?.let { @@ -465,7 +472,7 @@ class DeclarationsConverter( val classWrapper = ClassWrapper( this@DeclarationsConverter.session, SpecialNames.NO_NAME_PROVIDED, modifiers, ClassKind.OBJECT, hasPrimaryConstructor = false, - hasSecondaryConstructor = false, + hasSecondaryConstructor = classBody.getChildNodesByType(SECONDARY_CONSTRUCTOR).isNotEmpty(), delegatedSelfTypeRef = delegatedType, delegatedSuperTypeRef = delegatedType, superTypeCallEntry = superTypeCallEntry @@ -490,6 +497,7 @@ class DeclarationsConverter( var hasInitializerList = false val enumSuperTypeCallEntry = mutableListOf() val firDeclarations = mutableListOf() + var classBodyNode: LighterASTNode? = null enumEntry.forEachChildren { when (it.tokenType) { MODIFIER_LIST -> modifiers = convertModifierList(it) @@ -498,7 +506,7 @@ class DeclarationsConverter( hasInitializerList = true enumSuperTypeCallEntry += convertInitializerList(it) } - CLASS_BODY -> firDeclarations += convertClassBody(it, classWrapper) + CLASS_BODY -> classBodyNode = it } } @@ -512,16 +520,23 @@ class DeclarationsConverter( ) firEnumEntry.annotations += modifiers.annotations + val defaultDelegatedSuperTypeRef = when { + modifiers.isEnum() -> implicitEnumType + modifiers.isAnnotation() -> implicitAnnotationType + else -> implicitAnyType + } + val enumClassWrapper = ClassWrapper( session, enumEntryName, modifiers, ClassKind.ENUM_ENTRY, - hasPrimaryConstructor = true, hasSecondaryConstructor = false, + hasPrimaryConstructor = true, + hasSecondaryConstructor = classBodyNode.getChildNodesByType(SECONDARY_CONSTRUCTOR).isNotEmpty(), delegatedSelfTypeRef = toDelegatedSelfType(firEnumEntry), - delegatedSuperTypeRef = if (hasInitializerList) classWrapper.getFirUserTypeFromClassName() else implicitAnyType, + delegatedSuperTypeRef = if (hasInitializerList) classWrapper.getFirUserTypeFromClassName() else defaultDelegatedSuperTypeRef, superTypeCallEntry = enumSuperTypeCallEntry ) firEnumEntry.superTypeRefs += enumClassWrapper.delegatedSuperTypeRef - val firEnumPrimaryConstructor = convertPrimaryConstructor(null, enumClassWrapper)!! - firEnumEntry.addDeclaration(firEnumPrimaryConstructor) + convertPrimaryConstructor(null, enumClassWrapper)?.let { firEnumEntry.addDeclaration(it) } + classBodyNode?.also { firDeclarations += convertClassBody(it, /*classWrapper*/enumClassWrapper) } firDeclarations.forEach { firEnumEntry.addDeclaration(it) } return@withChildClassName firEnumEntry @@ -641,6 +656,10 @@ class DeclarationsConverter( } } + val delegatedSelfTypeRef = + if (classWrapper.isObjectLiteral()) FirErrorTypeRefImpl(session, null, "Constructor in object") + else classWrapper.delegatedSelfTypeRef + val firConstructor = FirConstructorImpl( session, null, @@ -648,13 +667,13 @@ class DeclarationsConverter( modifiers.getVisibility(), modifiers.hasExpect(), modifiers.hasActual(), - classWrapper.delegatedSelfTypeRef, + delegatedSelfTypeRef, constructorDelegationCall ) FunctionUtil.firFunctions += firConstructor firConstructor.annotations += modifiers.annotations - firConstructor.typeParameters += ConverterUtil.typeParametersFromSelfType(classWrapper.delegatedSelfTypeRef) + firConstructor.typeParameters += ConverterUtil.typeParametersFromSelfType(delegatedSelfTypeRef) firConstructor.valueParameters += firValueParameters.map { it.firValueParameter } firConstructor.body = convertFunctionBody(block, null) FunctionUtil.firFunctions.removeLast() @@ -680,10 +699,15 @@ class DeclarationsConverter( val isImplicit = constructorDelegationCall.getAsString().isEmpty() val isThis = (isImplicit && classWrapper.hasPrimaryConstructor) || thisKeywordPresent - val delegatedType = when { - isThis -> classWrapper.delegatedSelfTypeRef - else -> classWrapper.delegatedSuperTypeRef - } + val delegatedType = + if (classWrapper.isObjectLiteral() || classWrapper.isInterface()) when { + isThis -> FirErrorTypeRefImpl(session, null, "Constructor in object") + else -> FirErrorTypeRefImpl(session, null, "No super type") + } + else when { + isThis -> classWrapper.delegatedSelfTypeRef + else -> classWrapper.delegatedSuperTypeRef + } return FirDelegatedConstructorCallImpl( session, @@ -698,7 +722,7 @@ class DeclarationsConverter( */ private fun convertTypeAlias(typeAlias: LighterASTNode): FirDeclaration { var modifiers = Modifier(session) - lateinit var identifier: String + var identifier: String? = null lateinit var firType: FirTypeRef val firTypeParameters = mutableListOf() typeAlias.forEachChildren { @@ -733,10 +757,10 @@ class DeclarationsConverter( */ fun convertPropertyDeclaration(property: LighterASTNode): FirDeclaration { var modifiers = Modifier(session) - lateinit var identifier: String + var identifier: String? = null val firTypeParameters = mutableListOf() var isReturnType = false - var firDelegateExpression: FirExpression? = null + var delegateExpression: LighterASTNode? = null var isVar = false var receiverType: FirTypeRef? = null var returnType: FirTypeRef = implicitType @@ -752,13 +776,13 @@ class DeclarationsConverter( COLON -> isReturnType = true TYPE_REFERENCE -> if (isReturnType) returnType = convertType(it) else receiverType = convertType(it) TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it) - PROPERTY_DELEGATE -> firDelegateExpression = expressionConverter.getAsFirExpression(it) + PROPERTY_DELEGATE -> delegateExpression = it VAR_KEYWORD -> isVar = true PROPERTY_ACCESSOR -> { val propertyAccessor = convertGetterOrSetter(it, returnType) if (propertyAccessor.isGetter) getter = propertyAccessor else setter = propertyAccessor } - else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it) + else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it, "Should have initializer") } } @@ -774,7 +798,7 @@ class DeclarationsConverter( returnType, isVar, firExpression, - delegate = firDelegateExpression + delegate = delegateExpression?.let { expressionConverter.getAsFirExpression(it, "Incorrect delegate expression") } ).apply { annotations += modifiers.annotations } @@ -797,7 +821,7 @@ class DeclarationsConverter( firExpression, getter ?: FirDefaultPropertyGetter(session, null, returnType, modifiers.getVisibility()), if (isVar) setter ?: FirDefaultPropertySetter(session, null, returnType, modifiers.getVisibility()) else null, - firDelegateExpression + delegateExpression?.let { expressionConverter.getAsFirExpression(it, "Should have delegate") } ).apply { this.typeParameters += firTypeParameters this.joinTypeParameters(typeConstraints) @@ -812,12 +836,13 @@ class DeclarationsConverter( private fun convertDestructingDeclaration(destructingDeclaration: LighterASTNode): DestructuringDeclaration { var isVar = false val entries = mutableListOf>() - var firExpression: FirExpression? = null + var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "Destructuring declaration without initializer") destructingDeclaration.forEachChildren { when (it.tokenType) { VAR_KEYWORD -> isVar = true DESTRUCTURING_DECLARATION_ENTRY -> entries += convertDestructingDeclarationEntry(it) - else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it) + else -> if (it.isExpression()) firExpression = + expressionConverter.getAsFirExpression(it, "Destructuring declaration without initializer") } } @@ -829,7 +854,7 @@ class DeclarationsConverter( */ private fun convertDestructingDeclarationEntry(entry: LighterASTNode): FirVariable<*> { var modifiers = Modifier(session) - lateinit var identifier: String + var identifier: String? = null var firType: FirTypeRef? = null entry.forEachChildren { when (it.tokenType) { @@ -882,7 +907,7 @@ class DeclarationsConverter( firAccessor.valueParameters += firValueParameters } - firAccessor.body = convertFunctionBody(block, expression?.let { expressionConverter.getAsFirExpression(it) }) + firAccessor.body = convertFunctionBody(block, expression) FunctionUtil.firFunctions.removeLast() return firAccessor } @@ -909,11 +934,11 @@ class DeclarationsConverter( firValueParameter.name, if (firValueParameter.returnTypeRef == implicitType) propertyTypeRef else firValueParameter.returnTypeRef, firValueParameter.defaultValue, - isCrossinline = modifiers.hasCrossinline(), - isNoinline = modifiers.hasNoinline(), - isVararg = modifiers.hasVararg() + isCrossinline = modifiers.hasCrossinline() || firValueParameter.isCrossinline, + isNoinline = modifiers.hasNoinline() || firValueParameter.isNoinline, + isVararg = modifiers.hasVararg() || firValueParameter.isVararg ).apply { - annotations += modifiers.annotations + annotations += modifiers.annotations + firValueParameter.annotations } } @@ -924,30 +949,32 @@ class DeclarationsConverter( var modifiers = Modifier(session) var identifier: String? = null val firTypeParameters = mutableListOf() - val valueParametersList = mutableListOf() + var valueParametersList: LighterASTNode? = null var isReturnType = false var receiverType: FirTypeRef? = null var returnType: FirTypeRef? = null val typeConstraints = mutableListOf() var block: LighterASTNode? = null var expression: LighterASTNode? = null + var hasEqToken = false functionDeclaration.forEachChildren { when (it.tokenType) { MODIFIER_LIST -> modifiers = convertModifierList(it) IDENTIFIER -> identifier = it.getAsString() TYPE_PARAMETER_LIST -> firTypeParameters += convertTypeParameters(it) - VALUE_PARAMETER_LIST -> valueParametersList += convertValueParameters(it) + VALUE_PARAMETER_LIST -> valueParametersList = it //must convert later, because it can contains "return" COLON -> isReturnType = true TYPE_REFERENCE -> if (isReturnType) returnType = convertType(it) else receiverType = convertType(it) TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it) BLOCK -> block = it + EQ -> hasEqToken = true else -> if (it.isExpression()) expression = it } } if (returnType == null) { returnType = - if (block != null || (block == null && expression == null)) implicitUnitType + if (block != null || !hasEqToken) implicitUnitType else implicitType } @@ -986,8 +1013,8 @@ class DeclarationsConverter( firFunction.joinTypeParameters(typeConstraints) } - firFunction.valueParameters += valueParametersList.map { it.firValueParameter } - firFunction.body = convertFunctionBody(block, expression?.let { expressionConverter.getAsFirExpression(it) }) + valueParametersList?.let { firFunction.valueParameters += convertValueParameters(it).map { it.firValueParameter } } + firFunction.body = convertFunctionBody(block, expression) FunctionUtil.firFunctions.removeLast() return firFunction } @@ -996,10 +1023,13 @@ class DeclarationsConverter( * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseFunctionBody * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.buildFirBody */ - private fun convertFunctionBody(blockNode: LighterASTNode?, firExpression: FirExpression?): FirBlock? { + private fun convertFunctionBody(blockNode: LighterASTNode?, expression: LighterASTNode?): FirBlock? { return when { blockNode != null -> return convertBlock(blockNode) - firExpression != null -> FirSingleExpressionBlock(session, firExpression.toReturn()) + expression != null -> FirSingleExpressionBlock( + session, + expressionConverter.getAsFirExpression(expression, "Function has no body (but should)").toReturn() + ) else -> null } } @@ -1081,11 +1111,11 @@ class DeclarationsConverter( */ private fun convertExplicitDelegation(explicitDelegation: LighterASTNode): FirDelegatedTypeRef { lateinit var firTypeRef: FirTypeRef - var firExpression: FirExpression? = null + var firExpression: FirExpression? = FirErrorExpressionImpl(session, null, "Should have delegate") explicitDelegation.forEachChildren { when (it.tokenType) { TYPE_REFERENCE -> firTypeRef = convertType(it) - else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it) + else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it, "Should have delegate") } } @@ -1143,7 +1173,7 @@ class DeclarationsConverter( */ private fun convertTypeParameter(typeParameter: LighterASTNode): FirTypeParameter { var typeParameterModifiers = TypeParameterModifier(session) - lateinit var identifier: String + var identifier: String? = null var firType: FirTypeRef? = null typeParameter.forEachChildren { when (it.tokenType) { @@ -1171,16 +1201,22 @@ class DeclarationsConverter( * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeRef */ fun convertType(type: LighterASTNode): FirTypeRef { + if (type.getAsString().isEmpty()) { + return FirErrorTypeRefImpl(session, null, "Unwrapped type is null") + } var typeModifiers = TypeModifier(session) //TODO what with suspend? - lateinit var firType: FirTypeRef + var firType: FirTypeRef = FirErrorTypeRefImpl(session, null, "Incomplete code") + var afterLPar = false type.forEachChildren { when (it.tokenType) { + LPAR -> afterLPar = true TYPE_REFERENCE -> firType = convertType(it) - MODIFIER_LIST -> typeModifiers = convertTypeModifierList(it) - USER_TYPE -> firType = convertUserType(it).also { firUserType -> (firUserType as FirUserTypeRefImpl).qualifier.reverse() } + MODIFIER_LIST -> if (!afterLPar || typeModifiers.hasNoAnnotations()) typeModifiers = convertTypeModifierList(it) + USER_TYPE -> firType = convertUserType(it) NULLABLE_TYPE -> firType = convertNullableType(it) FUNCTION_TYPE -> firType = convertFunctionType(it) DYNAMIC_TYPE -> firType = FirDynamicTypeRefImpl(session, null, false) + TokenType.ERROR_ELEMENT -> firType = FirErrorTypeRefImpl(session, null, "Unwrapped type is null") } } @@ -1209,7 +1245,7 @@ class DeclarationsConverter( nullableType.forEachChildren { when (it.tokenType) { USER_TYPE -> firType = - convertUserType(it, true).also { firUserType -> (firUserType as FirUserTypeRefImpl).qualifier.reverse() } + convertUserType(it, true) FUNCTION_TYPE -> firType = convertFunctionType(it, true) NULLABLE_TYPE -> firType = convertNullableType(it) DYNAMIC_TYPE -> firType = FirDynamicTypeRefImpl(session, null, true) @@ -1222,18 +1258,21 @@ class DeclarationsConverter( /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseUserType */ - private fun convertUserType(userType: LighterASTNode, isNullable: Boolean = false): FirUserTypeRef { + private fun convertUserType(userType: LighterASTNode, isNullable: Boolean = false): FirTypeRef { var simpleFirUserType: FirUserTypeRef? = null - lateinit var identifier: String + var identifier: String? = null val firTypeArguments = mutableListOf() userType.forEachChildren { when (it.tokenType) { - USER_TYPE -> simpleFirUserType = convertUserType(it) //simple user type + USER_TYPE -> simpleFirUserType = convertUserType(it) as? FirUserTypeRef //simple user type REFERENCE_EXPRESSION -> identifier = it.getAsString() TYPE_ARGUMENT_LIST -> firTypeArguments += convertTypeArguments(it) } } + if (identifier == null) + return FirErrorTypeRefImpl(session, null, "Incomplete user type") + val qualifier = FirQualifierPartImpl( identifier.nameAsSafeName() ).apply { typeArguments += firTypeArguments } @@ -1244,7 +1283,7 @@ class DeclarationsConverter( isNullable ).apply { this.qualifier.add(qualifier) - simpleFirUserType?.qualifier?.let { this@apply.qualifier.addAll(it) } + simpleFirUserType?.qualifier?.let { this@apply.qualifier.addAll(0, it) } } } @@ -1338,7 +1377,7 @@ class DeclarationsConverter( IDENTIFIER -> identifier = it.getAsString() TYPE_REFERENCE -> firType = convertType(it) DESTRUCTURING_DECLARATION -> destructuringDeclaration = convertDestructingDeclaration(it) - else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it) + else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it, "Should have default value") } } diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt index f7f3db7e708..ba2d629e009 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt @@ -6,33 +6,31 @@ package org.jetbrains.kotlin.fir.lightTree.converter import com.intellij.lang.LighterASTNode +import com.intellij.psi.TokenType import com.intellij.psi.impl.source.tree.java.PsiForStatementImpl import com.intellij.util.diff.FlyweightCapableTreeStructure import org.jetbrains.kotlin.KtNodeTypes.* -import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.builder.* -import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.impl.FirAnonymousFunctionImpl -import org.jetbrains.kotlin.fir.declarations.impl.FirAnonymousObjectImpl import org.jetbrains.kotlin.fir.declarations.impl.FirErrorLoop import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl +import org.jetbrains.kotlin.fir.declarations.impl.FirVariableImpl import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.* import org.jetbrains.kotlin.fir.labels.FirLabelImpl import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.extractArgumentsFrom import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsString +import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsStringWithoutBacktick import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.isExpression import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.nameAsSafeName import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.toReturn import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.pop import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.removeLast import org.jetbrains.kotlin.fir.lightTree.converter.utils.* -import org.jetbrains.kotlin.fir.lightTree.fir.ClassWrapper import org.jetbrains.kotlin.fir.lightTree.fir.ValueParameter import org.jetbrains.kotlin.fir.lightTree.fir.WhenEntry -import org.jetbrains.kotlin.fir.lightTree.fir.modifier.Modifier import org.jetbrains.kotlin.fir.references.FirErrorNamedReference import org.jetbrains.kotlin.fir.references.FirExplicitSuperReference import org.jetbrains.kotlin.fir.references.FirExplicitThisReference @@ -57,12 +55,12 @@ class ExpressionsConverter( private val declarationsConverter: DeclarationsConverter ) : BaseConverter(session, tree) { - inline fun getAsFirExpression(expression: LighterASTNode): R { - return convertExpression(expression) as R + inline fun getAsFirExpression(expression: LighterASTNode?, errorReason: String = ""): R { + return expression?.let { convertExpression(it, errorReason) } as? R ?: (FirErrorExpressionImpl(session, null, errorReason) as R) } /***** EXPRESSIONS *****/ - fun convertExpression(expression: LighterASTNode): FirElement { + fun convertExpression(expression: LighterASTNode, errorReason: String): FirElement { if (!stubMode) { return when (expression.tokenType) { LAMBDA_EXPRESSION -> { @@ -93,22 +91,28 @@ class ExpressionsConverter( BREAK, CONTINUE -> convertLoopJump(expression) RETURN -> convertReturn(expression) THROW -> convertThrow(expression) - PARENTHESIZED, PROPERTY_DELEGATE, INDICES -> convertExpression(expression.getExpressionInParentheses()) + PARENTHESIZED -> getAsFirExpression(expression.getExpressionInParentheses(), "Empty parentheses") + PROPERTY_DELEGATE, INDICES, CONDITION, LOOP_RANGE -> + getAsFirExpression(expression.getExpressionInParentheses(), errorReason) THIS_EXPRESSION -> convertThisExpression(expression) SUPER_EXPRESSION -> convertSuperExpression(expression) OBJECT_LITERAL -> declarationsConverter.convertObjectLiteral(expression) FUN -> declarationsConverter.convertFunctionDeclaration(expression) - else -> FirExpressionStub(session, null) + else -> FirErrorExpressionImpl(session, null, errorReason) } } return FirExpressionStub(session, null) } + /** + * @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseFunctionLiteral + * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitLambdaExpression + */ private fun convertLambdaExpression(lambdaExpression: LighterASTNode): FirExpression { val valueParameterList = mutableListOf() - lateinit var block: LighterASTNode + var block: LighterASTNode? = null lambdaExpression.getChildNodesByType(FUNCTION_LITERAL).first().forEachChildren { when (it.tokenType) { VALUE_PARAMETER_LIST -> valueParameterList += declarationsConverter.convertValueParameters(it) @@ -141,7 +145,8 @@ class ExpressionsConverter( label = FunctionUtil.firLabels.pop() ?: FunctionUtil.firFunctionCalls.lastOrNull()?.calleeReference?.name?.let { FirLabelImpl(this@ExpressionsConverter.session, null, it.asString()) } - val bodyExpression = declarationsConverter.convertBlockExpression(block) + val bodyExpression = block?.let { declarationsConverter.convertBlockExpression(it) } + ?: FirErrorExpressionImpl(session, null, "Lambda has no body") body = if (bodyExpression is FirBlockImpl) { if (bodyExpression.statements.isEmpty()) { bodyExpression.statements.add(FirUnitExpression(this@ExpressionsConverter.session, null)) @@ -167,8 +172,8 @@ class ExpressionsConverter( private fun convertBinaryExpression(binaryExpression: LighterASTNode): FirStatement { var isLeftArgument = true lateinit var operationTokenName: String - lateinit var leftArgNode: LighterASTNode - lateinit var rightArgAsFir: FirExpression + var leftArgNode: LighterASTNode? = null + var rightArgAsFir: FirExpression = FirErrorExpressionImpl(session, null, "No right operand") binaryExpression.forEachChildren { when (it.tokenType) { OPERATION_REFERENCE -> { @@ -179,7 +184,7 @@ class ExpressionsConverter( if (isLeftArgument) { leftArgNode = it } else { - rightArgAsFir = getAsFirExpression(it) + rightArgAsFir = getAsFirExpression(it, "No right operand") } } } @@ -188,16 +193,16 @@ class ExpressionsConverter( val operationToken = operationTokenName.getOperationSymbol() when (operationToken) { ELVIS -> - return getAsFirExpression(leftArgNode).generateNotNullOrOther( + return getAsFirExpression(leftArgNode, "No left operand").generateNotNullOrOther( session, rightArgAsFir, "elvis", null ) ANDAND, OROR -> - return getAsFirExpression(leftArgNode).generateLazyLogicalOperation( + return getAsFirExpression(leftArgNode, "No left operand").generateLazyLogicalOperation( session, rightArgAsFir, operationToken == ANDAND, null ) in OperatorConventions.IN_OPERATIONS -> return rightArgAsFir.generateContainsOperation( - session, getAsFirExpression(leftArgNode), operationToken == NOT_IN, null, null + session, getAsFirExpression(leftArgNode, "No left operand"), operationToken == NOT_IN, null, null ) } val conventionCallName = operationToken.toBinaryName() @@ -207,7 +212,7 @@ class ExpressionsConverter( this@ExpressionsConverter.session, null, conventionCallName ?: operationTokenName.nameAsSafeName() ) - explicitReceiver = getAsFirExpression(leftArgNode) + explicitReceiver = getAsFirExpression(leftArgNode, "No left operand") arguments += rightArgAsFir } } else { @@ -216,7 +221,7 @@ class ExpressionsConverter( return convertAssignment(leftArgNode, rightArgAsFir, firOperation) } else { FirOperatorCallImpl(session, null, firOperation).apply { - arguments += getAsFirExpression(leftArgNode) + arguments += getAsFirExpression(leftArgNode, "No left operand") arguments += rightArgAsFir } } @@ -229,13 +234,13 @@ class ExpressionsConverter( */ private fun convertBinaryWithType(binaryExpression: LighterASTNode): FirTypeOperatorCall { lateinit var operationTokenName: String - lateinit var leftArgAsFir: FirExpression + var leftArgAsFir: FirExpression = FirErrorExpressionImpl(session, null, "No left operand") lateinit var firType: FirTypeRef binaryExpression.forEachChildren { when (it.tokenType) { OPERATION_REFERENCE -> operationTokenName = it.getAsString() TYPE_REFERENCE -> firType = declarationsConverter.convertType(it) - else -> if (it.isExpression()) leftArgAsFir = getAsFirExpression(it) + else -> if (it.isExpression()) leftArgAsFir = getAsFirExpression(it, "No left operand") } } @@ -250,13 +255,13 @@ class ExpressionsConverter( */ private fun convertIsExpression(isExpression: LighterASTNode): FirTypeOperatorCall { lateinit var operationTokenName: String - lateinit var leftArgAsFir: FirExpression + var leftArgAsFir: FirExpression = FirErrorExpressionImpl(session, null, "No left operand") lateinit var firType: FirTypeRef isExpression.forEachChildren { when (it.tokenType) { OPERATION_REFERENCE -> operationTokenName = it.getAsString() TYPE_REFERENCE -> firType = declarationsConverter.convertType(it) - else -> if (it.isExpression()) leftArgAsFir = getAsFirExpression(it) + else -> if (it.isExpression()) leftArgAsFir = getAsFirExpression(it, "No left operand") } } @@ -276,6 +281,8 @@ class ExpressionsConverter( labeledExpression.forEachChildren { when (it.tokenType) { LABEL_QUALIFIER -> FunctionUtil.firLabels += FirLabelImpl(session, null, it.toString().replace("@", "")) + BLOCK -> firExpression = declarationsConverter.convertBlock(it) + PROPERTY -> firExpression = declarationsConverter.convertPropertyDeclaration(it) else -> if (it.isExpression()) firExpression = getAsFirExpression(it) } } @@ -294,7 +301,7 @@ class ExpressionsConverter( */ private fun convertUnaryExpression(unaryExpression: LighterASTNode): FirExpression { lateinit var operationTokenName: String - lateinit var argument: LighterASTNode + var argument: LighterASTNode? = null unaryExpression.forEachChildren { when (it.tokenType) { OPERATION_REFERENCE -> operationTokenName = it.getAsString() @@ -304,7 +311,7 @@ class ExpressionsConverter( val operationToken = operationTokenName.getOperationSymbol() if (operationToken == EXCLEXCL) { - return bangBangToWhen(session, getAsFirExpression(argument)) + return bangBangToWhen(session, getAsFirExpression(argument, "No operand")) } val conventionCallName = operationToken.toUnaryName() @@ -318,12 +325,12 @@ class ExpressionsConverter( } FirFunctionCallImpl(session, null).apply { calleeReference = FirSimpleNamedReference(this@ExpressionsConverter.session, null, conventionCallName) - explicitReceiver = getAsFirExpression(argument) + explicitReceiver = getAsFirExpression(argument, "No operand") } } else { val firOperation = operationToken.toFirOperation() FirOperatorCallImpl(session, null, firOperation).apply { - arguments += getAsFirExpression(argument) + arguments += getAsFirExpression(argument, "No operand") } } } @@ -353,9 +360,9 @@ class ExpressionsConverter( * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitClassLiteralExpression */ private fun convertClassLiteralExpression(classLiteralExpression: LighterASTNode): FirExpression { - lateinit var firReceiverExpression: FirExpression + var firReceiverExpression: FirExpression = FirErrorExpressionImpl(session, null, "No receiver in class literal") classLiteralExpression.forEachChildren { - if (it.isExpression()) firReceiverExpression = getAsFirExpression(it) + if (it.isExpression()) firReceiverExpression = getAsFirExpression(it, "No receiver in class literal") } return FirGetClassCallImpl(session, null).apply { @@ -376,7 +383,7 @@ class ExpressionsConverter( COLONCOLON -> isReceiver = false else -> if (it.isExpression()) { if (isReceiver) { - firReceiverExpression = getAsFirExpression(it) + firReceiverExpression = getAsFirExpression(it, "Incorrect receiver expression") } else { firCallableReference = convertSimpleNameExpression(it) } @@ -397,8 +404,8 @@ class ExpressionsConverter( private fun convertQualifiedExpression(dotQualifiedExpression: LighterASTNode): FirExpression { var isSelector = false var isSafe = false - var firSelector: FirExpression? = null //after dot - lateinit var firReceiver: FirExpression //before dot + var firSelector: FirExpression = FirErrorExpressionImpl(session, null, "Qualified expression without selector") //after dot + var firReceiver: FirExpression? = null //before dot dotQualifiedExpression.forEachChildren { when (it.tokenType) { DOT -> isSelector = true @@ -406,20 +413,21 @@ class ExpressionsConverter( isSafe = true isSelector = true } - else -> if (isSelector) firSelector = getAsFirExpression(it) else firReceiver = getAsFirExpression(it) + else -> { + if (isSelector && it.tokenType != TokenType.ERROR_ELEMENT) + firSelector = getAsFirExpression(it, "Incorrect selector expression") + else + firReceiver = getAsFirExpression(it, "Incorrect receiver expression") + } } } - if (firSelector == null) { - return FirErrorExpressionImpl(session, null, "Qualified expression without selector") - } - //TODO use contracts? if (firSelector is FirModifiableQualifiedAccess<*>) { (firSelector as FirModifiableQualifiedAccess<*>).safe = isSafe (firSelector as FirModifiableQualifiedAccess<*>).explicitReceiver = firReceiver } - return firSelector!! + return firSelector } /** @@ -435,12 +443,13 @@ class ExpressionsConverter( REFERENCE_EXPRESSION -> name = it.getAsString() TYPE_ARGUMENT_LIST -> firTypeArguments += declarationsConverter.convertTypeArguments(it) VALUE_ARGUMENT_LIST, LAMBDA_ARGUMENT -> valueArguments += it - else -> additionalArgument = getAsFirExpression(it) + else -> if (it.tokenType != TokenType.ERROR_ELEMENT) additionalArgument = + getAsFirExpression(it, "Incorrect invoke receiver") } } return FirFunctionCallImpl(session, null).apply { - val calleeReference = when { + this.calleeReference = when { name != null -> FirSimpleNamedReference(this@ExpressionsConverter.session, null, name.nameAsSafeName()) additionalArgument != null -> { arguments += additionalArgument!! @@ -448,7 +457,7 @@ class ExpressionsConverter( } else -> FirErrorNamedReference(this@ExpressionsConverter.session, null, "Call has no callee") } - this.calleeReference = calleeReference + FunctionUtil.firFunctionCalls += this this.extractArgumentsFrom(valueArguments.flatMap { convertValueArguments(it) }, stubMode) typeArguments += firTypeArguments @@ -472,8 +481,11 @@ class ExpressionsConverter( FirConstExpressionImpl(session, null, IrConstKind.String, it.getAsString()) } ESCAPE_STRING_TEMPLATE_ENTRY -> { - sb.append(escapedStringToCharacter(it.getAsString())) - FirConstExpressionImpl(session, null, IrConstKind.String, escapedStringToCharacter(it.getAsString())?.toString() ?: "") + val escape = it.getAsString() + val unescaped = escapedStringToCharacter(escape)?.toString() + ?: escape.replace("\\", "").replace("u", "\\u") + sb.append(unescaped) + FirConstExpressionImpl(session, null, IrConstKind.String, unescaped) } SHORT_STRING_TEMPLATE_ENTRY, LONG_STRING_TEMPLATE_ENTRY -> { hasExpressions = true @@ -503,9 +515,9 @@ class ExpressionsConverter( } private fun convertShortOrLongStringTemplate(shortOrLongString: LighterASTNode): FirExpression { - lateinit var firExpression: FirExpression + var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "Incorrect template argument") shortOrLongString.forEachChildren(LONG_TEMPLATE_ENTRY_START, LONG_TEMPLATE_ENTRY_END) { - firExpression = getAsFirExpression(it) + firExpression = getAsFirExpression(it, "Incorrect template argument") } return firExpression } @@ -571,22 +583,24 @@ class ExpressionsConverter( val whenEntries = mutableListOf() whenExpression.forEachChildren { when (it.tokenType) { - PROPERTY -> subjectVariable = declarationsConverter.convertPropertyDeclaration(it) as FirVariable<*> - DESTRUCTURING_DECLARATION -> subjectExpression = getAsFirExpression(it) + PROPERTY -> subjectVariable = (declarationsConverter.convertPropertyDeclaration(it) as FirVariable<*>).let { variable -> + FirVariableImpl( + session, null, variable.name, variable.returnTypeRef, + isVar = false, initializer = variable.initializer + ) + } + DESTRUCTURING_DECLARATION -> subjectExpression = + getAsFirExpression(it, "Incorrect when subject expression: ${whenExpression.getAsString()}") WHEN_ENTRY -> whenEntries += convertWhenEntry(it) - else -> if (it.isExpression()) subjectExpression = getAsFirExpression(it) + else -> if (it.isExpression()) subjectExpression = + getAsFirExpression(it, "Incorrect when subject expression: ${whenExpression.getAsString()}") } } subjectExpression = subjectVariable?.initializer ?: subjectExpression val hasSubject = subjectExpression != null val subject = FirWhenSubject() - return FirWhenExpressionImpl( - session, - null, - subjectExpression, - subjectVariable - ).apply { + return FirWhenExpressionImpl(session, null, subjectExpression, subjectVariable).apply { if (hasSubject) { subject.bind(this) } @@ -615,7 +629,7 @@ class ExpressionsConverter( */ private fun convertWhenEntry(whenEntry: LighterASTNode): WhenEntry { var isElse = false - lateinit var firBlock: FirBlock + var firBlock: FirBlock = FirEmptyExpressionBlock(session) val conditions = mutableListOf() whenEntry.forEachChildren { when (it.tokenType) { @@ -632,10 +646,10 @@ class ExpressionsConverter( } private fun convertWhenConditionExpression(whenCondition: LighterASTNode): FirExpression { - lateinit var firExpression: FirExpression + var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "No expression in condition with expression") whenCondition.forEachChildren { when (it.tokenType) { - else -> if (it.isExpression()) firExpression = getAsFirExpression(it) + else -> if (it.isExpression()) firExpression = getAsFirExpression(it, "No expression in condition with expression") } } @@ -646,7 +660,7 @@ class ExpressionsConverter( private fun convertWhenConditionInRange(whenCondition: LighterASTNode): FirExpression { var isNegate = false - lateinit var firExpression: FirExpression + var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "No range in condition with range") whenCondition.forEachChildren { when (it.tokenType) { NOT_IN -> isNegate = true @@ -680,12 +694,12 @@ class ExpressionsConverter( * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitArrayAccessExpression */ private fun convertArrayAccessExpression(arrayAccess: LighterASTNode): FirFunctionCall { - lateinit var firExpression: FirExpression + var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "No array expression") val indices: MutableList = mutableListOf() arrayAccess.forEachChildren { when (it.tokenType) { INDICES -> indices += convertIndices(it) - else -> if (it.isExpression()) firExpression = getAsFirExpression(it) + else -> if (it.isExpression()) firExpression = getAsFirExpression(it, "No array expression") } } return FirFunctionCallImpl(session, null).apply { @@ -701,7 +715,7 @@ class ExpressionsConverter( private fun convertCollectionLiteralExpresion(expression: LighterASTNode): FirExpression { val firExpressionList = mutableListOf() expression.forEachChildren { - if (it.isExpression()) firExpressionList += getAsFirExpression(it) + if (it.isExpression()) firExpressionList += getAsFirExpression(it, "Incorrect collection literal argument") } return FirArrayOfCallImpl(session, null).apply { @@ -715,7 +729,7 @@ class ExpressionsConverter( private fun convertIndices(indices: LighterASTNode): List { val firExpressionList: MutableList = mutableListOf() indices.forEachChildren { - if (it.isExpression()) firExpressionList += getAsFirExpression(it) + if (it.isExpression()) firExpressionList += getAsFirExpression(it, "Incorrect index expression") } return firExpressionList @@ -738,17 +752,15 @@ class ExpressionsConverter( */ private fun convertDoWhile(doWhileLoop: LighterASTNode): FirElement { var block: LighterASTNode? = null - var condition: FirExpression? = null + var firCondition: FirExpression = FirErrorExpressionImpl(session, null, "No condition in do-while loop") doWhileLoop.forEachChildren { when (it.tokenType) { BODY -> block = it - CONDITION -> condition = convertCondition(it) + CONDITION -> firCondition = getAsFirExpression(it, "No condition in do-while loop") } } - return FirDoWhileLoopImpl( - session, null, condition ?: FirErrorExpressionImpl(session, null, "No condition in do-while loop") - ).configure { convertLoopBody(block) } + return FirDoWhileLoopImpl(session, null, firCondition).configure { convertLoopBody(block) } } /** @@ -757,17 +769,15 @@ class ExpressionsConverter( */ private fun convertWhile(whileLoop: LighterASTNode): FirElement { var block: LighterASTNode? = null - var condition: FirExpression? = null + var firCondition: FirExpression = FirErrorExpressionImpl(session, null, "No condition in while loop") whileLoop.forEachChildren { when (it.tokenType) { BODY -> block = it - CONDITION -> condition = convertCondition(it) + CONDITION -> firCondition = getAsFirExpression(it, "No condition in while loop") } } - return FirWhileLoopImpl( - session, null, condition ?: FirErrorExpressionImpl(session, null, "No condition in while loop") - ).configure { convertLoopBody(block) } + return FirWhileLoopImpl(session, null, firCondition).configure { convertLoopBody(block) } } /** @@ -781,7 +791,7 @@ class ExpressionsConverter( forLoop.forEachChildren { when (it.tokenType) { VALUE_PARAMETER -> parameter = declarationsConverter.convertValueParameter(it) - LOOP_RANGE -> convertCondition(it)?.apply { rangeExpression = this } + LOOP_RANGE -> rangeExpression = getAsFirExpression(it, "No range in for loop") BODY -> blockNode = it } } @@ -873,7 +883,7 @@ class ExpressionsConverter( tryExpression.forEachChildren { when (it.tokenType) { BLOCK -> tryBlock = declarationsConverter.convertBlock(it) - CATCH -> catchClauses += convertCatchClause(it) + CATCH -> convertCatchClause(it)?.also { oneClause -> catchClauses += oneClause } FINALLY -> finallyBlock = convertFinally(it) } } @@ -888,12 +898,12 @@ class ExpressionsConverter( /** * @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseTry */ - private fun convertCatchClause(catchClause: LighterASTNode): Pair { + private fun convertCatchClause(catchClause: LighterASTNode): Pair? { var valueParameter: ValueParameter? = null var blockNode: LighterASTNode? = null catchClause.forEachChildren { when (it.tokenType) { - VALUE_PARAMETER_LIST -> valueParameter = declarationsConverter.convertValueParameters(it).first() + VALUE_PARAMETER_LIST -> valueParameter = declarationsConverter.convertValueParameters(it).firstOrNull() ?: return null BLOCK -> blockNode = it } } @@ -920,20 +930,18 @@ class ExpressionsConverter( * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitIfExpression */ private fun convertIfExpression(ifExpression: LighterASTNode): FirExpression { - var condition: FirExpression? = null + var firCondition: FirExpression = FirErrorExpressionImpl(session, null, "If statement should have condition") var thenBlock: LighterASTNode? = null var elseBlock: LighterASTNode? = null ifExpression.forEachChildren { when (it.tokenType) { - CONDITION -> condition = convertCondition(it) + CONDITION -> firCondition = getAsFirExpression(it, "If statement should have condition") THEN -> thenBlock = it ELSE -> elseBlock = it } } return FirWhenExpressionImpl(session, null).apply { - val firCondition = - condition ?: FirErrorExpressionImpl(this@ExpressionsConverter.session, null, "If statement should have condition") val trueBranch = convertLoopBody(thenBlock) branches += FirWhenBranchImpl(this@ExpressionsConverter.session, null, firCondition, trueBranch) val elseBranch = convertLoopBody(elseBlock) @@ -943,17 +951,6 @@ class ExpressionsConverter( } } - /** - * @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseCondition - */ - private fun convertCondition(condition: LighterASTNode): FirExpression? { - condition.forEachChildren { - if (it.isExpression()) return getAsFirExpression(it) - } - - return null - } - /** * @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseJump * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitBreakExpression @@ -997,16 +994,15 @@ class ExpressionsConverter( */ private fun convertReturn(returnExpression: LighterASTNode): FirExpression { var labelName: String? = null - var firExpression: FirExpression? = null + var firExpression: FirExpression = FirUnitExpression(session, null) returnExpression.forEachChildren { when (it.tokenType) { - LABEL_QUALIFIER -> labelName = it.getAsString().replace("@", "") - else -> if (it.isExpression()) firExpression = getAsFirExpression(it) + LABEL_QUALIFIER -> labelName = it.getAsStringWithoutBacktick().replace("@", "") + else -> if (it.isExpression()) firExpression = getAsFirExpression(it, "Incorrect return expression") } } - val result = firExpression ?: FirUnitExpression(session, null) - return result.toReturn(labelName) + return firExpression.toReturn(labelName) } /** @@ -1014,12 +1010,12 @@ class ExpressionsConverter( * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitThrowExpression */ private fun convertThrow(throwExpression: LighterASTNode): FirExpression { - var firExpression: FirExpression? = null + var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "Nothing to throw") throwExpression.forEachChildren { - if (it.isExpression()) firExpression = getAsFirExpression(it) + if (it.isExpression()) firExpression = getAsFirExpression(it, "Nothing to throw") } - return FirThrowExpressionImpl(session, null, firExpression ?: FirErrorExpressionImpl(session, null, "Nothing to throw")) + return FirThrowExpressionImpl(session, null, firExpression) } /** @@ -1077,14 +1073,14 @@ class ExpressionsConverter( private fun convertValueArgument(valueArgument: LighterASTNode): FirExpression { var identifier: String? = null var isSpread = false - lateinit var firExpression: FirExpression + var firExpression: FirExpression = FirErrorExpressionImpl(session, null, "Argument is absent") valueArgument.forEachChildren { when (it.tokenType) { VALUE_ARGUMENT_NAME -> identifier = it.getAsString() MUL -> isSpread = true STRING_TEMPLATE -> firExpression = convertStringTemplate(it) is KtConstantExpressionElementType -> firExpression = convertConstantExpression(it) - else -> if (it.isExpression()) firExpression = getAsFirExpression(it) + else -> if (it.isExpression()) firExpression = getAsFirExpression(it, "Argument is absent") } } return when { @@ -1097,15 +1093,16 @@ class ExpressionsConverter( /** * @see org.jetbrains.kotlin.fir.builder.ConversionUtilsKt.initializeLValue */ - fun convertLValue(leftArgNode: LighterASTNode, container: FirModifiableQualifiedAccess<*>): FirReference { - return when (leftArgNode.tokenType) { + fun convertLValue(leftArgNode: LighterASTNode?, container: FirModifiableQualifiedAccess<*>): FirReference { + return when (leftArgNode?.tokenType) { + null -> FirErrorNamedReference(session, null, "Unsupported LValue: ${leftArgNode?.tokenType}") THIS_EXPRESSION -> convertThisExpression(leftArgNode).calleeReference REFERENCE_EXPRESSION -> FirSimpleNamedReference(session, null, leftArgNode.getAsString().nameAsSafeName()) - in qualifiedAccessTokens -> (getAsFirExpression(leftArgNode) as FirQualifiedAccess).let { firQualifiedAccess -> + in qualifiedAccessTokens -> (getAsFirExpression(leftArgNode) as? FirQualifiedAccess)?.let { firQualifiedAccess -> container.explicitReceiver = firQualifiedAccess.explicitReceiver container.safe = firQualifiedAccess.safe return@let firQualifiedAccess.calleeReference - } + } ?: FirErrorNamedReference(session, null, "Unsupported qualified LValue: ${leftArgNode.getAsString()}") PARENTHESIZED -> convertLValue(leftArgNode.getExpressionInParentheses(), container) else -> FirErrorNamedReference(session, null, "Unsupported LValue: ${leftArgNode.tokenType}") } diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/utils/ExpressionUtil.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/utils/ExpressionUtil.kt index 18f198e8769..22e6bab74bc 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/utils/ExpressionUtil.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/utils/ExpressionUtil.kt @@ -16,16 +16,14 @@ import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.* import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsString import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.nameAsSafeName -import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.pop -import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.removeLast import org.jetbrains.kotlin.fir.lightTree.converter.ExpressionsConverter import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil +import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.pop +import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.removeLast import org.jetbrains.kotlin.fir.lightTree.fir.DestructuringDeclaration import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol -import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.lexer.KtSingleValueToken -import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.parsing.KotlinExpressionParsing @@ -42,16 +40,17 @@ fun String.getOperationSymbol(): IElementType { } fun ExpressionsConverter.convertAssignment( - leftArgNode: LighterASTNode, + leftArgNode: LighterASTNode?, rightArgAsFir: FirExpression, operation: FirOperation ): FirStatement { - if (leftArgNode.tokenType == PARENTHESIZED) { + if (leftArgNode != null && leftArgNode.tokenType == PARENTHESIZED) { return convertAssignment(leftArgNode.getExpressionInParentheses(), rightArgAsFir, operation) } - if (leftArgNode.tokenType == ARRAY_ACCESS_EXPRESSION) { + if (leftArgNode != null && leftArgNode.tokenType == ARRAY_ACCESS_EXPRESSION) { val arrayAccessFunctionCall = getAsFirExpression(leftArgNode) as FirFunctionCall - val firArrayExpression = arrayAccessFunctionCall.explicitReceiver!! + val firArrayExpression = arrayAccessFunctionCall.explicitReceiver + ?: FirErrorExpressionImpl(session, null, "No array expression") val arraySet = if (operation != FirOperation.ASSIGN) { FirArraySetCallImpl(session, null, rightArgAsFir, operation).apply { indexes += arrayAccessFunctionCall.arguments @@ -76,12 +75,14 @@ fun ExpressionsConverter.convertAssignment( } } if (operation != FirOperation.ASSIGN && - leftArgNode.tokenType != REFERENCE_EXPRESSION && leftArgNode.tokenType != THIS_EXPRESSION && - (leftArgNode.tokenType !in qualifiedAccessTokens || getSelectorType(leftArgNode.getChildrenAsArray()) != REFERENCE_EXPRESSION) + leftArgNode?.tokenType != REFERENCE_EXPRESSION && leftArgNode?.tokenType != THIS_EXPRESSION && + (leftArgNode?.tokenType !in qualifiedAccessTokens || getSelectorType(leftArgNode.getChildrenAsArray()) != REFERENCE_EXPRESSION) ) { return FirBlockImpl(session, null).apply { val name = Name.special("") - statements += generateTemporaryVariable(this@convertAssignment.session, null, name, getAsFirExpression(leftArgNode)) + statements += generateTemporaryVariable( + this@convertAssignment.session, null, name, getAsFirExpression(leftArgNode, "No LValue in assignment") + ) statements += FirVariableAssignmentImpl(this@convertAssignment.session, null, rightArgAsFir, operation).apply { lValue = FirSimpleNamedReference(this@convertAssignment.session, null, name) } @@ -104,7 +105,7 @@ fun ExpressionsConverter.generateIncrementOrDecrementBlock( return FirBlockImpl(session, null).apply { val tempName = Name.special("") val temporaryVariable = generateTemporaryVariable( - this@generateIncrementOrDecrementBlock.session, null, tempName, getAsFirExpression(argument) + this@generateIncrementOrDecrementBlock.session, null, tempName, getAsFirExpression(argument, "Incorrect expression inside inc/dec") ) statements += temporaryVariable val resultName = Name.special("") diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/ClassWrapper.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/ClassWrapper.kt index 85a9a9fd372..202ad74b387 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/ClassWrapper.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/ClassWrapper.kt @@ -30,12 +30,16 @@ class ClassWrapper( val delegatedSuperTypeRef: FirTypeRef, val superTypeCallEntry: MutableList ) { + fun isObjectLiteral(): Boolean { + return className == SpecialNames.NO_NAME_PROVIDED && isObject() + } + private fun isObject(): Boolean { return classKind == ClassKind.OBJECT } private fun isSealed(): Boolean { - return modifiers.getModality() == Modality.SEALED + return modifiers.hasModality(Modality.SEALED) } private fun isEnum(): Boolean { diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/DestructuringDeclaration.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/DestructuringDeclaration.kt index 6caca174d8e..2433cda5164 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/DestructuringDeclaration.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/DestructuringDeclaration.kt @@ -16,18 +16,10 @@ import org.jetbrains.kotlin.fir.lightTree.converter.utils.generateDestructuringB data class DestructuringDeclaration( val isVar: Boolean, val entries: List>, - val initializer: FirExpression? + val initializer: FirExpression ) { fun toFirDestructingDeclaration(session: FirSession): FirExpression { - val baseVariable = generateTemporaryVariable( - session, null, "destruct", - initializer ?: FirErrorExpressionImpl(session, null, "Destructuring declaration without initializer") - ) - return generateDestructuringBlock( - session, - this, - baseVariable, - tmpVariable = true - ) + val baseVariable = generateTemporaryVariable(session, null, "destruct", initializer) + return generateDestructuringBlock(session, this, baseVariable, tmpVariable = true) } } \ No newline at end of file diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt index cce763dbf29..6b1ee9f9d52 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt @@ -17,6 +17,9 @@ import org.jetbrains.kotlin.fir.lightTree.converter.ClassNameUtil import org.jetbrains.kotlin.fir.lightTree.fir.modifier.Modifier import org.jetbrains.kotlin.fir.references.FirPropertyFromParameterCallableReference import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol +import org.jetbrains.kotlin.fir.types.FirErrorTypeRef +import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef +import org.jetbrains.kotlin.fir.types.impl.FirErrorTypeRefImpl class ValueParameter( private val isVal: Boolean, @@ -31,7 +34,10 @@ class ValueParameter( fun toFirProperty(): FirProperty { val name = this.firValueParameter.name - val type = this.firValueParameter.returnTypeRef + var type = this.firValueParameter.returnTypeRef + if (type is FirImplicitTypeRef) { + type = FirErrorTypeRefImpl(this.firValueParameter.session, null, "Incomplete code") + } return FirMemberPropertyImpl( this.firValueParameter.session, diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/WhenEntry.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/WhenEntry.kt index 9fe888a1e24..de514aec479 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/WhenEntry.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/WhenEntry.kt @@ -64,9 +64,9 @@ data class WhenEntry( val condition = conditions.first() return when (condition) { is FirOperatorCallImpl -> condition.arguments.first() - is FirFunctionCall -> condition.explicitReceiver!! - is FirTypeOperatorCallImpl -> condition - else -> FirErrorExpressionImpl(session, null, "Unsupported when condition: ${condition.javaClass}") + //is FirFunctionCall -> condition.explicitReceiver!! + //is FirTypeOperatorCallImpl -> condition + else -> FirErrorExpressionImpl(session, null, "No expression in condition with expression") } } } \ No newline at end of file diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/Modifier.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/Modifier.kt index ffc1e9359ef..3e2c8530801 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/Modifier.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/Modifier.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.lightTree.fir.modifier import com.intellij.lang.LighterASTNode import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.expressions.impl.FirAbstractAnnotatedElement @@ -24,49 +25,49 @@ class Modifier( session: FirSession, psi: PsiElement? = null, - private var classModifier: ClassModifier? = null, + private val classModifiers: MutableList = mutableListOf(), private val memberModifiers: MutableList = mutableListOf(), - private var visibilityModifier: VisibilityModifier = VisibilityModifier.UNKNOWN, + private val visibilityModifiers: MutableList = mutableListOf(), private val functionModifiers: MutableList = mutableListOf(), private var propertyModifier: PropertyModifier? = null, - private var inheritanceModifier: InheritanceModifier? = null, - private var parameterModifier: ParameterModifier? = null, - private var platformModifier: PlatformModifier? = null + private val inheritanceModifiers: MutableList = mutableListOf(), + private val parameterModifiers: MutableList = mutableListOf(), + private val platformModifiers: MutableList = mutableListOf() ) : FirAbstractAnnotatedElement(session, psi) { fun addModifier(modifier: LighterASTNode) { val tokenType = modifier.tokenType when { - CLASS_MODIFIER.contains(tokenType) -> this.classModifier = ClassModifier.valueOf(modifier.toString().toUpperCase()) + CLASS_MODIFIER.contains(tokenType) -> this.classModifiers += ClassModifier.valueOf(modifier.toString().toUpperCase()) MEMBER_MODIFIER.contains(tokenType) -> this.memberModifiers += MemberModifier.valueOf(modifier.toString().toUpperCase()) - VISIBILITY_MODIFIER.contains(tokenType) -> this.visibilityModifier = + VISIBILITY_MODIFIER.contains(tokenType) -> this.visibilityModifiers += VisibilityModifier.valueOf(modifier.toString().toUpperCase()) FUNCTION_MODIFIER.contains(tokenType) -> this.functionModifiers += FunctionModifier.valueOf(modifier.toString().toUpperCase()) PROPERTY_MODIFIER.contains(tokenType) -> this.propertyModifier = PropertyModifier.valueOf(modifier.toString().toUpperCase()) - INHERITANCE_MODIFIER.contains(tokenType) -> this.inheritanceModifier = + INHERITANCE_MODIFIER.contains(tokenType) -> this.inheritanceModifiers += InheritanceModifier.valueOf(modifier.toString().toUpperCase()) - PARAMETER_MODIFIER.contains(tokenType) -> this.parameterModifier = ParameterModifier.valueOf(modifier.toString().toUpperCase()) - PLATFORM_MODIFIER.contains(tokenType) -> this.platformModifier = PlatformModifier.valueOf(modifier.toString().toUpperCase()) + PARAMETER_MODIFIER.contains(tokenType) -> this.parameterModifiers += ParameterModifier.valueOf(modifier.toString().toUpperCase()) + PLATFORM_MODIFIER.contains(tokenType) -> this.platformModifiers += PlatformModifier.valueOf(modifier.toString().toUpperCase()) } } fun isEnum(): Boolean { - return classModifier == ClassModifier.ENUM + return classModifiers.contains(ClassModifier.ENUM) } fun isAnnotation(): Boolean { - return classModifier == ClassModifier.ANNOTATION + return classModifiers.contains(ClassModifier.ANNOTATION) } fun isDataClass(): Boolean { - return classModifier == ClassModifier.DATA + return classModifiers.contains(ClassModifier.DATA) } fun isInner(): Boolean { - return classModifier == ClassModifier.INNER + return classModifiers.contains(ClassModifier.INNER) } fun isCompanion(): Boolean { - return classModifier == ClassModifier.COMPANION + return classModifiers.contains(ClassModifier.COMPANION) } fun hasOverride(): Boolean { @@ -78,7 +79,13 @@ class Modifier( } fun getVisibility(): Visibility { - return visibilityModifier.toVisibility() + return when { + visibilityModifiers.contains(VisibilityModifier.PRIVATE) -> Visibilities.PRIVATE + visibilityModifiers.contains(VisibilityModifier.PUBLIC) -> Visibilities.PUBLIC + visibilityModifiers.contains(VisibilityModifier.PROTECTED) -> Visibilities.PROTECTED + visibilityModifiers.contains(VisibilityModifier.INTERNAL) -> Visibilities.INTERNAL + else -> Visibilities.UNKNOWN + } } fun hasTailrec(): Boolean { @@ -109,27 +116,43 @@ class Modifier( return propertyModifier == PropertyModifier.CONST } + fun hasModality(modality: Modality): Boolean { + return when { + modality == Modality.FINAL && inheritanceModifiers.contains(InheritanceModifier.FINAL) -> true + modality == Modality.SEALED && inheritanceModifiers.contains(InheritanceModifier.SEALED) -> true + modality == Modality.ABSTRACT && inheritanceModifiers.contains(InheritanceModifier.ABSTRACT) -> true + modality == Modality.OPEN && inheritanceModifiers.contains(InheritanceModifier.OPEN) -> true + else -> false + } + } + fun getModality(): Modality? { - return inheritanceModifier?.toModality() + return when { + inheritanceModifiers.contains(InheritanceModifier.FINAL) -> Modality.FINAL + inheritanceModifiers.contains(InheritanceModifier.SEALED) -> Modality.SEALED + inheritanceModifiers.contains(InheritanceModifier.ABSTRACT) -> Modality.ABSTRACT + inheritanceModifiers.contains(InheritanceModifier.OPEN) -> Modality.OPEN + else -> null + } } fun hasVararg(): Boolean { - return parameterModifier == ParameterModifier.VARARG + return parameterModifiers.contains(ParameterModifier.VARARG) } fun hasNoinline(): Boolean { - return parameterModifier == ParameterModifier.NOINLINE + return parameterModifiers.contains(ParameterModifier.NOINLINE) } fun hasCrossinline(): Boolean { - return parameterModifier == ParameterModifier.CROSSINLINE + return parameterModifiers.contains(ParameterModifier.CROSSINLINE) } fun hasExpect(): Boolean { - return platformModifier == PlatformModifier.EXPECT + return platformModifiers.contains(PlatformModifier.EXPECT) || platformModifiers.contains(PlatformModifier.HEADER) } fun hasActual(): Boolean { - return platformModifier == PlatformModifier.ACTUAL + return platformModifiers.contains(PlatformModifier.ACTUAL) || platformModifiers.contains(PlatformModifier.IMPL) } } diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/ModifierSets.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/ModifierSets.kt index 39947a4e7c6..2e2a9897410 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/ModifierSets.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/ModifierSets.kt @@ -41,7 +41,7 @@ object ModifierSets { SEALED_KEYWORD ) val PARAMETER_MODIFIER = TokenSet.create(VARARG_KEYWORD, NOINLINE_KEYWORD, CROSSINLINE_KEYWORD) - val PLATFORM_MODIFIER = TokenSet.create(EXPECT_KEYWORD, ACTUAL_KEYWORD) + val PLATFORM_MODIFIER = TokenSet.create(EXPECT_KEYWORD, ACTUAL_KEYWORD, HEADER_KEYWORD, IMPL_KEYWORD) val VARIANCE_MODIFIER = TokenSet.create(IN_KEYWORD, OUT_KEYWORD) val REIFICATION_MODIFIER = TokenSet.create(REIFIED_KEYWORD) } \ No newline at end of file diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/ModifiersEnumSet.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/ModifiersEnumSet.kt index b3d54443826..a2ea6374fb3 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/ModifiersEnumSet.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/ModifiersEnumSet.kt @@ -24,33 +24,11 @@ enum class MemberModifier { } enum class VisibilityModifier { - PUBLIC { - override fun toVisibility(): Visibility { - return Visibilities.PUBLIC - } - }, - PRIVATE { - override fun toVisibility(): Visibility { - return Visibilities.PRIVATE - } - }, - INTERNAL { - override fun toVisibility(): Visibility { - return Visibilities.INTERNAL - } - }, - PROTECTED { - override fun toVisibility(): Visibility { - return Visibilities.PROTECTED - } - }, - UNKNOWN { - override fun toVisibility(): Visibility { - return Visibilities.UNKNOWN - } - }; - - abstract fun toVisibility(): Visibility + PUBLIC, + PRIVATE, + INTERNAL, + PROTECTED, + UNKNOWN } enum class FunctionModifier { @@ -67,28 +45,10 @@ enum class PropertyModifier { } enum class InheritanceModifier { - ABSTRACT { - override fun toModality(): Modality { - return Modality.ABSTRACT - } - }, - FINAL { - override fun toModality(): Modality { - return Modality.FINAL - } - }, - OPEN { - override fun toModality(): Modality { - return Modality.OPEN - } - }, - SEALED { - override fun toModality(): Modality { - return Modality.SEALED - } - }; - - abstract fun toModality(): Modality + ABSTRACT, + FINAL, + OPEN, + SEALED } enum class ParameterModifier { @@ -99,27 +59,15 @@ enum class ParameterModifier { enum class PlatformModifier { EXPECT, - ACTUAL + ACTUAL, + HEADER, + IMPL } enum class VarianceModifier { - IN { - override fun toVariance(): Variance { - return Variance.IN_VARIANCE - } - }, - OUT { - override fun toVariance(): Variance { - return Variance.OUT_VARIANCE - } - }, - INVARIANT { - override fun toVariance(): Variance { - return Variance.INVARIANT - } - }; - - abstract fun toVariance(): Variance + IN, + OUT, + INVARIANT } enum class ReificationModifier { diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/TypeModifier.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/TypeModifier.kt index dc693169e08..931bf2b5947 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/TypeModifier.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/TypeModifier.kt @@ -22,4 +22,8 @@ class TypeModifier( KtTokens.SUSPEND_KEYWORD -> this.hasSuspend = true } } + + fun hasNoAnnotations(): Boolean { + return annotations.isEmpty() + } } diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/TypeParameterModifier.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/TypeParameterModifier.kt index c988ba12148..7a4463da11b 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/TypeParameterModifier.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/TypeParameterModifier.kt @@ -17,19 +17,24 @@ class TypeParameterModifier( session: FirSession, psi: PsiElement? = null, - private var varianceModifier: VarianceModifier = VarianceModifier.INVARIANT, + private val varianceModifiers: MutableList = mutableListOf(), private var reificationModifier: ReificationModifier? = null ) : FirAbstractAnnotatedElement(session, psi) { fun addModifier(modifier: LighterASTNode) { val tokenType = modifier.tokenType when { - VARIANCE_MODIFIER.contains(tokenType) -> this.varianceModifier = VarianceModifier.valueOf(modifier.toString().toUpperCase()) - REIFICATION_MODIFIER.contains(tokenType) -> this.reificationModifier = ReificationModifier.valueOf(modifier.toString().toUpperCase()) + VARIANCE_MODIFIER.contains(tokenType) -> this.varianceModifiers += VarianceModifier.valueOf(modifier.toString().toUpperCase()) + REIFICATION_MODIFIER.contains(tokenType) -> this.reificationModifier = + ReificationModifier.valueOf(modifier.toString().toUpperCase()) } } fun getVariance(): Variance { - return varianceModifier.toVariance() + return when { + varianceModifiers.contains(VarianceModifier.OUT) -> Variance.OUT_VARIANCE + varianceModifiers.contains(VarianceModifier.IN) -> Variance.IN_VARIANCE + else -> Variance.INVARIANT + } } fun hasReified(): Boolean { diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/TypeProjectionModifier.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/TypeProjectionModifier.kt index 5a79b5f6c07..e6e8d1becc0 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/TypeProjectionModifier.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/modifier/TypeProjectionModifier.kt @@ -16,16 +16,20 @@ class TypeProjectionModifier( session: FirSession, psi: PsiElement? = null, - private var varianceModifier: VarianceModifier = VarianceModifier.INVARIANT + private val varianceModifiers: MutableList = mutableListOf() ) : FirAbstractAnnotatedElement(session, psi) { fun addModifier(modifier: LighterASTNode) { val tokenType = modifier.tokenType when { - VARIANCE_MODIFIER.contains(tokenType) -> this.varianceModifier = VarianceModifier.valueOf(modifier.toString().toUpperCase()) + VARIANCE_MODIFIER.contains(tokenType) -> this.varianceModifiers += VarianceModifier.valueOf(modifier.toString().toUpperCase()) } } fun getVariance(): Variance { - return varianceModifier.toVariance() + return when { + varianceModifiers.contains(VarianceModifier.IN) -> Variance.IN_VARIANCE + varianceModifiers.contains(VarianceModifier.OUT) -> Variance.OUT_VARIANCE + else -> Variance.INVARIANT + } } } diff --git a/compiler/fir/lightTree/tests/org/jetbrains/kotlin/fir/lightTree/compare/TreesCompareTest.kt b/compiler/fir/lightTree/tests/org/jetbrains/kotlin/fir/lightTree/compare/TreesCompareTest.kt index 7e98e4ef30b..3105a265ba1 100644 --- a/compiler/fir/lightTree/tests/org/jetbrains/kotlin/fir/lightTree/compare/TreesCompareTest.kt +++ b/compiler/fir/lightTree/tests/org/jetbrains/kotlin/fir/lightTree/compare/TreesCompareTest.kt @@ -27,37 +27,56 @@ class TreesCompareTest : AbstractRawFirBuilderTestCase() { var counter = 0 var errorCounter = 0 + val onEachFile: (File) -> Unit = { file -> + if (!compareFir(file)) errorCounter++ + counter++ + } println("BASE PATH: $path") if (!withTestData) { - path.walkTopDown { file -> - if (!compareFir(file)) errorCounter++ - counter++ - } + path.walkTopDown(onEachFile) } else { - path.walkTopDownWithTestData { file -> - if (!compareFir(file)) errorCounter++ - counter++ - } + path.walkTopDownWithTestData(onEachFile) } println("All scanned files: $counter") println("Files that aren't equal to FIR: $errorCounter") TestCase.assertEquals(0, errorCounter) } - private fun compareAll(stubMode: Boolean, path: String = System.getProperty("user.dir"), withTestData: Boolean = false) { + private fun compareAll(stubMode: Boolean) { val lightTreeConverter = LightTree2Fir(stubMode, myProject) - compareBase(path, withTestData) { file -> + compareBase(System.getProperty("user.dir"), withTestData = false) { file -> val text = FileUtil.loadFile(file, CharsetToolkit.UTF8, true).trim() - //light tree - val firFileFromLightTree = lightTreeConverter.buildFirFile(text, file.name) - val treeFromLightTree = StringBuilder().also { FirRenderer(it).visitFile(firFileFromLightTree) }.toString() - //psi val ktFile = createPsiFile(FileUtil.getNameWithoutExtension(PathUtil.getFileName(file.path)), text) as KtFile val firFileFromPsi = ktFile.toFirFile(stubMode) val treeFromPsi = StringBuilder().also { FirRenderer(it).visitFile(firFileFromPsi) }.toString() + //light tree + val firFileFromLightTree = lightTreeConverter.buildFirFile(text, file.name) + val treeFromLightTree = StringBuilder().also { FirRenderer(it).visitFile(firFileFromLightTree) }.toString() + + return@compareBase treeFromLightTree == treeFromPsi + } + } + + fun testCompareDiagnostics() { + val lightTreeConverter = LightTree2Fir(false, myProject) + compareBase("compiler/testData/diagnostics/tests", withTestData = true) { file -> + val notEditedText = FileUtil.loadFile(file, CharsetToolkit.UTF8, true).trim() + val text = notEditedText.replace("()|()".toRegex(), "").replaceAfter(".java", "") + + //psi + val ktFile = createPsiFile(FileUtil.getNameWithoutExtension(PathUtil.getFileName(file.path)), text) as KtFile + val firFileFromPsi = ktFile.toFirFile(stubMode = false) + val treeFromPsi = StringBuilder().also { FirRenderer(it).visitFile(firFileFromPsi) }.toString() + .replace("".toRegex(), "") + + //light tree + val firFileFromLightTree = lightTreeConverter.buildFirFile(text, file.name) + val treeFromLightTree = StringBuilder().also { FirRenderer(it).visitFile(firFileFromLightTree) }.toString() + .replace("".toRegex(), "") + return@compareBase treeFromLightTree == treeFromPsi } } @@ -366,8 +385,4 @@ class TreesCompareTest : AbstractRawFirBuilderTestCase() { visitAnonymousObject = true ) } - - fun testDiagnostics() { - compareAll(false, "compiler/testData/diagnostics/tests", withTestData = true) - } }