[JS IR BE] Unit Materialization lowering

Fix unit-related things across backend
This commit is contained in:
romanart
2018-09-21 19:15:02 +03:00
parent 57ae60e9dc
commit 9b40981368
7 changed files with 76 additions and 24 deletions
@@ -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
}
})
}
}
@@ -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<IrModuleFragment>) {
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)
@@ -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<IrStatement>()
@@ -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
@@ -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)
@@ -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<JsEx
override fun visitGetObjectValue(expression: IrGetObjectValue, context: JsGenerationContext) = when (expression.symbol.owner.kind) {
ClassKind.OBJECT -> {
// 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()
}
@@ -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))