From 9b40981368430d4c6b0e24fb64373d3d8ad8808b Mon Sep 17 00:00:00 2001 From: romanart Date: Fri, 21 Sep 2018 19:15:02 +0300 Subject: [PATCH] [JS IR BE] Unit Materialization lowering Fix unit-related things across backend --- .../lower/UnitMaterializationLowering.kt | 39 +++++++++++++++++++ .../kotlin/ir/backend/js/compiler.kt | 11 +----- .../js/lower/BlockDecomposerLowering.kt | 2 +- .../backend/js/lower/BridgesConstruction.kt | 18 ++++++++- .../lower/coroutines/StateMachineBuilder.kt | 13 ++++++- .../IrElementToJsExpressionTransformer.kt | 11 ++---- .../backend/js/utils/SimpleNameGenerator.kt | 6 ++- 7 files changed, 76 insertions(+), 24 deletions(-) create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/UnitMaterializationLowering.kt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/UnitMaterializationLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/UnitMaterializationLowering.kt new file mode 100644 index 00000000000..ea57817b071 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/UnitMaterializationLowering.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.lower + +import org.jetbrains.kotlin.backend.common.BackendContext +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.types.classifierOrFail +import org.jetbrains.kotlin.ir.types.isUnit +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid + +class UnitMaterializationLowering(context: BackendContext): FileLoweringPass { + + private val unitType = context.irBuiltIns.unitType + private val unitValue = IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, unitType, unitType.classifierOrFail as IrClassSymbol) + + override fun lower(irFile: IrFile) { + irFile.transformChildrenVoid(object : IrElementTransformerVoid() { + override fun visitCall(expression: IrCall): IrExpression { + expression.transformChildrenVoid(this) + return if (expression.type.isUnit()) expression.let { + IrCompositeImpl(it.startOffset, it.endOffset, it.type, it.origin, listOf(it, unitValue)) + } + else expression + } + }) + } + +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index c4e9db111a8..67259e355f2 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -22,15 +22,6 @@ import org.jetbrains.kotlin.ir.backend.js.lower.inline.RemoveInlineFunctionsWith import org.jetbrains.kotlin.ir.backend.js.lower.inline.ReturnableBlockLowering import org.jetbrains.kotlin.ir.backend.js.lower.inline.replaceUnboundSymbols import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer -import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns -import org.jetbrains.kotlin.ir.expressions.IrBlock -import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock -import org.jetbrains.kotlin.ir.symbols.* -import org.jetbrains.kotlin.ir.symbols.impl.* -import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid -import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator @@ -84,7 +75,6 @@ fun compile( MoveExternalDeclarationsToSeparatePlace().lower(moduleFragment.files) - moduleFragment.files.forEach(CoroutineIntrinsicLowering(context)::lower) moduleFragment.files.forEach { ArrayInlineConstructorLowering(context).lower(it) } @@ -111,6 +101,7 @@ private fun JsIrBackendContext.performInlining(moduleFragment: IrModuleFragment) } private fun JsIrBackendContext.lower(moduleFragment: IrModuleFragment, dependencies: List) { + moduleFragment.files.forEach(UnitMaterializationLowering(this)::lower) moduleFragment.files.forEach(VarargLowering(this)::lower) moduleFragment.files.forEach(LateinitLowering(this, true)::lower) moduleFragment.files.forEach(DefaultArgumentStubGenerator(this)::runOnFilePostfix) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt index 1902c215342..47eb9c0b510 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt @@ -528,7 +528,7 @@ class BlockDecomposerTransformer(context: JsIrBackendContext) : IrElementTransfo override fun visitContainerExpression(expression: IrContainerExpression): IrExpression { - expression.run { if (statements.isEmpty()) return IrCompositeImpl(startOffset, endOffset, type, origin, emptyList()) } + expression.run { if (statements.isEmpty()) return IrCompositeImpl(startOffset, endOffset, type, origin, listOf(unitValue)) } val newStatements = mutableListOf() diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BridgesConstruction.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BridgesConstruction.kt index 5cca6c76557..d7156732185 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BridgesConstruction.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BridgesConstruction.kt @@ -103,6 +103,8 @@ class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass { } } + private val unitValue = JsIrBuilder.buildGetObjectValue(context.irBuiltIns.unitType, context.irBuiltIns.unitClass) + // Ported from from jvm.lower.BridgeLowering private fun createBridge( function: IrSimpleFunction, @@ -146,7 +148,19 @@ class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass { irFunction.valueParameters.subList(0, toTake).mapIndexed { i, valueParameter -> call.putValueArgument(i, irCastIfNeeded(irGet(valueParameter), delegateTo.valueParameters[i].type)) } - +irReturn(call) + + // This is required for Unit materialization + // TODO: generalize for boxed types and inline classes + // TODO: use return type in signature too + val returnValue = if (delegateTo.returnType.isUnit() && !function.returnType.isUnit()) { + irComposite(resultType = irFunction.returnType) { + +call + +unitValue + } + } else { + call + } + +irReturn(returnValue) }.apply { irFunction.body = this } @@ -156,7 +170,7 @@ class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass { // TODO: get rid of Unit check private fun IrBlockBodyBuilder.irCastIfNeeded(argument: IrExpression, type: IrType): IrExpression = - if (argument.type.classifierOrNull == type.classifierOrNull || type.isUnit()) argument else irAs(argument, type) + if (argument.type.classifierOrNull == type.classifierOrNull) argument else irAs(argument, type) } // Handle for common.bridges diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt index 202dc9ec3d2..b209f5db28a 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/coroutines/StateMachineBuilder.kt @@ -18,7 +18,10 @@ import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* -import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol +import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol +import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.visitors.* @@ -412,6 +415,12 @@ class StateMachineBuilder( transformLastExpression { expression.apply { value = it } } } + override fun visitTypeOperator(expression: IrTypeOperatorCall) { + if (expression !in suspendableNodes) return addStatement(expression) + expression.acceptChildrenVoid(this) + transformLastExpression { expression.apply { argument = it } } + } + override fun visitVariable(declaration: IrVariable) { if (declaration !in suspendableNodes) return addStatement(declaration) declaration.acceptChildrenVoid(this) @@ -542,7 +551,7 @@ class StateMachineBuilder( currentState.successors += catchBlockStack.peek()!! } - private fun hasResultingValue(expression: IrExpression) = expression.type.run { !isUnit() && !isNothing() } + private fun hasResultingValue(expression: IrExpression) = !expression.type.isNothing() override fun visitThrow(expression: IrThrow) { expression.acceptChildrenVoid(this) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt index 976ab768fe3..39940c49bcc 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol -import org.jetbrains.kotlin.ir.types.isUnit import org.jetbrains.kotlin.ir.util.isFunctionTypeOrSubtype import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.util.OperatorNameConventions @@ -70,13 +69,9 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer { - // TODO: return unit instance instead of null - if (expression.type.isUnit()) JsNullLiteral() - else { - val className = context.getNameForSymbol(expression.symbol) - val getInstanceName = className.ident + "_getInstance" - JsInvocation(JsNameRef(getInstanceName)) - } + val className = context.getNameForSymbol(expression.symbol) + val getInstanceName = className.ident + "_getInstance" + JsInvocation(JsNameRef(getInstanceName)) } else -> TODO() } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt index 217f793d1f7..efa4893562f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/SimpleNameGenerator.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.js.naming.isES5IdentifierPart import org.jetbrains.kotlin.js.naming.isES5IdentifierStart import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor // TODO: this class has to be reimplemented soon class SimpleNameGenerator : NameGenerator { @@ -147,7 +148,10 @@ class SimpleNameGenerator : NameGenerator { if (declaration.kind == ClassKind.OBJECT || declaration.name.isSpecial || declaration.visibility == Visibilities.LOCAL) { - nameDeclarator = context.staticContext.rootScope::declareFreshName + if (declaration.descriptor !is DeserializedClassDescriptor) { + // TODO: temporary workaround for Unit instance + nameDeclarator = context.staticContext.rootScope::declareFreshName + } val parent = declaration.parent when (parent) { is IrDeclaration -> nameBuilder.append(getNameForDeclaration(parent, context))