JS IR BE: migrate to IR types

(cherry picked from commit 064f47b)
This commit is contained in:
Zalim Bashorov
2018-06-21 22:31:07 +03:00
committed by Dmitry Petrov
parent 952163b2fb
commit bf2aa5263e
23 changed files with 470 additions and 340 deletions
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2016 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.
* 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.js
@@ -29,6 +18,7 @@ import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.name.Name
@@ -64,7 +54,7 @@ class JsDescriptorsFactory : DescriptorsFactory {
false
).apply {
setType(
outerClass.defaultType,
outerClass.defaultType.toKotlinType(),
emptyList(),
innerClass.descriptor.thisAsReceiverParameter,
null as? ReceiverParameterDescriptor
@@ -25,7 +25,7 @@ class JsIntrinsics(
context: JsIrBackendContext
) {
private val stubBuilder = DeclarationStubGenerator(context.module, context.symbolTable, JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB)
private val stubBuilder = DeclarationStubGenerator(module, context.module, context.symbolTable, JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB)
// Equality operations:
@@ -15,8 +15,8 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
import org.jetbrains.kotlin.ir.backend.js.lower.inline.ModuleIndex
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
@@ -25,6 +25,8 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -59,7 +61,7 @@ class JsIrBackendContext(
val secondaryConstructorsMap = mutableMapOf<IrConstructorSymbol, SecondaryCtorPair>()
fun getOperatorByName(name: Name, type: KotlinType) = operatorMap[name]?.get(type)
fun getOperatorByName(name: Name, type: IrType) = operatorMap[name]?.get(type.toKotlinType())
val originalModuleIndex = ModuleIndex(irModuleFragment)
@@ -109,6 +111,7 @@ class JsIrBackendContext(
}
private fun referenceOperators() = OperatorNames.ALL.map { name ->
// TODO to replace KotlinType with IrType we need right equals on IrType
name to irBuiltIns.primitiveTypes.fold(mutableMapOf<KotlinType, IrFunctionSymbol>()) { m, t ->
val function = t.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).singleOrNull()
function?.let { m.put(t, symbolTable.referenceSimpleFunction(it)) }
@@ -40,24 +40,28 @@ class JsSharedVariablesManager(val builtIns: KotlinBuiltIns, val jsInterinalPack
false, false, variableDescriptor.isLateInit, variableDescriptor.source
)
val valueType = originalDeclaration.descriptor.type
val valueType = originalDeclaration.type
val boxConstructor = closureBoxConstructorTypeDescriptor
val boxConstructorSymbol = closureBoxConstructorTypeSymbol
val constructorTypeParam = closureBoxConstructorTypeDescriptor.typeParameters[0]
val boxConstructorTypeArgument = mapOf(constructorTypeParam to valueType)
val initializer = originalDeclaration.initializer ?: IrConstImpl.constNull(
originalDeclaration.startOffset,
originalDeclaration.endOffset,
valueType
)
// TODO use buildCall?
val constructorCall = IrCallImpl(
originalDeclaration.startOffset,
originalDeclaration.endOffset,
// TODO wrong type
originalDeclaration.type,
boxConstructorSymbol,
boxConstructor,
boxConstructorTypeArgument,
1,
JsLoweredDeclarationOrigin.JS_CLOSURE_BOX_CLASS
).apply { putValueArgument(0, initializer) }
).apply {
putTypeArgument(0, valueType)
putValueArgument(0, initializer)
}
return IrVariableImpl(
@@ -65,6 +69,8 @@ class JsSharedVariablesManager(val builtIns: KotlinBuiltIns, val jsInterinalPack
originalDeclaration.endOffset,
originalDeclaration.origin,
sharedVariableDescriptor,
// TODO wrong type ?
originalDeclaration.type,
constructorCall
)
}
@@ -75,9 +81,11 @@ class JsSharedVariablesManager(val builtIns: KotlinBuiltIns, val jsInterinalPack
IrGetFieldImpl(
originalGet.startOffset, originalGet.endOffset,
closureBoxFieldSymbol,
originalGet.type,
IrGetValueImpl(
originalGet.startOffset,
originalGet.endOffset,
originalGet.type,
sharedVariableSymbol
),
originalGet.origin
@@ -90,9 +98,11 @@ class JsSharedVariablesManager(val builtIns: KotlinBuiltIns, val jsInterinalPack
IrGetValueImpl(
originalSet.startOffset,
originalSet.endOffset,
originalSet.type,
sharedVariableSymbol
),
originalSet.value,
originalSet.type,
originalSet.origin
)
@@ -45,7 +45,8 @@ fun compile(
moduleFragment
)
ExternalDependenciesGenerator(psi2IrContext.symbolTable, psi2IrContext.irBuiltIns).generateUnboundSymbolsAsDependencies(moduleFragment)
ExternalDependenciesGenerator(psi2IrContext.moduleDescriptor, psi2IrContext.symbolTable, psi2IrContext.irBuiltIns)
.generateUnboundSymbolsAsDependencies(moduleFragment)
context.performInlining(moduleFragment)
@@ -41,7 +41,7 @@ class JsIrArithBuilder(val context: JsIrBackendContext) {
fun inv(v: IrExpression): IrExpression = buildUnaryOperator(OperatorNames.INV, v)
fun andand(l: IrExpression, r: IrExpression) = // if (l) r else false
JsIrBuilder.buildIfElse(context.builtIns.booleanType, l, r, JsIrBuilder.buildBoolean(context.builtIns.booleanType, false))
JsIrBuilder.buildIfElse(context.irBuiltIns.booleanType, l, r, JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false))
fun oror(l: IrExpression, r: IrExpression) = // if (l) true else r
JsIrBuilder.buildIfElse(context.builtIns.booleanType, l, JsIrBuilder.buildBoolean(context.builtIns.booleanType, true), r)
JsIrBuilder.buildIfElse(context.irBuiltIns.booleanType, l, JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true), r)
}
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.ir.backend.js.ir
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
@@ -15,76 +15,103 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.ir.types.IrType
object JsIrBuilder {
object SYNTHESIZED_STATEMENT : IrStatementOriginImpl("SYNTHESIZED_STATEMENT")
object SYNTHESIZED_DECLARATION : IrDeclarationOriginImpl("SYNTHESIZED_DECLARATION")
fun buildCall(target: IrFunctionSymbol, type: KotlinType? = null, typeArguments: Map<TypeParameterDescriptor, KotlinType>? = null) =
fun buildCall(target: IrFunctionSymbol, type: IrType? = null, typeArguments: List<IrType>? = null): IrCall =
IrCallImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
type ?: target.descriptor.returnType!!,
type ?: target.owner.returnType,
target,
target.descriptor,
typeArguments,
target.owner.typeParameters.size,
SYNTHESIZED_STATEMENT
)
).apply {
typeArguments?.let {
assert(typeArguments.size == typeArgumentsCount)
it.withIndex().forEach { (i, t) -> putTypeArgument(i, t) }
}
}
fun buildReturn(targetSymbol: IrFunctionSymbol, value: IrExpression) =
IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, targetSymbol, value)
fun buildReturn(targetSymbol: IrFunctionSymbol, value: IrExpression, context: BackendContext) =
IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.nothingType, targetSymbol, value)
fun buildThrow(type: KotlinType, value: IrExpression) = IrThrowImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, value)
fun buildThrow(type: IrType, value: IrExpression) = IrThrowImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, value)
fun buildValueParameter(symbol: IrValueParameterSymbol) =
IrValueParameterImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SYNTHESIZED_DECLARATION, symbol)
fun buildValueParameter(symbol: IrValueParameterSymbol, type: IrType? = null) =
IrValueParameterImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SYNTHESIZED_DECLARATION, symbol, type ?: symbol.owner.type, null)
fun buildFunction(symbol: IrSimpleFunctionSymbol) = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SYNTHESIZED_DECLARATION, symbol)
fun buildFunction(symbol: IrSimpleFunctionSymbol, returnType: IrType) =
IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SYNTHESIZED_DECLARATION, symbol).apply {
this.returnType = returnType
}
fun buildGetObjectValue(type: KotlinType, classSymbol: IrClassSymbol) =
fun buildGetObjectValue(type: IrType, classSymbol: IrClassSymbol) =
IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, classSymbol)
fun buildGetClass(expression: IrExpression, type: KotlinType) = IrGetClassImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, expression)
fun buildGetClass(expression: IrExpression, type: IrType) = IrGetClassImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, expression)
fun buildGetValue(symbol: IrValueSymbol) = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol, SYNTHESIZED_STATEMENT)
fun buildSetVariable(symbol: IrVariableSymbol, value: IrExpression) =
IrSetVariableImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol, value, SYNTHESIZED_STATEMENT)
fun buildGetValue(symbol: IrValueSymbol) = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol.owner.type, symbol, SYNTHESIZED_STATEMENT)
fun buildSetVariable(symbol: IrVariableSymbol, value: IrExpression, type: IrType) =
IrSetVariableImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, symbol, value, SYNTHESIZED_STATEMENT)
fun buildGetField(symbol: IrFieldSymbol, receiver: IrExpression?, superQualifierSymbol: IrClassSymbol? = null) =
IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol, receiver, SYNTHESIZED_STATEMENT, superQualifierSymbol)
IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol, symbol.owner.type, receiver, SYNTHESIZED_STATEMENT, superQualifierSymbol)
fun buildSetField(symbol: IrFieldSymbol, receiver: IrExpression?, value: IrExpression, superQualifierSymbol: IrClassSymbol? = null) =
IrSetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol, receiver, value, SYNTHESIZED_STATEMENT, superQualifierSymbol)
fun buildSetField(symbol: IrFieldSymbol, receiver: IrExpression?, value: IrExpression, type: IrType, superQualifierSymbol: IrClassSymbol? = null) =
IrSetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol, receiver, value, type, SYNTHESIZED_STATEMENT, superQualifierSymbol)
fun buildBlockBody(statements: List<IrStatement>) = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, statements)
fun buildBlock(type: KotlinType) = IrBlockImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, SYNTHESIZED_STATEMENT)
fun buildBlock(type: KotlinType, statements: List<IrStatement>) =
fun buildBlock(type: IrType) = IrBlockImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, SYNTHESIZED_STATEMENT)
fun buildBlock(type: IrType, statements: List<IrStatement>) =
IrBlockImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, SYNTHESIZED_STATEMENT, statements)
fun buildFunctionReference(type: KotlinType, symbol: IrFunctionSymbol) =
IrFunctionReferenceImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, symbol, symbol.descriptor)
fun buildFunctionReference(type: IrType, symbol: IrFunctionSymbol) =
IrFunctionReferenceImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, symbol, symbol.descriptor, 0, null)
fun buildVar(symbol: IrVariableSymbol, initializer: IrExpression? = null) =
IrVariableImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SYNTHESIZED_DECLARATION, symbol).apply { this.initializer = initializer }
fun buildVar(symbol: IrVariableSymbol, initializer: IrExpression? = null, type: IrType?) =
IrVariableImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SYNTHESIZED_DECLARATION, symbol, type ?: symbol.owner.type).apply { this.initializer = initializer }
fun buildBreak(type: KotlinType, loop: IrLoop) = IrBreakImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, loop)
fun buildContinue(type: KotlinType, loop: IrLoop) = IrContinueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, loop)
fun buildBreak(type: IrType, loop: IrLoop) = IrBreakImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, loop)
fun buildContinue(type: IrType, loop: IrLoop) = IrContinueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, loop)
fun buildIfElse(type: KotlinType, cond: IrExpression, thenBranch: IrExpression, elseBranch: IrExpression? = null) = IrIfThenElseImpl(
fun buildIfElse(type: IrType, cond: IrExpression, thenBranch: IrExpression, elseBranch: IrExpression? = null): IrWhen = buildIfElse(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, cond, thenBranch, elseBranch, SYNTHESIZED_STATEMENT
)
fun buildWhen(type: KotlinType, branches: List<IrBranch>) =
fun buildIfElse(
startOffset: Int,
endOffset: Int,
type: IrType,
cond: IrExpression,
thenBranch: IrExpression,
elseBranch: IrExpression? = null,
origin: IrStatementOrigin? = null
): IrWhen {
val element = IrIfThenElseImpl(startOffset, endOffset, type, origin)
element.branches.add(IrBranchImpl(cond, thenBranch))
if (elseBranch != null) {
val irTrue = IrConstImpl.boolean(UNDEFINED_OFFSET, UNDEFINED_OFFSET, cond.type, true)
element.branches.add(IrElseBranchImpl(irTrue, elseBranch))
}
return element
}
fun buildWhen(type: IrType, branches: List<IrBranch>) =
IrWhenImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, SYNTHESIZED_STATEMENT, branches)
fun buildTypeOperator(type: KotlinType, operator: IrTypeOperator, argument: IrExpression, toType: KotlinType, symbol: IrClassifierSymbol) =
IrTypeOperatorCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, operator, toType, argument, symbol)
fun buildTypeOperator(type: IrType, operator: IrTypeOperator, argument: IrExpression, toType: IrType, symbol: IrClassifierSymbol) =
IrTypeOperatorCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, operator, toType, symbol, argument)
fun buildNull(type: KotlinType) = IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type)
fun buildBoolean(type: KotlinType, v: Boolean) = IrConstImpl.boolean(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v)
fun buildInt(type: KotlinType, v: Int) = IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v)
fun buildString(type: KotlinType, s: String) = IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, s)
}
fun buildNull(type: IrType) = IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type)
fun buildBoolean(type: IrType, v: Boolean) = IrConstImpl.boolean(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v)
fun buildInt(type: IrType, v: Int) = IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v)
fun buildString(type: IrType, s: String) = IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, s)
}
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
@@ -17,9 +16,11 @@ import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
private typealias VisitData = Nothing?
@@ -30,15 +31,20 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
private val statementVisitor = StatementVisitor()
private val expressionVisitor = ExpressionVisitor()
private val constTrue = JsIrBuilder.buildBoolean(context.builtIns.booleanType, true)
private val constFalse = JsIrBuilder.buildBoolean(context.builtIns.booleanType, false)
private val nothingType = context.builtIns.nullableNothingType
private val constTrue = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
private val constFalse = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false)
private val nothingType get() = context.irBuiltIns.nothingType
private val unitType get() = context.irBuiltIns.unitType
private val unitType = context.builtIns.unitType
private val unitValue = JsIrBuilder.buildGetObjectValue(unitType, context.symbolTable.referenceClass(context.builtIns.unit))
private val unreachableFunction =
JsSymbolBuilder.buildSimpleFunction(context.module, Namer.UNREACHABLE_NAME).initialize(type = nothingType)
private val unreachableFunction = JsIrBuilder.buildFunction(
JsSymbolBuilder.buildSimpleFunction(
context.module,
Namer.UNREACHABLE_NAME
).initialize(returnType = nothingType),
nothingType
)
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.transformFlat { declaration ->
@@ -61,17 +67,18 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
fun lower(irField: IrField, container: IrDeclarationContainer): List<IrDeclaration> {
irField.initializer?.apply {
val returnType = expression.type
val initFnSymbol = JsSymbolBuilder.buildSimpleFunction(
(container as IrSymbolOwner).symbol.descriptor,
irField.name.asString() + "\$init\$"
).initialize(type = expression.type)
).initialize(returnType = returnType)
val newBody = IrBlockBodyImpl(expression.startOffset, expression.endOffset).apply {
statements += JsIrBuilder.buildReturn(initFnSymbol, expression)
statements += JsIrBuilder.buildReturn(initFnSymbol, expression, context)
}
val initFn = JsIrBuilder.buildFunction(initFnSymbol).apply {
val initFn = JsIrBuilder.buildFunction(initFnSymbol, returnType).apply {
body = newBody
}
@@ -314,15 +321,15 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
expression.type,
expression.operator,
expression.typeOperand,
resultValue,
expression.typeOperandClassifier
expression.typeOperandClassifier,
resultValue
)
val resValue: IrExpression
if (!KotlinBuiltIns.isUnit(expression.type)) {
if (!expression.type.isUnit()) {
val resVar = makeTempVar(expression.type)
statements += JsIrBuilder.buildVar(resVar, newOperator)
statements += JsIrBuilder.buildVar(resVar, newOperator, type = expression.type)
resValue = JsIrBuilder.buildGetValue(resVar)
} else {
statements += newOperator
@@ -364,7 +371,7 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
}
if (needNew) {
newStatements += JsIrBuilder.buildSetField(expression.symbol, newReceiver, newValue, expression.superQualifierSymbol)
newStatements += JsIrBuilder.buildSetField(expression.symbol, newReceiver, newValue, unitType, expression.superQualifierSymbol)
return DecomposedResult(newStatements, unitValue)
}
@@ -375,7 +382,7 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
val valueResult = expression.value.accept(expressionVisitor, data)
return valueResult.runIfChanged {
statements += JsIrBuilder.buildSetVariable(expression.symbol, resultValue)
statements += JsIrBuilder.buildSetVariable(expression.symbol, resultValue, unitType)
DecomposedResult(statements, unitValue)
}
}
@@ -400,7 +407,7 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
// val x = x_tmp
override fun visitContainerExpression(expression: IrContainerExpression, data: VisitData): VisitResult {
val variable = makeTempVar(expression.type)
val varDeclaration = JsIrBuilder.buildVar(variable)
val varDeclaration = JsIrBuilder.buildVar(variable, type = expression.type)
val blockStatements = expression.statements
val lastStatement: IrStatement? = blockStatements.lastOrNull()
@@ -434,7 +441,7 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
collectingList += statements
resultValue
}
collectingList += JsIrBuilder.buildSetVariable(variable, result)
collectingList += JsIrBuilder.buildSetVariable(variable, result, unitType)
if (body is IrComposite) {
DecomposedResult(mutableListOf(varDeclaration, *collectingList.toTypedArray()) , JsIrBuilder.buildGetValue(variable))
} else {
@@ -463,7 +470,7 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
private fun prepareArgument(arg: IrExpression, needWrap: Boolean, statements: MutableList<IrStatement>): IrExpression {
return if (needWrap) {
val wrapVar = makeTempVar(arg.type)
statements += JsIrBuilder.buildVar(wrapVar, arg)
statements += JsIrBuilder.buildVar(wrapVar, arg, type = arg.type)
JsIrBuilder.buildGetValue(wrapVar)
} else arg
}
@@ -543,21 +550,21 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
val resultVar = makeTempVar(expression.type)
// TODO: get rid of temporary variable
newStatements += JsIrBuilder.buildVar(resultVar, expression)
newStatements += JsIrBuilder.buildVar(resultVar, expression, type = expression.type)
return DecomposedResult(newStatements, JsIrBuilder.buildGetValue(resultVar))
}
override fun visitWhen(expression: IrWhen, data: VisitData): VisitResult {
val collectiveVar = makeTempVar(expression.type)
val varDeclaration = JsIrBuilder.buildVar(collectiveVar)
val varDeclaration = JsIrBuilder.buildVar(collectiveVar, type = expression.type)
val newWhen = processWhen(expression, data, this, this) { visitResult, original ->
val resultList = mutableListOf<IrStatement>()
val newResult = visitResult.runIfChangedOrDefault(original as IrExpression) {
resultList += statements
resultValue
}
resultList.apply { add(JsIrBuilder.buildSetVariable(collectiveVar, newResult)) }
resultList.apply { add(JsIrBuilder.buildSetVariable(collectiveVar, newResult, unitType)) }
}
if (newWhen != expression) {
@@ -587,7 +594,7 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
resultValue
}
val wrapVar = makeTempVar(expression.varargElementType)
newStatements += JsIrBuilder.buildVar(wrapVar).apply { initializer = newExpression }
newStatements += JsIrBuilder.buildVar(wrapVar, type = expression.type).apply { initializer = newExpression }
val newValue = JsIrBuilder.buildGetValue(wrapVar)
if (original is IrSpreadElement) {
IrSpreadElementImpl(original.startOffset, original.endOffset, newValue)
@@ -641,7 +648,7 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
newStatements += instantiater(returnValue)
return TerminatedResult(newStatements, JsIrBuilder.buildCall(unreachableFunction))
return TerminatedResult(newStatements, JsIrBuilder.buildCall(unreachableFunction.symbol))
}
@@ -658,7 +665,7 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
)
override fun visitBreakContinue(jump: IrBreakContinue, data: VisitData): VisitResult {
return DecomposedResult(jump, JsIrBuilder.buildCall(unreachableFunction))
return DecomposedResult(jump, JsIrBuilder.buildCall(unreachableFunction.symbol))
}
override fun visitTry(aTry: IrTry, data: VisitData): VisitResult {
@@ -669,10 +676,10 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
finallyResult?.run { assert(status == VisitStatus.KEPT) }
val resultSymbol = makeTempVar(aTry.type)
val resultDeclaration = JsIrBuilder.buildVar(resultSymbol)
val resultDeclaration = JsIrBuilder.buildVar(resultSymbol, type = aTry.type)
val newTryValue = tryResult.runIfChangedOrDefault(aTry.tryResult) { resultValue }
val trySetResult = JsIrBuilder.buildSetVariable(resultSymbol, newTryValue) as IrStatement
val trySetResult = JsIrBuilder.buildSetVariable(resultSymbol, newTryValue, unitType) as IrStatement
val tryBlock = IrBlockImpl(aTry.tryResult.startOffset, aTry.tryResult.endOffset, unitType).apply {
statements += tryResult.runIfChangedOrDefault(listOf(trySetResult)) { statements + trySetResult }
@@ -680,7 +687,7 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
val catchBlocks = catchResults.map { (original, result) ->
val newCatchResult = result.runIfChangedOrDefault(original.result) { resultValue }
val catchSetResult = JsIrBuilder.buildSetVariable(resultSymbol, newCatchResult) as IrStatement
val catchSetResult = JsIrBuilder.buildSetVariable(resultSymbol, newCatchResult, unitType) as IrStatement
val catchBlock = IrBlockImpl(original.result.startOffset, original.result.endOffset, unitType)
catchBlock.statements += result.runIfChangedOrDefault(listOf(catchSetResult)) { statements + catchSetResult }
IrCatchImpl(original.startOffset, original.endOffset, original.catchParameter, catchBlock)
@@ -713,7 +720,7 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
}
}
fun makeTempVar(type: KotlinType) =
fun makeTempVar(type: IrType) =
JsSymbolBuilder.buildTempVar(function.symbol, type, "tmp\$dcms\$${tmpVarCounter++}", true)
fun makeLoopLabel() = "\$l\$${tmpVarCounter++}"
@@ -782,7 +789,7 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
JsIrBuilder.buildBlock(unitType).also {
val elseBlock = if (originalBranch is IrElseBranch) null else it
val ifElseNode = IrIfThenElseImpl(
val ifElseNode = JsIrBuilder.buildIfElse(
originalBranch.startOffset,
originalBranch.endOffset,
unitType,
@@ -24,6 +24,8 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.toIrType
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
@@ -39,9 +41,9 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
private val callableToGetterFunction = mutableMapOf<CallableReferenceKey, IrFunction>()
private val collectedReferenceMap = mutableMapOf<CallableReferenceKey, IrCallableReference>()
private val callableNameConst = JsIrBuilder.buildString(context.irBuiltIns.string, Namer.KCALLABLE_NAME)
private val getterConst = JsIrBuilder.buildString(context.irBuiltIns.string, Namer.KPROPERTY_GET)
private val setterConst = JsIrBuilder.buildString(context.irBuiltIns.string, Namer.KPROPERTY_SET)
private val callableNameConst = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KCALLABLE_NAME)
private val getterConst = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KPROPERTY_GET)
private val setterConst = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KPROPERTY_SET)
private val newDeclarations = mutableListOf<IrDeclaration>()
@@ -97,7 +99,13 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
}
private fun redirectToFunction(callable: IrCallableReference, newTarget: IrFunction) =
IrCallImpl(callable.startOffset, callable.endOffset, newTarget.symbol, callable.origin).apply {
IrCallImpl(
callable.startOffset, callable.endOffset,
newTarget.symbol.owner.returnType,
newTarget.symbol,
newTarget.symbol.descriptor,
callable.origin
).apply {
copyTypeArgumentsFrom(callable)
var index = 0
callable.dispatchReceiver?.let { putValueArgument(index++, it) }
@@ -156,13 +164,13 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
val additionalDeclarations = generateGetterBodyWithGuard(refGetFunction) {
val irClosureReference = JsIrBuilder.buildFunctionReference(functionReference.type, refClosureFunction.symbol)
val irVarSymbol = JsSymbolBuilder.buildTempVar(refGetFunction.symbol, irClosureReference.type)
val irVar = JsIrBuilder.buildVar(irVarSymbol, irClosureReference)
val irVar = JsIrBuilder.buildVar(irVarSymbol, irClosureReference, type = irClosureReference.type)
// TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.)
val irSetName = JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
putValueArgument(1, callableNameConst)
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.string, getReferenceName(declaration.descriptor)))
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.stringType, getReferenceName(declaration.descriptor)))
}
Pair(listOf(irVar, irSetName), irVarSymbol)
}
@@ -203,10 +211,11 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
val statements = mutableListOf<IrStatement>()
val getterFunctionType = context.builtIns.getFunction(getterFunction.valueParameters.size + 1)
val irGetReference = JsIrBuilder.buildFunctionReference(getterFunctionType.defaultType, getterFunction.symbol)
val irVarSymbol = JsSymbolBuilder.buildTempVar(refGetFunction.symbol, getterFunctionType.defaultType)
val type = getterFunctionType.toIrType()
val irGetReference = JsIrBuilder.buildFunctionReference(type, getterFunction.symbol)
val irVarSymbol = JsSymbolBuilder.buildTempVar(refGetFunction.symbol, type)
statements += JsIrBuilder.buildVar(irVarSymbol, irGetReference)
statements += JsIrBuilder.buildVar(irVarSymbol, irGetReference, type = type)
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
@@ -216,7 +225,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
if (setterFunction != null) {
val setterFunctionType = context.builtIns.getFunction(setterFunction.valueParameters.size + 1)
val irSetReference = JsIrBuilder.buildFunctionReference(setterFunctionType.defaultType, setterFunction.symbol)
val irSetReference = JsIrBuilder.buildFunctionReference(setterFunctionType.toIrType(), setterFunction.symbol)
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
putValueArgument(1, setterConst)
@@ -228,7 +237,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
putValueArgument(1, callableNameConst)
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.string, getReferenceName(propertyReference.descriptor)))
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.stringType, getReferenceName(propertyReference.descriptor)))
}
Pair(statements, irVarSymbol)
@@ -255,22 +264,23 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
// }
//
val cacheName = "${getterFunction.name}_${Namer.KCALLABLE_CACHE_SUFFIX}"
val type = getterFunction.returnType
val cacheVarSymbol =
JsSymbolBuilder.buildVar(getterFunction.descriptor.containingDeclaration, getterFunction.returnType, cacheName, true)
val irNull = JsIrBuilder.buildNull(cacheVarSymbol.descriptor.type)
val irCacheDeclaration = JsIrBuilder.buildVar(cacheVarSymbol)
JsSymbolBuilder.buildVar(getterFunction.descriptor.containingDeclaration, type, cacheName, true)
val irNull = JsIrBuilder.buildNull(context.irBuiltIns.nothingNType)
val irCacheDeclaration = JsIrBuilder.buildVar(cacheVarSymbol, irNull, type = type)
val irCacheValue = JsIrBuilder.buildGetValue(cacheVarSymbol)
val irIfCondition = JsIrBuilder.buildCall(context.irBuiltIns.eqeqSymbol).apply {
putValueArgument(0, irCacheValue)
putValueArgument(1, irNull)
}
val irSetCache = JsIrBuilder.buildSetVariable(cacheVarSymbol, JsIrBuilder.buildGetValue(varSymbol))
val irSetCache = JsIrBuilder.buildSetVariable(cacheVarSymbol, JsIrBuilder.buildGetValue(varSymbol), context.irBuiltIns.unitType)
val thenStatements = mutableListOf<IrStatement>().apply {
addAll(bodyStatements)
add(irSetCache)
}
val irThenBranch = JsIrBuilder.buildBlock(context.irBuiltIns.unit, thenStatements)
val irIfNode = JsIrBuilder.buildIfElse(context.irBuiltIns.unit, irIfCondition, irThenBranch)
val irThenBranch = JsIrBuilder.buildBlock(context.irBuiltIns.unitType, thenStatements)
val irIfNode = JsIrBuilder.buildIfElse(context.irBuiltIns.unitType, irIfCondition, irThenBranch)
statements += irIfNode
returnValue = irCacheValue
returnStatements = listOf(irCacheDeclaration)
@@ -280,7 +290,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
returnStatements = emptyList()
}
statements += JsIrBuilder.buildReturn(getterFunction.symbol, returnValue)
statements += JsIrBuilder.buildReturn(getterFunction.symbol, returnValue, context)
getterFunction.body = JsIrBuilder.buildBlockBody(statements)
return returnStatements
@@ -314,8 +324,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
private fun buildGetFunction(declaration: IrFunction, reference: IrCallableReference, getterName: String): IrSimpleFunction {
val callableType = reference.type
val closureParams = callableType.arguments.dropLast(1) // drop return type
var kFunctionValueParamsCount = closureParams.size
var kFunctionValueParamsCount = (callableType as? IrSimpleType)?.arguments?.size?.minus(1) ?: 0
if (declaration.dispatchReceiverParameter != null && reference.dispatchReceiver == null) {
kFunctionValueParamsCount--
@@ -342,14 +351,22 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
val refGetSymbol = JsSymbolBuilder.buildSimpleFunction(declaration.descriptor.containingDeclaration, getterName).apply {
initialize(
valueParameters = getterValueParameters.mapIndexed { i, p -> p.descriptor.copyAsValueParameter(descriptor, i) },
type = callableType
returnType = callableType
)
}
return JsIrBuilder.buildFunction(refGetSymbol).apply {
return JsIrBuilder.buildFunction(refGetSymbol, callableType).apply {
for (i in 0 until getterValueParameters.size) {
val p = getterValueParameters[i]
valueParameters += IrValueParameterImpl(p.startOffset, p.endOffset, p.origin, refGetSymbol.descriptor.valueParameters[i])
valueParameters +=
IrValueParameterImpl(
p.startOffset,
p.endOffset,
p.origin,
refGetSymbol.descriptor.valueParameters[i],
p.type,
p.varargElementType
)
}
}
}
@@ -366,15 +383,18 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
val closureParamSymbols = generateSignatureForClosure(declaration, refGetFunction, refClosureSymbol, reference)
val closureParamDescriptors = closureParamSymbols.map { it.descriptor as ValueParameterDescriptor }
refClosureSymbol.initialize(valueParameters = closureParamDescriptors, type = declaration.returnType)
val returnType = declaration.returnType
refClosureSymbol.initialize(valueParameters = closureParamDescriptors, returnType = returnType)
val closureFunction = JsIrBuilder.buildFunction(refClosureSymbol)
val closureFunction = JsIrBuilder.buildFunction(refClosureSymbol, returnType)
for (it in closureParamSymbols) {
closureFunction.valueParameters += JsIrBuilder.buildValueParameter(it)
for (param in closureParamSymbols) {
// TODO always take type from param
val type = if (param.isBound) param.owner.type else context.irBuiltIns.anyType
closureFunction.valueParameters += JsIrBuilder.buildValueParameter(param, type)
}
val irCall = JsIrBuilder.buildCall(declaration.symbol)
val irCall = JsIrBuilder.buildCall(declaration.symbol, type = returnType)
var cp = 0
var gp = 0
@@ -401,7 +421,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
irCall.putValueArgument(j++, JsIrBuilder.buildGetValue(closureParamSymbols[i]))
}
val irClosureReturn = JsIrBuilder.buildReturn(closureFunction.symbol, irCall)
val irClosureReturn = JsIrBuilder.buildReturn(closureFunction.symbol, irCall, context)
closureFunction.body = JsIrBuilder.buildBlockBody(listOf(irClosureReturn))
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.backend.common.utils.isSubtypeOfClass
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
@@ -19,10 +19,10 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.SimpleType
class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileLoweringPass {
@@ -33,16 +33,13 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
private val symbolToIrFunction: Map<IrFunctionSymbol, IrSimpleFunction>
private val nameToIrTransformer: Map<Name, (IrCall) -> IrCall>
val kCallable = context.builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kCallable.toSafe())
val kProperty = context.builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kProperty.asSingleFqName())
init {
memberToIrFunction = mutableMapOf()
symbolToIrFunction = mutableMapOf()
memberToTransformer = mutableMapOf()
nameToIrTransformer = mutableMapOf()
val primitiveNumbers = context.irBuiltIns.run { listOf(int, short, byte, float, double) }
val primitiveNumbers = context.irBuiltIns.run { listOf(intType, shortType, byteType, floatType, doubleType) }
memberToIrFunction.run {
for (type in primitiveNumbers) {
@@ -57,11 +54,11 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
op(type, OperatorNames.REM, context.intrinsics.jsMod)
}
context.irBuiltIns.string.let {
context.irBuiltIns.stringType.let {
op(it, OperatorNames.ADD, context.intrinsics.jsPlus)
}
context.irBuiltIns.int.let {
context.irBuiltIns.intType.let {
op(it, OperatorNames.SHL, context.intrinsics.jsBitShiftL)
op(it, OperatorNames.SHR, context.intrinsics.jsBitShiftR)
op(it, OperatorNames.SHRU, context.intrinsics.jsBitShiftRU)
@@ -71,7 +68,7 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
op(it, OperatorNames.INV, context.intrinsics.jsBitNot)
}
context.irBuiltIns.bool.let {
context.irBuiltIns.booleanType.let {
op(it, OperatorNames.AND, context.intrinsics.jsBitAnd)
op(it, OperatorNames.OR, context.intrinsics.jsBitOr)
op(it, OperatorNames.NOT, context.intrinsics.jsNot)
@@ -99,12 +96,12 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
// TODO: use increment and decrement when it's possible
op(type, OperatorNames.INC) {
irCall(it, context.intrinsics.jsPlus.symbol, dispatchReceiverAsFirstArgument = true).apply {
putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.int, 1))
putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.intType, 1))
}
}
op(type, OperatorNames.DEC) {
irCall(it, context.intrinsics.jsMinus.symbol, dispatchReceiverAsFirstArgument = true).apply {
putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.int, 1))
putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.intType, 1))
}
}
}
@@ -113,18 +110,18 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
nameToIrTransformer.run {
addWithPredicate(
Name.special(Namer.KCALLABLE_GET_NAME),
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { DescriptorUtils.isSubtypeOfClass(type, kCallable) } ?: false },
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { type.isSubtypeOfClass(context.irBuiltIns.kCallableClass) } ?: false },
{ call -> irCall(call, context.intrinsics.jsName.symbol, dispatchReceiverAsFirstArgument = true) })
addWithPredicate(
Name.identifier(Namer.KPROPERTY_GET),
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { DescriptorUtils.isSubtypeOfClass(type, kProperty) } ?: false },
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { type.isSubtypeOfClass(context.irBuiltIns.kPropertyClass) } ?: false },
{ call -> irCall(call, context.intrinsics.jsPropertyGet.symbol, dispatchReceiverAsFirstArgument = true)}
)
addWithPredicate(
Name.identifier(Namer.KPROPERTY_SET),
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { DescriptorUtils.isSubtypeOfClass(type, kProperty) } ?: false},
{ call -> call.symbol.owner.dispatchReceiverParameter?.run { type.isSubtypeOfClass(context.irBuiltIns.kPropertyClass) } ?: false},
{ call -> irCall(call, context.intrinsics.jsPropertySet.symbol, dispatchReceiverAsFirstArgument = true)}
)
}
@@ -207,12 +204,11 @@ private fun IrCall.copyTypeAndValueArgumentsFrom(call: IrCall, dispatchReceiverA
}
}
private fun <V> MutableMap<SimpleMemberKey, V>.op(type: KotlinType, name: Name, v: V) {
private fun <V> MutableMap<SimpleMemberKey, V>.op(type: IrType, name: Name, v: V) {
put(SimpleMemberKey(type, name), v)
}
// TODO issue: marked as unused, but used; rename works wrongly.
private fun <V> MutableMap<SimpleMemberKey, V>.op(type: KotlinType, name: String, v: V) {
private fun <V> MutableMap<SimpleMemberKey, V>.op(type: IrType, name: String, v: V) {
put(SimpleMemberKey(type, Name.identifier(name)), v)
}
@@ -232,4 +228,23 @@ private fun <K> MutableMap<K, (IrCall) -> IrCall>.addWithPredicate(from: K, pred
private inline fun <T> select(crossinline predicate: () -> Boolean, crossinline ifTrue: () -> T, crossinline ifFalse: () -> T): T = if (predicate()) ifTrue() else ifFalse()
private data class SimpleMemberKey(val klass: KotlinType, val name: Name)
private class SimpleMemberKey(val klass: IrType, val name: Name) {
// TODO drop custom equals and hashCode when IrTypes will have right equals
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as SimpleMemberKey
if (name != other.name) return false
if (klass.originalKotlinType != other.klass.originalKotlinType) return false
return true
}
override fun hashCode(): Int {
var result = klass.originalKotlinType?.hashCode() ?: 0
result = 31 * result + name.hashCode()
return result
}
}
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.utils.commonSupertype
import org.jetbrains.kotlin.backend.common.utils.isSubtypeOf
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
@@ -18,11 +20,10 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCatchImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrElseBranchImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.types.IrDynamicType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.types.CommonSupertypes
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
/**
* Since JS does not support multiple catch blocks by default we should replace them with similar `when` statement, so
@@ -49,9 +50,9 @@ import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
*/
class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPass {
val litTrue = JsIrBuilder.buildBoolean(context.irBuiltIns.bool, true)
val unitType = context.irBuiltIns.unit
val nothingType = context.irBuiltIns.nothing
val litTrue = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
val unitType = context.irBuiltIns.unitType
val nothingType = context.irBuiltIns.nothingType
override fun lower(irFile: IrFile) {
irFile.transformChildren(object : IrElementTransformer<IrDeclaration?> {
@@ -67,7 +68,7 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
val commonType = mergeTypes(aTry.catches.map { it.catchParameter.type })
val pendingExceptionSymbol = JsSymbolBuilder.buildVar(data!!.descriptor, commonType, "\$pending\$", false)
val pendingExceptionDeclaration = JsIrBuilder.buildVar(pendingExceptionSymbol)
val pendingExceptionDeclaration = JsIrBuilder.buildVar(pendingExceptionSymbol, type = commonType)
val pendingException = JsIrBuilder.buildGetValue(pendingExceptionSymbol)
val branches = mutableListOf<IrBranch>()
@@ -75,24 +76,27 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
for (catch in aTry.catches) {
assert(!catch.catchParameter.isVar) { "caught exception parameter has to immutable" }
val type = catch.catchParameter.type
val typeSymbol = context.symbolTable.referenceClassifier(type.constructor.declarationDescriptor!!)
val castedPendingException = buildImplicitCast(pendingException, type, typeSymbol)
val typeSymbol = type.classifierOrNull
val catchBody = catch.result.transform(object : IrElementTransformer<VariableDescriptor> {
override fun visitGetValue(expression: IrGetValue, data: VariableDescriptor) =
if (expression.descriptor == data) castedPendingException else expression
if (typeSymbol != null && expression.descriptor == data)
// TODO how is it good to generate implicit cast for each access?
buildImplicitCast(pendingException, type, typeSymbol)
else
expression
}, catch.parameter)
if (type.isDynamic()) {
if (type is IrDynamicType) {
branches += IrElseBranchImpl(catch.startOffset, catch.endOffset, litTrue, catchBody)
break
} else {
val typeCheck = buildIsCheck(pendingException, type, typeSymbol)
val typeCheck = buildIsCheck(pendingException, type, typeSymbol!!)
branches += IrBranchImpl(catch.startOffset, catch.endOffset, typeCheck, catchBody)
}
}
if (!commonType.isDynamic()) {
if (commonType !is IrDynamicType) {
val throwStatement = JsIrBuilder.buildThrow(nothingType, pendingException)
branches += IrElseBranchImpl(litTrue, JsIrBuilder.buildBlock(nothingType, listOf(throwStatement)))
}
@@ -106,14 +110,14 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
return aTry.run { IrTryImpl(startOffset, endOffset, type, tryResult, listOf(newCatch), finallyExpression) }
}
private fun buildIsCheck(value: IrExpression, toType: KotlinType, toTypeSymbol: IrClassifierSymbol) =
JsIrBuilder.buildTypeOperator(context.irBuiltIns.bool, IrTypeOperator.INSTANCEOF, value, toType, toTypeSymbol)
private fun buildIsCheck(value: IrExpression, toType: IrType, toTypeSymbol: IrClassifierSymbol) =
JsIrBuilder.buildTypeOperator(context.irBuiltIns.booleanType, IrTypeOperator.INSTANCEOF, value, toType, toTypeSymbol)
private fun buildImplicitCast(value: IrExpression, toType: KotlinType, toTypeSymbol: IrClassifierSymbol) =
private fun buildImplicitCast(value: IrExpression, toType: IrType, toTypeSymbol: IrClassifierSymbol) =
JsIrBuilder.buildTypeOperator(toType, IrTypeOperator.IMPLICIT_CAST, value, toType, toTypeSymbol)
private fun mergeTypes(types: List<KotlinType>) = CommonSupertypes.commonSupertype(types).also {
assert(it.isSubtypeOf(context.builtIns.throwable.defaultType) || it.isDynamic())
private fun mergeTypes(types: List<IrType>) = types.commonSupertype().also {
assert(it.isSubtypeOf(context.irBuiltIns.throwableType) || it is IrDynamicType)
}
}, null)
@@ -26,6 +26,8 @@ import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -72,8 +74,9 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) : IrElementTransfor
// val t = Object.create(Foo.prototype);
// return Foo_init_$Init$(..., t)
// }
val newInitConstructor = createInitConstructor(declaration, constructorName)
val newCreateConstructor = createCreateConstructor(declaration, newInitConstructor, constructorName)
val newInitConstructor = createInitConstructor(declaration, constructorName, irClass.defaultType)
val newCreateConstructor = createCreateConstructor(declaration, newInitConstructor, constructorName, irClass.defaultType)
oldCtorToNewMap[declaration.symbol] =
JsIrBackendContext.SecondaryCtorPair(newInitConstructor.symbol, newCreateConstructor.symbol)
@@ -95,14 +98,16 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) : IrElementTransfor
override fun visitReturn(expression: IrReturn): IrExpression = IrReturnImpl(
expression.startOffset,
expression.endOffset,
expression.type,
function,
IrGetValueImpl(expression.startOffset, expression.endOffset, thisSymbol)
IrGetValueImpl(expression.startOffset, expression.endOffset, thisSymbol.owner.type, thisSymbol)
)
override fun visitGetValue(expression: IrGetValue): IrExpression =
if (expression.descriptor.name.isSpecial && expression.descriptor.name.asString() == Namer.THIS_SPECIAL_NAME) IrGetValueImpl(
expression.startOffset,
expression.endOffset,
expression.type,
thisSymbol,
expression.origin
) else {
@@ -110,28 +115,32 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) : IrElementTransfor
}
}
private fun createInitConstructor(declaration: IrConstructor, name: String): IrSimpleFunction =
private fun createInitConstructor(
declaration: IrConstructor,
name: String,
type: IrType
): IrSimpleFunction =
JsSymbolBuilder.copyFunctionSymbol(declaration.symbol, "${name}_\$Init\$").let {
val thisSymbol =
JsSymbolBuilder.buildValueParameter(it, declaration.valueParameters.size, declaration.returnType, "\$this")
JsSymbolBuilder.buildValueParameter(it, declaration.valueParameters.size, type, "\$this")
it.initialize(
dispatchParameterDescriptor = declaration.descriptor.dispatchReceiverParameter,
typeParameters = declaration.descriptor.typeParameters,
valueParameters = declaration.descriptor.valueParameters + thisSymbol.descriptor as ValueParameterDescriptor,
type = declaration.descriptor.returnType,
returnType = type,
modality = declaration.descriptor.modality,
visibility = declaration.descriptor.visibility
)
val thisParam = JsIrBuilder.buildValueParameter(thisSymbol)
val thisParam = JsIrBuilder.buildValueParameter(thisSymbol, type)
return IrFunctionImpl(
declaration.startOffset, declaration.endOffset,
declaration.origin, it
).apply {
val retStmt = JsIrBuilder.buildReturn(it, JsIrBuilder.buildGetValue(thisSymbol))
val retStmt = JsIrBuilder.buildReturn(it, JsIrBuilder.buildGetValue(thisSymbol), context)
val statements = (declaration.body as IrStatementContainer).statements
valueParameters += (declaration.valueParameters + thisParam)
@@ -145,13 +154,13 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) : IrElementTransfor
}
private fun createCreateConstructor(ctorOrig: IrConstructor, ctorImpl: IrSimpleFunction, name: String): IrSimpleFunction =
private fun createCreateConstructor(ctorOrig: IrConstructor, ctorImpl: IrSimpleFunction, name: String, type: IrType): IrSimpleFunction =
JsSymbolBuilder.copyFunctionSymbol(ctorOrig.symbol, "${name}_\$Create\$").let {
it.initialize(
dispatchParameterDescriptor = ctorOrig.descriptor.dispatchReceiverParameter,
typeParameters = ctorOrig.descriptor.typeParameters,
valueParameters = ctorOrig.descriptor.valueParameters,
type = ctorOrig.returnType,
returnType = type,
modality = ctorOrig.descriptor.modality,
visibility = ctorOrig.visibility
)
@@ -165,14 +174,14 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) : IrElementTransfor
typeParameters += ctorOrig.typeParameters
// parent = ctorOrig.parent
val returnType = ctorOrig.returnType
val returnType = type
val createFunctionIntrinsic = context.intrinsics.jsObjectCreate
val irCreateCall = JsIrBuilder.buildCall(
createFunctionIntrinsic.symbol,
returnType,
mapOf(createFunctionIntrinsic.typeParameters[0].descriptor to returnType)
listOf(returnType)
)
val irDelegateCall = JsIrBuilder.buildCall(ctorImpl.symbol).also {
val irDelegateCall = JsIrBuilder.buildCall(ctorImpl.symbol, type).also {
for (i in 0 until valueParameters.size) {
it.putValueArgument(i, JsIrBuilder.buildGetValue(valueParameters[i].symbol))
}
@@ -181,7 +190,7 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) : IrElementTransfor
// typeParameters.mapIndexed { i, t -> ctorImpl.typeParameters[i].descriptor -> }
}
val irReturn = JsIrBuilder.buildReturn(it, irDelegateCall)
val irReturn = JsIrBuilder.buildReturn(it, irDelegateCall, context)
body = JsIrBuilder.buildBlockBody(listOf(irReturn))
@@ -233,10 +242,11 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) : IrElementTransfor
IrGetValueImpl(
expression.startOffset,
expression.endOffset,
expression.type,
IrValueParameterSymbolImpl(LazyClassReceiverParameterDescriptor(target.descriptor.containingDeclaration))
)
} else {
IrGetValueImpl(expression.startOffset, expression.endOffset, ownerFunc.valueParameters.last().symbol)
IrGetValueImpl(expression.startOffset, expression.endOffset, expression.type, ownerFunc.valueParameters.last().symbol)
}
newCall.putValueArgument(expression.valueArgumentsCount, readThis)
@@ -247,7 +257,7 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) : IrElementTransfor
private fun redirectCall(
call: IrFunctionAccessExpression,
newTarget: IrSimpleFunctionSymbol
) = IrCallImpl(call.startOffset, call.endOffset, newTarget).apply {
) = IrCallImpl(call.startOffset, call.endOffset, call.type, newTarget).apply {
copyTypeArgumentsFrom(call)
@@ -6,35 +6,34 @@
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.isFunctionOrKFunctionType
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.backend.common.utils.*
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrArithBuilder
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder
import org.jetbrains.kotlin.ir.backend.js.utils.isReified
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.isNullable
import org.jetbrains.kotlin.types.typeUtil.*
class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
private val unit = context.builtIns.unit
private val unitValue = JsIrBuilder.buildGetObjectValue(unit.defaultType, context.symbolTable.referenceClass(unit))
private val unit = context.irBuiltIns.unitType
private val unitValue = JsIrBuilder.buildGetObjectValue(unit, unit.classifierOrFail as IrClassSymbol)
private val lit24 = JsIrBuilder.buildInt(context.builtIns.intType, 24)
private val lit16 = JsIrBuilder.buildInt(context.builtIns.intType, 16)
private val lit24 = JsIrBuilder.buildInt(context.irBuiltIns.intType, 24)
private val lit16 = JsIrBuilder.buildInt(context.irBuiltIns.intType, 16)
private val byteMask = JsIrBuilder.buildInt(context.builtIns.intType, 0xFF)
private val shortMask = JsIrBuilder.buildInt(context.builtIns.intType, 0xFFFF)
private val byteMask = JsIrBuilder.buildInt(context.irBuiltIns.intType, 0xFF)
private val shortMask = JsIrBuilder.buildInt(context.irBuiltIns.intType, 0xFFFF)
private val calculator = JsIrArithBuilder(context)
@@ -53,13 +52,13 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
private val typeOfIntrinsicSymbol = context.intrinsics.jsTypeOf.symbol
private val toJSTypeIntrinsicSymbol = context.intrinsics.jsToJsType.symbol
private val stringMarker = JsIrBuilder.buildString(context.irBuiltIns.string, "string")
private val booleanMarker = JsIrBuilder.buildString(context.irBuiltIns.string, "boolean")
private val functionMarker = JsIrBuilder.buildString(context.irBuiltIns.string, "function")
private val numberMarker = JsIrBuilder.buildString(context.irBuiltIns.string, "number")
private val stringMarker = JsIrBuilder.buildString(context.irBuiltIns.stringType, "string")
private val booleanMarker = JsIrBuilder.buildString(context.irBuiltIns.stringType, "boolean")
private val functionMarker = JsIrBuilder.buildString(context.irBuiltIns.stringType, "function")
private val numberMarker = JsIrBuilder.buildString(context.irBuiltIns.stringType, "number")
private val litTrue: IrExpression = JsIrBuilder.buildBoolean(context.irBuiltIns.bool, true)
private val litNull: IrExpression = JsIrBuilder.buildNull(context.builtIns.nullableNothingType)
private val litTrue: IrExpression = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
private val litNull: IrExpression = JsIrBuilder.buildNull(context.irBuiltIns.nothingNType)
private fun getInternalFunction(name: String) = context.symbolTable.referenceSimpleFunction(context.getInternalFunctions(name).single())
@@ -126,16 +125,21 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
}
// Note: native `instanceOf` is not used which is important because of null-behaviour
private fun advancedCheckRequired(type: KotlinType) = type.isInterface() ||
KotlinBuiltIns.isArray(type) ||
KotlinBuiltIns.isPrimitiveArray(type) ||
private fun advancedCheckRequired(type: IrType) = type.isInterface() ||
type.isArray() ||
type.isPrimitiveArray() ||
isTypeOfCheckingType(type)
private fun isTypeOfCheckingType(type: KotlinType) =
((type.isPrimitiveNumberType() || KotlinBuiltIns.isNumber(type)) && !type.isLong() && !type.isChar()) ||
private fun isTypeOfCheckingType(type: IrType) =
type.isByte() ||
type.isShort() ||
type.isInt() ||
type.isFloat() ||
type.isDouble() ||
type.isNumber() ||
type.isBoolean() ||
type.isFunctionOrKFunctionType ||
KotlinBuiltIns.isString(type)
type.isFunctionOrKFunction() ||
type.isString()
fun lowerInstanceOf(
expression: IrTypeOperatorCall,
@@ -146,7 +150,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
assert((expression.operator == IrTypeOperator.NOT_INSTANCEOF) == inverted)
val toType = expression.typeOperand
val isCopyRequired = expression.argument.type.isNullable() && advancedCheckRequired(toType.makeNotNullable())
val isCopyRequired = expression.argument.type.isNullable() && advancedCheckRequired(toType.makeNotNull())
val newStatements = mutableListOf<IrStatement>()
val argument =
@@ -167,12 +171,12 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
private fun cacheValue(value: IrExpression, newStatements: MutableList<IrStatement>, cd: DeclarationDescriptor): IrExpression {
val varSymbol = JsSymbolBuilder.buildTempVar(cd, value.type, mutable = false)
newStatements += JsIrBuilder.buildVar(varSymbol, value)
newStatements += JsIrBuilder.buildVar(varSymbol, value, value.type)
return JsIrBuilder.buildGetValue(varSymbol)
}
private fun generateTypeCheck(argument: IrExpression, toType: KotlinType): IrExpression {
val toNotNullable = toType.makeNotNullable()
private fun generateTypeCheck(argument: IrExpression, toType: IrType): IrExpression {
val toNotNullable = toType.makeNotNull()
val instanceCheck = generateTypeCheckNonNull(argument, toNotNullable)
val isFromNullable = argument.type.isNullable()
val isToNullable = toType.isNullable()
@@ -190,14 +194,14 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
}
}
private fun generateTypeCheckNonNull(argument: IrExpression, toType: KotlinType): IrExpression {
assert(!toType.isMarkedNullable)
private fun generateTypeCheckNonNull(argument: IrExpression, toType: IrType): IrExpression {
assert(!toType.isMarkedNullable())
return when {
KotlinBuiltIns.isAny(toType) -> generateIsObjectCheck(argument)
toType.isAny() -> generateIsObjectCheck(argument)
isTypeOfCheckingType(toType) -> generateTypeOfCheck(argument, toType)
toType.isChar() -> generateCheckForChar(argument)
KotlinBuiltIns.isArray(toType) -> generateGenericArrayCheck(argument)
KotlinBuiltIns.isPrimitiveArray(toType) -> generatePrimitiveArrayTypeCheck(argument, toType)
toType.isArray() -> generateGenericArrayCheck(argument)
toType.isPrimitiveArray() -> generatePrimitiveArrayTypeCheck(argument, toType)
toType.isTypeParameter() -> generateTypeCheckWithTypeParameter(argument, toType)
toType.isInterface() -> generateInterfaceCheck(argument, toType)
else -> generateNativeInstanceOf(argument, toType)
@@ -208,12 +212,14 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
putValueArgument(0, argument)
}
private fun generateTypeCheckWithTypeParameter(argument: IrExpression, toType: KotlinType): IrExpression {
val typeParameterDescriptor = toType.constructor.declarationDescriptor as TypeParameterDescriptor
assert(!typeParameterDescriptor.isReified) { "reified parameters have to be lowered before" }
private fun generateTypeCheckWithTypeParameter(argument: IrExpression, toType: IrType): IrExpression {
val typeParameter =
(toType.classifierOrNull as? IrTypeParameterSymbol)?.owner ?: error("expected type parameter, but $toType")
return typeParameterDescriptor.upperBounds.fold(litTrue) { r, t ->
val check = generateTypeCheckNonNull(argument, t.makeNotNullable())
assert(!typeParameter.isReified) { "reified parameters have to be lowered before" }
return typeParameter.superTypes.fold(litTrue) { r, t ->
val check = generateTypeCheckNonNull(argument, t.makeNotNull())
calculator.and(r, check)
}
}
@@ -221,11 +227,11 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
private fun generateCheckForChar(argument: IrExpression) =
JsIrBuilder.buildCall(isCharSymbol).apply { dispatchReceiver = argument }
private fun generateTypeOfCheck(argument: IrExpression, toType: KotlinType): IrExpression {
private fun generateTypeOfCheck(argument: IrExpression, toType: IrType): IrExpression {
val marker = when {
toType.isFunctionOrKFunctionType -> functionMarker
toType.isFunctionOrKFunction() -> functionMarker
toType.isBoolean() -> booleanMarker
KotlinBuiltIns.isString(toType) -> stringMarker
toType.isString() -> stringMarker
else -> numberMarker
}
@@ -236,17 +242,17 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
}
}
private fun wrapTypeReference(toType: KotlinType) =
private fun wrapTypeReference(toType: IrType) =
JsIrBuilder.buildCall(toJSTypeIntrinsicSymbol).apply { putTypeArgument(0, toType) }
private fun generateGenericArrayCheck(argument: IrExpression) =
JsIrBuilder.buildCall(isArraySymbol).apply { putValueArgument(0, argument) }
private fun generatePrimitiveArrayTypeCheck(argument: IrExpression, toType: KotlinType): IrExpression {
private fun generatePrimitiveArrayTypeCheck(argument: IrExpression, toType: IrType): IrExpression {
TODO("Implement Typed Array check")
}
private fun generateInterfaceCheck(argument: IrExpression, toType: KotlinType): IrExpression {
private fun generateInterfaceCheck(argument: IrExpression, toType: IrType): IrExpression {
val irType = wrapTypeReference(toType)
return JsIrBuilder.buildCall(isInterfaceSymbol).apply {
putValueArgument(0, argument)
@@ -254,7 +260,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
}
}
private fun generateNativeInstanceOf(argument: IrExpression, toType: KotlinType): IrExpression {
private fun generateNativeInstanceOf(argument: IrExpression, toType: IrType): IrExpression {
val irType = wrapTypeReference(toType)
return JsIrBuilder.buildCall(instanceOfIntrinsicSymbol).apply {
putValueArgument(0, argument)
@@ -264,12 +270,12 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
private fun lowerCoercionToUnit(expression: IrTypeOperatorCall): IrExpression {
assert(expression.operator === IrTypeOperator.IMPLICIT_COERCION_TO_UNIT)
return expression.run { IrCompositeImpl(startOffset, endOffset, unit.defaultType, null, listOf(argument, unitValue)) }
return expression.run { IrCompositeImpl(startOffset, endOffset, unit, null, listOf(argument, unitValue)) }
}
private fun lowerIntegerCoercion(expression: IrTypeOperatorCall, containingDeclaration: DeclarationDescriptor): IrExpression {
assert(expression.operator === IrTypeOperator.IMPLICIT_INTEGER_COERCION)
assert(KotlinBuiltIns.isInt(expression.argument.type))
assert(expression.argument.type.isInt())
val isNullable = expression.argument.type.isNullable()
val toType = expression.typeOperand
@@ -284,9 +290,9 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
if (isNullable) cacheValue(expression.argument, newStatements, containingDeclaration) else expression.argument
val casted = when {
KotlinBuiltIns.isByte(toType) -> maskOp(argument, byteMask, lit24)
KotlinBuiltIns.isShort(toType) -> maskOp(argument, shortMask, lit16)
KotlinBuiltIns.isLong(toType) -> TODO("Long coercion")
toType.isByte() -> maskOp(argument, byteMask, lit24)
toType.isShort() -> maskOp(argument, shortMask, lit16)
toType.isLong() -> TODO("Long coercion")
else -> error("Unreachable execution (coercion to non-Integer type")
}
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.createClassSymbolOrNull
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.DeepCopyIrTree
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -34,7 +35,6 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.makeNullable
// backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt
@@ -479,7 +479,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
return IrCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = newDescriptor.returnType!!,
type = newDescriptor.returnType?.toIrType()!!,
descriptor = newDescriptor,
typeArgumentsCount = expression.typeArgumentsCount,
origin = expression.origin,
@@ -517,7 +517,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
//---------------------------------------------------------------------//
fun getTypeOperatorReturnType(operator: IrTypeOperator, type: KotlinType) : KotlinType {
fun getTypeOperatorReturnType(operator: IrTypeOperator, type: IrType) : IrType {
return when (operator) {
IrTypeOperator.CAST,
IrTypeOperator.IMPLICIT_CAST,
@@ -526,7 +526,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> type
IrTypeOperator.SAFE_CAST -> type.makeNullable()
IrTypeOperator.INSTANCEOF,
IrTypeOperator.NOT_INSTANCEOF -> context.builtIns.booleanType
IrTypeOperator.NOT_INSTANCEOF -> context.irBuiltIns.booleanType
}
}
@@ -541,7 +541,8 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
type = returnType,
operator = expression.operator,
typeOperand = typeOperand,
argument = expression.argument.transform(this, null)
argument = expression.argument.transform(this, null),
typeOperandClassifier = typeOperand.classifierOrFail
)
}
@@ -610,6 +611,8 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
//-------------------------------------------------------------------------//
private fun substituteType(oldType: IrType?): IrType? = substituteType(oldType?.toKotlinType())?.toIrType()
private fun substituteType(oldType: KotlinType?): KotlinType? {
if (typeSubstitutor == null) return oldType
if (oldType == null) return oldType
@@ -699,7 +702,8 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<
endOffset = declaration.endOffset,
origin = declaration.origin,
descriptor = newDescriptor,
initializer = declaration.initializer
initializer = declaration.initializer,
type = declaration.type
)
}
@@ -715,7 +719,8 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<
startOffset = expression.startOffset,
endOffset = expression.endOffset,
origin = expression.origin,
symbol = createValueSymbol(newDescriptor)
symbol = createValueSymbol(newDescriptor),
type = expression.type
)
}
@@ -732,7 +737,7 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<
return IrCallImpl(
startOffset = oldExpression.startOffset,
endOffset = oldExpression.endOffset,
type = newDescriptor.returnType!!,
type = oldExpression.type,
symbol = createFunctionSymbol(newDescriptor),
descriptor = newDescriptor,
typeArgumentsCount = oldExpression.typeArgumentsCount,
@@ -763,4 +768,3 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<
return oldExpression.shallowCopy(oldExpression.origin, createFunctionSymbol(newDescriptor), oldExpression.superQualifierSymbol)
}
}
@@ -23,14 +23,16 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.getDefault
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.TypeProjection
@@ -149,8 +151,8 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original
val constructorCall = irCall(delegatingConstructorCall.symbol,
constructorDescriptor.typeParameters.associate { it to delegatingConstructorCall.getTypeArgument(it)!! }).apply {
val constructorCall = irCall(delegatingConstructorCall.symbol).apply {
constructorDescriptor.typeParameters.forEach() { putTypeArgument(it.index, delegatingConstructorCall.getTypeArgument(it)!!) }
constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) }
}
val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter
@@ -159,12 +161,12 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this"
)
statements[0] = newThis
substituteMap[oldThis] = irGet(newThis.symbol)
statements.add(irReturn(irGet(newThis.symbol)))
substituteMap[oldThis] = irGet(newThis)
statements.add(irReturn(irGet(newThis)))
}
}
val returnType = copyFunctionDeclaration.descriptor.returnType!! // Substituted return type.
val returnType = copyFunctionDeclaration.returnType // Substituted return type.
val sourceFileName = context.originalModuleIndex.declarationToFile[caller.descriptor.original] ?: ""
val inlineFunctionBody = IrReturnableBlockImpl( // Create new IR element to replace "call".
startOffset = startOffset,
@@ -248,7 +250,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val substitutionContext = mutableMapOf<TypeConstructor, TypeProjection>()
for (index in 0 until irCall.typeArgumentsCount) {
val typeArgument = irCall.getTypeArgument(index) ?: continue
substitutionContext[typeParameters[index].typeConstructor] = TypeProjectionImpl(typeArgument)
substitutionContext[typeParameters[index].typeConstructor] = TypeProjectionImpl(typeArgument.toKotlinType())
}
return TypeSubstitutor.create(substitutionContext)
}
@@ -309,7 +311,8 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
}
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
functionDescriptor.valueParameters.forEach { parameterDescriptor -> // Iterate value parameter descriptors.
irFunction.valueParameters.forEach { parameter -> // Iterate value parameter descriptors.
val parameterDescriptor = parameter.descriptor as ValueParameterDescriptor
val argument = valueArguments[parameterDescriptor.index] // Get appropriate argument from call site.
when {
argument != null -> { // Argument is good enough.
@@ -331,8 +334,8 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val emptyArray = IrVarargImpl(
startOffset = irCall.startOffset,
endOffset = irCall.endOffset,
type = parameterDescriptor.type,
varargElementType = parameterDescriptor.varargElementType!!
type = parameter.type,
varargElementType = parameter.varargElementType!!
)
parameterToArgument += ParameterToArgument(
parameterDescriptor = parameterDescriptor,
@@ -377,7 +380,8 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val getVal = IrGetValueImpl( // Create new expression, representing access the new variable.
startOffset = currentScope.irElement.startOffset,
endOffset = currentScope.irElement.endOffset,
symbol = createValueSymbol(newVariable.descriptor)
type = newVariable.type,
symbol = newVariable.symbol
)
substituteMap[parameterDescriptor] = getVal // Parameter will be replaced with the new variable.
}
@@ -11,12 +11,13 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.lower.inline.addChildren
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrReturnTargetSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.toIrType
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.visitors.*
@@ -51,7 +52,11 @@ internal fun IrModuleFragment.replaceUnboundSymbols(context: JsIrBackendContext)
// Generate missing external stubs:
// TODO: ModuleGenerator::generateUnboundSymbolsAsDependencies(IRModuleFragment) is private function :/
@Suppress("DEPRECATION")
ExternalDependenciesGenerator(symbolTable = context.symbolTable, irBuiltIns = context.irBuiltIns).generateUnboundSymbolsAsDependencies(this)
ExternalDependenciesGenerator(
descriptor,
symbolTable = context.symbolTable,
irBuiltIns = context.irBuiltIns
).generateUnboundSymbolsAsDependencies(this)
// Merge duplicated module and package declarations:
this.acceptVoid(object : IrElementVisitorVoid {
@@ -161,7 +166,7 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrGetValueImpl(startOffset, endOffset, symbol, origin)
IrGetValueImpl(startOffset, endOffset, expression.type, symbol, origin)
}
}
@@ -170,13 +175,13 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrSetVariableImpl(startOffset, endOffset, symbol, value, origin)
IrSetVariableImpl(startOffset, endOffset, expression.type, symbol, value, origin)
}
}
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceClass) ?:
return super.visitGetObjectValue(expression)
return super.visitGetObjectValue(expression)
expression.transformChildrenVoid(this)
return with(expression) {
@@ -186,7 +191,7 @@ private class IrUnboundSymbolReplacer(
override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceEnumEntry) ?:
return super.visitGetEnumValue(expression)
return super.visitGetEnumValue(expression)
expression.transformChildrenVoid(this)
return with(expression) {
@@ -200,17 +205,11 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrClassReferenceImpl(startOffset, endOffset, type, symbol, symbol.descriptor.defaultType)
IrClassReferenceImpl(startOffset, endOffset, type, symbol, symbol.descriptor.toIrType())
}
}
override fun visitClass(declaration: IrClass): IrStatement {
declaration.superClasses.forEachIndexed { index, symbol ->
val newSymbol = symbol.replace(SymbolTable::referenceClass)
if (newSymbol != null) {
declaration.superClasses[index] = newSymbol
}
}
withLocal(declaration.thisReceiver?.symbol) {
return super.visitClass(declaration)
}
@@ -227,7 +226,7 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrGetFieldImpl(startOffset, endOffset, symbol, receiver, origin, superQualifierSymbol)
IrGetFieldImpl(startOffset, endOffset, symbol, type, receiver, origin, superQualifierSymbol)
}
}
@@ -242,11 +241,13 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrSetFieldImpl(startOffset, endOffset, symbol, receiver, value, origin, superQualifierSymbol)
IrSetFieldImpl(startOffset, endOffset, symbol, receiver, value, type /*wrong*/, origin, superQualifierSymbol)
}
}
override fun visitCall(expression: IrCall): IrExpression {
expression.replaceTypeArguments()
val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?: expression.symbol
val superQualifierSymbol = expression.superQualifierSymbol?.replaceOrSame(SymbolTable::referenceClass)
@@ -257,17 +258,21 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid()
return with(expression) {
IrCallImpl(startOffset, endOffset, symbol, descriptor,
getTypeArgumentsMap(),
origin, superQualifierSymbol).also {
IrCallImpl(startOffset, endOffset, type, symbol, descriptor,
typeArgumentsCount,
origin, superQualifierSymbol).also {
it.copyArgumentsFrom(this)
it.copyTypeArgumentsFrom(this)
}
}
}
private fun IrMemberAccessExpression.getTypeArgumentsMap() =
descriptor.original.typeParameters.associate { it to getTypeArgumentOrDefault(it) }
private fun IrMemberAccessExpression.replaceTypeArguments() {
repeat(typeArgumentsCount) {
putTypeArgument(it, getTypeArgument(it)/*?.toKotlinType()?.let { context.ir.translateErased(it) }*/)
}
}
private fun IrMemberAccessExpressionBase.copyArgumentsFrom(original: IrMemberAccessExpression) {
dispatchReceiver = original.dispatchReceiver
@@ -279,40 +284,48 @@ private class IrUnboundSymbolReplacer(
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression {
val symbol = expression.symbol.replace(SymbolTable::referenceConstructor) ?:
return super.visitEnumConstructorCall(expression)
return super.visitEnumConstructorCall(expression)
return with(expression) {
IrEnumConstructorCallImpl(startOffset, endOffset, symbol, null).also {
IrEnumConstructorCallImpl(startOffset, endOffset, expression.type, symbol, 0).also {
it.copyArgumentsFrom(this)
}
}
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.replaceTypeArguments()
val symbol = expression.symbol.replace(SymbolTable::referenceConstructor) ?:
return super.visitDelegatingConstructorCall(expression)
return super.visitDelegatingConstructorCall(expression)
expression.transformChildrenVoid()
return with(expression) {
IrDelegatingConstructorCallImpl(startOffset, endOffset, symbol, descriptor, getTypeArgumentsMap()).also {
IrDelegatingConstructorCallImpl(startOffset, endOffset, type, symbol, descriptor, typeArgumentsCount).also {
it.copyArgumentsFrom(this)
it.copyTypeArgumentsFrom(this)
}
}
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.replaceTypeArguments()
val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?:
return super.visitFunctionReference(expression)
return super.visitFunctionReference(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrFunctionReferenceImpl(startOffset, endOffset, type, symbol, descriptor, getTypeArgumentsMap()).also {
IrFunctionReferenceImpl(startOffset, endOffset, type, symbol, descriptor, 0).also {
it.copyArgumentsFrom(this)
it.copyTypeArgumentsFrom(this)
}
}
}
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
expression.replaceTypeArguments()
val field = expression.field?.replaceOrSame(SymbolTable::referenceField)
val getter = expression.getter?.replace(SymbolTable::referenceFunction) ?: expression.getter
val setter = expression.setter?.replace(SymbolTable::referenceFunction) ?: expression.setter
@@ -323,13 +336,14 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrPropertyReferenceImpl(startOffset, endOffset, type, descriptor,
field,
getter,
setter,
getTypeArgumentsMap(), origin).also {
IrPropertyReferenceImpl(startOffset, endOffset, type, descriptor, 0,
field,
getter,
setter,
origin).also {
it.copyArgumentsFrom(this)
it.copyTypeArgumentsFrom(this)
}
}
}
@@ -346,7 +360,7 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrLocalDelegatedPropertyReferenceImpl(startOffset, endOffset, type, descriptor,
delegate, getter, setter, origin).also {
delegate, getter, setter, origin).also {
it.copyArgumentsFrom(this)
}
@@ -406,12 +420,24 @@ private class IrUnboundSymbolReplacer(
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression {
val classSymbol = expression.classSymbol.replace(SymbolTable::referenceClass) ?:
return super.visitInstanceInitializerCall(expression)
return super.visitInstanceInitializerCall(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrInstanceInitializerCallImpl(startOffset, endOffset, classSymbol)
IrInstanceInitializerCallImpl(startOffset, endOffset, classSymbol, type)
}
}
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
expression.transformChildrenVoid(this)
return with(expression) {
val newTypeOperand = typeOperand /*context.ir.translateErased(typeOperand.toKotlinType())*/
IrTypeOperatorCallImpl(startOffset, endOffset, type, operator, newTypeOperand).also {
it.argument = argument
it.typeOperandClassifier = newTypeOperand.classifierOrFail
}
}
}
}
@@ -5,10 +5,11 @@
package org.jetbrains.kotlin.ir.backend.js.lower.inline
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -19,21 +20,6 @@ fun IrSimpleFunction.setOverrides(symbolTable: SymbolTable) {
this.descriptor.overriddenDescriptors.mapTo(this.overriddenSymbols) {
symbolTable.referenceSimpleFunction(it.original)
}
this.typeParameters.forEach { it.setSupers(symbolTable) }
}
fun IrTypeParameter.setSupers(symbolTable: SymbolTable) {
assert(this.superClassifiers.isEmpty())
this.descriptor.upperBounds.mapNotNullTo(this.superClassifiers) {
it.constructor.declarationDescriptor?.let {
if (it is TypeParameterDescriptor) {
IrTypeParameterSymbolImpl(it) // Workaround for deserialized inline functions
} else {
symbolTable.referenceClassifier(it)
}
}
}
}
fun IrDeclarationContainer.addChildren(declarations: List<IrDeclaration>) {
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.getTypeArgumentOrDefault
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -43,6 +45,10 @@ fun IrModuleFragment.referenceAllTypeExternalClassifiers(symbolTable: SymbolTabl
}
}
fun IrType.referenceAllClassifiers() {
this.toKotlinType().referenceAllClassifiers()
}
val visitor = object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
@@ -125,4 +131,4 @@ fun IrModuleFragment.referenceAllTypeExternalClassifiers(symbolTable: SymbolTabl
it.acceptVoid(visitor)
}
}
}
}
@@ -10,14 +10,18 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
import org.jetbrains.kotlin.ir.expressions.IrContainerExpression
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrReturn
import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDoWhileLoopImpl
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
/**
* Replaces returnable blocks and `return`'s with loops and `break`'s correspondingly.
@@ -93,7 +97,7 @@ private class ReturnableBlockTransformer(
return super.visitDeclaration(declaration, data)
}
private val constFalse = JsIrBuilder.buildBoolean(context.builtIns.booleanType, false)
private val constFalse = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false)
override fun visitContainerExpression(expression: IrContainerExpression, data: ReturnableBlockLoweringContext): IrExpression {
if (expression !is IrReturnableBlock) return super.visitContainerExpression(expression, data)
@@ -111,7 +115,7 @@ private class ReturnableBlockTransformer(
IrDoWhileLoopImpl(
expression.startOffset,
expression.endOffset,
context.builtIns.unitType,
context.irBuiltIns.unitType,
expression.origin
).apply {
label = "l\$ret\$${data.labelCnt++}"
@@ -127,10 +131,10 @@ private class ReturnableBlockTransformer(
IrCompositeImpl(
returnExpression.startOffset,
returnExpression.endOffset,
context.builtIns.unitType
context.irBuiltIns.unitType
).apply {
statements += JsIrBuilder.buildSetVariable(variable, returnExpression.value)
statements += JsIrBuilder.buildBreak(context.builtIns.unitType, loop)
statements += JsIrBuilder.buildSetVariable(variable, returnExpression.value, context.irBuiltIns.unitType)
statements += JsIrBuilder.buildBreak(context.irBuiltIns.unitType, loop)
}
}
@@ -138,7 +142,7 @@ private class ReturnableBlockTransformer(
if (i == expression.statements.lastIndex && s is IrReturn && s.returnTargetSymbol == expression.symbol) {
s.transformChildren(this, data)
if (!hasReturned) s.value else {
JsIrBuilder.buildSetVariable(variable, s.value)
JsIrBuilder.buildSetVariable(variable, s.value, context.irBuiltIns.unitType)
}
} else {
s.transform(this, data)
@@ -159,7 +163,7 @@ private class ReturnableBlockTransformer(
loop.body = IrBlockImpl(
expression.startOffset,
expression.endOffset,
context.builtIns.unitType,
context.irBuiltIns.unitType,
expression.origin,
newStatements
)
@@ -170,7 +174,7 @@ private class ReturnableBlockTransformer(
expression.type,
expression.origin
).apply {
statements += JsIrBuilder.buildVar(variable)
statements += JsIrBuilder.buildVar(variable, type = expression.type)
statements += loop
statements += JsIrBuilder.buildGetValue(variable)
}
@@ -18,12 +18,13 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
object JsSymbolBuilder {
fun buildValueParameter(containingSymbol: IrSimpleFunctionSymbol, index: Int, type: KotlinType, name: String? = null) =
IrValueParameterSymbolImpl(createValueParameter(containingSymbol.descriptor, index, name ?: "param$index", type))
fun buildValueParameter(containingSymbol: IrSimpleFunctionSymbol, index: Int, type: IrType, name: String? = null) =
IrValueParameterSymbolImpl(createValueParameter(containingSymbol.descriptor, index, name ?: "param$index", type.toKotlinType()))
fun buildSimpleFunction(
containingDeclaration: DeclarationDescriptor,
@@ -53,7 +54,7 @@ object JsSymbolBuilder {
fun buildVar(
containingDeclaration: DeclarationDescriptor,
type: KotlinType,
type: IrType,
name: String,
mutable: Boolean = false
) = IrVariableSymbolImpl(
@@ -61,42 +62,42 @@ object JsSymbolBuilder {
containingDeclaration,
Annotations.EMPTY,
Name.identifier(name),
type,
type.toKotlinType(),
mutable,
false,
SourceElement.NO_SOURCE
)
)
fun buildTempVar(containingSymbol: IrSymbol, type: KotlinType, name: String? = null, mutable: Boolean = false) =
fun buildTempVar(containingSymbol: IrSymbol, type: IrType, name: String? = null, mutable: Boolean = false) =
buildTempVar(containingSymbol.descriptor, type, name, mutable)
fun buildTempVar(containingDeclaration: DeclarationDescriptor, type: KotlinType, name: String? = null, mutable: Boolean = false) =
fun buildTempVar(containingDeclaration: DeclarationDescriptor, type: IrType, name: String? = null, mutable: Boolean = false) =
IrVariableSymbolImpl(
IrTemporaryVariableDescriptorImpl(
containingDeclaration,
Name.identifier(name ?: "tmp"),
type, mutable
type.toKotlinType(), mutable
)
)
}
fun IrSimpleFunctionSymbol.initialize(
receiverParameterType: KotlinType? = null,
receiverParameterType: IrType? = null,
dispatchParameterDescriptor: ReceiverParameterDescriptor? = null,
typeParameters: List<TypeParameterDescriptor> = emptyList(),
valueParameters: List<ValueParameterDescriptor> = emptyList(),
type: KotlinType? = null,
returnType: IrType? = null,
modality: Modality = Modality.FINAL,
visibility: Visibility = Visibilities.LOCAL
) = this.apply {
(descriptor as FunctionDescriptorImpl).initialize(
receiverParameterType,
receiverParameterType?.toKotlinType(),
dispatchParameterDescriptor,
typeParameters,
valueParameters,
type,
returnType?.toKotlinType(),
modality,
visibility
)
@@ -5,15 +5,15 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.backend.common.utils.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions
class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, JsGenerationContext> {
@@ -158,7 +158,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
val arguments = translateCallArguments(expression, context)
if (dispatchReceiver != null &&
dispatchReceiver.type.isFunctionTypeOrSubtype && symbol.owner.name == OperatorNameConventions.INVOKE
dispatchReceiver.type.isFunctionTypeOrSubtype() && symbol.owner.name == OperatorNameConventions.INVOKE
) {
return JsInvocation(jsDispatchReceiver!!, arguments)
}
@@ -11,12 +11,14 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.backend.js.utils.isAny
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isAny
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.util.isReal
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
@@ -26,8 +28,8 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
private val className = context.getNameForSymbol(irClass.symbol)
private val classNameRef = className.makeRef()
private val baseClass = irClass.superClasses.firstOrNull { !it.owner.isInterface }
private val baseClassName = baseClass?.let { context.getNameForSymbol(it) }
private val baseClass = irClass.superTypes.firstOrNull { !it.classifierOrFail.isInterface }
private val baseClassName = baseClass?.let { context.getNameForSymbol(it.classifierOrFail) }
private val classPrototypeRef = prototypeOf(classNameRef)
private val classBlock = JsGlobalBlock()
private val classModel = JsClassModel(className, baseClassName)
@@ -130,7 +132,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
}
private fun generateInheritanceCode(): List<JsStatement> {
if (baseClass == null || baseClass.isAny) {
if (baseClass == null || baseClass.isAny()) {
return emptyList()
}
@@ -158,7 +160,13 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
private fun generateSuperClasses(): JsPropertyInitializer = JsPropertyInitializer(
JsNameRef(Namer.METADATA_INTERFACES),
JsArrayLiteral(irClass.superClasses.filter { it.owner.isInterface }.map { JsNameRef(context.getNameForSymbol(it.owner.symbol)) })
JsArrayLiteral(
irClass.superTypes.mapNotNull {
val symbol = it.classifierOrFail
if (symbol.isInterface) JsNameRef(context.getNameForSymbol(symbol)) else null
}
)
)
}
private val IrClassifierSymbol.isInterface get() = (owner as? IrClass)?.isInterface == true
@@ -5,14 +5,13 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.js.backend.ast.*
typealias IrCallTransformer = (IrCall, context: JsGenerationContext) -> JsExpression
@@ -69,7 +68,7 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
add(intrinsics.jsObjectCreate) { call, context ->
val classToCreate = call.getTypeArgument(0)!!
val className = context.getNameForSymbol(IrClassSymbolImpl(classToCreate.constructor.declarationDescriptor as ClassDescriptor))
val className = context.getNameForSymbol(classToCreate.classifierOrFail)
val prototype = prototypeOf(className.makeRef())
JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype)
}
@@ -86,8 +85,7 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
}
add(intrinsics.jsToJsType) { call, context ->
val typeParameter = call.getTypeArgument(0)!!
val typeName = context.getNameForSymbol(IrClassSymbolImpl(typeParameter.constructor.declarationDescriptor as ClassDescriptor))
val typeName = context.getNameForSymbol(call.getTypeArgument(0)!!.classifierOrFail)
typeName.makeRef()
}