[K/JS] Add support of compilation with ES-classes
This commit is contained in:
+8
-8
@@ -65,7 +65,7 @@ public final class DebugKlibMetadataProtoBuf {
|
|||||||
* <code>optional int32 flags = 2;</code>
|
* <code>optional int32 flags = 2;</code>
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
*0x1 = preRelease
|
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
boolean hasFlags();
|
boolean hasFlags();
|
||||||
@@ -73,7 +73,7 @@ public final class DebugKlibMetadataProtoBuf {
|
|||||||
* <code>optional int32 flags = 2;</code>
|
* <code>optional int32 flags = 2;</code>
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
*0x1 = preRelease
|
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
int getFlags();
|
int getFlags();
|
||||||
@@ -433,7 +433,7 @@ public final class DebugKlibMetadataProtoBuf {
|
|||||||
* <code>optional int32 flags = 2;</code>
|
* <code>optional int32 flags = 2;</code>
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
*0x1 = preRelease
|
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public boolean hasFlags() {
|
public boolean hasFlags() {
|
||||||
@@ -443,7 +443,7 @@ public final class DebugKlibMetadataProtoBuf {
|
|||||||
* <code>optional int32 flags = 2;</code>
|
* <code>optional int32 flags = 2;</code>
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
*0x1 = preRelease
|
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public int getFlags() {
|
public int getFlags() {
|
||||||
@@ -1225,7 +1225,7 @@ public final class DebugKlibMetadataProtoBuf {
|
|||||||
* <code>optional int32 flags = 2;</code>
|
* <code>optional int32 flags = 2;</code>
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
*0x1 = preRelease
|
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public boolean hasFlags() {
|
public boolean hasFlags() {
|
||||||
@@ -1235,7 +1235,7 @@ public final class DebugKlibMetadataProtoBuf {
|
|||||||
* <code>optional int32 flags = 2;</code>
|
* <code>optional int32 flags = 2;</code>
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
*0x1 = preRelease
|
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public int getFlags() {
|
public int getFlags() {
|
||||||
@@ -1245,7 +1245,7 @@ public final class DebugKlibMetadataProtoBuf {
|
|||||||
* <code>optional int32 flags = 2;</code>
|
* <code>optional int32 flags = 2;</code>
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
*0x1 = preRelease
|
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public Builder setFlags(int value) {
|
public Builder setFlags(int value) {
|
||||||
@@ -1258,7 +1258,7 @@ public final class DebugKlibMetadataProtoBuf {
|
|||||||
* <code>optional int32 flags = 2;</code>
|
* <code>optional int32 flags = 2;</code>
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
*0x1 = preRelease
|
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public Builder clearFlags() {
|
public Builder clearFlags() {
|
||||||
|
|||||||
+11
@@ -291,6 +291,17 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
|
|||||||
)
|
)
|
||||||
var strictImplicitExportType: Boolean by FreezableVar(false)
|
var strictImplicitExportType: Boolean by FreezableVar(false)
|
||||||
|
|
||||||
|
@GradleOption(
|
||||||
|
value = DefaultValue.BOOLEAN_FALSE_DEFAULT,
|
||||||
|
gradleInputType = GradleInputTypes.INPUT,
|
||||||
|
shouldGenerateDeprecatedKotlinOptions = true,
|
||||||
|
)
|
||||||
|
@Argument(
|
||||||
|
value = "-Xes-classes",
|
||||||
|
description = "Generated JavaScript will use ES2015 classes."
|
||||||
|
)
|
||||||
|
var useEsClasses: Boolean by FreezableVar(false)
|
||||||
|
|
||||||
@GradleOption(
|
@GradleOption(
|
||||||
value = DefaultValue.BOOLEAN_TRUE_DEFAULT,
|
value = DefaultValue.BOOLEAN_TRUE_DEFAULT,
|
||||||
gradleInputType = GradleInputTypes.INPUT,
|
gradleInputType = GradleInputTypes.INPUT,
|
||||||
|
|||||||
@@ -144,7 +144,8 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
|||||||
arguments.irSafeExternalBooleanDiagnostic,
|
arguments.irSafeExternalBooleanDiagnostic,
|
||||||
messageCollector
|
messageCollector
|
||||||
),
|
),
|
||||||
granularity = arguments.granularity
|
granularity = arguments.granularity,
|
||||||
|
es6mode = arguments.useEsClasses
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,7 +669,14 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
|||||||
compilerConfiguration = configurationJs,
|
compilerConfiguration = configurationJs,
|
||||||
irFactory = { IrFactoryImplForJsIC(WholeWorldStageController()) },
|
irFactory = { IrFactoryImplForJsIC(WholeWorldStageController()) },
|
||||||
mainArguments = mainCallArguments,
|
mainArguments = mainCallArguments,
|
||||||
compilerInterfaceFactory = { mainModule, cfg -> JsIrCompilerWithIC(mainModule, cfg, arguments.granularity) }
|
compilerInterfaceFactory = { mainModule, cfg ->
|
||||||
|
JsIrCompilerWithIC(
|
||||||
|
mainModule,
|
||||||
|
cfg,
|
||||||
|
arguments.granularity,
|
||||||
|
es6mode = arguments.useEsClasses
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
val artifacts = cacheUpdater.actualizeCaches()
|
val artifacts = cacheUpdater.actualizeCaches()
|
||||||
|
|||||||
+1
-1
@@ -30,6 +30,6 @@ abstract class AbstractValueRemapper : IrElementTransformerVoid() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open class ValueRemapper(private val map: Map<IrValueSymbol, IrValueSymbol>) : AbstractValueRemapper() {
|
open class ValueRemapper(protected open val map: Map<IrValueSymbol, IrValueSymbol>) : AbstractValueRemapper() {
|
||||||
override fun remapValue(oldValue: IrValueSymbol): IrValueSymbol? = map[oldValue]
|
override fun remapValue(oldValue: IrValueSymbol): IrValueSymbol? = map[oldValue]
|
||||||
}
|
}
|
||||||
+7
@@ -125,6 +125,13 @@ class InlineClassLowering(val context: CommonBackendContext) {
|
|||||||
return builder.irGet(initFunction.valueParameters.single())
|
return builder.irGet(initFunction.valueParameters.single())
|
||||||
return expression
|
return expression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitSetValue(expression: IrSetValue): IrExpression {
|
||||||
|
expression.transformChildrenVoid()
|
||||||
|
if (expression.symbol == origParameterSymbol)
|
||||||
|
return builder.irSet(initFunction.valueParameters.single(), expression.value)
|
||||||
|
return expression
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
+irReturn(unboxedInlineClassValue())
|
+irReturn(unboxedInlineClassValue())
|
||||||
|
|||||||
@@ -152,11 +152,9 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
|||||||
val jsAnyToString = getInternalFunction("anyToString")
|
val jsAnyToString = getInternalFunction("anyToString")
|
||||||
val jsCompareTo = getInternalFunction("compareTo")
|
val jsCompareTo = getInternalFunction("compareTo")
|
||||||
val jsEquals = getInternalFunction("equals")
|
val jsEquals = getInternalFunction("equals")
|
||||||
val jsConstruct = getInternalFunction("construct")
|
|
||||||
val jsNewTarget = getInternalFunction("jsNewTarget")
|
val jsNewTarget = getInternalFunction("jsNewTarget")
|
||||||
val jsEmptyObject = getInternalFunction("emptyObject")
|
val jsEmptyObject = getInternalFunction("emptyObject")
|
||||||
val jsOpenInitializerBox = getInternalFunction("openInitializerBox")
|
val jsOpenInitializerBox = getInternalFunction("openInitializerBox")
|
||||||
val es6DefaultType = getInternalFunction("DefaultType")
|
|
||||||
|
|
||||||
val jsImul = getInternalFunction("imul")
|
val jsImul = getInternalFunction("imul")
|
||||||
|
|
||||||
@@ -167,6 +165,8 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
|||||||
val jsBooleanInExternalLog = getInternalFunction("booleanInExternalLog")
|
val jsBooleanInExternalLog = getInternalFunction("booleanInExternalLog")
|
||||||
val jsBooleanInExternalException = getInternalFunction("booleanInExternalException")
|
val jsBooleanInExternalException = getInternalFunction("booleanInExternalException")
|
||||||
|
|
||||||
|
val jsNewAnonymousClass = getInternalFunction("jsNewAnonymousClass")
|
||||||
|
|
||||||
// Coroutines
|
// Coroutines
|
||||||
|
|
||||||
val jsCoroutineContext
|
val jsCoroutineContext
|
||||||
@@ -369,7 +369,10 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
|||||||
|
|
||||||
val jsPrototypeOfSymbol = getInternalFunction("protoOf")
|
val jsPrototypeOfSymbol = getInternalFunction("protoOf")
|
||||||
val jsDefinePropertySymbol = getInternalFunction("defineProp")
|
val jsDefinePropertySymbol = getInternalFunction("defineProp")
|
||||||
val jsObjectCreateSymbol = getInternalFunction("objectCreate") // Object.create
|
val jsObjectCreateSymbol = getInternalFunction("objectCreate") // Object.create(x)
|
||||||
|
val jsCreateThisSymbol = getInternalFunction("createThis") // Object.create(x.prototype)
|
||||||
|
val jsBoxApplySymbol = getInternalFunction("boxApply")
|
||||||
|
val jsCreateExternalThisSymbol = getInternalFunction("createExternalThis")
|
||||||
|
|
||||||
// Helpers:
|
// Helpers:
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ private fun DeclarationContainerLoweringPass.runOnFilesPostfix(files: Iterable<I
|
|||||||
|
|
||||||
private fun ClassLoweringPass.runOnFilesPostfix(moduleFragment: IrModuleFragment) = moduleFragment.files.forEach { runOnFilePostfix(it) }
|
private fun ClassLoweringPass.runOnFilesPostfix(moduleFragment: IrModuleFragment) = moduleFragment.files.forEach { runOnFilePostfix(it) }
|
||||||
|
|
||||||
|
private fun List<Lowering>.toCompilerPhase() =
|
||||||
|
map {
|
||||||
|
@Suppress("USELESS_CAST")
|
||||||
|
it.modulePhase as CompilerPhase<JsIrBackendContext, Iterable<IrModuleFragment>, Iterable<IrModuleFragment>>
|
||||||
|
}.reduce { acc, lowering -> acc.then(lowering) }
|
||||||
|
|
||||||
private fun makeJsModulePhase(
|
private fun makeJsModulePhase(
|
||||||
lowering: (JsIrBackendContext) -> FileLoweringPass,
|
lowering: (JsIrBackendContext) -> FileLoweringPass,
|
||||||
name: String,
|
name: String,
|
||||||
@@ -683,19 +689,6 @@ private val typeOperatorLoweringPhase = makeBodyLoweringPhase(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val es6AddInternalParametersToConstructorPhase = makeBodyLoweringPhase(
|
|
||||||
::ES6AddInternalParametersToConstructorPhase,
|
|
||||||
name = "ES6CreateInitFunctionPhase",
|
|
||||||
description = "Add `box` and `resultType` params, create init functions for constructors"
|
|
||||||
)
|
|
||||||
|
|
||||||
private val es6ConstructorLowering = makeBodyLoweringPhase(
|
|
||||||
::ES6ConstructorLowering,
|
|
||||||
name = "ES6ConstructorLoweringPhase",
|
|
||||||
description = "Lower constructors",
|
|
||||||
prerequisite = setOf(es6AddInternalParametersToConstructorPhase)
|
|
||||||
)
|
|
||||||
|
|
||||||
private val secondaryConstructorLoweringPhase = makeDeclarationTransformerPhase(
|
private val secondaryConstructorLoweringPhase = makeDeclarationTransformerPhase(
|
||||||
::SecondaryConstructorLowering,
|
::SecondaryConstructorLowering,
|
||||||
name = "SecondaryConstructorLoweringPhase",
|
name = "SecondaryConstructorLoweringPhase",
|
||||||
@@ -791,10 +784,31 @@ private val invokeStaticInitializersPhase = makeBodyLoweringPhase(
|
|||||||
prerequisite = setOf(objectDeclarationLoweringPhase)
|
prerequisite = setOf(objectDeclarationLoweringPhase)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val es6AddBoxParameterToConstructorsLowering = makeDeclarationTransformerPhase(
|
||||||
|
::ES6AddBoxParameterToConstructorsLowering,
|
||||||
|
name = "ES6AddBoxParameterToConstructorsLowering",
|
||||||
|
description = "Add box parameter to a constructor if needed",
|
||||||
|
)
|
||||||
|
|
||||||
|
private val es6ConstructorLowering = makeDeclarationTransformerPhase(
|
||||||
|
::ES6ConstructorLowering,
|
||||||
|
name = "ES6ConstructorLowering",
|
||||||
|
description = "Lower constructors declarations to support ES classes",
|
||||||
|
prerequisite = setOf(es6AddBoxParameterToConstructorsLowering)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val es6ConstructorUsageLowering = makeBodyLoweringPhase(
|
||||||
|
::ES6ConstructorCallLowering,
|
||||||
|
name = "ES6ConstructorCallLowering",
|
||||||
|
description = "Lower constructor usages to support ES classes",
|
||||||
|
prerequisite = setOf(es6ConstructorLowering)
|
||||||
|
)
|
||||||
|
|
||||||
private val objectUsageLoweringPhase = makeBodyLoweringPhase(
|
private val objectUsageLoweringPhase = makeBodyLoweringPhase(
|
||||||
::ObjectUsageLowering,
|
::ObjectUsageLowering,
|
||||||
name = "ObjectUsageLowering",
|
name = "ObjectUsageLowering",
|
||||||
description = "Transform IrGetObjectValue into instance generator call"
|
description = "Transform IrGetObjectValue into instance generator call",
|
||||||
|
prerequisite = setOf(primaryConstructorLoweringPhase)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val escapedIdentifiersLowering = makeBodyLoweringPhase(
|
private val escapedIdentifiersLowering = makeBodyLoweringPhase(
|
||||||
@@ -809,7 +823,6 @@ private val implicitlyExportedDeclarationsMarkingLowering = makeDeclarationTrans
|
|||||||
description = "Add @JsImplicitExport annotation to declarations which are not exported but are used inside other exported declarations as a type"
|
description = "Add @JsImplicitExport annotation to declarations which are not exported but are used inside other exported declarations as a type"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
private val cleanupLoweringPhase = makeBodyLoweringPhase(
|
private val cleanupLoweringPhase = makeBodyLoweringPhase(
|
||||||
{ CleanupLowering() },
|
{ CleanupLowering() },
|
||||||
name = "CleanupLowering",
|
name = "CleanupLowering",
|
||||||
@@ -912,8 +925,6 @@ val loweringList = listOf<Lowering>(
|
|||||||
defaultParameterCleanerPhase,
|
defaultParameterCleanerPhase,
|
||||||
captureStackTraceInThrowablesPhase,
|
captureStackTraceInThrowablesPhase,
|
||||||
throwableSuccessorsLoweringPhase,
|
throwableSuccessorsLoweringPhase,
|
||||||
es6AddInternalParametersToConstructorPhase,
|
|
||||||
es6ConstructorLowering,
|
|
||||||
varargLoweringPhase,
|
varargLoweringPhase,
|
||||||
multipleCatchesLoweringPhase,
|
multipleCatchesLoweringPhase,
|
||||||
errorExpressionLoweringPhase,
|
errorExpressionLoweringPhase,
|
||||||
@@ -927,10 +938,13 @@ val loweringList = listOf<Lowering>(
|
|||||||
inlineClassDeclarationLoweringPhase,
|
inlineClassDeclarationLoweringPhase,
|
||||||
inlineClassUsageLoweringPhase,
|
inlineClassUsageLoweringPhase,
|
||||||
autoboxingTransformerPhase,
|
autoboxingTransformerPhase,
|
||||||
blockDecomposerLoweringPhase,
|
|
||||||
objectDeclarationLoweringPhase,
|
objectDeclarationLoweringPhase,
|
||||||
|
blockDecomposerLoweringPhase,
|
||||||
invokeStaticInitializersPhase,
|
invokeStaticInitializersPhase,
|
||||||
objectUsageLoweringPhase,
|
objectUsageLoweringPhase,
|
||||||
|
es6AddBoxParameterToConstructorsLowering,
|
||||||
|
es6ConstructorLowering,
|
||||||
|
es6ConstructorUsageLowering,
|
||||||
callsLoweringPhase,
|
callsLoweringPhase,
|
||||||
escapedIdentifiersLowering,
|
escapedIdentifiersLowering,
|
||||||
implicitlyExportedDeclarationsMarkingLowering,
|
implicitlyExportedDeclarationsMarkingLowering,
|
||||||
@@ -947,10 +961,56 @@ val pirLowerings = loweringList.filter { it is DeclarationLowering || it is Body
|
|||||||
val jsPhases = SameTypeNamedCompilerPhase(
|
val jsPhases = SameTypeNamedCompilerPhase(
|
||||||
name = "IrModuleLowering",
|
name = "IrModuleLowering",
|
||||||
description = "IR module lowering",
|
description = "IR module lowering",
|
||||||
lower = loweringList.map {
|
lower = loweringList.toCompilerPhase(),
|
||||||
@Suppress("USELESS_CAST")
|
actions = setOf(defaultDumper.toMultiModuleAction(), validationAction.toMultiModuleAction()),
|
||||||
it.modulePhase as CompilerPhase<JsIrBackendContext, Iterable<IrModuleFragment>, Iterable<IrModuleFragment>>
|
nlevels = 1
|
||||||
}.reduce { acc, lowering -> acc.then(lowering) },
|
)
|
||||||
|
|
||||||
|
private val es6CollectConstructorsWhichNeedBoxParameterLowering = makeDeclarationTransformerPhase(
|
||||||
|
::ES6CollectConstructorsWhichNeedBoxParameters,
|
||||||
|
name = "ES6CollectConstructorsWhichNeedBoxParameters",
|
||||||
|
description = "[Optimization] Collect all of the constructors which requires box parameter",
|
||||||
|
)
|
||||||
|
|
||||||
|
private val es6BoxParameterOptimization = makeBodyLoweringPhase(
|
||||||
|
::ES6ConstructorBoxParameterOptimizationLowering,
|
||||||
|
name = "ES6ConstructorBoxParameterOptimizationLowering",
|
||||||
|
description = "[Optimization] Remove box parameter from the constructors which don't require box parameter",
|
||||||
|
prerequisite = setOf(es6CollectConstructorsWhichNeedBoxParameterLowering)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val es6CollectPrimaryConstructorsWhichCouldBeOptimizedLowering = makeDeclarationTransformerPhase(
|
||||||
|
::ES6CollectPrimaryConstructorsWhichCouldBeOptimizedLowering,
|
||||||
|
name = "ES6CollectPrimaryConstructorsWhichCouldBeOptimizedLowering",
|
||||||
|
description = "[Optimization] Collect all of the constructors which could be translated into a regular constructor",
|
||||||
|
)
|
||||||
|
|
||||||
|
private val es6PrimaryConstructorOptimizationLowering = makeDeclarationTransformerPhase(
|
||||||
|
::ES6PrimaryConstructorOptimizationLowering,
|
||||||
|
name = "ES6PrimaryConstructorOptimizationLowering",
|
||||||
|
description = "[Optimization] Replace synthetically generated static fabric method with a plain old ES6 constructors whenever it's possible",
|
||||||
|
prerequisite = setOf(es6CollectPrimaryConstructorsWhichCouldBeOptimizedLowering)
|
||||||
|
)
|
||||||
|
|
||||||
|
private val es6PrimaryConstructorUsageOptimizationLowering = makeBodyLoweringPhase(
|
||||||
|
::ES6PrimaryConstructorUsageOptimizationLowering,
|
||||||
|
name = "ES6PrimaryConstructorUsageOptimizationLowering",
|
||||||
|
description = "[Optimization] Replace usage of synthetically generated static fabric method with a plain old ES6 constructors whenever it's possible",
|
||||||
|
prerequisite = setOf(es6BoxParameterOptimization, es6PrimaryConstructorOptimizationLowering)
|
||||||
|
)
|
||||||
|
|
||||||
|
val optimizationLoweringList = listOf<Lowering>(
|
||||||
|
es6CollectConstructorsWhichNeedBoxParameterLowering,
|
||||||
|
es6CollectPrimaryConstructorsWhichCouldBeOptimizedLowering,
|
||||||
|
es6BoxParameterOptimization,
|
||||||
|
es6PrimaryConstructorOptimizationLowering,
|
||||||
|
es6PrimaryConstructorUsageOptimizationLowering,
|
||||||
|
)
|
||||||
|
|
||||||
|
val jsOptimizationPhases = SameTypeNamedCompilerPhase(
|
||||||
|
name = "IrModuleOptimizationLowering",
|
||||||
|
description = "IR module optimization lowering",
|
||||||
|
lower = optimizationLoweringList.toCompilerPhase(),
|
||||||
actions = setOf(defaultDumper.toMultiModuleAction(), validationAction.toMultiModuleAction()),
|
actions = setOf(defaultDumper.toMultiModuleAction(), validationAction.toMultiModuleAction()),
|
||||||
nlevels = 1
|
nlevels = 1
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,9 +7,13 @@ package org.jetbrains.kotlin.ir.backend.js
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.DefaultDelegateFactory
|
import org.jetbrains.kotlin.backend.common.DefaultDelegateFactory
|
||||||
import org.jetbrains.kotlin.backend.common.DefaultMapping
|
import org.jetbrains.kotlin.backend.common.DefaultMapping
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.MutableReference
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
|
||||||
class JsMapping : DefaultMapping() {
|
class JsMapping : DefaultMapping() {
|
||||||
|
val esClassWhichNeedBoxParameters = mutableSetOf<IrClass>()
|
||||||
|
val esClassToPossibilityForOptimization = mutableMapOf<IrClass, MutableReference<Boolean>>()
|
||||||
|
|
||||||
val outerThisFieldSymbols = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrField>()
|
val outerThisFieldSymbols = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrField>()
|
||||||
val innerClassConstructors = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrConstructor, IrConstructor>()
|
val innerClassConstructors = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrConstructor, IrConstructor>()
|
||||||
val originalInnerClassPrimaryConstructorByClass = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrConstructor>()
|
val originalInnerClassPrimaryConstructorByClass = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrConstructor>()
|
||||||
@@ -20,8 +24,6 @@ class JsMapping : DefaultMapping() {
|
|||||||
val classToSyntheticPrimaryConstructor = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrConstructor>()
|
val classToSyntheticPrimaryConstructor = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrConstructor>()
|
||||||
val privateMemberToCorrespondingStatic = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrFunction, IrSimpleFunction>()
|
val privateMemberToCorrespondingStatic = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrFunction, IrSimpleFunction>()
|
||||||
|
|
||||||
val constructorToInitFunction = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrConstructor, IrSimpleFunction>()
|
|
||||||
|
|
||||||
val enumEntryToGetInstanceFun = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrEnumEntry, IrSimpleFunction>()
|
val enumEntryToGetInstanceFun = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrEnumEntry, IrSimpleFunction>()
|
||||||
val enumEntryToInstanceField = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrEnumEntry, IrField>()
|
val enumEntryToInstanceField = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrEnumEntry, IrField>()
|
||||||
val enumConstructorToNewConstructor = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrConstructor, IrConstructor>()
|
val enumConstructorToNewConstructor = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrConstructor, IrConstructor>()
|
||||||
|
|||||||
+73
-44
@@ -9,26 +9,35 @@ import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.isBuiltInClass
|
import org.jetbrains.kotlin.ir.backend.js.lower.isBuiltInClass
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.isEs6ConstructorReplacement
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
|
|
||||||
internal class JsUsefulDeclarationProcessor(
|
internal class JsUsefulDeclarationProcessor(
|
||||||
override val context: JsIrBackendContext,
|
override val context: JsIrBackendContext,
|
||||||
printReachabilityInfo: Boolean,
|
printReachabilityInfo: Boolean,
|
||||||
removeUnusedAssociatedObjects: Boolean
|
removeUnusedAssociatedObjects: Boolean
|
||||||
) : UsefulDeclarationProcessor(printReachabilityInfo, removeUnusedAssociatedObjects) {
|
) : UsefulDeclarationProcessor(printReachabilityInfo, removeUnusedAssociatedObjects) {
|
||||||
|
|
||||||
private val equalsMethod = getMethodOfAny("equals")
|
private val equalsMethod = getMethodOfAny("equals")
|
||||||
private val hashCodeMethod = getMethodOfAny("hashCode")
|
private val hashCodeMethod = getMethodOfAny("hashCode")
|
||||||
|
private val isEsModules = context.configuration[JSConfigurationKeys.MODULE_KIND] == ModuleKind.ES
|
||||||
|
|
||||||
override val bodyVisitor: BodyVisitorBase = object : BodyVisitorBase() {
|
override val bodyVisitor: BodyVisitorBase = object : BodyVisitorBase() {
|
||||||
override fun visitCall(expression: IrCall, data: IrDeclaration) {
|
override fun visitCall(expression: IrCall, data: IrDeclaration) {
|
||||||
super.visitCall(expression, data)
|
super.visitCall(expression, data)
|
||||||
|
|
||||||
|
if (expression.usePrototype(data)) {
|
||||||
|
context.intrinsics.jsPrototypeOfSymbol.owner.enqueue(expression.symbol.owner, "access to super type")
|
||||||
|
}
|
||||||
|
|
||||||
when (expression.symbol) {
|
when (expression.symbol) {
|
||||||
context.intrinsics.jsBoxIntrinsic -> {
|
context.intrinsics.jsBoxIntrinsic -> {
|
||||||
val inlineClass = context.inlineClassesUtils.getInlinedClass(expression.getTypeArgument(0)!!)!!
|
val inlineClass = context.inlineClassesUtils.getInlinedClass(expression.getTypeArgument(0)!!)!!
|
||||||
@@ -68,6 +77,21 @@ internal class JsUsefulDeclarationProcessor(
|
|||||||
constructedClasses += classToCreate
|
constructedClasses += classToCreate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.intrinsics.jsCreateThisSymbol -> {
|
||||||
|
val jsClassOrThis = expression.getValueArgument(0)
|
||||||
|
|
||||||
|
val classTypeToCreate = when (jsClassOrThis) {
|
||||||
|
is IrCall -> jsClassOrThis.getTypeArgument(0)!!
|
||||||
|
is IrGetValue -> jsClassOrThis.type
|
||||||
|
else -> error("Unexpected first argument of createThis function call")
|
||||||
|
}
|
||||||
|
|
||||||
|
val classToCreate = classTypeToCreate.classifierOrFail.owner as IrClass
|
||||||
|
|
||||||
|
classToCreate.enqueue(data, "intrinsic: jsCreateThis")
|
||||||
|
constructedClasses += classToCreate
|
||||||
|
}
|
||||||
|
|
||||||
context.intrinsics.jsEquals -> {
|
context.intrinsics.jsEquals -> {
|
||||||
equalsMethod.enqueue(data, "intrinsic: jsEquals")
|
equalsMethod.enqueue(data, "intrinsic: jsEquals")
|
||||||
}
|
}
|
||||||
@@ -86,26 +110,6 @@ internal class JsUsefulDeclarationProcessor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.intrinsics.jsConstruct -> {
|
|
||||||
val callType = expression.getTypeArgument(0)!!
|
|
||||||
val constructor = callType.getClass()!!.primaryConstructor
|
|
||||||
constructor!!.enqueue(data, "ctor call from jsConstruct-intrinsic")
|
|
||||||
}
|
|
||||||
|
|
||||||
context.intrinsics.es6DefaultType -> {
|
|
||||||
//same as jsClass
|
|
||||||
val ref = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrDeclaration
|
|
||||||
ref.enqueue(data, "intrinsic: jsClass")
|
|
||||||
referencedJsClasses += ref
|
|
||||||
|
|
||||||
//Generate klass in `val currResultType = resultType || klass`
|
|
||||||
val arg = expression.getTypeArgument(0)!!
|
|
||||||
val klass = arg.getClass()
|
|
||||||
if (klass != null) {
|
|
||||||
constructedClasses.add(klass)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.intrinsics.jsInvokeSuspendSuperType,
|
context.intrinsics.jsInvokeSuspendSuperType,
|
||||||
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiver,
|
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiver,
|
||||||
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiverAndParam -> {
|
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiverAndParam -> {
|
||||||
@@ -137,48 +141,57 @@ internal class JsUsefulDeclarationProcessor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (irClass.containsMetadata()) {
|
if (!irClass.containsMetadata()) return
|
||||||
when {
|
|
||||||
irClass.isObject -> context.intrinsics.metadataObjectConstructorSymbol.owner.enqueue(irClass, "object metadata")
|
|
||||||
|
|
||||||
irClass.isInterface -> {
|
when {
|
||||||
context.intrinsics.implementSymbol.owner.enqueue(irClass, "interface metadata")
|
irClass.isObject -> context.intrinsics.metadataObjectConstructorSymbol.owner.enqueue(irClass, "object metadata")
|
||||||
context.intrinsics.metadataInterfaceConstructorSymbol.owner.enqueue(irClass, "interface metadata")
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
irClass.isInterface -> {
|
||||||
context.intrinsics.metadataClassConstructorSymbol.owner.enqueue(irClass, "class metadata")
|
context.intrinsics.implementSymbol.owner.enqueue(irClass, "interface metadata")
|
||||||
}
|
context.intrinsics.metadataInterfaceConstructorSymbol.owner.enqueue(irClass, "interface metadata")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else -> context.intrinsics.metadataClassConstructorSymbol.owner.enqueue(irClass, "class metadata")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!irClass.isExpect && !irClass.isExternal && !irClass.defaultType.isAny()) {
|
context.intrinsics.setMetadataForSymbol.owner.enqueue(irClass, "metadata")
|
||||||
if (!irClass.isInterface) {
|
|
||||||
context.intrinsics.jsPrototypeOfSymbol.owner.enqueue(irClass, "class metadata")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (irClass.superTypes.any { !it.isInterface() }) {
|
if (irClass.containsInterfaceDefaultImplementation()) {
|
||||||
context.intrinsics.jsObjectCreateSymbol.owner.enqueue(irClass, "class metadata")
|
context.intrinsics.jsPrototypeOfSymbol.owner.enqueue(irClass, "interface default implementation")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (irClass.isInner || irClass.isObject) {
|
if ((!context.es6mode || !isEsModules) && (irClass.isInner || irClass.isObject)) {
|
||||||
context.intrinsics.jsDefinePropertySymbol.owner.enqueue(irClass, "class metadata")
|
context.intrinsics.jsDefinePropertySymbol.owner.enqueue(irClass, "object lazy initialization")
|
||||||
}
|
}
|
||||||
|
|
||||||
context.intrinsics.setMetadataForSymbol.owner.enqueue(irClass, "metadata")
|
if (context.es6mode) return
|
||||||
|
|
||||||
|
if (!irClass.isInterface) {
|
||||||
|
context.intrinsics.jsPrototypeOfSymbol.owner.enqueue(irClass, "class prototype access")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irClass.superTypes.any { !it.isInterface() }) {
|
||||||
|
context.intrinsics.jsObjectCreateSymbol.owner.enqueue(irClass, "class inheritance code")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun processSimpleFunction(irFunction: IrSimpleFunction) {
|
override fun processSimpleFunction(irFunction: IrSimpleFunction) {
|
||||||
super.processSimpleFunction(irFunction)
|
super.processSimpleFunction(irFunction)
|
||||||
|
|
||||||
|
if (irFunction.isEs6ConstructorReplacement) {
|
||||||
|
constructedClasses += irFunction.dispatchReceiverParameter?.type?.classOrNull?.owner!!
|
||||||
|
}
|
||||||
|
|
||||||
if (irFunction.isReal && irFunction.body != null) {
|
if (irFunction.isReal && irFunction.body != null) {
|
||||||
irFunction.parentClassOrNull?.takeIf { it.isInterface }?.enqueue(irFunction, "interface default method is used")
|
irFunction.parentClassOrNull?.takeIf { it.isInterface }?.enqueue(irFunction, "interface default method is used")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.es6mode && isEsModules) return
|
||||||
|
|
||||||
val property = irFunction.correspondingPropertySymbol?.owner ?: return
|
val property = irFunction.correspondingPropertySymbol?.owner ?: return
|
||||||
|
|
||||||
if (property.isExported(context) || property.isOverriddenExternal()) {
|
if (property.isExported(context) || property.getJsName() != null || property.isOverriddenExternal()) {
|
||||||
|
context.intrinsics.jsPrototypeOfSymbol.owner.enqueue(irFunction, "property for export")
|
||||||
context.intrinsics.jsDefinePropertySymbol.owner.enqueue(irFunction, "property for export")
|
context.intrinsics.jsDefinePropertySymbol.owner.enqueue(irFunction, "property for export")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,8 +238,24 @@ internal class JsUsefulDeclarationProcessor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isExported(declaration: IrDeclaration): Boolean = declaration.isExported(context)
|
override fun isExported(declaration: IrDeclaration): Boolean = declaration.isExported(context)
|
||||||
}
|
|
||||||
|
|
||||||
|
private fun IrCall.usePrototype(container: IrDeclaration?): Boolean {
|
||||||
|
if (superQualifierSymbol == null) return false
|
||||||
|
|
||||||
|
val currentFun = (container as? IrSimpleFunction)
|
||||||
|
val currentClass = currentFun?.parentClassOrNull
|
||||||
|
|
||||||
|
return !context.es6mode ||
|
||||||
|
currentFun?.dispatchReceiverParameter == null ||
|
||||||
|
currentClass != null && (currentClass.isInner || currentClass.isLocal)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrClass.containsInterfaceDefaultImplementation(): Boolean {
|
||||||
|
return superTypes.any { it.classOrNull?.owner?.isExternal == true } ||
|
||||||
|
isExported(context) ||
|
||||||
|
isInterface && declarations.any { it is IrFunction && it.body != null }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun Collection<IrClass>.filterDescendantsOf(bases: Collection<IrClass>): Collection<IrClass> {
|
private fun Collection<IrClass>.filterDescendantsOf(bases: Collection<IrClass>): Collection<IrClass> {
|
||||||
val visited = hashSetOf<IrClass>()
|
val visited = hashSetOf<IrClass>()
|
||||||
|
|||||||
-1
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.ir.backend.js.utils.isAssociatedObjectAnnotatedAnnot
|
|||||||
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.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
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.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
|||||||
+8
-6
@@ -13,8 +13,8 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
|||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_INIT_BOX_PARAMETER
|
import org.jetbrains.kotlin.ir.backend.js.lower.isBoxParameter
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_RESULT_TYPE_PARAMETER
|
import org.jetbrains.kotlin.ir.backend.js.lower.isEs6ConstructorReplacement
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
@@ -86,7 +86,7 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
|
|||||||
returnType = exportType(function.returnType),
|
returnType = exportType(function.returnType),
|
||||||
typeParameters = function.typeParameters.map(::exportTypeParameter),
|
typeParameters = function.typeParameters.map(::exportTypeParameter),
|
||||||
isMember = parent is IrClass,
|
isMember = parent is IrClass,
|
||||||
isStatic = function.isStaticMethodOfClass,
|
isStatic = function.isStaticMethod,
|
||||||
isAbstract = parent is IrClass && !parent.isInterface && function.modality == Modality.ABSTRACT,
|
isAbstract = parent is IrClass && !parent.isInterface && function.modality == Modality.ABSTRACT,
|
||||||
isProtected = function.visibility == DescriptorVisibilities.PROTECTED,
|
isProtected = function.visibility == DescriptorVisibilities.PROTECTED,
|
||||||
ir = function,
|
ir = function,
|
||||||
@@ -100,10 +100,9 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
|
|||||||
|
|
||||||
private fun exportConstructor(constructor: IrConstructor): ExportedDeclaration? {
|
private fun exportConstructor(constructor: IrConstructor): ExportedDeclaration? {
|
||||||
if (!constructor.isPrimary) return null
|
if (!constructor.isPrimary) return null
|
||||||
val allValueParameters = listOfNotNull(constructor.extensionReceiverParameter) +
|
val allValueParameters = listOfNotNull(constructor.extensionReceiverParameter) + constructor.valueParameters
|
||||||
constructor.valueParameters.filterNot { it.origin === ES6_RESULT_TYPE_PARAMETER || it.origin === ES6_INIT_BOX_PARAMETER }
|
|
||||||
return ExportedConstructor(
|
return ExportedConstructor(
|
||||||
parameters = allValueParameters.map { exportParameter(it) },
|
parameters = allValueParameters.filterNot { it.isBoxParameter }.map { exportParameter(it) },
|
||||||
visibility = constructor.visibility.toExportedVisibility()
|
visibility = constructor.visibility.toExportedVisibility()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -696,6 +695,9 @@ private class ExportedClassDeclarationsInfo(
|
|||||||
private val IrClassifierSymbol.isInterface
|
private val IrClassifierSymbol.isInterface
|
||||||
get() = (owner as? IrClass)?.isInterface == true
|
get() = (owner as? IrClass)?.isInterface == true
|
||||||
|
|
||||||
|
private val IrFunction.isStaticMethod: Boolean
|
||||||
|
get() = isEs6ConstructorReplacement || isStaticMethodOfClass
|
||||||
|
|
||||||
private fun getExportCandidate(declaration: IrDeclaration): IrDeclarationWithName? {
|
private fun getExportCandidate(declaration: IrDeclaration): IrDeclarationWithName? {
|
||||||
// Only actual public declarations with name can be exported
|
// Only actual public declarations with name can be exported
|
||||||
if (declaration !is IrDeclarationWithVisibility ||
|
if (declaration !is IrDeclarationWithVisibility ||
|
||||||
|
|||||||
+139
-61
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.export
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.isEs6ConstructorReplacement
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsAstUtils
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsAstUtils
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.defineProperty
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.defineProperty
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.jsAssignment
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.jsAssignment
|
||||||
@@ -15,13 +16,16 @@ import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.jsElementAccess
|
|||||||
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.emptyScope
|
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.util.companionObject
|
import org.jetbrains.kotlin.ir.util.companionObject
|
||||||
|
import org.jetbrains.kotlin.ir.util.isObject
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
|
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
|
||||||
|
|
||||||
class ExportModelToJsStatements(
|
class ExportModelToJsStatements(
|
||||||
private val namer: JsStaticContext,
|
private val staticContext: JsStaticContext,
|
||||||
private val declareNewNamespace: (String) -> String
|
private val es6mode: Boolean,
|
||||||
|
private val declareNewNamespace: (String) -> String,
|
||||||
) {
|
) {
|
||||||
private val namespaceToRefMap = mutableMapOf<String, JsNameRef>()
|
private val namespaceToRefMap = mutableMapOf<String, JsNameRef>()
|
||||||
|
|
||||||
@@ -38,7 +42,8 @@ class ExportModelToJsStatements(
|
|||||||
fun generateDeclarationExport(
|
fun generateDeclarationExport(
|
||||||
declaration: ExportedDeclaration,
|
declaration: ExportedDeclaration,
|
||||||
namespace: JsExpression?,
|
namespace: JsExpression?,
|
||||||
esModules: Boolean
|
esModules: Boolean,
|
||||||
|
parentClass: IrClass? = null
|
||||||
): List<JsStatement> {
|
): List<JsStatement> {
|
||||||
return when (declaration) {
|
return when (declaration) {
|
||||||
is ExportedNamespace -> {
|
is ExportedNamespace -> {
|
||||||
@@ -73,7 +78,7 @@ class ExportModelToJsStatements(
|
|||||||
}
|
}
|
||||||
|
|
||||||
is ExportedFunction -> {
|
is ExportedFunction -> {
|
||||||
val name = namer.getNameForStaticDeclaration(declaration.ir)
|
val name = staticContext.getNameForStaticDeclaration(declaration.ir)
|
||||||
when {
|
when {
|
||||||
namespace != null ->
|
namespace != null ->
|
||||||
listOf(jsAssignment(jsElementAccess(declaration.name, namespace), JsNameRef(name)).makeStmt())
|
listOf(jsAssignment(jsElementAccess(declaration.name, namespace), JsNameRef(name)).makeStmt())
|
||||||
@@ -88,28 +93,29 @@ class ExportModelToJsStatements(
|
|||||||
|
|
||||||
is ExportedProperty -> {
|
is ExportedProperty -> {
|
||||||
require(namespace != null || esModules) { "Only namespaced properties are allowed" }
|
require(namespace != null || esModules) { "Only namespaced properties are allowed" }
|
||||||
val getter = declaration.irGetter?.let { namer.getNameForStaticDeclaration(it) }
|
when {
|
||||||
val setter = declaration.irSetter?.let { namer.getNameForStaticDeclaration(it) }
|
namespace == null -> {
|
||||||
if (namespace == null) {
|
val property = declaration.generateTopLevelGetters()
|
||||||
val property = JsVars.JsVar(
|
listOf(JsVars(property), JsExport(property.name, JsName(declaration.name, false)))
|
||||||
JsName(declaration.name, false),
|
}
|
||||||
JsObjectLiteral(false).apply {
|
es6mode && declaration.isMember -> {
|
||||||
getter?.let {
|
val jsClass = parentClass?.getCorrespondingJsClass() ?: error("Expect to have parentClass at this point")
|
||||||
val fieldName = when (declaration.irGetter.origin) {
|
jsClass.members += declaration.generateClassMembers()
|
||||||
JsLoweredDeclarationOrigin.OBJECT_GET_INSTANCE_FUNCTION -> "getInstance"
|
listOf(JsEmpty)
|
||||||
else -> "get"
|
}
|
||||||
}
|
else -> {
|
||||||
propertyInitializers += JsPropertyInitializer(JsStringLiteral(fieldName), it.makeRef())
|
val getter = declaration.irGetter?.let { staticContext.getNameForStaticDeclaration(it) }
|
||||||
}
|
val setter = declaration.irSetter?.let { staticContext.getNameForStaticDeclaration(it) }
|
||||||
setter?.let { propertyInitializers += JsPropertyInitializer(JsStringLiteral("set"), it.makeRef()) }
|
listOf(
|
||||||
}
|
defineProperty(
|
||||||
)
|
namespace,
|
||||||
listOf(
|
declaration.name,
|
||||||
JsVars(property),
|
getter?.makeRef(),
|
||||||
JsExport(property.name, JsName(declaration.name, false))
|
setter?.makeRef(),
|
||||||
)
|
staticContext
|
||||||
} else {
|
).makeStmt()
|
||||||
listOf(defineProperty(namespace, declaration.name, getter?.makeRef(), setter?.makeRef(), namer).makeStmt())
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,24 +126,31 @@ class ExportModelToJsStatements(
|
|||||||
val newNameSpace = when {
|
val newNameSpace = when {
|
||||||
namespace != null -> jsElementAccess(declaration.name, namespace)
|
namespace != null -> jsElementAccess(declaration.name, namespace)
|
||||||
else ->
|
else ->
|
||||||
jsElementAccess(Namer.PROTOTYPE_NAME, namer.getNameForClass(declaration.ir).makeRef())
|
jsElementAccess(Namer.PROTOTYPE_NAME, staticContext.getNameForClass(declaration.ir).makeRef())
|
||||||
}
|
}
|
||||||
val staticsExport = declaration.nestedClasses.flatMap { generateDeclarationExport(it, newNameSpace, esModules) }
|
val staticsExport =
|
||||||
|
declaration.nestedClasses.flatMap { generateDeclarationExport(it, newNameSpace, esModules, declaration.ir) }
|
||||||
|
|
||||||
val objectExport = when (namespace) {
|
val objectExport = when {
|
||||||
null -> generateDeclarationExport(
|
es6mode || namespace == null -> generateDeclarationExport(
|
||||||
ExportedProperty(declaration.name, ExportedType.Primitive.Any, irGetter = declaration.irGetter),
|
ExportedProperty(
|
||||||
|
declaration.name,
|
||||||
|
ExportedType.Primitive.Any,
|
||||||
|
isStatic = parentClass?.isObject != true,
|
||||||
|
irGetter = declaration.irGetter,
|
||||||
|
isMember = parentClass != null
|
||||||
|
),
|
||||||
namespace,
|
namespace,
|
||||||
esModules
|
esModules,
|
||||||
|
parentClass
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> listOf(
|
else -> listOf(
|
||||||
defineProperty(
|
defineProperty(
|
||||||
namespace,
|
namespace,
|
||||||
declaration.name,
|
declaration.name,
|
||||||
namer.getNameForStaticDeclaration(declaration.irGetter).makeRef(),
|
staticContext.getNameForStaticDeclaration(declaration.irGetter).makeRef(),
|
||||||
null,
|
null,
|
||||||
namer
|
staticContext
|
||||||
).makeStmt()
|
).makeStmt()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -147,11 +160,11 @@ class ExportModelToJsStatements(
|
|||||||
|
|
||||||
is ExportedRegularClass -> {
|
is ExportedRegularClass -> {
|
||||||
if (declaration.isInterface) return emptyList()
|
if (declaration.isInterface) return emptyList()
|
||||||
val name = namer.getNameForStaticDeclaration(declaration.ir)
|
val name = staticContext.getNameForStaticDeclaration(declaration.ir)
|
||||||
val newNameSpace = when {
|
val newNameSpace = when {
|
||||||
namespace != null -> jsElementAccess(declaration.name, namespace)
|
namespace != null -> jsElementAccess(declaration.name, namespace)
|
||||||
esModules -> name.makeRef()
|
esModules -> name.makeRef()
|
||||||
else -> prototypeOf(namer.getNameForClass(declaration.ir).makeRef(), namer)
|
else -> prototypeOf(staticContext.getNameForClass(declaration.ir).makeRef(), staticContext)
|
||||||
}
|
}
|
||||||
val klassExport = when {
|
val klassExport = when {
|
||||||
namespace != null -> jsAssignment(newNameSpace, JsNameRef(name)).makeStmt()
|
namespace != null -> jsAssignment(newNameSpace, JsNameRef(name)).makeStmt()
|
||||||
@@ -161,7 +174,7 @@ class ExportModelToJsStatements(
|
|||||||
|
|
||||||
// These are only used when exporting secondary constructors annotated with @JsName
|
// These are only used when exporting secondary constructors annotated with @JsName
|
||||||
val staticFunctions = declaration.members
|
val staticFunctions = declaration.members
|
||||||
.filter { it is ExportedFunction && it.isStatic }
|
.filter { it is ExportedFunction && it.isStatic && !it.ir.isEs6ConstructorReplacement }
|
||||||
.takeIf { !declaration.ir.isInner }.orEmpty()
|
.takeIf { !declaration.ir.isInner }.orEmpty()
|
||||||
|
|
||||||
val enumEntries = declaration.members.filter { it is ExportedProperty && it.isStatic }
|
val enumEntries = declaration.members.filter { it is ExportedProperty && it.isStatic }
|
||||||
@@ -171,22 +184,75 @@ class ExportModelToJsStatements(
|
|||||||
.map { it.generateInnerClassAssignment(declaration) }
|
.map { it.generateInnerClassAssignment(declaration) }
|
||||||
|
|
||||||
val staticsExport = (staticFunctions + enumEntries + declaration.nestedClasses)
|
val staticsExport = (staticFunctions + enumEntries + declaration.nestedClasses)
|
||||||
.flatMap { generateDeclarationExport(it, newNameSpace, esModules) }
|
.flatMap { generateDeclarationExport(it, newNameSpace, esModules, declaration.ir) }
|
||||||
|
|
||||||
listOfNotNull(klassExport) + staticsExport + innerClassesAssignments
|
listOfNotNull(klassExport) + staticsExport + innerClassesAssignments
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun ExportedProperty.generateTopLevelGetters(): JsVars.JsVar {
|
||||||
|
val getter = irGetter?.let { staticContext.getNameForStaticDeclaration(it) }
|
||||||
|
val setter = irSetter?.let { staticContext.getNameForStaticDeclaration(it) }
|
||||||
|
|
||||||
|
return JsVars.JsVar(
|
||||||
|
JsName(name, false),
|
||||||
|
JsObjectLiteral(false).apply {
|
||||||
|
getter?.let {
|
||||||
|
val fieldName = when (irGetter?.origin) {
|
||||||
|
JsLoweredDeclarationOrigin.OBJECT_GET_INSTANCE_FUNCTION -> "getInstance"
|
||||||
|
else -> "get"
|
||||||
|
}
|
||||||
|
propertyInitializers += JsPropertyInitializer(JsStringLiteral(fieldName), it.makeRef())
|
||||||
|
}
|
||||||
|
setter?.let { propertyInitializers += JsPropertyInitializer(JsStringLiteral("set"), it.makeRef()) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ExportedProperty.generateClassMembers(): List<JsFunction> {
|
||||||
|
val getter = irGetter?.let { staticContext.getNameForStaticDeclaration(it) }
|
||||||
|
val setter = irSetter?.let { staticContext.getNameForStaticDeclaration(it) }
|
||||||
|
|
||||||
|
return buildList {
|
||||||
|
if (getter != null) {
|
||||||
|
add(JsFunction(emptyScope, "").also {
|
||||||
|
it.name = JsName(name, false)
|
||||||
|
if (isStatic) {
|
||||||
|
it.modifiers.add(JsFunction.Modifier.STATIC)
|
||||||
|
}
|
||||||
|
it.modifiers.add(JsFunction.Modifier.GET)
|
||||||
|
it.body = JsBlock().apply {
|
||||||
|
statements.add(JsReturn(JsInvocation(getter.makeRef())))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (setter != null) {
|
||||||
|
add(JsFunction(emptyScope, "").also {
|
||||||
|
val value = JsName("value", true)
|
||||||
|
it.name = JsName(name, false)
|
||||||
|
it.parameters.add(JsParameter(value))
|
||||||
|
if (isStatic) {
|
||||||
|
it.modifiers.add(JsFunction.Modifier.STATIC)
|
||||||
|
}
|
||||||
|
it.modifiers.add(JsFunction.Modifier.SET)
|
||||||
|
it.body = JsBlock().apply {
|
||||||
|
statements.add(JsExpressionStatement(JsInvocation(setter.makeRef(), value.makeRef())))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun ExportedClass.generateInnerClassAssignment(outerClass: ExportedClass): JsStatement {
|
private fun ExportedClass.generateInnerClassAssignment(outerClass: ExportedClass): JsStatement {
|
||||||
val innerClassRef = namer.getNameForStaticDeclaration(ir).makeRef()
|
val innerClassRef = staticContext.getNameForStaticDeclaration(ir).makeRef()
|
||||||
val outerClassRef = namer.getNameForStaticDeclaration(outerClass.ir).makeRef()
|
val outerClassRef = staticContext.getNameForStaticDeclaration(outerClass.ir).makeRef()
|
||||||
val companionObject = ir.companionObject()
|
val companionObject = ir.companionObject()
|
||||||
val secondaryConstructors = members.filterIsInstanceAnd<ExportedFunction> { it.isStatic }
|
val secondaryConstructors = members.filterIsInstanceAnd<ExportedFunction> { it.isStatic }
|
||||||
val bindConstructor = JsName("__bind_constructor_", false)
|
val bindConstructor = JsName("__bind_constructor_", false)
|
||||||
|
|
||||||
val blockStatements = mutableListOf<JsStatement>(
|
val blockStatements = mutableListOf<JsStatement>(
|
||||||
JsVars(JsVars.JsVar(bindConstructor, innerClassRef.bindToThis()))
|
JsVars(JsVars.JsVar(bindConstructor, innerClassRef.bindToThis(innerClassRef)))
|
||||||
)
|
)
|
||||||
|
|
||||||
if (companionObject != null) {
|
if (companionObject != null) {
|
||||||
@@ -200,35 +266,47 @@ class ExportModelToJsStatements(
|
|||||||
}
|
}
|
||||||
|
|
||||||
secondaryConstructors.forEach {
|
secondaryConstructors.forEach {
|
||||||
val currentFunRef = namer.getNameForStaticDeclaration(it.ir).makeRef()
|
val currentFunRef = if (it.ir.isEs6ConstructorReplacement) {
|
||||||
|
JsNameRef(staticContext.getNameForMemberFunction(it.ir), innerClassRef)
|
||||||
|
} else {
|
||||||
|
staticContext.getNameForStaticDeclaration(it.ir).makeRef()
|
||||||
|
}
|
||||||
|
|
||||||
val assignment = jsAssignment(
|
val assignment = jsAssignment(
|
||||||
JsNameRef(it.name, bindConstructor.makeRef()),
|
JsNameRef(it.name, bindConstructor.makeRef()),
|
||||||
currentFunRef.bindToThis()
|
currentFunRef.bindToThis(innerClassRef)
|
||||||
).makeStmt()
|
).makeStmt()
|
||||||
|
|
||||||
blockStatements.add(assignment)
|
blockStatements.add(assignment)
|
||||||
}
|
}
|
||||||
|
|
||||||
blockStatements.add(JsReturn(bindConstructor.makeRef()))
|
blockStatements.add(JsReturn(bindConstructor.makeRef()))
|
||||||
|
val innerClassGetter = JsFunction(emptyScope, JsBlock(*blockStatements.toTypedArray()), "inner class '$name' getter")
|
||||||
|
|
||||||
return defineProperty(
|
return if (es6mode) {
|
||||||
prototypeOf(outerClassRef, namer),
|
outerClass.ir.getCorrespondingJsClass().members += innerClassGetter.also {
|
||||||
name,
|
it.name = JsName(name, false)
|
||||||
JsFunction(
|
it.modifiers.add(JsFunction.Modifier.GET)
|
||||||
emptyScope,
|
}
|
||||||
JsBlock(*blockStatements.toTypedArray()),
|
JsEmpty
|
||||||
"inner class '$name' getter"
|
} else {
|
||||||
),
|
defineProperty(
|
||||||
null,
|
prototypeOf(outerClassRef, staticContext),
|
||||||
namer
|
name,
|
||||||
).makeStmt()
|
innerClassGetter,
|
||||||
|
null,
|
||||||
|
staticContext
|
||||||
|
).makeStmt()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun JsNameRef.bindToThis(): JsInvocation {
|
private fun IrClass.getCorrespondingJsClass(): JsClass {
|
||||||
return JsInvocation(
|
val jsClassModel = staticContext.classModels[symbol] ?: error("Class with name '$name' was not found")
|
||||||
JsNameRef("bind", this),
|
return (jsClassModel.preDeclarationBlock.statements.first() as? JsExpressionStatement)?.expression as? JsClass
|
||||||
JsNullLiteral(),
|
?: error("Expect to have JsClass as a first statement inside JsIrClassModel")
|
||||||
JsThisRef()
|
}
|
||||||
)
|
|
||||||
|
private fun JsNameRef.bindToThis(bindTo: JsExpression): JsInvocation {
|
||||||
|
return JsInvocation(JsNameRef("bind", this), bindTo, JsThisRef())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.ir.declarations.*
|
|||||||
import org.jetbrains.kotlin.ir.symbols.*
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.isJsImplicitExport
|
import org.jetbrains.kotlin.ir.backend.js.utils.isJsImplicitExport
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.superTypes
|
import org.jetbrains.kotlin.ir.types.superTypes
|
||||||
|
|||||||
@@ -734,6 +734,7 @@ fun rebuildCacheForDirtyFiles(
|
|||||||
irFactory: IrFactory,
|
irFactory: IrFactory,
|
||||||
exportedDeclarations: Set<FqName>,
|
exportedDeclarations: Set<FqName>,
|
||||||
mainArguments: List<String>?,
|
mainArguments: List<String>?,
|
||||||
|
es6mode: Boolean
|
||||||
): Pair<IrModuleFragment, List<Pair<IrFile, JsIrProgramFragment>>> {
|
): Pair<IrModuleFragment, List<Pair<IrFile, JsIrProgramFragment>>> {
|
||||||
val emptyMetadata = object : KotlinSourceFileExports() {
|
val emptyMetadata = object : KotlinSourceFileExports() {
|
||||||
override val inverseDependencies = KotlinSourceFileMap<Set<IdSignature>>(emptyMap())
|
override val inverseDependencies = KotlinSourceFileMap<Set<IdSignature>>(emptyMap())
|
||||||
@@ -753,7 +754,13 @@ fun rebuildCacheForDirtyFiles(
|
|||||||
currentIrModule.files.filter { irFile -> irFile.fileEntry.name in files }
|
currentIrModule.files.filter { irFile -> irFile.fileEntry.name in files }
|
||||||
} ?: currentIrModule.files
|
} ?: currentIrModule.files
|
||||||
|
|
||||||
val compilerWithIC = JsIrCompilerWithIC(currentIrModule, configuration, JsGenerationGranularity.PER_MODULE, exportedDeclarations)
|
val compilerWithIC = JsIrCompilerWithIC(
|
||||||
|
currentIrModule,
|
||||||
|
configuration,
|
||||||
|
JsGenerationGranularity.PER_MODULE,
|
||||||
|
exportedDeclarations,
|
||||||
|
es6mode
|
||||||
|
)
|
||||||
|
|
||||||
// Load declarations referenced during `context` initialization
|
// Load declarations referenced during `context` initialization
|
||||||
jsIrLinker.loadUnboundSymbols()
|
jsIrLinker.loadUnboundSymbols()
|
||||||
|
|||||||
@@ -15,19 +15,19 @@ 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.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
object JsIrBuilder {
|
object JsIrBuilder {
|
||||||
|
|
||||||
|
|
||||||
object SYNTHESIZED_DECLARATION : IrDeclarationOriginImpl("SYNTHESIZED_DECLARATION")
|
object SYNTHESIZED_DECLARATION : IrDeclarationOriginImpl("SYNTHESIZED_DECLARATION")
|
||||||
|
|
||||||
fun buildCall(
|
fun buildCall(
|
||||||
target: IrSimpleFunctionSymbol,
|
target: IrSimpleFunctionSymbol,
|
||||||
type: IrType? = null,
|
type: IrType? = null,
|
||||||
typeArguments: List<IrType>? = null,
|
typeArguments: List<IrType>? = null,
|
||||||
origin: IrStatementOrigin = JsStatementOrigins.SYNTHESIZED_STATEMENT
|
origin: IrStatementOrigin = JsStatementOrigins.SYNTHESIZED_STATEMENT,
|
||||||
|
superQualifierSymbol: IrClassSymbol? = null,
|
||||||
): IrCall {
|
): IrCall {
|
||||||
val owner = target.owner
|
val owner = target.owner
|
||||||
return IrCallImpl(
|
return IrCallImpl(
|
||||||
@@ -35,6 +35,7 @@ object JsIrBuilder {
|
|||||||
UNDEFINED_OFFSET,
|
UNDEFINED_OFFSET,
|
||||||
type ?: owner.returnType,
|
type ?: owner.returnType,
|
||||||
target,
|
target,
|
||||||
|
superQualifierSymbol = superQualifierSymbol,
|
||||||
typeArgumentsCount = owner.typeParameters.size,
|
typeArgumentsCount = owner.typeParameters.size,
|
||||||
valueArgumentsCount = owner.valueParameters.size,
|
valueArgumentsCount = owner.valueParameters.size,
|
||||||
origin = origin
|
origin = origin
|
||||||
@@ -46,54 +47,95 @@ object JsIrBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildConstructorCall(
|
fun buildArray(elements: List<IrExpression>, type: IrType, elementType: IrType): IrExpression {
|
||||||
target: IrConstructorSymbol,
|
return IrVarargImpl(
|
||||||
type: IrType? = null,
|
UNDEFINED_OFFSET,
|
||||||
typeArguments: List<IrType>? = null,
|
UNDEFINED_OFFSET,
|
||||||
constructorTypeArguments: List<IrType>? = null,
|
type,
|
||||||
origin: IrStatementOrigin = JsStatementOrigins.SYNTHESIZED_STATEMENT
|
elementType,
|
||||||
): IrConstructorCall {
|
elements
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun buildDelegatingConstructorCall(target: IrConstructorSymbol, typeArguments: List<IrType?>? = null): IrDelegatingConstructorCall {
|
||||||
val owner = target.owner
|
val owner = target.owner
|
||||||
val parent = owner.parentAsClass
|
val irClass = owner.parentAsClass
|
||||||
return IrConstructorCallImpl(
|
|
||||||
|
return IrDelegatingConstructorCallImpl(
|
||||||
UNDEFINED_OFFSET,
|
UNDEFINED_OFFSET,
|
||||||
UNDEFINED_OFFSET,
|
UNDEFINED_OFFSET,
|
||||||
type ?: owner.returnType,
|
owner.returnType,
|
||||||
target,
|
target,
|
||||||
typeArgumentsCount = parent.typeParameters.size,
|
typeArgumentsCount = irClass.typeParameters.size,
|
||||||
valueArgumentsCount = owner.valueParameters.size,
|
valueArgumentsCount = owner.valueParameters.size,
|
||||||
constructorTypeArgumentsCount = owner.typeParameters.size,
|
|
||||||
origin = origin
|
|
||||||
).apply {
|
).apply {
|
||||||
typeArguments?.let {
|
typeArguments?.let {
|
||||||
assert(typeArguments.size == typeArgumentsCount)
|
assert(it.size == typeArgumentsCount)
|
||||||
it.withIndex().forEach { (i, t) -> putTypeArgument(i, t) }
|
|
||||||
}
|
|
||||||
constructorTypeArguments?.let {
|
|
||||||
assert(constructorTypeArguments.size == constructorTypeArgumentsCount)
|
|
||||||
it.withIndex().forEach { (i, t) -> putTypeArgument(i, t) }
|
it.withIndex().forEach { (i, t) -> putTypeArgument(i, t) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun buildConstructorCall(
|
||||||
|
target: IrConstructorSymbol,
|
||||||
|
typeArguments: List<IrType?>? = null,
|
||||||
|
constructorTypeArguments: List<IrType?>? = null,
|
||||||
|
origin: IrStatementOrigin = JsStatementOrigins.SYNTHESIZED_STATEMENT
|
||||||
|
): IrConstructorCall {
|
||||||
|
val owner = target.owner
|
||||||
|
val irClass = owner.parentAsClass
|
||||||
|
|
||||||
|
return IrConstructorCallImpl(
|
||||||
|
UNDEFINED_OFFSET,
|
||||||
|
UNDEFINED_OFFSET,
|
||||||
|
owner.returnType,
|
||||||
|
target,
|
||||||
|
typeArgumentsCount = irClass.typeParameters.size,
|
||||||
|
constructorTypeArgumentsCount = owner.typeParameters.size,
|
||||||
|
valueArgumentsCount = owner.valueParameters.size,
|
||||||
|
origin = origin
|
||||||
|
).apply {
|
||||||
|
typeArguments?.let {
|
||||||
|
assert(it.size == typeArgumentsCount)
|
||||||
|
it.withIndex().forEach { (i, t) -> putTypeArgument(i, t) }
|
||||||
|
}
|
||||||
|
|
||||||
|
constructorTypeArguments?.let {
|
||||||
|
assert(it.size == typeArgumentsCount)
|
||||||
|
it.withIndex().forEach { (i, t) -> putTypeArgument(i, t) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun buildRawReference(targetSymbol: IrFunctionSymbol, type: IrType): IrRawFunctionReference =
|
||||||
|
IrRawFunctionReferenceImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, targetSymbol)
|
||||||
|
|
||||||
fun buildReturn(targetSymbol: IrFunctionSymbol, value: IrExpression, type: IrType) =
|
fun buildReturn(targetSymbol: IrFunctionSymbol, value: IrExpression, type: IrType) =
|
||||||
IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, targetSymbol, value)
|
IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, targetSymbol, value)
|
||||||
|
|
||||||
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(parent: IrFunction, name: String, index: Int, type: IrType): IrValueParameter =
|
fun buildValueParameter(
|
||||||
|
parent: IrFunction,
|
||||||
|
name: String,
|
||||||
|
index: Int,
|
||||||
|
type: IrType,
|
||||||
|
isAssignable: Boolean = false,
|
||||||
|
origin: IrDeclarationOrigin = SYNTHESIZED_DECLARATION
|
||||||
|
): IrValueParameter =
|
||||||
buildValueParameter(parent) {
|
buildValueParameter(parent) {
|
||||||
this.origin = SYNTHESIZED_DECLARATION
|
this.origin = origin
|
||||||
this.name = Name.identifier(name)
|
this.name = Name.identifier(name)
|
||||||
this.index = index
|
this.index = index
|
||||||
this.type = type
|
this.type = type
|
||||||
|
this.isAssignable = isAssignable
|
||||||
}
|
}
|
||||||
|
|
||||||
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 buildGetValue(symbol: IrValueSymbol) =
|
fun buildGetValue(symbol: IrValueSymbol, origin: IrStatementOrigin = JsStatementOrigins.SYNTHESIZED_STATEMENT) =
|
||||||
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol.owner.type, symbol, JsStatementOrigins.SYNTHESIZED_STATEMENT)
|
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol.owner.type, symbol, origin)
|
||||||
|
|
||||||
fun buildSetValue(symbol: IrValueSymbol, value: IrExpression) =
|
fun buildSetValue(symbol: IrValueSymbol, value: IrExpression) =
|
||||||
IrSetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol.owner.type, symbol, value, JsStatementOrigins.SYNTHESIZED_STATEMENT)
|
IrSetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol.owner.type, symbol, value, JsStatementOrigins.SYNTHESIZED_STATEMENT)
|
||||||
|
|||||||
+8
-2
@@ -5,17 +5,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
|
||||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.util.constructors
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
|
|
||||||
class AnnotationConstructorLowering(context: CommonBackendContext) : DeclarationTransformer {
|
class AnnotationConstructorLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||||
|
|
||||||
private val unitType = context.irBuiltIns.unitType
|
private val unitType = context.irBuiltIns.unitType
|
||||||
|
private val anyConstructor = context.irBuiltIns.anyClass.constructors.first()
|
||||||
|
|
||||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
if (declaration !is IrConstructor || !declaration.isPrimary) return null
|
if (declaration !is IrConstructor || !declaration.isPrimary) return null
|
||||||
@@ -27,6 +30,9 @@ class AnnotationConstructorLowering(context: CommonBackendContext) : Declaration
|
|||||||
// put empty body to make sure proper initializer is generated
|
// put empty body to make sure proper initializer is generated
|
||||||
// TODO what about its previous body?
|
// TODO what about its previous body?
|
||||||
declaration.body = declaration.factory.createBlockBody(declaration.startOffset, declaration.endOffset) {
|
declaration.body = declaration.factory.createBlockBody(declaration.startOffset, declaration.endOffset) {
|
||||||
|
if (context.es6mode) {
|
||||||
|
statements += IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.anyType, anyConstructor, 0, 0)
|
||||||
|
}
|
||||||
statements += IrInstanceInitializerCallImpl(startOffset, endOffset, irClass.symbol, unitType)
|
statements += IrInstanceInitializerCallImpl(startOffset, endOffset, irClass.symbol, unitType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -36,9 +36,7 @@ class JsBlockDecomposerLowering(val context: JsIrBackendContext) : AbstractBlock
|
|||||||
JsIrBuilder.buildCall(context.intrinsics.unreachable, context.irBuiltIns.nothingType)
|
JsIrBuilder.buildCall(context.intrinsics.unreachable, context.irBuiltIns.nothingType)
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractBlockDecomposerLowering(
|
abstract class AbstractBlockDecomposerLowering(private val context: JsCommonBackendContext) : BodyLoweringPass {
|
||||||
private val context: JsCommonBackendContext
|
|
||||||
) : BodyLoweringPass {
|
|
||||||
|
|
||||||
private val nothingType = context.irBuiltIns.nothingType
|
private val nothingType = context.irBuiltIns.nothingType
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -179,7 +179,11 @@ class CallableReferenceLowering(private val context: CommonBackendContext) : Bod
|
|||||||
origin = if (isKReference || !isLambda) FUNCTION_REFERENCE_IMPL else LAMBDA_IMPL
|
origin = if (isKReference || !isLambda) FUNCTION_REFERENCE_IMPL else LAMBDA_IMPL
|
||||||
name = makeContextDependentName()
|
name = makeContextDependentName()
|
||||||
}.apply {
|
}.apply {
|
||||||
superTypes = listOfNotNull(superClass, referenceType, secondFunctionInterface?.symbol?.typeWithArguments(referenceType.arguments))
|
superTypes = listOfNotNull(
|
||||||
|
this@CallableReferenceBuilder.superClass,
|
||||||
|
referenceType,
|
||||||
|
secondFunctionInterface?.symbol?.typeWithArguments(referenceType.arguments)
|
||||||
|
)
|
||||||
// if (samSuperType == null)
|
// if (samSuperType == null)
|
||||||
// superTypes += functionSuperClass.typeWith(parameterTypes)
|
// superTypes += functionSuperClass.typeWith(parameterTypes)
|
||||||
// if (irFunctionReference.isSuspend) superTypes += context.ir.symbols.suspendFunctionInterface.defaultType
|
// if (irFunctionReference.isSuspend) superTypes += context.ir.symbols.suspendFunctionInterface.defaultType
|
||||||
|
|||||||
+34
-8
@@ -6,18 +6,23 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||||
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
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.declarations.IrConstructor
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
|
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrRawFunctionReferenceImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrRawFunctionReferenceImpl
|
||||||
import org.jetbrains.kotlin.ir.util.isSubclassOf
|
import org.jetbrains.kotlin.ir.util.isSubclassOf
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
object ES6_THROWABLE_CONSTRUCTOR_SLOT : IrDeclarationOriginImpl("ES6_THROWABLE_CONSTRUCTOR_SLOT")
|
||||||
/**
|
/**
|
||||||
* Capture stack trace in primary constructors of Throwable
|
* Capture stack trace in primary constructors of Throwable
|
||||||
*/
|
*/
|
||||||
@@ -31,15 +36,36 @@ class CaptureStackTraceInThrowables(val context: JsIrBackendContext) : BodyLower
|
|||||||
if (!klass.isSubclassOf(context.irBuiltIns.throwableClass.owner))
|
if (!klass.isSubclassOf(context.irBuiltIns.throwableClass.owner))
|
||||||
return
|
return
|
||||||
|
|
||||||
val statements = (irBody as IrBlockBody).statements
|
val statements = (irBody as? IrBlockBody)?.statements ?: return
|
||||||
val delegatingConstructorCallIndex = statements.indexOfLast { it is IrDelegatingConstructorCall }
|
val delegatingConstructorCallIndex = statements.indexOfLast { it is IrDelegatingConstructorCall }
|
||||||
|
|
||||||
statements.add(delegatingConstructorCallIndex + 1, JsIrBuilder.buildCall(context.intrinsics.captureStack).also { call ->
|
statements.add(delegatingConstructorCallIndex + 1, JsIrBuilder.buildCall(context.intrinsics.captureStack).also { call ->
|
||||||
call.putValueArgument(0, JsIrBuilder.buildGetValue(klass.thisReceiver!!.symbol))
|
val self = klass.thisReceiver!!.symbol
|
||||||
call.putValueArgument(
|
|
||||||
1,
|
val constructorRef = if (context.es6mode) {
|
||||||
IrRawFunctionReferenceImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.anyType, container.symbol)
|
JsIrBuilder.buildGetField(klass.addThrowableConstructorSlot().symbol, JsIrBuilder.buildGetValue(self))
|
||||||
)
|
} else {
|
||||||
|
JsIrBuilder.buildRawReference(container.symbol, context.irBuiltIns.anyType)
|
||||||
|
}
|
||||||
|
|
||||||
|
call.putValueArgument(0, JsIrBuilder.buildGetValue(self))
|
||||||
|
call.putValueArgument(1, constructorRef)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrClass.addThrowableConstructorSlot(): IrField {
|
||||||
|
return factory.buildField {
|
||||||
|
type = context.dynamicType
|
||||||
|
isFinal = false
|
||||||
|
isExternal = false
|
||||||
|
isStatic = false
|
||||||
|
metadata = null
|
||||||
|
name = Name.identifier(Namer.THROWABLE_CONSTRUCTOR)
|
||||||
|
visibility = DescriptorVisibilities.PRIVATE
|
||||||
|
origin = ES6_THROWABLE_CONSTRUCTOR_SLOT
|
||||||
|
}.apply {
|
||||||
|
parent = this@addThrowableConstructorSlot
|
||||||
|
declarations.add(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -8,14 +8,20 @@ package org.jetbrains.kotlin.ir.backend.js.lower
|
|||||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.compilationException
|
import org.jetbrains.kotlin.backend.common.compilationException
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.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.types.classifierOrNull
|
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||||
import org.jetbrains.kotlin.ir.types.defaultType
|
import org.jetbrains.kotlin.ir.types.defaultType
|
||||||
@@ -33,7 +39,13 @@ class ConstTransformer(private val context: JsIrBackendContext) : IrElementTrans
|
|||||||
): IrExpression {
|
): IrExpression {
|
||||||
val constructor = irClass.constructors.single { it.owner.isPrimary }
|
val constructor = irClass.constructors.single { it.owner.isPrimary }
|
||||||
val argType = constructor.owner.valueParameters.first().type
|
val argType = constructor.owner.valueParameters.first().type
|
||||||
return IrConstructorCallImpl.fromSymbolOwner(expression.startOffset, expression.endOffset, irClass.defaultType, constructor).apply {
|
|
||||||
|
return IrConstructorCallImpl.fromSymbolOwner(
|
||||||
|
expression.startOffset,
|
||||||
|
expression.endOffset,
|
||||||
|
irClass.defaultType,
|
||||||
|
constructor
|
||||||
|
).apply {
|
||||||
for (i in args.indices) {
|
for (i in args.indices) {
|
||||||
putValueArgument(i, carrierFactory(startOffset, endOffset, argType, args[i]))
|
putValueArgument(i, carrierFactory(startOffset, endOffset, argType, args[i]))
|
||||||
}
|
}
|
||||||
|
|||||||
+182
@@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.ValueRemapper
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||||
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.hasStrictSignature
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
|
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
|
||||||
|
object ES6_BOX_PARAMETER : IrDeclarationOriginImpl("ES6_BOX_PARAMETER")
|
||||||
|
object ES6_BOX_PARAMETER_DEFAULT_RESOLUTION : IrStatementOriginImpl("ES6_BOX_PARAMETER_DEFAULT_RESOLUTION")
|
||||||
|
|
||||||
|
val IrValueParameter.isBoxParameter: Boolean
|
||||||
|
get() = origin == ES6_BOX_PARAMETER
|
||||||
|
|
||||||
|
val IrWhen.isBoxParameterDefaultResolution: Boolean
|
||||||
|
get() = origin == ES6_BOX_PARAMETER_DEFAULT_RESOLUTION
|
||||||
|
|
||||||
|
val IrFunction.boxParameter: IrValueParameter?
|
||||||
|
get() = valueParameters.lastOrNull()?.takeIf { it.isBoxParameter }
|
||||||
|
|
||||||
|
class ES6AddBoxParameterToConstructorsLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||||
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
|
if (!context.es6mode || declaration !is IrConstructor || declaration.hasStrictSignature(context)) return null
|
||||||
|
|
||||||
|
hackEnums(declaration)
|
||||||
|
hackExceptions(declaration)
|
||||||
|
hackSimpleClassWithCapturing(declaration)
|
||||||
|
|
||||||
|
if (!declaration.isSyntheticPrimaryConstructor) {
|
||||||
|
declaration.addBoxParameter()
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrConstructor.addBoxParameter() {
|
||||||
|
val irClass = parentAsClass
|
||||||
|
val boxParameter = generateBoxParameter(irClass).also { valueParameters += it }
|
||||||
|
|
||||||
|
val body = body as? IrBlockBody ?: return
|
||||||
|
val isBoxUsed = body.replaceThisWithBoxBeforeSuperCall(irClass, boxParameter.symbol)
|
||||||
|
|
||||||
|
if (isBoxUsed) {
|
||||||
|
body.statements.add(0, boxParameter.generateDefaultResolution())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createJsObjectLiteral(): IrExpression {
|
||||||
|
return JsIrBuilder.buildCall(context.intrinsics.jsEmptyObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrConstructor.generateBoxParameter(irClass: IrClass): IrValueParameter {
|
||||||
|
return JsIrBuilder.buildValueParameter(
|
||||||
|
parent = this,
|
||||||
|
name = Namer.ES6_BOX_PARAMETER_NAME,
|
||||||
|
index = valueParameters.size,
|
||||||
|
type = irClass.defaultType.makeNullable(),
|
||||||
|
origin = ES6_BOX_PARAMETER,
|
||||||
|
isAssignable = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrValueParameter.generateDefaultResolution(): IrExpression {
|
||||||
|
return with(context.createIrBuilder(symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET)) {
|
||||||
|
irIfThen(
|
||||||
|
context.irBuiltIns.unitType,
|
||||||
|
irEqeqeqWithoutBox(irGet(type, symbol), this@ES6AddBoxParameterToConstructorsLowering.context.getVoid()),
|
||||||
|
irSet(symbol, createJsObjectLiteral()),
|
||||||
|
ES6_BOX_PARAMETER_DEFAULT_RESOLUTION
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrBody.replaceThisWithBoxBeforeSuperCall(irClass: IrClass, boxParameterSymbol: IrValueSymbol): Boolean {
|
||||||
|
var meetCapturing = false
|
||||||
|
var meetDelegatingConstructor = false
|
||||||
|
val selfParameterSymbol = irClass.thisReceiver!!.symbol
|
||||||
|
|
||||||
|
transformChildrenVoid(object : ValueRemapper(mapOf(selfParameterSymbol to boxParameterSymbol)) {
|
||||||
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
|
return if (meetDelegatingConstructor) {
|
||||||
|
expression
|
||||||
|
} else {
|
||||||
|
super.visitGetValue(expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSetField(expression: IrSetField): IrExpression {
|
||||||
|
if (meetDelegatingConstructor) return expression
|
||||||
|
val newExpression = super.visitSetField(expression)
|
||||||
|
val receiver = expression.receiver as? IrGetValue
|
||||||
|
|
||||||
|
if (receiver?.symbol == boxParameterSymbol) {
|
||||||
|
meetCapturing = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return newExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||||
|
meetDelegatingConstructor = true
|
||||||
|
return super.visitDelegatingConstructorCall(expression)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return meetCapturing
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hackEnums(constructor: IrConstructor) {
|
||||||
|
constructor.transformChildren(object : IrElementTransformerVoid() {
|
||||||
|
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
|
||||||
|
return (expression.argument as? IrDelegatingConstructorCall) ?: expression
|
||||||
|
}
|
||||||
|
}, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hackSimpleClassWithCapturing(constructor: IrConstructor) {
|
||||||
|
val irClass = constructor.parentAsClass
|
||||||
|
|
||||||
|
if (irClass.superClass != null || (!irClass.isInner && !irClass.isLocal)) return
|
||||||
|
|
||||||
|
val statements = (constructor.body as? IrBlockBody)?.statements ?: return
|
||||||
|
val delegationConstructorIndex = statements.indexOfFirst { it is IrDelegatingConstructorCall }
|
||||||
|
|
||||||
|
if (delegationConstructorIndex == -1) return
|
||||||
|
|
||||||
|
val firstClassFieldAssignment = statements.indexOfFirst { statement ->
|
||||||
|
statement is IrSetField && statement.receiver?.let { it is IrGetValue && it.symbol == irClass.thisReceiver?.symbol } == true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstClassFieldAssignment == -1 || firstClassFieldAssignment > delegationConstructorIndex) return
|
||||||
|
|
||||||
|
statements.add(firstClassFieldAssignment, statements[delegationConstructorIndex])
|
||||||
|
statements.removeAt(delegationConstructorIndex + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap call synthetic primary ctor and call extendThrowable
|
||||||
|
*/
|
||||||
|
private fun hackExceptions(constructor: IrConstructor) {
|
||||||
|
val setPropertiesSymbol = context.setPropertiesToThrowableInstanceSymbol
|
||||||
|
|
||||||
|
val statements = (constructor.body as? IrBlockBody)?.statements ?: return
|
||||||
|
|
||||||
|
var callIndex = -1
|
||||||
|
var superCallIndex = -1
|
||||||
|
for (i in statements.indices) {
|
||||||
|
val s = statements[i]
|
||||||
|
|
||||||
|
if (s is IrCall && s.symbol === setPropertiesSymbol) {
|
||||||
|
callIndex = i
|
||||||
|
}
|
||||||
|
if (s is IrDelegatingConstructorCall && s.symbol.owner.origin === PrimaryConstructorLowering.SYNTHETIC_PRIMARY_CONSTRUCTOR) {
|
||||||
|
superCallIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callIndex != -1 && superCallIndex != -1) {
|
||||||
|
val tmp = statements[callIndex]
|
||||||
|
statements[callIndex] = statements[superCallIndex]
|
||||||
|
statements[superCallIndex] = tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
-216
@@ -1,216 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.PrimaryConstructorLowering.SYNTHETIC_PRIMARY_CONSTRUCTOR
|
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
|
||||||
import org.jetbrains.kotlin.ir.types.isAny
|
|
||||||
import org.jetbrains.kotlin.ir.util.defaultType
|
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
|
||||||
import org.jetbrains.kotlin.ir.util.statements
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add ES6_INIT_BOX_PARAMETER for each constructor (except constructors
|
|
||||||
* of inline, external and primitive (string, arrays) classes).
|
|
||||||
* Uses: Inline class's constructor initialize field of outer class before
|
|
||||||
* call `super`, but its impossible in ES6. ES6_INIT_BOX_PARAMETER - object,
|
|
||||||
* that collect these values and pass to super constructor. In the last
|
|
||||||
* constructor of delegation chain ES6_INIT_BOX_PARAMETER will be open
|
|
||||||
* with `Object.assign(this, box)`
|
|
||||||
*
|
|
||||||
* Add ES6_RESULT_TYPE PARAMETER for each secondary ctor (except
|
|
||||||
* constructors of external and primitive (string, arrays) classes).
|
|
||||||
* Uses: Pass information about type of new object to `Reflect.construct()`
|
|
||||||
*
|
|
||||||
* Transform SYNTHETIC_PRIMARY_CONSTRUCTOR:
|
|
||||||
* constructor() {
|
|
||||||
* //statements
|
|
||||||
* }
|
|
||||||
* ==>
|
|
||||||
* constructor() {
|
|
||||||
* init(this)
|
|
||||||
* }
|
|
||||||
* init($this$) {
|
|
||||||
* //statements from ctor
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
class ES6AddInternalParametersToConstructorPhase(val context: JsIrBackendContext) : BodyLoweringPass {
|
|
||||||
object ES6_SYNTHETIC_PRIMARY_INIT_FUNCTION : IrDeclarationOriginImpl("ES6_SYNTHETIC_PRIMARY_INIT_FUNCTION")
|
|
||||||
object ES6_INIT_BOX_PARAMETER : IrDeclarationOriginImpl("ES6_INIT_BOX_PARAMETER")
|
|
||||||
object ES6_RESULT_TYPE_PARAMETER : IrDeclarationOriginImpl("ES6_RESULT_TYPE_PARAMETER")
|
|
||||||
|
|
||||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
|
||||||
if (!context.es6mode) return
|
|
||||||
|
|
||||||
container.transform(CallSiteTransformer(), null)
|
|
||||||
|
|
||||||
if (container !is IrConstructor) return
|
|
||||||
|
|
||||||
if (!container.hasStrictSignature()) container.addInternalValueParameters()
|
|
||||||
|
|
||||||
if (container.origin === SYNTHETIC_PRIMARY_CONSTRUCTOR) {
|
|
||||||
createInitFunction(container)
|
|
||||||
openInitializerBox(container)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrConstructor.addInternalValueParameters() {
|
|
||||||
addValueParameter("box", context.dynamicType, ES6_INIT_BOX_PARAMETER)
|
|
||||||
|
|
||||||
if (!isPrimary) {
|
|
||||||
addValueParameter("resultType", context.dynamicType, ES6_RESULT_TYPE_PARAMETER)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createInitFunction(constructor: IrConstructor) {
|
|
||||||
val irClass = constructor.parentAsClass
|
|
||||||
val initFunction = buildInitFunction(constructor, irClass)
|
|
||||||
irClass.declarations += initFunction
|
|
||||||
|
|
||||||
context.mapping.constructorToInitFunction[constructor] = initFunction
|
|
||||||
|
|
||||||
initFunction.transformChildren(object : IrElementTransformerVoid() {
|
|
||||||
override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement {
|
|
||||||
declaration.parent = initFunction
|
|
||||||
return declaration
|
|
||||||
}
|
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun openInitializerBox(constructor: IrConstructor) = with(constructor.body as IrBlockBody) {
|
|
||||||
statements.clear()
|
|
||||||
statements += JsIrBuilder.buildCall(context.intrinsics.jsOpenInitializerBox).also {
|
|
||||||
it.putValueArgument(0, JsIrBuilder.buildGetValue(constructor.parentAsClass.thisReceiver!!.symbol))
|
|
||||||
it.putValueArgument(1, JsIrBuilder.buildGetValue(constructor.valueParameters.last().symbol))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildInitFunction(constructor: IrConstructor, irClass: IrClass): IrSimpleFunction {
|
|
||||||
val functionName = "${irClass.name}_init"
|
|
||||||
|
|
||||||
return context.irFactory.buildFun {
|
|
||||||
name = Name.identifier(functionName)
|
|
||||||
returnType = context.irBuiltIns.unitType
|
|
||||||
visibility = DescriptorVisibilities.PROTECTED
|
|
||||||
modality = Modality.FINAL
|
|
||||||
isInline = constructor.isInline
|
|
||||||
isExternal = constructor.isExternal
|
|
||||||
origin = ES6_SYNTHETIC_PRIMARY_INIT_FUNCTION
|
|
||||||
}.apply {
|
|
||||||
parent = irClass
|
|
||||||
addValueParameter("\$this\$", context.dynamicType)
|
|
||||||
|
|
||||||
body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET, constructor.body?.statements.orEmpty())
|
|
||||||
|
|
||||||
transformChildren(object : IrElementTransformerVoid() {
|
|
||||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
|
||||||
return if (expression.symbol.owner === constructor.parentAsClass.thisReceiver!!) {
|
|
||||||
with(expression) { IrGetValueImpl(startOffset, endOffset, type, valueParameters.single().symbol) }
|
|
||||||
} else {
|
|
||||||
expression
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pass `null` for ES6_INIT_BOX_PARAMETER and ES6_RESULT_TYPE_PARAMETER
|
|
||||||
*/
|
|
||||||
inner class CallSiteTransformer : IrElementTransformerVoid() {
|
|
||||||
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
|
||||||
val constructor = expression.symbol.owner
|
|
||||||
val parent = constructor.parentAsClass
|
|
||||||
|
|
||||||
if (constructor.hasStrictSignature() || parent.defaultType.isAny()) return expression
|
|
||||||
|
|
||||||
val newArgsCount = if (constructor.isPrimary) 1 else 2
|
|
||||||
return expression.run {
|
|
||||||
IrConstructorCallImpl(
|
|
||||||
startOffset,
|
|
||||||
endOffset,
|
|
||||||
type,
|
|
||||||
symbol,
|
|
||||||
typeArgumentsCount,
|
|
||||||
constructorTypeArgumentsCount,
|
|
||||||
valueArgumentsCount + newArgsCount
|
|
||||||
).also {
|
|
||||||
for (i in 0 until valueArgumentsCount) {
|
|
||||||
it.putValueArgument(i, getValueArgument(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
it.putValueArgument(
|
|
||||||
valueArgumentsCount,
|
|
||||||
JsIrBuilder.buildNull(context.dynamicType)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!constructor.isPrimary) {
|
|
||||||
it.putValueArgument(
|
|
||||||
valueArgumentsCount + 1,
|
|
||||||
JsIrBuilder.buildNull(context.dynamicType)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
|
||||||
val constructor = expression.symbol.owner
|
|
||||||
val parent = constructor.parentAsClass
|
|
||||||
|
|
||||||
if (constructor.hasStrictSignature() || parent.defaultType.isAny()) return expression
|
|
||||||
|
|
||||||
val newArgsCount = if (constructor.isPrimary) 1 else 2
|
|
||||||
|
|
||||||
return expression.run {
|
|
||||||
IrDelegatingConstructorCallImpl(
|
|
||||||
startOffset,
|
|
||||||
endOffset,
|
|
||||||
type,
|
|
||||||
symbol,
|
|
||||||
typeArgumentsCount,
|
|
||||||
valueArgumentsCount + newArgsCount
|
|
||||||
).also {
|
|
||||||
for (i in 0 until valueArgumentsCount) {
|
|
||||||
it.putValueArgument(i, getValueArgument(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
it.putValueArgument(
|
|
||||||
valueArgumentsCount,
|
|
||||||
JsIrBuilder.buildNull(context.dynamicType)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!constructor.isPrimary) {
|
|
||||||
it.putValueArgument(
|
|
||||||
valueArgumentsCount + 1,
|
|
||||||
JsIrBuilder.buildNull(context.dynamicType)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrConstructor.hasStrictSignature(): Boolean {
|
|
||||||
val primitives = with(context.irBuiltIns) { primitiveTypesToPrimitiveArrays.values + stringClass }
|
|
||||||
return with(parentAsClass) { isExternal || context.inlineClassesUtils.isClassInlineLike(this) || symbol in primitives }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+140
@@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.irEmpty
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.util.isLocal
|
||||||
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
|
import org.jetbrains.kotlin.ir.util.superClass
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
|
||||||
|
|
||||||
|
class ES6ConstructorBoxParameterOptimizationLowering(private val context: JsIrBackendContext) : BodyLoweringPass {
|
||||||
|
private val esClassWhichNeedBoxParameters = context.mapping.esClassWhichNeedBoxParameters
|
||||||
|
|
||||||
|
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||||
|
if (!context.es6mode) return
|
||||||
|
|
||||||
|
val containerFunction = container as? IrFunction
|
||||||
|
|
||||||
|
val shouldRemoveBoxRelatedDeclarationsAndStatements =
|
||||||
|
containerFunction?.isEs6ConstructorReplacement == true && !containerFunction.parentAsClass.requiredToHaveBoxParameter()
|
||||||
|
|
||||||
|
if (containerFunction != null && shouldRemoveBoxRelatedDeclarationsAndStatements && irBody is IrBlockBody) {
|
||||||
|
containerFunction.valueParameters = containerFunction.valueParameters.filter { !it.isBoxParameter }
|
||||||
|
}
|
||||||
|
|
||||||
|
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||||
|
override fun visitWhen(expression: IrWhen): IrExpression {
|
||||||
|
return if (shouldRemoveBoxRelatedDeclarationsAndStatements && expression.isBoxParameterDefaultResolution) {
|
||||||
|
irEmpty(context)
|
||||||
|
} else {
|
||||||
|
super.visitWhen(expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
val callee = expression.symbol.owner
|
||||||
|
|
||||||
|
return when {
|
||||||
|
shouldRemoveBoxRelatedDeclarationsAndStatements && (callee.symbol == context.intrinsics.jsCreateThisSymbol || callee.symbol == context.intrinsics.jsCreateExternalThisSymbol) -> {
|
||||||
|
expression.putValueArgument(expression.valueArgumentsCount - 1, context.getVoid())
|
||||||
|
super.visitCall(expression)
|
||||||
|
}
|
||||||
|
callee.isEs6ConstructorReplacement && (!callee.parentAsClass.requiredToHaveBoxParameter() || shouldRemoveBoxRelatedDeclarationsAndStatements) -> {
|
||||||
|
val newArgumentsSize = expression.valueArgumentsCount - 1
|
||||||
|
super.visitCall(IrCallImpl(
|
||||||
|
expression.startOffset,
|
||||||
|
expression.endOffset,
|
||||||
|
expression.type,
|
||||||
|
expression.symbol,
|
||||||
|
expression.typeArgumentsCount,
|
||||||
|
newArgumentsSize,
|
||||||
|
expression.origin,
|
||||||
|
superQualifierSymbol = expression.superQualifierSymbol
|
||||||
|
).apply {
|
||||||
|
copyTypeArgumentsFrom(expression)
|
||||||
|
|
||||||
|
dispatchReceiver = expression.dispatchReceiver
|
||||||
|
extensionReceiver = expression.extensionReceiver
|
||||||
|
|
||||||
|
for (i in 0 until newArgumentsSize) {
|
||||||
|
putValueArgument(i, expression.getValueArgument(i))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else -> super.visitCall(expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrClass.requiredToHaveBoxParameter(): Boolean {
|
||||||
|
return esClassWhichNeedBoxParameters.contains(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ES6CollectConstructorsWhichNeedBoxParameters(private val context: JsIrBackendContext) : DeclarationTransformer {
|
||||||
|
private val esClassWhichNeedBoxParameters = context.mapping.esClassWhichNeedBoxParameters
|
||||||
|
|
||||||
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
|
if (!context.es6mode || declaration !is IrClass) return null
|
||||||
|
|
||||||
|
val hasSuperClass = declaration.superClass != null
|
||||||
|
|
||||||
|
if (hasSuperClass && declaration.isInner) {
|
||||||
|
declaration.addToClassListWhichNeedBoxParameter()
|
||||||
|
}
|
||||||
|
if (hasSuperClass && declaration.isLocal && declaration.containsCapturedValues()) {
|
||||||
|
declaration.addToClassListWhichNeedBoxParameter()
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrClass.containsCapturedValues(): Boolean {
|
||||||
|
if (superClass == null) return false
|
||||||
|
|
||||||
|
declarations
|
||||||
|
.filterIsInstanceAnd<IrFunction> { it.isEs6ConstructorReplacement }
|
||||||
|
.forEach {
|
||||||
|
var meetCapturing = false
|
||||||
|
val boxParameter = it.boxParameter
|
||||||
|
|
||||||
|
it.body?.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||||
|
override fun visitSetField(expression: IrSetField) {
|
||||||
|
val receiver = expression.receiver as? IrGetValue
|
||||||
|
if (receiver != null && receiver.symbol == boxParameter?.symbol) {
|
||||||
|
meetCapturing = true
|
||||||
|
}
|
||||||
|
super.visitSetField(expression)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (meetCapturing) return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrClass.addToClassListWhichNeedBoxParameter() {
|
||||||
|
if (isExternal) return
|
||||||
|
esClassWhichNeedBoxParameters.add(this)
|
||||||
|
superClass?.addToClassListWhichNeedBoxParameter()
|
||||||
|
}
|
||||||
|
}
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.hasStrictSignature
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.jsConstructorReference
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
|
||||||
|
class ES6ConstructorCallLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||||
|
private var IrConstructor.constructorFactory by context.mapping.secondaryConstructorToFactory
|
||||||
|
|
||||||
|
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||||
|
if (!context.es6mode) return
|
||||||
|
|
||||||
|
val containerFunction = container as? IrFunction
|
||||||
|
|
||||||
|
irBody.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||||
|
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
||||||
|
val currentConstructor = expression.symbol.owner
|
||||||
|
val irClass = currentConstructor.parentAsClass
|
||||||
|
val currentFunction = currentFunction?.irElement as? IrFunction ?: containerFunction
|
||||||
|
|
||||||
|
if (irClass.symbol == context.irBuiltIns.anyClass || currentConstructor.hasStrictSignature(context)) {
|
||||||
|
return super.visitConstructorCall(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
val factoryFunction = currentConstructor.constructorFactory ?: error("Replacement for the constructor is not found")
|
||||||
|
|
||||||
|
if (expression.isInitCall) {
|
||||||
|
assert(factoryFunction.isInitFunction) { "Expect to have init function replacement" }
|
||||||
|
return JsIrBuilder.buildCall(factoryFunction.symbol).apply {
|
||||||
|
copyValueArgumentsFrom(expression, factoryFunction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val isDelegatingCall =
|
||||||
|
expression.isSyntheticDelegatingReplacement && currentFunction != null && currentFunction.parentAsClass != irClass
|
||||||
|
|
||||||
|
val factoryFunctionCall = JsIrBuilder.buildCall(
|
||||||
|
factoryFunction.symbol,
|
||||||
|
superQualifierSymbol = irClass.symbol.takeIf { isDelegatingCall },
|
||||||
|
origin = if (isDelegatingCall) ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT else JsStatementOrigins.SYNTHESIZED_STATEMENT
|
||||||
|
).apply {
|
||||||
|
copyValueArgumentsFrom(expression, factoryFunction)
|
||||||
|
|
||||||
|
if (expression.isSyntheticDelegatingReplacement) {
|
||||||
|
currentFunction?.boxParameter?.let {
|
||||||
|
putValueArgument(valueArgumentsCount - 1, JsIrBuilder.buildGetValue(it.symbol))
|
||||||
|
}
|
||||||
|
if (superQualifierSymbol == null) {
|
||||||
|
dispatchReceiver = JsIrBuilder.buildGetValue(factoryFunction.dispatchReceiverParameter!!.symbol)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dispatchReceiver = irClass.jsConstructorReference(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.visitCall(factoryFunctionCall)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
+204
-519
@@ -5,568 +5,253 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.backend.common.ir.ValueRemapper
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
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.export.isExported
|
||||||
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.lower.ES6AddInternalParametersToConstructorPhase.ES6_INIT_BOX_PARAMETER
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_RESULT_TYPE_PARAMETER
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.PrimaryConstructorLowering.SYNTHETIC_PRIMARY_CONSTRUCTOR
|
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||||
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.IrGetValueImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
|
import org.jetbrains.kotlin.ir.types.typeWith
|
||||||
import org.jetbrains.kotlin.ir.types.isAny
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.util.defaultType
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
|
||||||
import org.jetbrains.kotlin.ir.util.statements
|
|
||||||
import org.jetbrains.kotlin.ir.util.transformInPlace
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||||
|
|
||||||
object ES6_THIS_VARIABLE_ORIGIN : IrDeclarationOriginImpl("ES6_THIS_VARIABLE_ORIGIN")
|
object ES6_INIT_CALL : IrStatementOriginImpl("ES6_INIT_CALL")
|
||||||
|
object ES6_CONSTRUCTOR_REPLACEMENT : IrDeclarationOriginImpl("ES6_CONSTRUCTOR_REPLACEMENT")
|
||||||
|
object ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT : IrDeclarationOriginImpl("ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT")
|
||||||
|
object ES6_INIT_FUNCTION : IrDeclarationOriginImpl("ES6_INIT_FUNCTION")
|
||||||
|
object ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT : IrStatementOriginImpl("ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT")
|
||||||
|
|
||||||
class ES6ConstructorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
val IrDeclaration.isEs6ConstructorReplacement: Boolean
|
||||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
get() = origin == ES6_CONSTRUCTOR_REPLACEMENT || origin == ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT
|
||||||
if (!context.es6mode) return
|
|
||||||
|
|
||||||
if (container !is IrConstructor) return
|
val IrDeclaration.isEs6PrimaryConstructorReplacement: Boolean
|
||||||
|
get() = origin == ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT
|
||||||
|
|
||||||
if (container.hasStrictSignature()) return
|
val IrFunctionAccessExpression.isSyntheticDelegatingReplacement: Boolean
|
||||||
|
get() = origin == ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT
|
||||||
|
|
||||||
hackEnums(container)
|
val IrDeclaration.isInitFunction: Boolean
|
||||||
hackExceptions(context, container)
|
get() = origin == ES6_INIT_FUNCTION
|
||||||
|
|
||||||
val superCall = getSuperCall(container) ?: return
|
val IrFunctionAccessExpression.isInitCall: Boolean
|
||||||
val superCtor = superCall.symbol.owner
|
get() = origin == ES6_INIT_CALL
|
||||||
val helper = LowerCtorHelper(context, container, superCtor)
|
|
||||||
|
|
||||||
if (container.isPrimary) {
|
class ES6ConstructorLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||||
if (superCtor.isPrimary) primaryToPrimary(helper)
|
private var IrConstructor.constructorFactory by context.mapping.secondaryConstructorToFactory
|
||||||
else primaryToSecondary(helper)
|
|
||||||
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
|
if (!context.es6mode || declaration !is IrConstructor || declaration.hasStrictSignature(context)) return null
|
||||||
|
|
||||||
|
return if (declaration.isSyntheticPrimaryConstructor) {
|
||||||
|
listOf(declaration.generateInitFunction())
|
||||||
} else {
|
} else {
|
||||||
if (superCtor.isPrimary) secondaryToPrimary(helper)
|
val factoryFunction = declaration.generateCreateFunction()
|
||||||
else secondaryToSecondary(helper)
|
listOfNotNull(factoryFunction, declaration.generateExportedConstructorIfNeed(factoryFunction))
|
||||||
|
|
||||||
replaceCallToDefaultPrimary(context, container)
|
|
||||||
changeIrConstructorToIrFunction(context, container)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private fun IrConstructor.generateExportedConstructorIfNeed(factoryFunction: IrSimpleFunction): IrConstructor? {
|
||||||
* constructor(args, box) {
|
return runIf(isExported(context) && isPrimary) {
|
||||||
* var currBox = box || {}
|
apply {
|
||||||
*
|
valueParameters = valueParameters.filterNot { it.isBoxParameter }
|
||||||
* //1. Superclass is Any
|
(body as? IrBlockBody)?.let {
|
||||||
* Object.assign(this, currBox)
|
val selfReplacedConstructorCall = JsIrBuilder.buildCall(factoryFunction.symbol).apply {
|
||||||
* //body
|
valueParameters.forEachIndexed { i, it -> putValueArgument(i, JsIrBuilder.buildGetValue(it.symbol)) }
|
||||||
*
|
dispatchReceiver = JsIrBuilder.buildCall(context.intrinsics.jsNewTarget)
|
||||||
* //2. Base class isInline or isExternal or array/string
|
}
|
||||||
* super(args)
|
it.statements.add(JsIrBuilder.buildReturn(symbol, selfReplacedConstructorCall, returnType))
|
||||||
* Object.assign(this, currBox)
|
|
||||||
* //body
|
|
||||||
*
|
|
||||||
* //3. Base class !isInline and !isExternal and !(array/string)
|
|
||||||
* //fill initialization box
|
|
||||||
* super(args, currBox)
|
|
||||||
* //body
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
private fun primaryToPrimary(helper: LowerCtorHelper) = with(helper) {
|
|
||||||
statements.add(0, boxOrEmptyObject)
|
|
||||||
|
|
||||||
if (superCtor.parentAsClass.defaultType.isAny()) {
|
|
||||||
//after superCall
|
|
||||||
statements.add(1, openBoxStatement(thisSymbol, boxSymbol))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (superCtor.hasStrictSignature()) {
|
|
||||||
//after superCall
|
|
||||||
statements.add(2, openBoxStatement(thisSymbol, boxSymbol))
|
|
||||||
} else {
|
|
||||||
fillInitializerBox(boxSymbol, constructor)
|
|
||||||
putBoxToSuperCall(boxSymbol, constructor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* constructor(args, box) {
|
|
||||||
* var currBox = box || {}
|
|
||||||
*
|
|
||||||
* //1. Base class isExternal or array/string
|
|
||||||
* var $this$ = Base_constructor(.., currBox)
|
|
||||||
* Object.assign(this, currBox)
|
|
||||||
* return $this$
|
|
||||||
*
|
|
||||||
* //2. Base class !isInline and !isExternal and !(array/string)
|
|
||||||
* //fill initialization box
|
|
||||||
* var $this$ = Base_constructor(.., currBox, new.target)
|
|
||||||
* //body
|
|
||||||
* return $this$
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
private fun primaryToSecondary(helper: LowerCtorHelper) = with(helper) {
|
|
||||||
statements.add(0, boxOrEmptyObject)
|
|
||||||
|
|
||||||
if (superCtor.hasStrictSignature()) {
|
|
||||||
fun createNewSuperCall(): IrCall {
|
|
||||||
val callType = JsIrBuilder.buildCall(context.intrinsics.jsClass, context.dynamicType, listOf(superCtor.returnType))
|
|
||||||
val newTarget = JsIrBuilder.buildCall(context.intrinsics.jsNewTarget)
|
|
||||||
val args = IrVarargImpl(
|
|
||||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
|
||||||
context.dynamicType,
|
|
||||||
context.dynamicType,
|
|
||||||
getElements(constructor)
|
|
||||||
)
|
|
||||||
|
|
||||||
return JsIrBuilder.buildCall(context.intrinsics.jsConstruct).apply {
|
|
||||||
putValueArgument(0, callType)
|
|
||||||
putValueArgument(1, newTarget)
|
|
||||||
putValueArgument(2, args)
|
|
||||||
|
|
||||||
putTypeArgument(0, superCtor.returnType)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val newThis = createThisVariable(createNewSuperCall())
|
|
||||||
changeReturnUnitToReturnInstance(newThis)
|
|
||||||
|
|
||||||
statements.add(2, openBoxStatement(newThis.symbol, boxSymbol))
|
|
||||||
statements += returnThis(constructor, newThis)
|
|
||||||
|
|
||||||
redirectOldThisToNewOne(constructor, newThis)
|
|
||||||
} else {
|
|
||||||
putBoxToSuperCall(boxSymbol, constructor)
|
|
||||||
fillInitializerBox(boxSymbol, constructor)
|
|
||||||
|
|
||||||
val newTarget = JsIrBuilder.buildCall(context.intrinsics.jsNewTarget)
|
|
||||||
val newThis = createThisVariable(createNewSuperCallPrimaryToSecondary(superCall, newTarget))
|
|
||||||
changeReturnUnitToReturnInstance(newThis)
|
|
||||||
|
|
||||||
statements += returnThis(constructor, newThis)
|
|
||||||
|
|
||||||
redirectOldThisToNewOne(constructor, newThis)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private fun IrConstructor.generateInitFunction(): IrSimpleFunction {
|
||||||
* Derived_constructor(.., box, resultType) {
|
val constructor = this
|
||||||
* var currBox = box || {}
|
val irClass = parentAsClass
|
||||||
* var currResultType = resultType || Derived
|
val constructorName = "init_${irClass.constructorPostfix}"
|
||||||
*
|
return context.irFactory.buildFun {
|
||||||
* //1. Base class isInline or isExternal or array/string
|
name = Name.identifier(constructorName)
|
||||||
* var $this$ = construct(Base, currResultType, [..])
|
returnType = context.irBuiltIns.unitType
|
||||||
* Object.assign(this, currBox)
|
visibility = DescriptorVisibilities.PRIVATE
|
||||||
* //body
|
modality = Modality.FINAL
|
||||||
* return $this$
|
isInline = constructor.isInline
|
||||||
*
|
isExternal = constructor.isExternal
|
||||||
* //2. Base class !isInline and !isExternal and !(array/string)
|
origin = ES6_INIT_FUNCTION
|
||||||
* //fill initialization box
|
}.also { factory ->
|
||||||
* var $this$ = construct(Base, currResultType, [.., currBox])
|
factory.parent = irClass
|
||||||
* //body
|
factory.copyTypeParametersFrom(irClass)
|
||||||
* return $this$
|
factory.annotations = annotations
|
||||||
* }
|
factory.extensionReceiverParameter = irClass.thisReceiver?.copyTo(factory)
|
||||||
*/
|
|
||||||
private fun secondaryToPrimary(helper: LowerCtorHelper) = with(helper) {
|
|
||||||
statements.add(0, boxOrEmptyObject)
|
|
||||||
statements.add(1, resultTypeOrDefaultType())
|
|
||||||
val resultTypeSymbol = (statements[1] as IrVariable).symbol
|
|
||||||
|
|
||||||
if (superCtor.hasStrictSignature()) {
|
factory.body = constructor.body?.deepCopyWithSymbols(factory)?.apply {
|
||||||
val newThis = createThisVariable(createNewSuperCallSecondaryToPrimary(constructor, superCtor, resultTypeSymbol))
|
transformChildrenVoid(ValueRemapper(mapOf(irClass.thisReceiver!!.symbol to factory.extensionReceiverParameter!!.symbol)))
|
||||||
changeReturnUnitToReturnInstance(newThis)
|
|
||||||
|
|
||||||
statements.add(3, openBoxStatement(newThis.symbol, boxSymbol))
|
|
||||||
statements.add(returnThis(constructor, newThis))
|
|
||||||
|
|
||||||
redirectOldThisToNewOne(constructor, newThis)
|
|
||||||
} else {
|
|
||||||
fillInitializerBox(boxSymbol, constructor)
|
|
||||||
|
|
||||||
val newThis = createThisVariable(createNewSuperCallSecondaryToPrimary(constructor, superCtor, resultTypeSymbol, boxSymbol))
|
|
||||||
changeReturnUnitToReturnInstance(newThis)
|
|
||||||
|
|
||||||
statements.add(returnThis(constructor, newThis))
|
|
||||||
|
|
||||||
redirectOldThisToNewOne(constructor, newThis)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Derived_constructor(.., box, resultType) {
|
|
||||||
* var currBox = box || {}
|
|
||||||
* var currResultType = resultType || Derived
|
|
||||||
* //fill initialization box
|
|
||||||
*
|
|
||||||
* //1. Base class isInline or isExternal or array/string
|
|
||||||
* var $this$ = Base_constructor(..)
|
|
||||||
* Object.assign(this, currBox)
|
|
||||||
* //body
|
|
||||||
* return $this$
|
|
||||||
*
|
|
||||||
* //2. Base class !isInline and !isExternal and !(array/string)
|
|
||||||
* var $this$ = Base_constructor(.., currBox, currResultType)
|
|
||||||
* //body
|
|
||||||
* return $this$
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
private fun secondaryToSecondary(helper: LowerCtorHelper) = with(helper) {
|
|
||||||
statements.add(0, boxOrEmptyObject)
|
|
||||||
statements.add(1, resultTypeOrDefaultType())
|
|
||||||
val resultTypeSymbol = (statements[1] as IrVariable).symbol
|
|
||||||
|
|
||||||
putBoxToSuperCall(boxSymbol, constructor)
|
|
||||||
fillInitializerBox(boxSymbol, constructor)
|
|
||||||
|
|
||||||
if (superCtor.hasStrictSignature()) {
|
|
||||||
val newThis = createThisVariable(superCall)
|
|
||||||
changeReturnUnitToReturnInstance(newThis)
|
|
||||||
|
|
||||||
statements.add(3, openBoxStatement(newThis.symbol, boxSymbol))
|
|
||||||
statements += returnThis(constructor, newThis)
|
|
||||||
|
|
||||||
redirectOldThisToNewOne(constructor, newThis)
|
|
||||||
} else {
|
|
||||||
val newThis = createThisVariable(createNewSuperCallSecondaryToSecondary(superCall, boxSymbol, resultTypeSymbol))
|
|
||||||
changeReturnUnitToReturnInstance(newThis)
|
|
||||||
|
|
||||||
statements += returnThis(constructor, newThis)
|
|
||||||
|
|
||||||
redirectOldThisToNewOne(constructor, newThis)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//superCallBuilder
|
|
||||||
private fun createNewSuperCallSecondaryToSecondary(
|
|
||||||
superCall: IrDelegatingConstructorCall,
|
|
||||||
boxSymbol: IrValueSymbol,
|
|
||||||
resultTypeSymbol: IrVariableSymbol
|
|
||||||
) = superCall.apply {
|
|
||||||
putValueArgument(ES6_INIT_BOX_PARAMETER, JsIrBuilder.buildGetValue(boxSymbol))
|
|
||||||
putValueArgument(ES6_RESULT_TYPE_PARAMETER, JsIrBuilder.buildGetValue(resultTypeSymbol))
|
|
||||||
}
|
|
||||||
|
|
||||||
//superCallBuilder
|
|
||||||
private fun createNewSuperCallPrimaryToSecondary(
|
|
||||||
superCall: IrDelegatingConstructorCall,
|
|
||||||
newTarget: IrCall? = null
|
|
||||||
) = superCall.apply { putValueArgument(ES6_RESULT_TYPE_PARAMETER, newTarget) }
|
|
||||||
|
|
||||||
private fun IrDelegatingConstructorCall.putValueArgument(origin: IrDeclarationOrigin, value: IrExpression?) {
|
|
||||||
val valueParameters = symbol.owner.valueParameters
|
|
||||||
for (i in valueParameters.indices) {
|
|
||||||
if (valueParameters[i].origin === origin) {
|
|
||||||
putValueArgument(i, value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructorFactory = factory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//superCallBuilder
|
private fun IrConstructor.generateCreateFunction(): IrSimpleFunction {
|
||||||
private fun createNewSuperCallSecondaryToPrimary(
|
val constructor = this
|
||||||
constructor: IrConstructor,
|
val irClass = parentAsClass
|
||||||
superCtor: IrConstructor,
|
val type = irClass.defaultType
|
||||||
resultTypeSymbol: IrVariableSymbol,
|
val constructorName = "new_${irClass.constructorPostfix}"
|
||||||
boxSymbol: IrVariableSymbol? = null
|
|
||||||
): IrCall {
|
return context.irFactory.buildFun {
|
||||||
val callType = JsIrBuilder.buildCall(context.intrinsics.jsClass, context.dynamicType, listOf(superCtor.returnType))
|
name = Name.identifier(constructorName)
|
||||||
val resultType = JsIrBuilder.buildGetValue(resultTypeSymbol)
|
returnType = type
|
||||||
val arguments = IrVarargImpl(
|
visibility = constructor.visibility
|
||||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
modality = Modality.FINAL
|
||||||
context.irBuiltIns.anyNType,
|
isInline = constructor.isInline
|
||||||
context.irBuiltIns.anyNType,
|
isExternal = constructor.isExternal
|
||||||
getElements(constructor, boxSymbol)
|
origin = when {
|
||||||
|
constructor.isPrimary -> ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT
|
||||||
|
else -> ES6_CONSTRUCTOR_REPLACEMENT
|
||||||
|
}
|
||||||
|
}.also { factory ->
|
||||||
|
factory.parent = irClass
|
||||||
|
factory.copyTypeParametersFrom(irClass)
|
||||||
|
factory.copyValueParametersFrom(constructor)
|
||||||
|
factory.annotations = annotations
|
||||||
|
factory.dispatchReceiverParameter = irClass.thisReceiver?.copyTo(factory)
|
||||||
|
|
||||||
|
if (irClass.isExported(context) && constructor.isPrimary) {
|
||||||
|
factory.excludeFromExport()
|
||||||
|
}
|
||||||
|
|
||||||
|
factory.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||||
|
val bodyCopy = constructor.body?.deepCopyWithSymbols(factory) ?: return@createBlockBody
|
||||||
|
val self = bodyCopy.replaceSuperCallsAndThisUsages(irClass, factory, constructor)
|
||||||
|
statements.addAll(bodyCopy.statements)
|
||||||
|
statements.add(JsIrBuilder.buildReturn(factory.symbol, JsIrBuilder.buildGetValue(self), irClass.defaultType))
|
||||||
|
}
|
||||||
|
|
||||||
|
constructorFactory = factory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunction.generateThisVariable(irClass: IrClass, initializer: IrExpression): IrVariable {
|
||||||
|
return JsIrBuilder.buildVar(
|
||||||
|
type = irClass.defaultType,
|
||||||
|
parent = this,
|
||||||
|
name = Namer.SYNTHETIC_RECEIVER_NAME,
|
||||||
|
initializer = initializer
|
||||||
)
|
)
|
||||||
|
|
||||||
if (superCtor.parentAsClass.defaultType.isAny()) {
|
|
||||||
//superType is Any, and we have default primary --> create call to default primary
|
|
||||||
return JsIrBuilder.buildCall(context.intrinsics.jsConstruct, context.irBuiltIns.nothingType).apply {
|
|
||||||
arguments.elements.clear()
|
|
||||||
arguments.addElement(JsIrBuilder.buildGetValue(boxSymbol!!))
|
|
||||||
|
|
||||||
putValueArgument(0, JsIrBuilder.buildCall(context.intrinsics.jsClass, context.dynamicType, listOf(constructor.returnType)))
|
|
||||||
putValueArgument(1, resultType)
|
|
||||||
putValueArgument(2, arguments)
|
|
||||||
|
|
||||||
putTypeArgument(0, constructor.returnType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return JsIrBuilder.buildCall(context.intrinsics.jsConstruct, context.irBuiltIns.nothingType).apply {
|
|
||||||
putValueArgument(0, callType)
|
|
||||||
putValueArgument(1, resultType)
|
|
||||||
putValueArgument(2, arguments)
|
|
||||||
|
|
||||||
putTypeArgument(0, superCtor.returnType)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private val IrClass.constructorPostfix: String
|
||||||
* Copy arguments from superCall
|
get() = fqNameWhenAvailable?.asString()?.replace('.', '_') ?: name.toString()
|
||||||
*/
|
|
||||||
private fun getElements(constructor: IrConstructor, boxSymbol: IrValueSymbol? = null): List<IrVarargElement> {
|
|
||||||
val result = mutableListOf<IrVarargElement>()
|
|
||||||
|
|
||||||
val superCall = constructor.body!!.statements.filterIsInstance<IrDelegatingConstructorCall>().first()
|
private fun irAnyArray(elements: List<IrExpression>): IrExpression {
|
||||||
repeat(superCall.valueArgumentsCount) { i ->
|
return JsIrBuilder.buildArray(
|
||||||
val arg = superCall.getValueArgument(i) ?: return@repeat
|
elements,
|
||||||
if (superCall.symbol.owner.valueParameters[i].origin === ES6_INIT_BOX_PARAMETER) {
|
context.irBuiltIns.arrayClass.typeWith(context.irBuiltIns.anyNType),
|
||||||
result += JsIrBuilder.buildGetValue(boxSymbol!!)
|
context.irBuiltIns.anyNType,
|
||||||
} else {
|
)
|
||||||
if (context.inlineClassesUtils.getInlinedClass(arg.type) != null) {
|
}
|
||||||
val any = context.irBuiltIns.anyNType
|
|
||||||
result += JsIrBuilder.buildTypeOperator(any, IrTypeOperator.REINTERPRET_CAST, arg, any)
|
private fun IrBody.replaceSuperCallsAndThisUsages(
|
||||||
|
irClass: IrClass,
|
||||||
|
constructorReplacement: IrSimpleFunction,
|
||||||
|
currentConstructor: IrConstructor,
|
||||||
|
): IrValueSymbol {
|
||||||
|
var generatedThisValueSymbol: IrValueSymbol? = null
|
||||||
|
val selfParameterSymbol = irClass.thisReceiver!!.symbol
|
||||||
|
val boxParameterSymbol = constructorReplacement.boxParameter
|
||||||
|
|
||||||
|
transformChildrenVoid(object : ValueRemapper(emptyMap()) {
|
||||||
|
override val map: MutableMap<IrValueSymbol, IrValueSymbol> = currentConstructor.valueParameters
|
||||||
|
.zip(constructorReplacement.valueParameters)
|
||||||
|
.associate { it.first.symbol to it.second.symbol }
|
||||||
|
.toMutableMap()
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||||
|
return if (expression.returnTargetSymbol == currentConstructor.symbol) {
|
||||||
|
super.visitReturn(
|
||||||
|
JsIrBuilder.buildReturn(
|
||||||
|
constructorReplacement.symbol,
|
||||||
|
JsIrBuilder.buildGetValue(selfParameterSymbol),
|
||||||
|
irClass.defaultType
|
||||||
|
)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
result += arg
|
super.visitReturn(expression)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
//builder
|
|
||||||
private fun returnThis(constructor: IrConstructor, newThis: IrVariable): IrReturn {
|
|
||||||
return JsIrBuilder.buildReturn(
|
|
||||||
constructor.symbol,
|
|
||||||
JsIrBuilder.buildGetValue(newThis.symbol),
|
|
||||||
context.irBuiltIns.nothingType
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform statements like `this.x = y` to `box.x = y`
|
|
||||||
*/
|
|
||||||
private fun fillInitializerBox(boxSymbol: IrValueSymbol, constructor: IrConstructor) {
|
|
||||||
val statements = (constructor.body as IrBlockBody).statements
|
|
||||||
for (i in statements.indices) {
|
|
||||||
val current = statements[i]
|
|
||||||
if (current is IrSetField) {
|
|
||||||
if ((current.receiver as? IrGetValue)?.symbol?.owner === constructor.parentAsClass.thisReceiver) {
|
|
||||||
current.receiver = JsIrBuilder.buildGetValue(boxSymbol)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statements[i] is IrDelegatingConstructorCall) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//transformer
|
|
||||||
private fun putBoxToSuperCall(boxSymbol: IrValueSymbol, constructor: IrConstructor) {
|
|
||||||
constructor.transformChildren(object : IrElementTransformerVoid() {
|
|
||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||||
return expression.also { it.putValueArgument(ES6_INIT_BOX_PARAMETER, JsIrBuilder.buildGetValue(boxSymbol)) }
|
val constructor = expression.symbol.owner
|
||||||
|
|
||||||
|
if (constructor.isSyntheticPrimaryConstructor) {
|
||||||
|
return JsIrBuilder.buildConstructorCall(expression.symbol, origin = ES6_INIT_CALL)
|
||||||
|
.apply {
|
||||||
|
copyValueArgumentsFrom(expression, constructor)
|
||||||
|
extensionReceiver = JsIrBuilder.buildGetValue(selfParameterSymbol)
|
||||||
|
}
|
||||||
|
.run { visitConstructorCall(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val boxParameterGetter = boxParameterSymbol?.let { JsIrBuilder.buildGetValue(it.symbol) } ?: context.getVoid()
|
||||||
|
|
||||||
|
val newThisValue = when {
|
||||||
|
constructor.isEffectivelyExternal() ->
|
||||||
|
JsIrBuilder.buildCall(context.intrinsics.jsCreateExternalThisSymbol)
|
||||||
|
.apply {
|
||||||
|
putValueArgument(0, irClass.getCurrentConstructorReference(constructorReplacement))
|
||||||
|
putValueArgument(1, expression.symbol.owner.parentAsClass.jsConstructorReference(context))
|
||||||
|
putValueArgument(2, irAnyArray(expression.valueArguments.map { it ?: context.getVoid() }))
|
||||||
|
putValueArgument(3, boxParameterGetter)
|
||||||
|
}
|
||||||
|
constructor.parentAsClass.symbol == context.irBuiltIns.anyClass ->
|
||||||
|
JsIrBuilder.buildCall(context.intrinsics.jsCreateThisSymbol)
|
||||||
|
.apply {
|
||||||
|
putValueArgument(0, irClass.getCurrentConstructorReference(constructorReplacement))
|
||||||
|
putValueArgument(1, boxParameterGetter)
|
||||||
|
}
|
||||||
|
else ->
|
||||||
|
JsIrBuilder.buildConstructorCall(
|
||||||
|
expression.symbol,
|
||||||
|
null,
|
||||||
|
expression.typeArguments,
|
||||||
|
ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT
|
||||||
|
).apply {
|
||||||
|
copyValueArgumentsFrom(expression, constructor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val newThisVariable = constructorReplacement.generateThisVariable(irClass, newThisValue)
|
||||||
|
.also {
|
||||||
|
generatedThisValueSymbol = it.symbol
|
||||||
|
map[selfParameterSymbol] = it.symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.visitComposite(JsIrBuilder.buildComposite(context.irBuiltIns.unitType, listOf(newThisVariable)))
|
||||||
}
|
}
|
||||||
}, null)
|
})
|
||||||
|
|
||||||
|
return generatedThisValueSymbol!!
|
||||||
}
|
}
|
||||||
|
|
||||||
//builder
|
private fun IrClass.getCurrentConstructorReference(currentFactoryFunction: IrSimpleFunction): IrExpression {
|
||||||
private fun openBoxStatement(thisSymbol: IrValueSymbol, boxSymbol: IrValueSymbol): IrCall {
|
return if (isFinalClass) {
|
||||||
return JsIrBuilder.buildCall(context.intrinsics.jsOpenInitializerBox).also {
|
jsConstructorReference(context)
|
||||||
it.putValueArgument(0, JsIrBuilder.buildGetValue(thisSymbol))
|
} else {
|
||||||
it.putValueArgument(1, JsIrBuilder.buildGetValue(boxSymbol))
|
JsIrBuilder.buildGetValue(currentFactoryFunction.dispatchReceiverParameter!!.symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//util
|
private fun IrDeclaration.excludeFromExport() {
|
||||||
private fun IrConstructor.hasStrictSignature(): Boolean {
|
val jsExportIgnoreClass = context.intrinsics.jsExportIgnoreAnnotationSymbol.owner
|
||||||
val primitives = with(context.irBuiltIns) { primitiveTypesToPrimitiveArrays.values + stringClass }
|
val jsExportIgnoreCtor = jsExportIgnoreClass.primaryConstructor ?: return
|
||||||
return with(parentAsClass) { isExternal || context.inlineClassesUtils.isClassInlineLike(this) || symbol in primitives }
|
annotations += JsIrBuilder.buildConstructorCall(jsExportIgnoreCtor.symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//transformer
|
|
||||||
private fun replaceCallToDefaultPrimary(context: JsIrBackendContext, constructor: IrConstructor) {
|
|
||||||
val thisSymbol = (((constructor.body as IrBlockBody).statements
|
|
||||||
.find { it is IrVariable && it.origin === ES6_THIS_VARIABLE_ORIGIN }) as IrVariable?)?.symbol ?: return
|
|
||||||
|
|
||||||
(constructor.body as IrBlockBody).statements.transformInPlace {
|
|
||||||
if (it is IrDelegatingConstructorCall) {
|
|
||||||
val superCtor = it.symbol.owner
|
|
||||||
val initFunc = context.mapping.constructorToInitFunction[superCtor]!!
|
|
||||||
|
|
||||||
JsIrBuilder.buildCall(initFunc.symbol).apply {
|
|
||||||
putValueArgument(0, JsIrBuilder.buildGetValue(thisSymbol))
|
|
||||||
}
|
|
||||||
} else it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//transformer
|
|
||||||
private fun redirectOldThisToNewOne(constructor: IrConstructor, newThis: IrVariable) {
|
|
||||||
constructor.transformChildren(object : IrElementTransformerVoid() {
|
|
||||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
|
||||||
return if (expression.symbol.owner === constructor.parentAsClass.thisReceiver!!) {
|
|
||||||
with(expression) { IrGetValueImpl(startOffset, endOffset, type, newThis.symbol) }
|
|
||||||
} else {
|
|
||||||
expression
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change `return Unit` to `return $this$`
|
|
||||||
*/
|
|
||||||
private fun LowerCtorHelper.changeReturnUnitToReturnInstance(newThis: IrVariable) {
|
|
||||||
constructor.transformChildren(object : IrElementTransformerVoid() {
|
|
||||||
override fun visitReturn(expression: IrReturn): IrExpression {
|
|
||||||
return JsIrBuilder.buildReturn(
|
|
||||||
constructor.symbol,
|
|
||||||
JsIrBuilder.buildGetValue(newThis.symbol),
|
|
||||||
expression.type
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hackEnums(constructor: IrConstructor) {
|
|
||||||
constructor.transformChildren(object : IrElementTransformerVoid() {
|
|
||||||
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
|
|
||||||
return (expression.argument as? IrDelegatingConstructorCall) ?: expression
|
|
||||||
}
|
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Swap call synthetic primary ctor and call extendThrowable
|
|
||||||
*/
|
|
||||||
private fun hackExceptions(context: JsIrBackendContext, constructor: IrConstructor) {
|
|
||||||
val setPropertiesSymbol = context.setPropertiesToThrowableInstanceSymbol
|
|
||||||
|
|
||||||
val statements = (constructor.body as IrBlockBody).statements
|
|
||||||
|
|
||||||
var callIndex = -1
|
|
||||||
var superCallIndex = -1
|
|
||||||
for (i in statements.indices) {
|
|
||||||
val s = statements[i]
|
|
||||||
|
|
||||||
if (s is IrCall && s.symbol === setPropertiesSymbol) callIndex = i
|
|
||||||
if (s is IrDelegatingConstructorCall && s.symbol.owner.origin === SYNTHETIC_PRIMARY_CONSTRUCTOR) superCallIndex = i
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callIndex != -1 && superCallIndex != -1) {
|
|
||||||
val tmp = statements[callIndex]
|
|
||||||
statements[callIndex] = statements[superCallIndex]
|
|
||||||
statements[superCallIndex] = tmp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class LowerCtorHelper(
|
|
||||||
private val context: JsIrBackendContext,
|
|
||||||
val constructor: IrConstructor,
|
|
||||||
val superCtor: IrConstructor
|
|
||||||
) {
|
|
||||||
private val boxParameterSymbol = constructor.valueParameters.find { it.origin === ES6_INIT_BOX_PARAMETER }!!.symbol
|
|
||||||
val resultTypeParameterSymbol by lazy {
|
|
||||||
constructor.valueParameters.find { it.origin === ES6_RESULT_TYPE_PARAMETER }!!.symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
val statements = (constructor.body as IrBlockBody).statements
|
|
||||||
|
|
||||||
/**
|
|
||||||
* var currBox = box || {}
|
|
||||||
*/
|
|
||||||
val boxOrEmptyObject = boxOrEmptyObject(boxParameterSymbol, constructor)
|
|
||||||
private fun boxOrEmptyObject(boxSymbol: IrValueSymbol, parent: IrConstructor): IrVariable {
|
|
||||||
val emptyObject = JsIrBuilder.buildCall(context.intrinsics.jsEmptyObject)
|
|
||||||
val or = JsIrBuilder.buildCall(context.intrinsics.jsOr, context.dynamicType).apply {
|
|
||||||
putValueArgument(0, JsIrBuilder.buildGetValue(boxSymbol))
|
|
||||||
putValueArgument(1, emptyObject)
|
|
||||||
}
|
|
||||||
return JsIrBuilder.buildVar(context.dynamicType, parent, "currBox", initializer = or)
|
|
||||||
}
|
|
||||||
|
|
||||||
val boxSymbol = boxOrEmptyObject.symbol
|
|
||||||
val thisSymbol = constructor.parentAsClass.thisReceiver!!.symbol
|
|
||||||
|
|
||||||
val superCall: IrDelegatingConstructorCall by lazy { getSuperCall(constructor)!! }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* var $this$ = `newSuperCall`
|
|
||||||
*/
|
|
||||||
fun createThisVariable(newSuperCall: IrExpression): IrVariable {
|
|
||||||
val newThis = JsIrBuilder.buildVar(
|
|
||||||
context.dynamicType,
|
|
||||||
constructor,
|
|
||||||
"\$this\$",
|
|
||||||
initializer = newSuperCall
|
|
||||||
).apply {
|
|
||||||
origin = ES6_THIS_VARIABLE_ORIGIN
|
|
||||||
}
|
|
||||||
|
|
||||||
(constructor.body as IrBlockBody).statements.transformInPlace {
|
|
||||||
if (it === superCall) newThis
|
|
||||||
else it
|
|
||||||
}
|
|
||||||
|
|
||||||
return newThis
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* var currResultType = resultType || D
|
|
||||||
*/
|
|
||||||
fun resultTypeOrDefaultType(): IrStatement {
|
|
||||||
val defaultType = JsIrBuilder.buildCall(context.intrinsics.es6DefaultType).apply {
|
|
||||||
putTypeArgument(0, constructor.parentAsClass.defaultType)
|
|
||||||
}
|
|
||||||
val or = JsIrBuilder.buildCall(context.intrinsics.jsOr, context.dynamicType).apply {
|
|
||||||
putValueArgument(0, JsIrBuilder.buildGetValue(resultTypeParameterSymbol))
|
|
||||||
putValueArgument(1, defaultType)
|
|
||||||
}
|
|
||||||
return JsIrBuilder.buildVar(context.dynamicType, constructor, "currResultType", initializer = or)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSuperCall(constructor: IrConstructor): IrDelegatingConstructorCall? {
|
|
||||||
var result: IrDelegatingConstructorCall? = null
|
|
||||||
(constructor.body as IrBlockBody).acceptChildren(object : IrElementVisitor<Unit, Any?> {
|
|
||||||
override fun visitElement(element: IrElement, data: Any?) { }
|
|
||||||
|
|
||||||
override fun visitBlock(expression: IrBlock, data: Any?) {
|
|
||||||
expression.statements.forEach { it.accept(this, data) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Any?) {
|
|
||||||
result = result ?: expression
|
|
||||||
}
|
|
||||||
}, null)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun changeIrConstructorToIrFunction(context: JsIrBackendContext, container: IrConstructor) {
|
|
||||||
val newConstructor = context.irFactory.buildFun {
|
|
||||||
name = Name.identifier("${container.parentAsClass.name}_constructor")
|
|
||||||
returnType = container.returnType
|
|
||||||
origin = JsIrBuilder.SYNTHESIZED_DECLARATION
|
|
||||||
}.apply {
|
|
||||||
parent = container.parent
|
|
||||||
container.valueParameters.forEach { param ->
|
|
||||||
addValueParameter(param.name.asString(), param.type, param.origin)
|
|
||||||
}
|
|
||||||
|
|
||||||
val parametersMap = container.valueParameters.zip(valueParameters).toMap()
|
|
||||||
body = container.body
|
|
||||||
transformChildren(object : IrElementTransformerVoid() {
|
|
||||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
|
||||||
val newParam = parametersMap[expression.symbol.owner]
|
|
||||||
return if (newParam != null) JsIrBuilder.buildGetValue(newParam.symbol) else expression
|
|
||||||
}
|
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
container.parentAsClass.declarations.transformInPlace {
|
|
||||||
if (it === container) newConstructor else it
|
|
||||||
}
|
|
||||||
|
|
||||||
context.mapping.secondaryConstructorToDelegate[container] = newConstructor
|
|
||||||
}
|
|
||||||
|
|||||||
+258
@@ -0,0 +1,258 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.ValueRemapper
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.JsAnnotations
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.MutableReference
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.irEmpty
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.mutableReferenceOf
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
|
||||||
|
|
||||||
|
const val CREATE_EXTERNAL_THIS_CONSTRUCTOR_PARAMETERS = 2
|
||||||
|
|
||||||
|
class ES6PrimaryConstructorOptimizationLowering(private val context: JsIrBackendContext) : DeclarationTransformer {
|
||||||
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
|
if (!context.es6mode || declaration !is IrFunction || !declaration.shouldBeConvertedToPlainConstructor(context)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val irClass = declaration.parentAsClass
|
||||||
|
|
||||||
|
if (irClass.isExported(context)) {
|
||||||
|
irClass.removeConstructorForExport()
|
||||||
|
}
|
||||||
|
|
||||||
|
return listOf(declaration.convertToRegularConstructor(irClass))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunction.convertToRegularConstructor(irClass: IrClass): IrConstructor {
|
||||||
|
val original = this
|
||||||
|
val superClass = irClass.superClass
|
||||||
|
val classThisSymbol = irClass.thisReceiver!!.symbol
|
||||||
|
|
||||||
|
return factory.buildConstructor {
|
||||||
|
updateFrom(original)
|
||||||
|
isPrimary = true
|
||||||
|
returnType = original.returnType
|
||||||
|
origin = IrDeclarationOrigin.DEFINED
|
||||||
|
}.also { constructor ->
|
||||||
|
constructor.copyAnnotationsFrom(original)
|
||||||
|
constructor.copyParameterDeclarationsFrom(original)
|
||||||
|
constructor.parent = irClass
|
||||||
|
|
||||||
|
if (irClass.isExported(context)) {
|
||||||
|
constructor.annotations = original.annotations.withoutFirst { it.isAnnotation(JsAnnotations.jsExportIgnoreFqn) }
|
||||||
|
}
|
||||||
|
|
||||||
|
val boxParameter = constructor.boxParameter
|
||||||
|
val body = (original.body?.deepCopyWithSymbols(constructor) as IrBlockBody)
|
||||||
|
.also { constructor.body = it }
|
||||||
|
|
||||||
|
body.transformChildrenVoid(object : ValueRemapper(emptyMap()) {
|
||||||
|
override val map = original.valueParameters.zip(constructor.valueParameters)
|
||||||
|
.associate { it.first.symbol to it.second.symbol }
|
||||||
|
.toMutableMap<IrValueSymbol, IrValueSymbol>()
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||||
|
return if (expression.returnTargetSymbol == original.symbol) {
|
||||||
|
return irEmpty(context)
|
||||||
|
} else {
|
||||||
|
super.visitReturn(expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
return if (expression.symbol == context.intrinsics.jsBoxApplySymbol) {
|
||||||
|
irEmpty(context)
|
||||||
|
} else {
|
||||||
|
super.visitCall(expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitVariable(declaration: IrVariable): IrStatement {
|
||||||
|
val initializer = declaration.initializer
|
||||||
|
|
||||||
|
if (initializer is IrCall) {
|
||||||
|
when {
|
||||||
|
initializer.isSyntheticDelegatingReplacement -> {
|
||||||
|
map[declaration.symbol] = classThisSymbol
|
||||||
|
return super.visitCall(initializer)
|
||||||
|
}
|
||||||
|
initializer.symbol == context.intrinsics.jsCreateThisSymbol -> {
|
||||||
|
map[declaration.symbol] = classThisSymbol
|
||||||
|
|
||||||
|
return if (boxParameter != null && superClass == null) {
|
||||||
|
super.visitCall(JsIrBuilder.buildCall(context.intrinsics.jsBoxApplySymbol).apply {
|
||||||
|
putValueArgument(0, JsIrBuilder.buildGetValue(irClass.thisReceiver!!.symbol))
|
||||||
|
putValueArgument(1, JsIrBuilder.buildGetValue(boxParameter.symbol))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
irEmpty(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initializer.symbol == context.intrinsics.jsCreateExternalThisSymbol -> {
|
||||||
|
map[declaration.symbol] = classThisSymbol
|
||||||
|
|
||||||
|
val externalConstructor =
|
||||||
|
superClass?.primaryConstructor?.symbol ?: error("Expect to have external constructor here")
|
||||||
|
val parameters = initializer.getValueArgument(CREATE_EXTERNAL_THIS_CONSTRUCTOR_PARAMETERS) as? IrVararg
|
||||||
|
?: error("Wrong type of argument was provided")
|
||||||
|
|
||||||
|
return JsIrBuilder.buildDelegatingConstructorCall(externalConstructor).apply {
|
||||||
|
parameters.elements.forEachIndexed { i, it -> putValueArgument(i, it as IrExpression) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.visitVariable(declaration)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrClass.removeConstructorForExport() {
|
||||||
|
declarations.removeIf { it is IrConstructor }
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <T> Iterable<T>.withoutFirst(predicate: (T) -> Boolean): List<T> {
|
||||||
|
val original = this
|
||||||
|
return buildList {
|
||||||
|
var isFirstMatch = true
|
||||||
|
for (element in original) {
|
||||||
|
if (!isFirstMatch || !predicate(element)) {
|
||||||
|
add(element)
|
||||||
|
} else {
|
||||||
|
isFirstMatch = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ES6PrimaryConstructorUsageOptimizationLowering(private val context: JsIrBackendContext) : BodyLoweringPass {
|
||||||
|
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||||
|
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
val callee = expression.symbol.owner
|
||||||
|
return when {
|
||||||
|
!callee.shouldBeConvertedToPlainConstructor(context) -> super.visitCall(expression)
|
||||||
|
expression.isSyntheticDelegatingReplacement -> {
|
||||||
|
super.visitDelegatingConstructorCall(JsIrBuilder.buildDelegatingConstructorCall(callee.parentAsClass.primaryConstructor!!.symbol)
|
||||||
|
.apply { copyTypeAndValueArgumentsFrom(expression) })
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
super.visitConstructorCall(JsIrBuilder.buildConstructorCall(callee.parentAsClass.primaryConstructor!!.symbol)
|
||||||
|
.apply { copyTypeAndValueArgumentsFrom(expression) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When we can't optimize class hierarchy chain if there is a class inside which:
|
||||||
|
* 1. Has primary constructor which delegates to a secondary
|
||||||
|
* 2. Has secondary constructor which delegates to a primary
|
||||||
|
* 3. Has a constructor with a box parameter, and it has an external superclass
|
||||||
|
* 4. Is a subtype for Throwable, because we replace the super call inside constructors with `setPropertiesToThrowableInstance` call
|
||||||
|
* Otherwise, we can generate a simple ES-class constructor in each class of the hierarchy
|
||||||
|
*/
|
||||||
|
class ES6CollectPrimaryConstructorsWhichCouldBeOptimizedLowering(private val context: JsIrBackendContext) : DeclarationTransformer {
|
||||||
|
private val esClassWhichNeedBoxParameters = context.mapping.esClassWhichNeedBoxParameters
|
||||||
|
private val esClassToPossibilityForOptimization = context.mapping.esClassToPossibilityForOptimization
|
||||||
|
|
||||||
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
|
if (
|
||||||
|
context.es6mode &&
|
||||||
|
declaration is IrClass &&
|
||||||
|
!declaration.isExternal &&
|
||||||
|
!context.inlineClassesUtils.isClassInlineLike(declaration) &&
|
||||||
|
!esClassToPossibilityForOptimization.contains(declaration)
|
||||||
|
) {
|
||||||
|
declaration.checkIfCanBeOptimized()
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrClass.checkIfCanBeOptimized() {
|
||||||
|
var currentClass: IrClass? = this
|
||||||
|
var nearestOptimizationDecision: MutableReference<Boolean>? = null
|
||||||
|
|
||||||
|
while (currentClass != null && !currentClass.isExternal) {
|
||||||
|
val currentClassOptimizationDecision = esClassToPossibilityForOptimization[currentClass]
|
||||||
|
|
||||||
|
if (currentClassOptimizationDecision != null) {
|
||||||
|
nearestOptimizationDecision = currentClassOptimizationDecision
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
currentClass = currentClass.superClass
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nearestOptimizationDecision == null) {
|
||||||
|
nearestOptimizationDecision = mutableReferenceOf(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentClass = this
|
||||||
|
while (currentClass != null && !currentClass.isExternal && !esClassToPossibilityForOptimization.contains(currentClass)) {
|
||||||
|
esClassToPossibilityForOptimization[currentClass] = nearestOptimizationDecision
|
||||||
|
|
||||||
|
if (nearestOptimizationDecision.value && !currentClass.canBeOptimized()) {
|
||||||
|
nearestOptimizationDecision.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
currentClass = currentClass.superClass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrClass.canBeOptimized(): Boolean {
|
||||||
|
return superClass?.symbol != context.throwableClass && !isSubclassOfExternalClassWithRequiredBoxParameter() && !hasPrimaryDelegatedToSecondaryOrSecondaryToPrimary()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrClass.hasPrimaryDelegatedToSecondaryOrSecondaryToPrimary(): Boolean {
|
||||||
|
declarations
|
||||||
|
.filterIsInstanceAnd<IrFunction> { it.isEs6ConstructorReplacement }
|
||||||
|
.forEach {
|
||||||
|
var meetUnoptimizedDelegation = false
|
||||||
|
it.body?.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
if (expression.isSyntheticDelegatingReplacement && expression.symbol.owner.origin != it.origin) {
|
||||||
|
meetUnoptimizedDelegation = true
|
||||||
|
}
|
||||||
|
return super.visitCall(expression)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (meetUnoptimizedDelegation) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrClass.isSubclassOfExternalClassWithRequiredBoxParameter(): Boolean {
|
||||||
|
return superClass?.isExternal == true && esClassWhichNeedBoxParameters.contains(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrFunction.shouldBeConvertedToPlainConstructor(context: JsIrBackendContext): Boolean {
|
||||||
|
return isEs6PrimaryConstructorReplacement && context.mapping.esClassToPossibilityForOptimization[parentAsClass]?.value == true
|
||||||
|
}
|
||||||
+2
-3
@@ -6,11 +6,10 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.isJsImplicitExport
|
import org.jetbrains.kotlin.ir.backend.js.utils.isJsImplicitExport
|
||||||
import org.jetbrains.kotlin.ir.builders.irCall
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
@@ -86,7 +85,7 @@ class ImplicitlyExportedDeclarationsMarkingLowering(private val context: JsIrBac
|
|||||||
|
|
||||||
private fun IrDeclaration.markWithJsImplicitExport() {
|
private fun IrDeclaration.markWithJsImplicitExport() {
|
||||||
val jsImplicitExportCtor = context.intrinsics.jsImplicitExportAnnotationSymbol.constructors.single()
|
val jsImplicitExportCtor = context.intrinsics.jsImplicitExportAnnotationSymbol.constructors.single()
|
||||||
annotations += context.createIrBuilder(symbol).irCall(jsImplicitExportCtor)
|
annotations += JsIrBuilder.buildConstructorCall(jsImplicitExportCtor)
|
||||||
|
|
||||||
parentClassOrNull?.takeIf { it.shouldBeMarkedWithImplicitExport() }?.markWithJsImplicitExport()
|
parentClassOrNull?.takeIf { it.shouldBeMarkedWithImplicitExport() }?.markWithJsImplicitExport()
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-5
@@ -11,6 +11,7 @@ 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.JsStatementOrigins
|
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||||
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.jsConstructorReference
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
@@ -44,7 +45,7 @@ class JsClassUsageInReflectionLowering(val backendContext: JsIrBackendContext) :
|
|||||||
|
|
||||||
private fun IrClassReference.generateDirectValueUsage(): IrExpression? {
|
private fun IrClassReference.generateDirectValueUsage(): IrExpression? {
|
||||||
return with(backendContext) {
|
return with(backendContext) {
|
||||||
when(val classSymbol = symbol as? IrClassSymbol ?: return null) {
|
when (val classSymbol = symbol as? IrClassSymbol ?: return null) {
|
||||||
irBuiltIns.nothingClass -> null
|
irBuiltIns.nothingClass -> null
|
||||||
irBuiltIns.anyClass ->
|
irBuiltIns.anyClass ->
|
||||||
JsIrBuilder.buildCall(intrinsics.jsCode).apply {
|
JsIrBuilder.buildCall(intrinsics.jsCode).apply {
|
||||||
@@ -59,10 +60,7 @@ class JsClassUsageInReflectionLowering(val backendContext: JsIrBackendContext) :
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
else ->
|
else -> classSymbol.owner.jsConstructorReference(backendContext)
|
||||||
JsIrBuilder.buildCall(intrinsics.jsClass, origin = JsStatementOrigins.CLASS_REFERENCE).apply {
|
|
||||||
putTypeArgument(0, classSymbol.owner.defaultType)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-13
@@ -17,13 +17,11 @@ import org.jetbrains.kotlin.ir.backend.js.utils.JsAnnotations
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
|
||||||
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.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||||
|
|
||||||
@@ -72,18 +70,13 @@ class JsDefaultArgumentStubGenerator(override val context: JsIrBackendContext) :
|
|||||||
?.also { new -> variables[param] = new } ?: param
|
?.also { new -> variables[param] = new } ?: param
|
||||||
}
|
}
|
||||||
|
|
||||||
val defaultResolutionStatements = valueParameters.mapNotNull {
|
val blockBody = body as? IrBlockBody
|
||||||
irBuilder.createResolutionStatement(it, it.defaultValue?.expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (variables.isNotEmpty()) {
|
|
||||||
body?.transformChildren(VariableRemapper(variables), null)
|
|
||||||
|
|
||||||
body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
|
||||||
statements += defaultResolutionStatements
|
|
||||||
statements += body?.statements ?: emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (blockBody != null && variables.isNotEmpty()) {
|
||||||
|
blockBody.transformChildren(VariableRemapper(variables), null)
|
||||||
|
blockBody.statements.addAll(0, valueParameters.mapNotNull {
|
||||||
|
irBuilder.createResolutionStatement(it, it.defaultValue?.expression)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return also {
|
return also {
|
||||||
|
|||||||
+2
-13
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.jsConstructorReference
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
@@ -91,19 +92,7 @@ class JsDefaultParameterInjector(override val context: JsIrBackendContext) :
|
|||||||
0,
|
0,
|
||||||
1
|
1
|
||||||
).apply {
|
).apply {
|
||||||
putValueArgument(
|
putValueArgument(0, owner.jsConstructorReference(context))
|
||||||
0,
|
|
||||||
IrCallImpl(
|
|
||||||
UNDEFINED_OFFSET,
|
|
||||||
UNDEFINED_OFFSET,
|
|
||||||
context.dynamicType,
|
|
||||||
context.intrinsics.jsClass,
|
|
||||||
1,
|
|
||||||
0
|
|
||||||
).apply {
|
|
||||||
putTypeArgument(0, owner.defaultType)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.lower.InnerClassesSupport
|
|||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsMapping
|
import org.jetbrains.kotlin.ir.backend.js.JsMapping
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder.SYNTHESIZED_DECLARATION
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder.SYNTHESIZED_DECLARATION
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||||
@@ -41,7 +42,7 @@ class JsInnerClassesSupport(mapping: JsMapping, private val irFactory: IrFactory
|
|||||||
|
|
||||||
irFactory.buildField {
|
irFactory.buildField {
|
||||||
origin = IrDeclarationOrigin.FIELD_FOR_OUTER_THIS
|
origin = IrDeclarationOrigin.FIELD_FOR_OUTER_THIS
|
||||||
name = Name.identifier("\$this")
|
name = Name.identifier(Namer.SYNTHETIC_RECEIVER_NAME)
|
||||||
type = outerClass.defaultType
|
type = outerClass.defaultType
|
||||||
visibility = DescriptorVisibilities.PROTECTED
|
visibility = DescriptorVisibilities.PROTECTED
|
||||||
isFinal = true
|
isFinal = true
|
||||||
|
|||||||
+51
-28
@@ -12,15 +12,19 @@ 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.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
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.JsCommonBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||||
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.getVoid
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||||
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.symbols.IrFieldSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
@@ -28,9 +32,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
class ObjectDeclarationLowering(
|
class ObjectDeclarationLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||||
val context: JsCommonBackendContext
|
|
||||||
) : DeclarationTransformer {
|
|
||||||
|
|
||||||
private var IrClass.instanceField by context.mapping.objectToInstanceField
|
private var IrClass.instanceField by context.mapping.objectToInstanceField
|
||||||
private var IrClass.syntheticPrimaryConstructor by context.mapping.classToSyntheticPrimaryConstructor
|
private var IrClass.syntheticPrimaryConstructor by context.mapping.classToSyntheticPrimaryConstructor
|
||||||
@@ -39,7 +41,6 @@ class ObjectDeclarationLowering(
|
|||||||
* If the object being lowered is nested inside an enum class, we want to also initialize the enum entries when initializing the object.
|
* If the object being lowered is nested inside an enum class, we want to also initialize the enum entries when initializing the object.
|
||||||
*/
|
*/
|
||||||
private var IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun
|
private var IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun
|
||||||
|
|
||||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
if (declaration !is IrClass || declaration.kind != ClassKind.OBJECT || declaration.isEffectivelyExternal())
|
if (declaration !is IrClass || declaration.kind != ClassKind.OBJECT || declaration.isEffectivelyExternal())
|
||||||
return null
|
return null
|
||||||
@@ -67,7 +68,7 @@ class ObjectDeclarationLowering(
|
|||||||
if (initEntryInstancesFun != null)
|
if (initEntryInstancesFun != null)
|
||||||
+irCall(initEntryInstancesFun)
|
+irCall(initEntryInstancesFun)
|
||||||
+irIfThen(
|
+irIfThen(
|
||||||
irEqualsNull(irGetField(null, instanceField)),
|
irNullabilityCheck(instanceField),
|
||||||
// Instance field initialized inside constructor
|
// Instance field initialized inside constructor
|
||||||
irCallConstructor(primaryConstructor.symbol, emptyList())
|
irCallConstructor(primaryConstructor.symbol, emptyList())
|
||||||
)
|
)
|
||||||
@@ -77,35 +78,30 @@ class ObjectDeclarationLowering(
|
|||||||
|
|
||||||
return listOf(declaration, instanceField, getInstanceFun)
|
return listOf(declaration, instanceField, getInstanceFun)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrBuilderWithScope.irNullabilityCheck(instanceField: IrField): IrExpression {
|
||||||
|
val context = this@ObjectDeclarationLowering.context
|
||||||
|
return if (context is JsIrBackendContext && context.es6mode) {
|
||||||
|
irEqeqeqWithoutBox(irGetField(null, instanceField), context.getVoid())
|
||||||
|
} else {
|
||||||
|
irEqualsNull(irGetField(null, instanceField))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ObjectUsageLowering(
|
class ObjectUsageLowering(val context: JsCommonBackendContext) : BodyLoweringPass {
|
||||||
val context: JsCommonBackendContext
|
|
||||||
) : BodyLoweringPass {
|
|
||||||
|
|
||||||
private var IrClass.instanceField by context.mapping.objectToInstanceField
|
private var IrClass.instanceField by context.mapping.objectToInstanceField
|
||||||
|
|
||||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||||
if (container is IrConstructor && container.isPrimary) {
|
val functionContainer = container.takeIf { it is IrConstructor && it.isPrimary }
|
||||||
val irClass = container.parentAsClass
|
val irClass = functionContainer?.parentAsClass
|
||||||
irClass.instanceField?.let { instanceField ->
|
|
||||||
// Initialize instance field in the beginning of the constructor because it can be used inside the constructor later
|
irClass?.instanceField?.let {
|
||||||
val initInstanceField = context.createIrBuilder(container.symbol).buildStatement(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
if (context.es6mode && irClass.superClass == null) return@let
|
||||||
irSetField(null, instanceField, irGet(irClass.thisReceiver!!))
|
// Initialize instance field in the beginning of the constructor because it can be used inside the constructor later
|
||||||
}
|
val initInstanceField = generateInitInstanceField(it, irClass.getValueForInstanceFieldForTheFirstTime())
|
||||||
if (context.es6mode) {
|
(irBody as IrBlockBody).statements.add(0, initInstanceField)
|
||||||
//find `superCall` and put after
|
|
||||||
(irBody as IrBlockBody).statements.transformFlat {
|
|
||||||
if (it is IrDelegatingConstructorCall) listOf(it, initInstanceField)
|
|
||||||
else if (it is IrVariable && it.origin === ES6_THIS_VARIABLE_ORIGIN) {
|
|
||||||
initInstanceField.value = JsIrBuilder.buildGetValue(it.symbol)
|
|
||||||
listOf(it, initInstanceField)
|
|
||||||
} else null
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(irBody as IrBlockBody).statements.add(0, initInstanceField)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||||
@@ -114,8 +110,35 @@ class ObjectUsageLowering(
|
|||||||
if (obj.isEffectivelyExternal()) return expression
|
if (obj.isEffectivelyExternal()) return expression
|
||||||
return JsIrBuilder.buildCall(context.getOrCreateGetInstanceFunction(obj).symbol)
|
return JsIrBuilder.buildCall(context.getOrCreateGetInstanceFunction(obj).symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||||
|
val instanceField = irClass?.instanceField
|
||||||
|
return if (!context.es6mode || instanceField == null) {
|
||||||
|
super.visitDelegatingConstructorCall(expression)
|
||||||
|
} else {
|
||||||
|
JsIrBuilder.buildComposite(
|
||||||
|
context.irBuiltIns.unitType,
|
||||||
|
listOf(
|
||||||
|
super.visitDelegatingConstructorCall(expression),
|
||||||
|
generateInitInstanceField(instanceField, JsIrBuilder.buildGetValue(irClass.thisReceiver!!.symbol))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrClass.getValueForInstanceFieldForTheFirstTime(): IrExpression {
|
||||||
|
return if (context.es6mode && context is JsIrBackendContext) {
|
||||||
|
JsIrBuilder.buildNull(thisReceiver!!.type)
|
||||||
|
} else {
|
||||||
|
JsIrBuilder.buildGetValue(thisReceiver!!.symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateInitInstanceField(instanceField: IrField, value: IrExpression): IrStatement {
|
||||||
|
return JsIrBuilder.buildSetField(instanceField.symbol, null, value, context.irBuiltIns.unitType)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun JsCommonBackendContext.getOrCreateGetInstanceFunction(obj: IrClass) =
|
private fun JsCommonBackendContext.getOrCreateGetInstanceFunction(obj: IrClass) =
|
||||||
|
|||||||
+5
-2
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.lower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||||
@@ -17,18 +18,20 @@ import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
|
|||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
import org.jetbrains.kotlin.ir.util.constructors
|
||||||
import org.jetbrains.kotlin.ir.util.isInterface
|
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
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
|
||||||
|
|
||||||
|
val IrDeclaration.isSyntheticPrimaryConstructor: Boolean
|
||||||
|
get() = origin == PrimaryConstructorLowering.SYNTHETIC_PRIMARY_CONSTRUCTOR
|
||||||
|
|
||||||
// Create primary constructor if it doesn't exist
|
// Create primary constructor if it doesn't exist
|
||||||
class PrimaryConstructorLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
class PrimaryConstructorLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||||
|
|
||||||
private var IrClass.syntheticPrimaryConstructor by context.mapping.classToSyntheticPrimaryConstructor
|
private var IrClass.syntheticPrimaryConstructor by context.mapping.classToSyntheticPrimaryConstructor
|
||||||
|
|
||||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
if (declaration is IrClass && !declaration.isInterface) {
|
if (declaration is IrClass && declaration.kind != ClassKind.INTERFACE) {
|
||||||
val constructors = declaration.constructors
|
val constructors = declaration.constructors
|
||||||
|
|
||||||
if (constructors.any { it.isPrimary }) return null
|
if (constructors.any { it.isPrimary }) return null
|
||||||
|
|||||||
+16
-29
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.ir.backend.js.lower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||||
import org.jetbrains.kotlin.backend.common.compilationException
|
|
||||||
import org.jetbrains.kotlin.backend.common.getOrPut
|
import org.jetbrains.kotlin.backend.common.getOrPut
|
||||||
import org.jetbrains.kotlin.backend.common.ir.ValueRemapper
|
import org.jetbrains.kotlin.backend.common.ir.ValueRemapper
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
@@ -33,6 +32,7 @@ import org.jetbrains.kotlin.ir.util.*
|
|||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
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.utils.addToStdlib.runIf
|
||||||
|
|
||||||
class SecondaryConstructorLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
class SecondaryConstructorLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||||
|
|
||||||
@@ -234,6 +234,7 @@ private fun JsIrBackendContext.buildConstructorFactory(constructor: IrConstructo
|
|||||||
class SecondaryFactoryInjectorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
class SecondaryFactoryInjectorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||||
|
|
||||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||||
|
if (context.es6mode) return
|
||||||
// TODO Simplify? Is this needed at all?
|
// TODO Simplify? Is this needed at all?
|
||||||
var parentFunction: IrFunction? = container as? IrFunction
|
var parentFunction: IrFunction? = container as? IrFunction
|
||||||
var declaration = container
|
var declaration = container
|
||||||
@@ -266,14 +267,7 @@ private class CallsiteRedirectionTransformer(private val context: JsIrBackendCon
|
|||||||
|
|
||||||
val target = expression.symbol.owner
|
val target = expression.symbol.owner
|
||||||
return if (target.isSecondaryConstructorCall) {
|
return if (target.isSecondaryConstructorCall) {
|
||||||
val factory = with(context) {
|
val factory = context.buildConstructorFactory(target, target.parentAsClass)
|
||||||
if (es6mode) mapping.secondaryConstructorToDelegate[target]
|
|
||||||
?: compilationException(
|
|
||||||
"Not found IrFunction for secondary ctor",
|
|
||||||
expression
|
|
||||||
)
|
|
||||||
else buildConstructorFactory(target, target.parentAsClass)
|
|
||||||
}
|
|
||||||
replaceSecondaryConstructorWithFactoryFunction(expression, factory.symbol)
|
replaceSecondaryConstructorWithFactoryFunction(expression, factory.symbol)
|
||||||
} else expression
|
} else expression
|
||||||
}
|
}
|
||||||
@@ -285,18 +279,8 @@ private class CallsiteRedirectionTransformer(private val context: JsIrBackendCon
|
|||||||
|
|
||||||
return if (target.isSecondaryConstructorCall) {
|
return if (target.isSecondaryConstructorCall) {
|
||||||
val klass = target.parentAsClass
|
val klass = target.parentAsClass
|
||||||
val delegate = with(context) {
|
val delegate = context.buildConstructorDelegate(target, klass)
|
||||||
if (es6mode) mapping.secondaryConstructorToDelegate[target]
|
|
||||||
?: compilationException(
|
|
||||||
"Not found IrFunction for secondary ctor",
|
|
||||||
expression
|
|
||||||
)
|
|
||||||
else buildConstructorDelegate(target, klass)
|
|
||||||
}
|
|
||||||
val newCall = replaceSecondaryConstructorWithFactoryFunction(expression, delegate.symbol)
|
val newCall = replaceSecondaryConstructorWithFactoryFunction(expression, delegate.symbol)
|
||||||
if (context.es6mode) {
|
|
||||||
return newCall
|
|
||||||
}
|
|
||||||
|
|
||||||
val readThis = expression.run {
|
val readThis = expression.run {
|
||||||
if (data is IrConstructor) {
|
if (data is IrConstructor) {
|
||||||
@@ -315,16 +299,19 @@ private class CallsiteRedirectionTransformer(private val context: JsIrBackendCon
|
|||||||
private fun replaceSecondaryConstructorWithFactoryFunction(
|
private fun replaceSecondaryConstructorWithFactoryFunction(
|
||||||
call: IrFunctionAccessExpression,
|
call: IrFunctionAccessExpression,
|
||||||
newTarget: IrSimpleFunctionSymbol
|
newTarget: IrSimpleFunctionSymbol
|
||||||
) = IrCallImpl(
|
): IrCall {
|
||||||
call.startOffset, call.endOffset, call.type, newTarget,
|
val irClass = call.symbol.owner.parentAsClass
|
||||||
typeArgumentsCount = call.typeArgumentsCount,
|
return IrCallImpl(
|
||||||
valueArgumentsCount = newTarget.owner.valueParameters.size
|
call.startOffset, call.endOffset, call.type, newTarget,
|
||||||
).apply {
|
typeArgumentsCount = call.typeArgumentsCount,
|
||||||
|
valueArgumentsCount = newTarget.owner.valueParameters.size,
|
||||||
|
superQualifierSymbol = irClass.symbol.takeIf { context.es6mode && call.isSyntheticDelegatingReplacement }
|
||||||
|
).apply {
|
||||||
|
copyTypeArgumentsFrom(call)
|
||||||
|
|
||||||
copyTypeArgumentsFrom(call)
|
for (i in 0 until call.valueArgumentsCount) {
|
||||||
|
putValueArgument(i, call.getValueArgument(i))
|
||||||
for (i in 0 until call.valueArgumentsCount) {
|
}
|
||||||
putValueArgument(i, call.getValueArgument(i))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-8
@@ -6,8 +6,8 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
@@ -21,12 +21,7 @@ import org.jetbrains.kotlin.ir.util.*
|
|||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
|
|
||||||
|
|
||||||
class ThrowableLowering(
|
class ThrowableLowering(val context: JsIrBackendContext, val extendThrowableFunction: IrSimpleFunctionSymbol) : BodyLoweringPass {
|
||||||
val context: JsIrBackendContext,
|
|
||||||
val extendThrowableFunction: IrSimpleFunctionSymbol
|
|
||||||
) : BodyLoweringPass {
|
|
||||||
private val nothingNType = context.irBuiltIns.nothingNType
|
|
||||||
|
|
||||||
private val throwableConstructors = context.throwableConstructors
|
private val throwableConstructors = context.throwableConstructors
|
||||||
private val newThrowableFunction = context.newThrowableSymbol
|
private val newThrowableFunction = context.newThrowableSymbol
|
||||||
|
|
||||||
@@ -64,6 +59,8 @@ class ThrowableLowering(
|
|||||||
}
|
}
|
||||||
|
|
||||||
inner class Transformer : IrElementTransformer<IrDeclarationParent> {
|
inner class Transformer : IrElementTransformer<IrDeclarationParent> {
|
||||||
|
private val anyConstructor = context.irBuiltIns.anyClass.constructors.first()
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass, data: IrDeclarationParent) = super.visitClass(declaration, declaration)
|
override fun visitClass(declaration: IrClass, data: IrDeclarationParent) = super.visitClass(declaration, declaration)
|
||||||
|
|
||||||
override fun visitConstructorCall(expression: IrConstructorCall, data: IrDeclarationParent): IrExpression {
|
override fun visitConstructorCall(expression: IrConstructorCall, data: IrDeclarationParent): IrExpression {
|
||||||
@@ -93,7 +90,7 @@ class ThrowableLowering(
|
|||||||
val klass = data as IrClass
|
val klass = data as IrClass
|
||||||
val thisReceiver = IrGetValueImpl(expression.startOffset, expression.endOffset, klass.thisReceiver!!.symbol)
|
val thisReceiver = IrGetValueImpl(expression.startOffset, expression.endOffset, klass.thisReceiver!!.symbol)
|
||||||
|
|
||||||
return expression.run {
|
val expressionReplacement = expression.run {
|
||||||
IrCallImpl(
|
IrCallImpl(
|
||||||
startOffset, endOffset, type, extendThrowableFunction,
|
startOffset, endOffset, type, extendThrowableFunction,
|
||||||
valueArgumentsCount = 3,
|
valueArgumentsCount = 3,
|
||||||
@@ -104,6 +101,25 @@ class ThrowableLowering(
|
|||||||
it.putValueArgument(2, causeArg)
|
it.putValueArgument(2, causeArg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return if (!context.es6mode) {
|
||||||
|
expressionReplacement
|
||||||
|
} else {
|
||||||
|
JsIrBuilder.buildComposite(
|
||||||
|
context.irBuiltIns.unitType,
|
||||||
|
listOf(
|
||||||
|
IrDelegatingConstructorCallImpl(
|
||||||
|
expression.startOffset,
|
||||||
|
expression.endOffset,
|
||||||
|
context.irBuiltIns.anyType,
|
||||||
|
anyConstructor,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
expressionReplacement
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||||
|
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.dce.eliminateDeadDeclarations
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
|
|
||||||
|
fun optimizeProgramByIr(
|
||||||
|
modules: Iterable<IrModuleFragment>,
|
||||||
|
context: JsIrBackendContext,
|
||||||
|
removeUnusedAssociatedObjects: Boolean
|
||||||
|
) {
|
||||||
|
eliminateDeadDeclarations(modules, context, removeUnusedAssociatedObjects)
|
||||||
|
jsOptimizationPhases.invokeToplevel(PhaseConfig(jsOptimizationPhases), context, modules)
|
||||||
|
}
|
||||||
+1
-1
@@ -166,7 +166,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
}
|
}
|
||||||
|
|
||||||
return if (context.staticContext.backendContext.es6mode) {
|
return if (context.staticContext.backendContext.es6mode) {
|
||||||
JsInvocation(JsNameRef("super"), arguments)
|
JsInvocation(JsSuperRef(), arguments)
|
||||||
} else {
|
} else {
|
||||||
JsInvocation(callFuncRef, listOf(thisRef) + arguments)
|
JsInvocation(callFuncRef, listOf(thisRef) + arguments)
|
||||||
}.withSource(expression, context)
|
}.withSource(expression, context)
|
||||||
|
|||||||
+5
-1
@@ -65,7 +65,11 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitComposite(expression: IrComposite, context: JsGenerationContext): JsStatement {
|
override fun visitComposite(expression: IrComposite, context: JsGenerationContext): JsStatement {
|
||||||
return JsBlock(expression.statements.map { it.accept(this, context) }).withSource(expression, context)
|
return if (expression.statements.isEmpty()) {
|
||||||
|
JsEmpty
|
||||||
|
} else {
|
||||||
|
JsBlock(expression.statements.map { it.accept(this, context) }).withSource(expression, context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitExpression(expression: IrExpression, context: JsGenerationContext): JsStatement {
|
override fun visitExpression(expression: IrExpression, context: JsGenerationContext): JsStatement {
|
||||||
|
|||||||
+31
-27
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
|||||||
import org.jetbrains.kotlin.backend.common.serialization.checkIsFunctionInterface
|
import org.jetbrains.kotlin.backend.common.serialization.checkIsFunctionInterface
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
import org.jetbrains.kotlin.ir.backend.js.*
|
import org.jetbrains.kotlin.ir.backend.js.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.dce.eliminateDeadDeclarations
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.*
|
import org.jetbrains.kotlin.ir.backend.js.export.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.StaticMembersLowering
|
import org.jetbrains.kotlin.ir.backend.js.lower.StaticMembersLowering
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.isBuiltInClass
|
import org.jetbrains.kotlin.ir.backend.js.lower.isBuiltInClass
|
||||||
@@ -46,29 +45,33 @@ val IrModuleFragment.safeName: String
|
|||||||
get() = name.asString().safeModuleName
|
get() = name.asString().safeModuleName
|
||||||
|
|
||||||
enum class TranslationMode(
|
enum class TranslationMode(
|
||||||
val dce: Boolean,
|
val production: Boolean,
|
||||||
val perModule: Boolean,
|
val perModule: Boolean,
|
||||||
val minimizedMemberNames: Boolean,
|
val minimizedMemberNames: Boolean,
|
||||||
) {
|
) {
|
||||||
FULL(dce = false, perModule = false, minimizedMemberNames = false),
|
FULL_DEV(production = false, perModule = false, minimizedMemberNames = false),
|
||||||
FULL_DCE(dce = true, perModule = false, minimizedMemberNames = false),
|
FULL_PROD(production = true, perModule = false, minimizedMemberNames = false),
|
||||||
FULL_DCE_MINIMIZED_NAMES(dce = true, perModule = false, minimizedMemberNames = true),
|
FULL_PROD_MINIMIZED_NAMES(production = true, perModule = false, minimizedMemberNames = true),
|
||||||
PER_MODULE(dce = false, perModule = true, minimizedMemberNames = false),
|
PER_MODULE_DEV(production = false, perModule = true, minimizedMemberNames = false),
|
||||||
PER_MODULE_DCE(dce = true, perModule = true, minimizedMemberNames = false),
|
PER_MODULE_PROD(production = true, perModule = true, minimizedMemberNames = false),
|
||||||
PER_MODULE_DCE_MINIMIZED_NAMES(dce = true, perModule = true, minimizedMemberNames = true);
|
PER_MODULE_PROD_MINIMIZED_NAMES(production = true, perModule = true, minimizedMemberNames = true);
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromFlags(dce: Boolean, perModule: Boolean, minimizedMemberNames: Boolean): TranslationMode {
|
fun fromFlags(
|
||||||
|
production: Boolean,
|
||||||
|
perModule: Boolean,
|
||||||
|
minimizedMemberNames: Boolean
|
||||||
|
): TranslationMode {
|
||||||
return if (perModule) {
|
return if (perModule) {
|
||||||
if (dce) {
|
if (production) {
|
||||||
if (minimizedMemberNames) PER_MODULE_DCE_MINIMIZED_NAMES
|
if (minimizedMemberNames) PER_MODULE_PROD_MINIMIZED_NAMES
|
||||||
else PER_MODULE_DCE
|
else PER_MODULE_PROD
|
||||||
} else PER_MODULE
|
} else PER_MODULE_DEV
|
||||||
} else {
|
} else {
|
||||||
if (dce) {
|
if (production) {
|
||||||
if (minimizedMemberNames) FULL_DCE_MINIMIZED_NAMES
|
if (minimizedMemberNames) FULL_PROD_MINIMIZED_NAMES
|
||||||
else FULL_DCE
|
else FULL_PROD
|
||||||
} else FULL
|
} else FULL_DEV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,15 +149,15 @@ class IrModuleToJsTransformer(
|
|||||||
|
|
||||||
val result = EnumMap<TranslationMode, CompilationOutputs>(TranslationMode::class.java)
|
val result = EnumMap<TranslationMode, CompilationOutputs>(TranslationMode::class.java)
|
||||||
|
|
||||||
modes.filter { !it.dce }.forEach {
|
modes.filter { !it.production }.forEach {
|
||||||
result[it] = makeJsCodeGeneratorFromIr(exportData, it).generateJsCode(relativeRequirePath, true)
|
result[it] = makeJsCodeGeneratorFromIr(exportData, it).generateJsCode(relativeRequirePath, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modes.any { it.dce }) {
|
if (modes.any { it.production }) {
|
||||||
eliminateDeadDeclarations(modules, backendContext, removeUnusedAssociatedObjects)
|
optimizeProgramByIr(modules, backendContext, removeUnusedAssociatedObjects)
|
||||||
}
|
}
|
||||||
|
|
||||||
modes.filter { it.dce }.forEach {
|
modes.filter { it.production }.forEach {
|
||||||
result[it] = makeJsCodeGeneratorFromIr(exportData, it).generateJsCode(relativeRequirePath, true)
|
result[it] = makeJsCodeGeneratorFromIr(exportData, it).generateJsCode(relativeRequirePath, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,8 +168,8 @@ class IrModuleToJsTransformer(
|
|||||||
val exportData = associateIrAndExport(modules)
|
val exportData = associateIrAndExport(modules)
|
||||||
doStaticMembersLowering(modules)
|
doStaticMembersLowering(modules)
|
||||||
|
|
||||||
if (mode.dce) {
|
if (mode.production) {
|
||||||
eliminateDeadDeclarations(modules, backendContext, removeUnusedAssociatedObjects)
|
optimizeProgramByIr(modules, backendContext, removeUnusedAssociatedObjects)
|
||||||
}
|
}
|
||||||
|
|
||||||
return makeJsCodeGeneratorFromIr(exportData, mode)
|
return makeJsCodeGeneratorFromIr(exportData, mode)
|
||||||
@@ -242,8 +245,12 @@ class IrModuleToJsTransformer(
|
|||||||
|
|
||||||
val internalModuleName = ReservedJsNames.makeInternalModuleName().takeIf { !isEsModules }
|
val internalModuleName = ReservedJsNames.makeInternalModuleName().takeIf { !isEsModules }
|
||||||
val globalNames = NameTable<String>(globalNameScope)
|
val globalNames = NameTable<String>(globalNameScope)
|
||||||
|
|
||||||
|
val statements = result.declarations.statements
|
||||||
|
val fileStatements = fileExports.file.accept(IrFileToJsTransformer(useBareParameterNames = true), staticContext).statements
|
||||||
|
|
||||||
val exportStatements =
|
val exportStatements =
|
||||||
ExportModelToJsStatements(staticContext, { globalNames.declareFreshName(it, it) }).generateModuleExport(
|
ExportModelToJsStatements(staticContext, backendContext.es6mode, { globalNames.declareFreshName(it, it) }).generateModuleExport(
|
||||||
ExportedModule(mainModuleName, moduleKind, fileExports.exports),
|
ExportedModule(mainModuleName, moduleKind, fileExports.exports),
|
||||||
internalModuleName,
|
internalModuleName,
|
||||||
isEsModules
|
isEsModules
|
||||||
@@ -252,9 +259,6 @@ class IrModuleToJsTransformer(
|
|||||||
result.exports.statements += exportStatements
|
result.exports.statements += exportStatements
|
||||||
result.dts = fileExports.tsDeclarations
|
result.dts = fileExports.tsDeclarations
|
||||||
|
|
||||||
val statements = result.declarations.statements
|
|
||||||
|
|
||||||
val fileStatements = fileExports.file.accept(IrFileToJsTransformer(useBareParameterNames = true), staticContext).statements
|
|
||||||
if (fileStatements.isNotEmpty()) {
|
if (fileStatements.isNotEmpty()) {
|
||||||
var startComment = ""
|
var startComment = ""
|
||||||
|
|
||||||
|
|||||||
+71
-47
@@ -6,39 +6,32 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.compilationException
|
import org.jetbrains.kotlin.backend.common.compilationException
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
|
||||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
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.export.isAllowedFakeOverriddenDeclaration
|
import org.jetbrains.kotlin.ir.backend.js.export.isAllowedFakeOverriddenDeclaration
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.isOverriddenExported
|
import org.jetbrains.kotlin.ir.backend.js.export.isOverriddenExported
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.isEs6ConstructorReplacement
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
import org.jetbrains.kotlin.ir.builders.irCall
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.common.isValidES5Identifier
|
import org.jetbrains.kotlin.js.common.isValidES5Identifier
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
|
||||||
|
|
||||||
class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationContext) {
|
class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationContext) {
|
||||||
private val className = context.getNameForClass(irClass)
|
private val className = context.getNameForClass(irClass)
|
||||||
private val classNameRef = className.makeRef()
|
private val classNameRef = className.makeRef()
|
||||||
private val baseClass: IrType? = irClass.superTypes.firstOrNull { !it.classifierOrFail.isInterface }
|
private val baseClass: IrType? = irClass.superTypes.firstOrNull { !it.classifierOrFail.isInterface }
|
||||||
|
|
||||||
|
private val classPrototypeRef by lazy { prototypeOf(classNameRef, context.staticContext) }
|
||||||
private val baseClassRef by lazy { // Lazy in case was not collected by namer during JsClassGenerator construction
|
private val baseClassRef by lazy { // Lazy in case was not collected by namer during JsClassGenerator construction
|
||||||
if (baseClass != null && !baseClass.isAny()) baseClass.getClassRef(context) else null
|
if (baseClass != null && !baseClass.isAny()) baseClass.getClassRef(context) else null
|
||||||
}
|
}
|
||||||
private val classPrototypeRef = prototypeOf(classNameRef, context.staticContext)
|
|
||||||
private val classBlock = JsCompositeBlock()
|
private val classBlock = JsCompositeBlock()
|
||||||
private val classModel = JsIrClassModel(irClass)
|
private val classModel = JsIrClassModel(irClass)
|
||||||
|
|
||||||
@@ -67,14 +60,9 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
when (declaration) {
|
when (declaration) {
|
||||||
is IrConstructor -> {
|
is IrConstructor -> {
|
||||||
if (es6mode) {
|
if (es6mode) {
|
||||||
declaration.accept(IrFunctionToJsTransformer(), context).let {
|
declaration.accept(IrFunctionToJsTransformer(), context).let { fn ->
|
||||||
//HACK: add superCall to Error
|
if (fn.body.statements.any { it !is JsEmpty && !it.isSimpleSuperCall(fn) }) {
|
||||||
if ((baseClass?.classifierOrNull?.owner as? IrClass)?.symbol === context.staticContext.backendContext.throwableClass) {
|
jsClass.constructor = fn
|
||||||
it.body.statements.add(0, JsInvocation(JsNameRef("super")).makeStmt())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it.body.statements.any { it !is JsEmpty }) {
|
|
||||||
jsClass.constructor = it
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -85,13 +73,15 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
properties.addIfNotNull(declaration.correspondingPropertySymbol?.owner)
|
properties.addIfNotNull(declaration.correspondingPropertySymbol?.owner)
|
||||||
|
|
||||||
if (es6mode) {
|
if (es6mode) {
|
||||||
val (memberRef, function) = generateMemberFunction(declaration)
|
if (declaration.isEs6ConstructorReplacement && irClass.isInterface) continue
|
||||||
function?.let { jsClass.members += it }
|
val (memberName, function) = generateMemberFunction(declaration)
|
||||||
declaration.generateAssignmentIfMangled(memberRef)
|
function?.let { jsClass.members += it.escapedIfNeed() }
|
||||||
|
declaration.generateAssignmentIfMangled(memberName)
|
||||||
} else {
|
} else {
|
||||||
val (memberRef, function) = generateMemberFunction(declaration)
|
val (memberName, function) = generateMemberFunction(declaration)
|
||||||
|
val memberRef = jsElementAccess(memberName, classPrototypeRef)
|
||||||
function?.let { classBlock.statements += jsAssignment(memberRef, it.apply { name = null }).makeStmt() }
|
function?.let { classBlock.statements += jsAssignment(memberRef, it.apply { name = null }).makeStmt() }
|
||||||
declaration.generateAssignmentIfMangled(memberRef)
|
declaration.generateAssignmentIfMangled(memberName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is IrClass -> {
|
is IrClass -> {
|
||||||
@@ -164,6 +154,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
getterOverridesExternal ||
|
getterOverridesExternal ||
|
||||||
property.getJsName() != null
|
property.getJsName() != null
|
||||||
) {
|
) {
|
||||||
|
val propertyName = context.getNameForProperty(property)
|
||||||
|
|
||||||
// Use "direct dispatch" for final properties, i. e. instead of this:
|
// Use "direct dispatch" for final properties, i. e. instead of this:
|
||||||
// Object.defineProperty(Foo.prototype, 'prop', {
|
// Object.defineProperty(Foo.prototype, 'prop', {
|
||||||
@@ -180,7 +171,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
|
|
||||||
val getterForwarder = property.getter
|
val getterForwarder = property.getter
|
||||||
.takeIf { it.shouldExportAccessor(context.staticContext.backendContext) }
|
.takeIf { it.shouldExportAccessor(context.staticContext.backendContext) }
|
||||||
.getOrGenerateIfFinal {
|
.getOrGenerateIfFinalOrEs6Mode {
|
||||||
propertyAccessorForwarder("getter forwarder") {
|
propertyAccessorForwarder("getter forwarder") {
|
||||||
JsReturn(JsInvocation(it))
|
JsReturn(JsInvocation(it))
|
||||||
}
|
}
|
||||||
@@ -188,7 +179,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
|
|
||||||
val setterForwarder = property.setter
|
val setterForwarder = property.setter
|
||||||
.takeIf { it.shouldExportAccessor(context.staticContext.backendContext) }
|
.takeIf { it.shouldExportAccessor(context.staticContext.backendContext) }
|
||||||
.getOrGenerateIfFinal {
|
.getOrGenerateIfFinalOrEs6Mode {
|
||||||
val setterArgName = JsName("value", false)
|
val setterArgName = JsName("value", false)
|
||||||
propertyAccessorForwarder("setter forwarder") {
|
propertyAccessorForwarder("setter forwarder") {
|
||||||
JsInvocation(it, JsNameRef(setterArgName)).makeStmt()
|
JsInvocation(it, JsNameRef(setterArgName)).makeStmt()
|
||||||
@@ -197,29 +188,37 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
classBlock.statements += JsExpressionStatement(
|
if (es6mode) {
|
||||||
defineProperty(
|
jsClass.members += listOfNotNull(
|
||||||
classPrototypeRef,
|
(getterForwarder as? JsFunction)?.apply {
|
||||||
context.getNameForProperty(property).ident,
|
name = propertyName
|
||||||
getter = getterForwarder,
|
modifiers.add(JsFunction.Modifier.GET)
|
||||||
setter = setterForwarder,
|
},
|
||||||
context.staticContext
|
(setterForwarder as? JsFunction)?.apply {
|
||||||
|
name = propertyName
|
||||||
|
modifiers.add(JsFunction.Modifier.SET)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
)
|
} else {
|
||||||
|
classBlock.statements += JsExpressionStatement(
|
||||||
|
defineProperty(classPrototypeRef, propertyName.ident, getterForwarder, setterForwarder, context.staticContext)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
classModel.preDeclarationBlock.statements += generateSetMetadataCall()
|
val metadataPlace = if (es6mode) classModel.postDeclarationBlock else classModel.preDeclarationBlock
|
||||||
|
|
||||||
|
metadataPlace.statements += generateSetMetadataCall()
|
||||||
context.staticContext.classModels[irClass.symbol] = classModel
|
context.staticContext.classModels[irClass.symbol] = classModel
|
||||||
|
|
||||||
return classBlock
|
return classBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun IrSimpleFunction?.getOrGenerateIfFinal(generateFunc: IrSimpleFunction.() -> JsFunction?): JsExpression? {
|
private inline fun IrSimpleFunction?.getOrGenerateIfFinalOrEs6Mode(generateFunc: IrSimpleFunction.() -> JsFunction?): JsExpression? {
|
||||||
if (this == null) return null
|
if (this == null) return null
|
||||||
return if (modality == Modality.FINAL) accessorRef() else generateFunc()
|
return if (!es6mode && modality == Modality.FINAL) accessorRef() else generateFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrSimpleFunction.isDefinedInsideExportedInterface(): Boolean {
|
private fun IrSimpleFunction.isDefinedInsideExportedInterface(): Boolean {
|
||||||
@@ -237,13 +236,13 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrSimpleFunction.generateAssignmentIfMangled(memberRef: JsExpression) {
|
private fun IrSimpleFunction.generateAssignmentIfMangled(memberName: JsName) {
|
||||||
if (
|
if (
|
||||||
irClass.isExported(context.staticContext.backendContext) &&
|
irClass.isExported(context.staticContext.backendContext) &&
|
||||||
visibility.isPublicAPI && hasMangledName() &&
|
visibility.isPublicAPI && hasMangledName() &&
|
||||||
correspondingPropertySymbol == null
|
correspondingPropertySymbol == null
|
||||||
) {
|
) {
|
||||||
classBlock.statements += jsAssignment(prototypeAccessRef(), memberRef).makeStmt()
|
classBlock.statements += jsAssignment(prototypeAccessRef(), jsElementAccess(memberName, classPrototypeRef)).makeStmt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,9 +258,8 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
return isInterface && !isEffectivelyExternal()
|
return isInterface && !isEffectivelyExternal()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateMemberFunction(declaration: IrSimpleFunction): Pair<JsExpression, JsFunction?> {
|
private fun generateMemberFunction(declaration: IrSimpleFunction): Pair<JsName, JsFunction?> {
|
||||||
val memberName = context.getNameForMemberFunction(declaration.realOverrideTarget)
|
val memberName = context.getNameForMemberFunction(declaration.realOverrideTarget)
|
||||||
val memberRef = jsElementAccess(memberName.ident, classPrototypeRef)
|
|
||||||
|
|
||||||
if (declaration.isReal && declaration.body != null) {
|
if (declaration.isReal && declaration.body != null) {
|
||||||
val translatedFunction: JsFunction = declaration.accept(IrFunctionToJsTransformer(), context)
|
val translatedFunction: JsFunction = declaration.accept(IrFunctionToJsTransformer(), context)
|
||||||
@@ -269,10 +267,10 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
|
|
||||||
if (irClass.isInterface) {
|
if (irClass.isInterface) {
|
||||||
classModel.preDeclarationBlock.statements += translatedFunction.makeStmt()
|
classModel.preDeclarationBlock.statements += translatedFunction.makeStmt()
|
||||||
return Pair(memberRef, null)
|
return Pair(memberName, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Pair(memberRef, translatedFunction)
|
return Pair(memberName, translatedFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
// do not generate code like
|
// do not generate code like
|
||||||
@@ -294,7 +292,10 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
|
|
||||||
if (implClassDeclaration.shouldCopyFrom()) {
|
if (implClassDeclaration.shouldCopyFrom()) {
|
||||||
val reference = context.getNameForStaticDeclaration(it).makeRef()
|
val reference = context.getNameForStaticDeclaration(it).makeRef()
|
||||||
classModel.postDeclarationBlock.statements += jsAssignment(memberRef, reference).makeStmt()
|
classModel.postDeclarationBlock.statements += jsAssignment(
|
||||||
|
jsElementAccess(memberName, classPrototypeRef),
|
||||||
|
reference
|
||||||
|
).makeStmt()
|
||||||
if (isFakeOverride) {
|
if (isFakeOverride) {
|
||||||
classModel.postDeclarationBlock.statements += missedOverrides
|
classModel.postDeclarationBlock.statements += missedOverrides
|
||||||
.map { missedOverride ->
|
.map { missedOverride ->
|
||||||
@@ -307,7 +308,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Pair(memberRef, null)
|
return Pair(memberName, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maybeGeneratePrimaryConstructor() {
|
private fun maybeGeneratePrimaryConstructor() {
|
||||||
@@ -322,7 +323,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
val setMetadataFor = context.staticContext.backendContext.intrinsics.setMetadataForSymbol.owner
|
val setMetadataFor = context.staticContext.backendContext.intrinsics.setMetadataForSymbol.owner
|
||||||
|
|
||||||
val ctor = classNameRef
|
val ctor = classNameRef
|
||||||
val parent = baseClassRef
|
val parent = baseClassRef?.takeIf { !es6mode }
|
||||||
val name = generateSimpleName()
|
val name = generateSimpleName()
|
||||||
val interfaces = generateInterfacesList()
|
val interfaces = generateInterfacesList()
|
||||||
val metadataConstructor = getMetadataConstructor()
|
val metadataConstructor = getMetadataConstructor()
|
||||||
@@ -352,8 +353,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
|
|
||||||
private fun IrType.isFunctionType() = isFunctionOrKFunction() || isSuspendFunctionOrKFunction()
|
private fun IrType.isFunctionType() = isFunctionOrKFunction() || isSuspendFunctionOrKFunction()
|
||||||
|
|
||||||
private fun isCoroutineClass(): Boolean = irClass.superTypes.any { it.isSuspendFunctionTypeOrSubtype() }
|
|
||||||
|
|
||||||
private fun generateSimpleName(): JsStringLiteral? {
|
private fun generateSimpleName(): JsStringLiteral? {
|
||||||
return irClass.name.takeIf { !it.isSpecial }?.let { JsStringLiteral(it.identifier) }
|
return irClass.name.takeIf { !it.isSpecial }?.let { JsStringLiteral(it.identifier) }
|
||||||
}
|
}
|
||||||
@@ -386,7 +385,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
.distinct()
|
.distinct()
|
||||||
.map { JsIntLiteral(it) }
|
.map { JsIntLiteral(it) }
|
||||||
|
|
||||||
return JsArrayLiteral(arity)
|
return JsArrayLiteral(arity).takeIf { arity.isNotEmpty() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateAssociatedObjectKey(): JsIntLiteral? {
|
private fun generateAssociatedObjectKey(): JsIntLiteral? {
|
||||||
@@ -411,6 +410,31 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun JsFunction.escapedIfNeed(): JsFunction {
|
||||||
|
if (name?.ident?.isValidES5Identifier() == false) {
|
||||||
|
name = JsName("'${name.ident}'", name.isTemporary)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun JsStatement.isSimpleSuperCall(container: JsFunction): Boolean {
|
||||||
|
if (this !is JsExpressionStatement) return false
|
||||||
|
val invocation = expression as? JsInvocation ?: return false
|
||||||
|
if (invocation.qualifier !is JsSuperRef || container.parameters.size != invocation.arguments.size) return false
|
||||||
|
|
||||||
|
for (i in 0..container.parameters.lastIndex) {
|
||||||
|
val declaredParameter = container.parameters[i]
|
||||||
|
val providedParameter = (invocation.arguments[i] as? JsNameRef)?.takeIf { it.qualifier == null } ?: return false
|
||||||
|
|
||||||
|
if (declaredParameter.name != providedParameter.name) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
fun IrSimpleFunction?.shouldExportAccessor(context: JsIrBackendContext): Boolean {
|
fun IrSimpleFunction?.shouldExportAccessor(context: JsIrBackendContext): Boolean {
|
||||||
if (this == null) return false
|
if (this == null) return false
|
||||||
|
|
||||||
|
|||||||
+10
-5
@@ -119,11 +119,6 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
|||||||
JsObjectLiteral()
|
JsObjectLiteral()
|
||||||
}
|
}
|
||||||
|
|
||||||
add(intrinsics.es6DefaultType) { call, context ->
|
|
||||||
val typeArgument = call.getTypeArgument(0)!!
|
|
||||||
typeArgument.getClassRef(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
addIfNotNull(intrinsics.jsCode) { call, _ ->
|
addIfNotNull(intrinsics.jsCode) { call, _ ->
|
||||||
compilationException(
|
compilationException(
|
||||||
"Should not be called",
|
"Should not be called",
|
||||||
@@ -272,6 +267,16 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
|||||||
add(intrinsics.jsInvokeSuspendSuperTypeWithReceiverAndParam, suspendInvokeTransform)
|
add(intrinsics.jsInvokeSuspendSuperTypeWithReceiverAndParam, suspendInvokeTransform)
|
||||||
|
|
||||||
add(intrinsics.jsArguments) { _, _ -> Namer.ARGUMENTS }
|
add(intrinsics.jsArguments) { _, _ -> Namer.ARGUMENTS }
|
||||||
|
|
||||||
|
add(intrinsics.jsNewAnonymousClass) { call, context ->
|
||||||
|
val baseClass = translateCallArguments(call, context).single() as JsNameRef
|
||||||
|
JsClass(baseClass = baseClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
add(intrinsics.void.owner.getter!!.symbol) { _, context ->
|
||||||
|
val backingField = context.getNameForField(intrinsics.void.owner.backingField!!)
|
||||||
|
JsNameRef(backingField)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -39,8 +39,9 @@ class Merger(
|
|||||||
importStatements.putIfAbsent(declaration, JsVars(JsVars.JsVar(importName, rename(importExpression))))
|
importStatements.putIfAbsent(declaration, JsVars(JsVars.JsVar(importName, rename(importExpression))))
|
||||||
}
|
}
|
||||||
|
|
||||||
val classModels = mutableMapOf<JsName, JsIrIcClassModel>() + f.classes
|
val classModels = (mutableMapOf<JsName, JsIrIcClassModel>() + f.classes)
|
||||||
f.classes.clear()
|
.also { f.classes.clear() }
|
||||||
|
|
||||||
classModels.entries.forEach { (name, model) ->
|
classModels.entries.forEach { (name, model) ->
|
||||||
f.classes[rename(name)] = JsIrIcClassModel(model.superClasses.map { rename(it) }).also {
|
f.classes[rename(name)] = JsIrIcClassModel(model.superClasses.map { rename(it) }).also {
|
||||||
it.preDeclarationBlock.statements += model.preDeclarationBlock.statements
|
it.preDeclarationBlock.statements += model.preDeclarationBlock.statements
|
||||||
|
|||||||
+20
-3
@@ -13,6 +13,7 @@ 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.JsLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.sourceMapsInfo
|
import org.jetbrains.kotlin.ir.backend.js.sourceMapsInfo
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
@@ -32,7 +33,6 @@ import java.io.IOException
|
|||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
|
|
||||||
fun jsUndefined(context: IrNamer, backendContext: JsIrBackendContext): JsExpression {
|
fun jsUndefined(context: IrNamer, backendContext: JsIrBackendContext): JsExpression {
|
||||||
return when (val void = backendContext.getVoid()) {
|
return when (val void = backendContext.getVoid()) {
|
||||||
is IrGetField -> context.getNameForField(void.symbol.owner).makeRef()
|
is IrGetField -> context.getNameForField(void.symbol.owner).makeRef()
|
||||||
@@ -114,6 +114,7 @@ fun translateFunction(declaration: IrFunction, name: JsName?, context: JsGenerat
|
|||||||
val body = declaration.body?.accept(IrElementToJsStatementTransformer(), functionContext) as? JsBlock ?: JsBlock()
|
val body = declaration.body?.accept(IrElementToJsStatementTransformer(), functionContext) as? JsBlock ?: JsBlock()
|
||||||
|
|
||||||
val function = JsFunction(emptyScope, body, "member function ${name ?: "annon"}")
|
val function = JsFunction(emptyScope, body, "member function ${name ?: "annon"}")
|
||||||
|
.apply { if (declaration.isEs6ConstructorReplacement) modifiers.add(JsFunction.Modifier.STATIC) }
|
||||||
.withSource(declaration, context, useNameOf = declaration)
|
.withSource(declaration, context, useNameOf = declaration)
|
||||||
|
|
||||||
function.name = name
|
function.name = name
|
||||||
@@ -147,6 +148,7 @@ fun translateCall(
|
|||||||
transformer: IrElementToJsExpressionTransformer
|
transformer: IrElementToJsExpressionTransformer
|
||||||
): JsExpression {
|
): JsExpression {
|
||||||
val function = expression.symbol.owner.realOverrideTarget
|
val function = expression.symbol.owner.realOverrideTarget
|
||||||
|
val currentDispatchReceiver = context.currentFunction?.parentClassOrNull
|
||||||
|
|
||||||
context.staticContext.intrinsics[function.symbol]?.let {
|
context.staticContext.intrinsics[function.symbol]?.let {
|
||||||
return it(expression, context)
|
return it(expression, context)
|
||||||
@@ -194,6 +196,10 @@ fun translateCall(
|
|||||||
Pair(function, superQualifier.owner)
|
Pair(function, superQualifier.owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (expression.isSyntheticDelegatingReplacement || currentDispatchReceiver.canUseSuperRef(function, context, klass)) {
|
||||||
|
return JsInvocation(JsNameRef(context.getNameForMemberFunction(target), JsSuperRef()), arguments)
|
||||||
|
}
|
||||||
|
|
||||||
val callRef = if (klass.isInterface) {
|
val callRef = if (klass.isInterface) {
|
||||||
val nameForStaticDeclaration = context.getNameForStaticDeclaration(target)
|
val nameForStaticDeclaration = context.getNameForStaticDeclaration(target)
|
||||||
JsNameRef(Namer.CALL_FUNCTION, JsNameRef(nameForStaticDeclaration))
|
JsNameRef(Namer.CALL_FUNCTION, JsNameRef(nameForStaticDeclaration))
|
||||||
@@ -373,12 +379,15 @@ fun translateCallArguments(
|
|||||||
): List<JsExpression> {
|
): List<JsExpression> {
|
||||||
val size = expression.valueArgumentsCount
|
val size = expression.valueArgumentsCount
|
||||||
|
|
||||||
val varargParameterIndex = expression.symbol.owner.realOverrideTarget.varargParameterIndex()
|
val function = expression.symbol.owner
|
||||||
|
val varargParameterIndex = function.realOverrideTarget.varargParameterIndex()
|
||||||
|
|
||||||
val validWithNullArgs = expression.validWithNullArgs()
|
val validWithNullArgs = expression.validWithNullArgs()
|
||||||
val arguments = (0 until size)
|
val arguments = (0 until size)
|
||||||
.mapTo(ArrayList(size)) { index ->
|
.mapTo(ArrayList(size)) { index ->
|
||||||
expression.getValueArgument(index).checkOnNullability(validWithNullArgs)
|
expression.getValueArgument(index).checkOnNullability(
|
||||||
|
validWithNullArgs || function.valueParameters[index].isBoxParameter
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.dropLastWhile {
|
.dropLastWhile {
|
||||||
allowDropTailVoids &&
|
allowDropTailVoids &&
|
||||||
@@ -635,3 +644,11 @@ private val nameMappingOriginAllowList = setOf(
|
|||||||
BOUND_VALUE_PARAMETER,
|
BOUND_VALUE_PARAMETER,
|
||||||
JsLoweredDeclarationOrigin.JS_SHADOWED_DEFAULT_PARAMETER,
|
JsLoweredDeclarationOrigin.JS_SHADOWED_DEFAULT_PARAMETER,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun IrClass?.canUseSuperRef(function: IrFunction, context: JsGenerationContext, superClass: IrClass): Boolean {
|
||||||
|
return this != null &&
|
||||||
|
function.origin != IrDeclarationOrigin.LOWERED_SUSPEND_FUNCTION &&
|
||||||
|
context.staticContext.backendContext.es6mode &&
|
||||||
|
!superClass.isInterface && !isInner && !isLocal &&
|
||||||
|
context.currentFunction?.isEs6ConstructorReplacement != true
|
||||||
|
}
|
||||||
|
|||||||
+13
-1
@@ -74,8 +74,20 @@ private fun JsNode.computeScopes(): Scope {
|
|||||||
accept(object : RecursiveJsVisitor() {
|
accept(object : RecursiveJsVisitor() {
|
||||||
var currentScope: Scope = rootScope
|
var currentScope: Scope = rootScope
|
||||||
|
|
||||||
override fun visitFunction(x: JsFunction) {
|
override fun visitClass(x: JsClass) {
|
||||||
x.name?.let { currentScope.declaredNames += it }
|
x.name?.let { currentScope.declaredNames += it }
|
||||||
|
// We need it to not rename methods and fields inside class body
|
||||||
|
// Because if they are in clash with something, it means overriding
|
||||||
|
x.constructor?.accept(this)
|
||||||
|
x.members.forEach { visitFunction(it, shouldReserveName = false) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunction(x: JsFunction) {
|
||||||
|
visitFunction(x, shouldReserveName = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun visitFunction(x: JsFunction, shouldReserveName: Boolean) {
|
||||||
|
x.name?.takeIf { shouldReserveName }?.let { currentScope.declaredNames += it }
|
||||||
val oldScope = currentScope
|
val oldScope = currentScope
|
||||||
currentScope = Scope().apply {
|
currentScope = Scope().apply {
|
||||||
currentScope.children += this
|
currentScope.children += this
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.ir.declarations.IrOverridableDeclaration
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrVararg
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
@@ -37,10 +36,6 @@ object JsAnnotations {
|
|||||||
fun IrConstructorCall.getSingleConstStringArgument() =
|
fun IrConstructorCall.getSingleConstStringArgument() =
|
||||||
(getValueArgument(0) as IrConst<String>).value
|
(getValueArgument(0) as IrConst<String>).value
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun IrConstructorCall.getClassReferencVarargArguments() =
|
|
||||||
(getValueArgument(0) as? IrVararg)?.elements as? List<IrClassReference>
|
|
||||||
|
|
||||||
fun IrAnnotationContainer.getJsModule(): String? =
|
fun IrAnnotationContainer.getJsModule(): String? =
|
||||||
getAnnotation(JsAnnotations.jsModuleFqn)?.getSingleConstStringArgument()
|
getAnnotation(JsAnnotations.jsModuleFqn)?.getSingleConstStringArgument()
|
||||||
|
|
||||||
|
|||||||
@@ -9,16 +9,28 @@ import org.jetbrains.kotlin.descriptors.isClass
|
|||||||
import org.jetbrains.kotlin.descriptors.isInterface
|
import org.jetbrains.kotlin.descriptors.isInterface
|
||||||
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.JsStatementOrigins
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrReturn
|
import org.jetbrains.kotlin.ir.expressions.IrReturn
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
|
import org.jetbrains.kotlin.ir.util.isAnnotationClass
|
||||||
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
|
fun IrClass.jsConstructorReference(context: JsIrBackendContext): IrExpression {
|
||||||
|
return JsIrBuilder.buildCall(context.intrinsics.jsClass, origin = JsStatementOrigins.CLASS_REFERENCE)
|
||||||
|
.apply { putTypeArgument(0, defaultType) }
|
||||||
|
}
|
||||||
|
|
||||||
fun IrDeclaration.isExportedMember(context: JsIrBackendContext) =
|
fun IrDeclaration.isExportedMember(context: JsIrBackendContext) =
|
||||||
(this is IrDeclarationWithVisibility && visibility.isPublicAPI) &&
|
(this is IrDeclarationWithVisibility && visibility.isPublicAPI) &&
|
||||||
parentClassOrNull?.isExported(context) == true
|
parentClassOrNull?.isExported(context) == true
|
||||||
@@ -42,10 +54,23 @@ fun IrDeclarationWithName.getFqNameWithJsNameWhenAvailable(shouldIncludePackage:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun IrConstructor.hasStrictSignature(context: JsIrBackendContext): Boolean {
|
||||||
|
val primitives = with(context.irBuiltIns) { primitiveTypesToPrimitiveArrays.values + stringClass }
|
||||||
|
return with(parentAsClass) {
|
||||||
|
isExternal || isExpect || isAnnotationClass || context.inlineClassesUtils.isClassInlineLike(this) || symbol in primitives
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun getKotlinOrJsQualifier(parent: IrPackageFragment, shouldIncludePackage: Boolean): FqName? {
|
private fun getKotlinOrJsQualifier(parent: IrPackageFragment, shouldIncludePackage: Boolean): FqName? {
|
||||||
return (parent as? IrFile)?.getJsQualifier()?.let { FqName(it) } ?: parent.fqName.takeIf { shouldIncludePackage }
|
return (parent as? IrFile)?.getJsQualifier()?.let { FqName(it) } ?: parent.fqName.takeIf { shouldIncludePackage }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val IrFunctionAccessExpression.typeArguments: List<IrType?>
|
||||||
|
get() = List(typeArgumentsCount) { getTypeArgument(it) }
|
||||||
|
|
||||||
|
val IrFunctionAccessExpression.valueArguments: List<IrExpression?>
|
||||||
|
get() = List(valueArgumentsCount) { getValueArgument(it) }
|
||||||
|
|
||||||
// TODO: the code is written to pass Repl tests, so we should understand. why in Repl tests we don't have backingField
|
// TODO: the code is written to pass Repl tests, so we should understand. why in Repl tests we don't have backingField
|
||||||
fun JsIrBackendContext.getVoid(): IrExpression =
|
fun JsIrBackendContext.getVoid(): IrExpression =
|
||||||
intrinsics.void.owner.backingField?.let {
|
intrinsics.void.owner.backingField?.let {
|
||||||
@@ -60,3 +85,8 @@ fun JsIrBackendContext.getVoid(): IrExpression =
|
|||||||
UNDEFINED_OFFSET,
|
UNDEFINED_OFFSET,
|
||||||
irBuiltIns.nothingNType
|
irBuiltIns.nothingNType
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun irEmpty(context: JsIrBackendContext): IrExpression {
|
||||||
|
return JsIrBuilder.buildComposite(context.dynamicType, emptyList())
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,13 @@ object Namer {
|
|||||||
|
|
||||||
val OUTER_NAME = "\$outer"
|
val OUTER_NAME = "\$outer"
|
||||||
val UNREACHABLE_NAME = "\$unreachable"
|
val UNREACHABLE_NAME = "\$unreachable"
|
||||||
|
val THROWABLE_CONSTRUCTOR = "\$throwableCtor"
|
||||||
|
|
||||||
val DELEGATE = "\$delegate"
|
val DELEGATE = "\$delegate"
|
||||||
|
|
||||||
val IMPLICIT_RECEIVER_NAME = "this"
|
val IMPLICIT_RECEIVER_NAME = "this"
|
||||||
|
val SYNTHETIC_RECEIVER_NAME = "\$this"
|
||||||
|
val ES6_BOX_PARAMETER_NAME = "\$box"
|
||||||
|
|
||||||
val ARGUMENTS = JsNameRef("arguments")
|
val ARGUMENTS = JsNameRef("arguments")
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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
|
||||||
|
|
||||||
|
class MutableReference<T>(var value: T)
|
||||||
|
|
||||||
|
fun <T> mutableReferenceOf(value: T): MutableReference<T> = MutableReference(value)
|
||||||
+2
@@ -54,4 +54,6 @@ object ExpressionIds {
|
|||||||
const val PROPERTY_REFERENCE = 19
|
const val PROPERTY_REFERENCE = 19
|
||||||
const val INVOCATION = 20
|
const val INVOCATION = 20
|
||||||
const val NEW = 21
|
const val NEW = 21
|
||||||
|
const val CLASS = 22
|
||||||
|
const val SUPER_REF = 23
|
||||||
}
|
}
|
||||||
+23
-5
@@ -240,6 +240,7 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
|||||||
private val sideEffectKindValues = SideEffectKind.values()
|
private val sideEffectKindValues = SideEffectKind.values()
|
||||||
private val jsBinaryOperatorValues = JsBinaryOperator.values()
|
private val jsBinaryOperatorValues = JsBinaryOperator.values()
|
||||||
private val jsUnaryOperatorValues = JsUnaryOperator.values()
|
private val jsUnaryOperatorValues = JsUnaryOperator.values()
|
||||||
|
private val jsFunctionModifiersValues = JsFunction.Modifier.values()
|
||||||
|
|
||||||
private fun readExpression(): JsExpression {
|
private fun readExpression(): JsExpression {
|
||||||
return withComments {
|
return withComments {
|
||||||
@@ -249,6 +250,9 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
|||||||
THIS_REF -> {
|
THIS_REF -> {
|
||||||
JsThisRef()
|
JsThisRef()
|
||||||
}
|
}
|
||||||
|
SUPER_REF -> {
|
||||||
|
JsSuperRef()
|
||||||
|
}
|
||||||
NULL -> {
|
NULL -> {
|
||||||
JsNullLiteral()
|
JsNullLiteral()
|
||||||
}
|
}
|
||||||
@@ -283,10 +287,15 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
FUNCTION -> {
|
FUNCTION -> {
|
||||||
JsFunction(scope, readBlock(), "").apply {
|
readFunction()
|
||||||
readRepeated { parameters += readParameter() }
|
}
|
||||||
ifTrue { name = nameTable[readInt()] }
|
CLASS -> {
|
||||||
isLocal = readBoolean()
|
JsClass(
|
||||||
|
ifTrue { nameTable[readInt()] },
|
||||||
|
ifTrue { nameTable[readInt()].makeRef() },
|
||||||
|
ifTrue { readFunction() },
|
||||||
|
).apply {
|
||||||
|
readRepeated { members += readFunction() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DOC_COMMENT -> {
|
DOC_COMMENT -> {
|
||||||
@@ -353,6 +362,15 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun readFunction(): JsFunction {
|
||||||
|
return JsFunction(scope, readBlock(), "").apply {
|
||||||
|
readRepeated { parameters += readParameter() }
|
||||||
|
readRepeated { modifiers += jsFunctionModifiersValues[readInt()] }
|
||||||
|
ifTrue { name = nameTable[readInt()] }
|
||||||
|
isLocal = readBoolean()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun readJsImportedModule(): JsImportedModule {
|
private fun readJsImportedModule(): JsImportedModule {
|
||||||
return JsImportedModule(
|
return JsImportedModule(
|
||||||
stringTable[readInt()],
|
stringTable[readInt()],
|
||||||
@@ -447,4 +465,4 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
|||||||
ifTrue { this.commentsAfterNode = readArray { readComment() }.toList() }
|
ifTrue { this.commentsAfterNode = readArray { readComment() }.toList() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+29
-3
@@ -336,6 +336,10 @@ private class JsIrAstSerializer {
|
|||||||
writeByte(ExpressionIds.THIS_REF)
|
writeByte(ExpressionIds.THIS_REF)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitSuper(x: JsSuperRef) {
|
||||||
|
writeByte(ExpressionIds.SUPER_REF)
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitNull(x: JsNullLiteral) {
|
override fun visitNull(x: JsNullLiteral) {
|
||||||
writeByte(ExpressionIds.NULL)
|
writeByte(ExpressionIds.NULL)
|
||||||
}
|
}
|
||||||
@@ -387,12 +391,24 @@ private class JsIrAstSerializer {
|
|||||||
|
|
||||||
override fun visitFunction(x: JsFunction) {
|
override fun visitFunction(x: JsFunction) {
|
||||||
writeByte(ExpressionIds.FUNCTION)
|
writeByte(ExpressionIds.FUNCTION)
|
||||||
writeBlock(x.body)
|
writeFunction(x)
|
||||||
writeCollection(x.parameters) { writeParameter(it) }
|
}
|
||||||
|
|
||||||
|
override fun visitClass(x: JsClass) {
|
||||||
|
writeByte(ExpressionIds.CLASS)
|
||||||
ifNotNull(x.name) {
|
ifNotNull(x.name) {
|
||||||
writeInt(internalizeName(it))
|
writeInt(internalizeName(it))
|
||||||
}
|
}
|
||||||
writeBoolean(x.isLocal)
|
// TODO: add more complex JsNameRef parsing in future when we will support `class` expressions inside a `js` call
|
||||||
|
ifNotNull(x.baseClass?.name) {
|
||||||
|
writeInt(internalizeName(it))
|
||||||
|
}
|
||||||
|
ifNotNull(x.constructor) {
|
||||||
|
writeFunction(it)
|
||||||
|
}
|
||||||
|
writeCollection(x.members) {
|
||||||
|
writeFunction(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitDocComment(comment: JsDocComment) {
|
override fun visitDocComment(comment: JsDocComment) {
|
||||||
@@ -494,6 +510,16 @@ private class JsIrAstSerializer {
|
|||||||
ifNotNull(module.plainReference) { writeExpression(it) }
|
ifNotNull(module.plainReference) { writeExpression(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun DataWriter.writeFunction(function: JsFunction) {
|
||||||
|
writeBlock(function.body)
|
||||||
|
writeCollection(function.parameters) { writeParameter(it) }
|
||||||
|
writeCollection(function.modifiers) { writeInt(it.ordinal) }
|
||||||
|
ifNotNull(function.name) {
|
||||||
|
writeInt(internalizeName(it))
|
||||||
|
}
|
||||||
|
writeBoolean(function.isLocal)
|
||||||
|
}
|
||||||
|
|
||||||
private fun DataWriter.writeParameter(parameter: JsParameter) {
|
private fun DataWriter.writeParameter(parameter: JsParameter) {
|
||||||
writeInt(internalizeName(parameter.name))
|
writeInt(internalizeName(parameter.name))
|
||||||
writeBoolean(parameter.hasDefaultValue)
|
writeBoolean(parameter.hasDefaultValue)
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.expressions
|
package org.jetbrains.kotlin.ir.expressions
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
|
|
||||||
|
|
||||||
abstract class IrStatementOriginImpl(val debugName: String) : IrStatementOrigin {
|
abstract class IrStatementOriginImpl(val debugName: String) : IrStatementOrigin {
|
||||||
override fun toString(): String = debugName
|
override fun toString(): String = debugName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,6 +205,12 @@ val IrProperty.isSimpleProperty: Boolean
|
|||||||
val IrClass.functions: Sequence<IrSimpleFunction>
|
val IrClass.functions: Sequence<IrSimpleFunction>
|
||||||
get() = declarations.asSequence().filterIsInstance<IrSimpleFunction>()
|
get() = declarations.asSequence().filterIsInstance<IrSimpleFunction>()
|
||||||
|
|
||||||
|
val IrClass.superClass: IrClass?
|
||||||
|
get() = superTypes
|
||||||
|
.firstOrNull { !it.isInterface() && !it.isAny() }
|
||||||
|
?.classOrNull
|
||||||
|
?.owner
|
||||||
|
|
||||||
val IrClassSymbol.functions: Sequence<IrSimpleFunctionSymbol>
|
val IrClassSymbol.functions: Sequence<IrSimpleFunctionSymbol>
|
||||||
get() = owner.functions.map { it.symbol }
|
get() = owner.functions.map { it.symbol }
|
||||||
|
|
||||||
@@ -823,8 +829,11 @@ fun IrFunction.copyValueParametersFrom(from: IrFunction, substitutionMap: Map<Ir
|
|||||||
fun IrFunction.copyParameterDeclarationsFrom(from: IrFunction) {
|
fun IrFunction.copyParameterDeclarationsFrom(from: IrFunction) {
|
||||||
assert(typeParameters.isEmpty())
|
assert(typeParameters.isEmpty())
|
||||||
copyTypeParametersFrom(from)
|
copyTypeParametersFrom(from)
|
||||||
val substitutionMap = makeTypeParameterSubstitutionMap(from, this)
|
copyValueParametersFrom(from)
|
||||||
copyValueParametersFrom(from, substitutionMap)
|
}
|
||||||
|
|
||||||
|
fun IrFunction.copyValueParametersFrom(from: IrFunction) {
|
||||||
|
copyValueParametersFrom(from, makeTypeParameterSubstitutionMap(from, this))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrTypeParametersContainer.copyTypeParameters(
|
fun IrTypeParametersContainer.copyTypeParameters(
|
||||||
|
|||||||
+1
@@ -45,6 +45,7 @@ where advanced options include:
|
|||||||
-Xtyped-arrays Translate primitive arrays to JS typed arrays
|
-Xtyped-arrays Translate primitive arrays to JS typed arrays
|
||||||
-Xuse-deprecated-legacy-compiler
|
-Xuse-deprecated-legacy-compiler
|
||||||
Use deprecated legacy compiler without error
|
Use deprecated legacy compiler without error
|
||||||
|
-Xes-classes Generated JavaScript will use ES2015 classes.
|
||||||
-Xwasm Use experimental WebAssembly compiler backend
|
-Xwasm Use experimental WebAssembly compiler backend
|
||||||
-Xwasm-debug-info Add debug info to WebAssembly compiled module
|
-Xwasm-debug-info Add debug info to WebAssembly compiled module
|
||||||
-Xwasm-enable-array-range-checks
|
-Xwasm-enable-array-range-checks
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JS, JS_IR, WASM
|
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, WASM
|
||||||
var result = ""
|
var result = ""
|
||||||
|
|
||||||
fun sideEffecting(): Int {
|
fun sideEffecting(): Int {
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JS, JS_IR
|
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6
|
||||||
|
|
||||||
// The code in this test should be prohibited in the frontend, see KT-36188.
|
// The code in this test should be prohibited in the frontend, see KT-36188.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JS, JS_IR
|
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6
|
||||||
// !JVM_DEFAULT_MODE: all
|
// !JVM_DEFAULT_MODE: all
|
||||||
// JVM_TARGET: 1.8
|
// JVM_TARGET: 1.8
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
// ^ wasm-function[1893]:0x1cf8a: RuntimeError: dereferencing a null pointer
|
// ^ wasm-function[1893]:0x1cf8a: RuntimeError: dereferencing a null pointer
|
||||||
|
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
// IGNORE_BACKEND: JS_IR
|
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||||
// ^ TypeError: tmp is not a function
|
// ^ TypeError: tmp is not a function
|
||||||
|
|
||||||
// FILE: funInterfaceConstructedObjectsEquality.kt
|
// FILE: funInterfaceConstructedObjectsEquality.kt
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
// ^ Failed: ks1 != ks2 (same file, same SAM type)
|
// ^ Failed: ks1 != ks2 (same file, same SAM type)
|
||||||
|
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
// IGNORE_BACKEND: JS_IR
|
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||||
// ^ Failed: ks1 != ks2 (same file, same SAM type)
|
// ^ Failed: ks1 != ks2 (same file, same SAM type)
|
||||||
|
|
||||||
// FILE: funInterfaceConstructorEquality.kt
|
// FILE: funInterfaceConstructorEquality.kt
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// !LANGUAGE: +DefinitelyNonNullableTypes
|
// !LANGUAGE: +DefinitelyNonNullableTypes
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
// IGNORE_BACKEND: JS_IR
|
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
|
|
||||||
fun <T> test(t: T) = t as (T & Any)
|
fun <T> test(t: T) = t as (T & Any)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JS, JS_IR, WASM
|
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, WASM
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <T> f() = 1L as T
|
fun <T> f() = 1L as T
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JS, JS_IR, WASM
|
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, WASM
|
||||||
|
|
||||||
// boxed primitive comparisons
|
// boxed primitive comparisons
|
||||||
fun isBoolean(a: Any) = a::class == true::class
|
fun isBoolean(a: Any) = a::class == true::class
|
||||||
|
|||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JS_IR_ES6
|
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
|
||||||
// IGNORE_BACKEND_K2: JS_IR
|
|
||||||
|
|
||||||
class Outer(val x: Any) {
|
class Outer(val x: Any) {
|
||||||
inner class Inner(
|
inner class Inner(
|
||||||
|
|||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JS_IR_ES6
|
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
|
||||||
// IGNORE_BACKEND_K2: JS_IR
|
|
||||||
|
|
||||||
class Outer(val x: Any) {
|
class Outer(val x: Any) {
|
||||||
inner class Inner(
|
inner class Inner(
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
|
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
|
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// MODULE: lib(support)
|
// MODULE: lib(support)
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// MODULE: lib(support)
|
// MODULE: lib(support)
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||||
// KT-55464
|
// KT-55464
|
||||||
// IGNORE_BACKEND_K2: NATIVE
|
// IGNORE_BACKEND_K2: NATIVE
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// MODULE: lib(support)
|
// MODULE: lib(support)
|
||||||
|
|||||||
Vendored
-1
@@ -1,7 +1,6 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: NESTED_OBJECT_INIT
|
// WASM_MUTE_REASON: NESTED_OBJECT_INIT
|
||||||
// IGNORE_BACKEND: NATIVE
|
// IGNORE_BACKEND: NATIVE
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// WITH_COROUTINES
|
// WITH_COROUTINES
|
||||||
import helpers.*
|
import helpers.*
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// FULL_JDK
|
// FULL_JDK
|
||||||
// IGNORE_BACKEND: JS_IR
|
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||||
|
|
||||||
import kotlin.coroutines.*
|
import kotlin.coroutines.*
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// IGNORE_BACKEND: JVM, JS, JS_IR
|
// IGNORE_BACKEND: JVM, JS, JS_IR, JS_IR_ES6
|
||||||
// KT-30080
|
// KT-30080
|
||||||
|
|
||||||
data class A(
|
data class A(
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// CHECK_BYTECODE_LISTING
|
// CHECK_BYTECODE_LISTING
|
||||||
// FIR_IDENTICAL
|
// FIR_IDENTICAL
|
||||||
// IGNORE_BACKEND: JS_IR
|
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||||
|
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||||
|
|
||||||
open class A {
|
open class A {
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
|
|
||||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun noTails() {
|
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun noTails() {
|
||||||
// nothing here
|
// nothing here
|
||||||
|
|||||||
Vendored
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||||
|
|||||||
-1
@@ -1,7 +1,6 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
|
|
||||||
tailrec fun test(x : Int) : Int {
|
tailrec fun test(x : Int) : Int {
|
||||||
var z = if (x > 3) 3 else x
|
var z = if (x > 3) 3 else x
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,7 +1,6 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
|
|
||||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo() {
|
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo() {
|
||||||
bar {
|
bar {
|
||||||
|
|||||||
Vendored
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
|
|
||||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo() {
|
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo() {
|
||||||
fun bar() {
|
fun bar() {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
|
|
||||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
|
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
|
||||||
if (counter == 0) return 0
|
if (counter == 0) return 0
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
|
|
||||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
|
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
|
||||||
if (counter == 0) return 0
|
if (counter == 0) return 0
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
|
|
||||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
|
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
|
||||||
if (counter == 0) return 0
|
if (counter == 0) return 0
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
|
|
||||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
|
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
|
||||||
if (counter == 0) return 0
|
if (counter == 0) return 0
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
|
|
||||||
|
|||||||
Vendored
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
|
|
||||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(go: Boolean) : Unit {
|
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(go: Boolean) : Unit {
|
||||||
if (!go) return
|
if (!go) return
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// DONT_RUN_GENERATED_CODE: JS
|
// DONT_RUN_GENERATED_CODE: JS
|
||||||
// IGNORE_BACKEND: JVM
|
// IGNORE_BACKEND: JVM
|
||||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// DONT_RUN_GENERATED_CODE: JS
|
// DONT_RUN_GENERATED_CODE: JS
|
||||||
|
|
||||||
object O {
|
object O {
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,6 +1,5 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
// IGNORE_BACKEND: WASM
|
||||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||||
// IGNORE_BACKEND: JS_IR_ES6
|
|
||||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user