[JS IR BE] Implement type check
* IrTypeOperator lowering * runtime support * refactoring
This commit is contained in:
@@ -10,21 +10,22 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
|||||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
|
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getFunctions
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
|
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
|
||||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
|
||||||
import org.jetbrains.kotlin.js.resolve.JsPlatform.builtIns
|
import org.jetbrains.kotlin.js.resolve.JsPlatform.builtIns
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
|
||||||
class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns: IrBuiltIns, symbolTable: SymbolTable) {
|
class JsIntrinsics(
|
||||||
|
private val module: ModuleDescriptor,
|
||||||
|
private val irBuiltIns: IrBuiltIns,
|
||||||
|
context: JsIrBackendContext
|
||||||
|
) {
|
||||||
|
|
||||||
private val stubBuilder = DeclarationStubGenerator(symbolTable, JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB)
|
private val stubBuilder = DeclarationStubGenerator(context.symbolTable, JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB)
|
||||||
|
|
||||||
// Equality operations:
|
// Equality operations:
|
||||||
|
|
||||||
@@ -81,18 +82,45 @@ class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns:
|
|||||||
val jsPropertyGet = binOp("kPropertyGet")
|
val jsPropertyGet = binOp("kPropertyGet")
|
||||||
val jsPropertySet = tripleOp("kPropertySet", irBuiltIns.unit)
|
val jsPropertySet = tripleOp("kPropertySet", irBuiltIns.unit)
|
||||||
|
|
||||||
// Other:
|
|
||||||
|
// Type checks:
|
||||||
|
|
||||||
val jsInstanceOf = binOpBool("jsInstanceOf")
|
val jsInstanceOf = binOpBool("jsInstanceOf")
|
||||||
|
val jsTypeOf = unOp("jsTypeOf", irBuiltIns.string)
|
||||||
|
|
||||||
val jsObjectCreate = defineObjectCreateIntrinsic()
|
|
||||||
|
|
||||||
val jsSetJSField = defineSetJSPropertyIntrinsic()
|
// Other:
|
||||||
|
|
||||||
val jsCode = module.getFunctions(FqName("kotlin.js.js")).singleOrNull()?.let { symbolTable.referenceFunction(it) }
|
val jsObjectCreate = defineObjectCreateIntrinsic() // Object.create
|
||||||
|
val jsSetJSField = defineSetJSPropertyIntrinsic() // till we don't have dynamic type we use intrinsic which sets a field with any name
|
||||||
|
val jsToJsType = defineToJsType() // creates name reference to KotlinType
|
||||||
|
val jsCode = context.getInternalFunctions("js").singleOrNull()?.let { context.symbolTable.referenceFunction(it) } // js("<code>")
|
||||||
|
|
||||||
// Helpers:
|
// Helpers:
|
||||||
|
|
||||||
|
private fun defineToJsType(): IrSimpleFunction {
|
||||||
|
val desc = SimpleFunctionDescriptorImpl.create(
|
||||||
|
module,
|
||||||
|
Annotations.EMPTY,
|
||||||
|
Name.identifier("\$toJSType\$"),
|
||||||
|
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||||
|
SourceElement.NO_SOURCE
|
||||||
|
).apply {
|
||||||
|
|
||||||
|
val typeParameter = TypeParameterDescriptorImpl.createWithDefaultBound(
|
||||||
|
this,
|
||||||
|
Annotations.EMPTY,
|
||||||
|
false,
|
||||||
|
Variance.INVARIANT,
|
||||||
|
Name.identifier("T"),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
initialize(null, null, listOf(typeParameter), emptyList(), builtIns.anyType, Modality.FINAL, Visibilities.PUBLIC)
|
||||||
|
}
|
||||||
|
|
||||||
|
return stubBuilder.generateFunctionStub(desc)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: unify how we create intrinsic symbols
|
// TODO: unify how we create intrinsic symbols
|
||||||
private fun defineObjectCreateIntrinsic(): IrSimpleFunction {
|
private fun defineObjectCreateIntrinsic(): IrSimpleFunction {
|
||||||
|
|
||||||
@@ -121,7 +149,6 @@ class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns:
|
|||||||
return stubBuilder.generateFunctionStub(desc)
|
return stubBuilder.generateFunctionStub(desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun defineSetJSPropertyIntrinsic(): IrSimpleFunction {
|
private fun defineSetJSPropertyIntrinsic(): IrSimpleFunction {
|
||||||
val returnType = irBuiltIns.unit
|
val returnType = irBuiltIns.unit
|
||||||
|
|
||||||
|
|||||||
+40
-26
@@ -12,21 +12,23 @@ import org.jetbrains.kotlin.backend.common.ir.Ir
|
|||||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||||
import org.jetbrains.kotlin.backend.js.JsDescriptorsFactory
|
import org.jetbrains.kotlin.backend.js.JsDescriptorsFactory
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
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.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
class JsIrBackendContext(
|
class JsIrBackendContext(
|
||||||
val module: ModuleDescriptor,
|
val module: ModuleDescriptor,
|
||||||
@@ -35,20 +37,31 @@ class JsIrBackendContext(
|
|||||||
irModuleFragment: IrModuleFragment
|
irModuleFragment: IrModuleFragment
|
||||||
) : CommonBackendContext {
|
) : CommonBackendContext {
|
||||||
|
|
||||||
val intrinsics = JsIntrinsics(module, irBuiltIns, symbolTable)
|
|
||||||
|
|
||||||
override val builtIns = module.builtIns
|
override val builtIns = module.builtIns
|
||||||
|
|
||||||
override val sharedVariablesManager =
|
override val sharedVariablesManager =
|
||||||
JsSharedVariablesManager(builtIns, KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal")))
|
JsSharedVariablesManager(builtIns, KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal")))
|
||||||
override val descriptorsFactory = JsDescriptorsFactory()
|
override val descriptorsFactory = JsDescriptorsFactory()
|
||||||
|
|
||||||
override val reflectionTypes: ReflectionTypes by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
override val reflectionTypes: ReflectionTypes by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||||
// TODO
|
// TODO
|
||||||
ReflectionTypes(module, FqName("kotlin.reflect"))
|
ReflectionTypes(module, FqName("kotlin.reflect"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override val ir: Ir<CommonBackendContext> = object : Ir<CommonBackendContext>(this, irModuleFragment) {
|
private val internalPackageName = FqName("kotlin.js")
|
||||||
override val symbols: Symbols<CommonBackendContext> = object : Symbols<CommonBackendContext>(this@JsIrBackendContext, symbolTable) {
|
private val internalPackage = module.getPackage(internalPackageName)
|
||||||
|
|
||||||
|
val intrinsics = JsIntrinsics(module, irBuiltIns, this)
|
||||||
|
|
||||||
|
private val operatorMap = referenceOperators()
|
||||||
|
|
||||||
|
data class SecondaryCtorPair(val delegate: IrSimpleFunctionSymbol, val stub: IrSimpleFunctionSymbol)
|
||||||
|
|
||||||
|
val secondaryConstructorsMap = mutableMapOf<IrConstructorSymbol, SecondaryCtorPair>()
|
||||||
|
|
||||||
|
fun getOperatorByName(name: Name, type: KotlinType) = operatorMap[name]?.get(type)
|
||||||
|
|
||||||
|
override val ir = object : Ir<CommonBackendContext>(this, irModuleFragment) {
|
||||||
|
override val symbols = object : Symbols<CommonBackendContext>(this@JsIrBackendContext, symbolTable) {
|
||||||
|
|
||||||
override fun calc(initializer: () -> IrClassSymbol): IrClassSymbol {
|
override fun calc(initializer: () -> IrClassSymbol): IrClassSymbol {
|
||||||
return object : IrClassSymbol {
|
return object : IrClassSymbol {
|
||||||
@@ -63,13 +76,13 @@ class JsIrBackendContext(
|
|||||||
get () = TODO("not implemented")
|
get () = TODO("not implemented")
|
||||||
|
|
||||||
override val ThrowNullPointerException
|
override val ThrowNullPointerException
|
||||||
get () = TODO("not implemented")
|
get () = irBuiltIns.throwNpeSymbol
|
||||||
|
|
||||||
override val ThrowNoWhenBranchMatchedException
|
override val ThrowNoWhenBranchMatchedException
|
||||||
get () = TODO("not implemented")
|
get () = irBuiltIns.noWhenBranchMatchedExceptionSymbol
|
||||||
|
|
||||||
override val ThrowTypeCastException
|
override val ThrowTypeCastException
|
||||||
get () = TODO("not implemented")
|
get () = irBuiltIns.throwCceSymbol
|
||||||
|
|
||||||
override val ThrowUninitializedPropertyAccessException = symbolTable.referenceSimpleFunction(
|
override val ThrowUninitializedPropertyAccessException = symbolTable.referenceSimpleFunction(
|
||||||
irBuiltIns.defineOperator(
|
irBuiltIns.defineOperator(
|
||||||
@@ -92,29 +105,30 @@ class JsIrBackendContext(
|
|||||||
override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true
|
override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true
|
||||||
}
|
}
|
||||||
|
|
||||||
data class SecondaryCtorPair(val delegate: IrSimpleFunctionSymbol, val stub: IrSimpleFunctionSymbol)
|
private fun referenceOperators() = OperatorNames.ALL.map { name ->
|
||||||
|
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)) }
|
||||||
|
m
|
||||||
|
}
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
val secondaryConstructorsMap = mutableMapOf<IrConstructorSymbol, SecondaryCtorPair>()
|
private fun findClass(memberScope: MemberScope, className: String) = findClass(memberScope, Name.identifier(className))
|
||||||
|
|
||||||
private fun find(memberScope: MemberScope, className: String): ClassDescriptor {
|
private fun findClass(memberScope: MemberScope, name: Name) =
|
||||||
return find(memberScope, Name.identifier(className))
|
memberScope.getContributedClassifier(name, NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||||
}
|
|
||||||
|
|
||||||
private fun find(memberScope: MemberScope, name: Name): ClassDescriptor {
|
private fun findFunctions(memberScope: MemberScope, className: String) =
|
||||||
return memberScope.getContributedClassifier(name, NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
findFunctions(memberScope, Name.identifier(className))
|
||||||
}
|
|
||||||
|
|
||||||
override fun getInternalClass(name: String): ClassDescriptor {
|
private fun findFunctions(memberScope: MemberScope, name: Name) =
|
||||||
return find(module.getPackage(FqName("kotlin.js")).memberScope, name)
|
memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).toList()
|
||||||
}
|
|
||||||
|
|
||||||
override fun getClass(fqName: FqName): ClassDescriptor {
|
override fun getInternalClass(name: String) = findClass(internalPackage.memberScope, name)
|
||||||
return find(module.getPackage(fqName.parent()).memberScope, fqName.shortName())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getInternalFunctions(name: String): List<FunctionDescriptor> {
|
override fun getClass(fqName: FqName) = findClass(module.getPackage(fqName.parent()).memberScope, fqName.shortName())
|
||||||
TODO("not implemented")
|
|
||||||
}
|
override fun getInternalFunctions(name: String) = findFunctions(internalPackage.memberScope, name)
|
||||||
|
|
||||||
override fun log(message: () -> String) {
|
override fun log(message: () -> String) {
|
||||||
/*TODO*/
|
/*TODO*/
|
||||||
|
|||||||
@@ -9,10 +9,7 @@ import com.intellij.openapi.project.Project
|
|||||||
import org.jetbrains.kotlin.backend.common.lower.*
|
import org.jetbrains.kotlin.backend.common.lower.*
|
||||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.BlockDecomposerLowering
|
import org.jetbrains.kotlin.ir.backend.js.lower.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.CallableReferenceLowering
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.IntrinsicifyCallsLowering
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.SecondaryCtorLowering
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||||
@@ -65,6 +62,7 @@ fun JsIrBackendContext.lower(file: IrFile) {
|
|||||||
InnerClassConstructorCallsLowering(this).runOnFilePostfix(file)
|
InnerClassConstructorCallsLowering(this).runOnFilePostfix(file)
|
||||||
PropertiesLowering().lower(file)
|
PropertiesLowering().lower(file)
|
||||||
InitializersLowering(this, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).runOnFilePostfix(file)
|
InitializersLowering(this, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).runOnFilePostfix(file)
|
||||||
|
TypeOperatorLowering(this).lower(file)
|
||||||
BlockDecomposerLowering(this).runOnFilePostfix(file)
|
BlockDecomposerLowering(this).runOnFilePostfix(file)
|
||||||
SecondaryCtorLowering(this).runOnFilePostfix(file)
|
SecondaryCtorLowering(this).runOnFilePostfix(file)
|
||||||
CallableReferenceLowering(this).lower(file)
|
CallableReferenceLowering(this).lower(file)
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.ir.backend.js.ir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
class JsIrArithBuilder(val context: JsIrBackendContext) {
|
||||||
|
|
||||||
|
val symbols = context.ir.symbols
|
||||||
|
|
||||||
|
private fun buildBinaryOperator(name: Name, l: IrExpression, r: IrExpression): IrExpression {
|
||||||
|
val symbol = context.getOperatorByName(name, l.type)!!
|
||||||
|
return JsIrBuilder.buildCall(symbol).apply {
|
||||||
|
dispatchReceiver = l
|
||||||
|
putValueArgument(0, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildUnaryOperator(name: Name, v: IrExpression): IrExpression {
|
||||||
|
val symbol = context.getOperatorByName(name, v.type)!!
|
||||||
|
return JsIrBuilder.buildCall(symbol).apply { dispatchReceiver = v }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(l: IrExpression, r: IrExpression) = buildBinaryOperator(OperatorNames.ADD, l, r)
|
||||||
|
fun sub(l: IrExpression, r: IrExpression) = buildBinaryOperator(OperatorNames.SUB, l, r)
|
||||||
|
fun mul(l: IrExpression, r: IrExpression) = buildBinaryOperator(OperatorNames.MUL, l, r)
|
||||||
|
fun div(l: IrExpression, r: IrExpression) = buildBinaryOperator(OperatorNames.DIV, l, r)
|
||||||
|
fun mod(l: IrExpression, r: IrExpression) = buildBinaryOperator(OperatorNames.MOD, l, r)
|
||||||
|
fun and(l: IrExpression, r: IrExpression) = buildBinaryOperator(OperatorNames.AND, l, r)
|
||||||
|
fun or(l: IrExpression, r: IrExpression) = buildBinaryOperator(OperatorNames.OR, l, r)
|
||||||
|
fun shl(l: IrExpression, r: IrExpression) = buildBinaryOperator(OperatorNames.SHL, l, r)
|
||||||
|
fun shr(l: IrExpression, r: IrExpression) = buildBinaryOperator(OperatorNames.SHR, l, r)
|
||||||
|
fun shru(l: IrExpression, r: IrExpression) = buildBinaryOperator(OperatorNames.SHRU, l, r)
|
||||||
|
fun not(v: IrExpression): IrExpression = buildUnaryOperator(OperatorNames.NOT, v)
|
||||||
|
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))
|
||||||
|
fun oror(l: IrExpression, r: IrExpression) = // if (l) true else r
|
||||||
|
JsIrBuilder.buildIfElse(context.builtIns.booleanType, l, JsIrBuilder.buildBoolean(context.builtIns.booleanType, true), r)
|
||||||
|
}
|
||||||
@@ -78,5 +78,6 @@ object JsIrBuilder {
|
|||||||
|
|
||||||
fun buildNull(type: KotlinType) = IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type)
|
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 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 buildString(type: KotlinType, s: String) = IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, s)
|
||||||
}
|
}
|
||||||
+1
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
|||||||
import org.jetbrains.kotlin.ir.visitors.*
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
|
|
||||||
|
// TODO: generate $metadata$ property and fill it with corresponding KFunction/KProperty interface
|
||||||
class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||||
|
|
||||||
private data class CallableReferenceKey(
|
private data class CallableReferenceKey(
|
||||||
|
|||||||
+26
-28
@@ -7,25 +7,23 @@ package org.jetbrains.kotlin.ir.backend.js.lower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
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
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
|
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.SimpleType
|
import org.jetbrains.kotlin.types.SimpleType
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
|
||||||
|
|
||||||
class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileLoweringPass {
|
class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileLoweringPass {
|
||||||
|
|
||||||
@@ -48,36 +46,36 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
|||||||
|
|
||||||
memberToIrFunction.run {
|
memberToIrFunction.run {
|
||||||
for (type in primitiveNumbers) {
|
for (type in primitiveNumbers) {
|
||||||
op(type, OperatorNameConventions.UNARY_PLUS, context.intrinsics.jsUnaryPlus)
|
op(type, OperatorNames.UNARY_PLUS, context.intrinsics.jsUnaryPlus)
|
||||||
op(type, OperatorNameConventions.UNARY_MINUS, context.intrinsics.jsUnaryMinus)
|
op(type, OperatorNames.UNARY_MINUS, context.intrinsics.jsUnaryMinus)
|
||||||
|
|
||||||
op(type, OperatorNameConventions.PLUS, context.intrinsics.jsPlus)
|
op(type, OperatorNames.ADD, context.intrinsics.jsPlus)
|
||||||
op(type, OperatorNameConventions.MINUS, context.intrinsics.jsMinus)
|
op(type, OperatorNames.SUB, context.intrinsics.jsMinus)
|
||||||
op(type, OperatorNameConventions.TIMES, context.intrinsics.jsMult)
|
op(type, OperatorNames.MUL, context.intrinsics.jsMult)
|
||||||
op(type, OperatorNameConventions.DIV, context.intrinsics.jsDiv)
|
op(type, OperatorNames.DIV, context.intrinsics.jsDiv)
|
||||||
op(type, OperatorNameConventions.MOD, context.intrinsics.jsMod)
|
op(type, OperatorNames.MOD, context.intrinsics.jsMod)
|
||||||
op(type, OperatorNameConventions.REM, context.intrinsics.jsMod)
|
op(type, OperatorNames.REM, context.intrinsics.jsMod)
|
||||||
}
|
}
|
||||||
|
|
||||||
context.irBuiltIns.string.let {
|
context.irBuiltIns.string.let {
|
||||||
op(it, OperatorNameConventions.PLUS, context.intrinsics.jsPlus)
|
op(it, OperatorNames.ADD, context.intrinsics.jsPlus)
|
||||||
}
|
}
|
||||||
|
|
||||||
context.irBuiltIns.int.let {
|
context.irBuiltIns.int.let {
|
||||||
op(it, "shl", context.intrinsics.jsBitShiftL)
|
op(it, OperatorNames.SHL, context.intrinsics.jsBitShiftL)
|
||||||
op(it, "shr", context.intrinsics.jsBitShiftR)
|
op(it, OperatorNames.SHR, context.intrinsics.jsBitShiftR)
|
||||||
op(it, "ushr", context.intrinsics.jsBitShiftRU)
|
op(it, OperatorNames.SHRU, context.intrinsics.jsBitShiftRU)
|
||||||
op(it, "and", context.intrinsics.jsBitAnd)
|
op(it, OperatorNames.AND, context.intrinsics.jsBitAnd)
|
||||||
op(it, "or", context.intrinsics.jsBitOr)
|
op(it, OperatorNames.OR, context.intrinsics.jsBitOr)
|
||||||
op(it, "xor", context.intrinsics.jsBitXor)
|
op(it, OperatorNames.XOR, context.intrinsics.jsBitXor)
|
||||||
op(it, "inv", context.intrinsics.jsBitNot)
|
op(it, OperatorNames.INV, context.intrinsics.jsBitNot)
|
||||||
}
|
}
|
||||||
|
|
||||||
context.irBuiltIns.bool.let {
|
context.irBuiltIns.bool.let {
|
||||||
op(it, OperatorNameConventions.AND, context.intrinsics.jsAnd)
|
op(it, OperatorNames.AND, context.intrinsics.jsAnd)
|
||||||
op(it, OperatorNameConventions.OR, context.intrinsics.jsOr)
|
op(it, OperatorNames.OR, context.intrinsics.jsOr)
|
||||||
op(it, OperatorNameConventions.NOT, context.intrinsics.jsNot)
|
op(it, OperatorNames.NOT, context.intrinsics.jsNot)
|
||||||
op(it, "xor", context.intrinsics.jsBitXor)
|
op(it, OperatorNames.XOR, context.intrinsics.jsBitXor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,14 +97,14 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
|
|||||||
memberToTransformer.run {
|
memberToTransformer.run {
|
||||||
for (type in primitiveNumbers) {
|
for (type in primitiveNumbers) {
|
||||||
// TODO: use increment and decrement when it's possible
|
// TODO: use increment and decrement when it's possible
|
||||||
op(type, OperatorNameConventions.INC) {
|
op(type, OperatorNames.INC) {
|
||||||
irCall(it, context.intrinsics.jsPlus.symbol, dispatchReceiverAsFirstArgument = true).apply {
|
irCall(it, context.intrinsics.jsPlus.symbol, dispatchReceiverAsFirstArgument = true).apply {
|
||||||
putValueArgument(1, IrConstImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.int, IrConstKind.Int, 1))
|
putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.int, 1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
op(type, OperatorNameConventions.DEC) {
|
op(type, OperatorNames.DEC) {
|
||||||
irCall(it, context.intrinsics.jsMinus.symbol, dispatchReceiverAsFirstArgument = true).apply {
|
irCall(it, context.intrinsics.jsMinus.symbol, dispatchReceiverAsFirstArgument = true).apply {
|
||||||
putValueArgument(1, IrConstImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.int, IrConstKind.Int, 1))
|
putValueArgument(1, JsIrBuilder.buildInt(context.irBuiltIns.int, 1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+299
@@ -0,0 +1,299 @@
|
|||||||
|
/*
|
||||||
|
* 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.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.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.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.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 lit24 = JsIrBuilder.buildInt(context.builtIns.intType, 24)
|
||||||
|
private val lit16 = JsIrBuilder.buildInt(context.builtIns.intType, 16)
|
||||||
|
|
||||||
|
private val byteMask = JsIrBuilder.buildInt(context.builtIns.intType, 0xFF)
|
||||||
|
private val shortMask = JsIrBuilder.buildInt(context.builtIns.intType, 0xFFFF)
|
||||||
|
|
||||||
|
private val calculator = JsIrArithBuilder(context)
|
||||||
|
|
||||||
|
//NOTE: Should we define JS-own functions similar to current implementation?
|
||||||
|
private val throwCCE = context.irBuiltIns.throwCceSymbol
|
||||||
|
private val throwNPE = context.irBuiltIns.throwNpeSymbol
|
||||||
|
|
||||||
|
private val eqeq = context.irBuiltIns.eqeqSymbol
|
||||||
|
|
||||||
|
private val isInterfaceSymbol = getInternalFunction("isInterface")
|
||||||
|
private val isArraySymbol = getInternalFunction("isArray")
|
||||||
|
private val isCharSymbol = getInternalFunction("isChar")
|
||||||
|
private val isObjectSymbol = getInternalFunction("isObject")
|
||||||
|
|
||||||
|
private val instanceOfIntrinsicSymbol = context.intrinsics.jsInstanceOf.symbol
|
||||||
|
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 litTrue: IrExpression = JsIrBuilder.buildBoolean(context.irBuiltIns.bool, true)
|
||||||
|
private val litNull: IrExpression = JsIrBuilder.buildNull(context.builtIns.nullableNothingType)
|
||||||
|
|
||||||
|
private fun getInternalFunction(name: String) = context.symbolTable.referenceSimpleFunction(context.getInternalFunctions(name).single())
|
||||||
|
|
||||||
|
override fun lower(irFile: IrFile) {
|
||||||
|
// TODO: get rid of descriptors
|
||||||
|
irFile.transformChildren(object : IrElementTransformer<DeclarationDescriptor> {
|
||||||
|
override fun visitDeclaration(declaration: IrDeclaration, data: DeclarationDescriptor) =
|
||||||
|
super.visitDeclaration(declaration, declaration.descriptor)
|
||||||
|
|
||||||
|
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: DeclarationDescriptor): IrExpression {
|
||||||
|
super.visitTypeOperator(expression, data)
|
||||||
|
|
||||||
|
return when (expression.operator) {
|
||||||
|
IrTypeOperator.IMPLICIT_CAST -> lowerImplicitCast(expression)
|
||||||
|
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> lowerCoercionToUnit(expression)
|
||||||
|
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> lowerIntegerCoercion(expression, data)
|
||||||
|
IrTypeOperator.IMPLICIT_NOTNULL -> lowerImplicitNotNull(expression, data)
|
||||||
|
IrTypeOperator.INSTANCEOF -> lowerInstanceOf(expression, data, false)
|
||||||
|
IrTypeOperator.NOT_INSTANCEOF -> lowerInstanceOf(expression, data, true)
|
||||||
|
IrTypeOperator.CAST -> lowerCast(expression, data, false)
|
||||||
|
IrTypeOperator.SAFE_CAST -> lowerCast(expression, data, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lowerImplicitNotNull(expression: IrTypeOperatorCall, containingDeclaration: DeclarationDescriptor): IrExpression {
|
||||||
|
assert(expression.operator == IrTypeOperator.IMPLICIT_NOTNULL)
|
||||||
|
assert(expression.typeOperand.isNullable() xor expression.argument.type.isNullable())
|
||||||
|
|
||||||
|
val newStatements = mutableListOf<IrStatement>()
|
||||||
|
|
||||||
|
val argument = cacheValue(expression.argument, newStatements, containingDeclaration)
|
||||||
|
val irNullCheck = nullCheck(argument)
|
||||||
|
|
||||||
|
newStatements += JsIrBuilder.buildIfElse(expression.typeOperand, irNullCheck, JsIrBuilder.buildCall(throwNPE), argument)
|
||||||
|
|
||||||
|
return expression.run { IrCompositeImpl(startOffset, endOffset, typeOperand, null, newStatements) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lowerCast(
|
||||||
|
expression: IrTypeOperatorCall,
|
||||||
|
containingDeclaration: DeclarationDescriptor,
|
||||||
|
isSafe: Boolean
|
||||||
|
): IrExpression {
|
||||||
|
assert(expression.operator == IrTypeOperator.CAST || expression.operator == IrTypeOperator.SAFE_CAST)
|
||||||
|
assert((expression.operator == IrTypeOperator.SAFE_CAST) == isSafe)
|
||||||
|
|
||||||
|
val toType = expression.typeOperand
|
||||||
|
val failResult = if (isSafe) litNull else JsIrBuilder.buildCall(throwCCE)
|
||||||
|
|
||||||
|
val newStatements = mutableListOf<IrStatement>()
|
||||||
|
|
||||||
|
val argument = cacheValue(expression.argument, newStatements, containingDeclaration)
|
||||||
|
|
||||||
|
val check = generateTypeCheck(argument, toType)
|
||||||
|
|
||||||
|
newStatements += JsIrBuilder.buildIfElse(toType, check, argument, failResult)
|
||||||
|
|
||||||
|
return expression.run { IrCompositeImpl(startOffset, endOffset, toType, null, newStatements) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lowerImplicitCast(expression: IrTypeOperatorCall) = expression.run {
|
||||||
|
assert(operator == IrTypeOperator.IMPLICIT_CAST)
|
||||||
|
IrCompositeImpl(startOffset, endOffset, typeOperand, null, listOf(argument))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) ||
|
||||||
|
isTypeOfCheckingType(type)
|
||||||
|
|
||||||
|
private fun isTypeOfCheckingType(type: KotlinType) =
|
||||||
|
((type.isPrimitiveNumberType() || KotlinBuiltIns.isNumber(type)) && !type.isLong() && !type.isChar()) ||
|
||||||
|
type.isBoolean() ||
|
||||||
|
type.isFunctionOrKFunctionType ||
|
||||||
|
KotlinBuiltIns.isString(type)
|
||||||
|
|
||||||
|
fun lowerInstanceOf(
|
||||||
|
expression: IrTypeOperatorCall,
|
||||||
|
containingDeclaration: DeclarationDescriptor,
|
||||||
|
inverted: Boolean
|
||||||
|
): IrExpression {
|
||||||
|
assert(expression.operator == IrTypeOperator.INSTANCEOF || expression.operator == IrTypeOperator.NOT_INSTANCEOF)
|
||||||
|
assert((expression.operator == IrTypeOperator.NOT_INSTANCEOF) == inverted)
|
||||||
|
|
||||||
|
val toType = expression.typeOperand
|
||||||
|
val isCopyRequired = expression.argument.type.isNullable() && advancedCheckRequired(toType.makeNotNullable())
|
||||||
|
val newStatements = mutableListOf<IrStatement>()
|
||||||
|
|
||||||
|
val argument =
|
||||||
|
if (isCopyRequired) cacheValue(expression.argument, newStatements, containingDeclaration) else expression.argument
|
||||||
|
val check = generateTypeCheck(argument, toType)
|
||||||
|
val result = if (inverted) calculator.not(check) else check
|
||||||
|
|
||||||
|
return if (isCopyRequired) {
|
||||||
|
newStatements += result
|
||||||
|
IrCompositeImpl(expression.startOffset, expression.endOffset, toType, null, newStatements)
|
||||||
|
} else result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun nullCheck(value: IrExpression) = JsIrBuilder.buildCall(eqeq).apply {
|
||||||
|
putValueArgument(0, value)
|
||||||
|
putValueArgument(1, litNull)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
return JsIrBuilder.buildGetValue(varSymbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateTypeCheck(argument: IrExpression, toType: KotlinType): IrExpression {
|
||||||
|
val toNotNullable = toType.makeNotNullable()
|
||||||
|
val instanceCheck = generateTypeCheckNonNull(argument, toNotNullable)
|
||||||
|
val isFromNullable = argument.type.isNullable()
|
||||||
|
val isToNullable = toType.isNullable()
|
||||||
|
val isNativeCheck = !advancedCheckRequired(toNotNullable)
|
||||||
|
|
||||||
|
return when {
|
||||||
|
!isFromNullable -> instanceCheck // ! -> *
|
||||||
|
isToNullable -> calculator.run { oror(nullCheck(argument), instanceCheck) } // * -> ?
|
||||||
|
else -> if (isNativeCheck) instanceCheck else calculator.run {
|
||||||
|
andand(
|
||||||
|
not(nullCheck(argument)),
|
||||||
|
instanceCheck
|
||||||
|
)
|
||||||
|
} // ? -> !
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateTypeCheckNonNull(argument: IrExpression, toType: KotlinType): IrExpression {
|
||||||
|
assert(!toType.isMarkedNullable)
|
||||||
|
return when {
|
||||||
|
KotlinBuiltIns.isAny(toType) -> generateIsObjectCheck(argument)
|
||||||
|
isTypeOfCheckingType(toType) -> generateTypeOfCheck(argument, toType)
|
||||||
|
toType.isChar() -> generateCheckForChar(argument)
|
||||||
|
KotlinBuiltIns.isArray(toType) -> generateGenericArrayCheck(argument)
|
||||||
|
KotlinBuiltIns.isPrimitiveArray(toType) -> generatePrimitiveArrayTypeCheck(argument, toType)
|
||||||
|
toType.isTypeParameter() -> generateTypeCheckWithTypeParameter(argument, toType)
|
||||||
|
toType.isInterface() -> generateInterfaceCheck(argument, toType)
|
||||||
|
else -> generateNativeInstanceOf(argument, toType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateIsObjectCheck(argument: IrExpression) = JsIrBuilder.buildCall(isObjectSymbol).apply {
|
||||||
|
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" }
|
||||||
|
|
||||||
|
return typeParameterDescriptor.upperBounds.fold(litTrue) { r, t ->
|
||||||
|
val check = generateTypeCheckNonNull(argument, t.makeNotNullable())
|
||||||
|
calculator.and(r, check)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateCheckForChar(argument: IrExpression) =
|
||||||
|
JsIrBuilder.buildCall(isCharSymbol).apply { dispatchReceiver = argument }
|
||||||
|
|
||||||
|
private fun generateTypeOfCheck(argument: IrExpression, toType: KotlinType): IrExpression {
|
||||||
|
val marker = when {
|
||||||
|
toType.isFunctionOrKFunctionType -> functionMarker
|
||||||
|
toType.isBoolean() -> booleanMarker
|
||||||
|
KotlinBuiltIns.isString(toType) -> stringMarker
|
||||||
|
else -> numberMarker
|
||||||
|
}
|
||||||
|
|
||||||
|
val typeOf = JsIrBuilder.buildCall(typeOfIntrinsicSymbol).apply { putValueArgument(0, argument) }
|
||||||
|
return JsIrBuilder.buildCall(eqeq).apply {
|
||||||
|
putValueArgument(0, typeOf)
|
||||||
|
putValueArgument(1, marker)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun wrapTypeReference(toType: KotlinType) =
|
||||||
|
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 {
|
||||||
|
TODO("Implement Typed Array check")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateInterfaceCheck(argument: IrExpression, toType: KotlinType): IrExpression {
|
||||||
|
val irType = wrapTypeReference(toType)
|
||||||
|
return JsIrBuilder.buildCall(isInterfaceSymbol).apply {
|
||||||
|
putValueArgument(0, argument)
|
||||||
|
putValueArgument(1, irType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateNativeInstanceOf(argument: IrExpression, toType: KotlinType): IrExpression {
|
||||||
|
val irType = wrapTypeReference(toType)
|
||||||
|
return JsIrBuilder.buildCall(instanceOfIntrinsicSymbol).apply {
|
||||||
|
putValueArgument(0, argument)
|
||||||
|
putValueArgument(1, irType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lowerIntegerCoercion(expression: IrTypeOperatorCall, containingDeclaration: DeclarationDescriptor): IrExpression {
|
||||||
|
assert(expression.operator === IrTypeOperator.IMPLICIT_INTEGER_COERCION)
|
||||||
|
assert(KotlinBuiltIns.isInt(expression.argument.type))
|
||||||
|
|
||||||
|
val isNullable = expression.argument.type.isNullable()
|
||||||
|
val toType = expression.typeOperand
|
||||||
|
|
||||||
|
fun maskOp(arg: IrExpression, mask: IrExpression, shift: IrExpression) = calculator.run {
|
||||||
|
shr(shl(and(arg, mask), shift), shift)
|
||||||
|
}
|
||||||
|
|
||||||
|
val newStatements = mutableListOf<IrStatement>()
|
||||||
|
|
||||||
|
val argument =
|
||||||
|
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")
|
||||||
|
else -> error("Unreachable execution (coercion to non-Integer type")
|
||||||
|
}
|
||||||
|
|
||||||
|
newStatements += if (isNullable) JsIrBuilder.buildIfElse(toType, nullCheck(argument), litNull, casted) else casted
|
||||||
|
|
||||||
|
return expression.run { IrCompositeImpl(startOffset, endOffset, toType, null, newStatements) }
|
||||||
|
}
|
||||||
|
}, irFile.packageFragmentDescriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-1
@@ -68,9 +68,12 @@ object JsSymbolBuilder {
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun buildTempVar(containingSymbol: IrFunctionSymbol, type: KotlinType, name: String? = null, mutable: Boolean = false) =
|
fun buildTempVar(containingSymbol: IrFunctionSymbol, type: KotlinType, name: String? = null, mutable: Boolean = false) =
|
||||||
|
buildTempVar(containingSymbol.descriptor, type, name, mutable)
|
||||||
|
|
||||||
|
fun buildTempVar(containingDeclaration: DeclarationDescriptor, type: KotlinType, name: String? = null, mutable: Boolean = false) =
|
||||||
IrVariableSymbolImpl(
|
IrVariableSymbolImpl(
|
||||||
IrTemporaryVariableDescriptorImpl(
|
IrTemporaryVariableDescriptorImpl(
|
||||||
containingSymbol.descriptor,
|
containingDeclaration,
|
||||||
Name.identifier(name ?: "tmp"),
|
Name.identifier(name ?: "tmp"),
|
||||||
type, mutable
|
type, mutable
|
||||||
)
|
)
|
||||||
|
|||||||
+2
-4
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
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.Namer
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
@@ -70,7 +69,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
body.expression.accept(this, context)
|
body.expression.accept(this, context)
|
||||||
|
|
||||||
override fun visitFunctionReference(expression: IrFunctionReference, context: JsGenerationContext): JsExpression {
|
override fun visitFunctionReference(expression: IrFunctionReference, context: JsGenerationContext): JsExpression {
|
||||||
val irFunction = expression.symbol.owner as IrFunction
|
val irFunction = expression.symbol.owner
|
||||||
return irFunction.accept(IrFunctionToJsTransformer(), context).apply { name = null }
|
return irFunction.accept(IrFunctionToJsTransformer(), context).apply { name = null }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +110,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
|
|
||||||
override fun visitGetObjectValue(expression: IrGetObjectValue, context: JsGenerationContext) = when (expression.symbol.owner.kind) {
|
override fun visitGetObjectValue(expression: IrGetObjectValue, context: JsGenerationContext) = when (expression.symbol.owner.kind) {
|
||||||
ClassKind.OBJECT -> {
|
ClassKind.OBJECT -> {
|
||||||
// TODO:
|
// TODO: return unit instance instead of null
|
||||||
if (expression.type.isUnit()) JsNullLiteral()
|
if (expression.type.isUnit()) JsNullLiteral()
|
||||||
else {
|
else {
|
||||||
val className = context.getNameForSymbol(expression.symbol)
|
val className = context.getNameForSymbol(expression.symbol)
|
||||||
@@ -175,7 +174,6 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
return if (symbol is IrConstructorSymbol) {
|
return if (symbol is IrConstructorSymbol) {
|
||||||
JsNew(context.getNameForSymbol(symbol).makeRef(), arguments)
|
JsNew(context.getNameForSymbol(symbol).makeRef(), arguments)
|
||||||
} else {
|
} else {
|
||||||
// TODO sanitize name
|
|
||||||
val symbolName = context.getNameForSymbol(symbol)
|
val symbolName = context.getNameForSymbol(symbol)
|
||||||
val ref = if (jsDispatchReceiver != null) JsNameRef(symbolName, jsDispatchReceiver) else JsNameRef(symbolName)
|
val ref = if (jsDispatchReceiver != null) JsNameRef(symbolName, jsDispatchReceiver) else JsNameRef(symbolName)
|
||||||
JsInvocation(ref, jsExtensionReceiver?.let { listOf(jsExtensionReceiver) + arguments } ?: arguments)
|
JsInvocation(ref, jsExtensionReceiver?.let { listOf(jsExtensionReceiver) + arguments } ?: arguments)
|
||||||
|
|||||||
-8
@@ -14,14 +14,6 @@ import org.jetbrains.kotlin.js.backend.ast.*
|
|||||||
|
|
||||||
class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
||||||
|
|
||||||
// TODO: is it right place for this logic? Or should it be implemented as a separate lowering?
|
|
||||||
override fun visitTypeOperator(expression: IrTypeOperatorCall, context: JsGenerationContext): JsStatement {
|
|
||||||
if (expression.operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT) {
|
|
||||||
return expression.argument.accept(this, context)
|
|
||||||
}
|
|
||||||
return super.visitTypeOperator(expression, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitBlockBody(body: IrBlockBody, context: JsGenerationContext): JsStatement {
|
override fun visitBlockBody(body: IrBlockBody, context: JsGenerationContext): JsStatement {
|
||||||
return JsBlock(body.statements.map { it.accept(this, context) })
|
return JsBlock(body.statements.map { it.accept(this, context) })
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
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.JsGenerationContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
|
||||||
@@ -15,6 +16,12 @@ class IrModuleToJsTransformer(val backendContext: JsIrBackendContext) : BaseIrEl
|
|||||||
val program = JsProgram()
|
val program = JsProgram()
|
||||||
val rootContext = JsGenerationContext(JsRootScope(program), backendContext)
|
val rootContext = JsGenerationContext(JsRootScope(program), backendContext)
|
||||||
|
|
||||||
|
// TODO: fix it up with new name generator
|
||||||
|
val kotlinAny = "kotlin\$${backendContext.builtIns.any.name.asString()}"
|
||||||
|
val anyName = rootContext.currentScope.declareName(kotlinAny)
|
||||||
|
|
||||||
|
program.globalBlock.statements += JsVars(JsVars.JsVar(anyName, Namer.JS_OBJECT))
|
||||||
|
|
||||||
declaration.files.forEach {
|
declaration.files.forEach {
|
||||||
program.globalBlock.statements.add(it.accept(IrFileToJsTransformer(), rootContext))
|
program.globalBlock.statements.add(it.accept(IrFileToJsTransformer(), rootContext))
|
||||||
}
|
}
|
||||||
@@ -38,7 +45,12 @@ class IrModuleToJsTransformer(val backendContext: JsIrBackendContext) : BaseIrEl
|
|||||||
return statements
|
return statements
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addPostDeclaration(name: JsName, visited: MutableSet<JsName>, statements: MutableList<JsStatement>, classModels: Map<JsName, JsClassModel>) {
|
private fun addPostDeclaration(
|
||||||
|
name: JsName,
|
||||||
|
visited: MutableSet<JsName>,
|
||||||
|
statements: MutableList<JsStatement>,
|
||||||
|
classModels: Map<JsName, JsClassModel>
|
||||||
|
) {
|
||||||
if (visited.add(name)) {
|
if (visited.add(name)) {
|
||||||
classModels[name]?.run {
|
classModels[name]?.run {
|
||||||
superName?.let { addPostDeclaration(it, visited, statements, classModels) }
|
superName?.let { addPostDeclaration(it, visited, statements, classModels) }
|
||||||
|
|||||||
+10
@@ -37,6 +37,8 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
|||||||
binOp(intrinsics.jsLtEq, JsBinaryOperator.LTE)
|
binOp(intrinsics.jsLtEq, JsBinaryOperator.LTE)
|
||||||
|
|
||||||
prefixOp(intrinsics.jsNot, JsUnaryOperator.NOT)
|
prefixOp(intrinsics.jsNot, JsUnaryOperator.NOT)
|
||||||
|
binOp(intrinsics.jsAnd, JsBinaryOperator.AND)
|
||||||
|
binOp(intrinsics.jsOr, JsBinaryOperator.OR)
|
||||||
|
|
||||||
prefixOp(intrinsics.jsUnaryPlus, JsUnaryOperator.POS)
|
prefixOp(intrinsics.jsUnaryPlus, JsUnaryOperator.POS)
|
||||||
prefixOp(intrinsics.jsUnaryMinus, JsUnaryOperator.NEG)
|
prefixOp(intrinsics.jsUnaryMinus, JsUnaryOperator.NEG)
|
||||||
@@ -63,6 +65,8 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
|||||||
|
|
||||||
binOp(intrinsics.jsInstanceOf, JsBinaryOperator.INSTANCEOF)
|
binOp(intrinsics.jsInstanceOf, JsBinaryOperator.INSTANCEOF)
|
||||||
|
|
||||||
|
prefixOp(intrinsics.jsTypeOf, JsUnaryOperator.TYPEOF)
|
||||||
|
|
||||||
add(intrinsics.jsObjectCreate) { call, context ->
|
add(intrinsics.jsObjectCreate) { call, context ->
|
||||||
val classToCreate = call.getTypeArgument(0)!!
|
val classToCreate = call.getTypeArgument(0)!!
|
||||||
val className = context.getNameForSymbol(IrClassSymbolImpl(classToCreate.constructor.declarationDescriptor as ClassDescriptor))
|
val className = context.getNameForSymbol(IrClassSymbolImpl(classToCreate.constructor.declarationDescriptor as ClassDescriptor))
|
||||||
@@ -81,6 +85,12 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
|||||||
jsAssignment(JsNameRef(fieldNameLiteral, receiver), fieldValue)
|
jsAssignment(JsNameRef(fieldNameLiteral, receiver), fieldValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
add(intrinsics.jsToJsType) { call, context ->
|
||||||
|
val typeParameter = call.getTypeArgument(0)!!
|
||||||
|
val typeName = context.getNameForSymbol(IrClassSymbolImpl(typeParameter.constructor.declarationDescriptor as ClassDescriptor))
|
||||||
|
typeName.makeRef()
|
||||||
|
}
|
||||||
|
|
||||||
add(backendContext.sharedVariablesManager.closureBoxConstructorTypeSymbol) { call, context ->
|
add(backendContext.sharedVariablesManager.closureBoxConstructorTypeSymbol) { call, context ->
|
||||||
val args = translateCallArguments(call, context)
|
val args = translateCallArguments(call, context)
|
||||||
val initializer = args[0]
|
val initializer = args[0]
|
||||||
|
|||||||
+24
-5
@@ -6,24 +6,43 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
import com.google.gwt.dev.js.ThrowExceptionOnErrorReporter
|
import com.google.gwt.dev.js.ThrowExceptionOnErrorReporter
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrStringConcatenation
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.parser.parse
|
import org.jetbrains.kotlin.js.parser.parse
|
||||||
|
|
||||||
|
|
||||||
fun translateJsCode(call: IrCall, scope: JsScope): JsNode {
|
fun translateJsCode(call: IrCall, scope: JsScope): JsNode {
|
||||||
//TODO check non simple compile time constants (expressions)
|
//TODO check non simple compile time constants (expressions)
|
||||||
|
|
||||||
val arg = call.getValueArgument(0) as? IrConst<*>
|
fun foldString(expression: IrExpression): String {
|
||||||
val kind = arg?.kind as? IrConstKind.String ?: error("Parameter of js function must be compile time String constant")
|
val builder = StringBuilder()
|
||||||
|
expression.acceptVoid(object : IrElementVisitorVoid {
|
||||||
|
override fun visitElement(element: IrElement) = error("Parameter of js function must be compile time String constant")
|
||||||
|
|
||||||
val statements = parseJsCode(kind.valueOf(arg), JsFunctionScope(scope, "<js-code>")).orEmpty()
|
override fun <T> visitConst(expression: IrConst<T>) {
|
||||||
|
builder.append(expression.kind.valueOf(expression))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitStringConcatenation(expression: IrStringConcatenation) = expression.acceptChildrenVoid(this)
|
||||||
|
})
|
||||||
|
|
||||||
|
return builder.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
val code = call.getValueArgument(0)!!
|
||||||
|
val statements = parseJsCode(code.run(::foldString), JsFunctionScope(scope, "<js-code>")).orEmpty()
|
||||||
val size = statements.size
|
val size = statements.size
|
||||||
|
|
||||||
return when (size) {
|
return when (size) {
|
||||||
0 -> JsEmpty
|
0 -> JsEmpty
|
||||||
1 -> statements[0].let { if (it is JsExpressionStatement) it.expression else it }
|
1 -> statements[0].let { (it as? JsExpressionStatement)?.expression ?: it }
|
||||||
else -> JsBlock(statements)
|
else -> JsBlock(statements)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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.ir.backend.js.utils
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
|
object OperatorNames {
|
||||||
|
val UNARY_PLUS = OperatorNameConventions.UNARY_PLUS
|
||||||
|
val UNARY_MINUS = OperatorNameConventions.UNARY_MINUS
|
||||||
|
|
||||||
|
val ADD = OperatorNameConventions.PLUS
|
||||||
|
val SUB = OperatorNameConventions.MINUS
|
||||||
|
val MUL = OperatorNameConventions.TIMES
|
||||||
|
val DIV = OperatorNameConventions.DIV
|
||||||
|
val MOD = OperatorNameConventions.MOD
|
||||||
|
val REM = OperatorNameConventions.REM
|
||||||
|
|
||||||
|
val AND = OperatorNameConventions.AND
|
||||||
|
val OR = OperatorNameConventions.OR
|
||||||
|
val XOR = Name.identifier("xor")
|
||||||
|
val INV = Name.identifier("inv")
|
||||||
|
|
||||||
|
val SHL = Name.identifier("shl")
|
||||||
|
val SHR = Name.identifier("shr")
|
||||||
|
val SHRU = Name.identifier("shru")
|
||||||
|
|
||||||
|
val NOT = OperatorNameConventions.NOT
|
||||||
|
|
||||||
|
val INC = OperatorNameConventions.INC
|
||||||
|
val DEC = OperatorNameConventions.DEC
|
||||||
|
|
||||||
|
|
||||||
|
val BINARY = setOf(ADD, SUB, MUL, DIV, MOD, REM, AND, OR, XOR, SHL, SHR, SHRU)
|
||||||
|
val UNARY = setOf(UNARY_PLUS, UNARY_MINUS, INV, NOT, INC, DEC)
|
||||||
|
val ALL = BINARY + UNARY
|
||||||
|
}
|
||||||
+1
-1
@@ -142,7 +142,7 @@ class DataClassMembersGenerator(declarationGenerator: DeclarationGenerator) : De
|
|||||||
buildMember(function, declaration) {
|
buildMember(function, declaration) {
|
||||||
+irIfThenReturnTrue(irEqeqeq(irThis(), irOther()))
|
+irIfThenReturnTrue(irEqeqeq(irThis(), irOther()))
|
||||||
+irIfThenReturnFalse(irNotIs(irOther(), classDescriptor.defaultType, irClass.symbol))
|
+irIfThenReturnFalse(irNotIs(irOther(), classDescriptor.defaultType, irClass.symbol))
|
||||||
val otherWithCast = irTemporary(irAs(irOther(), classDescriptor.defaultType, irClass.symbol), "other_with_cast")
|
val otherWithCast = irTemporary(irImplicitCast(irOther(), classDescriptor.defaultType, irClass.symbol), "other_with_cast")
|
||||||
for (property in properties) {
|
for (property in properties) {
|
||||||
val arg1 = irGet(irThis(), getPropertyGetterSymbol(property))
|
val arg1 = irGet(irThis(), getPropertyGetterSymbol(property))
|
||||||
val arg2 = irGet(irGet(otherWithCast.symbol), getPropertyGetterSymbol(property))
|
val arg2 = irGet(irGet(otherWithCast.symbol), getPropertyGetterSymbol(property))
|
||||||
|
|||||||
@@ -99,18 +99,21 @@ class IrBuiltIns(val builtIns: KotlinBuiltIns) {
|
|||||||
val eqeqeqFun = defineOperator("EQEQEQ", bool, listOf(anyN, anyN))
|
val eqeqeqFun = defineOperator("EQEQEQ", bool, listOf(anyN, anyN))
|
||||||
val eqeqFun = defineOperator("EQEQ", bool, listOf(anyN, anyN))
|
val eqeqFun = defineOperator("EQEQ", bool, listOf(anyN, anyN))
|
||||||
val throwNpeFun = defineOperator("THROW_NPE", nothing, listOf())
|
val throwNpeFun = defineOperator("THROW_NPE", nothing, listOf())
|
||||||
|
val throwCceFun = defineOperator("THROW_CCE", nothing, listOf())
|
||||||
val booleanNotFun = defineOperator("NOT", bool, listOf(bool))
|
val booleanNotFun = defineOperator("NOT", bool, listOf(bool))
|
||||||
val noWhenBranchMatchedExceptionFun = defineOperator("noWhenBranchMatchedException", unit, listOf())
|
val noWhenBranchMatchedExceptionFun = defineOperator("noWhenBranchMatchedException", unit, listOf())
|
||||||
|
|
||||||
val eqeqeq = eqeqeqFun.descriptor
|
val eqeqeq = eqeqeqFun.descriptor
|
||||||
val eqeq = eqeqFun.descriptor
|
val eqeq = eqeqFun.descriptor
|
||||||
val throwNpe = throwNpeFun.descriptor
|
val throwNpe = throwNpeFun.descriptor
|
||||||
|
val throwCce = throwCceFun.descriptor
|
||||||
val booleanNot = booleanNotFun.descriptor
|
val booleanNot = booleanNotFun.descriptor
|
||||||
val noWhenBranchMatchedException = noWhenBranchMatchedExceptionFun.descriptor
|
val noWhenBranchMatchedException = noWhenBranchMatchedExceptionFun.descriptor
|
||||||
|
|
||||||
val eqeqeqSymbol = eqeqeqFun.symbol
|
val eqeqeqSymbol = eqeqeqFun.symbol
|
||||||
val eqeqSymbol = eqeqFun.symbol
|
val eqeqSymbol = eqeqFun.symbol
|
||||||
val throwNpeSymbol = throwNpeFun.symbol
|
val throwNpeSymbol = throwNpeFun.symbol
|
||||||
|
val throwCceSymbol = throwCceFun.symbol
|
||||||
val booleanNotSymbol = booleanNotFun.symbol
|
val booleanNotSymbol = booleanNotFun.symbol
|
||||||
val noWhenBranchMatchedExceptionSymbol = noWhenBranchMatchedExceptionFun.symbol
|
val noWhenBranchMatchedExceptionSymbol = noWhenBranchMatchedExceptionFun.symbol
|
||||||
|
|
||||||
|
|||||||
@@ -944,6 +944,10 @@ public abstract class KotlinBuiltIns {
|
|||||||
return classFqNameEquals(classDescriptor, FQ_NAMES._boolean);
|
return classFqNameEquals(classDescriptor, FQ_NAMES._boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isNumber(@NotNull KotlinType type) {
|
||||||
|
return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES.number);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isChar(@NotNull KotlinType type) {
|
public static boolean isChar(@NotNull KotlinType type) {
|
||||||
return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._char);
|
return isConstructedFromGivenClassAndNotNullable(type, FQ_NAMES._char);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ abstract class BasicIrBoxTest(
|
|||||||
) {
|
) {
|
||||||
val runtime = listOf(
|
val runtime = listOf(
|
||||||
"libraries/stdlib/js/src/kotlin/core.kt",
|
"libraries/stdlib/js/src/kotlin/core.kt",
|
||||||
"libraries/stdlib/js/irRuntime/dummy.kt"
|
"libraries/stdlib/js/irRuntime/annotations.kt",
|
||||||
|
"libraries/stdlib/js/irRuntime/internalAnnotations.kt",
|
||||||
|
"libraries/stdlib/js/irRuntime/typeCheckUtils.kt"
|
||||||
).map { createPsiFile(it) }
|
).map { createPsiFile(it) }
|
||||||
|
|
||||||
val filesToIgnore = listOf(
|
val filesToIgnore = listOf(
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* 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 kotlin
|
||||||
|
|
||||||
|
interface Annotation
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* 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 kotlin.internal
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY)
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
|
internal annotation class DynamicExtension
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* 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 kotlin.js
|
||||||
|
|
||||||
|
@kotlin.internal.DynamicExtension
|
||||||
|
public fun <T> dynamic.unsafeCast(): T = this
|
||||||
|
|
||||||
|
private fun isInterfaceImpl(ctor: dynamic, iface: dynamic): Boolean {
|
||||||
|
if (ctor === iface) return true;
|
||||||
|
|
||||||
|
val self = ::isInterfaceImpl
|
||||||
|
return js(
|
||||||
|
"""
|
||||||
|
var metadata = ctor.${'$'}metadata${'$'};
|
||||||
|
if (metadata != null) {
|
||||||
|
var interfaces = metadata.interfaces;
|
||||||
|
for (var i = 0; i < interfaces.length; i++) {
|
||||||
|
if (self_0(interfaces[i], iface)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var superPrototype = ctor.prototype != null ? Object.getPrototypeOf(ctor.prototype) : null;
|
||||||
|
var superConstructor = superPrototype != null ? superPrototype.constructor : null;
|
||||||
|
return superConstructor != null && self_0(superConstructor, iface);
|
||||||
|
"""
|
||||||
|
).unsafeCast<Boolean>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun isInterface(obj: dynamic, iface: dynamic): Boolean {
|
||||||
|
//TODO: val ctor = obj.constructor
|
||||||
|
val ctor = js("obj.constructor")
|
||||||
|
|
||||||
|
if (ctor == null) return false
|
||||||
|
|
||||||
|
return isInterfaceImpl(ctor, iface)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
internal interface ClassMetadata {
|
||||||
|
val simpleName: String
|
||||||
|
val interfaces: Array<dynamic>
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: replace `isInterface` with the following
|
||||||
|
public fun isInterface(ctor: dynamic, IType: dynamic): Boolean {
|
||||||
|
if (ctor === IType) return true
|
||||||
|
|
||||||
|
val metadata = ctor.`$metadata$`.unsafeCast<ClassMetadata?>()
|
||||||
|
|
||||||
|
if (metadata !== null) {
|
||||||
|
val interfaces = metadata.interfaces
|
||||||
|
for (i in interfaces) {
|
||||||
|
if (isInterface(i, IType)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var superPrototype = ctor.prototype
|
||||||
|
if (superPrototype !== null) {
|
||||||
|
superPrototype = js("Object.getPrototypeOf(superPrototype)")
|
||||||
|
}
|
||||||
|
|
||||||
|
val superConstructor = if (superPrototype !== null) {
|
||||||
|
superPrototype.constructor
|
||||||
|
} else null
|
||||||
|
|
||||||
|
return superConstructor != null && isInterface(superConstructor, IType)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline private fun typeOf(obj: dynamic) = js("typeof obj").unsafeCast<String>()
|
||||||
|
|
||||||
|
fun isObject(obj: dynamic): Boolean {
|
||||||
|
val objTypeOf = typeOf(obj)
|
||||||
|
|
||||||
|
return when (objTypeOf) {
|
||||||
|
"string" -> true
|
||||||
|
"number" -> true
|
||||||
|
"boolean" -> true
|
||||||
|
"function" -> true
|
||||||
|
else -> js("obj instanceof Object").unsafeCast<Boolean>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun isArray(obj: Any): Boolean {
|
||||||
|
return js("Array.isArray(obj)").unsafeCast<Boolean>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun isChar(c: Any): Boolean {
|
||||||
|
return js("throw Error(\"isChar is not implemented\")").unsafeCast<Boolean>()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user