From c1609ed490c414719a2a22679b0e072ac7d64fde Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 24 Jun 2020 15:25:52 +0300 Subject: [PATCH] [FIR] Make expect class members also expect --- .../resolve/multifile/simpleStarImport.txt | 2 +- .../multiModule/FakeOverrides.txt | 4 +-- .../multiModule/MemberType.txt | 4 +-- .../resolveWithStdlib/multiModule/Members.kt | 6 ++++ .../resolveWithStdlib/multiModule/Members.txt | 12 ++++++-- .../multiModule/SuperTypes.txt | 4 +-- .../fir/backend/Fir2IrDeclarationStorage.kt | 2 +- .../generators/ClassMemberGenerator.kt | 4 +-- .../generators/FakeOverrideGenerator.kt | 8 ++++-- .../converter/DeclarationsConverter.kt | 19 +++++++------ .../kotlin/fir/lightTree/fir/ClassWrapper.kt | 5 +++- .../fir/lightTree/fir/ValueParameter.kt | 4 +-- .../kotlin/fir/builder/RawFirBuilder.kt | 28 +++++++++++-------- .../rawBuilder/declarations/expectActual.txt | 2 +- .../scopes/impl/FirClassSubstitutionScope.kt | 26 +++++++++++++---- .../jetbrains/kotlin/fir/EnumClassUtils.kt | 10 +++++-- .../org/jetbrains/kotlin/fir/FirRenderer.kt | 9 +++++- .../expectClassInherited.fir.txt | 28 ++++++++----------- .../multiplatform/expectedEnumClass.fir.txt | 10 ++----- .../multiplatform/expectedSealedClass.fir.txt | 22 ++++++--------- 20 files changed, 124 insertions(+), 85 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/resolve/multifile/simpleStarImport.txt b/compiler/fir/analysis-tests/testData/resolve/multifile/simpleStarImport.txt index b4ee96b6861..0da7210adf1 100644 --- a/compiler/fir/analysis-tests/testData/resolve/multifile/simpleStarImport.txt +++ b/compiler/fir/analysis-tests/testData/resolve/multifile/simpleStarImport.txt @@ -2,7 +2,7 @@ FILE: B.kt public abstract expect interface Other : R|kotlin/Any| { } public final expect class Another : R|kotlin/Any| { - public constructor(): R|b/d/Another| { + public expect constructor(): R|b/d/Another| { super() } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.txt index e7459dd83ed..c6791a68568 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/FakeOverrides.txt @@ -1,10 +1,10 @@ FILE: common.kt public open expect class A : R|kotlin/Any| { - public constructor(): R|A| { + public expect constructor(): R|A| { super() } - public open fun foo(arg: R|T|): R|kotlin/Unit| + public open expect fun foo(arg: R|T|): R|kotlin/Unit| } public open class B : R|A| { diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.txt index 36a25e3079a..40613912c09 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/MemberType.txt @@ -1,10 +1,10 @@ FILE: common.kt public final expect class MyList : R|kotlin/Any| { - public constructor(): R|MyList| { + public expect constructor(): R|MyList| { super() } - public final fun get(i: R|kotlin/Int|): R|kotlin/Int| + public final expect fun get(i: R|kotlin/Int|): R|kotlin/Int| } public open class Wrapper : R|kotlin/Any| { diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.kt index bee90651ef6..f978266a1f5 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.kt @@ -4,6 +4,8 @@ expect open class A() { fun foo() + + val x: Int } open class B : A() @@ -15,12 +17,15 @@ actual open class A { actual fun foo() {} fun bar() {} + + actual val x = 42 } class C : B() { fun test() { foo() bar() + x + x } } @@ -28,5 +33,6 @@ class D : A() { fun test() { foo() bar() + x + x } } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.txt index 0e65433b8a6..902141ba54a 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/Members.txt @@ -1,10 +1,13 @@ FILE: common.kt public open expect class A : R|kotlin/Any| { - public constructor(): R|A| { + public expect constructor(): R|A| { super() } - public final fun foo(): R|kotlin/Unit| + public final expect fun foo(): R|kotlin/Unit| + + public final expect val x: R|kotlin/Int| + public get(): R|kotlin/Int| } public open class B : R|A| { @@ -25,6 +28,9 @@ FILE: jvm.kt public final fun bar(): R|kotlin/Unit| { } + public final actual val x: R|kotlin/Int| = Int(42) + public get(): R|kotlin/Int| + } public final class C : R|B| { public constructor(): R|C| { @@ -34,6 +40,7 @@ FILE: jvm.kt public final fun test(): R|kotlin/Unit| { this@R|/C|.R|/A.foo|() this@R|/C|.R|/A.bar|() + this@R|/C|.R|/A.x|.R|kotlin/Int.plus|(this@R|/C|.R|/A.x|) } } @@ -45,6 +52,7 @@ FILE: jvm.kt public final fun test(): R|kotlin/Unit| { this@R|/D|.R|/A.foo|() this@R|/D|.R|/A.bar|() + this@R|/D|.R|/A.x|.R|kotlin/Int.plus|(this@R|/D|.R|/A.x|) } } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/SuperTypes.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/SuperTypes.txt index 4e67881f9dc..d011977dbb4 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/SuperTypes.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/multiModule/SuperTypes.txt @@ -1,10 +1,10 @@ FILE: common.kt public open expect class A : R|kotlin/Any| { - public constructor(): R|A| { + public expect constructor(): R|A| { super() } - public final fun foo(): R|kotlin/Unit| + public final expect fun foo(): R|kotlin/Unit| } public open class B : R|A| { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt index 568ec3ce490..d7b43a937ec 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt @@ -465,7 +465,7 @@ class Fir2IrDeclarationStorage( startOffset, endOffset, origin, symbol, Name.special(""), constructor.visibility, constructor.returnTypeRef.toIrType(), - isInline = false, isExternal = false, isPrimary = isPrimary, isExpect = false + isInline = false, isExternal = false, isPrimary = isPrimary, isExpect = constructor.isExpect ).apply { metadata = FirMetadataSource.Function(constructor) enterScope(this) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt index daf76abf455..4f2ac29e530 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt @@ -109,7 +109,7 @@ internal class ClassMemberGenerator( } annotationGenerator.generate(irFunction, firFunction) } - if (firFunction is FirConstructor && irFunction is IrConstructor && !parentAsClass.isAnnotationClass) { + if (firFunction is FirConstructor && irFunction is IrConstructor && !parentAsClass.isAnnotationClass && !firFunction.isExpect) { val body = IrBlockBodyImpl(startOffset, endOffset) val delegatedConstructor = firFunction.delegatedConstructor if (delegatedConstructor != null) { @@ -129,7 +129,7 @@ internal class ClassMemberGenerator( if (body.statements.isNotEmpty()) { irFunction.body = body } - } else if (irFunction !is IrConstructor) { + } else if (irFunction !is IrConstructor && !irFunction.isExpect) { when { irFunction.origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER -> { val kind = Fir2IrDeclarationStorage.ENUM_SYNTHETIC_NAMES.getValue(irFunction.name) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt index 6a2ecf3ba44..5ccac2d3b97 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/FakeOverrideGenerator.kt @@ -95,7 +95,9 @@ class FakeOverrideGenerator( } else if (fakeOverrideMode != FakeOverrideMode.SUBSTITUTION && originalFunction.allowsToHaveFakeOverrideIn(klass)) { // Trivial fake override case val fakeOverrideSymbol = FirClassSubstitutionScope.createFakeOverrideFunction( - session, originalFunction, baseSymbol, derivedClassId = klass.symbol.classId + session, originalFunction, baseSymbol, + derivedClassId = klass.symbol.classId, + isExpect = (klass as? FirRegularClass)?.isExpect == true ) val fakeOverrideFunction = fakeOverrideSymbol.fir @@ -137,7 +139,9 @@ class FakeOverrideGenerator( } else if (fakeOverrideMode != FakeOverrideMode.SUBSTITUTION && originalProperty.allowsToHaveFakeOverrideIn(klass)) { // Trivial fake override case val fakeOverrideSymbol = FirClassSubstitutionScope.createFakeOverrideProperty( - session, originalProperty, baseSymbol, derivedClassId = klass.symbol.classId + session, originalProperty, baseSymbol, + derivedClassId = klass.symbol.classId, + isExpect = (klass as? FirRegularClass)?.isExpect == true ) val fakeOverrideProperty = fakeOverrideSymbol.fir 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 d92424a7b17..cd06871b4cc 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 @@ -458,7 +458,7 @@ class DeclarationsConverter( //parse properties properties += primaryConstructorWrapper.valueParameters .filter { it.hasValOrVar() } - .map { it.toFirProperty(baseSession, callableIdForName(it.firValueParameter.name)) } + .map { it.toFirProperty(baseSession, callableIdForName(it.firValueParameter.name), classWrapper.hasExpect()) } addDeclarations(properties) } @@ -482,8 +482,8 @@ class DeclarationsConverter( } if (modifiers.isEnum()) { - generateValuesFunction(baseSession, context.packageFqName, context.className) - generateValueOfFunction(baseSession, context.packageFqName, context.className) + generateValuesFunction(baseSession, context.packageFqName, context.className, modifiers.hasExpect()) + generateValueOfFunction(baseSession, context.packageFqName, context.className, modifiers.hasExpect()) } } } @@ -584,6 +584,7 @@ class DeclarationsConverter( symbol = FirVariableSymbol(CallableId(context.currentClassId, enumEntryName)) status = FirDeclarationStatusImpl(Visibilities.PUBLIC, Modality.FINAL).apply { isStatic = true + isExpect = classWrapper.hasExpect() } if (classWrapper.hasDefaultConstructor && enumEntry.getChildNodeByType(INITIALIZER_LIST) == null && modifiers.annotations.isEmpty() && classBodyNode == null @@ -647,7 +648,7 @@ class DeclarationsConverter( when (node.tokenType) { ENUM_ENTRY -> container += convertEnumEntry(node, classWrapper) CLASS -> container += convertClass(node) - FUN -> container += convertFunctionDeclaration(node) + FUN -> container += convertFunctionDeclaration(node, classWrapper) PROPERTY -> container += convertPropertyDeclaration(node, classWrapper) TYPEALIAS -> container += convertTypeAlias(node) OBJECT_DECLARATION -> container += convertClass(node) @@ -688,7 +689,7 @@ class DeclarationsConverter( val explicitVisibility = if (primaryConstructor != null) modifiers.getVisibility() else null val status = FirDeclarationStatusImpl(explicitVisibility ?: defaultVisibility, Modality.FINAL).apply { - isExpect = modifiers.hasExpect() + isExpect = modifiers.hasExpect() || classWrapper.hasExpect() isActual = modifiers.hasActual() isInner = classWrapper.isInner() isFromSealedClass = classWrapper.isSealed() && explicitVisibility !== Visibilities.PRIVATE @@ -753,7 +754,7 @@ class DeclarationsConverter( val explicitVisibility = modifiers.getVisibility() val status = FirDeclarationStatusImpl(explicitVisibility, Modality.FINAL).apply { - isExpect = modifiers.hasExpect() + isExpect = modifiers.hasExpect() || classWrapper.hasExpect() isActual = modifiers.hasActual() isInner = classWrapper.isInner() isFromSealedClass = classWrapper.isSealed() && explicitVisibility !== Visibilities.PRIVATE @@ -955,7 +956,7 @@ class DeclarationsConverter( // Note that, depending on `var` or `val`, checking setter's modifiers should be careful: for `val`, setter doesn't // exist (null); for `var`, the retrieval of the specific modifier is supposed to be `true` status = FirDeclarationStatusImpl(propertyVisibility, modifiers.getModality()).apply { - isExpect = modifiers.hasExpect() + isExpect = modifiers.hasExpect() || classWrapper?.hasExpect() == true isActual = modifiers.hasActual() isOverride = modifiers.hasOverride() isConst = modifiers.isConst() @@ -1150,7 +1151,7 @@ class DeclarationsConverter( /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseFunction */ - fun convertFunctionDeclaration(functionDeclaration: LighterASTNode): FirDeclaration { + fun convertFunctionDeclaration(functionDeclaration: LighterASTNode, classWrapper: ClassWrapper? = null): FirDeclaration { var modifiers = Modifier() var identifier: String? = null val firTypeParameters = mutableListOf() @@ -1208,7 +1209,7 @@ class DeclarationsConverter( if (isLocal) Visibilities.LOCAL else modifiers.getVisibility(), modifiers.getModality() ).apply { - isExpect = modifiers.hasExpect() + isExpect = modifiers.hasExpect() || classWrapper?.hasExpect() == true isActual = modifiers.hasActual() isOverride = modifiers.hasOverride() isOperator = modifiers.hasOperator() diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ClassWrapper.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ClassWrapper.kt index 696e88b8782..b53d635a56c 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ClassWrapper.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ClassWrapper.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.declarations.builder.FirClassBuilder import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.lightTree.fir.modifier.Modifier -import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames @@ -57,6 +56,10 @@ class ClassWrapper( return modifiers.isInner() } + fun hasExpect(): Boolean { + return modifiers.hasExpect() + } + // See DescriptorUtils#getDefaultConstructorVisibility in core.descriptors fun defaultConstructorVisibility(): Visibility { return when { diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt index 44dd6d10efa..d3a8cf560af 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt @@ -35,7 +35,7 @@ class ValueParameter( return isVal || isVar } - fun toFirProperty(session: FirSession, callableId: CallableId): FirProperty { + fun toFirProperty(session: FirSession, callableId: CallableId, isExpect: Boolean): FirProperty { val name = this.firValueParameter.name var type = this.firValueParameter.returnTypeRef if (type is FirImplicitTypeRef) { @@ -58,7 +58,7 @@ class ValueParameter( symbol = FirPropertySymbol(callableId) isLocal = false status = FirDeclarationStatusImpl(modifiers.getVisibility(), modifiers.getModality()).apply { - isExpect = modifiers.hasExpect() + this.isExpect = isExpect isActual = modifiers.hasActual() isOverride = modifiers.hasOverride() isConst = false 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 08e74664f53..5c0f311c42c 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 @@ -38,6 +38,7 @@ import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier @@ -348,11 +349,11 @@ class RawFirBuilder( } } - private fun KtParameter.toFirProperty(firParameter: FirValueParameter): FirProperty { + private fun KtParameter.toFirProperty(firParameter: FirValueParameter, isExpect: Boolean): FirProperty { require(hasValOrVar()) - var type = typeReference.toFirOrErrorType() + val type = typeReference.toFirOrErrorType() val status = FirDeclarationStatusImpl(visibility, modality).apply { - isExpect = hasExpectModifier() + this.isExpect = isExpect isActual = hasActualModifier() isOverride = hasModifier(OVERRIDE_KEYWORD) isConst = false @@ -554,8 +555,8 @@ class RawFirBuilder( val explicitVisibility = this?.visibility val status = FirDeclarationStatusImpl(explicitVisibility ?: defaultVisibility(), Modality.FINAL).apply { - isExpect = this@toFirConstructor?.hasExpectModifier() ?: false - isActual = this@toFirConstructor?.hasActualModifier() ?: false + isExpect = this@toFirConstructor?.hasExpectModifier() == true || owner.hasExpectModifier() + isActual = this@toFirConstructor?.hasActualModifier() == true isInner = owner.hasModifier(INNER_KEYWORD) isFromSealedClass = owner.hasModifier(SEALED_KEYWORD) && explicitVisibility !== Visibilities.PRIVATE isFromEnumClass = owner.hasModifier(ENUM_KEYWORD) @@ -612,6 +613,7 @@ class RawFirBuilder( name = nameAsSafeName status = FirDeclarationStatusImpl(Visibilities.PUBLIC, Modality.FINAL).apply { isStatic = true + isExpect = containingClassOrObject?.hasExpectModifier() == true } symbol = FirVariableSymbol(callableIdForName(nameAsSafeName)) // NB: not sure should annotations be on enum entry itself, or on its corresponding object @@ -718,7 +720,7 @@ class RawFirBuilder( firPrimaryConstructor.valueParameters ).forEach { (ktParameter, firParameter) -> if (ktParameter.hasValOrVar()) { - addDeclaration(ktParameter.toFirProperty(firParameter)) + addDeclaration(ktParameter.toFirProperty(firParameter, classOrObject.hasExpectModifier())) } } } @@ -751,8 +753,12 @@ class RawFirBuilder( } if (classOrObject.hasModifier(ENUM_KEYWORD)) { - generateValuesFunction(baseSession, context.packageFqName, context.className) - generateValueOfFunction(baseSession, context.packageFqName, context.className) + generateValuesFunction( + baseSession, context.packageFqName, context.className, classOrObject.hasExpectModifier() + ) + generateValueOfFunction( + baseSession, context.packageFqName, context.className, classOrObject.hasExpectModifier() + ) } } } @@ -843,7 +849,7 @@ class RawFirBuilder( if (function.isLocal) Visibilities.LOCAL else function.visibility, function.modality, ).apply { - isExpect = function.hasExpectModifier() + isExpect = function.hasExpectModifier() || function.containingClassOrObject?.hasExpectModifier() == true isActual = function.hasActualModifier() isOverride = function.hasModifier(OVERRIDE_KEYWORD) isOperator = function.hasModifier(OPERATOR_KEYWORD) @@ -994,7 +1000,7 @@ class RawFirBuilder( returnTypeRef = delegatedSelfTypeRef val explicitVisibility = visibility status = FirDeclarationStatusImpl(explicitVisibility, Modality.FINAL).apply { - isExpect = hasExpectModifier() + isExpect = hasExpectModifier() || owner.hasExpectModifier() isActual = hasActualModifier() isInner = owner.hasModifier(INNER_KEYWORD) isFromSealedClass = owner.hasModifier(SEALED_KEYWORD) && explicitVisibility !== Visibilities.PRIVATE @@ -1098,7 +1104,7 @@ class RawFirBuilder( // Note that, depending on `var` or `val`, checking setter's modifiers should be careful: for `val`, setter doesn't // exist (null); for `var`, the retrieval of the specific modifier is supposed to be `true` status = FirDeclarationStatusImpl(visibility, modality).apply { - isExpect = hasExpectModifier() + isExpect = hasExpectModifier() || containingClassOrObject?.hasExpectModifier() == true isActual = hasActualModifier() isOverride = hasModifier(OVERRIDE_KEYWORD) isConst = hasModifier(CONST_KEYWORD) diff --git a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/expectActual.txt b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/expectActual.txt index e6c02a95fc6..1bf748afb05 100644 --- a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/expectActual.txt +++ b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/expectActual.txt @@ -1,6 +1,6 @@ FILE: expectActual.kt public? final? expect class MyClass : R|kotlin/Any| { - public? constructor(): R|MyClass| { + public? expect constructor(): R|MyClass| { super() } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt index b86ff9dd3df..b38740aad99 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassSubstitutionScope.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.builder.* import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl +import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty import org.jetbrains.kotlin.fir.resolve.ScopeSession @@ -323,6 +324,16 @@ class FirClassSubstitutionScope( } } + private fun FirDeclarationStatus.withExpect(isExpect: Boolean): FirDeclarationStatus { + return if (this.isExpect == isExpect) { + this + } else { + FirResolvedDeclarationStatusImpl(visibility, effectiveVisibility, modality!!).apply { + this.isExpect = isExpect + } + } + } + private fun createFakeOverrideFunction( fakeOverrideSymbol: FirFunctionSymbol, session: FirSession, @@ -330,7 +341,8 @@ class FirClassSubstitutionScope( newReceiverType: ConeKotlinType? = null, newReturnType: ConeKotlinType? = null, newParameterTypes: List? = null, - newTypeParameters: List? = null + newTypeParameters: List? = null, + isExpect: Boolean = baseFunction.isExpect ): FirSimpleFunction { // TODO: consider using here some light-weight functions instead of pseudo-real FirMemberFunctionImpl // As second alternative, we can invent some light-weight kind of FirRegularClass @@ -342,7 +354,7 @@ class FirClassSubstitutionScope( returnTypeRef = baseFunction.returnTypeRef.withReplacedReturnType(newReturnType) receiverTypeRef = baseFunction.receiverTypeRef?.withReplacedConeType(newReceiverType) name = baseFunction.name - status = baseFunction.status.withLocalEffectiveVisibility(isLocal) + status = baseFunction.status.withLocalEffectiveVisibility(isLocal).withExpect(isExpect) symbol = fakeOverrideSymbol resolvePhase = baseFunction.resolvePhase configureAnnotationsAndParameters(session, baseFunction, newParameterTypes) @@ -365,14 +377,15 @@ class FirClassSubstitutionScope( newReturnType: ConeKotlinType? = null, newParameterTypes: List? = null, newTypeParameters: List? = null, - derivedClassId: ClassId? = null + derivedClassId: ClassId? = null, + isExpect: Boolean = baseFunction.isExpect ): FirNamedFunctionSymbol { val symbol = FirNamedFunctionSymbol( CallableId(derivedClassId ?: baseSymbol.callableId.classId!!, baseFunction.name), isFakeOverride = true, overriddenSymbol = baseSymbol ) createFakeOverrideFunction( - symbol, session, baseFunction, newReceiverType, newReturnType, newParameterTypes, newTypeParameters + symbol, session, baseFunction, newReceiverType, newReturnType, newParameterTypes, newTypeParameters, isExpect ) return symbol } @@ -384,7 +397,8 @@ class FirClassSubstitutionScope( newReceiverType: ConeKotlinType? = null, newReturnType: ConeKotlinType? = null, newTypeParameters: List? = null, - derivedClassId: ClassId? = null + derivedClassId: ClassId? = null, + isExpect: Boolean = baseProperty.isExpect ): FirPropertySymbol { val symbol = FirPropertySymbol( CallableId(derivedClassId ?: baseSymbol.callableId.classId!!, baseProperty.name), @@ -400,7 +414,7 @@ class FirClassSubstitutionScope( isVar = baseProperty.isVar this.symbol = symbol isLocal = false - status = baseProperty.status.withLocalEffectiveVisibility(isLocal) + status = baseProperty.status.withLocalEffectiveVisibility(isLocal).withExpect(isExpect) resolvePhase = baseProperty.resolvePhase annotations += baseProperty.annotations if (newTypeParameters != null) { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/EnumClassUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/EnumClassUtils.kt index defa2218d69..bf882edee41 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/EnumClassUtils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/EnumClassUtils.kt @@ -29,7 +29,9 @@ private val ENUM_VALUES = Name.identifier("values") private val ENUM_VALUE_OF = Name.identifier("valueOf") private val VALUE = Name.identifier("value") -fun FirRegularClassBuilder.generateValuesFunction(session: FirSession, packageFqName: FqName, classFqName: FqName) { +fun FirRegularClassBuilder.generateValuesFunction( + session: FirSession, packageFqName: FqName, classFqName: FqName, makeExpect: Boolean = false +) { declarations += buildSimpleFunction { source = this@generateValuesFunction.source origin = FirDeclarationOrigin.Source @@ -47,6 +49,7 @@ fun FirRegularClassBuilder.generateValuesFunction(session: FirSession, packageFq name = ENUM_VALUES this.status = FirDeclarationStatusImpl(Visibilities.PUBLIC, Modality.FINAL).apply { isStatic = true + isExpect = makeExpect } symbol = FirNamedFunctionSymbol(CallableId(packageFqName, classFqName, ENUM_VALUES)) resolvePhase = FirResolvePhase.BODY_RESOLVE @@ -54,7 +57,9 @@ fun FirRegularClassBuilder.generateValuesFunction(session: FirSession, packageFq } } -fun FirRegularClassBuilder.generateValueOfFunction(session: FirSession, packageFqName: FqName, classFqName: FqName) { +fun FirRegularClassBuilder.generateValueOfFunction( + session: FirSession, packageFqName: FqName, classFqName: FqName, makeExpect: Boolean = false +) { declarations += buildSimpleFunction { source = this@generateValueOfFunction.source origin = FirDeclarationOrigin.Source @@ -70,6 +75,7 @@ fun FirRegularClassBuilder.generateValueOfFunction(session: FirSession, packageF name = ENUM_VALUE_OF status = FirDeclarationStatusImpl(Visibilities.PUBLIC, Modality.FINAL).apply { isStatic = true + isExpect = makeExpect } symbol = FirNamedFunctionSymbol(CallableId(packageFqName, classFqName, ENUM_VALUE_OF)) valueParameters += buildValueParameter vp@{ diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt index 1549a8948f9..a2dcf372e09 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt @@ -402,7 +402,14 @@ class FirRenderer(builder: StringBuilder, private val mode: RenderMode = RenderM override fun visitConstructor(constructor: FirConstructor) { constructor.annotations.renderAnnotations() - print(constructor.visibility.asString(constructor.effectiveVisibility) + " constructor") + print(constructor.visibility.asString(constructor.effectiveVisibility) + " ") + if (constructor.isExpect) { + print("expect ") + } + if (constructor.isActual) { + print("actual ") + } + print("constructor") constructor.typeParameters.renderTypeParameters() constructor.valueParameters.renderParameters() print(": ") diff --git a/compiler/testData/ir/irText/declarations/multiplatform/expectClassInherited.fir.txt b/compiler/testData/ir/irText/declarations/multiplatform/expectClassInherited.fir.txt index 6b2b0cbcfb8..53a7f7fc634 100644 --- a/compiler/testData/ir/irText/declarations/multiplatform/expectClassInherited.fir.txt +++ b/compiler/testData/ir/irText/declarations/multiplatform/expectClassInherited.fir.txt @@ -1,47 +1,41 @@ FILE fqName: fileName:/expectClassInherited.kt CLASS CLASS name:A modality:ABSTRACT visibility:public [expect] superTypes:[kotlin.Any] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.A - CONSTRUCTOR visibility:protected <> () returnType:.A [primary] - BLOCK_BODY - DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:A modality:ABSTRACT visibility:public [expect] superTypes:[kotlin.Any]' - FUN name:foo visibility:public modality:ABSTRACT <> ($this:.A) returnType:kotlin.Unit + CONSTRUCTOR visibility:protected <> () returnType:.A [primary,expect] + FUN name:foo visibility:public modality:ABSTRACT <> ($this:.A) returnType:kotlin.Unit [expect] $this: VALUE_PARAMETER name: type:.A - FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [expect,fake_override] overridden: public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any VALUE_PARAMETER name:other index:0 type:kotlin.Any? - FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [expect,fake_override] overridden: public open fun hashCode (): kotlin.Int declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any - FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [expect,fake_override] overridden: public open fun toString (): kotlin.String declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any CLASS CLASS name:B modality:OPEN visibility:public [expect] superTypes:[.A] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.B - CONSTRUCTOR visibility:public <> (i:kotlin.Int) returnType:.B [primary] + CONSTRUCTOR visibility:public <> (i:kotlin.Int) returnType:.B [primary,expect] VALUE_PARAMETER name:i index:0 type:kotlin.Int - BLOCK_BODY - DELEGATING_CONSTRUCTOR_CALL 'protected constructor () [primary] declared in .A' - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:B modality:OPEN visibility:public [expect] superTypes:[.A]' - FUN name:foo visibility:public modality:OPEN <> ($this:.B) returnType:kotlin.Unit + FUN name:foo visibility:public modality:OPEN <> ($this:.B) returnType:kotlin.Unit [expect] $this: VALUE_PARAMETER name: type:.B - FUN name:bar visibility:public modality:OPEN <> ($this:.B, s:kotlin.String) returnType:kotlin.Unit + FUN name:bar visibility:public modality:OPEN <> ($this:.B, s:kotlin.String) returnType:kotlin.Unit [expect] $this: VALUE_PARAMETER name: type:.B VALUE_PARAMETER name:s index:0 type:kotlin.String - FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [expect,fake_override] overridden: public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any VALUE_PARAMETER name:other index:0 type:kotlin.Any? - FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [expect,fake_override] overridden: public open fun hashCode (): kotlin.Int declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any - FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [expect,fake_override] overridden: public open fun toString (): kotlin.String declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any diff --git a/compiler/testData/ir/irText/declarations/multiplatform/expectedEnumClass.fir.txt b/compiler/testData/ir/irText/declarations/multiplatform/expectedEnumClass.fir.txt index 00a5aa53d75..acf41918283 100644 --- a/compiler/testData/ir/irText/declarations/multiplatform/expectedEnumClass.fir.txt +++ b/compiler/testData/ir/irText/declarations/multiplatform/expectedEnumClass.fir.txt @@ -1,17 +1,13 @@ FILE fqName: fileName:/expectedEnumClass.kt CLASS ENUM_CLASS name:MyEnum modality:FINAL visibility:public [expect] superTypes:[kotlin.Enum<.MyEnum>] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.MyEnum - CONSTRUCTOR visibility:private <> () returnType:.MyEnum [primary] - BLOCK_BODY - ENUM_CONSTRUCTOR_CALL 'public constructor (name: kotlin.String, ordinal: kotlin.Int) [primary] declared in kotlin.Enum' - : .MyEnum - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS ENUM_CLASS name:MyEnum modality:FINAL visibility:public [expect] superTypes:[kotlin.Enum<.MyEnum>]' + CONSTRUCTOR visibility:private <> () returnType:.MyEnum [primary,expect] ENUM_ENTRY name:FOO init: EXPRESSION_BODY - ENUM_CONSTRUCTOR_CALL 'private constructor () [primary] declared in .MyEnum' + ENUM_CONSTRUCTOR_CALL 'private constructor () [primary,expect] declared in .MyEnum' ENUM_ENTRY name:BAR init: EXPRESSION_BODY - ENUM_CONSTRUCTOR_CALL 'private constructor () [primary] declared in .MyEnum' + ENUM_CONSTRUCTOR_CALL 'private constructor () [primary,expect] declared in .MyEnum' FUN ENUM_CLASS_SPECIAL_MEMBER name:values visibility:public modality:FINAL <> () returnType:kotlin.Array<.MyEnum> SYNTHETIC_BODY kind=ENUM_VALUES FUN ENUM_CLASS_SPECIAL_MEMBER name:valueOf visibility:public modality:FINAL <> (value:kotlin.String) returnType:.MyEnum diff --git a/compiler/testData/ir/irText/declarations/multiplatform/expectedSealedClass.fir.txt b/compiler/testData/ir/irText/declarations/multiplatform/expectedSealedClass.fir.txt index 76abb775dbf..599f95d1b86 100644 --- a/compiler/testData/ir/irText/declarations/multiplatform/expectedSealedClass.fir.txt +++ b/compiler/testData/ir/irText/declarations/multiplatform/expectedSealedClass.fir.txt @@ -1,39 +1,33 @@ FILE fqName: fileName:/expectedSealedClass.kt CLASS CLASS name:Ops modality:SEALED visibility:public [expect] superTypes:[kotlin.Any] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Ops - CONSTRUCTOR visibility:private <> () returnType:.Ops [primary] - BLOCK_BODY - DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Ops modality:SEALED visibility:public [expect] superTypes:[kotlin.Any]' - FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + CONSTRUCTOR visibility:private <> () returnType:.Ops [primary,expect] + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [expect,fake_override] overridden: public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any VALUE_PARAMETER name:other index:0 type:kotlin.Any? - FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [expect,fake_override] overridden: public open fun hashCode (): kotlin.Int declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any - FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [expect,fake_override] overridden: public open fun toString (): kotlin.String declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any CLASS CLASS name:Add modality:FINAL visibility:public [expect] superTypes:[.Ops] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Add - CONSTRUCTOR visibility:public <> () returnType:.Add [primary] - BLOCK_BODY - DELEGATING_CONSTRUCTOR_CALL 'private constructor () [primary] declared in .Ops' - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Add modality:FINAL visibility:public [expect] superTypes:[.Ops]' - FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + CONSTRUCTOR visibility:public <> () returnType:.Add [primary,expect] + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [expect,fake_override] overridden: public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any VALUE_PARAMETER name:other index:0 type:kotlin.Any? - FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [expect,fake_override] overridden: public open fun hashCode (): kotlin.Int declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any - FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [expect,fake_override] overridden: public open fun toString (): kotlin.String declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any