Fake wrapped descriptors first working draft

get rid of descriptors in Bridge and Enum lowerings
Replace property accessors function type with IrSimpleFunction because they couldn't be constructors
get rid of descriptors in Callable reference lowering
refactored descriptor factory and inner class lowering
Add isReified property to IrTypeParameter declaration
keep getting rid of descriptors
Get rid of descriptors in Shared Variable Manager
LocalDeclarationLowering also uses no descriptors
Fix psi2ir
Fix nested classes names
Fix outer reference in inner classes
Fix name generator
get rid of descriptors in coroutines - something is working
Fix name generator
Fix unbound symbols in JVM BE
Rename DeclarationFactory members
This commit is contained in:
Roman Artemev
2018-07-25 23:03:09 +03:00
committed by romanart
parent daadba0927
commit d1621b80cc
88 changed files with 3138 additions and 2716 deletions
@@ -16,9 +16,9 @@
package org.jetbrains.kotlin.backend.common package org.jetbrains.kotlin.backend.common
import org.jetbrains.kotlin.backend.common.descriptors.DescriptorsFactory import org.jetbrains.kotlin.backend.common.ir.DeclarationFactory
import org.jetbrains.kotlin.backend.common.descriptors.SharedVariablesManager
import org.jetbrains.kotlin.backend.common.ir.Ir import org.jetbrains.kotlin.backend.common.ir.Ir
import org.jetbrains.kotlin.backend.common.ir.SharedVariablesManager
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
@@ -27,5 +27,5 @@ interface BackendContext {
val builtIns: KotlinBuiltIns val builtIns: KotlinBuiltIns
val irBuiltIns: IrBuiltIns val irBuiltIns: IrBuiltIns
val sharedVariablesManager: SharedVariablesManager val sharedVariablesManager: SharedVariablesManager
val descriptorsFactory: DescriptorsFactory val declarationFactory: DeclarationFactory
} }
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.backend.common
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
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.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.util.usesDefaultArguments import org.jetbrains.kotlin.ir.util.usesDefaultArguments
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -35,7 +36,7 @@ import org.jetbrains.kotlin.types.typeUtil.isUnit
* However any returned call can be correctly optimized as tail recursion. * However any returned call can be correctly optimized as tail recursion.
*/ */
fun collectTailRecursionCalls(irFunction: IrFunction): Set<IrCall> { fun collectTailRecursionCalls(irFunction: IrFunction): Set<IrCall> {
if (!irFunction.descriptor.isTailrec) { if ((irFunction as? IrSimpleFunction)?.isTailrec != true) {
return emptySet() return emptySet()
} }
@@ -1,20 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.descriptors
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
interface DescriptorsFactory {
fun getSymbolForEnumEntry(enumEntry: IrEnumEntrySymbol): IrFieldSymbol
fun getOuterThisFieldSymbol(innerClass: IrClass): IrFieldSymbol
fun getInnerClassConstructorWithOuterThisParameter(innerClassConstructor: IrConstructor): IrConstructorSymbol
fun getSymbolForObjectInstance(singleton: IrClassSymbol): IrFieldSymbol
}
@@ -0,0 +1,568 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.descriptors
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
import org.jetbrains.kotlin.types.*
abstract class WrappedDeclarationDescriptor<T : IrDeclaration>(override val annotations: Annotations) : DeclarationDescriptor {
lateinit var owner: T
fun bind(declaration: T) { owner = declaration }
}
abstract class WrappedCallableDescriptor<T : IrDeclaration>(
annotations: Annotations,
private val sourceElement: SourceElement
) : CallableDescriptor, WrappedDeclarationDescriptor<T>(annotations) {
override fun getOriginal() = this
override fun substitute(substitutor: TypeSubstitutor): CallableDescriptor {
TODO("not implemented")
}
override fun getOverriddenDescriptors(): Collection<CallableDescriptor> {
TODO("not implemented")
}
override fun getSource() = sourceElement
override fun getExtensionReceiverParameter(): ReceiverParameterDescriptor? = null
override fun getDispatchReceiverParameter(): ReceiverParameterDescriptor? = null
override fun getTypeParameters(): List<TypeParameterDescriptor> {
TODO("not implemented")
}
override fun getReturnType(): KotlinType? {
TODO("not implemented")
}
override fun getValueParameters(): MutableList<ValueParameterDescriptor> {
TODO("not implemented")
}
override fun hasStableParameterNames(): Boolean {
TODO("not implemented")
}
override fun hasSynthesizedParameterNames() = false
override fun getVisibility(): Visibility {
TODO("not implemented")
}
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D): R {
TODO("not implemented")
}
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
TODO("not implemented")
}
}
open class WrappedValueParameterDescriptor(
annotations: Annotations = Annotations.EMPTY,
sourceElement: SourceElement = SourceElement.NO_SOURCE
) : ValueParameterDescriptor, WrappedCallableDescriptor<IrValueParameter>(annotations, sourceElement) {
override val index get() = owner.index
override val isCrossinline get() = owner.isCrossinline
override val isNoinline get() = owner.isNoinline
override val varargElementType get() = owner.varargElementType?.toKotlinType()
override fun isConst() = false
override fun isVar() = false
override fun getContainingDeclaration() = (owner.parent as IrFunction).descriptor
override fun getType() = owner.type.toKotlinType()
override fun getName() = owner.name
override fun declaresDefaultValue() = owner.defaultValue != null
override fun getCompileTimeInitializer(): ConstantValue<*>? = null
override fun copy(newOwner: CallableDescriptor, newName: Name, newIndex: Int) = object : WrappedValueParameterDescriptor() {
override fun getContainingDeclaration() = newOwner as FunctionDescriptor
override fun getName() = newName
override val index = newIndex
}.also { it.bind(owner) }
override fun getOverriddenDescriptors(): Collection<ValueParameterDescriptor> = emptyList()
override fun getOriginal() = this
override fun substitute(substitutor: TypeSubstitutor): ValueParameterDescriptor {
TODO("")
}
override fun getReturnType(): KotlinType? = owner.type.toKotlinType()
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D) =
visitor!!.visitValueParameterDescriptor(this, data)!!
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
visitor!!.visitValueParameterDescriptor(this, null)
}
}
open class WrappedTypeParameterDescriptor(
annotations: Annotations = Annotations.EMPTY,
sourceElement: SourceElement = SourceElement.NO_SOURCE
) : TypeParameterDescriptor, WrappedCallableDescriptor<IrTypeParameter>(annotations, sourceElement) {
override fun getName() = owner.name
override fun isReified() = owner.isReified
override fun getVariance() = owner.variance
override fun getUpperBounds() = owner.superTypes.map { it.toKotlinType() }
override fun getTypeConstructor(): TypeConstructor {
return object : TypeConstructor {
override fun getParameters(): List<TypeParameterDescriptor> {
TODO("not implemented")
}
override fun getSupertypes() = upperBounds
override fun isFinal() = false
override fun isDenotable() = false
override fun getDeclarationDescriptor() = owner.descriptor
override fun getBuiltIns(): KotlinBuiltIns {
TODO("not implemented")
}
}
}
override fun getOriginal() = this
override fun getIndex() = owner.index
override fun isCapturedFromOuterDeclaration() = false
override fun getDefaultType(): SimpleType {
TODO("not implemented")
}
override fun getContainingDeclaration() = (owner.parent as IrDeclaration).descriptor
override fun <R, D> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D): R =
visitor!!.visitTypeParameterDescriptor(this, data)
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
visitor!!.visitTypeParameterDescriptor(this, null)
}
}
open class WrappedVariableDescriptor(
annotations: Annotations = Annotations.EMPTY,
sourceElement: SourceElement = SourceElement.NO_SOURCE
) : VariableDescriptor, WrappedCallableDescriptor<IrVariable>(annotations, sourceElement) {
override fun getContainingDeclaration() = (owner.parent as IrFunction).descriptor
override fun getType() = owner.type.toKotlinType()
override fun getName() = owner.name
override fun isConst() = owner.isConst
override fun isVar() = owner.isVar
override fun isLateInit() = owner.isLateinit
override fun getCompileTimeInitializer(): ConstantValue<*>? {
TODO("")
}
override fun getOverriddenDescriptors(): Collection<VariableDescriptor> {
TODO("Not Implemented")
}
override fun getOriginal() = this
override fun substitute(substitutor: TypeSubstitutor): VariableDescriptor {
TODO("")
}
override fun <R, D> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D): R =
visitor!!.visitVariableDescriptor(this, data)
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
visitor!!.visitVariableDescriptor(this, null)
}
}
open class WrappedSimpleFunctionDescriptor(
annotations: Annotations = Annotations.EMPTY,
sourceElement: SourceElement = SourceElement.NO_SOURCE
) : SimpleFunctionDescriptor, WrappedCallableDescriptor<IrSimpleFunction>(annotations, sourceElement) {
override fun getOverriddenDescriptors() = owner.overriddenSymbols.map { it.descriptor }
override fun getContainingDeclaration() = (owner.parent as IrSymbolOwner).symbol.descriptor
override fun getModality() = owner.modality
override fun getName() = owner.name
override fun getVisibility() = owner.visibility
override fun getReturnType() = owner.returnType.toKotlinType()
override fun getDispatchReceiverParameter() = owner.dispatchReceiverParameter?.run {
(containingDeclaration as ClassDescriptor).thisAsReceiverParameter
}
val extensionReceiver by lazy {
owner.extensionReceiverParameter?.let {
ReceiverParameterDescriptorImpl(this, ExtensionReceiver(it.descriptor, it.type.toKotlinType(), null))
}
}
override fun getExtensionReceiverParameter() = extensionReceiver
override fun getTypeParameters() = owner.typeParameters.map { it.descriptor }
override fun getValueParameters() = owner.valueParameters
.asSequence()
.mapNotNull { it.descriptor as? ValueParameterDescriptor }
.toMutableList()
override fun isExternal() = owner.isExternal
override fun isSuspend() = owner.isSuspend
override fun isTailrec() = owner.isTailrec
override fun isInline() = owner.isInline
override fun isExpect() = false
override fun isActual() = false
override fun isInfix() = false
override fun isOperator() = false
override fun getOriginal() = this
override fun substitute(substitutor: TypeSubstitutor): SimpleFunctionDescriptor {
TODO("")
}
override fun setOverriddenDescriptors(overriddenDescriptors: MutableCollection<out CallableMemberDescriptor>) {
TODO("not implemented")
}
override fun getKind() =
if (owner.origin == IrDeclarationOrigin.FAKE_OVERRIDE) CallableMemberDescriptor.Kind.FAKE_OVERRIDE
else CallableMemberDescriptor.Kind.SYNTHESIZED
override fun isHiddenToOvercomeSignatureClash(): Boolean {
TODO("not implemented")
}
override fun copy(
newOwner: DeclarationDescriptor?,
modality: Modality?,
visibility: Visibility?,
kind: CallableMemberDescriptor.Kind?,
copyOverrides: Boolean
): SimpleFunctionDescriptor {
TODO("not implemented")
}
override fun isHiddenForResolutionEverywhereBesideSupercalls(): Boolean {
TODO("not implemented")
}
override fun getInitialSignatureDescriptor() = null
override fun <V : Any?> getUserData(key: FunctionDescriptor.UserDataKey<V>?): V? = null
override fun newCopyBuilder(): FunctionDescriptor.CopyBuilder<out SimpleFunctionDescriptor> {
TODO("not implemented")
}
override fun <R, D> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D) =
visitor!!.visitFunctionDescriptor(this, data)
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
visitor!!.visitFunctionDescriptor(this, null)
}
}
open class WrappedClassConstructorDescriptor(
annotations: Annotations = Annotations.EMPTY,
sourceElement: SourceElement = SourceElement.NO_SOURCE
) : ClassConstructorDescriptor, WrappedCallableDescriptor<IrConstructor>(annotations, sourceElement) {
override fun getContainingDeclaration() = (owner.parent as IrClass).descriptor
override fun getTypeParameters() = owner.typeParameters.map { it.descriptor }
override fun getValueParameters() = owner.valueParameters.asSequence()
.mapNotNull { it.descriptor as? ValueParameterDescriptor }
.toMutableList()
override fun getOriginal() = this
override fun substitute(substitutor: TypeSubstitutor): ClassConstructorDescriptor {
TODO("not implemented")
}
override fun copy(
newOwner: DeclarationDescriptor,
modality: Modality,
visibility: Visibility,
kind: CallableMemberDescriptor.Kind,
copyOverrides: Boolean
): ClassConstructorDescriptor {
TODO("not implemented")
}
override fun getModality() = Modality.FINAL
override fun setOverriddenDescriptors(overriddenDescriptors: MutableCollection<out CallableMemberDescriptor>) {
TODO("not implemented")
}
override fun getKind() = CallableMemberDescriptor.Kind.SYNTHESIZED
override fun getConstructedClass() = (owner.parent as IrClass).descriptor
override fun getName() = owner.name
override fun getOverriddenDescriptors(): MutableCollection<out FunctionDescriptor> = mutableListOf()
override fun getInitialSignatureDescriptor(): FunctionDescriptor? = null
override fun getVisibility() = owner.visibility
override fun isHiddenToOvercomeSignatureClash(): Boolean {
TODO("not implemented")
}
override fun isOperator() = false
override fun isInline() = owner.isInline
override fun isHiddenForResolutionEverywhereBesideSupercalls(): Boolean {
TODO("not implemented")
}
override fun getReturnType() = owner.returnType.toKotlinType()
override fun isPrimary() = owner.isPrimary
override fun isExpect() = false
override fun isTailrec() = false
override fun isActual() = false
override fun isInfix() = false
override fun isSuspend() = false
override fun <V : Any?> getUserData(key: FunctionDescriptor.UserDataKey<V>?): V? = null
override fun isExternal() = owner.isExternal
override fun newCopyBuilder(): FunctionDescriptor.CopyBuilder<out FunctionDescriptor> {
TODO("not implemented")
}
override fun <R, D> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D): R =
visitor!!.visitConstructorDescriptor(this, data)
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
visitor!!.visitConstructorDescriptor(this, null)
}
}
open class WrappedClassDescriptor(
annotations: Annotations = Annotations.EMPTY,
private val sourceElement: SourceElement = SourceElement.NO_SOURCE
) : ClassDescriptor, WrappedDeclarationDescriptor<IrClass>(annotations) {
override fun getName() = owner.name
override fun getMemberScope(typeArguments: MutableList<out TypeProjection>): MemberScope {
TODO("not implemented")
}
override fun getMemberScope(typeSubstitution: TypeSubstitution): MemberScope {
TODO("not implemented")
}
override fun getUnsubstitutedMemberScope(): MemberScope {
TODO("not implemented")
}
override fun getUnsubstitutedInnerClassesScope(): MemberScope {
TODO("not implemented")
}
override fun getStaticScope(): MemberScope {
TODO("not implemented")
}
override fun getSource() = sourceElement
override fun getConstructors() = owner.declarations.asSequence().filterIsInstance<IrConstructor>().map { it.descriptor }.toList()
override fun getContainingDeclaration() = (owner.parent as IrSymbolOwner).symbol.descriptor
override fun getDefaultType(): SimpleType {
TODO("not implemented")
}
override fun getKind() = owner.kind
override fun getModality() = owner.modality
override fun getCompanionObjectDescriptor() = owner.declarations.filterIsInstance<IrClass>().firstOrNull { it.isCompanion }?.descriptor
override fun getVisibility() = owner.visibility
override fun isCompanionObject() = owner.isCompanion
override fun isData() = owner.isData
override fun isInline() = owner.isInline
override fun getThisAsReceiverParameter() = owner.thisReceiver?.descriptor as ReceiverParameterDescriptor
override fun getUnsubstitutedPrimaryConstructor(): ClassConstructorDescriptor? {
TODO("not implemented")
}
override fun getDeclaredTypeParameters() = owner.typeParameters.map { it.descriptor }
override fun getSealedSubclasses(): Collection<ClassDescriptor> {
TODO("not implemented")
}
override fun getOriginal() = this
override fun isExpect() = false
override fun substitute(substitutor: TypeSubstitutor): ClassifierDescriptorWithTypeParameters {
TODO("not implemented")
}
override fun isActual() = false
override fun getTypeConstructor(): TypeConstructor {
TODO("not implemented")
}
override fun isInner() = owner.isInner
override fun isExternal() = owner.isExternal
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D): R =
visitor!!.visitClassDescriptor(this, data)
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
visitor!!.visitClassDescriptor(this, null)
}
}
open class WrappedPropertyDescriptor(
annotations: Annotations = Annotations.EMPTY,
private val sourceElement: SourceElement = SourceElement.NO_SOURCE
) : PropertyDescriptor, WrappedDeclarationDescriptor<IrField>(annotations) {
override fun getModality() = if (owner.isFinal) Modality.FINAL else Modality.OPEN
override fun setOverriddenDescriptors(overriddenDescriptors: MutableCollection<out CallableMemberDescriptor>) {
TODO("not implemented")
}
override fun getKind() = CallableMemberDescriptor.Kind.SYNTHESIZED
override fun getName() = owner.name
override fun getSource() = sourceElement
override fun hasSynthesizedParameterNames(): Boolean {
TODO("not implemented")
}
override fun getOverriddenDescriptors(): MutableCollection<out PropertyDescriptor> = mutableListOf()
override fun copy(
newOwner: DeclarationDescriptor?,
modality: Modality?,
visibility: Visibility?,
kind: CallableMemberDescriptor.Kind?,
copyOverrides: Boolean
): CallableMemberDescriptor {
TODO("not implemented")
}
override fun getValueParameters(): MutableList<ValueParameterDescriptor> = mutableListOf()
override fun getCompileTimeInitializer(): ConstantValue<*>? {
TODO("not implemented")
}
override fun isSetterProjectedOut(): Boolean {
TODO("not implemented")
}
override fun getAccessors(): MutableList<PropertyAccessorDescriptor> = mutableListOf()
override fun getTypeParameters() = emptyList()
override fun getVisibility() = owner.visibility
override val setter: PropertySetterDescriptor? get() = null
override fun getOriginal() = this
override fun isExpect() = false
override fun substitute(substitutor: TypeSubstitutor): PropertyDescriptor {
TODO("not implemented")
}
override fun isActual() = false
override fun getReturnType() = owner.type.toKotlinType()
override fun hasStableParameterNames(): Boolean {
TODO("not implemented")
}
override fun getType(): KotlinType = owner.type.toKotlinType()
override fun isVar() = owner.isFinal
override fun getDispatchReceiverParameter(): ReceiverParameterDescriptor? {
TODO("not implemented")
}
override fun isConst() = false
override fun getContainingDeclaration() = (owner.parent as IrSymbolOwner).symbol.descriptor
override fun isLateInit() = false
override fun getExtensionReceiverParameter(): ReceiverParameterDescriptor? {
TODO("not implemented")
}
override fun isExternal() = owner.isExternal
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D) =
visitor!!.visitPropertyDescriptor(this, data)
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
visitor!!.visitPropertyDescriptor(this, null)
}
override val getter: PropertyGetterDescriptor? get() = null
override fun newCopyBuilder(): CallableMemberDescriptor.CopyBuilder<out PropertyDescriptor> {
TODO("not implemented")
}
override val isDelegated get() = false
}
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.ir
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.IrType
interface DeclarationFactory {
object FIELD_FOR_OUTER_THIS : IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
fun getFieldForEnumEntry(enumEntry: IrEnumEntry, type: IrType): IrField
fun getOuterThisField(innerClass: IrClass): IrField
fun getInnerClassConstructorWithOuterThisParameter(innerClassConstructor: IrConstructor): IrConstructor
fun getFieldForObjectInstance(singleton: IrClass): IrField
}
@@ -25,7 +25,7 @@ abstract class Ir<out T : CommonBackendContext>(val context: T, val irModule: Ir
abstract val symbols: Symbols<T> abstract val symbols: Symbols<T>
val defaultParameterDeclarationsCache = mutableMapOf<FunctionDescriptor, IrFunction>() val defaultParameterDeclarationsCache = mutableMapOf<IrFunction, IrFunction>()
open fun shouldGenerateHandlerParameterForDefaultBodyFun() = false open fun shouldGenerateHandlerParameterForDefaultBodyFun() = false
} }
@@ -17,18 +17,25 @@
package org.jetbrains.kotlin.backend.common.ir package org.jetbrains.kotlin.backend.common.ir
import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import java.io.StringWriter import java.io.StringWriter
@@ -133,3 +140,40 @@ fun IrClass.addSimpleDelegatingConstructor(
this.declarations.add(constructor) this.declarations.add(constructor)
} }
} }
val IrCall.isSuspend get() = (symbol.owner as? IrSimpleFunction)?.isSuspend == true
val IrFunctionReference.isSuspend get() = (symbol.owner as? IrSimpleFunction)?.isSuspend == true
fun IrValueParameter.copyTo(irFunction: IrFunction, shift: Int = 0): IrValueParameter {
val descriptor = WrappedValueParameterDescriptor(symbol.descriptor.annotations, symbol.descriptor.source)
val symbol = IrValueParameterSymbolImpl(descriptor)
return IrValueParameterImpl(
startOffset, endOffset, origin, symbol,
name, shift + index, type, varargElementType, isCrossinline, isNoinline
).also {
descriptor.bind(it)
it.parent = irFunction
}
}
fun IrTypeParameter.copyTo(irFunction: IrFunction, shift: Int = 0): IrTypeParameter {
val descriptor = WrappedTypeParameterDescriptor(symbol.descriptor.annotations, symbol.descriptor.source)
val symbol = IrTypeParameterSymbolImpl(descriptor)
return IrTypeParameterImpl(startOffset, endOffset, origin, symbol, name, shift + index, isReified, variance).also {
descriptor.bind(it)
it.parent = irFunction
}
}
fun IrFunction.copyParameterDeclarationsFrom(from: IrFunction) {
dispatchReceiverParameter = from.dispatchReceiverParameter?.copyTo(this)
extensionReceiverParameter = from.extensionReceiverParameter?.copyTo(this)
val shift = valueParameters.size
valueParameters += from.valueParameters.map { it.copyTo(this, shift) }
assert(typeParameters.isEmpty())
from.typeParameters.mapTo(typeParameters) { it.copyTo(this) }
}
@@ -1,20 +1,9 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * 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.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ */
package org.jetbrains.kotlin.backend.common.descriptors package org.jetbrains.kotlin.backend.common.ir
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
@@ -16,13 +16,12 @@
package org.jetbrains.kotlin.backend.common.lower package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCatch import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -33,27 +32,27 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
// TODO: rename the file. // TODO: rename the file.
class Closure(val capturedValues: List<IrValueSymbol> = emptyList()) class Closure(val capturedValues: List<IrValueSymbol> = emptyList())
class ClosureAnnotator { class ClosureAnnotator(declaration: IrDeclaration) {
private val closureBuilders = mutableMapOf<DeclarationDescriptor, ClosureBuilder>() private val closureBuilders = mutableMapOf<IrDeclaration, ClosureBuilder>()
constructor(declaration: IrDeclaration) { init {
// Collect all closures for classes and functions. Collect call graph // Collect all closures for classes and functions. Collect call graph
declaration.acceptChildrenVoid(ClosureCollectorVisitor()) declaration.acceptChildrenVoid(ClosureCollectorVisitor())
} }
fun getFunctionClosure(descriptor: FunctionDescriptor) = getClosure(descriptor) fun getFunctionClosure(declaration: IrFunction) = getClosure(declaration)
fun getClassClosure(descriptor: ClassDescriptor) = getClosure(descriptor) fun getClassClosure(declaration: IrClass) = getClosure(declaration)
private fun getClosure(descriptor: DeclarationDescriptor) : Closure { private fun getClosure(declaration: IrDeclaration): Closure {
closureBuilders.values.forEach { it.processed = false } closureBuilders.values.forEach { it.processed = false }
return closureBuilders return closureBuilders
.getOrElse(descriptor) { throw AssertionError("No closure builder for passed descriptor.") } .getOrElse(declaration) { throw AssertionError("No closure builder for passed descriptor.") }
.buildClosure() .buildClosure()
} }
private class ClosureBuilder(val owner: DeclarationDescriptor) { private class ClosureBuilder(val owner: IrDeclaration) {
val capturedValues = mutableSetOf<IrValueSymbol>() val capturedValues = mutableSetOf<IrValueSymbol>()
private val declaredValues = mutableSetOf<ValueDescriptor>() private val declaredValues = mutableSetOf<IrValueDeclaration>()
private val includes = mutableSetOf<ClosureBuilder>() private val includes = mutableSetOf<ClosureBuilder>()
var processed = false var processed = false
@@ -65,10 +64,10 @@ class ClosureAnnotator {
*/ */
fun buildClosure(): Closure { fun buildClosure(): Closure {
val result = mutableSetOf<IrValueSymbol>().apply { addAll(capturedValues) } val result = mutableSetOf<IrValueSymbol>().apply { addAll(capturedValues) }
includes.forEach { includes.forEach { builder ->
if (!it.processed) { if (!builder.processed) {
it.processed = true builder.processed = true
it.buildClosure().capturedValues.filterTo(result) { isExternal(it.descriptor) } builder.buildClosure().capturedValues.filterTo(result) { isExternal(it.owner) }
} }
} }
// TODO: We can save the closure and reuse it. // TODO: We can save the closure and reuse it.
@@ -80,20 +79,19 @@ class ClosureAnnotator {
includes.add(includingBuilder) includes.add(includingBuilder)
} }
fun declareVariable(valueDescriptor: ValueDescriptor?) { fun declareVariable(valueDeclaration: IrValueDeclaration?) {
if (valueDescriptor != null) if (valueDeclaration != null)
declaredValues.add(valueDescriptor) declaredValues.add(valueDeclaration)
} }
fun seeVariable(value: IrValueSymbol) { fun seeVariable(value: IrValueSymbol) {
if (isExternal(value.descriptor)) if (isExternal(value.owner))
capturedValues.add(value) capturedValues.add(value)
} }
fun isExternal(valueDescriptor: ValueDescriptor): Boolean { fun isExternal(valueDeclaration: IrValueDeclaration): Boolean {
return !declaredValues.contains(valueDescriptor) return !declaredValues.contains(valueDeclaration)
} }
} }
private inner class ClosureCollectorVisitor : IrElementVisitorVoid { private inner class ClosureCollectorVisitor : IrElementVisitorVoid {
@@ -104,7 +102,7 @@ class ClosureAnnotator {
// We don't include functions or classes in a parent function when they are declared. // We don't include functions or classes in a parent function when they are declared.
// Instead we will include them when are is used (use = call for a function or constructor call for a class). // Instead we will include them when are is used (use = call for a function or constructor call for a class).
val parentBuilder = closuresStack.peek() val parentBuilder = closuresStack.peek()
if (parentBuilder != null && parentBuilder.owner !is FunctionDescriptor) { if (parentBuilder != null && parentBuilder.owner !is IrFunction) {
parentBuilder.include(builder) parentBuilder.include(builder)
} }
} }
@@ -114,18 +112,18 @@ class ClosureAnnotator {
} }
override fun visitClass(declaration: IrClass) { override fun visitClass(declaration: IrClass) {
val classDescriptor = declaration.descriptor val closureBuilder = ClosureBuilder(declaration)
val closureBuilder = ClosureBuilder(classDescriptor) closureBuilders[declaration] = closureBuilder
closureBuilders[declaration.descriptor] = closureBuilder
closureBuilder.declareVariable(classDescriptor.thisAsReceiverParameter) closureBuilder.declareVariable(declaration.thisReceiver)
if (declaration.isInner) { if (declaration.isInner) {
closureBuilder.declareVariable((classDescriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter) closureBuilder.declareVariable((declaration.parent as IrClass).thisReceiver)
includeInParent(closureBuilder) includeInParent(closureBuilder)
} }
classDescriptor.unsubstitutedPrimaryConstructor?.valueParameters?.forEach { declaration.declarations.firstOrNull { it is IrConstructor && it.isPrimary }?.let {
closureBuilder.declareVariable(it) val constructor = it as IrConstructor
constructor.valueParameters.forEach { v -> closureBuilder.declareVariable(v) }
} }
closuresStack.push(closureBuilder) closuresStack.push(closureBuilder)
@@ -134,23 +132,26 @@ class ClosureAnnotator {
} }
override fun visitFunction(declaration: IrFunction) { override fun visitFunction(declaration: IrFunction) {
val functionDescriptor = declaration.descriptor val closureBuilder = ClosureBuilder(declaration)
val closureBuilder = ClosureBuilder(functionDescriptor) closureBuilders[declaration] = closureBuilder
closureBuilders[functionDescriptor] = closureBuilder
declaration.valueParameters.forEach { closureBuilder.declareVariable(it) }
closureBuilder.declareVariable(declaration.dispatchReceiverParameter)
closureBuilder.declareVariable(declaration.extensionReceiverParameter)
if (declaration is IrConstructor) {
val constructedClass = (declaration.parent as IrClass)
closureBuilder.declareVariable(constructedClass.thisReceiver)
functionDescriptor.valueParameters.forEach { closureBuilder.declareVariable(it) }
closureBuilder.declareVariable(functionDescriptor.dispatchReceiverParameter)
closureBuilder.declareVariable(functionDescriptor.extensionReceiverParameter)
if (functionDescriptor is ConstructorDescriptor) {
closureBuilder.declareVariable(functionDescriptor.constructedClass.thisAsReceiverParameter)
// Include closure of the class in the constructor closure. // Include closure of the class in the constructor closure.
val classBuilder = closuresStack.peek() val classBuilder = closuresStack.peek()
classBuilder?.let { classBuilder?.let {
assert(classBuilder.owner == functionDescriptor.constructedClass) assert(classBuilder.owner == constructedClass)
closureBuilder.include(classBuilder) closureBuilder.include(classBuilder)
} }
} }
closuresStack.push(closureBuilder) closuresStack.push(closureBuilder)
declaration.acceptChildrenVoid(this) declaration.acceptChildrenVoid(this)
closuresStack.pop() closuresStack.pop()
@@ -169,21 +170,40 @@ class ClosureAnnotator {
} }
override fun visitVariable(declaration: IrVariable) { override fun visitVariable(declaration: IrVariable) {
closuresStack.peek()?.declareVariable(declaration.descriptor) closuresStack.peek()?.declareVariable(declaration)
super.visitVariable(declaration) super.visitVariable(declaration)
} }
override fun visitCatch(aCatch: IrCatch) { override fun visitCatch(aCatch: IrCatch) {
closuresStack.peek()?.declareVariable(aCatch.parameter) closuresStack.peek()?.declareVariable(aCatch.catchParameter)
super.visitCatch(aCatch) super.visitCatch(aCatch)
} }
// Process delegating constructor calls, enum constructor calls, calls and callable references. override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
override fun visitMemberAccess(expression: IrMemberAccessExpression) {
expression.acceptChildrenVoid(this) expression.acceptChildrenVoid(this)
val descriptor = expression.descriptor processMemberAccess(expression.symbol.owner)
if (DescriptorUtils.isLocal(descriptor)) { }
val builder = closureBuilders[descriptor]
override fun visitCall(expression: IrCall) {
expression.acceptChildrenVoid(this)
processMemberAccess(expression.symbol.owner)
}
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall) {
expression.acceptChildrenVoid(this)
processMemberAccess(expression.symbol.owner)
}
override fun visitFunctionReference(expression: IrFunctionReference) {
expression.acceptChildrenVoid(this)
processMemberAccess(expression.symbol.owner)
}
// override fun visitPropertyReference(expression: IrPropertyReference) = processMemberAccess(expression.)
private fun processMemberAccess(declaration: IrDeclaration) {
if (DescriptorUtils.isLocal(declaration.descriptor)) {
val builder = closureBuilders[declaration]
builder?.let { builder?.let {
closuresStack.peek()?.include(builder) closuresStack.peek()?.include(builder)
} }
@@ -8,20 +8,18 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.ir2string import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
@@ -30,13 +28,18 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
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.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.calls.components.isVararg // TODO: fix expect/actual default parameters
open class DefaultArgumentStubGenerator constructor(val context: CommonBackendContext, private val skipInlineMethods: Boolean = true) : open class DefaultArgumentStubGenerator constructor(val context: CommonBackendContext, private val skipInlineMethods: Boolean = true) :
DeclarationContainerLoweringPass { DeclarationContainerLoweringPass {
@@ -53,71 +56,70 @@ open class DefaultArgumentStubGenerator constructor(val context: CommonBackendCo
private val symbols = context.ir.symbols private val symbols = context.ir.symbols
private fun lower(irFunction: IrFunction): List<IrFunction> { private fun lower(irFunction: IrFunction): List<IrFunction> {
val functionDescriptor = irFunction.descriptor if (!irFunction.needsDefaultArgumentsLowering(skipInlineMethods))
if (!functionDescriptor.needsDefaultArgumentsLowering(skipInlineMethods))
return listOf(irFunction) return listOf(irFunction)
val bodies = functionDescriptor.valueParameters val bodies = irFunction.valueParameters.mapNotNull { it.defaultValue }
.mapNotNull { irFunction.getDefault(it) }
log { "detected ${functionDescriptor.name.asString()} has got #${bodies.size} default expressions" } log { "detected ${irFunction.name.asString()} has got #${bodies.size} default expressions" }
functionDescriptor.overriddenDescriptors.forEach { context.log { "DEFAULT-REPLACER: $it" } }
if (bodies.isNotEmpty()) { if (bodies.isNotEmpty()) {
val newIrFunction = irFunction.generateDefaultsFunction(context) val newIrFunction = irFunction.generateDefaultsFunction(context)
newIrFunction.parent = irFunction.parent newIrFunction.parent = irFunction.parent
val descriptor = newIrFunction.descriptor
log { "$functionDescriptor -> $descriptor" } log { "$irFunction -> $newIrFunction" }
val builder = context.createIrBuilder(newIrFunction.symbol) val builder = context.createIrBuilder(newIrFunction.symbol)
newIrFunction.body = builder.irBlockBody(newIrFunction) { newIrFunction.body = builder.irBlockBody(newIrFunction) {
val params = mutableListOf<IrVariable>() val params = mutableListOf<IrVariable>()
val variables = mutableMapOf<ValueDescriptor, IrValueDeclaration>() val variables = mutableMapOf<IrValueDeclaration, IrValueDeclaration>()
irFunction.dispatchReceiverParameter?.let { irFunction.dispatchReceiverParameter?.let {
variables[it.descriptor] = newIrFunction.dispatchReceiverParameter!! variables[it] = newIrFunction.dispatchReceiverParameter!!
} }
if (descriptor.extensionReceiverParameter != null) { irFunction.extensionReceiverParameter?.let {
variables[functionDescriptor.extensionReceiverParameter!!] = variables[it] = newIrFunction.extensionReceiverParameter!!
newIrFunction.extensionReceiverParameter!!
} }
for (valueParameter in functionDescriptor.valueParameters) { for (valueParameter in irFunction.valueParameters) {
val parameter = newIrFunction.valueParameters[valueParameter.index] val parameter = newIrFunction.valueParameters[valueParameter.index]
val argument = if (valueParameter.hasDefaultValue()) { val argument = if (valueParameter.defaultValue != null) {
val kIntAnd = symbols.intAnd.owner val kIntAnd = symbols.intAnd.owner
val condition = irNotEquals(irCall(kIntAnd).apply { val condition = irNotEquals(irCall(kIntAnd).apply {
dispatchReceiver = irGet(maskParameter(newIrFunction, valueParameter.index / 32)) dispatchReceiver = irGet(maskParameter(newIrFunction, valueParameter.index / 32))
putValueArgument(0, irInt(1 shl (valueParameter.index % 32))) putValueArgument(0, irInt(1 shl (valueParameter.index % 32)))
}, irInt(0)) }, irInt(0))
val expressionBody = getDefaultParameterExpressionBody(irFunction, valueParameter)
/* Use previously calculated values in next expression. */ val expressionBody = valueParameter.defaultValue!!
expressionBody.transformChildrenVoid(object : IrElementTransformerVoid() { expressionBody.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
log { "GetValue: ${expression.descriptor}" } log { "GetValue: ${expression.symbol.owner}" }
val valueSymbol = variables[expression.descriptor] ?: return expression val valueSymbol = variables[expression.symbol.owner] ?: return expression
return irGet(valueSymbol) return irGet(valueSymbol)
} }
}) })
irIfThenElse( irIfThenElse(
type = parameter.type, type = parameter.type,
condition = condition, condition = condition,
thenPart = expressionBody.expression, thenPart = expressionBody.expression,
elsePart = irGet(parameter) elsePart = irGet(parameter)
) )
/* Mapping calculated values with its origin variables. */
} else { } else {
irGet(parameter) irGet(parameter)
} }
val temporaryVariable = irTemporary(argument, nameHint = parameter.name.asString()) val temporaryVariable = irTemporary(argument, nameHint = parameter.name.asString())
params.add(temporaryVariable) params.add(temporaryVariable)
variables.put(valueParameter, temporaryVariable) variables[valueParameter] = temporaryVariable
} }
if (irFunction is IrConstructor) { if (irFunction is IrConstructor) {
+IrDelegatingConstructorCallImpl( +IrDelegatingConstructorCallImpl(
startOffset = irFunction.startOffset, startOffset = irFunction.startOffset,
@@ -126,31 +128,23 @@ open class DefaultArgumentStubGenerator constructor(val context: CommonBackendCo
symbol = irFunction.symbol, descriptor = irFunction.symbol.descriptor, symbol = irFunction.symbol, descriptor = irFunction.symbol.descriptor,
typeArgumentsCount = irFunction.typeParameters.size typeArgumentsCount = irFunction.typeParameters.size
).apply { ).apply {
params.forEachIndexed { i, variable -> dispatchReceiver = newIrFunction.dispatchReceiverParameter?.let { irGet(it) }
putValueArgument(i, irGet(variable))
} params.forEachIndexed { i, variable -> putValueArgument(i, irGet(variable)) }
if (functionDescriptor.dispatchReceiverParameter != null) {
dispatchReceiver = irGet(newIrFunction.dispatchReceiverParameter!!)
}
} }
} else { } else {
+irReturn(irCall(irFunction).apply { +irReturn(irCall(irFunction).apply {
if (functionDescriptor.dispatchReceiverParameter != null) { dispatchReceiver = newIrFunction.dispatchReceiverParameter?.let { irGet(it) }
dispatchReceiver = irGet(newIrFunction.dispatchReceiverParameter!!) extensionReceiver = newIrFunction.extensionReceiverParameter?.let { irGet(it) }
}
if (functionDescriptor.extensionReceiverParameter != null) { params.forEachIndexed { i, variable -> putValueArgument(i, irGet(variable)) }
extensionReceiver = irGet(variables[functionDescriptor.extensionReceiverParameter!!]!!)
}
params.forEachIndexed { i, variable ->
putValueArgument(i, irGet(variable))
}
}) })
} }
} }
// Remove default argument initializers. // Remove default argument initializers.
irFunction.valueParameters.forEach { // irFunction.valueParameters.forEach {
it.defaultValue = null // it.defaultValue = null
} // }
return listOf(irFunction, newIrFunction) return listOf(irFunction, newIrFunction)
} }
@@ -161,18 +155,14 @@ open class DefaultArgumentStubGenerator constructor(val context: CommonBackendCo
private fun log(msg: () -> String) = context.log { "DEFAULT-REPLACER: ${msg()}" } private fun log(msg: () -> String) = context.log { "DEFAULT-REPLACER: ${msg()}" }
} }
private fun getDefaultParameterExpressionBody(irFunction: IrFunction, valueParameter: ValueParameterDescriptor): IrExpressionBody { private fun maskParameterDeclaration(function: IrFunction, number: Int) =
return irFunction.getDefault(valueParameter) ?: TODO("FIXME!!!") maskParameter(function, number)
}
private fun maskParameterDescriptor(function: IrFunction, number: Int) =
maskParameter(function, number).descriptor as ValueParameterDescriptor
private fun maskParameter(function: IrFunction, number: Int) = private fun maskParameter(function: IrFunction, number: Int) =
function.valueParameters.single { it.descriptor.name == parameterMaskName(number) } function.valueParameters.single { it.name == parameterMaskName(number) }
private fun markerParameterDescriptor(descriptor: FunctionDescriptor) = private fun markerParameterDeclaration(function: IrFunction) =
descriptor.valueParameters.single { it.name == kConstructorMarkerName } function.valueParameters.single { it.name == kConstructorMarkerName }
open class DefaultParameterInjector constructor( open class DefaultParameterInjector constructor(
val context: CommonBackendContext, val context: CommonBackendContext,
@@ -183,12 +173,17 @@ open class DefaultParameterInjector constructor(
irBody.transformChildrenVoid(object : IrElementTransformerVoid() { irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
super.visitDelegatingConstructorCall(expression) super.visitDelegatingConstructorCall(expression)
val descriptor = expression.descriptor
if (!descriptor.needsDefaultArgumentsLowering(skipInline)) val declaration = expression.symbol.owner as IrFunction
if (!declaration.needsDefaultArgumentsLowering(skipInline))
return expression return expression
val argumentsCount = argumentCount(expression) val argumentsCount = argumentCount(expression)
if (argumentsCount == descriptor.valueParameters.size)
if (argumentsCount == declaration.valueParameters.size)
return expression return expression
val (symbolForCall, params) = parametersForCall(expression) val (symbolForCall, params) = parametersForCall(expression)
symbolForCall as IrConstructorSymbol symbolForCall as IrConstructorSymbol
return IrDelegatingConstructorCallImpl( return IrDelegatingConstructorCallImpl(
@@ -211,18 +206,24 @@ open class DefaultParameterInjector constructor(
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
super.visitCall(expression) super.visitCall(expression)
val functionDescriptor = expression.descriptor val functionDeclaration = expression.symbol.owner
if (!functionDescriptor.needsDefaultArgumentsLowering(skipInline)) if (!functionDeclaration.needsDefaultArgumentsLowering(skipInline))
return expression return expression
val argumentsCount = argumentCount(expression) val argumentsCount = argumentCount(expression)
if (argumentsCount == functionDescriptor.valueParameters.size) if (argumentsCount == functionDeclaration.valueParameters.size)
return expression return expression
val (symbol, params) = parametersForCall(expression) val (symbol, params) = parametersForCall(expression)
val descriptor = symbol.descriptor val descriptor = symbol.descriptor
descriptor.typeParameters.forEach { log { "$descriptor [${it.index}]: $it" } } val declaration = symbol.owner
descriptor.original.typeParameters.forEach { log { "${descriptor.original}[${it.index}] : $it" } }
for (i in 0 until expression.typeArgumentsCount) {
log { "$descriptor [$i]: $expression.getTypeArgument(i)" }
}
declaration.typeParameters.forEach { log { "$declaration[${it.index}] : $it" } }
return IrCallImpl( return IrCallImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
@@ -238,81 +239,86 @@ open class DefaultParameterInjector constructor(
log { "call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}" } log { "call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}" }
putValueArgument(it.first.index, it.second) putValueArgument(it.first.index, it.second)
} }
expression.extensionReceiver?.apply {
extensionReceiver = expression.extensionReceiver dispatchReceiver = expression.dispatchReceiver
} extensionReceiver = expression.extensionReceiver
expression.dispatchReceiver?.apply {
dispatchReceiver = expression.dispatchReceiver
}
log { "call::extension@: ${ir2string(expression.extensionReceiver)}" } log { "call::extension@: ${ir2string(expression.extensionReceiver)}" }
log { "call::dispatch@: ${ir2string(expression.dispatchReceiver)}" } log { "call::dispatch@: ${ir2string(expression.dispatchReceiver)}" }
} }
} }
private fun IrFunction.findSuperMethodWithDefaultArguments(): IrFunction? { private fun IrFunction.findSuperMethodWithDefaultArguments(): IrFunction? {
if (!this.descriptor.needsDefaultArgumentsLowering(skipInline)) return null if (!needsDefaultArgumentsLowering(skipInline)) return null
if (this !is IrSimpleFunction) return this if (this !is IrSimpleFunction) return this
this.overriddenSymbols.forEach { for (s in overriddenSymbols) {
it.owner.findSuperMethodWithDefaultArguments()?.let { return it } s.owner.findSuperMethodWithDefaultArguments()?.let { return it }
} }
return this return this
} }
private fun parametersForCall(expression: IrFunctionAccessExpression): Pair<IrFunctionSymbol, List<Pair<ValueParameterDescriptor, IrExpression?>>> { private fun parametersForCall(expression: IrFunctionAccessExpression): Pair<IrFunctionSymbol, List<Pair<IrValueParameter, IrExpression?>>> {
val descriptor = expression.descriptor val declaration = expression.symbol.owner
val keyFunction = expression.symbol.owner.findSuperMethodWithDefaultArguments()!!
val realFunction = keyFunction.generateDefaultsFunction(context)
realFunction.parent = keyFunction.parent
val realDescriptor = realFunction.descriptor
log { "$descriptor -> $realDescriptor" } val keyFunction = declaration.findSuperMethodWithDefaultArguments()!!
val maskValues = Array((descriptor.valueParameters.size + 31) / 32, { 0 }) val realFunction = keyFunction.generateDefaultsFunction(context)
val params = mutableListOf<Pair<ValueParameterDescriptor, IrExpression?>>()
params.addAll(descriptor.valueParameters.mapIndexed { i, _ -> realFunction.parent = keyFunction.parent
log { "$declaration -> $realFunction" }
val maskValues = Array((declaration.valueParameters.size + 31) / 32) { 0 }
val params = mutableListOf<Pair<IrValueParameter, IrExpression?>>()
params += declaration.valueParameters.mapIndexed { i, _ ->
val valueArgument = expression.getValueArgument(i) val valueArgument = expression.getValueArgument(i)
if (valueArgument == null) { if (valueArgument == null) {
val maskIndex = i / 32 val maskIndex = i / 32
maskValues[maskIndex] = maskValues[maskIndex] or (1 shl (i % 32)) maskValues[maskIndex] = maskValues[maskIndex] or (1 shl (i % 32))
} }
val valueParameterDescriptor = realDescriptor.valueParameters[i] val valueParameterDeclaration = realFunction.valueParameters[i]
val defaultValueArgument = if (valueParameterDescriptor.isVararg) { val defaultValueArgument = if (valueParameterDeclaration.varargElementType != null) {
null null
} else { } else {
nullConst(expression, realFunction.valueParameters[i].type) nullConst(expression, realFunction.valueParameters[i].type)
} }
valueParameterDescriptor to (valueArgument ?: defaultValueArgument) valueParameterDeclaration to (valueArgument ?: defaultValueArgument)
}) }
maskValues.forEachIndexed { i, maskValue -> maskValues.forEachIndexed { i, maskValue ->
params += maskParameterDescriptor(realFunction, i) to IrConstImpl.int( params += maskParameterDeclaration(realFunction, i) to IrConstImpl.int(
startOffset = irBody.startOffset, startOffset = irBody.startOffset,
endOffset = irBody.endOffset, endOffset = irBody.endOffset,
type = context.irBuiltIns.intType, type = context.irBuiltIns.intType,
value = maskValue value = maskValue
) )
} }
if (expression.descriptor is ClassConstructorDescriptor) { if (expression.symbol is IrConstructorSymbol) {
val defaultArgumentMarker = context.ir.symbols.defaultConstructorMarker val defaultArgumentMarker = context.ir.symbols.defaultConstructorMarker
params += markerParameterDescriptor(realDescriptor) to IrGetObjectValueImpl( params += markerParameterDeclaration(realFunction) to IrGetObjectValueImpl(
startOffset = irBody.startOffset, startOffset = irBody.startOffset,
endOffset = irBody.endOffset, endOffset = irBody.endOffset,
type = defaultArgumentMarker.owner.defaultType, type = defaultArgumentMarker.owner.defaultType,
symbol = defaultArgumentMarker symbol = defaultArgumentMarker
) )
} else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) { } else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
params += realDescriptor.valueParameters.last() to params += realFunction.valueParameters.last() to
IrConstImpl.constNull(irBody.startOffset, irBody.endOffset, context.irBuiltIns.nothingNType) IrConstImpl.constNull(irBody.startOffset, irBody.endOffset, context.irBuiltIns.nothingNType)
} }
params.forEach { params.forEach {
log { "descriptor::${realDescriptor.name.asString()}#${it.first.index}: ${it.first.name.asString()}" } log { "descriptor::${realFunction.name.asString()}#${it.first.index}: ${it.first.name.asString()}" }
} }
return Pair(realFunction.symbol, params) return Pair(realFunction.symbol, params)
} }
private fun argumentCount(expression: IrMemberAccessExpression) = private fun argumentCount(expression: IrMemberAccessExpression): Int {
expression.descriptor.valueParameters.count { expression.getValueArgument(it) != null } var result = 0
for (i in 0 until expression.valueArgumentsCount) {
expression.getValueArgument(i)?.run { ++result }
}
return result
}
}) })
} }
@@ -331,169 +337,126 @@ open class DefaultParameterInjector constructor(
private fun log(msg: () -> String) = context.log { "DEFAULT-INJECTOR: ${msg()}" } private fun log(msg: () -> String) = context.log { "DEFAULT-INJECTOR: ${msg()}" }
} }
private fun CallableMemberDescriptor.needsDefaultArgumentsLowering(skipInlineMethods: Boolean) = class DefaultParameterCleaner constructor(val context: CommonBackendContext) : FunctionLoweringPass {
valueParameters.any { it.hasDefaultValue() } && !(this is FunctionDescriptor && isInline && skipInlineMethods) override fun lower(irFunction: IrFunction) {
irFunction.valueParameters.forEach { it.defaultValue = null }
private fun IrFunction.generateDefaultsFunction(context: CommonBackendContext): IrFunction = with(this.descriptor) {
return context.ir.defaultParameterDeclarationsCache.getOrPut(this) {
val descriptor = when (this) {
is ClassConstructorDescriptor ->
ClassConstructorDescriptorImpl.create(
/* containingDeclaration = */ containingDeclaration,
/* annotations = */ annotations,
/* isPrimary = */ false,
/* source = */ source
)
else -> {
val name = Name.identifier("$name\$default")
SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ containingDeclaration,
/* annotations = */ annotations,
/* name = */ name,
/* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED,
/* source = */ source
)
}
}
val function = this@generateDefaultsFunction
val syntheticParameters = MutableList((valueParameters.size + 31) / 32) { i ->
valueParameter(descriptor, valueParameters.size + i, parameterMaskName(i), context.irBuiltIns.intType)
}
if (this is ClassConstructorDescriptor) {
syntheticParameters += valueParameter(
descriptor, syntheticParameters.last().index + 1,
kConstructorMarkerName,
context.ir.symbols.defaultConstructorMarker.owner.defaultType
)
} else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
syntheticParameters += valueParameter(
descriptor, syntheticParameters.last().index + 1,
"handler".synthesizedName,
context.irBuiltIns.anyType
)
}
val newValueParameters = function.valueParameters.map {
val parameterDescriptor = ValueParameterDescriptorImpl(
containingDeclaration = descriptor,
original = null, /* ValueParameterDescriptorImpl::copy do not save original. */
index = it.index,
annotations = it.descriptor.annotations,
name = it.name,
outType = it.descriptor.type,
declaresDefaultValue = false,
isCrossinline = it.isCrossinline,
isNoinline = it.isNoinline,
varargElementType = (it.descriptor as ValueParameterDescriptor).varargElementType,
source = it.descriptor.source
)
it.copy(parameterDescriptor)
} + syntheticParameters
descriptor.initialize(
/* receiverParameterType = */ extensionReceiverParameter,
/* dispatchReceiverParameter = */ dispatchReceiverParameter,
/* typeParameters = */ typeParameters.map {
TypeParameterDescriptorImpl.createForFurtherModification(
/* containingDeclaration = */ descriptor,
/* annotations = */ it.annotations,
/* reified = */ it.isReified,
/* variance = */ it.variance,
/* name = */ it.name,
/* index = */ it.index,
/* source = */ it.source,
/* reportCycleError = */ null,
/* supertypeLoopsChecker = */ SupertypeLoopChecker.EMPTY
).apply {
it.upperBounds.forEach { addUpperBound(it) }
setInitialized()
}
},
/* unsubstitutedValueParameters = */ newValueParameters.map { it.descriptor as ValueParameterDescriptor },
/* unsubstitutedReturnType = */ returnType,
/* modality = */ Modality.FINAL,
/* visibility = */ this.visibility
)
descriptor.isSuspend = this.isSuspend
context.log { "adds to cache[$this] = $descriptor" }
val startOffset = this.startOffsetOrUndefined
val endOffset = this.endOffsetOrUndefined
val result: IrFunction = when (descriptor) {
is ClassConstructorDescriptor -> IrConstructorImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
descriptor
)
else -> IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
descriptor
)
}
result.returnType = function.returnType
function.typeParameters.mapTo(result.typeParameters) {
assert(function.descriptor.typeParameters[it.index] == it.descriptor)
IrTypeParameterImpl(
startOffset, endOffset, origin, descriptor.typeParameters[it.index]
).apply { this.superTypes += it.superTypes }
}
result.parent = function.parent
result.createDispatchReceiverParameter()
function.extensionReceiverParameter?.let {
result.extensionReceiverParameter = IrValueParameterImpl(
it.startOffset,
it.endOffset,
it.origin,
descriptor.extensionReceiverParameter!!,
it.type,
it.varargElementType
).apply { parent = result }
}
result.valueParameters += newValueParameters.also { it.forEach { it.parent = result } }
function.annotations.mapTo(result.annotations) { it.deepCopyWithSymbols() }
result
} }
} }
private fun IrFunction.needsDefaultArgumentsLowering(skipInlineMethods: Boolean): Boolean {
if (isInline && skipInlineMethods) return false
if (valueParameters.any { it.defaultValue != null }) return true
if (this !is IrSimpleFunction) return false
return overriddenSymbols.any { it.owner.needsDefaultArgumentsLowering(skipInlineMethods) }
}
private fun IrFunction.generateDefaultsFunctionImpl(context: CommonBackendContext): IrFunction {
val newFunction = buildFunctionDeclaration(this)
val syntheticParameters = MutableList((valueParameters.size + 31) / 32) { i ->
valueParameter(valueParameters.size + i, parameterMaskName(i), context.irBuiltIns.intType)
}
if (this is IrConstructor) {
syntheticParameters += newFunction.valueParameter(
syntheticParameters.last().index + 1,
kConstructorMarkerName,
context.ir.symbols.defaultConstructorMarker.owner.defaultType
)
} else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
syntheticParameters += newFunction.valueParameter(
syntheticParameters.last().index + 1,
"handler".synthesizedName,
context.irBuiltIns.anyType
)
}
val newValueParameters = valueParameters.map { it.copyTo(newFunction) } + syntheticParameters
val newTypeParameters = typeParameters.map { it.copyTo(newFunction) }
newFunction.returnType = returnType
newFunction.dispatchReceiverParameter = dispatchReceiverParameter?.copyTo(newFunction)
newFunction.extensionReceiverParameter = extensionReceiverParameter?.copyTo(newFunction)
newFunction.valueParameters += newValueParameters
newFunction.typeParameters += newTypeParameters
annotations.mapTo(newFunction.annotations) { it.deepCopyWithSymbols() }
return newFunction
}
private fun buildFunctionDeclaration(irFunction: IrFunction): IrFunction {
when (irFunction) {
is IrConstructor -> {
val descriptor = WrappedClassConstructorDescriptor(irFunction.descriptor.annotations, irFunction.descriptor.source)
return IrConstructorImpl(
irFunction.startOffset,
irFunction.endOffset,
DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
IrConstructorSymbolImpl(descriptor),
irFunction.name,
irFunction.visibility,
irFunction.isInline,
irFunction.isExternal,
false
).also {
descriptor.bind(it)
it.parent = irFunction.parent
}
}
is IrSimpleFunction -> {
val descriptor = WrappedSimpleFunctionDescriptor(irFunction.descriptor.annotations, irFunction.descriptor.source)
val name = Name.identifier("${irFunction.name}\$default")
return IrFunctionImpl(
irFunction.startOffset,
irFunction.endOffset,
DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
IrSimpleFunctionSymbolImpl(descriptor),
name,
irFunction.visibility,
irFunction.modality,
irFunction.isInline,
irFunction.isExternal,
irFunction.isTailrec,
irFunction.isSuspend
).also {
descriptor.bind(it)
it.parent = irFunction.parent
}
}
else -> throw IllegalStateException("Unknown function type")
}
}
private fun IrFunction.generateDefaultsFunction(context: CommonBackendContext): IrFunction =
context.ir.defaultParameterDeclarationsCache.getOrPut(this) {
generateDefaultsFunctionImpl(context)
}
object DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER : object DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER :
IrDeclarationOriginImpl("DEFAULT_PARAMETER_EXTENT") IrDeclarationOriginImpl("DEFAULT_PARAMETER_EXTENT")
private fun IrFunction.valueParameter(descriptor: FunctionDescriptor, index: Int, name: Name, type: IrType): IrValueParameter { private fun IrFunction.valueParameter(index: Int, name: Name, type: IrType): IrValueParameter {
val parameterDescriptor = ValueParameterDescriptorImpl( val parameterDescriptor = WrappedValueParameterDescriptor()
containingDeclaration = descriptor,
original = null,
index = index,
annotations = Annotations.EMPTY,
name = name,
outType = type.toKotlinType(),
declaresDefaultValue = false,
isCrossinline = false,
isNoinline = false,
varargElementType = null,
source = SourceElement.NO_SOURCE
)
return IrValueParameterImpl( return IrValueParameterImpl(
startOffset, startOffset,
endOffset, endOffset,
IrDeclarationOrigin.DEFINED, IrDeclarationOrigin.DEFINED,
parameterDescriptor, IrValueParameterSymbolImpl(parameterDescriptor),
name,
index,
type, type,
null null,
) false,
false
).also {
parameterDescriptor.bind(it)
it.parent = this
}
} }
internal val kConstructorMarkerName = "marker".synthesizedName internal val kConstructorMarkerName = "marker".synthesizedName
@@ -15,11 +15,10 @@ 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.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrAnonymousInitializer import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
@@ -94,8 +93,8 @@ class InitializersLowering(
fun transformInstanceInitializerCallsInConstructors(irClass: IrClass) { fun transformInstanceInitializerCallsInConstructors(irClass: IrClass) {
irClass.transformChildrenVoid(object : IrElementTransformerVoid() { irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression { override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression {
return IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, val copiedBlock = IrBlockImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.unitType, null, instanceInitializerStatements).copy(irClass) as IrBlock
instanceInitializerStatements.map { it.copy(irClass) }) return IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, copiedBlock.statements)
} }
}) })
} }
@@ -125,7 +124,7 @@ class InitializersLowering(
companion object { companion object {
val clinitName = Name.special("<clinit>") val clinitName = Name.special("<clinit>")
fun IrStatement.copy(containingDeclaration: IrClass) = deepCopyWithSymbols(containingDeclaration) fun IrStatement.copy(containingDeclaration: IrDeclarationParent) = deepCopyWithSymbols(containingDeclaration)
fun IrExpression.copy(containingDeclaration: IrClass) = deepCopyWithSymbols(containingDeclaration) fun IrExpression.copy(containingDeclaration: IrDeclarationParent) = deepCopyWithSymbols(containingDeclaration)
} }
} }
@@ -8,29 +8,25 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import java.util.* import java.util.*
class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass { class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
object FIELD_FOR_OUTER_THIS : IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
override fun lower(irClass: IrClass) { override fun lower(irClass: IrClass) {
InnerClassTransformer(irClass).lowerInnerClass() InnerClassTransformer(irClass).lowerInnerClass()
} }
@@ -38,12 +34,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
private inner class InnerClassTransformer(val irClass: IrClass) { private inner class InnerClassTransformer(val irClass: IrClass) {
lateinit var outerThisField: IrField lateinit var outerThisField: IrField
val oldConstructorParameterToNew = HashMap<ValueDescriptor, IrValueParameter>() val oldConstructorParameterToNew = HashMap<IrValueParameter, IrValueParameter>()
val class2Symbol = HashMap<ClassDescriptor, IrClass>()
fun lowerInnerClass() { fun lowerInnerClass() {
if (!irClass.isInner) return if (!irClass.isInner) return
rememberClassSymbols()
createOuterThisField() createOuterThisField()
lowerConstructors() lowerConstructors()
@@ -51,36 +45,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
lowerOuterThisReferences() lowerOuterThisReferences()
} }
//TODO: rewrite: this methods is required to 'getClassForImplicitThis' method
private fun rememberClassSymbols() {
var current = irClass.parent as? IrClass
while (current != null) {
class2Symbol[current.descriptor] = current
current = current.parent as? IrClass
}
irClass.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitClass(declaration: IrClass) {
return super.visitClass(declaration).also { class2Symbol[declaration.descriptor] = declaration }
}
})
}
private fun createOuterThisField() { private fun createOuterThisField() {
val fieldSymbol = context.descriptorsFactory.getOuterThisFieldSymbol(irClass) val field = context.declarationFactory.getOuterThisField(irClass)
irClass.declarations.add( outerThisField = field
IrFieldImpl( irClass.declarations += field
irClass.startOffset, irClass.endOffset,
FIELD_FOR_OUTER_THIS,
fieldSymbol,
irClass.defaultType
).also {
outerThisField = it
}
)
} }
private fun lowerConstructors() { private fun lowerConstructors() {
@@ -96,42 +64,31 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
val startOffset = irConstructor.startOffset val startOffset = irConstructor.startOffset
val endOffset = irConstructor.endOffset val endOffset = irConstructor.endOffset
val newSymbol = context.descriptorsFactory.getInnerClassConstructorWithOuterThisParameter(irConstructor) val loweredConstructor = context.declarationFactory.getInnerClassConstructorWithOuterThisParameter(irConstructor)
val loweredConstructor = IrConstructorImpl(
startOffset, endOffset,
irConstructor.origin, // TODO special origin for lowered inner class constructors?
newSymbol,
null
).apply {
parent = irConstructor.parent
returnType = irConstructor.returnType
}
loweredConstructor.createParameterDeclarations()
val outerThisValueParameter = loweredConstructor.valueParameters[0].symbol val outerThisValueParameter = loweredConstructor.valueParameters[0].symbol
irConstructor.descriptor.valueParameters.forEach { oldValueParameter -> irConstructor.valueParameters.forEach { old ->
oldConstructorParameterToNew[oldValueParameter] = loweredConstructor.valueParameters[oldValueParameter.index + 1] oldConstructorParameterToNew[old] = loweredConstructor.valueParameters[old.index + 1]
} }
val blockBody = irConstructor.body as? IrBlockBody ?: throw AssertionError("Unexpected constructor body: ${irConstructor.body}") val blockBody = irConstructor.body as? IrBlockBody ?: throw AssertionError("Unexpected constructor body: ${irConstructor.body}")
val instanceInitializerIndex = blockBody.statements.indexOfFirst { it is IrInstanceInitializerCall } val instanceInitializerIndex = blockBody.statements.indexOfFirst { it is IrInstanceInitializerCall }
if (instanceInitializerIndex >= 0) {
// Initializing constructor: initialize 'this.this$0' with '$outer' // Initializing constructor: initialize 'this.this$0' with '$outer'
blockBody.statements.add( blockBody.statements.add(
instanceInitializerIndex, 0,
IrSetFieldImpl( IrSetFieldImpl(
startOffset, endOffset, outerThisField.symbol, startOffset, endOffset, outerThisField.symbol,
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol), IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol),
IrGetValueImpl(startOffset, endOffset, outerThisValueParameter), IrGetValueImpl(startOffset, endOffset, outerThisValueParameter),
context.irBuiltIns.unitType context.irBuiltIns.unitType
)
) )
} else { )
if (instanceInitializerIndex < 0) {
// Delegating constructor: invoke old constructor with dispatch receiver '$outer' // Delegating constructor: invoke old constructor with dispatch receiver '$outer'
val delegatingConstructorCall = (blockBody.statements.find { it is IrDelegatingConstructorCall } val delegatingConstructorCall = (blockBody.statements.find { it is IrDelegatingConstructorCall }
?: throw AssertionError("Delegating constructor call expected: ${irConstructor.dump()}") ?: throw AssertionError("Delegating constructor call expected: ${irConstructor.dump()}")
) as IrDelegatingConstructorCall ) as IrDelegatingConstructorCall
delegatingConstructorCall.dispatchReceiver = IrGetValueImpl( delegatingConstructorCall.dispatchReceiver = IrGetValueImpl(
delegatingConstructorCall.startOffset, delegatingConstructorCall.endOffset, outerThisValueParameter delegatingConstructorCall.startOffset, delegatingConstructorCall.endOffset, outerThisValueParameter
@@ -175,8 +132,15 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
return expression return expression
} }
val outerThisField = context.descriptorsFactory.getOuterThisFieldSymbol(innerClass) val outerThisField = context.declarationFactory.getOuterThisField(innerClass)
irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField, innerClass.defaultType, irThis, origin) irThis = IrGetFieldImpl(
startOffset,
endOffset,
outerThisField.symbol,
innerClass.defaultType,
irThis,
origin
)
val outer = innerClass.parent val outer = innerClass.parent
innerClass = outer as? IrClass ?: innerClass = outer as? IrClass ?:
@@ -189,11 +153,13 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
} }
private fun IrValueSymbol.getClassForImplicitThis(): IrClass? { private fun IrValueSymbol.getClassForImplicitThis(): IrClass? {
val descriptor1 = this.descriptor //TODO: is it correct way to get class
if (descriptor1 is ReceiverParameterDescriptor) { if (this is IrValueParameterSymbol) {
val receiverValue = descriptor1.value val declaration = owner
if (receiverValue is ImplicitClassReceiver) { if (declaration.index == -1) { // means value is either IMPLICIT or EXTENSION receiver
return class2Symbol[receiverValue.classDescriptor] if (declaration.name.isSpecial) { // whether name is <this>
return owner.type.classifierOrNull?.owner as IrClass
}
} }
} }
return null return null
@@ -212,15 +178,15 @@ class InnerClassConstructorCallsLowering(val context: BackendContext) : BodyLowe
val parent = callee.owner.parent as? IrClass ?: return expression val parent = callee.owner.parent as? IrClass ?: return expression
if (!parent.isInner) return expression if (!parent.isInner) return expression
val newCallee = context.descriptorsFactory.getInnerClassConstructorWithOuterThisParameter(callee.owner) val newCallee = context.declarationFactory.getInnerClassConstructorWithOuterThisParameter(callee.owner)
val newCall = IrCallImpl( val newCall = IrCallImpl(
expression.startOffset, expression.endOffset, expression.type, newCallee, newCallee.descriptor, expression.startOffset, expression.endOffset, expression.type, newCallee.symbol, newCallee.descriptor,
0, // TODO type arguments map 0, // TODO type arguments map
expression.origin expression.origin
) )
newCall.putValueArgument(0, dispatchReceiver) newCall.putValueArgument(0, dispatchReceiver)
for (i in 1..newCallee.descriptor.valueParameters.lastIndex) { for (i in 1..newCallee.valueParameters.lastIndex) {
newCall.putValueArgument(i, expression.getValueArgument(i - 1)) newCall.putValueArgument(i, expression.getValueArgument(i - 1))
} }
@@ -234,14 +200,14 @@ class InnerClassConstructorCallsLowering(val context: BackendContext) : BodyLowe
val classConstructor = expression.symbol.owner val classConstructor = expression.symbol.owner
if (!(classConstructor.parent as IrClass).isInner) return expression if (!(classConstructor.parent as IrClass).isInner) return expression
val newCallee = context.descriptorsFactory.getInnerClassConstructorWithOuterThisParameter(classConstructor) val newCallee = context.declarationFactory.getInnerClassConstructorWithOuterThisParameter(classConstructor)
val newCall = IrDelegatingConstructorCallImpl( val newCall = IrDelegatingConstructorCallImpl(
expression.startOffset, expression.endOffset, context.irBuiltIns.unitType, newCallee, newCallee.descriptor, expression.startOffset, expression.endOffset, context.irBuiltIns.unitType, newCallee.symbol, newCallee.descriptor,
classConstructor.typeParameters.size classConstructor.typeParameters.size
).apply { copyTypeArgumentsFrom(expression) } ).apply { copyTypeArgumentsFrom(expression) }
newCall.putValueArgument(0, dispatchReceiver) newCall.putValueArgument(0, dispatchReceiver)
for (i in 1..newCallee.descriptor.valueParameters.lastIndex) { for (i in 1..newCallee.valueParameters.lastIndex) {
newCall.putValueArgument(i, expression.getValueArgument(i - 1)) newCall.putValueArgument(i, expression.getValueArgument(i - 1))
} }
@@ -255,9 +221,19 @@ class InnerClassConstructorCallsLowering(val context: BackendContext) : BodyLowe
val parent = callee.owner.parent as? IrClass ?: return expression val parent = callee.owner.parent as? IrClass ?: return expression
if (!parent.isInner) return expression if (!parent.isInner) return expression
val newCallee = context.descriptorsFactory.getInnerClassConstructorWithOuterThisParameter(callee.owner) val newCallee = context.declarationFactory.getInnerClassConstructorWithOuterThisParameter(callee.owner)
val newReference = expression.run { IrFunctionReferenceImpl(startOffset, endOffset, type, newCallee, newCallee.descriptor, typeArgumentsCount, origin) } val newReference = expression.run {
IrFunctionReferenceImpl(
startOffset,
endOffset,
type,
newCallee.symbol,
newCallee.descriptor,
typeArgumentsCount,
origin
)
}
newReference.let { newReference.let {
it.dispatchReceiver = expression.dispatchReceiver it.dispatchReceiver = expression.dispatchReceiver
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
@@ -31,7 +30,6 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isPrimitiveType import org.jetbrains.kotlin.ir.types.isPrimitiveType
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType
class LateinitLowering( class LateinitLowering(
val context: CommonBackendContext, val context: CommonBackendContext,
@@ -26,17 +26,17 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.NonReportingOverrideStrategy
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.Printer
@@ -55,16 +55,16 @@ class DeclarationIrBuilder(
) )
abstract class AbstractVariableRemapper : IrElementTransformerVoid() { abstract class AbstractVariableRemapper : IrElementTransformerVoid() {
protected abstract fun remapVariable(value: ValueDescriptor): IrValueParameter? protected abstract fun remapVariable(value: IrValueDeclaration): IrValueParameter?
override fun visitGetValue(expression: IrGetValue): IrExpression = override fun visitGetValue(expression: IrGetValue): IrExpression =
remapVariable(expression.descriptor)?.let { remapVariable(expression.symbol.owner)?.let {
IrGetValueImpl(expression.startOffset, expression.endOffset, it.type, it.symbol, expression.origin) IrGetValueImpl(expression.startOffset, expression.endOffset, it.type, it.symbol, expression.origin)
} ?: expression } ?: expression
} }
class VariableRemapper(val mapping: Map<ValueDescriptor, IrValueParameter>) : AbstractVariableRemapper() { class VariableRemapper(val mapping: Map<IrValueParameter, IrValueParameter>) : AbstractVariableRemapper() {
override fun remapVariable(value: ValueDescriptor): IrValueParameter? = override fun remapVariable(value: IrValueDeclaration): IrValueParameter? =
mapping[value] mapping[value]
} }
@@ -157,35 +157,6 @@ open class IrBuildingTransformer(private val context: BackendContext) : IrElemen
} }
} }
fun computeOverrides(current: ClassDescriptor, functionsFromCurrent: List<CallableMemberDescriptor>): List<DeclarationDescriptor> {
val result = mutableListOf<DeclarationDescriptor>()
val allSuperDescriptors = current.typeConstructor.supertypes
.flatMap { it.memberScope.getContributedDescriptors() }
.filterIsInstance<CallableMemberDescriptor>()
for ((name, group) in allSuperDescriptors.groupBy { it.name }) {
OverridingUtil.generateOverridesInFunctionGroup(
name,
/* membersFromSupertypes = */ group,
/* membersFromCurrent = */ functionsFromCurrent.filter { it.name == name },
current,
object : NonReportingOverrideStrategy() {
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) {
result.add(fakeOverride)
}
override fun conflict(fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor) {
error("Conflict in scope of $current: $fromSuper vs $fromCurrent")
}
}
)
}
return result
}
class SimpleMemberScope(val members: List<DeclarationDescriptor>) : MemberScopeImpl() { class SimpleMemberScope(val members: List<DeclarationDescriptor>) : MemberScopeImpl() {
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? =
@@ -207,12 +178,14 @@ class SimpleMemberScope(val members: List<DeclarationDescriptor>) : MemberScopeI
members.filter { kindFilter.accepts(it) && nameFilter(it.name) } members.filter { kindFilter.accepts(it) && nameFilter(it.name) }
override fun printScopeStructure(p: Printer) = TODO("not implemented") override fun printScopeStructure(p: Printer) = TODO("not implemented")
} }
fun IrConstructor.callsSuper(): Boolean { fun IrConstructor.callsSuper(irBuiltIns: IrBuiltIns): Boolean {
val constructedClass = descriptor.constructedClass val constructedClass = parent as IrClass
val superClass = constructedClass.getSuperClassOrAny() val superClass = constructedClass.superTypes
.mapNotNull { it as? IrSimpleType }
.firstOrNull { (it.classifier.owner as IrClass).run { kind == ClassKind.CLASS || kind == ClassKind.ANNOTATION_CLASS || kind == ClassKind.ANNOTATION_CLASS } }
?: irBuiltIns.anyType
var callsSuper = false var callsSuper = false
var numberOfCalls = 0 var numberOfCalls = 0
acceptChildrenVoid(object : IrElementVisitorVoid { acceptChildrenVoid(object : IrElementVisitorVoid {
@@ -225,17 +198,18 @@ fun IrConstructor.callsSuper(): Boolean {
} }
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
assert(++numberOfCalls == 1, { "More than one delegating constructor call: $descriptor" }) assert(++numberOfCalls == 1) { "More than one delegating constructor call: ${symbol.owner}" }
if (expression.descriptor.constructedClass == superClass) val delegatingClass = expression.symbol.owner.parent as IrClass
if (delegatingClass == superClass.classifierOrFail.owner)
callsSuper = true callsSuper = true
else if (expression.descriptor.constructedClass != constructedClass) else if (delegatingClass != constructedClass)
throw AssertionError( throw AssertionError(
"Expected either call to another constructor of the class being constructed or" + "Expected either call to another constructor of the class being constructed or" +
" call to super class constructor. But was: ${expression.descriptor.constructedClass}" " call to super class constructor. But was: $delegatingClass"
) )
} }
}) })
assert(numberOfCalls == 1, { "Expected exactly one delegating constructor call but none encountered: $descriptor" }) assert(numberOfCalls == 1) { "Expected exactly one delegating constructor call but none encountered: ${symbol.owner}" }
return callsSuper return callsSuper
} }
@@ -73,7 +73,7 @@ private class StringConcatenationTransformer(val lower: StringConcatenationLower
it.valueParameters.size == 0 && it.name == nameToString it.valueParameters.size == 0 && it.name == nameToString
} }
private val defaultAppendFunction = stringBuilder.functions.single { private val defaultAppendFunction = stringBuilder.functions.single {
it.descriptor.name == nameAppend && it.name == nameAppend &&
it.valueParameters.size == 1 && it.valueParameters.size == 1 &&
it.valueParameters.single().type.isNullableAny() it.valueParameters.single().type.isNullableAny()
} }
@@ -82,7 +82,7 @@ private class StringConcatenationTransformer(val lower: StringConcatenationLower
private val appendFunctions: Map<KotlinType, IrSimpleFunction?> = private val appendFunctions: Map<KotlinType, IrSimpleFunction?> =
typesWithSpecialAppendFunction.map { type -> typesWithSpecialAppendFunction.map { type ->
type to stringBuilder.functions.toList().atMostOne { type to stringBuilder.functions.toList().atMostOne {
it.descriptor.name == nameAppend && it.name == nameAppend &&
it.valueParameters.size == 1 && it.valueParameters.size == 1 &&
it.valueParameters.single().type.toKotlinType() == type it.valueParameters.single().type.toKotlinType() == type
} }
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.backend.common.utils
import org.jetbrains.kotlin.backend.common.descriptors.isFunctionOrKFunctionType import org.jetbrains.kotlin.backend.common.descriptors.isFunctionOrKFunctionType
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toIrType import org.jetbrains.kotlin.ir.types.toIrType
@@ -20,24 +19,34 @@ import org.jetbrains.kotlin.types.typeUtil.isInterface
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
// TODO: implement pure Ir-based function (see IrTypeUtils.kt)
@Deprecated("Use pure Ir helper")
fun IrType.isNullable() = toKotlinType().isNullable() fun IrType.isNullable() = toKotlinType().isNullable()
@Deprecated("Use pure Ir helper")
fun IrType.isInterface() = toKotlinType().isInterface() fun IrType.isInterface() = toKotlinType().isInterface()
@Deprecated("Use pure Ir helper")
fun IrType.isPrimitiveArray() = KotlinBuiltIns.isPrimitiveArray(toKotlinType()) fun IrType.isPrimitiveArray() = KotlinBuiltIns.isPrimitiveArray(toKotlinType())
@Deprecated("Use pure Ir helper")
fun IrType.getPrimitiveArrayElementType() = KotlinBuiltIns.getPrimitiveArrayElementType(toKotlinType()) fun IrType.getPrimitiveArrayElementType() = KotlinBuiltIns.getPrimitiveArrayElementType(toKotlinType())
@Deprecated("Use pure Ir helper")
fun IrType.isTypeParameter() = toKotlinType().isTypeParameter() fun IrType.isTypeParameter() = toKotlinType().isTypeParameter()
@Deprecated("Use pure Ir helper")
fun IrType.isFunctionOrKFunction() = toKotlinType().isFunctionOrKFunctionType fun IrType.isFunctionOrKFunction() = toKotlinType().isFunctionOrKFunctionType
fun IrType.isFunctionTypeOrSubtype() = toKotlinType().isFunctionTypeOrSubtype @Deprecated("Use pure Ir helper")
fun List<IrType>.commonSupertype() = CommonSupertypes.commonSupertype(map(IrType::toKotlinType)).toIrType()!! fun List<IrType>.commonSupertype() = CommonSupertypes.commonSupertype(map(IrType::toKotlinType)).toIrType()!!
@Deprecated("Use pure Ir helper")
fun IrType.isSubtypeOf(superType: IrType) = toKotlinType().isSubtypeOf(superType.toKotlinType()) fun IrType.isSubtypeOf(superType: IrType) = toKotlinType().isSubtypeOf(superType.toKotlinType())
@Deprecated("Use pure Ir helper")
fun IrType.isSubtypeOfClass(superClass: IrClassSymbol) = DescriptorUtils.isSubtypeOfClass(toKotlinType(), superClass.descriptor) fun IrType.isSubtypeOfClass(superClass: IrClassSymbol) = DescriptorUtils.isSubtypeOfClass(toKotlinType(), superClass.descriptor)
@Deprecated("Use pure Ir helper")
fun IrType.isBuiltinFunctionalTypeOrSubtype() = toKotlinType().isBuiltinFunctionalTypeOrSubtype fun IrType.isBuiltinFunctionalTypeOrSubtype() = toKotlinType().isBuiltinFunctionalTypeOrSubtype
@@ -0,0 +1,41 @@
/*
* 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.util
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.utils.DFS
fun IrType.isFunctionTypeOrSubtype(): Boolean {
val kotlinPackageFqn = FqName.fromSegments(listOf("kotlin"))
fun checkType(irType: IrType): Boolean {
val classifier = irType.classifierOrNull ?: return false
val name = classifier.descriptor.name.asString()
if (!name.startsWith("Function")) return false
val declaration = classifier.owner as IrDeclaration
val parent = declaration.parent as? IrPackageFragment ?: return false
return parent.fqName == kotlinPackageFqn
}
fun superTypes(irType: IrType): List<IrType> {
val classifier = irType.classifierOrNull?.owner ?: return emptyList()
return when(classifier) {
is IrClass -> classifier.superTypes
is IrTypeParameter -> classifier.superTypes
else -> throw IllegalStateException()
}
}
return DFS.ifAny(listOf(this), ::superTypes, ::checkType)
}
@@ -13,4 +13,5 @@ object JsLoweredDeclarationOrigin : IrDeclarationOrigin {
object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER") object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER")
object JS_INTRINSICS_STUB : IrDeclarationOriginImpl("JS_INTRINSICS_STUB") object JS_INTRINSICS_STUB : IrDeclarationOriginImpl("JS_INTRINSICS_STUB")
object JS_CLOSURE_BOX_CLASS : IrStatementOriginImpl("JS_CLOSURE_BOX_CLASS") object JS_CLOSURE_BOX_CLASS : IrStatementOriginImpl("JS_CLOSURE_BOX_CLASS")
object JS_CLOSURE_BOX_CLASS_DECLARATION : IrDeclarationOriginImpl("JS_CLOSURE_BOX_CLASS_DECLARATION")
} }
@@ -0,0 +1,136 @@
/*
* 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
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedPropertyDescriptor
import org.jetbrains.kotlin.backend.common.ir.DeclarationFactory
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.name.Name
import java.util.*
class JsDeclarationFactory : DeclarationFactory {
private val singletonFieldDescriptors = HashMap<IrClass, IrField>()
private val outerThisFieldSymbols = HashMap<IrClass, IrField>()
private val innerClassConstructors = HashMap<IrConstructor, IrConstructor>()
override fun getFieldForEnumEntry(enumEntry: IrEnumEntry, type: IrType): IrField = TODO()
override fun getOuterThisField(innerClass: IrClass): IrField =
if (!innerClass.isInner) throw AssertionError("Class is not inner: ${innerClass.dump()}")
else {
outerThisFieldSymbols.getOrPut(innerClass) {
val outerClass = innerClass.parent as? IrClass
?: throw AssertionError("No containing class for inner class ${innerClass.dump()}")
val name = Name.identifier("\$this")
val fieldType = outerClass.defaultType
val visibility = Visibilities.PROTECTED
createPropertyWithBackingField(name, visibility, innerClass, fieldType, DeclarationFactory.FIELD_FOR_OUTER_THIS)
}
}
private fun createPropertyWithBackingField(name: Name, visibility: Visibility, parent: IrClass, fieldType: IrType, origin: IrDeclarationOrigin): IrField {
val descriptor = WrappedPropertyDescriptor()
val symbol = IrFieldSymbolImpl(descriptor)
return IrFieldImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
origin,
symbol,
name,
fieldType,
visibility,
true,
false,
false
).also {
descriptor.bind(it)
it.parent = parent
}
}
override fun getInnerClassConstructorWithOuterThisParameter(innerClassConstructor: IrConstructor): IrConstructor {
val innerClass = innerClassConstructor.parent as IrClass
assert(innerClass.isInner) { "Class is not inner: $innerClass" }
return innerClassConstructors.getOrPut(innerClassConstructor) {
createInnerClassConstructorWithOuterThisParameter(innerClassConstructor)
}
}
private fun createInnerClassConstructorWithOuterThisParameter(oldConstructor: IrConstructor): IrConstructor {
val irClass = oldConstructor.parent as IrClass
val outerThisType = (irClass.parent as IrClass).defaultType
val descriptor = WrappedClassConstructorDescriptor(oldConstructor.descriptor.annotations, oldConstructor.descriptor.source)
val symbol = IrConstructorSymbolImpl(descriptor)
val newConstructor = IrConstructorImpl(
oldConstructor.startOffset,
oldConstructor.endOffset,
oldConstructor.origin,
symbol,
oldConstructor.name,
oldConstructor.visibility,
oldConstructor.isInline,
oldConstructor.isExternal,
oldConstructor.isPrimary
).also {
descriptor.bind(it)
it.parent = oldConstructor.parent
it.returnType = oldConstructor.returnType
}
val outerThisValueParameter =
JsIrBuilder.buildValueParameter(Namer.OUTER_NAME, 0, outerThisType).also { it.parent = newConstructor }
val newValueParameters = mutableListOf(outerThisValueParameter)
for (p in oldConstructor.valueParameters) {
newValueParameters += p.copyTo(newConstructor, 1)
}
for (p in oldConstructor.typeParameters) {
newConstructor.typeParameters += p.copyTo(newConstructor)
}
newConstructor.valueParameters += newValueParameters
return newConstructor
}
override fun getFieldForObjectInstance(singleton: IrClass): IrField =
singletonFieldDescriptors.getOrPut(singleton) {
createObjectInstanceFieldDescriptor(singleton, JsIrBuilder.SYNTHESIZED_DECLARATION)
}
private fun createObjectInstanceFieldDescriptor(singleton: IrClass, origin: IrDeclarationOrigin): IrField {
assert(singleton.kind == ClassKind.OBJECT) { "Should be an object: $singleton" }
val name = Name.identifier("INSTANCE")
return createPropertyWithBackingField(name, Visibilities.PUBLIC, singleton, singleton.defaultType, origin)
}
}
@@ -1,110 +0,0 @@
/*
* 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
import org.jetbrains.kotlin.backend.common.descriptors.DescriptorsFactory
import org.jetbrains.kotlin.builtins.CompanionObjectMapping.isMappedIntrinsicCompanionObject
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
import org.jetbrains.kotlin.ir.declarations.IrClass
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
import java.util.*
class JsDescriptorsFactory : DescriptorsFactory {
private val singletonFieldDescriptors = HashMap<IrBindableSymbol<*, *>, IrFieldSymbol>()
private val outerThisFieldSymbols = HashMap<IrClass, IrFieldSymbol>()
private val innerClassConstructors = HashMap<IrConstructorSymbol, IrConstructorSymbol>()
override fun getSymbolForEnumEntry(enumEntry: IrEnumEntrySymbol): IrFieldSymbol = TODO()
override fun getOuterThisFieldSymbol(innerClass: IrClass): IrFieldSymbol =
if (!innerClass.isInner) throw AssertionError("Class is not inner: ${innerClass.dump()}")
else outerThisFieldSymbols.getOrPut(innerClass) {
val outerClass = innerClass.parent as? IrClass
?: throw AssertionError("No containing class for inner class ${innerClass.dump()}")
IrFieldSymbolImpl(PropertyDescriptorImpl.create(
innerClass.descriptor,
Annotations.EMPTY,
Modality.FINAL,
Visibilities.PROTECTED,
false,
Name.identifier("\$this"),
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE,
false,
true,
false,
false,
false,
false
).apply {
setType(outerClass.defaultType.toKotlinType(), emptyList(), innerClass.descriptor.thisAsReceiverParameter, null)
initialize(null, null)
})
}
override fun getInnerClassConstructorWithOuterThisParameter(innerClassConstructor: IrConstructor): IrConstructorSymbol {
val innerClass = innerClassConstructor.parent as IrClass
assert(innerClass.isInner) { "Class is not inner: $innerClass" }
return innerClassConstructors.getOrPut(innerClassConstructor.symbol) {
createInnerClassConstructorWithOuterThisParameter(innerClassConstructor.descriptor)
}
}
private fun createInnerClassConstructorWithOuterThisParameter(oldDescriptor: ClassConstructorDescriptor): IrConstructorSymbol {
val classDescriptor = oldDescriptor.containingDeclaration
val outerThisType = (classDescriptor.containingDeclaration as ClassDescriptor).defaultType
val newDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
classDescriptor, oldDescriptor.annotations, oldDescriptor.isPrimary, oldDescriptor.source
)
val outerThisValueParameter = createValueParameter(newDescriptor, 0, Namer.OUTER_NAME, outerThisType)
val newValueParameters =
listOf(outerThisValueParameter) +
oldDescriptor.valueParameters.map { it.copy(newDescriptor, it.name, it.index + 1) }
newDescriptor.initialize(newValueParameters, oldDescriptor.visibility)
newDescriptor.returnType = oldDescriptor.returnType
return IrConstructorSymbolImpl(newDescriptor)
}
override fun getSymbolForObjectInstance(singleton: IrClassSymbol): IrFieldSymbol =
singletonFieldDescriptors.getOrPut(singleton) {
IrFieldSymbolImpl(createObjectInstanceFieldDescriptor(singleton.descriptor))
}
private fun createObjectInstanceFieldDescriptor(objectDescriptor: ClassDescriptor): PropertyDescriptor {
assert(objectDescriptor.kind == ClassKind.OBJECT) { "Should be an object: $objectDescriptor" }
val isNotMappedCompanion = objectDescriptor.isCompanionObject && !isMappedIntrinsicCompanionObject(objectDescriptor)
val name = if (isNotMappedCompanion) objectDescriptor.name else Name.identifier("INSTANCE")
val containingDeclaration = if (isNotMappedCompanion) objectDescriptor.containingDeclaration else objectDescriptor
return PropertyDescriptorImpl.create(
containingDeclaration,
Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC, false,
name,
CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE, /* lateInit = */ false, /* isConst = */ false,
/* isExpect = */ false, /* isActual = */ false, /* isExternal = */ false, /* isDelegated = */ false
).apply {
setType(objectDescriptor.defaultType, emptyList(), null, null)
initialize(null, null)
}
}
}
@@ -7,31 +7,20 @@ package org.jetbrains.kotlin.ir.backend.js
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
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.symbols.impl.IrExternalPackageFragmentSymbolImpl
import org.jetbrains.kotlin.js.resolve.JsPlatform.builtIns
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.psi2ir.findSingleFunction import org.jetbrains.kotlin.psi2ir.findSingleFunction
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.Variance
class JsIntrinsics( class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendContext) {
private val module: ModuleDescriptor,
private val irBuiltIns: IrBuiltIns,
val context: JsIrBackendContext
) {
private val stubBuilder = DeclarationStubGenerator( private val externalPackageFragmentSymbol = IrExternalPackageFragmentSymbolImpl(context.internalPackageFragmentDescriptor)
module, context.symbolTable, JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB, irBuiltIns.languageVersionSettings private val externalPackageFragment = IrExternalPackageFragmentImpl(externalPackageFragmentSymbol)
)
// Equality operations: // Equality operations:
@@ -172,6 +161,11 @@ class JsIntrinsics(
val charConstructor = context.symbolTable.referenceConstructor(context.getClass(KotlinBuiltIns.FQ_NAMES._char.toSafe()).constructors.single()) val charConstructor = context.symbolTable.referenceConstructor(context.getClass(KotlinBuiltIns.FQ_NAMES._char.toSafe()).constructors.single())
val unreachable = defineUnreachableIntrinsic()
val returnIfSuspended = getInternalFunction("returnIfSuspended")
val getContinuation = getInternalFunction("getContinuation")
// Helpers: // Helpers:
private fun getInternalFunction(name: String) = private fun getInternalFunction(name: String) =
@@ -180,53 +174,35 @@ class JsIntrinsics(
private fun getInternalWithoutPackage(name: String) = private fun getInternalWithoutPackage(name: String) =
context.symbolTable.referenceSimpleFunction(context.getFunctions(FqName(name)).single()) context.symbolTable.referenceSimpleFunction(context.getFunctions(FqName(name)).single())
// TODO: unify how we create intrinsic symbols // TODO: unify how we create intrinsic symbols
private fun defineObjectCreateIntrinsic(): IrSimpleFunction { private fun defineObjectCreateIntrinsic() =
JsIrBuilder.buildFunction("Object\$create", isInline = true, origin = JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB).also {
val typeParam = TypeParameterDescriptorImpl.createWithDefaultBound( val typeParameter = JsIrBuilder.buildTypeParameter(Name.identifier("T"), 0, true)
builtIns.any, val anyType = irBuiltIns.anyType
Annotations.EMPTY, typeParameter.parent = it
true, typeParameter.superTypes += anyType
Variance.INVARIANT, it.typeParameters += typeParameter
Name.identifier("T"), it.returnType = anyType
0 it.parent = externalPackageFragment
) externalPackageFragment.declarations += it
val returnType = KotlinTypeFactory.simpleType(Annotations.EMPTY, typeParam.typeConstructor, emptyList(), false)
val desc = SimpleFunctionDescriptorImpl.create(
module,
Annotations.EMPTY,
Name.identifier("Object\$create"),
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE
).apply {
initialize(null, null, listOf(typeParam), emptyList(), returnType, Modality.FINAL, Visibilities.PUBLIC)
isInline = true
} }
return stubBuilder.generateFunctionStub(desc) private fun defineSetJSPropertyIntrinsic() =
} JsIrBuilder.buildFunction("\$setJSProperty\$", origin = JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB).also {
it.returnType = irBuiltIns.unitType
private fun defineSetJSPropertyIntrinsic(): IrSimpleFunction { listOf("receiver", "fieldName", "fieldValue").mapIndexedTo(it.valueParameters) { i, p ->
val returnType = irBuiltIns.unit JsIrBuilder.buildValueParameter(p, i, irBuiltIns.anyType).also { v -> v.parent = it }
}
val desc = SimpleFunctionDescriptorImpl.create( it.parent = externalPackageFragment
module, externalPackageFragment.declarations += it
Annotations.EMPTY,
Name.identifier("\$setJSProperty\$"),
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE
).apply {
val parameterDescriptors = listOf("receiver", "fieldName", "fieldValue")
.mapIndexed { i, name -> createValueParameter(this, i, name, irBuiltIns.any) }
initialize(null, null, emptyList(), parameterDescriptors, returnType, Modality.FINAL, Visibilities.PUBLIC)
} }
return stubBuilder.generateFunctionStub(desc) private fun defineUnreachableIntrinsic() =
} JsIrBuilder.buildFunction(Namer.UNREACHABLE_NAME, origin = JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB).also {
it.returnType = irBuiltIns.nothingType
it.parent = externalPackageFragment
externalPackageFragment.declarations += it
}
private fun unOp(name: String, returnType: KotlinType = irBuiltIns.anyN) = private fun unOp(name: String, returnType: KotlinType = irBuiltIns.anyN) =
irBuiltIns.run { defineOperator(name, returnType, listOf(anyN)) } irBuiltIns.run { defineOperator(name, returnType, listOf(anyN)) }
@@ -10,19 +10,23 @@ import org.jetbrains.kotlin.backend.common.ReflectionTypes
import org.jetbrains.kotlin.backend.common.descriptors.KnownPackageFragmentDescriptor import org.jetbrains.kotlin.backend.common.descriptors.KnownPackageFragmentDescriptor
import org.jetbrains.kotlin.backend.common.ir.Ir 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.JsDeclarationFactory
import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
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.SourceManager
import org.jetbrains.kotlin.ir.SourceRangeInfo
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.lower.inline.ModuleIndex import org.jetbrains.kotlin.ir.backend.js.lower.inline.ModuleIndex
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames 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.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
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.IrEnumEntrySymbol import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
@@ -46,9 +50,23 @@ class JsIrBackendContext(
override val builtIns = module.builtIns override val builtIns = module.builtIns
val internalPackageFragmentDescriptor = KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal"))
val implicitDeclarationFile = IrFileImpl(object : SourceManager.FileEntry {
override val name = "<implicitDeclarations>"
override val maxOffset = UNDEFINED_OFFSET
override fun getSourceRangeInfo(beginOffset: Int, endOffset: Int) =
SourceRangeInfo("", UNDEFINED_OFFSET, UNDEFINED_OFFSET, UNDEFINED_OFFSET, UNDEFINED_OFFSET, UNDEFINED_OFFSET, UNDEFINED_OFFSET)
override fun getLineNumber(offset: Int) = UNDEFINED_OFFSET
override fun getColumnNumber(offset: Int) = UNDEFINED_OFFSET
}, internalPackageFragmentDescriptor).also {
irModuleFragment.files += it
}
override val sharedVariablesManager = override val sharedVariablesManager =
JsSharedVariablesManager(builtIns, KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal"))) JsSharedVariablesManager(irBuiltIns, implicitDeclarationFile)
override val descriptorsFactory = JsDescriptorsFactory() override val declarationFactory = JsDeclarationFactory()
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"))
@@ -98,7 +116,7 @@ class JsIrBackendContext(
return vars.single() return vars.single()
} }
val intrinsics = JsIntrinsics(module, irBuiltIns, this) val intrinsics = JsIntrinsics(irBuiltIns, this)
private val operatorMap = referenceOperators() private val operatorMap = referenceOperators()
@@ -5,101 +5,97 @@
package org.jetbrains.kotlin.ir.backend.js package org.jetbrains.kotlin.ir.backend.js
import org.jetbrains.kotlin.backend.common.descriptors.KnownClassDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.SharedVariablesManager import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.backend.common.descriptors.WrappedPropertyDescriptor
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.backend.common.ir.DeclarationFactory
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.backend.common.ir.SharedVariablesManager
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.IrSetVariable import org.jetbrains.kotlin.ir.expressions.IrSetVariable
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.Variance
class JsSharedVariablesManager(val builtIns: KotlinBuiltIns, val jsInterinalPackage: PackageFragmentDescriptor) : SharedVariablesManager { class JsSharedVariablesManager(val builtIns: IrBuiltIns, val implicitDeclarationsFile: IrFile) : SharedVariablesManager {
override fun declareSharedVariable(originalDeclaration: IrVariable): IrVariable { override fun declareSharedVariable(originalDeclaration: IrVariable): IrVariable {
val variableDescriptor = originalDeclaration.descriptor
val sharedVariableDescriptor = LocalVariableDescriptor(
variableDescriptor.containingDeclaration, variableDescriptor.annotations, variableDescriptor.name,
getSharedVariableType(variableDescriptor.type),
false, false, variableDescriptor.isLateInit, variableDescriptor.source
)
val valueType = originalDeclaration.type val valueType = originalDeclaration.type
val boxConstructor = closureBoxConstructorTypeDescriptor
val boxConstructorSymbol = closureBoxConstructorTypeSymbol
val initializer = originalDeclaration.initializer ?: IrConstImpl.constNull( val initializer = originalDeclaration.initializer ?: IrConstImpl.constNull(
originalDeclaration.startOffset, originalDeclaration.startOffset,
originalDeclaration.endOffset, originalDeclaration.endOffset,
valueType valueType
) )
// TODO use buildCall?
val constructorCall = IrCallImpl( val constructorSymbol = closureBoxConstructorDeclaration.symbol
originalDeclaration.startOffset,
originalDeclaration.endOffset, val irCall = IrCallImpl(initializer.startOffset, initializer.endOffset, closureBoxType, constructorSymbol).apply {
// TODO wrong type
originalDeclaration.type,
boxConstructorSymbol,
boxConstructor,
1,
JsLoweredDeclarationOrigin.JS_CLOSURE_BOX_CLASS
).apply {
putTypeArgument(0, valueType)
putValueArgument(0, initializer) putValueArgument(0, initializer)
} }
val descriptor = WrappedVariableDescriptor()
return IrVariableImpl( return IrVariableImpl(
originalDeclaration.startOffset, originalDeclaration.startOffset,
originalDeclaration.endOffset, originalDeclaration.endOffset,
originalDeclaration.origin, originalDeclaration.origin,
sharedVariableDescriptor, IrVariableSymbolImpl(descriptor),
// TODO wrong type ? originalDeclaration.name,
originalDeclaration.type, irCall.type,
constructorCall false,
) false,
false
).also {
descriptor.bind(it)
it.parent = originalDeclaration.parent
it.initializer = irCall
}
} }
override fun defineSharedValue(originalDeclaration: IrVariable, sharedVariableDeclaration: IrVariable) = sharedVariableDeclaration override fun defineSharedValue(originalDeclaration: IrVariable, sharedVariableDeclaration: IrVariable) = sharedVariableDeclaration
override fun getSharedValue(sharedVariableSymbol: IrVariableSymbol, originalGet: IrGetValue): IrExpression = override fun getSharedValue(sharedVariableSymbol: IrVariableSymbol, originalGet: IrGetValue) = IrGetFieldImpl(
IrGetFieldImpl( originalGet.startOffset, originalGet.endOffset,
originalGet.startOffset, originalGet.endOffset, closureBoxFieldDeclaration.symbol,
closureBoxFieldSymbol, originalGet.type,
originalGet.type, IrGetValueImpl(
IrGetValueImpl( originalGet.startOffset,
originalGet.startOffset, originalGet.endOffset,
originalGet.endOffset, closureBoxType,
originalGet.type, sharedVariableSymbol,
sharedVariableSymbol
),
originalGet.origin originalGet.origin
) ),
originalGet.origin
)
override fun setSharedValue(sharedVariableSymbol: IrVariableSymbol, originalSet: IrSetVariable): IrExpression = override fun setSharedValue(sharedVariableSymbol: IrVariableSymbol, originalSet: IrSetVariable): IrExpression =
IrSetFieldImpl( IrSetFieldImpl(
originalSet.startOffset, originalSet.endOffset, originalSet.startOffset,
closureBoxFieldSymbol, originalSet.endOffset,
closureBoxFieldDeclaration.symbol,
IrGetValueImpl( IrGetValueImpl(
originalSet.startOffset, originalSet.startOffset,
originalSet.endOffset, originalSet.endOffset,
originalSet.type, closureBoxType,
sharedVariableSymbol sharedVariableSymbol,
originalSet.origin
), ),
originalSet.value, originalSet.value,
originalSet.type, originalSet.type,
@@ -108,84 +104,93 @@ class JsSharedVariablesManager(val builtIns: KotlinBuiltIns, val jsInterinalPack
private val boxTypeName = "\$closureBox\$" private val boxTypeName = "\$closureBox\$"
private val closureBoxTypeDescriptor = createClosureBoxClass() private val closureBoxClassDeclaration by lazy {
private val closureBoxConstructorTypeDescriptor = createClosureBoxClassConstructor() createClosureBoxClassDeclaration()
private val closureBoxFieldDescriptor = createClosureBoxField() }
val closureBoxConstructorTypeSymbol = createFunctionSymbol(closureBoxConstructorTypeDescriptor) private val closureBoxConstructorDeclaration by lazy {
private val closureBoxFieldSymbol = IrFieldSymbolImpl(closureBoxFieldDescriptor) createClosureBoxConstructorDeclaration()
}
private val closureBoxFieldDeclaration by lazy {
closureBoxPropertyDeclaration
}
private fun createClosureBoxClass(): ClassDescriptor = private val closureBoxPropertyDeclaration by lazy {
KnownClassDescriptor.createClassWithTypeParameters( createClosureBoxPropertyDeclaration()
Name.identifier(boxTypeName), jsInterinalPackage, listOf(builtIns.anyType), listOf( }
Name.identifier("T")
) private lateinit var closureBoxType: IrType
private fun createClosureBoxClassDeclaration(): IrClass {
val descriptor = WrappedClassDescriptor()
val declaration = IrClassImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, JsLoweredDeclarationOrigin.JS_CLOSURE_BOX_CLASS_DECLARATION, IrClassSymbolImpl(descriptor),
Name.identifier(boxTypeName), ClassKind.CLASS, Visibilities.PUBLIC, Modality.FINAL, false, false, false, false, false
) )
private fun createClosureBoxClassConstructor(): ClassConstructorDescriptor = descriptor.bind(declaration)
ClassConstructorDescriptorImpl.create( declaration.parent = implicitDeclarationsFile
closureBoxTypeDescriptor, closureBoxType = IrSimpleTypeImpl(declaration.symbol, false, emptyList(), emptyList())
Annotations.EMPTY, declaration.thisReceiver =
true, JsIrBuilder.buildValueParameter(Name.special("<this>"), -1, closureBoxType, IrDeclarationOrigin.INSTANCE_RECEIVER)
SourceElement.NO_SOURCE implicitDeclarationsFile.declarations += declaration
).apply {
val typeParameter = constructedClass.declaredTypeParameters[0]
val typeParameterType = KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
Annotations.EMPTY,
typeParameter.typeConstructor,
listOf(),
false,
MemberScope.Empty
)
val parameterType = KotlinTypeFactory.simpleType( return declaration
Annotations.EMPTY, }
typeParameter.typeConstructor,
listOf(), true
)
val paramDesc = createValueParameter(this, 0, "v", parameterType) private fun createClosureBoxPropertyDeclaration(): IrField {
val descriptor = WrappedPropertyDescriptor()
initialize(listOf(paramDesc), Visibilities.PUBLIC) val symbol = IrFieldSymbolImpl(descriptor)
returnType = KotlinTypeFactory.simpleNotNullType( val fieldName = Name.identifier("v")
Annotations.EMPTY, return IrFieldImpl(
closureBoxTypeDescriptor, UNDEFINED_OFFSET,
listOf(TypeProjectionImpl(Variance.INVARIANT, typeParameterType)) UNDEFINED_OFFSET,
) DeclarationFactory.FIELD_FOR_OUTER_THIS,
} symbol,
fieldName,
private fun createClosureBoxField(): PropertyDescriptor { builtIns.anyNType,
val desc = PropertyDescriptorImpl.create(
closureBoxTypeDescriptor,
Annotations.EMPTY,
Modality.FINAL,
Visibilities.PUBLIC, Visibilities.PUBLIC,
true,
Name.identifier("v"),
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE,
false,
false,
false,
false, false,
false, false,
false false
) ).also {
descriptor.bind(it)
desc.setType(builtIns.anyType, emptyList(), closureBoxTypeDescriptor.thisAsReceiverParameter, null) it.parent = closureBoxClassDeclaration
desc.initialize(null, null) closureBoxClassDeclaration.declarations += it
}
return desc
} }
private fun getRefType(valueType: KotlinType) = private fun createClosureBoxConstructorDeclaration(): IrConstructor {
KotlinTypeFactory.simpleNotNullType( val descriptor = WrappedClassConstructorDescriptor()
Annotations.EMPTY, val symbol = IrConstructorSymbolImpl(descriptor)
closureBoxTypeDescriptor,
listOf(TypeProjectionImpl(Variance.INVARIANT, valueType)) val declaration = IrConstructorImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, JsLoweredDeclarationOrigin.JS_CLOSURE_BOX_CLASS_DECLARATION, symbol,
Name.special("<init>"), Visibilities.PUBLIC, false, false, true
) )
private fun getSharedVariableType(type: KotlinType) = getRefType(type) descriptor.bind(declaration)
declaration.parent = closureBoxClassDeclaration
val parameterDeclaration = createClosureBoxConstructorParameterDeclaration(declaration)
declaration.valueParameters += parameterDeclaration
val receiver = JsIrBuilder.buildGetValue(closureBoxClassDeclaration.thisReceiver!!.symbol)
val value = JsIrBuilder.buildGetValue(parameterDeclaration.symbol)
val setField = JsIrBuilder.buildSetField(closureBoxFieldDeclaration.symbol, receiver, value, closureBoxFieldDeclaration.type)
declaration.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, listOf(setField))
closureBoxClassDeclaration.declarations += declaration
return declaration
}
private fun createClosureBoxConstructorParameterDeclaration(irConstructor: IrConstructor): IrValueParameter {
return JsIrBuilder.buildValueParameter("p", 0, closureBoxPropertyDeclaration.type).also {
it.parent = irConstructor
}
}
} }
@@ -93,6 +93,7 @@ private fun JsIrBackendContext.lower(moduleFragment: IrModuleFragment) {
moduleFragment.files.forEach(LateinitLowering(this, true)::lower) moduleFragment.files.forEach(LateinitLowering(this, true)::lower)
moduleFragment.files.forEach(DefaultArgumentStubGenerator(this)::runOnFilePostfix) moduleFragment.files.forEach(DefaultArgumentStubGenerator(this)::runOnFilePostfix)
moduleFragment.files.forEach(DefaultParameterInjector(this)::runOnFilePostfix) moduleFragment.files.forEach(DefaultParameterInjector(this)::runOnFilePostfix)
moduleFragment.files.forEach(DefaultParameterCleaner(this)::runOnFilePostfix)
moduleFragment.files.forEach(SharedVariablesLowering(this)::runOnFilePostfix) moduleFragment.files.forEach(SharedVariablesLowering(this)::runOnFilePostfix)
moduleFragment.files.forEach(EnumClassLowering(this)::runOnFilePostfix) moduleFragment.files.forEach(EnumClassLowering(this)::runOnFilePostfix)
moduleFragment.files.forEach(EnumUsageLowering(this)::lower) moduleFragment.files.forEach(EnumUsageLowering(this)::lower)
@@ -5,31 +5,32 @@
package org.jetbrains.kotlin.ir.backend.js.ir package org.jetbrains.kotlin.ir.backend.js.ir
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
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.IrType
import org.jetbrains.kotlin.ir.types.createType
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.createDispatchReceiverParameter
import org.jetbrains.kotlin.ir.util.endOffset
import org.jetbrains.kotlin.ir.util.startOffset
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.resolve.OverridingStrategy import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
import java.lang.reflect.Proxy
object JsIrBuilder { object JsIrBuilder {
@@ -57,27 +58,108 @@ object JsIrBuilder {
fun buildThrow(type: IrType, 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, type: IrType? = null) = fun buildValueParameter(name: String = "tmp", index: Int, type: IrType) = buildValueParameter(Name.identifier(name), index, type)
IrValueParameterImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SYNTHESIZED_DECLARATION, symbol, type ?: symbol.owner.type, null)
fun buildFunction(symbol: IrSimpleFunctionSymbol, returnType: IrType) = fun buildValueParameter(name: Name, index: Int, type: IrType, origin: IrDeclarationOrigin = SYNTHESIZED_DECLARATION): IrValueParameter {
IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SYNTHESIZED_DECLARATION, symbol).apply { val descriptor = WrappedValueParameterDescriptor()
this.returnType = returnType return IrValueParameterImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
origin,
IrValueParameterSymbolImpl(descriptor),
name,
index,
type,
null,
false,
false
).also {
descriptor.bind(it)
} }
}
fun buildTypeParameter(name: Name, index: Int, isReified: Boolean, variance: Variance = Variance.INVARIANT): IrTypeParameter {
val descriptor = WrappedTypeParameterDescriptor()
return IrTypeParameterImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
SYNTHESIZED_DECLARATION,
IrTypeParameterSymbolImpl(descriptor),
name,
index,
isReified,
variance
).also {
descriptor.bind(it)
}
}
fun buildFunction(
name: String,
visibility: Visibility = Visibilities.PUBLIC,
modality: Modality = Modality.FINAL,
isInline: Boolean = false,
isExternal: Boolean = false,
isTailrec: Boolean = false,
isSuspend: Boolean = false,
origin: IrDeclarationOrigin = SYNTHESIZED_DECLARATION
) = JsIrBuilder.buildFunction(Name.identifier(name), visibility, modality, isInline, isExternal, isTailrec, isSuspend, origin)
fun buildFunction(
name: Name,
visibility: Visibility = Visibilities.PUBLIC,
modality: Modality = Modality.FINAL,
isInline: Boolean = false,
isExternal: Boolean = false,
isTailrec: Boolean = false,
isSuspend: Boolean = false,
origin: IrDeclarationOrigin = SYNTHESIZED_DECLARATION
): IrSimpleFunction {
val descriptor = WrappedSimpleFunctionDescriptor()
return IrFunctionImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
origin,
IrSimpleFunctionSymbolImpl(descriptor),
name,
visibility,
modality,
isInline,
isExternal,
isTailrec,
isSuspend
).also { descriptor.bind(it) }
}
fun buildGetObjectValue(type: IrType, classSymbol: IrClassSymbol) = fun buildGetObjectValue(type: IrType, classSymbol: IrClassSymbol) =
IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, classSymbol) IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, classSymbol)
fun buildGetClass(expression: IrExpression, type: IrType) = 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.owner.type, symbol, 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) = fun buildSetVariable(symbol: IrVariableSymbol, value: IrExpression, type: IrType) =
IrSetVariableImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, symbol, value, SYNTHESIZED_STATEMENT) IrSetVariableImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, symbol, value, SYNTHESIZED_STATEMENT)
fun buildGetField(symbol: IrFieldSymbol, receiver: IrExpression?, superQualifierSymbol: IrClassSymbol? = null, type: IrType? = null) = fun buildGetField(symbol: IrFieldSymbol, receiver: IrExpression?, superQualifierSymbol: IrClassSymbol? = null, type: IrType? = null) =
IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol, type ?: symbol.owner.type, receiver, SYNTHESIZED_STATEMENT, superQualifierSymbol) IrGetFieldImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
symbol,
type ?: symbol.owner.type,
receiver,
SYNTHESIZED_STATEMENT,
superQualifierSymbol
)
fun buildSetField(symbol: IrFieldSymbol, receiver: IrExpression?, value: IrExpression, type: IrType, superQualifierSymbol: IrClassSymbol? = null) = 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) IrSetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol, receiver, value, type, SYNTHESIZED_STATEMENT, superQualifierSymbol)
fun buildBlockBody(statements: List<IrStatement>) = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, statements) fun buildBlockBody(statements: List<IrStatement>) = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, statements)
@@ -92,9 +174,30 @@ object JsIrBuilder {
fun buildFunctionReference(type: IrType, symbol: IrFunctionSymbol) = fun buildFunctionReference(type: IrType, symbol: IrFunctionSymbol) =
IrFunctionReferenceImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, symbol, symbol.descriptor, 0, null) IrFunctionReferenceImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, symbol, symbol.descriptor, 0, null)
fun buildVar(symbol: IrVariableSymbol, initializer: IrExpression? = null, type: IrType) = fun buildVar(
IrVariableImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SYNTHESIZED_DECLARATION, symbol, type) type: IrType,
.apply { this.initializer = initializer } name: String = "tmp",
isVar: Boolean = false,
isConst: Boolean = false,
isLateinit: Boolean = false,
initializer: IrExpression? = null
): IrVariable {
val descriptor = WrappedVariableDescriptor()
return IrVariableImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
SYNTHESIZED_DECLARATION,
IrVariableSymbolImpl(descriptor),
Name.identifier(name),
type,
isVar,
isConst,
isLateinit
).also {
descriptor.bind(it)
it.initializer = initializer
}
}
fun buildBreak(type: IrType, loop: IrLoop) = IrBreakImpl(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 buildContinue(type: IrType, loop: IrLoop) = IrContinueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, loop)
@@ -135,7 +238,6 @@ object JsIrBuilder {
fun buildCatch(ex: IrVariable, block: IrBlockImpl) = IrCatchImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, ex, block) fun buildCatch(ex: IrVariable, block: IrBlockImpl) = IrCatchImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, ex, block)
} }
object SetDeclarationsParentVisitor : IrElementVisitor<Unit, IrDeclarationParent> { object SetDeclarationsParentVisitor : IrElementVisitor<Unit, IrDeclarationParent> {
override fun visitElement(element: IrElement, data: IrDeclarationParent) { override fun visitElement(element: IrElement, data: IrDeclarationParent) {
if (element !is IrDeclarationParent) { if (element !is IrDeclarationParent) {
@@ -149,21 +251,6 @@ object SetDeclarationsParentVisitor : IrElementVisitor<Unit, IrDeclarationParent
} }
} }
fun SymbolTable.translateErased(type: KotlinType): IrSimpleType {
val descriptor = TypeUtils.getClassDescriptor(type)
if (descriptor == null) return translateErased(type.immediateSupertypes().first())
val classSymbol = this.referenceClass(descriptor)
val nullable = type.isMarkedNullable
val arguments = type.arguments.map { IrStarProjectionImpl }
return classSymbol.createType(nullable, arguments)
}
fun IrDeclarationContainer.addChildren(declarations: List<IrDeclaration>) {
declarations.forEach { this.addChild(it) }
}
fun IrDeclarationContainer.addChild(declaration: IrDeclaration) { fun IrDeclarationContainer.addChild(declaration: IrDeclaration) {
this.declarations += declaration this.declarations += declaration
declaration.accept(SetDeclarationsParentVisitor, this) declaration.accept(SetDeclarationsParentVisitor, this)
@@ -172,236 +259,9 @@ fun IrDeclarationContainer.addChild(declaration: IrDeclaration) {
fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMap { fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMap {
when (it) { when (it) {
is IrSimpleFunction -> listOf(it) is IrSimpleFunction -> listOf(it)
is IrProperty -> listOfNotNull(it.getter as IrSimpleFunction?, it.setter as IrSimpleFunction?) is IrProperty -> listOfNotNull(it.getter, it.setter)
else -> emptyList() else -> emptyList()
} }
} }
fun IrClass.setSuperSymbols(superTypes: List<IrType>) {
val supers = superTypes.map { it.getClass()!! }
assert(this.superDescriptors().toSet() == supers.map { it.descriptor }.toSet())
assert(this.superTypes.isEmpty())
this.superTypes += superTypes
val superMembers = supers.flatMap {
it.simpleFunctions()
}.associateBy { it.descriptor }
this.simpleFunctions().forEach {
assert(it.overriddenSymbols.isEmpty())
it.descriptor.overriddenDescriptors.mapTo(it.overriddenSymbols) {
val superMember = superMembers[it.original] ?: error(it.original)
superMember.symbol
}
}
}
fun IrSimpleFunction.setOverrides(symbolTable: SymbolTable) {
assert(this.overriddenSymbols.isEmpty())
this.descriptor.overriddenDescriptors.mapTo(this.overriddenSymbols) {
symbolTable.referenceSimpleFunction(it.original)
}
}
private fun IrClass.superDescriptors() =
this.descriptor.typeConstructor.supertypes.map { it.constructor.declarationDescriptor as ClassDescriptor }
fun IrClass.setSuperSymbols(symbolTable: SymbolTable) {
assert(this.superTypes.isEmpty())
this.descriptor.typeConstructor.supertypes.mapTo(this.superTypes) { symbolTable.translateErased(it) }
this.simpleFunctions().forEach {
it.setOverrides(symbolTable)
}
}
private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int =
descriptor.startOffset ?: this.startOffset
private fun IrElement.innerEndOffset(descriptor: DeclarationDescriptorWithSource): Int =
descriptor.endOffset ?: this.endOffset
fun IrFunction.createParameterDeclarations(symbolTable: SymbolTable) {
fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl(
innerStartOffset(this), innerEndOffset(this),
IrDeclarationOrigin.DEFINED,
this, symbolTable.translateErased(this.type),
(this as? ValueParameterDescriptor)?.varargElementType?.let { symbolTable.translateErased(it) }
).also {
it.parent = this@createParameterDeclarations
}
dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.irValueParameter()
extensionReceiverParameter = descriptor.extensionReceiverParameter?.irValueParameter()
assert(valueParameters.isEmpty())
descriptor.valueParameters.mapTo(valueParameters) { it.irValueParameter() }
assert(typeParameters.isEmpty())
descriptor.typeParameters.mapTo(typeParameters) {
IrTypeParameterImpl(
innerStartOffset(it), innerEndOffset(it),
IrDeclarationOrigin.DEFINED,
it
).also { typeParameter ->
typeParameter.parent = this
typeParameter.descriptor.upperBounds.mapTo(typeParameter.superTypes, symbolTable::translateErased)
}
}
}
private fun createFakeOverride(
descriptor: CallableMemberDescriptor,
startOffset: Int,
endOffset: Int,
symbolTable: SymbolTable
): IrDeclaration {
fun FunctionDescriptor.createFunction(): IrSimpleFunction = IrFunctionImpl(
startOffset, endOffset,
IrDeclarationOrigin.FAKE_OVERRIDE, this
).apply {
returnType = symbolTable.translateErased(this@createFunction.returnType!!)
createParameterDeclarations(symbolTable)
}
return when (descriptor) {
is FunctionDescriptor -> descriptor.createFunction()
is PropertyDescriptor ->
IrPropertyImpl(startOffset, endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, descriptor).apply {
// TODO: add field if getter is missing?
getter = descriptor.getter?.createFunction() as IrSimpleFunction?
setter = descriptor.setter?.createFunction() as IrSimpleFunction?
}
else -> TODO(descriptor.toString())
}
}
private fun createFakeOverride(
descriptor: CallableMemberDescriptor,
overriddenDeclarations: List<IrDeclaration>,
irClass: IrClass
): IrDeclaration {
// TODO: this function doesn't substitute types.
fun IrSimpleFunction.copyFake(descriptor: FunctionDescriptor): IrSimpleFunction = IrFunctionImpl(
irClass.startOffset, irClass.endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, descriptor
).also {
it.returnType = returnType
it.parent = irClass
it.createDispatchReceiverParameter()
it.extensionReceiverParameter = this.extensionReceiverParameter?.let {
IrValueParameterImpl(
it.startOffset,
it.endOffset,
IrDeclarationOrigin.DEFINED,
it.descriptor.extensionReceiverParameter!!,
it.type,
null
)
}
this.valueParameters.mapTo(it.valueParameters) { oldParameter ->
IrValueParameterImpl(
oldParameter.startOffset,
oldParameter.endOffset,
IrDeclarationOrigin.DEFINED,
it.descriptor.valueParameters[oldParameter.index],
oldParameter.type,
(oldParameter as? IrValueParameter)?.varargElementType
)
}
this.typeParameters.mapTo(it.typeParameters) { oldParameter ->
IrTypeParameterImpl(
irClass.startOffset,
irClass.endOffset,
IrDeclarationOrigin.DEFINED,
it.descriptor.typeParameters[oldParameter.index]
).apply {
superTypes += oldParameter.superTypes
}
}
}
val copiedDeclaration = overriddenDeclarations.first()
return when (copiedDeclaration) {
is IrSimpleFunction -> copiedDeclaration.copyFake(descriptor as FunctionDescriptor)
is IrProperty -> IrPropertyImpl(
irClass.startOffset,
irClass.endOffset,
IrDeclarationOrigin.FAKE_OVERRIDE,
descriptor as PropertyDescriptor
).apply {
parent = irClass
getter = copiedDeclaration.getter?.copyFake(descriptor.getter!!)
setter = copiedDeclaration.setter?.copyFake(descriptor.setter!!)
}
else -> error(copiedDeclaration)
}
}
fun IrClass.setSuperSymbolsAndAddFakeOverrides(superTypes: List<IrType>) {
val overriddenSuperMembers = this.declarations.map { it.descriptor }
.filterIsInstance<CallableMemberDescriptor>().flatMap { it.overriddenDescriptors.map { it.original } }.toSet()
val unoverriddenSuperMembers = superTypes.map { it.getClass()!! }.flatMap {
it.declarations.filter { it.descriptor !in overriddenSuperMembers }.mapNotNull {
when (it) {
is IrSimpleFunction -> it.descriptor to it
is IrProperty -> it.descriptor to it
else -> null
}
}
}.toMap()
val irClass = this
val overridingStrategy = object : OverridingStrategy() {
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) {
val overriddenDeclarations =
fakeOverride.overriddenDescriptors.map { unoverriddenSuperMembers[it]!! }
assert(overriddenDeclarations.isNotEmpty())
irClass.declarations.add(createFakeOverride(fakeOverride, overriddenDeclarations, irClass))
}
override fun inheritanceConflict(first: CallableMemberDescriptor, second: CallableMemberDescriptor) {
error("inheritance conflict in synthesized class ${irClass.descriptor}:\n $first\n $second")
}
override fun overrideConflict(fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor) {
error("override conflict in synthesized class ${irClass.descriptor}:\n $fromSuper\n $fromCurrent")
}
}
unoverriddenSuperMembers.keys.groupBy { it.name }.forEach { (name, members) ->
OverridingUtil.generateOverridesInFunctionGroup(
name,
members,
emptyList(),
this.descriptor,
overridingStrategy
)
}
this.setSuperSymbols(superTypes)
}
inline fun <reified T> stub(name: String): T {
return Proxy.newProxyInstance(T::class.java.classLoader, arrayOf(T::class.java)) {
_ /* proxy */, method, _ /* methodArgs */ ->
if (method.name == "toString" && method.parameterCount == 0) {
"${T::class.simpleName} stub for $name"
} else {
error("${T::class.simpleName}.${method.name} is not supported for $name")
}
} as T
}
@@ -10,9 +10,6 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
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.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.initialize
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
@@ -47,27 +44,24 @@ class BlockDecomposerLowering(context: JsIrBackendContext) : DeclarationContaine
fun lower(irField: IrField, container: IrDeclarationContainer): List<IrDeclaration> { fun lower(irField: IrField, container: IrDeclarationContainer): List<IrDeclaration> {
irField.initializer?.apply { irField.initializer?.apply {
val initFnSymbol = JsSymbolBuilder.buildSimpleFunction( val initFunction = JsIrBuilder.buildFunction(irField.name.asString() + "\$init\$", irField.visibility).also {
(container as IrSymbolOwner).symbol.descriptor, it.parent = container
irField.name.asString() + "\$init\$" it.returnType = expression.type
).initialize(returnType = expression.type) }
val returnStatement = JsIrBuilder.buildReturn(initFunction.symbol, expression, nothingType)
val returnStatement = JsIrBuilder.buildReturn(initFnSymbol, expression, nothingType)
val newBody = IrBlockBodyImpl(expression.startOffset, expression.endOffset).apply { val newBody = IrBlockBodyImpl(expression.startOffset, expression.endOffset).apply {
statements += returnStatement statements += returnStatement
} }
val initFn = JsIrBuilder.buildFunction(initFnSymbol, expression.type).apply { initFunction.body = newBody
body = newBody
}
lower(initFn) lower(initFunction)
val lastStatement = newBody.statements.last() val lastStatement = newBody.statements.last()
if (lastStatement != returnStatement || (lastStatement as IrReturn).value != expression) { if (lastStatement != returnStatement || (lastStatement as IrReturn).value != expression) {
expression = JsIrBuilder.buildCall(initFnSymbol, expression.type) expression = JsIrBuilder.buildCall(initFunction.symbol, expression.type)
return listOf(initFn, irField) return listOf(initFunction, irField)
} }
} }
@@ -89,8 +83,7 @@ class BlockDecomposerTransformer(context: JsIrBackendContext) : IrElementTransfo
private val unitType = context.irBuiltIns.unitType private val unitType = context.irBuiltIns.unitType
private val unitValue = JsIrBuilder.buildGetObjectValue(unitType, context.symbolTable.referenceClass(context.builtIns.unit)) private val unitValue = JsIrBuilder.buildGetObjectValue(unitType, context.symbolTable.referenceClass(context.builtIns.unit))
private val unreachableFunction = private val unreachableFunction = context.intrinsics.unreachable
JsSymbolBuilder.buildSimpleFunction(context.module, Namer.UNREACHABLE_NAME).initialize(returnType = nothingType)
private val booleanNotSymbol = context.irBuiltIns.booleanNotSymbol private val booleanNotSymbol = context.irBuiltIns.booleanNotSymbol
override fun visitFunction(declaration: IrFunction): IrStatement { override fun visitFunction(declaration: IrFunction): IrStatement {
@@ -107,8 +100,8 @@ class BlockDecomposerTransformer(context: JsIrBackendContext) : IrElementTransfo
} }
} }
private fun makeTempVar(type: IrType) = private fun makeTempVar(type: IrType, init: IrExpression? = null) =
JsSymbolBuilder.buildTempVar(function.symbol, type, "tmp\$dcms\$${tmpVarCounter++}", true) JsIrBuilder.buildVar(type, initializer = init, isVar = true).also { it.parent = function }
private fun makeLoopLabel() = "\$l\$${tmpVarCounter++}" private fun makeLoopLabel() = "\$l\$${tmpVarCounter++}"
@@ -184,8 +177,7 @@ class BlockDecomposerTransformer(context: JsIrBackendContext) : IrElementTransfo
if (receiverResult != null && valueResult != null) { if (receiverResult != null && valueResult != null) {
val result = IrCompositeImpl(receiverResult.startOffset, expression.endOffset, unitType) val result = IrCompositeImpl(receiverResult.startOffset, expression.endOffset, unitType)
val receiverValue = receiverResult.statements.last() as IrExpression val receiverValue = receiverResult.statements.last() as IrExpression
val tmp = makeTempVar(receiverResult.type) val irVar = makeTempVar(receiverValue.type, receiverValue)
val irVar = JsIrBuilder.buildVar(tmp, receiverValue, receiverResult.type)
val setValue = valueResult.statements.last() as IrExpression val setValue = valueResult.statements.last() as IrExpression
result.statements += receiverResult.statements.run { subList(0, lastIndex) } result.statements += receiverResult.statements.run { subList(0, lastIndex) }
result.statements += irVar result.statements += irVar
@@ -195,7 +187,7 @@ class BlockDecomposerTransformer(context: JsIrBackendContext) : IrElementTransfo
startOffset, startOffset,
endOffset, endOffset,
symbol, symbol,
JsIrBuilder.buildGetValue(tmp), JsIrBuilder.buildGetValue(irVar.symbol),
setValue, setValue,
type, type,
origin, origin,
@@ -216,10 +208,9 @@ class BlockDecomposerTransformer(context: JsIrBackendContext) : IrElementTransfo
assert(valueResult != null) assert(valueResult != null)
val receiver = expression.receiver?.let { val receiver = expression.receiver?.let {
val tmp = makeTempVar(it.type) val irVar = makeTempVar(it.type, it)
val irVar = JsIrBuilder.buildVar(tmp, it, it.type)
valueResult!!.statements.add(0, irVar) valueResult!!.statements.add(0, irVar)
JsIrBuilder.buildGetValue(tmp) JsIrBuilder.buildGetValue(irVar.symbol)
} }
return materializeLastExpression(valueResult!!) { return materializeLastExpression(valueResult!!) {
@@ -420,11 +411,11 @@ class BlockDecomposerTransformer(context: JsIrBackendContext) : IrElementTransfo
override fun visitSetField(expression: IrSetField) = expression.asExpression(unitValue) override fun visitSetField(expression: IrSetField) = expression.asExpression(unitValue)
override fun visitBreakContinue(jump: IrBreakContinue) = jump.asExpression(JsIrBuilder.buildCall(unreachableFunction, nothingType)) override fun visitBreakContinue(jump: IrBreakContinue) = jump.asExpression(JsIrBuilder.buildCall(unreachableFunction.symbol, nothingType))
override fun visitThrow(expression: IrThrow) = expression.asExpression(JsIrBuilder.buildCall(unreachableFunction, nothingType)) override fun visitThrow(expression: IrThrow) = expression.asExpression(JsIrBuilder.buildCall(unreachableFunction.symbol, nothingType))
override fun visitReturn(expression: IrReturn) = expression.asExpression(JsIrBuilder.buildCall(unreachableFunction, nothingType)) override fun visitReturn(expression: IrReturn) = expression.asExpression(JsIrBuilder.buildCall(unreachableFunction.symbol, nothingType))
override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression { override fun visitStringConcatenation(expression: IrStringConcatenation): IrExpression {
expression.transformChildrenVoid(expressionTransformer) expression.transformChildrenVoid(expressionTransformer)
@@ -458,9 +449,9 @@ class BlockDecomposerTransformer(context: JsIrBackendContext) : IrElementTransfo
val newArg = if (compositesLeft != 0) { val newArg = if (compositesLeft != 0) {
if (value != null) { if (value != null) {
// TODO: do not wrap if value is pure (const, variable, etc) // TODO: do not wrap if value is pure (const, variable, etc)
val tmp = makeTempVar(value.type) val irVar = makeTempVar(value.type, value)
newStatements += JsIrBuilder.buildVar(tmp, value, value.type) newStatements += irVar
JsIrBuilder.buildGetValue(tmp) JsIrBuilder.buildGetValue(irVar.symbol)
} else value } else value
} else value } else value
@@ -568,18 +559,18 @@ class BlockDecomposerTransformer(context: JsIrBackendContext) : IrElementTransfo
// tmp // tmp
// ] // ]
override fun visitTry(aTry: IrTry): IrExpression { override fun visitTry(aTry: IrTry): IrExpression {
val tmp = makeTempVar(aTry.type) val irVar = makeTempVar(aTry.type)
val newTryResult = wrap(aTry.tryResult, tmp) val newTryResult = wrap(aTry.tryResult, irVar.symbol)
val newCatches = aTry.catches.map { val newCatches = aTry.catches.map {
val newCatchBody = wrap(it.result, tmp) val newCatchBody = wrap(it.result, irVar.symbol)
IrCatchImpl(it.startOffset, it.endOffset, it.catchParameter, newCatchBody) IrCatchImpl(it.startOffset, it.endOffset, it.catchParameter, newCatchBody)
} }
val newTry = aTry.run { IrTryImpl(startOffset, endOffset, unitType, newTryResult, newCatches, finallyExpression) } val newTry = aTry.run { IrTryImpl(startOffset, endOffset, unitType, newTryResult, newCatches, finallyExpression) }
newTry.transformChildrenVoid(statementTransformer) newTry.transformChildrenVoid(statementTransformer)
val newStatements = listOf(JsIrBuilder.buildVar(tmp, type = aTry.type), newTry, JsIrBuilder.buildGetValue(tmp)) val newStatements = listOf(irVar, newTry, JsIrBuilder.buildGetValue(irVar.symbol))
return JsIrBuilder.buildComposite(aTry.type, newStatements) return JsIrBuilder.buildComposite(aTry.type, newStatements)
} }
@@ -616,22 +607,21 @@ class BlockDecomposerTransformer(context: JsIrBackendContext) : IrElementTransfo
} }
if (hasComposites) { if (hasComposites) {
val tmp = makeTempVar(expression.type) val irVar = makeTempVar(expression.type)
val newBranches = decomposedResults.map { (branch, condition, result) -> val newBranches = decomposedResults.map { (branch, condition, result) ->
val newResult = wrap(result, tmp) val newResult = wrap(result, irVar.symbol)
when (branch) { when (branch) {
is IrElseBranch -> IrElseBranchImpl(branch.startOffset, branch.endOffset, condition, newResult) is IrElseBranch -> IrElseBranchImpl(branch.startOffset, branch.endOffset, condition, newResult)
else /* IrBranch */ -> IrBranchImpl(branch.startOffset, branch.endOffset, condition, newResult) else /* IrBranch */ -> IrBranchImpl(branch.startOffset, branch.endOffset, condition, newResult)
} }
} }
val irVar = JsIrBuilder.buildVar(tmp, type = expression.type)
val newWhen = val newWhen =
expression.run { IrWhenImpl(startOffset, endOffset, unitType, origin, newBranches) } expression.run { IrWhenImpl(startOffset, endOffset, unitType, origin, newBranches) }
.transform(statementTransformer, null) // deconstruct into `if-else` chain .transform(statementTransformer, null) // deconstruct into `if-else` chain
return JsIrBuilder.buildComposite(expression.type, listOf(irVar, newWhen, JsIrBuilder.buildGetValue(tmp))) return JsIrBuilder.buildComposite(expression.type, listOf(irVar, newWhen, JsIrBuilder.buildGetValue(irVar.symbol)))
} else { } else {
val newBranches = decomposedResults.map { (branch, condition, result) -> val newBranches = decomposedResults.map { (branch, condition, result) ->
when (branch) { when (branch) {
@@ -19,25 +19,22 @@ package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.bridges.FunctionHandle import org.jetbrains.kotlin.backend.common.bridges.FunctionHandle
import org.jetbrains.kotlin.backend.common.bridges.generateBridges import org.jetbrains.kotlin.backend.common.bridges.generateBridges
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.isSuspend
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
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.transformers.irToJs.isStatic import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.isStatic
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.isUnit import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.isInterface import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.util.isReal import org.jetbrains.kotlin.ir.util.isReal
import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.ir.util.parentAsClass
@@ -49,29 +46,28 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
// Example: for given class hierarchy // Example: for given class hierarchy
// //
// class C<T> { // class C<T> {
// fun foo(t: T) = ... // bridge // fun foo(t: T) = ...
// } // }
// //
// class D : C<Int> { // class D : C<Int> {
// override fun foo(t: Int) = impl // delegate to // override fun foo(t: Int) = impl
// }
//
// class E : D {
// <fake override> fun foo(t: Int) // function
// } // }
// //
// it adds method D that delegates generic calls to implementation: // it adds method D that delegates generic calls to implementation:
// //
// class E : D { // class D : C<Int> {
// fun foo(t: Any?) = foo(t as Int) // bridgeDescriptorForIrFunction // override fun foo(t: Int) = impl
// fun foo(t: Any?) = foo(t as Int) // Constructed bridge
// } // }
// //
class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass { class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass {
override fun lower(irClass: IrClass) { override fun lower(irClass: IrClass) {
irClass.declarations irClass.declarations
.asSequence()
.filterIsInstance<IrSimpleFunction>() .filterIsInstance<IrSimpleFunction>()
.filter { !it.isStatic } .filter { !it.isStatic }
.toList()
.forEach { generateBridges(it, irClass) } .forEach { generateBridges(it, irClass) }
irClass.declarations irClass.declarations
@@ -112,29 +108,27 @@ class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass {
bridge: IrSimpleFunction, bridge: IrSimpleFunction,
delegateTo: IrSimpleFunction delegateTo: IrSimpleFunction
): IrFunction { ): IrFunction {
val containingClass = function.parentAsClass.descriptor
val bridgeDescriptorForIrFunction = SimpleFunctionDescriptorImpl.create(
containingClass,
Annotations.EMPTY, // TODO: Should we copy annotations?
bridge.name,
CallableMemberDescriptor.Kind.SYNTHESIZED,
function.descriptor.source
)
bridgeDescriptorForIrFunction.initialize(
bridge.descriptor.extensionReceiverParameter?.copy(bridge.descriptor), containingClass.thisAsReceiverParameter,
bridge.descriptor.typeParameters,
bridge.descriptor.valueParameters.map { it.copy(bridgeDescriptorForIrFunction, it.name, it.index) },
bridge.descriptor.returnType, bridge.descriptor.modality, function.visibility
)
bridgeDescriptorForIrFunction.isSuspend = bridge.descriptor.isSuspend
// TODO: Support offsets for debug info // TODO: Support offsets for debug info
val irFunction = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED, bridgeDescriptorForIrFunction) val irFunction = JsIrBuilder.buildFunction(
irFunction.createParameterDeclarations() bridge.name,
irFunction.returnType = bridge.returnType bridge.visibility,
bridge.modality, // TODO: should copy modality?
bridge.isInline,
bridge.isExternal,
bridge.isTailrec,
bridge.isSuspend,
IrDeclarationOrigin.BRIDGE
).apply {
dispatchReceiverParameter = bridge.dispatchReceiverParameter?.copyTo(this)
extensionReceiverParameter = bridge.extensionReceiverParameter?.copyTo(this)
typeParameters += bridge.typeParameters
valueParameters += bridge.valueParameters.map { p -> p.copyTo(this) }
annotations += bridge.annotations
returnType = bridge.returnType
parent = delegateTo.parent
}
context.createIrBuilder(irFunction.symbol).irBlockBody(irFunction) { context.createIrBuilder(irFunction.symbol).irBlockBody(irFunction) {
val call = irCall(delegateTo.symbol) val call = irCall(delegateTo.symbol)
@@ -143,7 +137,7 @@ class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass {
call.extensionReceiver = irCastIfNeeded(irGet(it), delegateTo.extensionReceiverParameter!!.type) call.extensionReceiver = irCastIfNeeded(irGet(it), delegateTo.extensionReceiverParameter!!.type)
} }
val toTake = irFunction.valueParameters.size - if (call.descriptor.isSuspend xor irFunction.descriptor.isSuspend) 1 else 0 val toTake = irFunction.valueParameters.size - if (call.isSuspend xor irFunction.isSuspend) 1 else 0
irFunction.valueParameters.subList(0, toTake).mapIndexed { i, valueParameter -> irFunction.valueParameters.subList(0, toTake).mapIndexed { i, valueParameter ->
call.putValueArgument(i, irCastIfNeeded(irGet(valueParameter), delegateTo.valueParameters[i].type)) call.putValueArgument(i, irCastIfNeeded(irGet(valueParameter), delegateTo.valueParameters[i].type))
@@ -191,6 +185,7 @@ class FunctionAndSignature(val function: IrSimpleFunction) {
private val signature = Signature( private val signature = Signature(
function.name, function.name,
// TODO: should kotlinTypes be used here?
function.extensionReceiverParameter?.type?.toKotlinType()?.toString(), function.extensionReceiverParameter?.type?.toKotlinType()?.toString(),
function.valueParameters.map { it.type.toKotlinType().toString() } function.valueParameters.map { it.type.toKotlinType().toString() }
) )
@@ -6,29 +6,23 @@
package org.jetbrains.kotlin.ir.backend.js.lower 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.backend.common.lower.copyAsValueParameter import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
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.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.initialize
import org.jetbrains.kotlin.ir.backend.js.utils.Namer import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol 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.IrValueSymbol import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.toIrType import org.jetbrains.kotlin.ir.types.toIrType
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
// TODO: generate $metadata$ property and fill it with corresponding KFunction/KProperty interface // TODO: generate $metadata$ property and fill it with corresponding KFunction/KProperty interface
class CallableReferenceLowering(val context: JsIrBackendContext) { class CallableReferenceLowering(val context: JsIrBackendContext) {
@@ -39,7 +33,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
val hasExtensionReceiver: Boolean val hasExtensionReceiver: Boolean
) )
private val callableToGetterFunction = mutableMapOf<CallableReferenceKey, IrFunction>() private val callableToGetterFunction = mutableMapOf<CallableReferenceKey, IrSimpleFunction>()
private val collectedReferenceMap = mutableMapOf<CallableReferenceKey, IrCallableReference>() private val collectedReferenceMap = mutableMapOf<CallableReferenceKey, IrCallableReference>()
private val callableNameConst = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KCALLABLE_NAME) private val callableNameConst = JsIrBuilder.buildString(context.irBuiltIns.stringType, Namer.KCALLABLE_NAME)
@@ -83,7 +77,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
} }
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) { override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) {
collectedReferenceMap[makeCallableKey(expression.getter!!.owner, expression)] = expression collectedReferenceMap[makeCallableKey(expression.getter.owner, expression)] = expression
} }
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
@@ -138,9 +132,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
} }
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression { override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression {
return callableToGetterFunction[makeCallableKey(expression.getter!!.owner, expression)]!!.let { return redirectToFunction(expression, callableToGetterFunction[makeCallableKey(expression.getter.owner, expression)]!!)
redirectToFunction(expression, it)
}
} }
private fun redirectToFunction(callable: IrCallableReference, newTarget: IrFunction) = private fun redirectToFunction(callable: IrCallableReference, newTarget: IrFunction) =
@@ -164,28 +156,37 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
} }
} }
private fun createFunctionClosureGetterName(descriptor: CallableDescriptor) = createHelperFunctionName(descriptor, "KReferenceGet") private fun createFunctionClosureGetterName(declaration: IrDeclaration) = createHelperFunctionName(declaration, "KReferenceGet")
private fun createPropertyClosureGetterName(descriptor: CallableDescriptor) = createHelperFunctionName(descriptor, "KPropertyGet") private fun createPropertyClosureGetterName(declaration: IrDeclaration) = createHelperFunctionName(declaration, "KPropertyGet")
private fun createClosureInstanceName(descriptor: CallableDescriptor) = createHelperFunctionName(descriptor, "KReferenceClosure") private fun createClosureInstanceName(declaration: IrDeclaration) = createHelperFunctionName(declaration, "KReferenceClosure")
private fun createHelperFunctionName(descriptor: CallableDescriptor, suffix: String): String { private fun createHelperFunctionName(declaration: IrDeclaration, suffix: String): String {
val nameBuilder = StringBuilder() val nameBuilder = StringBuilder()
if (descriptor is ClassConstructorDescriptor) { if (declaration is IrConstructor) {
nameBuilder.append(descriptor.constructedClass.fqNameSafe) val klass = declaration.parent as IrClass
nameBuilder.append(klass.name.asString())
nameBuilder.append('_') nameBuilder.append('_')
} }
nameBuilder.append(descriptor.name)
when (declaration) {
is IrFunction -> nameBuilder.append(declaration.name)
is IrProperty -> nameBuilder.append(declaration.name)
is IrVariable -> nameBuilder.append(declaration.name)
else -> TODO("Unexpected declaration type")
}
nameBuilder.append('_') nameBuilder.append('_')
nameBuilder.append(suffix) nameBuilder.append(suffix)
return nameBuilder.toString() return nameBuilder.toString()
} }
private fun getReferenceName(descriptor: CallableDescriptor): String { private fun getReferenceName(declaration: IrDeclaration) = when (declaration) {
if (descriptor is ClassConstructorDescriptor) { is IrConstructor -> (declaration.parent as IrClass).name.identifier
return descriptor.constructedClass.name.identifier is IrProperty -> declaration.name.identifier
} is IrSimpleFunction -> declaration.name.asString()
return descriptor.name.identifier is IrVariable -> declaration.name.asString().replace("\$delegate", "")
else -> TODO("Unexpected declaration type")
} }
private fun lowerKFunctionReference(declaration: IrFunction, functionReference: IrFunctionReference): List<IrDeclaration> { private fun lowerKFunctionReference(declaration: IrFunction, functionReference: IrFunctionReference): List<IrDeclaration> {
@@ -203,21 +204,23 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
// KFunctionN<Foo, T2, ..., TN, TReturn>, arguments.size = N + 1 // KFunctionN<Foo, T2, ..., TN, TReturn>, arguments.size = N + 1
val refGetFunction = buildGetFunction(declaration, functionReference, createFunctionClosureGetterName(declaration.descriptor)) val refGetFunction = buildGetFunction(declaration, functionReference, createFunctionClosureGetterName(declaration))
val refClosureFunction = buildClosureFunction(declaration, refGetFunction, functionReference) val refClosureFunction = buildClosureFunction(declaration, refGetFunction, functionReference)
val additionalDeclarations = generateGetterBodyWithGuard(refGetFunction) { val additionalDeclarations = generateGetterBodyWithGuard(refGetFunction) {
val irClosureReference = JsIrBuilder.buildFunctionReference(functionReference.type, refClosureFunction.symbol) val irClosureReference = JsIrBuilder.buildFunctionReference(functionReference.type, refClosureFunction.symbol)
val irVarSymbol = JsSymbolBuilder.buildTempVar(refGetFunction.symbol, irClosureReference.type)
val irVar = JsIrBuilder.buildVar(irVarSymbol, irClosureReference, type = irClosureReference.type) val irVar = JsIrBuilder.buildVar(irClosureReference.type, initializer = irClosureReference).also {
it.parent = refGetFunction
}
// TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.) // TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.)
val irSetName = JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply { val irSetName = JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol)) putValueArgument(0, JsIrBuilder.buildGetValue(irVar.symbol))
putValueArgument(1, callableNameConst) putValueArgument(1, callableNameConst)
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.stringType, getReferenceName(declaration.descriptor))) putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.stringType, getReferenceName(declaration)))
} }
Pair(listOf(irVar, irSetName), irVarSymbol) Pair(listOf(irVar, irSetName), irVar.symbol)
} }
@@ -226,7 +229,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
return additionalDeclarations + listOf(refGetFunction) return additionalDeclarations + listOf(refGetFunction)
} }
private fun lowerKPropertyReference(getterDeclaration: IrFunction, propertyReference: IrPropertyReference): List<IrDeclaration> { private fun lowerKPropertyReference(getterDeclaration: IrSimpleFunction, propertyReference: IrPropertyReference): List<IrDeclaration> {
// transform // transform
// x = Foo::bar -> // x = Foo::bar ->
// x = Foo_bar_KreferenceGet() : KPropertyN<Foo, PType> { // x = Foo_bar_KreferenceGet() : KPropertyN<Foo, PType> {
@@ -246,7 +249,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
// return $cache$ // return $cache$
// } // }
val getterName = createPropertyClosureGetterName(propertyReference.descriptor) val getterName = createPropertyClosureGetterName(getterDeclaration.correspondingProperty!!)
val refGetFunction = buildGetFunction(propertyReference.getter!!.owner, propertyReference, getterName) val refGetFunction = buildGetFunction(propertyReference.getter!!.owner, propertyReference, getterName)
val getterFunction = propertyReference.getter?.let { buildClosureFunction(it.owner, refGetFunction, propertyReference) }!! val getterFunction = propertyReference.getter?.let { buildClosureFunction(it.owner, refGetFunction, propertyReference) }!!
@@ -256,23 +259,26 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
val statements = mutableListOf<IrStatement>() val statements = mutableListOf<IrStatement>()
val getterFunctionType = context.builtIns.getFunction(getterFunction.valueParameters.size + 1) val getterFunctionType = context.builtIns.getFunction(getterFunction.valueParameters.size + 1)
val type = getterFunctionType.toIrType() val type = getterFunctionType.toIrType(symbolTable = context.symbolTable)
val irGetReference = JsIrBuilder.buildFunctionReference(type, getterFunction.symbol) val irGetReference = JsIrBuilder.buildFunctionReference(type, getterFunction.symbol)
val irVarSymbol = JsSymbolBuilder.buildTempVar(refGetFunction.symbol, type) val irVar = JsIrBuilder.buildVar(type, initializer = irGetReference).also { it.parent = refGetFunction }
statements += JsIrBuilder.buildVar(irVarSymbol, irGetReference, type = type) statements += irVar
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply { statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol)) putValueArgument(0, JsIrBuilder.buildGetValue(irVar.symbol))
putValueArgument(1, getterConst) putValueArgument(1, getterConst)
putValueArgument(2, JsIrBuilder.buildGetValue(irVarSymbol)) putValueArgument(2, JsIrBuilder.buildGetValue(irVar.symbol))
} }
if (setterFunction != null) { if (setterFunction != null) {
val setterFunctionType = context.builtIns.getFunction(setterFunction.valueParameters.size + 1) val setterFunctionType = context.builtIns.getFunction(setterFunction.valueParameters.size + 1)
val irSetReference = JsIrBuilder.buildFunctionReference(setterFunctionType.toIrType(), setterFunction.symbol) val irSetReference = JsIrBuilder.buildFunctionReference(
setterFunctionType.toIrType(symbolTable = context.symbolTable),
setterFunction.symbol
)
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply { statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol)) putValueArgument(0, JsIrBuilder.buildGetValue(irVar.symbol))
putValueArgument(1, setterConst) putValueArgument(1, setterConst)
putValueArgument(2, irSetReference) putValueArgument(2, irSetReference)
} }
@@ -280,12 +286,18 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
// TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.) // TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.)
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply { statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol)) putValueArgument(0, JsIrBuilder.buildGetValue(irVar.symbol))
putValueArgument(1, callableNameConst) putValueArgument(1, callableNameConst)
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.stringType, getReferenceName(propertyReference.descriptor))) putValueArgument(
2,
JsIrBuilder.buildString(
context.irBuiltIns.stringType,
getReferenceName(getterDeclaration.correspondingProperty!!)
)
)
} }
Pair(statements, irVarSymbol) Pair(statements, irVar.symbol)
} }
callableToGetterFunction[makeCallableKey(getterDeclaration, propertyReference)] = refGetFunction callableToGetterFunction[makeCallableKey(getterDeclaration, propertyReference)] = refGetFunction
@@ -308,7 +320,8 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
// return $cache$ // return $cache$
// } // }
val getterName = createPropertyClosureGetterName(propertyReference.descriptor) val declaration = propertyReference.delegate.owner
val getterName = createPropertyClosureGetterName(declaration)
val refGetFunction = buildGetFunction(propertyReference.getter.owner, propertyReference, getterName) val refGetFunction = buildGetFunction(propertyReference.getter.owner, propertyReference, getterName)
val getterFunction = buildClosureFunction(context.irBuiltIns.throwIseFun, refGetFunction, propertyReference) val getterFunction = buildClosureFunction(context.irBuiltIns.throwIseFun, refGetFunction, propertyReference)
@@ -316,11 +329,12 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
val statements = mutableListOf<IrStatement>() val statements = mutableListOf<IrStatement>()
val getterFunctionType = context.builtIns.getFunction(getterFunction.valueParameters.size + 1) val getterFunctionType = context.builtIns.getFunction(getterFunction.valueParameters.size + 1)
val type = getterFunctionType.toIrType() val type = getterFunctionType.toIrType(symbolTable = context.symbolTable)
val irGetReference = JsIrBuilder.buildFunctionReference(type, getterFunction.symbol) val irGetReference = JsIrBuilder.buildFunctionReference(type, getterFunction.symbol)
val irVarSymbol = JsSymbolBuilder.buildTempVar(refGetFunction.symbol, type) val irVar = JsIrBuilder.buildVar(type = type, initializer = irGetReference).also { it.parent = refGetFunction }
val irVarSymbol = irVar.symbol
statements += JsIrBuilder.buildVar(irVarSymbol, irGetReference, type = type) statements += irVar
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply { statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol)) putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
@@ -331,7 +345,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply { statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol)) putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol))
putValueArgument(1, callableNameConst) putValueArgument(1, callableNameConst)
putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.stringType, getReferenceName(propertyReference.descriptor))) putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.stringType, getReferenceName(declaration)))
} }
Pair(statements, irVarSymbol) Pair(statements, irVarSymbol)
@@ -359,16 +373,18 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
// //
val cacheName = "${getterFunction.name}_${Namer.KCALLABLE_CACHE_SUFFIX}" val cacheName = "${getterFunction.name}_${Namer.KCALLABLE_CACHE_SUFFIX}"
val type = getterFunction.returnType val type = getterFunction.returnType
val cacheVarSymbol =
JsSymbolBuilder.buildVar(getterFunction.descriptor.containingDeclaration, type, cacheName, true)
val irNull = JsIrBuilder.buildNull(context.irBuiltIns.nothingNType) val irNull = JsIrBuilder.buildNull(context.irBuiltIns.nothingNType)
val irCacheDeclaration = JsIrBuilder.buildVar(cacheVarSymbol, irNull, type = type) val cacheVar = JsIrBuilder.buildVar(type, cacheName, true, initializer = irNull).also {
val irCacheValue = JsIrBuilder.buildGetValue(cacheVarSymbol) it.parent = getterFunction.parent
}
val irCacheValue = JsIrBuilder.buildGetValue(cacheVar.symbol)
val irIfCondition = JsIrBuilder.buildCall(context.irBuiltIns.eqeqSymbol).apply { val irIfCondition = JsIrBuilder.buildCall(context.irBuiltIns.eqeqSymbol).apply {
putValueArgument(0, irCacheValue) putValueArgument(0, irCacheValue)
putValueArgument(1, irNull) putValueArgument(1, irNull)
} }
val irSetCache = JsIrBuilder.buildSetVariable(cacheVarSymbol, JsIrBuilder.buildGetValue(varSymbol), context.irBuiltIns.unitType) val irSetCache =
JsIrBuilder.buildSetVariable(cacheVar.symbol, JsIrBuilder.buildGetValue(varSymbol), context.irBuiltIns.unitType)
val thenStatements = mutableListOf<IrStatement>().apply { val thenStatements = mutableListOf<IrStatement>().apply {
addAll(bodyStatements) addAll(bodyStatements)
add(irSetCache) add(irSetCache)
@@ -377,7 +393,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
val irIfNode = JsIrBuilder.buildIfElse(context.irBuiltIns.unitType, irIfCondition, irThenBranch) val irIfNode = JsIrBuilder.buildIfElse(context.irBuiltIns.unitType, irIfCondition, irThenBranch)
statements += irIfNode statements += irIfNode
returnValue = irCacheValue returnValue = irCacheValue
returnStatements = listOf(irCacheDeclaration) returnStatements = listOf(cacheVar)
} else { } else {
statements += bodyStatements statements += bodyStatements
returnValue = JsIrBuilder.buildGetValue(varSymbol) returnValue = JsIrBuilder.buildGetValue(varSymbol)
@@ -393,23 +409,25 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
private fun generateSignatureForClosure( private fun generateSignatureForClosure(
callable: IrFunction, callable: IrFunction,
getter: IrFunction, getter: IrFunction,
closure: IrSimpleFunctionSymbol, closure: IrSimpleFunction,
reference: IrCallableReference reference: IrCallableReference
): List<IrValueParameterSymbol> { ): List<IrValueParameter> {
val result = mutableListOf<IrValueParameterSymbol>() val result = mutableListOf<IrValueParameter>()
if (callable.dispatchReceiverParameter != null && reference.dispatchReceiver == null) { if (callable.dispatchReceiverParameter != null && reference.dispatchReceiver == null) {
result.add(JsSymbolBuilder.buildValueParameter(closure, result.size, callable.dispatchReceiverParameter!!.type)) val dispatch = callable.dispatchReceiverParameter!!
result.add(JsIrBuilder.buildValueParameter(dispatch.name, result.size, dispatch.type).also { it.parent = closure })
} }
if (callable.extensionReceiverParameter != null && reference.extensionReceiver == null) { if (callable.extensionReceiverParameter != null && reference.extensionReceiver == null) {
result.add(JsSymbolBuilder.buildValueParameter(closure, result.size, callable.extensionReceiverParameter!!.type)) val ext = callable.extensionReceiverParameter!!
result.add(JsIrBuilder.buildValueParameter(ext.name, result.size, ext.type).also { it.parent = closure })
} }
for (i in getter.valueParameters.size until callable.valueParameters.size) { for (i in getter.valueParameters.size until callable.valueParameters.size) {
val param = callable.valueParameters[i] val param = callable.valueParameters[i]
val paramName = param.name.run { if (!isSpecial) identifier else null } val paramName = param.name.run { if (!isSpecial) identifier else "p$i" }
result += JsSymbolBuilder.buildValueParameter(closure, result.size, param.type, paramName) result += JsIrBuilder.buildValueParameter(paramName, result.size, param.type).also { it.parent = closure }
} }
return result return result
@@ -433,36 +451,44 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
// The `getter` function takes only closure parameters // The `getter` function takes only closure parameters
val receivers = mutableListOf<IrValueParameter>() val receivers = mutableListOf<IrValueParameter>()
if (reference.dispatchReceiver != null) { if (reference.dispatchReceiver != null) {
receivers += declaration.dispatchReceiverParameter!! if (declaration.dispatchReceiverParameter != null) {
receivers += declaration.dispatchReceiverParameter!!
}
} }
if (reference.extensionReceiver != null) { if (reference.extensionReceiver != null) {
receivers += declaration.extensionReceiverParameter!! if (declaration.extensionReceiverParameter != null) {
receivers += declaration.extensionReceiverParameter!!
}
} }
val getterValueParameters = receivers + declaration.valueParameters.dropLast(kFunctionValueParamsCount) val getterValueParameters = receivers + declaration.valueParameters.dropLast(kFunctionValueParamsCount)
val refGetSymbol = JsSymbolBuilder.buildSimpleFunction(declaration.descriptor.containingDeclaration, getterName).apply { val refGetDeclaration = JsIrBuilder.buildFunction(getterName, declaration.visibility)
initialize(
valueParameters = getterValueParameters.mapIndexed { i, p -> p.descriptor.copyAsValueParameter(descriptor, i) },
returnType = callableType
)
}
return JsIrBuilder.buildFunction(refGetSymbol, callableType).apply { refGetDeclaration.parent = declaration.parent
for (i in 0 until getterValueParameters.size) { refGetDeclaration.returnType = callableType
val p = getterValueParameters[i]
valueParameters += for ((i, p) in getterValueParameters.withIndex()) {
IrValueParameterImpl( val descriptor = WrappedValueParameterDescriptor()
p.startOffset, refGetDeclaration.valueParameters += IrValueParameterImpl(
p.endOffset, p.startOffset,
p.origin, p.endOffset,
refGetSymbol.descriptor.valueParameters[i], p.origin,
p.type, IrValueParameterSymbolImpl(descriptor),
p.varargElementType p.name,
) i,
p.type,
p.varargElementType,
p.isCrossinline,
p.isNoinline
).also {
descriptor.bind(it)
it.parent = refGetDeclaration
} }
} }
return refGetDeclaration
} }
private fun buildClosureFunction( private fun buildClosureFunction(
@@ -470,23 +496,16 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
refGetFunction: IrSimpleFunction, refGetFunction: IrSimpleFunction,
reference: IrCallableReference reference: IrCallableReference
): IrFunction { ): IrFunction {
val closureName = createClosureInstanceName(declaration.descriptor) val closureName = createClosureInstanceName(declaration)
val refClosureSymbol = JsSymbolBuilder.buildSimpleFunction(refGetFunction.descriptor, closureName) val refClosureDeclaration = JsIrBuilder.buildFunction(closureName, Visibilities.LOCAL).also { it.parent = refGetFunction }
// the params which are passed to closure // the params which are passed to closure
val closureParamSymbols = generateSignatureForClosure(declaration, refGetFunction, refClosureSymbol, reference) val closureParamDeclarations = generateSignatureForClosure(declaration, refGetFunction, refClosureDeclaration, reference)
val closureParamDescriptors = closureParamSymbols.map { it.descriptor as ValueParameterDescriptor } val closureParamSymbols = closureParamDeclarations.map { it.symbol }
val returnType = declaration.returnType val returnType = declaration.returnType
refClosureSymbol.initialize(valueParameters = closureParamDescriptors, returnType = returnType)
val closureFunction = JsIrBuilder.buildFunction(refClosureSymbol, returnType) refClosureDeclaration.valueParameters += closureParamDeclarations
refClosureDeclaration.returnType = returnType
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, type = returnType) val irCall = JsIrBuilder.buildCall(declaration.symbol, type = returnType)
@@ -515,10 +534,10 @@ class CallableReferenceLowering(val context: JsIrBackendContext) {
irCall.putValueArgument(j++, JsIrBuilder.buildGetValue(closureParamSymbols[i])) irCall.putValueArgument(j++, JsIrBuilder.buildGetValue(closureParamSymbols[i]))
} }
val irClosureReturn = JsIrBuilder.buildReturn(closureFunction.symbol, irCall, context.irBuiltIns.nothingType) val irClosureReturn = JsIrBuilder.buildReturn(refClosureDeclaration.symbol, irCall, context.irBuiltIns.nothingType)
closureFunction.body = JsIrBuilder.buildBlockBody(listOf(irClosureReturn)) refClosureDeclaration.body = JsIrBuilder.buildBlockBody(listOf(irClosureReturn))
return closureFunction return refClosureDeclaration
} }
} }
@@ -7,20 +7,16 @@ package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.backend.common.lower.irIfThen import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
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.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.initialize
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
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.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
@@ -207,7 +203,7 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
} }
private fun createGetEntryInstanceFuns( private fun createGetEntryInstanceFuns(
initEntryInstancesFun: IrFunctionImpl, initEntryInstancesFun: IrSimpleFunction,
entryInstances: List<IrVariable> entryInstances: List<IrVariable>
) = enumEntries.mapIndexed { index, enumEntry -> ) = enumEntries.mapIndexed { index, enumEntry ->
buildFunction( buildFunction(
@@ -305,41 +301,31 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
} }
private fun transformEnumConstructor(enumConstructor: IrConstructor, enumClass: IrClass): IrConstructor { private fun transformEnumConstructor(enumConstructor: IrConstructor, enumClass: IrClass): IrConstructor {
val loweredConstructorSymbol = lowerEnumConstructor(enumConstructor) val loweredConstructorDescriptor = WrappedClassConstructorDescriptor()
val loweredConstructorSymbol = IrConstructorSymbolImpl(loweredConstructorDescriptor)
return IrConstructorImpl( return IrConstructorImpl(
enumConstructor.startOffset, enumConstructor.endOffset, enumConstructor.origin, enumConstructor.startOffset,
enumConstructor.endOffset,
enumConstructor.origin,
loweredConstructorSymbol, loweredConstructorSymbol,
enumConstructor.body // will be transformed later enumConstructor.name,
enumConstructor.visibility,
enumConstructor.isInline,
enumConstructor.isExternal,
enumConstructor.isPrimary
).apply { ).apply {
loweredConstructorDescriptor.bind(this)
parent = enumClass parent = enumClass
returnType = enumConstructor.returnType returnType = enumConstructor.returnType
createParameterDeclarations() valueParameters += JsIrBuilder.buildValueParameter("name", 0, context.irBuiltIns.stringType).also { it.parent = this }
valueParameters += JsIrBuilder.buildValueParameter("ordinal", 1, context.irBuiltIns.intType).also { it.parent = this }
copyParameterDeclarationsFrom(enumConstructor)
body = enumConstructor.body
loweredEnumConstructors[enumConstructor.symbol] = this loweredEnumConstructors[enumConstructor.symbol] = this
} }
} }
private fun lowerEnumConstructor(enumConstructor: IrConstructor): IrConstructorSymbol {
val constructorDescriptor = enumConstructor.descriptor
val loweredConstructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
constructorDescriptor.containingDeclaration,
constructorDescriptor.annotations,
constructorDescriptor.isPrimary,
constructorDescriptor.source
)
val valueParameters =
listOf(
createValueParameter(loweredConstructorDescriptor, 0, "name", context.builtIns.stringType),
createValueParameter(loweredConstructorDescriptor, 1, "ordinal", context.builtIns.intType)
) + constructorDescriptor.valueParameters.map {
it.copy(loweredConstructorDescriptor, it.name, it.index + 2)
}
loweredConstructorDescriptor.initialize(valueParameters, Visibilities.PROTECTED)
loweredConstructorDescriptor.returnType = constructorDescriptor.returnType
return IrConstructorSymbolImpl(loweredConstructorDescriptor)
}
private fun findFunctionDescriptorForMemberWithSyntheticBodyKind(kind: IrSyntheticBodyKind): IrFunction = private fun findFunctionDescriptorForMemberWithSyntheticBodyKind(kind: IrSyntheticBodyKind): IrFunction =
irClass.declarations.asSequence().filterIsInstance<IrFunction>() irClass.declarations.asSequence().filterIsInstance<IrFunction>()
.first { .first {
@@ -352,12 +338,10 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
name: String, name: String,
returnType: IrType = context.irBuiltIns.unitType, returnType: IrType = context.irBuiltIns.unitType,
bodyBuilder: IrBlockBodyBuilder.() -> Unit bodyBuilder: IrBlockBodyBuilder.() -> Unit
) = JsIrBuilder.buildFunction( ) = JsIrBuilder.buildFunction(name).also {
symbol = JsSymbolBuilder.buildSimpleFunction(irClass.descriptor.containingDeclaration, name) it.returnType = returnType
.initialize(returnType = returnType), it.parent = irClass
returnType = returnType it.body = context.createIrBuilder(it.symbol).irBlockBody(it, bodyBuilder)
).apply {
body = context.createIrBuilder(this.symbol).irBlockBody(this, bodyBuilder)
} }
private fun IrEnumEntry.getNameExpression() = builder.irString(this.name.identifier) private fun IrEnumEntry.getNameExpression() = builder.irString(this.name.identifier)
@@ -12,7 +12,9 @@ import org.jetbrains.kotlin.backend.common.utils.isSubtypeOfClass
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
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.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.utils.* import org.jetbrains.kotlin.ir.backend.js.utils.ConversionNames
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
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.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
@@ -21,10 +23,9 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol 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.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
import org.jetbrains.kotlin.ir.util.isNullConst import org.jetbrains.kotlin.ir.util.*
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.types.SimpleType import org.jetbrains.kotlin.types.SimpleType
@@ -226,7 +227,7 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
} }
put(Name.identifier("hashCode")) { call -> put(Name.identifier("hashCode")) { call ->
if (call.symbol.owner.descriptor.isFakeOverriddenFromAny()) { if (call.symbol.owner.isFakeOverriddenFromAny()) {
if (call.isSuperToAny()) { if (call.isSuperToAny()) {
irCall(call, intrinsics.jsGetObjectHashCode, dispatchReceiverAsFirstArgument = true) irCall(call, intrinsics.jsGetObjectHashCode, dispatchReceiverAsFirstArgument = true)
} else { } else {
@@ -315,25 +316,32 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
if (call is IrCall) { if (call is IrCall) {
val symbol = call.symbol val symbol = call.symbol
val declaration = symbol.owner
if (symbol.isDynamic() || symbol.isEffectivelyExternal()) { if (declaration.isDynamic || declaration.isEffectivelyExternal()) {
when (call.origin) { when (call.origin) {
IrStatementOrigin.GET_PROPERTY -> { IrStatementOrigin.GET_PROPERTY -> {
val fieldSymbol = IrFieldSymbolImpl((symbol.descriptor as PropertyAccessorDescriptor).correspondingProperty) val fieldSymbol = context.symbolTable.lazyWrapper.referenceField(
(symbol.descriptor as PropertyAccessorDescriptor).correspondingProperty
)
return JsIrBuilder.buildGetField(fieldSymbol, call.dispatchReceiver, type = call.type) return JsIrBuilder.buildGetField(fieldSymbol, call.dispatchReceiver, type = call.type)
} }
// assignment to a property // assignment to a property
IrStatementOrigin.EQ -> { IrStatementOrigin.EQ -> {
if (symbol.descriptor is PropertyAccessorDescriptor) { if (symbol.descriptor is PropertyAccessorDescriptor) {
val fieldSymbol = IrFieldSymbolImpl((symbol.descriptor as PropertyAccessorDescriptor).correspondingProperty) val fieldSymbol = context.symbolTable.lazyWrapper.referenceField(
return JsIrBuilder.buildSetField(fieldSymbol, call.dispatchReceiver, call.getValueArgument(0)!!, call.type) (symbol.descriptor as PropertyAccessorDescriptor).correspondingProperty
)
return call.run {
JsIrBuilder.buildSetField(fieldSymbol, dispatchReceiver, getValueArgument(0)!!, type)
}
} }
} }
} }
} }
if (symbol.isDynamic()) { if (declaration.isDynamic) {
dynamicCallOriginToIrFunction[call.origin]?.let { dynamicCallOriginToIrFunction[call.origin]?.let {
return irCall(call, it.symbol, dispatchReceiverAsFirstArgument = true) return irCall(call, it.symbol, dispatchReceiverAsFirstArgument = true)
} }
@@ -343,20 +351,16 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
return it(call) return it(call)
} }
// TODO: get rid of unbound symbols (symbol.owner as? IrFunction)?.dispatchReceiverParameter?.let {
if (symbol.isBound) { val key = SimpleMemberKey(it.type, symbol.owner.name)
memberToTransformer[key]?.let {
(symbol.owner as? IrFunction)?.dispatchReceiverParameter?.let {
val key = SimpleMemberKey(it.type, symbol.owner.name)
memberToTransformer[key]?.let {
return it(call)
}
}
nameToTransformer[symbol.owner.name]?.let {
return it(call) return it(call)
} }
} }
nameToTransformer[symbol.owner.name]?.let {
return it(call)
}
} }
return call return call
@@ -407,14 +411,13 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
private fun IrType.findEqualsMethod(rhs: IrType): IrSimpleFunction? { private fun IrType.findEqualsMethod(rhs: IrType): IrSimpleFunction? {
val classifier = classifierOrNull ?: return null val classifier = classifierOrNull ?: return null
if (!classifier.isBound) return null
return ((classifier.owner as? IrClass) ?: return null).declarations return ((classifier.owner as? IrClass) ?: return null).declarations
.filterIsInstance<IrSimpleFunction>() .filterIsInstance<IrSimpleFunction>()
.filter { .filter {
it.name == Name.identifier("equals") it.name == Name.identifier("equals")
&& it.valueParameters.size == 1 && it.valueParameters.size == 1
&& rhs.isSubtypeOf(it.valueParameters[0].type) && rhs.isSubtypeOf(it.valueParameters[0].type)
&& !it.descriptor.isFakeOverriddenFromAny() && !it./*descriptor.*/isFakeOverriddenFromAny()
} }
.maxWith( // Find the most specific function .maxWith( // Find the most specific function
Comparator { f1, f2 -> Comparator { f1, f2 ->
@@ -481,7 +484,6 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
private fun transformEqualsMethodCall(call: IrCall): IrExpression { private fun transformEqualsMethodCall(call: IrCall): IrExpression {
val symbol = call.symbol val symbol = call.symbol
if (!symbol.isBound) return call
val function = (symbol.owner as? IrFunction) ?: return call val function = (symbol.owner as? IrFunction) ?: return call
val lhs = function.dispatchReceiverParameter ?: function.extensionReceiverParameter ?: return call val lhs = function.dispatchReceiverParameter ?: function.extensionReceiverParameter ?: return call
val rhs = call.getValueArgument(0) ?: return call val rhs = call.getValueArgument(0) ?: return call
@@ -489,7 +491,7 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL
is IdentityOperator -> irCall(call, intrinsics.jsEqeqeq.symbol) is IdentityOperator -> irCall(call, intrinsics.jsEqeqeq.symbol)
is EqualityOperator -> irCall(call, intrinsics.jsEqeq.symbol) is EqualityOperator -> irCall(call, intrinsics.jsEqeq.symbol)
is RuntimeFunctionCall -> irCall(call, intrinsics.jsEquals, true) is RuntimeFunctionCall -> irCall(call, intrinsics.jsEquals, true)
is RuntimeOrMethodCall -> if (symbol.owner.descriptor.isFakeOverriddenFromAny()) { is RuntimeOrMethodCall -> if (symbol.owner.isFakeOverriddenFromAny()) {
if (call.isSuperToAny()) { if (call.isSuperToAny()) {
irCall(call, intrinsics.jsEqeqeq.symbol, dispatchReceiverAsFirstArgument = true) irCall(call, intrinsics.jsEqeqeq.symbol, dispatchReceiverAsFirstArgument = true)
} else { } else {
@@ -8,11 +8,11 @@ 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.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.ir.backend.js.lower.inline.addChild import org.jetbrains.kotlin.ir.backend.js.lower.inline.addChild
import org.jetbrains.kotlin.ir.backend.js.utils.isEffectivelyExternal
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.symbols.IrExternalPackageFragmentSymbol import org.jetbrains.kotlin.ir.symbols.IrExternalPackageFragmentSymbol
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
class MoveExternalDeclarationsToSeparatePlace : FileLoweringPass { class MoveExternalDeclarationsToSeparatePlace : FileLoweringPass {
@@ -8,18 +8,19 @@ 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.backend.common.utils.commonSupertype import org.jetbrains.kotlin.backend.common.utils.commonSupertype
import org.jetbrains.kotlin.backend.common.utils.isSubtypeOf import org.jetbrains.kotlin.backend.common.utils.isSubtypeOf
import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.ir.IrStatement
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.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
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.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCatchImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCatchImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrElseBranchImpl import org.jetbrains.kotlin.ir.expressions.impl.IrElseBranchImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.types.IrDynamicType import org.jetbrains.kotlin.ir.types.IrDynamicType
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.classifierOrNull
@@ -55,21 +56,21 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
val nothingType = context.irBuiltIns.nothingType val nothingType = context.irBuiltIns.nothingType
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
irFile.transformChildren(object : IrElementTransformer<IrDeclaration?> { irFile.transformChildren(object : IrElementTransformer<IrDeclarationParent> {
override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclaration?) = override fun visitFunction(declaration: IrFunction, data: IrDeclarationParent): IrStatement {
super.visitDeclaration(declaration, declaration) return super.visitFunction(declaration, declaration)
}
override fun visitTry(aTry: IrTry, data: IrDeclaration?): IrExpression { override fun visitTry(aTry: IrTry, data: IrDeclarationParent): IrExpression {
aTry.transformChildren(this, data) aTry.transformChildren(this, data)
if (aTry.catches.isEmpty()) return aTry.apply { assert(finallyExpression != null) } if (aTry.catches.isEmpty()) return aTry.apply { assert(finallyExpression != null) }
val commonType = mergeTypes(aTry.catches.map { it.catchParameter.type }) val commonType = mergeTypes(aTry.catches.map { it.catchParameter.type })
val pendingExceptionSymbol = JsSymbolBuilder.buildVar(data!!.descriptor, commonType, "\$p", false) val pendingExceptionDeclaration = JsIrBuilder.buildVar(commonType, "\$p").apply { parent = data }
val pendingExceptionDeclaration = JsIrBuilder.buildVar(pendingExceptionSymbol, type = commonType) val pendingException = JsIrBuilder.buildGetValue(pendingExceptionDeclaration.symbol)
val pendingException = JsIrBuilder.buildGetValue(pendingExceptionSymbol)
val branches = mutableListOf<IrBranch>() val branches = mutableListOf<IrBranch>()
@@ -82,13 +83,13 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
buildImplicitCast(pendingException, type, typeSymbol!!) buildImplicitCast(pendingException, type, typeSymbol!!)
else pendingException else pendingException
val catchBody = catch.result.transform(object : IrElementTransformer<VariableDescriptor> { val catchBody = catch.result.transform(object : IrElementTransformer<IrValueSymbol> {
override fun visitGetValue(expression: IrGetValue, data: VariableDescriptor) = override fun visitGetValue(expression: IrGetValue, data: IrValueSymbol) =
if (expression.descriptor == data) if (expression.symbol == data)
castedPendingException castedPendingException
else else
expression expression
}, catch.parameter) }, catch.catchParameter.symbol)
if (type is IrDynamicType) { if (type is IrDynamicType) {
branches += IrElseBranchImpl(catch.startOffset, catch.endOffset, litTrue, catchBody) branches += IrElseBranchImpl(catch.startOffset, catch.endOffset, litTrue, catchBody)
@@ -124,6 +125,6 @@ class MultipleCatchesLowering(val context: JsIrBackendContext) : FileLoweringPas
assert(it.isSubtypeOf(context.irBuiltIns.throwableType) || it is IrDynamicType) assert(it.isSubtypeOf(context.irBuiltIns.throwableType) || it is IrDynamicType)
} }
}, null) }, irFile)
} }
} }
@@ -6,17 +6,14 @@
package org.jetbrains.kotlin.ir.backend.js.lower package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.impl.LazyClassReceiverParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
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.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.initialize
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
@@ -24,9 +21,8 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
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.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
@@ -102,11 +98,12 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) {
private class ThisUsageReplaceTransformer( private class ThisUsageReplaceTransformer(
val function: IrFunctionSymbol, val function: IrFunctionSymbol,
val newThisSymbol: IrValueSymbol, val symbolMapping: Map<IrValueParameter, IrValueParameter>
val oldThisSymbol: IrValueSymbol?
) : ) :
IrElementTransformerVoid() { IrElementTransformerVoid() {
val newThisSymbol = symbolMapping.values.last().symbol
override fun visitReturn(expression: IrReturn): IrExpression = IrReturnImpl( override fun visitReturn(expression: IrReturn): IrExpression = IrReturnImpl(
expression.startOffset, expression.startOffset,
expression.endOffset, expression.endOffset,
@@ -116,11 +113,11 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) {
) )
override fun visitGetValue(expression: IrGetValue): IrExpression = override fun visitGetValue(expression: IrGetValue): IrExpression =
if (expression.symbol == oldThisSymbol) IrGetValueImpl( if (expression.symbol.owner in symbolMapping) IrGetValueImpl(
expression.startOffset, expression.startOffset,
expression.endOffset, expression.endOffset,
expression.type, expression.type,
newThisSymbol, symbolMapping[expression.symbol.owner]!!.symbol,
expression.origin expression.origin
) else { ) else {
expression expression
@@ -132,86 +129,81 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) {
klass: IrClass, klass: IrClass,
name: String, name: String,
type: IrType type: IrType
): IrSimpleFunction = ): IrSimpleFunction {
JsSymbolBuilder.copyFunctionSymbol(declaration.symbol, "${name}_\$Init\$").let {
val thisSymbol = val thisParam = JsIrBuilder.buildValueParameter("\$this", declaration.valueParameters.size, type)
JsSymbolBuilder.buildValueParameter(it, declaration.valueParameters.size, type, "\$this") val oldThisReceiver = klass.thisReceiver!!
val functionName = "${name}_\$Init\$"
it.initialize( return JsIrBuilder.buildFunction(
dispatchParameterDescriptor = declaration.descriptor.dispatchReceiverParameter, functionName,
typeParameters = declaration.descriptor.typeParameters, declaration.visibility,
valueParameters = declaration.descriptor.valueParameters + thisSymbol.descriptor as ValueParameterDescriptor, Modality.FINAL,
returnType = type, declaration.isInline,
modality = declaration.descriptor.modality, declaration.isExternal
visibility = declaration.descriptor.visibility ).also {
) thisParam.run { parent = it }
val retStmt = JsIrBuilder.buildReturn(it.symbol, JsIrBuilder.buildGetValue(thisParam.symbol), context.irBuiltIns.nothingType)
val statements = (declaration.body!!.deepCopyWithSymbols(it) as IrStatementContainer).statements
val thisParam = JsIrBuilder.buildValueParameter(thisSymbol, type) val newValueParameters = declaration.valueParameters.map { p -> p.copyTo(it) }
val oldThisReceiver = klass.thisReceiver?.symbol
return IrFunctionImpl( it.valueParameters += (newValueParameters + thisParam)
declaration.startOffset, declaration.endOffset,
declaration.origin, it
).apply {
val retStmt = JsIrBuilder.buildReturn(it, JsIrBuilder.buildGetValue(thisSymbol), context.irBuiltIns.nothingType)
val statements = (declaration.body as IrStatementContainer).statements
valueParameters += (declaration.valueParameters + thisParam) it.typeParameters += declaration.typeParameters.map { p -> p.copyTo(it) }
typeParameters += declaration.typeParameters
// parent = declaration.parent it.returnType = type
body = JsIrBuilder.buildBlockBody(statements + retStmt).apply { it.parent = declaration.parent
transformChildrenVoid(ThisUsageReplaceTransformer(it, thisSymbol, oldThisReceiver))
} val oldValueParameters = declaration.valueParameters + oldThisReceiver
// TODO: replace parameters as well
it.body = JsIrBuilder.buildBlockBody(statements + retStmt).apply {
transformChildrenVoid(ThisUsageReplaceTransformer(it.symbol, oldValueParameters.zip(it.valueParameters).toMap()))
} }
} }
}
private fun createCreateConstructor(
declaration: IrConstructor,
ctorImpl: IrSimpleFunction,
name: String,
type: IrType
): IrSimpleFunction {
private fun createCreateConstructor(ctorOrig: IrConstructor, ctorImpl: IrSimpleFunction, name: String, type: IrType): IrSimpleFunction = val functionName = "${name}_\$Create\$"
JsSymbolBuilder.copyFunctionSymbol(ctorOrig.symbol, "${name}_\$Create\$").let {
it.initialize(
dispatchParameterDescriptor = ctorOrig.descriptor.dispatchReceiverParameter,
typeParameters = ctorOrig.descriptor.typeParameters,
valueParameters = ctorOrig.descriptor.valueParameters,
returnType = type,
modality = ctorOrig.descriptor.modality,
visibility = ctorOrig.visibility
)
return IrFunctionImpl( return JsIrBuilder.buildFunction(
ctorOrig.startOffset, ctorOrig.endOffset, functionName,
ctorOrig.origin, it declaration.visibility,
).apply { Modality.FINAL,
declaration.isInline,
declaration.isExternal
).also {
it.valueParameters += declaration.valueParameters.map { p -> p.copyTo(it) }
it.typeParameters += declaration.typeParameters.map { p -> p.copyTo(it) }
it.parent = declaration.parent
valueParameters += ctorOrig.valueParameters it.returnType = type
typeParameters += ctorOrig.typeParameters
// parent = ctorOrig.parent
returnType = type val createFunctionIntrinsic = context.intrinsics.jsObjectCreate
val createFunctionIntrinsic = context.intrinsics.jsObjectCreate val irCreateCall = JsIrBuilder.buildCall(createFunctionIntrinsic.symbol, type, listOf(type))
val irCreateCall = JsIrBuilder.buildCall( val irDelegateCall = JsIrBuilder.buildCall(ctorImpl.symbol, type).also { call ->
createFunctionIntrinsic.symbol, for (i in 0 until it.valueParameters.size) {
returnType, call.putValueArgument(i, JsIrBuilder.buildGetValue(it.valueParameters[i].symbol))
listOf(returnType) }
)
val irDelegateCall = JsIrBuilder.buildCall(ctorImpl.symbol, type).also {
for (i in 0 until valueParameters.size) {
it.putValueArgument(i, JsIrBuilder.buildGetValue(valueParameters[i].symbol))
}
// valueParameters.forEachIndexed { i, p -> it.putValueArgument(i, JsIrBuilder.buildGetValue(p.symbol)) } // valueParameters.forEachIndexed { i, p -> it.putValueArgument(i, JsIrBuilder.buildGetValue(p.symbol)) }
it.putValueArgument(ctorOrig.valueParameters.size, irCreateCall) call.putValueArgument(declaration.valueParameters.size, irCreateCall)
// typeParameters.mapIndexed { i, t -> ctorImpl.typeParameters[i].descriptor -> } // typeParameters.mapIndexed { i, t -> ctorImpl.typeParameters[i].descriptor -> }
}
val irReturn = JsIrBuilder.buildReturn(it, irDelegateCall, context.irBuiltIns.nothingType)
body = JsIrBuilder.buildBlockBody(listOf(irReturn))
} }
} val irReturn = JsIrBuilder.buildReturn(it.symbol, irDelegateCall, context.irBuiltIns.nothingType)
it.body = JsIrBuilder.buildBlockBody(listOf(irReturn))
}
}
inner class CallsiteRedirectionTransformer : IrElementTransformer<IrFunction?> { inner class CallsiteRedirectionTransformer : IrElementTransformer<IrFunction?> {
override fun visitFunction(declaration: IrFunction, data: IrFunction?): IrStatement = super.visitFunction(declaration, declaration) override fun visitFunction(declaration: IrFunction, data: IrFunction?): IrStatement = super.visitFunction(declaration, declaration)
@@ -219,17 +211,13 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) {
override fun visitCall(expression: IrCall, data: IrFunction?): IrElement { override fun visitCall(expression: IrCall, data: IrFunction?): IrElement {
super.visitCall(expression, data) super.visitCall(expression, data)
// TODO: figure out the reason why symbol is not bound val target = expression.symbol.owner
if (expression.symbol.isBound) {
val target = expression.symbol.owner if (target is IrConstructor) {
if (!target.isPrimary) {
if (target is IrConstructor) { val ctor = oldCtorToNewMap[target.symbol]
if (!target.descriptor.isPrimary) { if (ctor != null) {
val ctor = oldCtorToNewMap[target.symbol] return redirectCall(expression, ctor.stub)
if (ctor != null) {
return redirectCall(expression, ctor.stub)
}
} }
} }
} }
@@ -252,12 +240,9 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) {
val newCall = redirectCall(expression, ctor.delegate) val newCall = redirectCall(expression, ctor.delegate)
val readThis = if (fromPrimary) { val readThis = if (fromPrimary) {
IrGetValueImpl( val thisKlass = expression.symbol.owner.parent as IrClass
expression.startOffset, val thisSymbol = thisKlass.thisReceiver!!.symbol
expression.endOffset, IrGetValueImpl(expression.startOffset, expression.endOffset, expression.type, thisSymbol)
expression.type,
IrValueParameterSymbolImpl(LazyClassReceiverParameterDescriptor(target.descriptor.containingDeclaration))
)
} else { } else {
IrGetValueImpl(expression.startOffset, expression.endOffset, expression.type, data.valueParameters.last().symbol) IrGetValueImpl(expression.startOffset, expression.endOffset, expression.type, data.valueParameters.last().symbol)
} }
@@ -278,6 +263,5 @@ class SecondaryCtorLowering(val context: JsIrBackendContext) {
putValueArgument(i, call.getValueArgument(i)) putValueArgument(i, call.getValueArgument(i))
} }
} }
} }
} }
@@ -7,15 +7,14 @@ 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.backend.common.utils.* import org.jetbrains.kotlin.backend.common.utils.*
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext 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.JsIrArithBuilder
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.backend.js.utils.isReified import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
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.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
@@ -45,7 +44,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
private val isInterfaceSymbol get() = context.intrinsics.isInterfaceSymbol private val isInterfaceSymbol get() = context.intrinsics.isInterfaceSymbol
private val isArraySymbol get() = context.intrinsics.isArraySymbol private val isArraySymbol get() = context.intrinsics.isArraySymbol
// private val isCharSymbol get() = context.intrinsics.isCharSymbol // private val isCharSymbol get() = context.intrinsics.isCharSymbol
private val isObjectSymbol get() = context.intrinsics.isObjectSymbol private val isObjectSymbol get() = context.intrinsics.isObjectSymbol
private val instanceOfIntrinsicSymbol = context.intrinsics.jsInstanceOf.symbol private val instanceOfIntrinsicSymbol = context.intrinsics.jsInstanceOf.symbol
@@ -61,12 +60,15 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
private val litNull: IrExpression = JsIrBuilder.buildNull(context.irBuiltIns.nothingNType) private val litNull: IrExpression = JsIrBuilder.buildNull(context.irBuiltIns.nothingNType)
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
// TODO: get rid of descriptors irFile.transformChildren(object : IrElementTransformer<IrDeclarationParent> {
irFile.transformChildren(object : IrElementTransformer<DeclarationDescriptor> { override fun visitFunction(declaration: IrFunction, data: IrDeclarationParent) =
override fun visitDeclaration(declaration: IrDeclaration, data: DeclarationDescriptor) = super.visitFunction(declaration, declaration)
super.visitDeclaration(declaration, declaration.descriptor)
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: DeclarationDescriptor): IrExpression { override fun visitClass(declaration: IrClass, data: IrDeclarationParent): IrStatement {
return super.visitClass(declaration, declaration)
}
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: IrDeclarationParent): IrExpression {
super.visitTypeOperator(expression, data) super.visitTypeOperator(expression, data)
return when (expression.operator) { return when (expression.operator) {
@@ -81,13 +83,13 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
} }
} }
private fun lowerImplicitNotNull(expression: IrTypeOperatorCall, containingDeclaration: DeclarationDescriptor): IrExpression { private fun lowerImplicitNotNull(expression: IrTypeOperatorCall, declaration: IrDeclarationParent): IrExpression {
assert(expression.operator == IrTypeOperator.IMPLICIT_NOTNULL) assert(expression.operator == IrTypeOperator.IMPLICIT_NOTNULL)
assert(expression.typeOperand.isNullable() xor expression.argument.type.isNullable()) assert(expression.typeOperand.isNullable() xor expression.argument.type.isNullable())
val newStatements = mutableListOf<IrStatement>() val newStatements = mutableListOf<IrStatement>()
val argument = cacheValue(expression.argument, newStatements, containingDeclaration) val argument = cacheValue(expression.argument, newStatements, declaration)
val irNullCheck = nullCheck(argument) val irNullCheck = nullCheck(argument)
newStatements += JsIrBuilder.buildIfElse(expression.typeOperand, irNullCheck, JsIrBuilder.buildCall(throwNPE), argument) newStatements += JsIrBuilder.buildIfElse(expression.typeOperand, irNullCheck, JsIrBuilder.buildCall(throwNPE), argument)
@@ -97,7 +99,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
private fun lowerCast( private fun lowerCast(
expression: IrTypeOperatorCall, expression: IrTypeOperatorCall,
containingDeclaration: DeclarationDescriptor, declaration: IrDeclarationParent,
isSafe: Boolean isSafe: Boolean
): IrExpression { ): IrExpression {
assert(expression.operator == IrTypeOperator.CAST || expression.operator == IrTypeOperator.SAFE_CAST) assert(expression.operator == IrTypeOperator.CAST || expression.operator == IrTypeOperator.SAFE_CAST)
@@ -108,7 +110,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
val newStatements = mutableListOf<IrStatement>() val newStatements = mutableListOf<IrStatement>()
val argument = cacheValue(expression.argument, newStatements, containingDeclaration) val argument = cacheValue(expression.argument, newStatements, declaration)
val check = generateTypeCheck(argument, toType) val check = generateTypeCheck(argument, toType)
@@ -141,7 +143,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
fun lowerInstanceOf( fun lowerInstanceOf(
expression: IrTypeOperatorCall, expression: IrTypeOperatorCall,
containingDeclaration: DeclarationDescriptor, declaration: IrDeclarationParent,
inverted: Boolean inverted: Boolean
): IrExpression { ): IrExpression {
assert(expression.operator == IrTypeOperator.INSTANCEOF || expression.operator == IrTypeOperator.NOT_INSTANCEOF) assert(expression.operator == IrTypeOperator.INSTANCEOF || expression.operator == IrTypeOperator.NOT_INSTANCEOF)
@@ -152,7 +154,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
val newStatements = mutableListOf<IrStatement>() val newStatements = mutableListOf<IrStatement>()
val argument = val argument =
if (isCopyRequired) cacheValue(expression.argument, newStatements, containingDeclaration) else expression.argument if (isCopyRequired) cacheValue(expression.argument, newStatements, declaration) else expression.argument
val check = generateTypeCheck(argument, toType) val check = generateTypeCheck(argument, toType)
val result = if (inverted) calculator.not(check) else check val result = if (inverted) calculator.not(check) else check
@@ -167,10 +169,14 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
putValueArgument(1, litNull) putValueArgument(1, litNull)
} }
private fun cacheValue(value: IrExpression, newStatements: MutableList<IrStatement>, cd: DeclarationDescriptor): IrExpression { private fun cacheValue(
val varSymbol = JsSymbolBuilder.buildTempVar(cd, value.type, mutable = false) value: IrExpression,
newStatements += JsIrBuilder.buildVar(varSymbol, value, value.type) newStatements: MutableList<IrStatement>,
return JsIrBuilder.buildGetValue(varSymbol) declaration: IrDeclarationParent
): IrExpression {
val varDeclaration = JsIrBuilder.buildVar(value.type, initializer = value).apply { parent = declaration }
newStatements += varDeclaration
return JsIrBuilder.buildGetValue(varDeclaration.symbol)
} }
private fun generateTypeCheck(argument: IrExpression, toType: IrType): IrExpression { private fun generateTypeCheck(argument: IrExpression, toType: IrType): IrExpression {
@@ -272,7 +278,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
return expression.run { IrCompositeImpl(startOffset, endOffset, unit, null, listOf(argument, unitValue)) } return expression.run { IrCompositeImpl(startOffset, endOffset, unit, null, listOf(argument, unitValue)) }
} }
private fun lowerIntegerCoercion(expression: IrTypeOperatorCall, containingDeclaration: DeclarationDescriptor): IrExpression { private fun lowerIntegerCoercion(expression: IrTypeOperatorCall, declaration: IrDeclarationParent): IrExpression {
assert(expression.operator === IrTypeOperator.IMPLICIT_INTEGER_COERCION) assert(expression.operator === IrTypeOperator.IMPLICIT_INTEGER_COERCION)
assert(expression.argument.type.isInt()) assert(expression.argument.type.isInt())
@@ -286,7 +292,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
val newStatements = mutableListOf<IrStatement>() val newStatements = mutableListOf<IrStatement>()
val argument = val argument =
if (isNullable) cacheValue(expression.argument, newStatements, containingDeclaration) else expression.argument if (isNullable) cacheValue(expression.argument, newStatements, declaration) else expression.argument
val casted = when { val casted = when {
toType.isByte() -> maskOp(argument, byteMask, lit24) toType.isByte() -> maskOp(argument, byteMask, lit24)
@@ -299,6 +305,6 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
return expression.run { IrCompositeImpl(startOffset, endOffset, toType, null, newStatements) } return expression.run { IrCompositeImpl(startOffset, endOffset, toType, null, newStatements) }
} }
}, irFile.packageFragmentDescriptor) }, irFile)
} }
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.ir.backend.js.lower.coroutines package org.jetbrains.kotlin.ir.backend.js.lower.coroutines
import org.jetbrains.kotlin.backend.common.ir.isSuspend
import org.jetbrains.kotlin.backend.common.peek import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.common.push
@@ -13,7 +14,6 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET 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.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
@@ -75,8 +75,7 @@ class StateMachineBuilder(
val entryState = SuspendState(unit) val entryState = SuspendState(unit)
val rootExceptionTrap = buildExceptionTrapState() val rootExceptionTrap = buildExceptionTrapState()
private val globalExceptionSymbol = private val globalExceptionVar = JsIrBuilder.buildVar(exceptionSymbol.owner.type, "e").also { it.parent = function.owner }
JsSymbolBuilder.buildTempVar(function, exceptionSymbol.owner.type, "e")
lateinit var globalCatch: IrCatch lateinit var globalCatch: IrCatch
fun finalizeStateMachine() { fun finalizeStateMachine() {
@@ -93,8 +92,8 @@ class StateMachineBuilder(
private fun buildGlobalCatch(): IrCatch { private fun buildGlobalCatch(): IrCatch {
val catchVariable = val catchVariable = globalExceptionVar
JsIrBuilder.buildVar(globalExceptionSymbol, type = exceptionSymbol.owner.type) val globalExceptionSymbol = globalExceptionVar.symbol
val block = JsIrBuilder.buildBlock(unit) val block = JsIrBuilder.buildBlock(unit)
if (hasExceptions) { if (hasExceptions) {
val thenBlock = JsIrBuilder.buildBlock(unit) val thenBlock = JsIrBuilder.buildBlock(unit)
@@ -253,9 +252,9 @@ class StateMachineBuilder(
val exitState = SuspendState(unit) val exitState = SuspendState(unit)
val resultVariable = if (hasResultingValue(expression)) { val resultVariable = if (hasResultingValue(expression)) {
val symbol = tempVar(expression.type, "RETURNABLE_BLOCK") val irVar = tempVar(expression.type, "RETURNABLE_BLOCK")
addStatement(JsIrBuilder.buildVar(symbol, null, expression.type)) addStatement(irVar)
symbol irVar.symbol
} else null } else null
returnableBlockMap[expression.symbol] = Pair(exitState, resultVariable) returnableBlockMap[expression.symbol] = Pair(exitState, resultVariable)
@@ -282,7 +281,7 @@ class StateMachineBuilder(
override fun visitCall(expression: IrCall) { override fun visitCall(expression: IrCall) {
super.visitCall(expression) super.visitCall(expression)
if (expression.descriptor.isSuspend) { if (expression.isSuspend) {
val result = lastExpression() val result = lastExpression()
val continueState = SuspendState(unit) val continueState = SuspendState(unit)
val dispatch = IrDispatchPoint(continueState) val dispatch = IrDispatchPoint(continueState)
@@ -331,8 +330,9 @@ class StateMachineBuilder(
val branches: List<IrBranch> val branches: List<IrBranch>
if (hasResultingValue(expression)) { if (hasResultingValue(expression)) {
varSymbol = tempVar(expression.type, "WHEN_RESULT") val irVar = tempVar(expression.type, "WHEN_RESULT")
addStatement(JsIrBuilder.buildVar(varSymbol, type = expression.type)) varSymbol = irVar.symbol
addStatement(irVar)
branches = expression.branches.map { branches = expression.branches.map {
val wrapped = wrap(it.result, varSymbol) val wrapped = wrap(it.result, varSymbol)
@@ -340,18 +340,8 @@ class StateMachineBuilder(
suspendableNodes += wrapped suspendableNodes += wrapped
} }
when (it) { when (it) {
is IrElseBranch -> IrElseBranchImpl( is IrElseBranch -> IrElseBranchImpl(it.startOffset, it.endOffset, it.condition, wrapped)
it.startOffset, else /* IrBranch */ -> IrBranchImpl(it.startOffset, it.endOffset, it.condition, wrapped)
it.endOffset,
it.condition,
wrapped
)
else /* IrBranch */ -> IrBranchImpl(
it.startOffset,
it.endOffset,
it.condition,
wrapped
)
} }
} }
} else { } else {
@@ -440,9 +430,11 @@ class StateMachineBuilder(
newArguments[i] = if (arg != null && suspendableCount > 0) { newArguments[i] = if (arg != null && suspendableCount > 0) {
if (arg in suspendableNodes) suspendableCount-- if (arg in suspendableNodes) suspendableCount--
arg.acceptVoid(this) arg.acceptVoid(this)
val tmp = tempVar(arg.type, "ARGUMENT") val irVar = tempVar(arg.type, "ARGUMENT")
transformLastExpression { JsIrBuilder.buildVar(tmp, it, it.type) } transformLastExpression {
JsIrBuilder.buildGetValue(tmp) irVar.apply { initializer = it }
}
JsIrBuilder.buildGetValue(irVar.symbol)
} else arg } else arg
} }
@@ -554,28 +546,24 @@ class StateMachineBuilder(
catchBlockStack.push(tryState.catchState) catchBlockStack.push(tryState.catchState)
val finallyStateVarSymbol = tempVar(int, "FINALLY_STATE") val finallyStateVar = tempVar(int, "FINALLY_STATE")
val exitState = SuspendState(unit) val exitState = SuspendState(unit)
val varSymbol = if (hasResultingValue(aTry)) tempVar(aTry.type, "TRY_RESULT") else null val varSymbol = if (hasResultingValue(aTry)) tempVar(aTry.type, "TRY_RESULT") else null
if (aTry.finallyExpression != null) { if (aTry.finallyExpression != null) {
addStatement( finallyStateVar.initializer = IrDispatchPoint(exitState)
JsIrBuilder.buildVar( addStatement(finallyStateVar)
finallyStateVarSymbol,
IrDispatchPoint(exitState), int
)
)
} }
if (varSymbol != null) { if (varSymbol != null) {
addStatement(JsIrBuilder.buildVar(varSymbol, type = aTry.type)) addStatement(varSymbol)
} }
// TODO: refact it with exception table, see coroutinesInternal.kt // TODO: refact it with exception table, see coroutinesInternal.kt
setupExceptionState(tryState.catchState) setupExceptionState(tryState.catchState)
val tryResult = if (varSymbol != null) { val tryResult = if (varSymbol != null) {
JsIrBuilder.buildSetVariable(varSymbol, aTry.tryResult, unit).also { JsIrBuilder.buildSetVariable(varSymbol.symbol, aTry.tryResult, unit).also {
if (it.value in suspendableNodes) suspendableNodes += it if (it.value in suspendableNodes) suspendableNodes += it
} }
} else aTry.tryResult } else aTry.tryResult
@@ -610,7 +598,7 @@ class StateMachineBuilder(
it.initializer = initializer it.initializer = initializer
} }
val catchResult = if (varSymbol != null) { val catchResult = if (varSymbol != null) {
JsIrBuilder.buildSetVariable(varSymbol, catch.result, unit).also { JsIrBuilder.buildSetVariable(varSymbol.symbol, catch.result, unit).also {
if (it.value in suspendableNodes) suspendableNodes += it if (it.value in suspendableNodes) suspendableNodes += it
} }
} else catch.result } else catch.result
@@ -661,7 +649,7 @@ class StateMachineBuilder(
tryState.tryState.successors += finallyState.fromThrow tryState.tryState.successors += finallyState.fromThrow
addStatement( addStatement(
JsIrBuilder.buildSetVariable( JsIrBuilder.buildSetVariable(
finallyStateVarSymbol, finallyStateVar.symbol,
IrDispatchPoint(throwExitState), int IrDispatchPoint(throwExitState), int
) )
) )
@@ -677,7 +665,7 @@ class StateMachineBuilder(
stateSymbol, stateSymbol,
thisReceiver, thisReceiver,
JsIrBuilder.buildGetValue( JsIrBuilder.buildGetValue(
finallyStateVarSymbol finallyStateVar.symbol
), ),
unit unit
) )
@@ -691,7 +679,7 @@ class StateMachineBuilder(
updateState(exitState) updateState(exitState)
if (varSymbol != null) { if (varSymbol != null) {
addStatement(JsIrBuilder.buildGetValue(varSymbol)) addStatement(JsIrBuilder.buildGetValue(varSymbol.symbol))
} }
} }
@@ -730,6 +718,6 @@ class StateMachineBuilder(
toType.classifierOrNull!! toType.classifierOrNull!!
) )
private fun tempVar(type: IrType, name: String? = null) = private fun tempVar(type: IrType, name: String = "tmp") =
JsSymbolBuilder.buildTempVar(function, type, name) JsIrBuilder.buildVar(type, name).also { it.parent = function.owner }
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.ir.backend.js.lower.coroutines package org.jetbrains.kotlin.ir.backend.js.lower.coroutines
import org.jetbrains.kotlin.backend.common.ir.isSuspend
import org.jetbrains.kotlin.backend.common.lower.FinallyBlocksLowering import org.jetbrains.kotlin.backend.common.lower.FinallyBlocksLowering
import org.jetbrains.kotlin.backend.common.pop import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.common.push
@@ -44,7 +45,7 @@ open class SuspendableNodesCollector(protected val suspendableNodes: MutableSet<
override fun visitCall(expression: IrCall) { override fun visitCall(expression: IrCall) {
super.visitCall(expression) super.visitCall(expression)
if (expression.descriptor.isSuspend) { if (expression.isSuspend) {
suspendableNodes += expression suspendableNodes += expression
hasSuspendableChildren = true hasSuspendableChildren = true
} }
@@ -493,7 +493,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
return IrCallImpl( return IrCallImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
type = newDescriptor.returnType?.toIrType()!!, type = newDescriptor.returnType?.toIrType(context.symbolTable)!!,
descriptor = newDescriptor, descriptor = newDescriptor,
typeArgumentsCount = expression.typeArgumentsCount, typeArgumentsCount = expression.typeArgumentsCount,
origin = expression.origin, origin = expression.origin,
@@ -625,7 +625,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun substituteType(oldType: IrType?): IrType? = substituteType(oldType?.toKotlinType())?.toIrType() private fun substituteType(oldType: IrType?): IrType? = substituteType(oldType?.toKotlinType())?.toIrType(context.symbolTable)
private fun substituteType(oldType: KotlinType?): KotlinType? { private fun substituteType(oldType: KotlinType?): KotlinType? {
if (typeSubstitutor == null) return oldType if (typeSubstitutor == null) return oldType
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.utils.propertyIfAccessor
import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.builders.irReturn
@@ -171,7 +171,7 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
return with(expression) { return with(expression) {
IrClassReferenceImpl(startOffset, endOffset, type, symbol, symbol.descriptor.toIrType()) IrClassReferenceImpl(startOffset, endOffset, type, symbol, symbol.descriptor.toIrType(symbolTable = symbolTable))
} }
} }
@@ -293,8 +293,8 @@ private class IrUnboundSymbolReplacer(
expression.replaceTypeArguments() expression.replaceTypeArguments()
val field = expression.field?.replaceOrSame(SymbolTable::referenceField) val field = expression.field?.replaceOrSame(SymbolTable::referenceField)
val getter = expression.getter?.replace(SymbolTable::referenceFunction) ?: expression.getter val getter = expression.getter?.replace(SymbolTable::referenceSimpleFunction) ?: expression.getter
val setter = expression.setter?.replace(SymbolTable::referenceFunction) ?: expression.setter val setter = expression.setter?.replace(SymbolTable::referenceSimpleFunction) ?: expression.setter
if (field == expression.field && getter == expression.getter && setter == expression.setter) { if (field == expression.field && getter == expression.getter && setter == expression.setter) {
return super.visitPropertyReference(expression) return super.visitPropertyReference(expression)
@@ -316,8 +316,8 @@ private class IrUnboundSymbolReplacer(
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression { override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression {
val delegate = expression.delegate.replaceOrSame(SymbolTable::referenceVariable) val delegate = expression.delegate.replaceOrSame(SymbolTable::referenceVariable)
val getter = expression.getter.replace(SymbolTable::referenceFunction) ?: expression.getter val getter = expression.getter.replace(SymbolTable::referenceSimpleFunction) ?: expression.getter
val setter = expression.setter?.replace(SymbolTable::referenceFunction) ?: expression.setter val setter = expression.setter?.replace(SymbolTable::referenceSimpleFunction) ?: expression.setter
if (delegate == expression.delegate && getter == expression.getter && setter == expression.setter) { if (delegate == expression.delegate && getter == expression.getter && setter == expression.setter) {
return super.visitLocalDelegatedPropertyReference(expression) return super.visitLocalDelegatedPropertyReference(expression)
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.ir.backend.js.lower.inline package org.jetbrains.kotlin.ir.backend.js.lower.inline
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
@@ -43,3 +45,9 @@ object SetDeclarationsParentVisitor : IrElementVisitor<Unit, IrDeclarationParent
super.visitDeclaration(declaration, data) super.visitDeclaration(declaration, data)
} }
} }
@Deprecated("Do not use descriptor-based utils")
val CallableMemberDescriptor.propertyIfAccessor
get() = if (this is PropertyAccessorDescriptor)
this.correspondingProperty
else this
@@ -6,10 +6,8 @@
package org.jetbrains.kotlin.ir.backend.js.lower.inline package org.jetbrains.kotlin.ir.backend.js.lower.inline
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.ir.backend.js.utils.isReified
import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.util.deepCopyOld
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
@@ -9,10 +9,9 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
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.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder
import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
import org.jetbrains.kotlin.ir.declarations.IrFile 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.IrContainerExpression
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrReturn import org.jetbrains.kotlin.ir.expressions.IrReturn
@@ -76,7 +75,7 @@ class ReturnableBlockLowering(val context: JsIrBackendContext) : FileLoweringPas
} }
} }
private class ReturnableBlockLoweringContext(val containingDeclaration: IrSymbolOwner) { private class ReturnableBlockLoweringContext(val containingDeclaration: IrDeclarationParent) {
var labelCnt = 0 var labelCnt = 0
val returnMap = mutableMapOf<IrReturnableBlockSymbol, (IrReturn) -> IrExpression>() val returnMap = mutableMapOf<IrReturnableBlockSymbol, (IrReturn) -> IrExpression>()
} }
@@ -91,7 +90,7 @@ private class ReturnableBlockTransformer(
} }
override fun visitDeclaration(declaration: IrDeclaration, data: ReturnableBlockLoweringContext): IrStatement { override fun visitDeclaration(declaration: IrDeclaration, data: ReturnableBlockLoweringContext): IrStatement {
if (declaration is IrSymbolOwner) { if (declaration is IrDeclarationParent) {
declaration.transformChildren(this, ReturnableBlockLoweringContext(declaration)) declaration.transformChildren(this, ReturnableBlockLoweringContext(declaration))
} }
return super.visitDeclaration(declaration, data) return super.visitDeclaration(declaration, data)
@@ -103,12 +102,8 @@ private class ReturnableBlockTransformer(
if (expression !is IrReturnableBlock) return super.visitContainerExpression(expression, data) if (expression !is IrReturnableBlock) return super.visitContainerExpression(expression, data)
val variable by lazy { val variable by lazy {
JsSymbolBuilder.buildTempVar( JsIrBuilder.buildVar(expression.type, "tmp\$ret\$${data.labelCnt++}", true)
data.containingDeclaration.symbol, .also { it.parent = data.containingDeclaration }
expression.type,
"tmp\$ret\$${data.labelCnt++}",
true
)
} }
val loop by lazy { val loop by lazy {
@@ -133,7 +128,7 @@ private class ReturnableBlockTransformer(
returnExpression.endOffset, returnExpression.endOffset,
context.irBuiltIns.unitType context.irBuiltIns.unitType
).apply { ).apply {
statements += JsIrBuilder.buildSetVariable(variable, returnExpression.value, context.irBuiltIns.unitType) statements += JsIrBuilder.buildSetVariable(variable.symbol, returnExpression.value, context.irBuiltIns.unitType)
statements += JsIrBuilder.buildBreak(context.irBuiltIns.unitType, loop) statements += JsIrBuilder.buildBreak(context.irBuiltIns.unitType, loop)
} }
} }
@@ -142,7 +137,7 @@ private class ReturnableBlockTransformer(
if (i == expression.statements.lastIndex && s is IrReturn && s.returnTargetSymbol == expression.symbol) { if (i == expression.statements.lastIndex && s is IrReturn && s.returnTargetSymbol == expression.symbol) {
s.transformChildren(this, data) s.transformChildren(this, data)
if (!hasReturned) s.value else { if (!hasReturned) s.value else {
JsIrBuilder.buildSetVariable(variable, s.value, context.irBuiltIns.unitType) JsIrBuilder.buildSetVariable(variable.symbol, s.value, context.irBuiltIns.unitType)
} }
} else { } else {
s.transform(this, data) s.transform(this, data)
@@ -174,9 +169,9 @@ private class ReturnableBlockTransformer(
expression.type, expression.type,
expression.origin expression.origin
).apply { ).apply {
statements += JsIrBuilder.buildVar(variable, type = expression.type) statements += variable
statements += loop statements += loop
statements += JsIrBuilder.buildGetValue(variable) statements += JsIrBuilder.buildGetValue(variable.symbol)
} }
} }
} }
@@ -1,104 +0,0 @@
/*
* 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.symbols
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
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
object JsSymbolBuilder {
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,
name: String,
annotations: Annotations = Annotations.EMPTY,
kind: CallableMemberDescriptor.Kind = CallableMemberDescriptor.Kind.SYNTHESIZED,
source: SourceElement = SourceElement.NO_SOURCE
) = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
containingDeclaration,
annotations,
Name.identifier(name),
kind,
source
)
)
fun copyFunctionSymbol(symbol: IrFunctionSymbol, newName: String) = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
symbol.descriptor.containingDeclaration,
symbol.descriptor.annotations,
Name.identifier(newName),
symbol.descriptor.kind,
symbol.descriptor.source
)
)
fun buildVar(
containingDeclaration: DeclarationDescriptor,
type: IrType,
name: String,
mutable: Boolean = false
) = IrVariableSymbolImpl(
LocalVariableDescriptor(
containingDeclaration,
Annotations.EMPTY,
Name.identifier(name),
type.toKotlinType(),
mutable,
false,
SourceElement.NO_SOURCE
)
)
fun buildTempVar(containingSymbol: IrSymbol, type: IrType, name: String? = null, mutable: Boolean = false) =
buildTempVar(containingSymbol.descriptor, type, name, mutable)
fun buildTempVar(containingDeclaration: DeclarationDescriptor, type: IrType, name: String? = null, mutable: Boolean = false) =
IrVariableSymbolImpl(
IrTemporaryVariableDescriptorImpl(
containingDeclaration,
Name.identifier(name ?: "tmp"),
type.toKotlinType(), mutable
)
)
}
fun IrSimpleFunctionSymbol.initialize(
extensionReceiverParameter: ReceiverParameterDescriptor? = null,
dispatchParameterDescriptor: ReceiverParameterDescriptor? = null,
typeParameters: List<TypeParameterDescriptor> = emptyList(),
valueParameters: List<ValueParameterDescriptor> = emptyList(),
returnType: IrType? = null,
modality: Modality = Modality.FINAL,
visibility: Visibility = Visibilities.LOCAL
) = this.apply {
(descriptor as FunctionDescriptorImpl).initialize(
extensionReceiverParameter,
dispatchParameterDescriptor,
typeParameters,
valueParameters,
returnType?.toKotlinType(),
modality,
visibility
)
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.js.backend.ast.JsEmpty
import org.jetbrains.kotlin.js.backend.ast.JsStatement import org.jetbrains.kotlin.js.backend.ast.JsStatement
import org.jetbrains.kotlin.js.backend.ast.JsVars import org.jetbrains.kotlin.js.backend.ast.JsVars
@@ -27,6 +28,8 @@ class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatemen
override fun visitField(declaration: IrField, context: JsGenerationContext): JsStatement { override fun visitField(declaration: IrField, context: JsGenerationContext): JsStatement {
val fieldName = context.getNameForSymbol(declaration.symbol) val fieldName = context.getNameForSymbol(declaration.symbol)
if (declaration.isExternal) return JsEmpty
if (declaration.initializer != null) { if (declaration.initializer != null) {
val initializer = declaration.initializer!!.accept(IrElementToJsExpressionTransformer(), context) val initializer = declaration.initializer!!.accept(IrElementToJsExpressionTransformer(), context)
context.staticContext.initializerBlock.statements += jsAssignment(fieldName.makeRef(), initializer).makeStmt() context.staticContext.initializerBlock.statements += jsAssignment(fieldName.makeRef(), initializer).makeStmt()
@@ -5,14 +5,15 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.backend.common.utils.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.descriptors.ClassKind 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.IrSimpleFunction
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.ir.types.isUnit import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -158,8 +159,9 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
val jsExtensionReceiver = expression.extensionReceiver?.accept(this, context) val jsExtensionReceiver = expression.extensionReceiver?.accept(this, context)
val arguments = translateCallArguments(expression, context) val arguments = translateCallArguments(expression, context)
if (dispatchReceiver != null && val isSuspend = (symbol.owner as? IrSimpleFunction)?.isSuspend ?: false
dispatchReceiver.type.isFunctionTypeOrSubtype() && symbol.descriptor.name == OperatorNameConventions.INVOKE && !symbol.descriptor.isSuspend
if (dispatchReceiver != null && symbol.owner.name == OperatorNameConventions.INVOKE && !isSuspend && dispatchReceiver.type.isFunctionTypeOrSubtype()
) { ) {
return JsInvocation(jsDispatchReceiver!!, arguments) return JsInvocation(jsDispatchReceiver!!, arguments)
} }
@@ -5,12 +5,12 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.COROUTINE_SWITCH import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.COROUTINE_SWITCH
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.constructedClass
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.isAny
import org.jetbrains.kotlin.ir.util.constructedClassType
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
@@ -55,7 +55,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
} }
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, context: JsGenerationContext): JsStatement { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, context: JsGenerationContext): JsStatement {
if (KotlinBuiltIns.isAny(expression.symbol.constructedClass)) { if (expression.symbol.owner.constructedClassType.isAny()) {
return JsEmpty return JsEmpty
} }
return expression.accept(IrElementToJsExpressionTransformer(), context).makeStmt() return expression.accept(IrElementToJsExpressionTransformer(), context).makeStmt()
@@ -12,18 +12,14 @@ import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.DFS
class IrModuleToJsTransformer(val backendContext: JsIrBackendContext) : BaseIrElementToJsNodeTransformer<JsNode, Nothing?> { class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) : BaseIrElementToJsNodeTransformer<JsNode, Nothing?> {
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode { override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode {
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 // TODO: fix it up with new name generator
val symbolTable = backendContext.symbolTable val anyName = rootContext.getNameForSymbol(backendContext.irBuiltIns.anyClass)
val throwableName = rootContext.getNameForSymbol(backendContext.irBuiltIns.throwableClass)
val anySymbol = symbolTable.referenceClass(backendContext.builtIns.any)
val throwableSymbol = symbolTable.referenceClass(backendContext.builtIns.throwable)
val anyName = rootContext.getNameForSymbol(anySymbol)
val throwableName = rootContext.getNameForSymbol(throwableSymbol)
program.globalBlock.statements += JsVars(JsVars.JsVar(anyName, Namer.JS_OBJECT)) program.globalBlock.statements += JsVars(JsVars.JsVar(anyName, Namer.JS_OBJECT))
program.globalBlock.statements += JsVars(JsVars.JsVar(throwableName, Namer.JS_ERROR)) program.globalBlock.statements += JsVars(JsVars.JsVar(throwableName, Namer.JS_ERROR))
@@ -6,19 +6,11 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.backend.common.onlyIf import org.jetbrains.kotlin.backend.common.onlyIf
import org.jetbrains.kotlin.backend.common.utils.isBuiltinFunctionalTypeOrSubtype
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind 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.backend.js.utils.isEffectivelyExternal import org.jetbrains.kotlin.ir.declarations.*
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.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isAny import org.jetbrains.kotlin.ir.types.isAny
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
@@ -29,7 +21,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
private val className = context.getNameForSymbol(irClass.symbol) private val className = context.getNameForSymbol(irClass.symbol)
private val classNameRef = className.makeRef() private val classNameRef = className.makeRef()
private val baseClass = irClass.superTypes.firstOrNull { !it.classifierOrFail.isInterface } private val baseClass = irClass.superTypes.firstOrNull { !it.classifierOrFail.isInterface }
private val baseClassName = baseClass?.let { context.getNameForSymbol(it.classifierOrFail) } private val baseClassName = baseClass?.let { context.getNameForType(it) }
private val classPrototypeRef = prototypeOf(classNameRef) private val classPrototypeRef = prototypeOf(classNameRef)
private val classBlock = JsGlobalBlock() private val classBlock = JsGlobalBlock()
private val classModel = JsClassModel(className, baseClassName) private val classModel = JsClassModel(className, baseClassName)
@@ -83,10 +75,10 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
// II.prototype.foo = I.prototype.foo // II.prototype.foo = I.prototype.foo
if (!irClass.isInterface) { if (!irClass.isInterface) {
declaration.resolveFakeOverride()?.let { declaration.resolveFakeOverride()?.let {
val implClassDesc = it.descriptor.containingDeclaration as ClassDescriptor val implClassDeclaration = it.parent as IrClass
if (!KotlinBuiltIns.isAny(implClassDesc) && !it.isEffectivelyExternal()) { if (!implClassDeclaration.defaultType.isAny() && !it.isEffectivelyExternal()) {
val implMethodName = context.getNameForSymbol(it.symbol) val implMethodName = context.getNameForSymbol(it.symbol)
val implClassName = context.getNameForSymbol(IrClassSymbolImpl(implClassDesc)) val implClassName = context.getNameForSymbol(implClassDeclaration.symbol)
val implClassPrototype = prototypeOf(implClassName.makeRef()) val implClassPrototype = prototypeOf(implClassName.makeRef())
val implMemberRef = JsNameRef(implMethodName, implClassPrototype) val implMemberRef = JsNameRef(implMethodName, implClassPrototype)
@@ -167,16 +159,22 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
return jsAssignment(JsNameRef(Namer.METADATA, classNameRef), metadataLiteral).makeStmt() return jsAssignment(JsNameRef(Namer.METADATA, classNameRef), metadataLiteral).makeStmt()
} }
private fun generateSuperClasses(): JsPropertyInitializer = JsPropertyInitializer( private fun generateSuperClasses(): JsPropertyInitializer {
JsNameRef(Namer.METADATA_INTERFACES), val functionTypeOrSubtype = irClass.defaultType.isFunctionTypeOrSubtype()
JsArrayLiteral( return JsPropertyInitializer(
irClass.superTypes.mapNotNull { JsNameRef(Namer.METADATA_INTERFACES),
val symbol = it.classifierOrFail JsArrayLiteral(
// TODO: make sure that there is a test which breaks when isExternal is used here instead of isEffectivelyExternal irClass.superTypes.mapNotNull {
if (symbol.isInterface && !irClass.defaultType.isBuiltinFunctionalTypeOrSubtype() && !symbol.isEffectivelyExternal()) JsNameRef(context.getNameForSymbol(symbol)) else null val symbol = it.classifierOrFail
} // TODO: make sure that there is a test which breaks when isExternal is used here instead of isEffectivelyExternal
if (symbol.isInterface && !functionTypeOrSubtype && !symbol.isEffectivelyExternal) {
JsNameRef(context.getNameForSymbol(symbol))
} else null
}
)
) )
) }
} }
private val IrClassifierSymbol.isInterface get() = (owner as? IrClass)?.isInterface == true private val IrClassifierSymbol.isInterface get() = (owner as? IrClass)?.isInterface == true
private val IrClassifierSymbol.isEffectivelyExternal get() = (owner as? IrDeclaration)?.isEffectivelyExternal() == true
@@ -95,13 +95,6 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
typeName.makeRef() typeName.makeRef()
} }
add(backendContext.sharedVariablesManager.closureBoxConstructorTypeSymbol) { call, context ->
val args = translateCallArguments(call, context)
val initializer = args[0]
val propertyInit = JsPropertyInitializer(JsNameRef("v"), initializer)
JsObjectLiteral(listOf(propertyInit))
}
addIfNotNull(intrinsics.jsCode) { call, context -> addIfNotNull(intrinsics.jsCode) { call, context ->
val jsCode = translateJsCode(call, context.currentScope) val jsCode = translateJsCode(call, context.currentScope)
@@ -10,6 +10,7 @@ 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.IrLoop import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
class JsGenerationContext { class JsGenerationContext {
@@ -44,6 +45,8 @@ class JsGenerationContext {
} }
fun getNameForSymbol(symbol: IrSymbol): JsName = staticContext.getNameForSymbol(symbol, this) fun getNameForSymbol(symbol: IrSymbol): JsName = staticContext.getNameForSymbol(symbol, this)
fun getNameForType(type: IrType): JsName = staticContext.getNameForType(type, this)
// fun getNameForReceiver(symbol: IrValueSymbol, isExt: Boolean): JsName = staticContext.getNameForReceiver(symbol, isExt, this)
fun getNameForLoop(loop: IrLoop): JsName? = staticContext.getNameForLoop(loop, this) fun getNameForLoop(loop: IrLoop): JsName? = staticContext.getNameForLoop(loop, this)
val continuation val continuation
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIntrinsicTransfo
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrLoop import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.js.backend.ast.JsClassModel import org.jetbrains.kotlin.js.backend.ast.JsClassModel
import org.jetbrains.kotlin.js.backend.ast.JsGlobalBlock import org.jetbrains.kotlin.js.backend.ast.JsGlobalBlock
import org.jetbrains.kotlin.js.backend.ast.JsName import org.jetbrains.kotlin.js.backend.ast.JsName
@@ -17,10 +18,10 @@ import org.jetbrains.kotlin.js.backend.ast.JsRootScope
class JsStaticContext( class JsStaticContext(
private val rootScope: JsRootScope, val rootScope: JsRootScope,
private val globalBlock: JsGlobalBlock, private val globalBlock: JsGlobalBlock,
private val nameGenerator: NameGenerator, private val nameGenerator: NameGenerator,
backendContext: JsIrBackendContext val backendContext: JsIrBackendContext
) { ) {
val intrinsics = JsIntrinsicTransformers(backendContext) val intrinsics = JsIntrinsicTransformers(backendContext)
// TODO: use IrSymbol instead of JsName // TODO: use IrSymbol instead of JsName
@@ -32,5 +33,6 @@ class JsStaticContext(
val initializerBlock = JsGlobalBlock() val initializerBlock = JsGlobalBlock()
fun getNameForSymbol(irSymbol: IrSymbol, context: JsGenerationContext) = nameGenerator.getNameForSymbol(irSymbol, context) fun getNameForSymbol(irSymbol: IrSymbol, context: JsGenerationContext) = nameGenerator.getNameForSymbol(irSymbol, context)
fun getNameForType(type: IrType, context: JsGenerationContext) = nameGenerator.getNameForType(type, context)
fun getNameForLoop(loop: IrLoop, context: JsGenerationContext) = nameGenerator.getNameForLoop(loop, context) fun getNameForLoop(loop: IrLoop, context: JsGenerationContext) = nameGenerator.getNameForLoop(loop, context)
} }
@@ -7,9 +7,11 @@ package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.ir.expressions.IrLoop import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.js.backend.ast.JsName import org.jetbrains.kotlin.js.backend.ast.JsName
interface NameGenerator { interface NameGenerator {
fun getNameForSymbol(symbol: IrSymbol, context: JsGenerationContext): JsName fun getNameForSymbol(symbol: IrSymbol, context: JsGenerationContext): JsName
fun getNameForType(type: IrType, context: JsGenerationContext): JsName
fun getNameForLoop(loop: IrLoop, context: JsGenerationContext): JsName? fun getNameForLoop(loop: IrLoop, context: JsGenerationContext): JsName?
} }
@@ -6,118 +6,175 @@
package org.jetbrains.kotlin.ir.backend.js.utils package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrLoop import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.isDynamic
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.js.backend.ast.JsName import org.jetbrains.kotlin.js.backend.ast.JsName
import org.jetbrains.kotlin.js.naming.isES5IdentifierPart import org.jetbrains.kotlin.js.naming.isES5IdentifierPart
import org.jetbrains.kotlin.js.naming.isES5IdentifierStart import org.jetbrains.kotlin.js.naming.isES5IdentifierStart
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
// TODO: this class has to be reimplemented soon
class SimpleNameGenerator : NameGenerator { class SimpleNameGenerator : NameGenerator {
private val nameCache = mutableMapOf<DeclarationDescriptor, JsName>() private val nameCache = mutableMapOf<IrDeclaration, JsName>()
private val loopCache = mutableMapOf<IrLoop, JsName>() private val loopCache = mutableMapOf<IrLoop, JsName>()
override fun getNameForSymbol(symbol: IrSymbol, context: JsGenerationContext): JsName = getNameForDescriptor(symbol.descriptor, context) override fun getNameForSymbol(symbol: IrSymbol, context: JsGenerationContext): JsName =
if (symbol.isBound) getNameForDeclaration(symbol.owner as IrDeclaration, context) else
declareDynamic(symbol.descriptor, context)
override fun getNameForLoop(loop: IrLoop, context: JsGenerationContext): JsName? = loop.label?.let { override fun getNameForLoop(loop: IrLoop, context: JsGenerationContext): JsName? = loop.label?.let {
loopCache.getOrPut(loop) { context.currentScope.declareFreshName(sanitizeName(loop.label!!)) } loopCache.getOrPut(loop) { context.currentScope.declareFreshName(sanitizeName(loop.label!!)) }
} }
override fun getNameForType(type: IrType, context: JsGenerationContext) =
getNameForDeclaration(type.classifierOrFail.owner as IrDeclaration, context)
private fun getNameForDescriptor(descriptor: DeclarationDescriptor, context: JsGenerationContext): JsName = @Deprecated("Descriptors-based code is deprecated")
nameCache.getOrPut(descriptor) { private fun declareDynamic(descriptor: DeclarationDescriptor, context: JsGenerationContext): JsName {
if (descriptor.isDynamic()) {
return context.currentScope.declareName(descriptor.name.asString())
}
if (descriptor is MemberDescriptor && descriptor.isEffectivelyExternal()) {
val descriptorForName = when (descriptor) {
is ConstructorDescriptor -> descriptor.constructedClass
is PropertyAccessorDescriptor -> descriptor.correspondingProperty
else -> descriptor
}
return context.currentScope.declareName(descriptorForName.name.asString())
}
throw IllegalStateException("Unbound non-dynamic symbol")
}
private val RESERVED_IDENTIFIERS = setOf(
// keywords
"await", "break", "case", "catch", "continue", "debugger", "default", "delete", "do", "else", "finally", "for", "function", "if",
"in", "instanceof", "new", "return", "switch", "throw", "try", "typeof", "var", "void", "while", "with",
// future reserved words
"class", "const", "enum", "export", "extends", "import", "super",
// as future reserved words in strict mode
"implements", "interface", "let", "package", "private", "protected", "public", "static", "yield",
// additional reserved words
// "null", "true", "false",
// disallowed as variable names in strict mode
"eval", "arguments",
// global identifiers usually declared in a typical JS interpreter
"NaN", "isNaN", "Infinity", "undefined",
"Error", "Object", "Number",
// "Math", "String", "Boolean", "Date", "Array", "RegExp", "JSON",
// global identifiers usually declared in know environments (node.js, browser, require.js, WebWorkers, etc)
// "require", "define", "module", "window", "self",
// the special Kotlin object
"Kotlin"
)
private fun getNameForDeclaration(declaration: IrDeclaration, context: JsGenerationContext): JsName =
nameCache.getOrPut(declaration) {
var nameDeclarator: (String) -> JsName = context.currentScope::declareName var nameDeclarator: (String) -> JsName = context.currentScope::declareName
val nameBuilder = StringBuilder()
if (descriptor.isDynamic()) { val descriptor = declaration.descriptor
return@getOrPut nameDeclarator(descriptor.name.asString())
if (declaration.isDynamic) {
return@getOrPut nameDeclarator(declaration.descriptor.name.asString())
} }
if (descriptor is MemberDescriptor && descriptor.isEffectivelyExternal()) { if (declaration.isEffectivelyExternal()) {
// TODO: descriptors are still used here due to the corresponding declaration doesn't have enough information yet
val descriptorForName = when (descriptor) { val descriptorForName = when (descriptor) {
is ConstructorDescriptor -> descriptor.constructedClass is ConstructorDescriptor -> descriptor.constructedClass
is PropertyAccessorDescriptor -> descriptor.correspondingProperty is PropertyAccessorDescriptor -> descriptor.correspondingProperty
else -> descriptor else -> descriptor
} }
return@getOrPut nameDeclarator(descriptorForName.name.asString()) return@getOrPut context.staticContext.rootScope.declareName(descriptorForName.name.asString())
} }
val nameBuilder = StringBuilder() when (declaration) {
when (descriptor) { is IrValueParameter -> {
is ReceiverParameterDescriptor -> { if ((context.currentFunction is IrConstructor && declaration.origin == IrDeclarationOrigin.INSTANCE_RECEIVER && declaration.name.isSpecial) ||
when (descriptor.value) { declaration == context.currentFunction?.dispatchReceiverParameter
is ExtensionReceiver -> nameBuilder.append(Namer.EXTENSION_RECEIVER_NAME) )
is ImplicitClassReceiver -> nameBuilder.append(Namer.IMPLICIT_RECEIVER_NAME) nameBuilder.append(Namer.IMPLICIT_RECEIVER_NAME)
else -> TODO("name for $descriptor") else if (declaration == context.currentFunction?.extensionReceiverParameter) {
} nameBuilder.append(Namer.EXTENSION_RECEIVER_NAME)
}
is ValueParameterDescriptor -> {
val declaredName = descriptor.name.asString()
nameBuilder.append(declaredName)
nameDeclarator = context.currentScope::declareFreshName
}
is PropertyDescriptor -> {
nameBuilder.append(descriptor.name.asString())
if (descriptor.visibility == Visibilities.PRIVATE || descriptor.modality != Modality.FINAL) {
nameBuilder.append('$')
nameBuilder.append(getNameForDescriptor(descriptor.containingDeclaration, context))
}
}
is PropertyAccessorDescriptor -> {
when (descriptor) {
is PropertyGetterDescriptor -> nameBuilder.append(Namer.GETTER_PREFIX)
is PropertySetterDescriptor -> nameBuilder.append(Namer.SETTER_PREFIX)
}
nameBuilder.append(descriptor.correspondingProperty.name.asString())
descriptor.extensionReceiverParameter?.let {
nameBuilder.append("_r$${it.type}")
}
if (descriptor.visibility == Visibilities.PRIVATE) {
nameBuilder.append('$')
nameBuilder.append(getNameForDescriptor(descriptor.containingDeclaration, context))
}
}
is ClassDescriptor -> {
if (descriptor.name.isSpecial) {
nameBuilder.append(descriptor.name.asString().let {
it.substring(1, it.length - 1) + "${descriptor.hashCode()}"
})
} else { } else {
nameBuilder.append(descriptor.fqNameSafe.asString().replace('.', '$')) val declaredName = declaration.name.asString()
nameBuilder.append(declaredName)
if (declaredName.startsWith("\$")) {
nameBuilder.append('.')
nameBuilder.append(declaration.index)
}
nameDeclarator = context.currentScope::declareFreshName
} }
} }
is ConstructorDescriptor -> { is IrField -> {
nameBuilder.append(getNameForDescriptor(descriptor.constructedClass, context)) nameBuilder.append(declaration.name.asString())
if (declaration.parent is IrDeclaration) {
nameBuilder.append('.')
nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclaration, context))
}
} }
is VariableDescriptor -> { is IrClass -> {
nameBuilder.append(descriptor.name.identifier) if (declaration.isCompanion) {
nameBuilder.append(getNameForDeclaration(declaration.parent as IrDeclaration, context))
nameBuilder.append('.')
}
nameBuilder.append(declaration.name.asString())
(declaration.parent as? IrClass)?.let {
nameBuilder.append("$")
nameBuilder.append(getNameForDeclaration(it, context))
}
if (declaration.kind == ClassKind.OBJECT || declaration.name.isSpecial || declaration.visibility == Visibilities.LOCAL) {
nameDeclarator = context.staticContext.rootScope::declareFreshName
}
}
is IrConstructor -> {
nameBuilder.append(getNameForDeclaration(declaration.parent as IrClass, context))
}
is IrVariable -> {
nameBuilder.append(declaration.name.identifier)
nameDeclarator = context.currentScope::declareFreshName nameDeclarator = context.currentScope::declareFreshName
} }
is CallableDescriptor -> { is IrSimpleFunction -> {
nameBuilder.append(descriptor.name.asString()) nameBuilder.append(declaration.name.asString())
descriptor.typeParameters.ifNotEmpty { declaration.extensionReceiverParameter?.let { nameBuilder.append("_\$${it.type.render()}") }
nameBuilder.append("_\$t") declaration.typeParameters.forEach { nameBuilder.append("_${it.name.asString()}") }
joinTo(nameBuilder, "") { "_${it.name}" } declaration.valueParameters.forEach { nameBuilder.append("_${it.type.render()}") }
}
descriptor.extensionReceiverParameter?.let {
nameBuilder.append("_r$${it.type}")
}
descriptor.valueParameters.ifNotEmpty {
joinTo(nameBuilder, "") { "_${it.type}" }
}
} }
} }
if (nameBuilder.toString() in RESERVED_IDENTIFIERS) {
nameBuilder.append(0)
nameDeclarator = context.currentScope::declareFreshName
}
nameDeclarator(sanitizeName(nameBuilder.toString())) nameDeclarator(sanitizeName(nameBuilder.toString()))
} }
private fun sanitizeName(name: String): String { private fun sanitizeName(name: String): String {
if (name.isEmpty()) return "_" if (name.isEmpty()) return "_"
@@ -1,63 +0,0 @@
/*
* 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.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
import org.jetbrains.kotlin.types.KotlinType
val IrConstructorSymbol.constructedClass get() = descriptor.constructedClass
fun createValueParameter(containingDeclaration: CallableDescriptor, index: Int, name: String, type: KotlinType): ValueParameterDescriptor {
return ValueParameterDescriptorImpl(
containingDeclaration = containingDeclaration,
original = null,
index = index,
annotations = Annotations.EMPTY,
name = Name.identifier(name),
outType = type,
declaresDefaultValue = false,
isCrossinline = false,
isNoinline = false,
varargElementType = null,
source = SourceElement.NO_SOURCE
)
}
val CallableMemberDescriptor.propertyIfAccessor
get() = if (this is PropertyAccessorDescriptor)
this.correspondingProperty
else this
val IrTypeParameter.isReified
get() = descriptor.isReified
// Return is method has no real implementation except fake overrides from Any
fun CallableMemberDescriptor.isFakeOverriddenFromAny(): Boolean {
if (kind.isReal) {
return (containingDeclaration is ClassDescriptor) && KotlinBuiltIns.isAny(containingDeclaration as ClassDescriptor)
}
return overriddenDescriptors.all { it.isFakeOverriddenFromAny() }
}
fun IrDeclaration.isEffectivelyExternal() = descriptor.isEffectivelyExternal()
fun IrSymbol.isEffectivelyExternal() = descriptor.isEffectivelyExternal()
fun IrSymbol.isDynamic() = descriptor.isDynamic()
fun IrCall.isSuperToAny() =
superQualifier?.let { this.symbol.owner.descriptor.isFakeOverriddenFromAny() } ?: false
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.ReflectionTypes import org.jetbrains.kotlin.backend.common.ReflectionTypes
import org.jetbrains.kotlin.backend.common.ir.Ir 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.jvm.descriptors.JvmDescriptorsFactory import org.jetbrains.kotlin.backend.jvm.descriptors.JvmDeclarationFactory
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmSharedVariablesManager import org.jetbrains.kotlin.backend.jvm.descriptors.JvmSharedVariablesManager
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -34,7 +34,7 @@ class JvmBackendContext(
irModuleFragment: IrModuleFragment, symbolTable: SymbolTable irModuleFragment: IrModuleFragment, symbolTable: SymbolTable
) : CommonBackendContext { ) : CommonBackendContext {
override val builtIns = state.module.builtIns override val builtIns = state.module.builtIns
override val descriptorsFactory: JvmDescriptorsFactory = JvmDescriptorsFactory(psiSourceManager, builtIns) override val declarationFactory: JvmDeclarationFactory = JvmDeclarationFactory(psiSourceManager, builtIns)
override val sharedVariablesManager = JvmSharedVariablesManager(builtIns, irBuiltIns) override val sharedVariablesManager = JvmSharedVariablesManager(builtIns, irBuiltIns)
override val reflectionTypes: ReflectionTypes by lazy(LazyThreadSafetyMode.PUBLICATION) { override val reflectionTypes: ReflectionTypes by lazy(LazyThreadSafetyMode.PUBLICATION) {
@@ -53,7 +53,8 @@ class JvmLower(val context: JvmBackendContext) {
override fun localName(descriptor: DeclarationDescriptor): String = override fun localName(descriptor: DeclarationDescriptor): String =
NameUtils.sanitizeAsJavaIdentifier(super.localName(descriptor)) NameUtils.sanitizeAsJavaIdentifier(super.localName(descriptor))
}, },
Visibilities.PUBLIC //TODO properly figure out visibility Visibilities.PUBLIC, //TODO properly figure out visibility
true
).runOnFilePostfix(irFile) ).runOnFilePostfix(irFile)
CallableReferenceLowering(context).lower(irFile) CallableReferenceLowering(context).lower(irFile)
@@ -5,7 +5,8 @@
package org.jetbrains.kotlin.backend.jvm.descriptors package org.jetbrains.kotlin.backend.jvm.descriptors
import org.jetbrains.kotlin.backend.common.descriptors.DescriptorsFactory import org.jetbrains.kotlin.backend.common.ir.DeclarationFactory
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.builtins.CompanionObjectMapping.isMappedIntrinsicCompanionObject import org.jetbrains.kotlin.builtins.CompanionObjectMapping.isMappedIntrinsicCompanionObject
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.descriptors.FileClassDescriptor import org.jetbrains.kotlin.codegen.descriptors.FileClassDescriptor
@@ -15,11 +16,16 @@ import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.ir.SourceManager import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toIrType
import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.util.dump
@@ -30,17 +36,24 @@ import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import java.util.* import java.util.*
class JvmDescriptorsFactory( class JvmDeclarationFactory(
private val psiSourceManager: PsiSourceManager, private val psiSourceManager: PsiSourceManager,
private val builtIns: KotlinBuiltIns private val builtIns: KotlinBuiltIns
) : DescriptorsFactory { ) : DeclarationFactory {
private val singletonFieldDescriptors = HashMap<IrBindableSymbol<*, *>, IrFieldSymbol>() private val singletonFieldDeclarations = HashMap<IrSymbolOwner, IrField>()
private val outerThisDescriptors = HashMap<IrClass, IrFieldSymbol>() private val outerThisDeclarations = HashMap<IrClass, IrField>()
private val innerClassConstructors = HashMap<IrConstructorSymbol, IrConstructorSymbol>() private val innerClassConstructors = HashMap<IrConstructor, IrConstructor>()
override fun getSymbolForEnumEntry(enumEntry: IrEnumEntrySymbol): IrFieldSymbol = override fun getFieldForEnumEntry(enumEntry: IrEnumEntry, type: IrType): IrField =
singletonFieldDescriptors.getOrPut(enumEntry) { singletonFieldDeclarations.getOrPut(enumEntry) {
IrFieldSymbolImpl(createEnumEntryFieldDescriptor(enumEntry.descriptor)) val symbol = IrFieldSymbolImpl(createEnumEntryFieldDescriptor(enumEntry.descriptor))
IrFieldImpl(
enumEntry.startOffset,
enumEntry.endOffset,
JvmLoweredDeclarationOrigin.FIELD_FOR_ENUM_ENTRY,
symbol,
type
)
} }
fun createFileClassDescriptor(fileEntry: SourceManager.FileEntry, packageFragment: PackageFragmentDescriptor): FileClassDescriptor { fun createFileClassDescriptor(fileEntry: SourceManager.FileEntry, packageFragment: PackageFragmentDescriptor): FileClassDescriptor {
@@ -56,29 +69,33 @@ class JvmDescriptorsFactory(
) )
} }
override fun getOuterThisFieldSymbol(innerClass: IrClass): IrFieldSymbol = override fun getOuterThisField(innerClass: IrClass): IrField =
if (!innerClass.isInner) throw AssertionError("Class is not inner: ${innerClass.dump()}") if (!innerClass.isInner) throw AssertionError("Class is not inner: ${innerClass.dump()}")
else outerThisDescriptors.getOrPut(innerClass) { else outerThisDeclarations.getOrPut(innerClass) {
val outerClass = innerClass.parent as? IrClass val outerClass = innerClass.parent as? IrClass
?: throw AssertionError("No containing class for inner class ${innerClass.dump()}") ?: throw AssertionError("No containing class for inner class ${innerClass.dump()}")
IrFieldSymbolImpl( val symbol = IrFieldSymbolImpl(
JvmPropertyDescriptorImpl.createFinalField( JvmPropertyDescriptorImpl.createFinalField(
Name.identifier("this$0"), outerClass.defaultType.toKotlinType(), innerClass.descriptor, Name.identifier("this$0"), outerClass.defaultType.toKotlinType(), innerClass.descriptor,
Annotations.EMPTY, JavaVisibilities.PACKAGE_VISIBILITY, Opcodes.ACC_SYNTHETIC, SourceElement.NO_SOURCE Annotations.EMPTY, JavaVisibilities.PACKAGE_VISIBILITY, Opcodes.ACC_SYNTHETIC, SourceElement.NO_SOURCE
) )
) )
IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, DeclarationFactory.FIELD_FOR_OUTER_THIS, symbol, outerClass.defaultType).also {
it.parent = innerClass
}
} }
override fun getInnerClassConstructorWithOuterThisParameter(innerClassConstructor: IrConstructor): IrConstructorSymbol { override fun getInnerClassConstructorWithOuterThisParameter(innerClassConstructor: IrConstructor): IrConstructor {
assert((innerClassConstructor.parent as IrClass).isInner) { "Class is not inner: ${(innerClassConstructor.parent as IrClass).dump()}" } assert((innerClassConstructor.parent as IrClass).isInner) { "Class is not inner: ${(innerClassConstructor.parent as IrClass).dump()}" }
return innerClassConstructors.getOrPut(innerClassConstructor.symbol) { return innerClassConstructors.getOrPut(innerClassConstructor) {
createInnerClassConstructorWithOuterThisParameter(innerClassConstructor) createInnerClassConstructorWithOuterThisParameter(innerClassConstructor)
} }
} }
private fun createInnerClassConstructorWithOuterThisParameter(oldConstructor: IrConstructor): IrConstructorSymbol { private fun createInnerClassConstructorWithOuterThisParameter(oldConstructor: IrConstructor): IrConstructor {
val oldDescriptor = oldConstructor.descriptor val oldDescriptor = oldConstructor.descriptor
val classDescriptor = oldDescriptor.containingDeclaration val classDescriptor = oldDescriptor.containingDeclaration
val outerThisType = (classDescriptor.containingDeclaration as ClassDescriptor).defaultType val outerThisType = (classDescriptor.containingDeclaration as ClassDescriptor).defaultType
@@ -102,7 +119,26 @@ class JvmDescriptorsFactory(
oldDescriptor.returnType, oldDescriptor.returnType,
oldDescriptor.modality, oldDescriptor.modality,
oldDescriptor.visibility) oldDescriptor.visibility)
return IrConstructorSymbolImpl(newDescriptor) val symbol = IrConstructorSymbolImpl(newDescriptor)
return IrConstructorImpl(oldConstructor.startOffset, oldConstructor.endOffset, oldConstructor.origin, symbol).also { constructor ->
newValueParameters.mapIndexedTo(constructor.valueParameters) { i, v ->
constructor.parent = oldConstructor.parent
constructor.returnType = oldConstructor.returnType
if (i == 0) {
IrValueParameterImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
JvmLoweredDeclarationOrigin.FIELD_FOR_OUTER_THIS, IrValueParameterSymbolImpl(v), outerThisType.toIrType()!!, null)
} else {
val oldParameter = oldConstructor.valueParameters[i - 1]
IrValueParameterImpl(
oldParameter.startOffset, oldParameter.endOffset, oldParameter.origin,
IrValueParameterSymbolImpl(v), oldParameter.type, oldParameter.varargElementType
).also {
it.defaultValue = oldParameter.defaultValue
}
}
}
}
} }
@@ -124,9 +160,16 @@ class JvmDescriptorsFactory(
) )
} }
override fun getSymbolForObjectInstance(singleton: IrClassSymbol): IrFieldSymbol = override fun getFieldForObjectInstance(singleton: IrClass): IrField =
singletonFieldDescriptors.getOrPut(singleton) { singletonFieldDeclarations.getOrPut(singleton) {
IrFieldSymbolImpl(createObjectInstanceFieldDescriptor(singleton.descriptor)) val symbol = IrFieldSymbolImpl(createObjectInstanceFieldDescriptor(singleton.descriptor))
return IrFieldImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
JvmLoweredDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE,
symbol,
singleton.defaultType
)
} }
private fun createObjectInstanceFieldDescriptor(objectDescriptor: ClassDescriptor): PropertyDescriptor { private fun createObjectInstanceFieldDescriptor(objectDescriptor: ClassDescriptor): PropertyDescriptor {
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.backend.jvm.descriptors
import org.jetbrains.kotlin.backend.common.descriptors.KnownClassDescriptor import org.jetbrains.kotlin.backend.common.descriptors.KnownClassDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.KnownPackageFragmentDescriptor import org.jetbrains.kotlin.backend.common.descriptors.KnownPackageFragmentDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.SharedVariablesManager import org.jetbrains.kotlin.backend.common.ir.SharedVariablesManager
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
@@ -16,20 +16,32 @@ import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.IrSetVariable import org.jetbrains.kotlin.ir.expressions.IrSetVariable
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol
import org.jetbrains.kotlin.ir.types.toIrType import org.jetbrains.kotlin.ir.types.toIrType
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.* import org.jetbrains.kotlin.types.*
private val SHARED_VARIABLE_ORIGIN = object : IrDeclarationOriginImpl("SHARED_VARIABLE_ORIGIN") {}
class JvmSharedVariablesManager( class JvmSharedVariablesManager(
val builtIns: KotlinBuiltIns, val builtIns: KotlinBuiltIns,
val irBuiltIns: IrBuiltIns val irBuiltIns: IrBuiltIns
@@ -47,6 +59,8 @@ class JvmSharedVariablesManager(
returnType = refType returnType = refType
} }
val refConstructorSymbol = IrConstructorSymbolImpl(refConstructor)
val elementField: PropertyDescriptor = val elementField: PropertyDescriptor =
PropertyDescriptorImpl.create( PropertyDescriptorImpl.create(
refClass, Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC, true, refClass, Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC, true,
@@ -54,6 +68,10 @@ class JvmSharedVariablesManager(
/* lateInit = */ false, /* isConst = */ false, /* isExpect = */ false, /* isActual = */ false, /* lateInit = */ false, /* isConst = */ false, /* isExpect = */ false, /* isActual = */ false,
/* isExternal = */ false, /* isDelegated = */ false /* isExternal = */ false, /* isDelegated = */ false
).initialize(type, dispatchReceiverParameter = refClass.thisAsReceiverParameter) ).initialize(type, dispatchReceiverParameter = refClass.thisAsReceiverParameter)
val elementFieldSymbol = IrFieldSymbolImpl(elementField)
val elementFieldDeclaration =
IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SHARED_VARIABLE_ORIGIN, elementFieldSymbol, type.toIrType()!!)
} }
private val primitiveRefDescriptorProviders: Map<PrimitiveType, PrimitiveRefDescriptorsProvider> = private val primitiveRefDescriptorProviders: Map<PrimitiveType, PrimitiveRefDescriptorsProvider> =
@@ -111,6 +129,11 @@ class JvmSharedVariablesManager(
dispatchReceiverParameter = genericRefClass.thisAsReceiverParameter dispatchReceiverParameter = genericRefClass.thisAsReceiverParameter
) )
val genericElementFieldSymbol = IrFieldSymbolImpl(genericElementField)
val elementFieldDeclaration =
IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SHARED_VARIABLE_ORIGIN, genericElementFieldSymbol, irBuiltIns.anyType)
fun getRefType(valueType: KotlinType) = fun getRefType(valueType: KotlinType) =
KotlinTypeFactory.simpleNotNullType( KotlinTypeFactory.simpleNotNullType(
Annotations.EMPTY, Annotations.EMPTY,
@@ -128,6 +151,7 @@ class JvmSharedVariablesManager(
getSharedVariableType(variableDescriptor.type), getSharedVariableType(variableDescriptor.type),
false, false, variableDescriptor.isLateInit, variableDescriptor.source false, false, variableDescriptor.isLateInit, variableDescriptor.source
) )
val sharedVariableSymbol = IrVariableSymbolImpl(sharedVariableDescriptor)
val valueType = originalDeclaration.descriptor.type val valueType = originalDeclaration.descriptor.type
val primitiveRefDescriptorsProvider = primitiveRefDescriptorProviders[getPrimitiveType(valueType)] val primitiveRefDescriptorsProvider = primitiveRefDescriptorProviders[getPrimitiveType(valueType)]
@@ -135,6 +159,12 @@ class JvmSharedVariablesManager(
val refConstructor = val refConstructor =
primitiveRefDescriptorsProvider?.refConstructor ?: objectRefDescriptorsProvider.getSubstitutedRefConstructor(valueType) primitiveRefDescriptorsProvider?.refConstructor ?: objectRefDescriptorsProvider.getSubstitutedRefConstructor(valueType)
val refConstructorSymbol =
primitiveRefDescriptorsProvider?.refConstructorSymbol ?: createFunctionSymbol(refConstructor) as IrConstructorSymbol
val refConstructorDeclaration = if (refConstructorSymbol.isBound) refConstructorSymbol.owner else
IrConstructorImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, SHARED_VARIABLE_ORIGIN, refConstructorSymbol)
val refConstructorTypeArguments = val refConstructorTypeArguments =
if (primitiveRefDescriptorsProvider != null) null if (primitiveRefDescriptorsProvider != null) null
else mapOf(objectRefDescriptorsProvider.constructorTypeParameter to valueType) else mapOf(objectRefDescriptorsProvider.constructorTypeParameter to valueType)
@@ -143,11 +173,12 @@ class JvmSharedVariablesManager(
val refConstructorCall = IrCallImpl( val refConstructorCall = IrCallImpl(
originalDeclaration.startOffset, originalDeclaration.endOffset, originalDeclaration.startOffset, originalDeclaration.endOffset,
refConstructor.constructedClass.defaultType.toIrType()!!, refConstructor.constructedClass.defaultType.toIrType()!!,
refConstructor, refConstructorTypeArguments?.size ?: 0 refConstructorSymbol, refConstructor,
refConstructorTypeArguments?.size ?: 0
) )
return IrVariableImpl( return IrVariableImpl(
originalDeclaration.startOffset, originalDeclaration.endOffset, originalDeclaration.origin, originalDeclaration.startOffset, originalDeclaration.endOffset, originalDeclaration.origin,
sharedVariableDescriptor, sharedVariableDescriptor.type.toIrType()!!, refConstructorCall sharedVariableSymbol, sharedVariableDescriptor.type.toIrType()!!, refConstructorCall
) )
} }
@@ -160,12 +191,12 @@ class JvmSharedVariablesManager(
val valueType = originalDeclaration.descriptor.type val valueType = originalDeclaration.descriptor.type
val primitiveRefDescriptorsProvider = primitiveRefDescriptorProviders[getPrimitiveType(valueType)] val primitiveRefDescriptorsProvider = primitiveRefDescriptorProviders[getPrimitiveType(valueType)]
val elementPropertyDescriptor = val elementPropertySymbol =
primitiveRefDescriptorsProvider?.elementField ?: objectRefDescriptorsProvider.genericElementField primitiveRefDescriptorsProvider?.elementFieldSymbol ?: objectRefDescriptorsProvider.genericElementFieldSymbol
val sharedVariableInitialization = IrSetFieldImpl( val sharedVariableInitialization = IrSetFieldImpl(
initializer.startOffset, initializer.endOffset, initializer.startOffset, initializer.endOffset,
elementPropertyDescriptor, elementPropertySymbol,
IrGetValueImpl(initializer.startOffset, initializer.endOffset, sharedVariableDeclaration.symbol), IrGetValueImpl(initializer.startOffset, initializer.endOffset, sharedVariableDeclaration.symbol),
initializer, initializer,
originalDeclaration.type originalDeclaration.type
@@ -177,34 +208,26 @@ class JvmSharedVariablesManager(
) )
} }
private fun getElementFieldDescriptor(valueType: KotlinType): PropertyDescriptor { private fun getElementFieldSymbol(valueType: KotlinType): IrFieldSymbol {
val primitiveRefDescriptorsProvider = primitiveRefDescriptorProviders[getPrimitiveType(valueType)] val primitiveRefDescriptorsProvider = primitiveRefDescriptorProviders[getPrimitiveType(valueType)]
return primitiveRefDescriptorsProvider?.elementField ?: objectRefDescriptorsProvider.genericElementField return primitiveRefDescriptorsProvider?.elementFieldSymbol ?: objectRefDescriptorsProvider.genericElementFieldSymbol
} }
override fun getSharedValue(sharedVariableSymbol: IrVariableSymbol, originalGet: IrGetValue): IrExpression = override fun getSharedValue(sharedVariableSymbol: IrVariableSymbol, originalGet: IrGetValue): IrExpression =
IrGetFieldImpl( IrGetFieldImpl(
originalGet.startOffset, originalGet.endOffset, originalGet.startOffset, originalGet.endOffset,
getElementFieldDescriptor(originalGet.descriptor.type), getElementFieldSymbol(originalGet.descriptor.type),
IrGetValueImpl(
originalGet.startOffset,
originalGet.endOffset,
sharedVariableSymbol
),
originalGet.type, originalGet.type,
IrGetValueImpl(originalGet.startOffset, originalGet.endOffset, sharedVariableSymbol),
originalGet.origin originalGet.origin
) )
override fun setSharedValue(sharedVariableSymbol: IrVariableSymbol, originalSet: IrSetVariable): IrExpression = override fun setSharedValue(sharedVariableSymbol: IrVariableSymbol, originalSet: IrSetVariable): IrExpression =
IrSetFieldImpl( IrSetFieldImpl(
originalSet.startOffset, originalSet.endOffset, originalSet.startOffset, originalSet.endOffset,
getElementFieldDescriptor(originalSet.descriptor.type), getElementFieldSymbol(originalSet.descriptor.type),
IrGetValueImpl( IrGetValueImpl(originalSet.startOffset, originalSet.endOffset, sharedVariableSymbol),
originalSet.startOffset,
originalSet.endOffset,
sharedVariableSymbol
),
originalSet.value, originalSet.value,
originalSet.type, originalSet.type,
originalSet.origin originalSet.origin
@@ -186,18 +186,12 @@ class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringPass {
return enumEntryClass return enumEntryClass
} }
private fun createFieldForEnumEntry(enumEntry: IrEnumEntry): IrField { private fun createFieldForEnumEntry(enumEntry: IrEnumEntry) =
val fieldSymbol = context.descriptorsFactory.getSymbolForEnumEntry(enumEntry.symbol) context.declarationFactory.getFieldForEnumEntry(enumEntry, enumEntry.initializerExpression!!.type).also {
return IrFieldImpl(
enumEntry.startOffset, enumEntry.endOffset, JvmLoweredDeclarationOrigin.FIELD_FOR_ENUM_ENTRY,
fieldSymbol, enumEntry.initializerExpression!!.type
).also {
it.initializer = IrExpressionBodyImpl(enumEntry.initializerExpression!!) it.initializer = IrExpressionBodyImpl(enumEntry.initializerExpression!!)
enumEntryFields.add(it) enumEntryFields.add(it)
enumEntriesByField[it] = enumEntry enumEntriesByField[it] = enumEntry
} }
}
private fun setupSynthesizedEnumClassMembers() { private fun setupSynthesizedEnumClassMembers() {
val irField = createSyntheticValuesFieldDeclaration() val irField = createSyntheticValuesFieldDeclaration()
@@ -39,7 +39,7 @@ class FileClassLowering(val context: JvmBackendContext) : FileLoweringPass {
if (fileClassMembers.isEmpty()) return if (fileClassMembers.isEmpty()) return
val fileClassDescriptor = context.descriptorsFactory.createFileClassDescriptor(irFile.fileEntry, irFile.packageFragmentDescriptor) val fileClassDescriptor = context.declarationFactory.createFileClassDescriptor(irFile.fileEntry, irFile.packageFragmentDescriptor)
val irFileClass = IrClassImpl(0, irFile.fileEntry.maxOffset, IrDeclarationOrigin.DEFINED, fileClassDescriptor, fileClassMembers) val irFileClass = IrClassImpl(0, irFile.fileEntry.maxOffset, IrDeclarationOrigin.DEFINED, fileClassDescriptor, fileClassMembers)
classes.add(irFileClass) classes.add(irFileClass)
@@ -142,12 +142,11 @@ internal fun FunctionDescriptor.createFunctionAndMapVariables(
visibility = visibility visibility = visibility
).apply { ).apply {
body = oldFunction.body body = oldFunction.body
returnType = oldFunction.returnType
createParameterDeclarations() createParameterDeclarations()
val mapping: Map<ValueDescriptor, IrValueParameter> = val mapping: Map<IrValueParameter, IrValueParameter> =
( (listOfNotNull(oldFunction.dispatchReceiverParameter!!, oldFunction.extensionReceiverParameter) + oldFunction.valueParameters)
listOfNotNull(oldFunction.descriptor.dispatchReceiverParameter!!, oldFunction.descriptor.extensionReceiverParameter) + .zip(valueParameters).toMap()
oldFunction.descriptor.valueParameters
).zip(valueParameters).toMap()
body?.transform(VariableRemapper(mapping), null) body?.transform(VariableRemapper(mapping), null)
} }
@@ -106,7 +106,8 @@ private class CompanionObjectJvmStaticLowering(val context: JvmBackendContext) :
} }
private fun createProxyBody(target: IrFunction, proxy: IrFunction, companion: IrClass): IrBody { private fun createProxyBody(target: IrFunction, proxy: IrFunction, companion: IrClass): IrBody {
val companionInstanceFieldSymbol = context.descriptorsFactory.getSymbolForObjectInstance(companion.symbol) val companionInstanceField = context.declarationFactory.getFieldForObjectInstance(companion)
val companionInstanceFieldSymbol = companionInstanceField.symbol
val call = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, target.returnType, target.symbol) val call = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, target.returnType, target.symbol)
call.dispatchReceiver = IrGetFieldImpl( call.dispatchReceiver = IrGetFieldImpl(
@@ -147,9 +148,9 @@ private class SingletonObjectJvmStaticLowering(
irClass.declarations.filter(::isJvmStaticFunction).forEach { irClass.declarations.filter(::isJvmStaticFunction).forEach {
val jvmStaticFunction = it as IrSimpleFunction val jvmStaticFunction = it as IrSimpleFunction
val oldDispatchReceiverParemeter = jvmStaticFunction.dispatchReceiverParameter!! val oldDispatchReceiverParameter = jvmStaticFunction.dispatchReceiverParameter!!
jvmStaticFunction.dispatchReceiverParameter = null jvmStaticFunction.dispatchReceiverParameter = null
modifyBody(jvmStaticFunction, irClass, oldDispatchReceiverParemeter) modifyBody(jvmStaticFunction, irClass, oldDispatchReceiverParameter)
functionsMadeStatic.add(jvmStaticFunction.symbol) functionsMadeStatic.add(jvmStaticFunction.symbol)
} }
} }
@@ -165,17 +166,16 @@ private class ReplaceThisByStaticReference(
val oldThisReceiverParameter: IrValueParameter val oldThisReceiverParameter: IrValueParameter
) : IrElementTransformer<Nothing?> { ) : IrElementTransformer<Nothing?> {
override fun visitGetValue(expression: IrGetValue, data: Nothing?): IrExpression { override fun visitGetValue(expression: IrGetValue, data: Nothing?): IrExpression {
val irGetValue = expression if (expression.symbol == oldThisReceiverParameter.symbol) {
if (irGetValue.symbol == oldThisReceiverParameter.symbol) { val instanceField = context.declarationFactory.getFieldForObjectInstance(irClass)
val instanceSymbol = context.descriptorsFactory.getSymbolForObjectInstance(irClass.symbol)
return IrGetFieldImpl( return IrGetFieldImpl(
expression.startOffset, expression.startOffset,
expression.endOffset, expression.endOffset,
instanceSymbol, instanceField.symbol,
irClass.defaultType irClass.defaultType
) )
} }
return super.visitGetValue(irGetValue, data) return super.visitGetValue(expression, data)
} }
} }
@@ -47,7 +47,7 @@ class ObjectClassLowering(val context: JvmBackendContext) : IrElementTransformer
private fun process(irClass: IrClass) { private fun process(irClass: IrClass) {
if (!irClass.isObject) return if (!irClass.isObject) return
val publicInstance = context.descriptorsFactory.getSymbolForObjectInstance(irClass.symbol) val publicInstanceField = context.declarationFactory.getFieldForObjectInstance(irClass)
val constructor = irClass.descriptor.unsubstitutedPrimaryConstructor val constructor = irClass.descriptor.unsubstitutedPrimaryConstructor
?: throw AssertionError("Object should have a primary constructor: ${irClass.descriptor}") ?: throw AssertionError("Object should have a primary constructor: ${irClass.descriptor}")
@@ -55,7 +55,7 @@ class ObjectClassLowering(val context: JvmBackendContext) : IrElementTransformer
val publicInstanceOwner = if (irClass.descriptor.isCompanionObject) parentScope!!.irElement as IrDeclarationContainer else irClass val publicInstanceOwner = if (irClass.descriptor.isCompanionObject) parentScope!!.irElement as IrDeclarationContainer else irClass
if (isCompanionObjectInInterfaceNotIntrinsic(irClass.descriptor)) { if (isCompanionObjectInInterfaceNotIntrinsic(irClass.descriptor)) {
// TODO rename to $$INSTANCE // TODO rename to $$INSTANCE
val privateInstance = publicInstance.descriptor.copy( val privateInstance = publicInstanceField.descriptor.copy(
irClass.descriptor, irClass.descriptor,
Modality.FINAL, Modality.FINAL,
Visibilities.PROTECTED/*TODO package local*/, Visibilities.PROTECTED/*TODO package local*/,
@@ -64,15 +64,15 @@ class ObjectClassLowering(val context: JvmBackendContext) : IrElementTransformer
) as PropertyDescriptor ) as PropertyDescriptor
privateInstance.name privateInstance.name
val field = createInstanceFieldWithInitializer(IrFieldSymbolImpl(privateInstance), constructor, irClass, irClass.defaultType) val field = createInstanceFieldWithInitializer(IrFieldSymbolImpl(privateInstance), constructor, irClass, irClass.defaultType)
createFieldWithCustomInitializer( publicInstanceField.initializer =
publicInstance, IrExpressionBodyImpl(IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, field.symbol, irClass.defaultType))
IrGetFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, field.symbol, irClass.defaultType),
publicInstanceOwner,
irClass.defaultType
)
} else { } else {
createInstanceFieldWithInitializer(publicInstance, constructor, publicInstanceOwner, irClass.defaultType) val constructorCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irClass.defaultType, constructor, 0)
publicInstanceField.initializer = IrExpressionBodyImpl(constructorCall)
} }
publicInstanceField.parent = publicInstanceOwner
pendingTransformations.add { publicInstanceOwner.declarations.add(publicInstanceField) }
} }
private fun createInstanceFieldWithInitializer( private fun createInstanceFieldWithInitializer(
@@ -99,6 +99,7 @@ class ObjectClassLowering(val context: JvmBackendContext) : IrElementTransformer
fieldSymbol, objectType fieldSymbol, objectType
).also { ).also {
it.initializer = IrExpressionBodyImpl(instanceInitializer) it.initializer = IrExpressionBodyImpl(instanceInitializer)
it.parent = instanceOwner
pendingTransformations.add { instanceOwner.declarations.add(it) } pendingTransformations.add { instanceOwner.declarations.add(it) }
} }
} }
@@ -21,12 +21,12 @@ class SingletonReferencesLowering(val context: JvmBackendContext) : BodyLowering
} }
override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression { override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression {
val entrySymbol = context.descriptorsFactory.getSymbolForEnumEntry(expression.symbol) val entrySymbol = context.declarationFactory.getFieldForEnumEntry(expression.symbol.owner, expression.type)
return IrGetFieldImpl(expression.startOffset, expression.endOffset, entrySymbol, expression.type) return IrGetFieldImpl(expression.startOffset, expression.endOffset, entrySymbol.symbol, expression.type)
} }
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression { override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
val instanceField = context.descriptorsFactory.getSymbolForObjectInstance(expression.symbol) val instanceField = context.declarationFactory.getFieldForObjectInstance(expression.symbol.owner)
return IrGetFieldImpl(expression.startOffset, expression.endOffset, instanceField, expression.type) return IrGetFieldImpl(expression.startOffset, expression.endOffset, instanceField.symbol, expression.type)
} }
} }
@@ -38,8 +38,9 @@ class StaticDefaultFunctionLowering(val state: GenerationState) : IrElementTrans
declaration.descriptor.containingDeclaration as ClassDescriptor, declaration.descriptor.containingDeclaration as ClassDescriptor,
declaration.descriptor.name, declaration.descriptor.name,
declaration.descriptor, declaration.descriptor,
declaration.descriptor.dispatchReceiverParameter!!.type declaration.dispatchReceiverParameter!!.descriptor.type
) )
// NOTE: Fix it
newFunction.createFunctionAndMapVariables(declaration, Visibilities.PUBLIC) newFunction.createFunctionAndMapVariables(declaration, Visibilities.PUBLIC)
} else { } else {
super.visitFunction(declaration) super.visitFunction(declaration)
@@ -242,6 +242,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
ktConstructorElement.pureStartOffset, ktConstructorElement.pureEndOffset, IrDeclarationOrigin.DEFINED, ktConstructorElement.pureStartOffset, ktConstructorElement.pureEndOffset, IrDeclarationOrigin.DEFINED,
constructorDescriptor constructorDescriptor
).buildWithScope { irConstructor -> ).buildWithScope { irConstructor ->
declarationGenerator.generateScopedTypeParameterDeclarations(irConstructor, constructorDescriptor.typeParameters)
generateValueParameterDeclarations(irConstructor, ktParametersElement, null) generateValueParameterDeclarations(irConstructor, ktParametersElement, null)
irConstructor.body = createBodyGenerator(irConstructor.symbol).generateBody() irConstructor.body = createBodyGenerator(irConstructor.symbol).generateBody()
irConstructor.returnType = constructorDescriptor.returnType.toIrType() irConstructor.returnType = constructorDescriptor.returnType.toIrType()
@@ -118,8 +118,8 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
variableDescriptor.getter ?: throw AssertionError("Local delegated property should have a getter: $variableDescriptor") variableDescriptor.getter ?: throw AssertionError("Local delegated property should have a getter: $variableDescriptor")
val setterDescriptor = variableDescriptor.setter val setterDescriptor = variableDescriptor.setter
val getterSymbol = context.symbolTable.referenceFunction(getterDescriptor) val getterSymbol = context.symbolTable.referenceSimpleFunction(getterDescriptor)
val setterSymbol = setterDescriptor?.let { context.symbolTable.referenceFunction(it) } val setterSymbol = setterDescriptor?.let { context.symbolTable.referenceSimpleFunction(it) }
return IrLocalDelegatedPropertyReferenceImpl( return IrLocalDelegatedPropertyReferenceImpl(
startOffset, endOffset, type.toIrType(), startOffset, endOffset, type.toIrType(),
@@ -141,8 +141,8 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
val setterDescriptor = propertyDescriptor.setter val setterDescriptor = propertyDescriptor.setter
val fieldSymbol = if (getterDescriptor == null) context.symbolTable.referenceField(propertyDescriptor) else null val fieldSymbol = if (getterDescriptor == null) context.symbolTable.referenceField(propertyDescriptor) else null
val getterSymbol = getterDescriptor?.let { context.symbolTable.referenceFunction(it.original) } val getterSymbol = getterDescriptor?.let { context.symbolTable.referenceSimpleFunction(it.original) }
val setterSymbol = setterDescriptor?.let { context.symbolTable.referenceFunction(it.original) } val setterSymbol = setterDescriptor?.let { context.symbolTable.referenceSimpleFunction(it.original) }
return IrPropertyReferenceImpl( return IrPropertyReferenceImpl(
startOffset, endOffset, type.toIrType(), startOffset, endOffset, type.toIrType(),
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.ir.declarations package org.jetbrains.kotlin.ir.declarations
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
@@ -30,6 +29,7 @@ interface IrTypeParameter : IrSymbolDeclaration<IrTypeParameterSymbol> {
val name: Name val name: Name
val variance: Variance val variance: Variance
val index: Int val index: Int
val isReified: Boolean
val superTypes: MutableList<IrType> val superTypes: MutableList<IrType>
override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrTypeParameter override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrTypeParameter
@@ -35,6 +35,7 @@ class IrTypeParameterImpl(
override val symbol: IrTypeParameterSymbol, override val symbol: IrTypeParameterSymbol,
override val name: Name, override val name: Name,
override val index: Int, override val index: Int,
override val isReified: Boolean,
override val variance: Variance override val variance: Variance
) : ) :
IrDeclarationBase(startOffset, endOffset, origin), IrDeclarationBase(startOffset, endOffset, origin),
@@ -50,9 +51,21 @@ class IrTypeParameterImpl(
startOffset, endOffset, origin, symbol, startOffset, endOffset, origin, symbol,
symbol.descriptor.name, symbol.descriptor.name,
symbol.descriptor.index, symbol.descriptor.index,
symbol.descriptor.isReified,
symbol.descriptor.variance symbol.descriptor.variance
) )
constructor(
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
symbol: IrTypeParameterSymbol,
name: Name,
index: Int,
variance: Variance
) : this(startOffset, endOffset, origin, symbol, name, index, symbol.descriptor.isReified, variance)
@Deprecated("Use constructor which takes symbol instead of descriptor")
constructor( constructor(
startOffset: Int, startOffset: Int,
endOffset: Int, endOffset: Int,
@@ -55,6 +55,24 @@ class IrVariableImpl(
isLateinit = symbol.descriptor.isLateInit isLateinit = symbol.descriptor.isLateInit
) )
constructor(
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
symbol: IrVariableSymbol,
type: IrType,
initializer: IrExpression?
) : this(
startOffset, endOffset, origin, symbol,
symbol.descriptor.name, type,
isVar = symbol.descriptor.isVar,
isConst = symbol.descriptor.isConst,
isLateinit = symbol.descriptor.isLateInit
) {
this.initializer = initializer
}
@Deprecated("Use constructor which takes symbol instead of descriptor")
constructor( constructor(
startOffset: Int, startOffset: Int,
endOffset: Int, endOffset: Int,
@@ -63,6 +81,7 @@ class IrVariableImpl(
type: IrType type: IrType
) : this(startOffset, endOffset, origin, IrVariableSymbolImpl(descriptor), type) ) : this(startOffset, endOffset, origin, IrVariableSymbolImpl(descriptor), type)
@Deprecated("Use constructor which takes symbol instead of descriptor")
constructor( constructor(
startOffset: Int, startOffset: Int,
endOffset: Int, endOffset: Int,
@@ -5,9 +5,14 @@
package org.jetbrains.kotlin.ir.declarations.lazy package org.jetbrains.kotlin.ir.declarations.lazy
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
import org.jetbrains.kotlin.ir.util.ReferenceSymbolTable
import org.jetbrains.kotlin.ir.util.SymbolTable
class IrLazySymbolTable(private val originalTable: SymbolTable) : ReferenceSymbolTable by originalTable { class IrLazySymbolTable(private val originalTable: SymbolTable) : ReferenceSymbolTable by originalTable {
@@ -25,6 +25,7 @@ class IrLazyTypeParameter(
override val symbol: IrTypeParameterSymbol, override val symbol: IrTypeParameterSymbol,
override val name: Name, override val name: Name,
override val index: Int, override val index: Int,
override val isReified: Boolean,
override val variance: Variance, override val variance: Variance,
stubGenerator: DeclarationStubGenerator, stubGenerator: DeclarationStubGenerator,
typeTranslator: TypeTranslator typeTranslator: TypeTranslator
@@ -44,6 +45,7 @@ class IrLazyTypeParameter(
startOffset, endOffset, origin, symbol, startOffset, endOffset, origin, symbol,
symbol.descriptor.name, symbol.descriptor.name,
symbol.descriptor.index, symbol.descriptor.index,
symbol.descriptor.isReified,
symbol.descriptor.variance, symbol.descriptor.variance,
stubGenerator, TypeTranslator stubGenerator, TypeTranslator
) )
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
interface IrCallableReference : IrMemberAccessExpression { interface IrCallableReference : IrMemberAccessExpression {
@@ -36,13 +37,13 @@ interface IrFunctionReference : IrCallableReference {
interface IrPropertyReference : IrCallableReference { interface IrPropertyReference : IrCallableReference {
override val descriptor: PropertyDescriptor override val descriptor: PropertyDescriptor
val field: IrFieldSymbol? val field: IrFieldSymbol?
val getter: IrFunctionSymbol? val getter: IrSimpleFunctionSymbol?
val setter: IrFunctionSymbol? val setter: IrSimpleFunctionSymbol?
} }
interface IrLocalDelegatedPropertyReference : IrCallableReference { interface IrLocalDelegatedPropertyReference : IrCallableReference {
override val descriptor: VariableDescriptorWithAccessors override val descriptor: VariableDescriptorWithAccessors
val delegate: IrVariableSymbol val delegate: IrVariableSymbol
val getter: IrFunctionSymbol val getter: IrSimpleFunctionSymbol
val setter: IrFunctionSymbol? val setter: IrSimpleFunctionSymbol?
} }
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.ir.expressions.impl
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
import org.jetbrains.kotlin.ir.expressions.IrLocalDelegatedPropertyReference import org.jetbrains.kotlin.ir.expressions.IrLocalDelegatedPropertyReference
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -30,8 +30,8 @@ class IrLocalDelegatedPropertyReferenceImpl(
type: IrType, type: IrType,
override val descriptor: VariableDescriptorWithAccessors, override val descriptor: VariableDescriptorWithAccessors,
override val delegate: IrVariableSymbol, override val delegate: IrVariableSymbol,
override val getter: IrFunctionSymbol, override val getter: IrSimpleFunctionSymbol,
override val setter: IrFunctionSymbol?, override val setter: IrSimpleFunctionSymbol?,
origin: IrStatementOrigin? = null origin: IrStatementOrigin? = null
) : ) :
IrNoArgumentsCallableReferenceBase(startOffset, endOffset, type, 0, origin), IrNoArgumentsCallableReferenceBase(startOffset, endOffset, type, 0, origin),
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
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.IrType
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -31,8 +31,8 @@ class IrPropertyReferenceImpl(
override val descriptor: PropertyDescriptor, override val descriptor: PropertyDescriptor,
typeArgumentsCount: Int, typeArgumentsCount: Int,
override val field: IrFieldSymbol?, override val field: IrFieldSymbol?,
override val getter: IrFunctionSymbol?, override val getter: IrSimpleFunctionSymbol?,
override val setter: IrFunctionSymbol?, override val setter: IrSimpleFunctionSymbol?,
origin: IrStatementOrigin? = null origin: IrStatementOrigin? = null
) : ) :
IrNoArgumentsCallableReferenceBase(startOffset, endOffset, type, typeArgumentsCount, origin), IrNoArgumentsCallableReferenceBase(startOffset, endOffset, type, typeArgumentsCount, origin),
@@ -26,9 +26,9 @@ abstract class IrSymbolBase<out D : DeclarationDescriptor>(override val descript
abstract class IrBindableSymbolBase<out D : DeclarationDescriptor, B : IrSymbolOwner>(descriptor: D) : abstract class IrBindableSymbolBase<out D : DeclarationDescriptor, B : IrSymbolOwner>(descriptor: D) :
IrBindableSymbol<D, B>, IrSymbolBase<D>(descriptor) { IrBindableSymbol<D, B>, IrSymbolBase<D>(descriptor) {
init { init {
assert(isOriginalDescriptor(descriptor)) { // assert(isOriginalDescriptor(descriptor)) {
"Substituted descriptor $descriptor for ${descriptor.original}" // "Substituted descriptor $descriptor for ${descriptor.original}"
} // }
} }
private fun isOriginalDescriptor(descriptor: DeclarationDescriptor): Boolean = private fun isOriginalDescriptor(descriptor: DeclarationDescriptor): Boolean =
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.impl.* import org.jetbrains.kotlin.ir.types.impl.*
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -104,8 +105,8 @@ private fun makeKotlinType(
return classifier.descriptor.defaultType.replace(newArguments = kotlinTypeArguments).makeNullableAsSpecified(hasQuestionMark) return classifier.descriptor.defaultType.replace(newArguments = kotlinTypeArguments).makeNullableAsSpecified(hasQuestionMark)
} }
fun ClassifierDescriptor.toIrType(hasQuestionMark: Boolean = false): IrType { fun ClassifierDescriptor.toIrType(hasQuestionMark: Boolean = false, symbolTable: SymbolTable? = null): IrType {
val symbol = getSymbol() val symbol = getSymbol(symbolTable)
return IrSimpleTypeImpl(defaultType, symbol, hasQuestionMark, listOf(), listOf()) return IrSimpleTypeImpl(defaultType, symbol, hasQuestionMark, listOf(), listOf())
} }
@@ -123,14 +124,14 @@ fun IrClassifierSymbol.typeWith(arguments: List<IrType>): IrSimpleType =
fun IrClass.typeWith(arguments: List<IrType>) = this.symbol.typeWith(arguments) fun IrClass.typeWith(arguments: List<IrType>) = this.symbol.typeWith(arguments)
fun KotlinType.toIrType(): IrType? { fun KotlinType.toIrType(symbolTable: SymbolTable? = null): IrType? {
if (isDynamic()) return IrDynamicTypeImpl(this, listOf(), Variance.INVARIANT) if (isDynamic()) return IrDynamicTypeImpl(this, listOf(), Variance.INVARIANT)
val symbol = constructor.declarationDescriptor?.getSymbol() ?: return null val symbol = constructor.declarationDescriptor?.getSymbol(symbolTable) ?: return null
val arguments = this.arguments.mapIndexed { i, projection -> val arguments = this.arguments.map { projection ->
when (projection) { when (projection) {
is TypeProjectionImpl -> IrTypeProjectionImpl(projection.type.toIrType()!!, projection.projectionKind) is TypeProjectionImpl -> IrTypeProjectionImpl(projection.type.toIrType(symbolTable)!!, projection.projectionKind)
is StarProjectionImpl -> IrStarProjectionImpl is StarProjectionImpl -> IrStarProjectionImpl
else -> error(projection) else -> error(projection)
} }
@@ -142,8 +143,8 @@ fun KotlinType.toIrType(): IrType? {
} }
// TODO: this function creates unbound symbol which is the great source of problems // TODO: this function creates unbound symbol which is the great source of problems
private fun ClassifierDescriptor.getSymbol(): IrClassifierSymbol = when (this) { private fun ClassifierDescriptor.getSymbol(symbolTable: SymbolTable?): IrClassifierSymbol = when (this) {
is ClassDescriptor -> IrClassSymbolImpl(this) is ClassDescriptor -> symbolTable?.referenceClass(this) ?: IrClassSymbolImpl(this)
is TypeParameterDescriptor -> IrTypeParameterSymbolImpl(this) is TypeParameterDescriptor -> /*symbolTable?.referenceTypeParameter(this) ?: */IrTypeParameterSymbolImpl(this)
else -> TODO() else -> TODO()
} }
@@ -478,8 +478,8 @@ open class DeepCopyIrTreeWithSymbols(
expression.descriptor, expression.descriptor,
expression.typeArgumentsCount, expression.typeArgumentsCount,
expression.field?.let { symbolRemapper.getReferencedField(it) }, expression.field?.let { symbolRemapper.getReferencedField(it) },
expression.getter?.let { symbolRemapper.getReferencedFunction(it) }, expression.getter?.let { symbolRemapper.getReferencedSimpleFunction(it) },
expression.setter?.let { symbolRemapper.getReferencedFunction(it) }, expression.setter?.let { symbolRemapper.getReferencedSimpleFunction(it) },
mapStatementOrigin(expression.origin) mapStatementOrigin(expression.origin)
).apply { ).apply {
copyRemappedTypeArgumentsFrom(expression) copyRemappedTypeArgumentsFrom(expression)
@@ -492,8 +492,8 @@ open class DeepCopyIrTreeWithSymbols(
expression.type.remapType(), expression.type.remapType(),
expression.descriptor, expression.descriptor,
symbolRemapper.getReferencedVariable(expression.delegate), symbolRemapper.getReferencedVariable(expression.delegate),
symbolRemapper.getReferencedFunction(expression.getter), symbolRemapper.getReferencedSimpleFunction(expression.getter),
expression.setter?.let { symbolRemapper.getReferencedFunction(it) }, expression.setter?.let { symbolRemapper.getReferencedSimpleFunction(it) },
mapStatementOrigin(expression.origin) mapStatementOrigin(expression.origin)
) )
@@ -157,6 +157,7 @@ open class DeepCopySymbolRemapper(
override fun getReferencedVariable(symbol: IrVariableSymbol): IrVariableSymbol = variables.getReferenced(symbol) override fun getReferencedVariable(symbol: IrVariableSymbol): IrVariableSymbol = variables.getReferenced(symbol)
override fun getReferencedField(symbol: IrFieldSymbol): IrFieldSymbol = fields.getReferenced(symbol) override fun getReferencedField(symbol: IrFieldSymbol): IrFieldSymbol = fields.getReferenced(symbol)
override fun getReferencedConstructor(symbol: IrConstructorSymbol): IrConstructorSymbol = constructors.getReferenced(symbol) override fun getReferencedConstructor(symbol: IrConstructorSymbol): IrConstructorSymbol = constructors.getReferenced(symbol)
override fun getReferencedSimpleFunction(symbol: IrSimpleFunctionSymbol): IrSimpleFunctionSymbol = functions.getReferenced(symbol)
override fun getReferencedValue(symbol: IrValueSymbol): IrValueSymbol = override fun getReferencedValue(symbol: IrValueSymbol): IrValueSymbol =
when (symbol) { when (symbol) {
is IrValueParameterSymbol -> valueParameters.getReferenced(symbol) is IrValueParameterSymbol -> valueParameters.getReferenced(symbol)
@@ -158,6 +158,7 @@ fun IrFunction.createParameterDeclarations() {
assert(valueParameters.isEmpty()) assert(valueParameters.isEmpty())
descriptor.valueParameters.mapTo(valueParameters) { it.irValueParameter() } descriptor.valueParameters.mapTo(valueParameters) { it.irValueParameter() }
// valueParameters.mapTo(valueParameters) { it.descriptor.irValueParameter() }
assert(typeParameters.isEmpty()) assert(typeParameters.isEmpty())
descriptor.typeParameters.mapTo(typeParameters) { descriptor.typeParameters.mapTo(typeParameters) {
@@ -316,6 +317,30 @@ fun IrAnnotationContainer.hasAnnotation(name: FqName) =
it.symbol.owner.parentAsClass.descriptor.fqNameSafe == name it.symbol.owner.parentAsClass.descriptor.fqNameSafe == name
} }
val IrConstructor.constructedClassType get() = (parent as IrClass).thisReceiver?.type!!
fun IrFunction.isFakeOverriddenFromAny(): Boolean {
if (origin != IrDeclarationOrigin.FAKE_OVERRIDE) {
return (parent as? IrClass)?.thisReceiver?.type?.isAny() ?: false
}
return (this as IrSimpleFunction).overriddenSymbols.all { it.owner.isFakeOverriddenFromAny() }
}
fun IrCall.isSuperToAny() = superQualifier?.let { this.symbol.owner.isFakeOverriddenFromAny() } ?: false
fun IrDeclaration.isEffectivelyExternal(): Boolean {
return when (this) {
is IrConstructor -> isExternal || parent is IrDeclaration && parent.isEffectivelyExternal()
is IrFunction -> isExternal || parent is IrDeclaration && parent.isEffectivelyExternal()
is IrField -> isExternal || parent is IrDeclaration && parent.isEffectivelyExternal()
is IrClass -> isExternal || parent is IrDeclaration && parent.isEffectivelyExternal()
else -> false
}
}
val IrDeclaration.isDynamic get() = this is IrFunction && dispatchReceiverParameter?.type is IrDynamicType
fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter { fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter {
assert(this.descriptor.type == newDescriptor.type) assert(this.descriptor.type == newDescriptor.type)
@@ -37,6 +37,7 @@ interface SymbolRemapper {
fun getReferencedConstructor(symbol: IrConstructorSymbol): IrConstructorSymbol fun getReferencedConstructor(symbol: IrConstructorSymbol): IrConstructorSymbol
fun getReferencedValue(symbol: IrValueSymbol): IrValueSymbol fun getReferencedValue(symbol: IrValueSymbol): IrValueSymbol
fun getReferencedFunction(symbol: IrFunctionSymbol): IrFunctionSymbol fun getReferencedFunction(symbol: IrFunctionSymbol): IrFunctionSymbol
fun getReferencedSimpleFunction(symbol: IrSimpleFunctionSymbol): IrSimpleFunctionSymbol
fun getReferencedReturnableBlock(symbol: IrReturnableBlockSymbol): IrReturnableBlockSymbol fun getReferencedReturnableBlock(symbol: IrReturnableBlockSymbol): IrReturnableBlockSymbol
fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol
} }
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
//adopted snippet from kdoc //adopted snippet from kdoc
open class KModel { open class KModel {
val sourcesInfo: String val sourcesInfo: String
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
class Test { class Test {
val property:Int val property:Int
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1129 // EXPECTED_REACHABLE_NODES: 1129
package foo package foo
+4 -3
View File
@@ -2,11 +2,12 @@
<html> <html>
<head> <head>
<script type="application/javascript" src="../../../dist/js/kotlin.js"></script> <script type="application/javascript" src="../../../dist/js/kotlin.js"></script>
<script type="application/javascript" src="../../../dist/classes/kotlin-test-js/kotlin-test.js"></script> <!--<script type="application/javascript" src="../../../dist/classes/kotlin-test-js/kotlin-test.js"></script>-->
<script type="application/javascript" src="out/box/expression/try/tryCatchExpr_v5.js"></script> <script type="application/javascript" src="out/irBox/testRuntime.js"></script>
<script type="application/javascript" src="out/irBox/expression/for/forIteratesOverNonLiteralRange_v5.js"></script>
<script type="application/javascript"> <script type="application/javascript">
console.log(JS_TESTS.foo.box()); console.log(box());
</script> </script>
</head> </head>
<body> <body>
+2 -2
View File
@@ -14,8 +14,8 @@ fun equals(obj1: dynamic, obj2: dynamic): Boolean {
} }
return js(""" return js("""
if (typeof obj1 === "object" && typeof obj1.equals_Any_ === "function") { if (typeof obj1 === "object" && typeof obj1.equals_kotlin_Any_ === "function") {
return obj1.equals_Any_(obj2); return obj1.equals_kotlin_Any_(obj2);
} }
if (obj1 !== obj1) { if (obj1 !== obj1) {