diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/optimizations.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/optimizations.kt index e6b7af92bc4..7d57c228ac5 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/optimizations.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/optimizations.kt @@ -11,6 +11,8 @@ import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel import org.jetbrains.kotlin.ir.backend.js.dce.DceDumpNameCache import org.jetbrains.kotlin.ir.backend.js.dce.eliminateDeadDeclarations import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment +import org.jetbrains.kotlin.ir.backend.js.utils.JsStaticContext +import org.jetbrains.kotlin.ir.backend.js.utils.getVoid import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.js.backend.ast.JsClass import org.jetbrains.kotlin.js.backend.ast.JsFunction @@ -35,11 +37,13 @@ fun optimizeProgramByIr( } } -fun optimizeFragmentByJsAst(fragment: JsIrProgramFragment) { +fun optimizeFragmentByJsAst(fragment: JsIrProgramFragment, context: JsStaticContext) { + val voidName = context.backendContext.intrinsics.void.owner.backingField?.let(context::getNameForField) + val optimizer = object : RecursiveJsVisitor() { override fun visitFunction(x: JsFunction) { super.visitFunction(x) - FunctionPostProcessor(x).apply() + FunctionPostProcessor(x, voidName).apply() } override fun visitClass(x: JsClass) { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt index 15f92281337..2ccaa665607 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.js.backend.ast.* +import org.jetbrains.kotlin.js.backend.ast.metadata.constant @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt index d9334d38024..8b9f5aa1a06 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt @@ -471,7 +471,7 @@ class IrModuleToJsTransformer( result.computeAndSaveDefinitions(definitionSet, fileExports) if (optimizeGeneratedJs) { - optimizeFragmentByJsAst(result) + optimizeFragmentByJsAst(result, staticContext) } return JsIrProgramFragments(result, exportFragment) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsNameLinkingNamer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsNameLinkingNamer.kt index eac89ca3619..0a7d3453e47 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsNameLinkingNamer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsNameLinkingNamer.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.js.backend.ast.* +import org.jetbrains.kotlin.js.backend.ast.metadata.constant import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -50,7 +51,11 @@ class JsNameLinkingNamer( } } - return declaration.getName() + return declaration.getName().also { + if (declaration == context.intrinsics.void.owner.backingField) { + it.constant = true + } + } } override fun getNameForMemberFunction(function: IrSimpleFunction): JsName { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt index 003bb3d3425..d7c11a1346e 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt @@ -459,6 +459,7 @@ private class JsIrAstDeserializer(private val source: ByteArray) { } ?: JsDynamicScope.declareName(identifier) ifTrue { name.localAlias = readLocalAlias() } ifTrue { name.imported = true } + ifTrue { name.constant = true } ifTrue { name.specialFunction = specialFunctionValues[readInt()] } return name } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt index a854ab2197c..039e0d72c99 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt @@ -605,6 +605,7 @@ private class JsIrAstSerializer { writeBoolean(name.isTemporary) ifNotNull(name.localAlias) { writeLocalAlias(it) } writeBoolean(name.imported && name !in importedNames) + writeBoolean(name.constant) ifNotNull(name.specialFunction) { writeByte(it.ordinal) } } nameMap.size diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt index 02ec58e845b..e45f1e1415b 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt @@ -77,6 +77,7 @@ var JsFunction.functionDescriptor: FunctionDescriptor? by MetadataProperty(defau */ var JsReturn.returnTarget: FunctionDescriptor? by MetadataProperty(default = null) +var HasMetadata.constant: Boolean by MetadataProperty(default = false) var HasMetadata.synthetic: Boolean by MetadataProperty(default = false) var HasMetadata.isInlineClassBoxing: Boolean by MetadataProperty(default = false) diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/FunctionPostProcessor.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/FunctionPostProcessor.kt index 32879ffc88f..3c6f18feb89 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/FunctionPostProcessor.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/FunctionPostProcessor.kt @@ -17,8 +17,9 @@ package org.jetbrains.kotlin.js.inline.clean import org.jetbrains.kotlin.js.backend.ast.JsFunction +import org.jetbrains.kotlin.js.backend.ast.JsName -class FunctionPostProcessor(val root: JsFunction) { +class FunctionPostProcessor(val root: JsFunction, private val voidName: JsName? = null) { val optimizations = listOf( { RedundantLabelRemoval(root.body).apply() }, { EmptyStatementElimination(root.body).apply() }, @@ -32,7 +33,8 @@ class FunctionPostProcessor(val root: JsFunction) { { RedundantStatementElimination(root).apply() }, { CoroutineStateElimination(root.body).apply() }, { BoxingUnboxingElimination(root.body).apply() }, - { MoveTemporaryVariableDeclarationToAssignment(root.body).apply() } + { MoveTemporaryVariableDeclarationToAssignment(root.body).apply() }, + { voidName?.let { VoidPropertiesElimination(root.body, voidName).apply() } ?: false } ) // TODO: reduce to A || B, A && B if possible diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt index 37242ebc24c..69035486297 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt @@ -17,10 +17,7 @@ package org.jetbrains.kotlin.js.inline.clean import org.jetbrains.kotlin.js.backend.ast.* -import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind -import org.jetbrains.kotlin.js.backend.ast.metadata.imported -import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects -import org.jetbrains.kotlin.js.backend.ast.metadata.synthetic +import org.jetbrains.kotlin.js.backend.ast.metadata.* import org.jetbrains.kotlin.js.inline.util.collectFreeVariables import org.jetbrains.kotlin.js.inline.util.collectLocalVariables import org.jetbrains.kotlin.js.translate.context.Namer @@ -481,8 +478,8 @@ internal class TemporaryVariableElimination(private val function: JsFunction) { override fun visitNameRef(nameRef: JsNameRef) { val name = nameRef.name - if (name != null && name in localVariables) { - if (name !in namesToSubstitute && shouldConsiderTemporary(name)) { + if (name != null && (name in localVariables || name.constant)) { + if (name.constant || (name !in namesToSubstitute && shouldConsiderTemporary(name))) { if (!sideEffectOccurred) { substitutableVariableReferences += name } @@ -637,16 +634,18 @@ internal class TemporaryVariableElimination(private val function: JsFunction) { private fun isTrivial(expr: JsExpression): Boolean = when (expr) { is JsNameRef -> { val qualifier = expr.qualifier - if (expr.sideEffects == SideEffectKind.PURE && (qualifier == null || isTrivial(qualifier))) { - expr.name !in temporary - } - else { - val name = expr.name - name in localVariables && when (definitions[name]) { - // Local variables with zero definitions are function parameters. We can relocate and copy them. - null, 0 -> true - 1 -> name !in namesToSubstitute || definedValues[name]?.let { isTrivial(it) } ?: false - else -> false + when { + expr.name?.constant == true -> true + expr.sideEffects == SideEffectKind.PURE && (qualifier == null || isTrivial(qualifier)) -> + expr.name !in temporary + else -> { + val name = expr.name + name in localVariables && when (definitions[name]) { + // Local variables with zero definitions are function parameters. We can relocate and copy them. + null, 0 -> true + 1 -> name !in namesToSubstitute || definedValues[name]?.let { isTrivial(it) } ?: false + else -> false + } } } } diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/VoidPropertiesElimination.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/VoidPropertiesElimination.kt new file mode 100644 index 00000000000..135fc75e4ed --- /dev/null +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/VoidPropertiesElimination.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.js.inline.clean + +import org.jetbrains.kotlin.js.backend.ast.* +import org.jetbrains.kotlin.js.backend.ast.metadata.isInlineClassBoxing +import org.jetbrains.kotlin.js.backend.ast.metadata.isInlineClassUnboxing + +// Replaces { a: 2, b: VOID, c: VOID } with { a: 2 } +class VoidPropertiesElimination(private val root: JsBlock, private val voidName: JsName) { + private var changed = false + + fun apply(): Boolean { + val visitor = object : JsVisitorWithContextImpl() { + override fun endVisit(x: JsPropertyInitializer, ctx: JsContext) { + super.endVisit(x, ctx) + if ((x.valueExpr as? JsNameRef)?.name === voidName) { + ctx.removeMe() + changed = true + } + } + } + + visitor.accept(root) + + return changed + } +} diff --git a/plugins/js-plain-objects/compiler-plugin/js-plain-objects.backend/src/org/jetbrains/kotlinx/jso/compiler/backend/JsObjectLoweringExtension.kt b/plugins/js-plain-objects/compiler-plugin/js-plain-objects.backend/src/org/jetbrains/kotlinx/jso/compiler/backend/JsObjectLoweringExtension.kt index 670b620f7e1..5ab07c3b35a 100644 --- a/plugins/js-plain-objects/compiler-plugin/js-plain-objects.backend/src/org/jetbrains/kotlinx/jso/compiler/backend/JsObjectLoweringExtension.kt +++ b/plugins/js-plain-objects/compiler-plugin/js-plain-objects.backend/src/org/jetbrains/kotlinx/jso/compiler/backend/JsObjectLoweringExtension.kt @@ -10,10 +10,13 @@ import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl import org.jetbrains.kotlin.ir.expressions.IrBlockBody import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI +import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlinx.jspo.compiler.resolve.JsPlainObjectsPluginKey import org.jetbrains.kotlinx.jspo.compiler.resolve.StandardIds @@ -32,7 +35,8 @@ private class MoveExternalInlineFunctionsWithBodiesOutsideLowering(private val c file.declarations.add(declaration) declaration.body = when (declaration.name) { - StandardNames.DATA_CLASS_COPY, OperatorNameConventions.INVOKE -> declaration.generateBodyForFactoryAndCopyFunction() + StandardNames.DATA_CLASS_COPY -> declaration.generateBodyForCopyFunction() + OperatorNameConventions.INVOKE -> declaration.generateBodyForFactoryFunction() else -> error("Unexpected function with name `${declaration.name.identifier}`") } @@ -42,7 +46,7 @@ private class MoveExternalInlineFunctionsWithBodiesOutsideLowering(private val c return emptyList() } - private fun IrSimpleFunction.generateBodyForFactoryAndCopyFunction(): IrBlockBody { + private fun IrSimpleFunction.generateBodyForFactoryFunction(): IrBlockBody { val declaration = this return context.irFactory.createBlockBody(startOffset, declaration.endOffset).apply { statements += IrReturnImpl( @@ -64,6 +68,49 @@ private class MoveExternalInlineFunctionsWithBodiesOutsideLowering(private val c ) } } + + private fun IrSimpleFunction.generateBodyForCopyFunction(): IrBlockBody { + val declaration = this + return context.irFactory.createBlockBody(startOffset, declaration.endOffset).apply { + val selfName = Name.identifier("${"$$"}tmp_self${"$$"}") + statements += IrVariableImpl( + declaration.startOffset, + declaration.endOffset, + IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, + IrVariableSymbolImpl(), + selfName, + context.irBuiltIns.nothingType, + isVar = false, + isConst = false, + isLateinit = false + ).apply { + parent = declaration + initializer = IrGetValueImpl( + declaration.startOffset, + declaration.endOffset, + declaration.dispatchReceiverParameter!!.symbol + ) + } + statements += IrReturnImpl( + declaration.startOffset, + declaration.endOffset, + declaration.returnType, + declaration.symbol, + IrCallImpl( + declaration.startOffset, + declaration.endOffset, + declaration.returnType, + jsFunction, + 0, + 1, + ).apply { + val jsObject = "{ ${declaration.valueParameters.joinToString(", ") { "${it.name.identifier}:${it.name.identifier}" }} }" + val objectAssignCall = "Object.assign({}, ${selfName.identifier}, $jsObject)" + putValueArgument(0, objectAssignCall.toIrConst(context.irBuiltIns.stringType)) + } + ) + } + } } open class JsPlainObjectsLoweringExtension : IrGenerationExtension { diff --git a/plugins/js-plain-objects/compiler-plugin/js-plain-objects.common/src/org/jetbrains/kotlinx/jso/compiler/resolve/NamingConventions.kt b/plugins/js-plain-objects/compiler-plugin/js-plain-objects.common/src/org/jetbrains/kotlinx/jso/compiler/resolve/NamingConventions.kt index d535a7622c0..71ceb07c73d 100644 --- a/plugins/js-plain-objects/compiler-plugin/js-plain-objects.common/src/org/jetbrains/kotlinx/jso/compiler/resolve/NamingConventions.kt +++ b/plugins/js-plain-objects/compiler-plugin/js-plain-objects.common/src/org/jetbrains/kotlinx/jso/compiler/resolve/NamingConventions.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.name.Name object StandardIds { val KOTLIN_JS_FQN = FqName("kotlin.js") val JS_FUNCTION_ID = CallableId(KOTLIN_JS_FQN, Name.identifier("js")) + val VOID_PROPERTY_NAME = Name.identifier("VOID") } object JsPlainObjectsAnnotations { diff --git a/plugins/js-plain-objects/compiler-plugin/js-plain-objects.k2/src/org/jetbrains/kotlinx/jso/compiler/fir/JsPlainObjectsFunctionsGenerator.kt b/plugins/js-plain-objects/compiler-plugin/js-plain-objects.k2/src/org/jetbrains/kotlinx/jso/compiler/fir/JsPlainObjectsFunctionsGenerator.kt index d3b41d9473d..98f38bfbd7f 100644 --- a/plugins/js-plain-objects/compiler-plugin/js-plain-objects.k2/src/org/jetbrains/kotlinx/jso/compiler/fir/JsPlainObjectsFunctionsGenerator.kt +++ b/plugins/js-plain-objects/compiler-plugin/js-plain-objects.k2/src/org/jetbrains/kotlinx/jso/compiler/fir/JsPlainObjectsFunctionsGenerator.kt @@ -28,9 +28,9 @@ import org.jetbrains.kotlin.fir.extensions.MemberGenerationContext import org.jetbrains.kotlin.fir.extensions.NestedClassGenerationContext import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider import org.jetbrains.kotlin.fir.moduleData -import org.jetbrains.kotlin.fir.references.builder.buildImplicitThisReference import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.defaultType +import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.impl.* @@ -40,11 +40,11 @@ import org.jetbrains.kotlin.fir.types.toFirResolvedTypeRef import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames -import org.jetbrains.kotlin.types.ConstantValueKind import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlinx.jspo.compiler.fir.services.jsPlainObjectPropertiesProvider import org.jetbrains.kotlinx.jspo.compiler.resolve.JsPlainObjectsPluginKey +import org.jetbrains.kotlinx.jspo.compiler.resolve.StandardIds /** * The extension generate a synthetic factory and copy-method for an `external interface` annotated with @JsPlainObjects @@ -56,6 +56,7 @@ import org.jetbrains.kotlinx.jspo.compiler.resolve.JsPlainObjectsPluginKey * @JsPlainObjects * external interface Admin { * val chat: Chat + * val email: String? * } * ``` * @@ -64,21 +65,26 @@ import org.jetbrains.kotlinx.jspo.compiler.resolve.JsPlainObjectsPluginKey * external interface Admin { * val chat: Chat * - * inline fun copy(chat: Chat = this.chat, name: String = this.name): Admin = + * inline fun copy(chat: Chat = this.chat, email: String = this.email): Admin = * Admin.Companion.invoke(chat, name) * * companion object { - * inline operator fun invoke(chat: Chat, name: String): Admin = + * inline operator fun invoke(chat: Chat, email: String? = VOID): Admin = * js("{ chat: chat, name: name }") * } * } * ``` */ class JsPlainObjectsFunctionsGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) { - private val predicateBasedProvider = session.predicateBasedProvider + private val voidPropertySymbol by lazy { + session.symbolProvider + .getTopLevelPropertySymbols(StandardIds.KOTLIN_JS_FQN, StandardIds.VOID_PROPERTY_NAME) + .single() + } - private val matchedInterfaces by lazy { - predicateBasedProvider.getSymbolsByPredicate(JsPlainObjectsPredicates.AnnotatedWithJsPlainObject.LOOKUP) + private val matchedInterfaces by lazy { + session.predicateBasedProvider + .getSymbolsByPredicate(JsPlainObjectsPredicates.AnnotatedWithJsPlainObject.LOOKUP) .filterIsInstance() .toSet() } @@ -102,7 +108,7 @@ class JsPlainObjectsFunctionsGenerator(session: FirSession) : FirDeclarationGene return if ( owner is FirRegularClassSymbol && owner.isJsPlainObject && - name == org.jetbrains.kotlin.name.SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT + name == SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT ) generateCompanionDeclaration(owner) else null } @@ -167,12 +173,13 @@ class JsPlainObjectsFunctionsGenerator(session: FirSession) : FirDeclarationGene ): FirSimpleFunction { return createJsPlainObjectsFunction(callableId, parent, jsPlainObjectInterface) { runIf(resolvedReturnTypeRef.type.isNullable) { - buildConstExpression( - source = null, - value = null, - kind = ConstantValueKind.Null, - setType = true - ) + buildPropertyAccessExpression { + calleeReference = buildResolvedNamedReference { + name = StandardIds.VOID_PROPERTY_NAME + resolvedSymbol = voidPropertySymbol + } + coneTypeOrNull = voidPropertySymbol.resolvedReturnType + } } } } @@ -185,15 +192,11 @@ class JsPlainObjectsFunctionsGenerator(session: FirSession) : FirDeclarationGene val interfaceType = jsPlainObjectInterface.defaultType() return createJsPlainObjectsFunction(callableId, parent, jsPlainObjectInterface) { buildPropertyAccessExpression { - dispatchReceiver = buildThisReceiverExpression { - calleeReference = buildImplicitThisReference { boundSymbol = jsPlainObjectInterface } - coneTypeOrNull = interfaceType - } calleeReference = buildResolvedNamedReference { - name = this@createJsPlainObjectsFunction.name - resolvedSymbol = this@createJsPlainObjectsFunction + name = StandardIds.VOID_PROPERTY_NAME + resolvedSymbol = voidPropertySymbol } - coneTypeOrNull = resolvedReturnType + coneTypeOrNull = voidPropertySymbol.resolvedReturnType } } } diff --git a/plugins/js-plain-objects/compiler-plugin/testData/box/optional.kt b/plugins/js-plain-objects/compiler-plugin/testData/box/optional.kt index f222c0d42f8..cc5881e0875 100644 --- a/plugins/js-plain-objects/compiler-plugin/testData/box/optional.kt +++ b/plugins/js-plain-objects/compiler-plugin/testData/box/optional.kt @@ -16,7 +16,7 @@ fun box(): String { if (user.age != 10) return "Fail: problem with `age` property" val json = js("JSON.stringify(user)") - if (json != "{\"email\":null,\"age\":10,\"name\":\"Name\"}") return "Fail: got the next json: $json" + if (json != "{\"age\":10,\"name\":\"Name\"}") return "Fail: got the next json: $json" val withEmail = User(name = "Name", age = 10, email = "test@test")