From 3b2df7ade3f8cb3c7a44a2def98903023dfc6b15 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Tue, 1 Jun 2021 12:23:54 +0300 Subject: [PATCH] [FIR] Inherit `expect` modifier from outer classes --- .../converter/DeclarationsConverter.kt | 48 +++++++++++-------- .../kotlin/fir/builder/RawFirBuilder.kt | 46 ++++++++++-------- .../kotlin/fir/builder/BaseFirBuilder.kt | 4 ++ .../jetbrains/kotlin/fir/builder/Context.kt | 1 + .../RawFirNonLocalDeclarationBuilder.kt | 3 +- 5 files changed, 60 insertions(+), 42 deletions(-) diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt index 800c8fb1204..fae80d3ff2f 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt @@ -51,7 +51,6 @@ import org.jetbrains.kotlin.fir.types.impl.FirTypeArgumentListImpl import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.name.* -import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier import org.jetbrains.kotlin.utils.addToStdlib.runIf class DeclarationsConverter( @@ -403,13 +402,14 @@ class DeclarationsConverter( val className = identifier.nameAsSafeName(if (modifiers.isCompanion()) "Companion" else "") val isLocal = isClassLocal(classNode) { getParent() } + val classIsExpect = modifiers.hasExpect() || context.containerIsExpect - return withChildClassName(className, isLocal) { + return withChildClassName(className, isExpect = classIsExpect, isLocal) { val status = FirDeclarationStatusImpl( if (isLocal) Visibilities.Local else modifiers.getVisibility(), modifiers.getModality(isClassOrObject = true) ).apply { - isExpect = modifiers.hasExpect() + isExpect = classIsExpect isActual = modifiers.hasActual() isInner = modifiers.isInner() isCompanion = modifiers.isCompanion() && classKind == ClassKind.OBJECT @@ -489,7 +489,11 @@ class DeclarationsConverter( ) //parse primary constructor val primaryConstructorWrapper = convertPrimaryConstructor( - primaryConstructor, selfType.source, classWrapper, delegatedConstructorSource + primaryConstructor, + selfType.source, + classWrapper, + delegatedConstructorSource, + containingClassIsExpectClass = status.isExpect ) val firPrimaryConstructor = primaryConstructorWrapper?.firConstructor firPrimaryConstructor?.let { declarations += it } @@ -557,7 +561,7 @@ class DeclarationsConverter( * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitObjectLiteralExpression */ fun convertObjectLiteral(objectLiteral: LighterASTNode): FirElement { - return withChildClassName(ANONYMOUS_OBJECT_NAME) { + return withChildClassName(ANONYMOUS_OBJECT_NAME, isExpect = false) { buildAnonymousObjectExpression { val objectDeclaration = objectLiteral.getChildNodesByType(OBJECT_DECLARATION).first() val sourceElement = objectDeclaration.toFirSourceElement() @@ -619,7 +623,7 @@ class DeclarationsConverter( ) //parse primary constructor convertPrimaryConstructor( - primaryConstructor, delegatedSelfType.source, classWrapper, delegatedConstructorSource + primaryConstructor, delegatedSelfType.source, classWrapper, delegatedConstructorSource, containingClassIsExpectClass = false )?.let { this.declarations += it.firConstructor } delegateFields?.let { this.declarations += it } @@ -665,7 +669,7 @@ class DeclarationsConverter( symbol = FirEnumEntrySymbol(CallableId(context.currentClassId, enumEntryName)) status = FirDeclarationStatusImpl(Visibilities.Public, Modality.FINAL).apply { isStatic = true - isExpect = classWrapper.hasExpect() + isExpect = classWrapper.hasExpect() || context.containerIsExpect } if (classWrapper.hasDefaultConstructor && enumEntry.getChildNodeByType(INITIALIZER_LIST) == null && modifiers.annotations.isEmpty() && classBodyNode == null @@ -673,7 +677,7 @@ class DeclarationsConverter( return@buildEnumEntry } annotations += modifiers.annotations - initializer = withChildClassName(enumEntryName) { + initializer = withChildClassName(enumEntryName, isExpect = false) { buildAnonymousObjectExpression { val entrySource = enumEntry.toFirSourceElement(FirFakeSourceElementKind.EnumInitializer) source = entrySource @@ -705,11 +709,12 @@ class DeclarationsConverter( enumEntry.toFirSourceElement(), enumClassWrapper, superTypeCallEntry?.toFirSourceElement(), - isEnumEntry = true + isEnumEntry = true, + containingClassIsExpectClass = false )?.let { declarations += it.firConstructor } classBodyNode?.also { // Use ANONYMOUS_OBJECT_NAME for the owner class id of enum entry declarations - withChildClassName(ANONYMOUS_OBJECT_NAME, forceLocalContext = true) { + withChildClassName(ANONYMOUS_OBJECT_NAME, forceLocalContext = true, isExpect = false) { declarations += convertClassBody(it, enumClassWrapper) } } @@ -746,7 +751,7 @@ class DeclarationsConverter( when (node.tokenType) { ENUM_ENTRY -> container += convertEnumEntry(node, classWrapper) CLASS -> container += convertClass(node) - FUN -> container += convertFunctionDeclaration(node, classWrapper) as FirDeclaration + FUN -> container += convertFunctionDeclaration(node) as FirDeclaration PROPERTY -> container += convertPropertyDeclaration(node, classWrapper) TYPEALIAS -> container += convertTypeAlias(node) OBJECT_DECLARATION -> container += convertClass(node) @@ -765,11 +770,12 @@ class DeclarationsConverter( selfTypeSource: FirSourceElement?, classWrapper: ClassWrapper, delegatedConstructorSource: FirLightSourceElement?, - isEnumEntry: Boolean = false + isEnumEntry: Boolean = false, + containingClassIsExpectClass: Boolean ): PrimaryConstructor? { if (primaryConstructor == null && !classWrapper.isEnumEntry() && classWrapper.hasSecondaryConstructor) return null val classKind = classWrapper.classBuilder.classKind - if (primaryConstructor == null && (classWrapper.hasExpect() && classKind == ClassKind.ENUM_CLASS)) return null + if (primaryConstructor == null && (containingClassIsExpectClass && classKind != ClassKind.ENUM_CLASS)) return null if (classWrapper.isInterface()) return null var modifiers = Modifier() @@ -808,7 +814,7 @@ class DeclarationsConverter( modifiers.getVisibility().takeUnless { it == Visibilities.Unknown } } val status = FirDeclarationStatusImpl(explicitVisibility ?: defaultVisibility, Modality.FINAL).apply { - isExpect = modifiers.hasExpect() || classWrapper.hasExpect() + isExpect = modifiers.hasExpect() || context.containerIsExpect isActual = modifiers.hasActual() isInner = classWrapper.isInner() isFromSealedClass = classWrapper.isSealed() && explicitVisibility !== Visibilities.Private @@ -877,7 +883,7 @@ class DeclarationsConverter( val explicitVisibility = modifiers.getVisibility() val status = FirDeclarationStatusImpl(explicitVisibility, Modality.FINAL).apply { - isExpect = modifiers.hasExpect() || classWrapper.hasExpect() + isExpect = modifiers.hasExpect() || context.containerIsExpect isActual = modifiers.hasActual() isInner = classWrapper.isInner() isFromSealedClass = classWrapper.isSealed() && explicitVisibility !== Visibilities.Private @@ -976,7 +982,8 @@ class DeclarationsConverter( } val typeAliasName = identifier.nameAsSafeName() - return withChildClassName(typeAliasName) { + val typeAliasIsExpect = modifiers.hasExpect() || context.containerIsExpect + return withChildClassName(typeAliasName, isExpect = typeAliasIsExpect) { val classSymbol = FirTypeAliasSymbol(context.currentClassId) val firTypeParameters = mutableListOf() @@ -985,14 +992,13 @@ class DeclarationsConverter( firTypeParameters += convertTypeParameters(it, emptyList(), classSymbol) } } - return@withChildClassName buildTypeAlias { source = typeAlias.toFirSourceElement() moduleData = baseModuleData origin = FirDeclarationOrigin.Source name = typeAliasName status = FirDeclarationStatusImpl(modifiers.getVisibility(), Modality.FINAL).apply { - isExpect = modifiers.hasExpect() + isExpect = typeAliasIsExpect isActual = modifiers.hasActual() } symbol = classSymbol @@ -1128,7 +1134,7 @@ class DeclarationsConverter( } else null status = FirDeclarationStatusImpl(propertyVisibility, modifiers.getModality(isClassOrObject = false)).apply { - isExpect = modifiers.hasExpect() || classWrapper?.hasExpect() == true + isExpect = modifiers.hasExpect() || context.containerIsExpect isActual = modifiers.hasActual() isOverride = modifiers.hasOverride() isConst = modifiers.isConst() @@ -1366,7 +1372,7 @@ class DeclarationsConverter( /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseFunction */ - fun convertFunctionDeclaration(functionDeclaration: LighterASTNode, classWrapper: ClassWrapper? = null): FirStatement { + fun convertFunctionDeclaration(functionDeclaration: LighterASTNode): FirStatement { var modifiers = Modifier() var identifier: String? = null var valueParametersList: LighterASTNode? = null @@ -1429,7 +1435,7 @@ class DeclarationsConverter( if (isLocal) Visibilities.Local else modifiers.getVisibility(), modifiers.getModality(isClassOrObject = false) ).apply { - isExpect = modifiers.hasExpect() || classWrapper?.hasExpect() == true + isExpect = modifiers.hasExpect() || context.containerIsExpect isActual = modifiers.hasActual() isOverride = modifiers.hasOverride() isOperator = modifiers.hasOperator() diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index 64f46eb81e4..4eb46ca57af 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -462,11 +462,11 @@ open class RawFirBuilder( } } - private fun KtParameter.toFirProperty(firParameter: FirValueParameter, isExpect: Boolean): FirProperty { + private fun KtParameter.toFirProperty(firParameter: FirValueParameter): FirProperty { require(hasValOrVar()) val type = typeReference.toFirOrErrorType() val status = FirDeclarationStatusImpl(visibility, modality).apply { - this.isExpect = isExpect + isExpect = hasExpectModifier() || this@RawFirBuilder.context.containerIsExpect isActual = hasActualModifier() isOverride = hasModifier(OVERRIDE_KEYWORD) isConst = hasModifier(CONST_KEYWORD) @@ -630,7 +630,8 @@ open class RawFirBuilder( delegatedSelfTypeRef: FirTypeRef?, delegatedEnumSuperTypeRef: FirTypeRef?, classKind: ClassKind, - containerTypeParameters: List + containerTypeParameters: List, + containingClassIsExpectClass: Boolean ): FirTypeRef { var superTypeCallEntry: KtSuperTypeCallEntry? = null var delegatedSuperTypeRef: FirTypeRef? = null @@ -708,7 +709,7 @@ open class RawFirBuilder( // it may be not possible to determine delegated super type right here delegatedSuperTypeRef = delegatedSuperTypeRef ?: defaultDelegatedSuperTypeRef val shouldNotGenerateImplicitPrimaryConstructor = hasExplicitPrimaryConstructor() || hasSecondaryConstructors() || - (hasExpectModifier() && classKind != ClassKind.ENUM_CLASS) + (containingClassIsExpectClass && classKind != ClassKind.ENUM_CLASS) if ((this !is KtClass || !this.isInterface()) && (primaryConstructor != null || !shouldNotGenerateImplicitPrimaryConstructor)) { val firPrimaryConstructor = primaryConstructor.toFirConstructor( @@ -759,7 +760,7 @@ open class RawFirBuilder( val explicitVisibility = this?.visibility?.takeUnless { it == Visibilities.Unknown } val status = FirDeclarationStatusImpl(explicitVisibility ?: defaultVisibility(), Modality.FINAL).apply { - isExpect = this@toFirConstructor?.hasExpectModifier() == true || owner.hasExpectModifier() + isExpect = this@toFirConstructor?.hasExpectModifier() == true || this@RawFirBuilder.context.containerIsExpect isActual = this@toFirConstructor?.hasActualModifier() == true isInner = owner.hasModifier(INNER_KEYWORD) isFromSealedClass = owner.hasModifier(SEALED_KEYWORD) && explicitVisibility !== Visibilities.Private @@ -823,7 +824,7 @@ open class RawFirBuilder( name = nameAsSafeName status = FirDeclarationStatusImpl(Visibilities.Public, Modality.FINAL).apply { isStatic = true - isExpect = containingClassOrObject?.hasExpectModifier() == true + isExpect = hasExpectModifier() || this@RawFirBuilder.context.containerIsExpect } symbol = FirEnumEntrySymbol(callableIdForName(nameAsSafeName)) if (ownerClassHasDefaultConstructor && ktEnumEntry.initializerList == null && @@ -832,7 +833,7 @@ open class RawFirBuilder( return@buildEnumEntry } extractAnnotationsTo(this) - initializer = withChildClassName(nameAsSafeName) { + initializer = withChildClassName(nameAsSafeName, isExpect = false) { buildAnonymousObjectExpression { val enumEntrySource = toFirSourceElement(FirFakeSourceElementKind.EnumInitializer) source = enumEntrySource @@ -864,7 +865,7 @@ open class RawFirBuilder( typeParameters ) // Use ANONYMOUS_OBJECT_NAME for the owner class id for enum entry declarations (see KT-42351) - withChildClassName(ANONYMOUS_OBJECT_NAME, forceLocalContext = true) { + withChildClassName(ANONYMOUS_OBJECT_NAME, forceLocalContext = true, isExpect = false) { for (declaration in ktEnumEntry.declarations) { declarations += declaration.toFirDeclaration( correctedEnumSelfTypeRef, @@ -892,8 +893,10 @@ open class RawFirBuilder( override fun visitClassOrObject(classOrObject: KtClassOrObject, data: Unit): FirElement { // NB: enum entry nested classes are considered local by FIR design (see discussion in KT-45115) val isLocal = classOrObject.isLocal || classOrObject.getStrictParentOfType() != null + val classIsExpect = classOrObject.hasExpectModifier() || context.containerIsExpect return withChildClassName( classOrObject.nameAsSafeName, + isExpect = classIsExpect, forceLocalContext = isLocal ) { val classKind = when (classOrObject) { @@ -910,7 +913,7 @@ open class RawFirBuilder( if (isLocal) Visibilities.Local else classOrObject.visibility, classOrObject.modality, ).apply { - isExpect = classOrObject.hasExpectModifier() + isExpect = classIsExpect isActual = classOrObject.hasActualModifier() isInner = classOrObject.hasModifier(INNER_KEYWORD) isCompanion = (classOrObject as? KtObjectDeclaration)?.isCompanion() == true @@ -950,7 +953,8 @@ open class RawFirBuilder( delegatedSelfType, null, classKind, - typeParameters + typeParameters, + containingClassIsExpectClass = classIsExpect ) val primaryConstructor = classOrObject.primaryConstructor @@ -960,7 +964,7 @@ open class RawFirBuilder( firPrimaryConstructor.valueParameters ).forEach { (ktParameter, firParameter) -> if (ktParameter.hasValOrVar()) { - addDeclaration(ktParameter.toFirProperty(firParameter, classOrObject.hasExpectModifier())) + addDeclaration(ktParameter.toFirProperty(firParameter)) } } } @@ -1002,11 +1006,11 @@ open class RawFirBuilder( baseModuleData, context.packageFqName, context.className, - classOrObject.hasExpectModifier() + classIsExpect ) generateValueOfFunction( baseModuleData, context.packageFqName, context.className, - classOrObject.hasExpectModifier() + classIsExpect ) } @@ -1021,7 +1025,7 @@ open class RawFirBuilder( override fun visitObjectLiteralExpression(expression: KtObjectLiteralExpression, data: Unit): FirElement { val objectDeclaration = expression.objectDeclaration - return withChildClassName(ANONYMOUS_OBJECT_NAME, forceLocalContext = true) { + return withChildClassName(ANONYMOUS_OBJECT_NAME, forceLocalContext = true, isExpect = false) { buildAnonymousObjectExpression { val sourceElement = objectDeclaration.toFirSourceElement() source = sourceElement @@ -1043,7 +1047,8 @@ open class RawFirBuilder( delegatedSelfType, null, ClassKind.CLASS, - containerTypeParameters = emptyList() + containerTypeParameters = emptyList(), + containingClassIsExpectClass = false ) for (declaration in objectDeclaration.declarations) { @@ -1061,14 +1066,15 @@ open class RawFirBuilder( } override fun visitTypeAlias(typeAlias: KtTypeAlias, data: Unit): FirElement { - return withChildClassName(typeAlias.nameAsSafeName) { + val typeAliasIsExpect = typeAlias.hasExpectModifier() || context.containerIsExpect + return withChildClassName(typeAlias.nameAsSafeName, isExpect = typeAliasIsExpect) { buildTypeAlias { source = typeAlias.toFirSourceElement() moduleData = baseModuleData origin = FirDeclarationOrigin.Source name = typeAlias.nameAsSafeName status = FirDeclarationStatusImpl(typeAlias.visibility, Modality.FINAL).apply { - isExpect = typeAlias.hasExpectModifier() + isExpect = typeAliasIsExpect isActual = typeAlias.hasActualModifier() } symbol = FirTypeAliasSymbol(context.currentClassId) @@ -1108,7 +1114,7 @@ open class RawFirBuilder( if (function.isLocal) Visibilities.Local else function.visibility, function.modality, ).apply { - isExpect = function.hasExpectModifier() || function.containingClassOrObject?.hasExpectModifier() == true + isExpect = function.hasExpectModifier() || context.containerIsExpect isActual = function.hasActualModifier() isOverride = function.hasModifier(OVERRIDE_KEYWORD) isOperator = function.hasModifier(OPERATOR_KEYWORD) @@ -1293,7 +1299,7 @@ open class RawFirBuilder( returnTypeRef = delegatedSelfTypeRef val explicitVisibility = visibility status = FirDeclarationStatusImpl(explicitVisibility, Modality.FINAL).apply { - isExpect = hasExpectModifier() || owner.hasExpectModifier() + isExpect = hasExpectModifier() || this@RawFirBuilder.context.containerIsExpect isActual = hasActualModifier() isInner = owner.hasModifier(INNER_KEYWORD) isFromSealedClass = owner.hasModifier(SEALED_KEYWORD) && explicitVisibility !== Visibilities.Private @@ -1436,7 +1442,7 @@ open class RawFirBuilder( setter = this@toFirProperty.setter.toFirPropertyAccessor(this@toFirProperty, propertyType, isGetter = false) status = FirDeclarationStatusImpl(visibility, modality).apply { - isExpect = hasExpectModifier() || containingClassOrObject?.hasExpectModifier() == true + isExpect = hasExpectModifier() || this@RawFirBuilder.context.containerIsExpect isActual = hasActualModifier() isOverride = hasModifier(OVERRIDE_KEYWORD) isConst = hasModifier(CONST_KEYWORD) diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt index 01d10e84743..df2f8209607 100644 --- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt @@ -66,12 +66,15 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte /**** Class name utils ****/ inline fun withChildClassName( name: Name, + isExpect: Boolean, forceLocalContext: Boolean = false, l: () -> T ): T { context.className = context.className.child(name) val oldForcedLocalContext = context.forcedLocalContext context.forcedLocalContext = forceLocalContext || context.forcedLocalContext + val previousIsExpect = context.containerIsExpect + context.containerIsExpect = previousIsExpect || isExpect val dispatchReceiversNumber = context.dispatchReceiverTypesStack.size return try { l() @@ -86,6 +89,7 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte context.className = context.className.parent() context.forcedLocalContext = oldForcedLocalContext + context.containerIsExpect = previousIsExpect } } diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/Context.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/Context.kt index e67f1a1f14f..170ca879a48 100644 --- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/Context.kt +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/Context.kt @@ -33,6 +33,7 @@ class Context { var forcedElementSourceKind: FirSourceElementKind? = null val dispatchReceiverTypesStack = mutableListOf() + var containerIsExpect: Boolean = false fun pushFirTypeParameters(notNested: Boolean, parameters: List) { capturedTypeParameters.add(StatusFirTypeParameterSymbolList(notNested, parameters.map { it.symbol })) diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/RawFirNonLocalDeclarationBuilder.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/RawFirNonLocalDeclarationBuilder.kt index 5f28818250e..97f1b41f51c 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/RawFirNonLocalDeclarationBuilder.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/RawFirNonLocalDeclarationBuilder.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignation import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier internal class RawFirNonLocalDeclarationBuilder private constructor( session: FirSession, @@ -123,7 +124,7 @@ internal class RawFirNonLocalDeclarationBuilder private constructor( val classOrObject = parent.psi check(classOrObject is KtClassOrObject) - withChildClassName(classOrObject.nameAsSafeName, false) { + withChildClassName(classOrObject.nameAsSafeName, isExpect = classOrObject.hasExpectModifier() || context.containerIsExpect) { withCapturedTypeParameters(parent.isInner, parent.typeParameters.subList(0, classOrObject.typeParameters.size)) { registerSelfType(classOrObject.toDelegatedSelfType(parent)) return moveNext(iterator, parent)