Use local aliases for Kotlin runtime functions in JS BE

This commit is contained in:
Alexey Andreev
2017-07-17 15:04:48 +03:00
parent 8c256b24dc
commit 7646c2fc72
21 changed files with 539 additions and 70 deletions
@@ -190,6 +190,88 @@ public final class DebugJsAstProtoBuf {
// @@protoc_insertion_point(enum_scope:org.jetbrains.kotlin.serialization.js.ast.InlineStrategy)
}
/**
* Protobuf enum {@code org.jetbrains.kotlin.serialization.js.ast.SpecialFunction}
*/
public enum SpecialFunction
implements org.jetbrains.kotlin.protobuf.ProtocolMessageEnum {
/**
* <code>DEFINE_INLINE_FUNCTION = 1;</code>
*/
DEFINE_INLINE_FUNCTION(0, 1),
/**
* <code>WRAP_FUNCTION = 2;</code>
*/
WRAP_FUNCTION(1, 2),
;
/**
* <code>DEFINE_INLINE_FUNCTION = 1;</code>
*/
public static final int DEFINE_INLINE_FUNCTION_VALUE = 1;
/**
* <code>WRAP_FUNCTION = 2;</code>
*/
public static final int WRAP_FUNCTION_VALUE = 2;
public final int getNumber() { return value; }
public static SpecialFunction valueOf(int value) {
switch (value) {
case 1: return DEFINE_INLINE_FUNCTION;
case 2: return WRAP_FUNCTION;
default: return null;
}
}
public static org.jetbrains.kotlin.protobuf.Internal.EnumLiteMap<SpecialFunction>
internalGetValueMap() {
return internalValueMap;
}
private static org.jetbrains.kotlin.protobuf.Internal.EnumLiteMap<SpecialFunction>
internalValueMap =
new org.jetbrains.kotlin.protobuf.Internal.EnumLiteMap<SpecialFunction>() {
public SpecialFunction findValueByNumber(int number) {
return SpecialFunction.valueOf(number);
}
};
public final org.jetbrains.kotlin.protobuf.Descriptors.EnumValueDescriptor
getValueDescriptor() {
return getDescriptor().getValues().get(index);
}
public final org.jetbrains.kotlin.protobuf.Descriptors.EnumDescriptor
getDescriptorForType() {
return getDescriptor();
}
public static final org.jetbrains.kotlin.protobuf.Descriptors.EnumDescriptor
getDescriptor() {
return org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.getDescriptor().getEnumTypes().get(2);
}
private static final SpecialFunction[] VALUES = values();
public static SpecialFunction valueOf(
org.jetbrains.kotlin.protobuf.Descriptors.EnumValueDescriptor desc) {
if (desc.getType() != getDescriptor()) {
throw new java.lang.IllegalArgumentException(
"EnumValueDescriptor is not for this type.");
}
return VALUES[desc.getIndex()];
}
private final int index;
private final int value;
private SpecialFunction(int index, int value) {
this.index = index;
this.value = value;
}
// @@protoc_insertion_point(enum_scope:org.jetbrains.kotlin.serialization.js.ast.SpecialFunction)
}
public interface LocationOrBuilder extends
// @@protoc_insertion_point(interface_extends:org.jetbrains.kotlin.serialization.js.ast.Location)
org.jetbrains.kotlin.protobuf.MessageOrBuilder {
@@ -47073,13 +47155,22 @@ public final class DebugJsAstProtoBuf {
int getLocalNameId();
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
boolean hasImported();
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
boolean getImported();
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
boolean hasSpecialFunction();
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction getSpecialFunction();
}
/**
* Protobuf type {@code org.jetbrains.kotlin.serialization.js.ast.Name}
@@ -47153,6 +47244,17 @@ public final class DebugJsAstProtoBuf {
imported_ = input.readBool();
break;
}
case 40: {
int rawValue = input.readEnum();
org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction value = org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction.valueOf(rawValue);
if (value == null) {
unknownFields.mergeVarintField(5, rawValue);
} else {
bitField0_ |= 0x00000010;
specialFunction_ = value;
}
break;
}
}
}
} catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
@@ -47241,23 +47343,39 @@ public final class DebugJsAstProtoBuf {
public static final int IMPORTED_FIELD_NUMBER = 4;
private boolean imported_;
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
public boolean hasImported() {
return ((bitField0_ & 0x00000008) == 0x00000008);
}
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
public boolean getImported() {
return imported_;
}
public static final int SPECIAL_FUNCTION_FIELD_NUMBER = 5;
private org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction specialFunction_;
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
public boolean hasSpecialFunction() {
return ((bitField0_ & 0x00000010) == 0x00000010);
}
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
public org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction getSpecialFunction() {
return specialFunction_;
}
private void initFields() {
temporary_ = false;
identifier_ = 0;
localNameId_ = 0;
imported_ = false;
specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
@@ -47288,6 +47406,9 @@ public final class DebugJsAstProtoBuf {
if (((bitField0_ & 0x00000008) == 0x00000008)) {
output.writeBool(4, imported_);
}
if (((bitField0_ & 0x00000010) == 0x00000010)) {
output.writeEnum(5, specialFunction_.getNumber());
}
getUnknownFields().writeTo(output);
}
@@ -47313,6 +47434,10 @@ public final class DebugJsAstProtoBuf {
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
.computeBoolSize(4, imported_);
}
if (((bitField0_ & 0x00000010) == 0x00000010)) {
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
.computeEnumSize(5, specialFunction_.getNumber());
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@@ -47438,6 +47563,8 @@ public final class DebugJsAstProtoBuf {
bitField0_ = (bitField0_ & ~0x00000004);
imported_ = false;
bitField0_ = (bitField0_ & ~0x00000008);
specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
bitField0_ = (bitField0_ & ~0x00000010);
return this;
}
@@ -47482,6 +47609,10 @@ public final class DebugJsAstProtoBuf {
to_bitField0_ |= 0x00000008;
}
result.imported_ = imported_;
if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
to_bitField0_ |= 0x00000010;
}
result.specialFunction_ = specialFunction_;
result.bitField0_ = to_bitField0_;
onBuilt();
return result;
@@ -47510,6 +47641,9 @@ public final class DebugJsAstProtoBuf {
if (other.hasImported()) {
setImported(other.getImported());
}
if (other.hasSpecialFunction()) {
setSpecialFunction(other.getSpecialFunction());
}
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@@ -47639,19 +47773,19 @@ public final class DebugJsAstProtoBuf {
private boolean imported_ ;
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
public boolean hasImported() {
return ((bitField0_ & 0x00000008) == 0x00000008);
}
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
public boolean getImported() {
return imported_;
}
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
public Builder setImported(boolean value) {
bitField0_ |= 0x00000008;
@@ -47660,7 +47794,7 @@ public final class DebugJsAstProtoBuf {
return this;
}
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
public Builder clearImported() {
bitField0_ = (bitField0_ & ~0x00000008);
@@ -47669,6 +47803,41 @@ public final class DebugJsAstProtoBuf {
return this;
}
private org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
public boolean hasSpecialFunction() {
return ((bitField0_ & 0x00000010) == 0x00000010);
}
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
public org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction getSpecialFunction() {
return specialFunction_;
}
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
public Builder setSpecialFunction(org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000010;
specialFunction_ = value;
onChanged();
return this;
}
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
public Builder clearSpecialFunction() {
bitField0_ = (bitField0_ & ~0x00000010);
specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.DebugJsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
onChanged();
return this;
}
// @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.serialization.js.ast.Name)
}
@@ -49160,19 +49329,23 @@ public final class DebugJsAstProtoBuf {
"ule\022\024\n\014signature_id\030\001 \002(\005\022\025\n\rexpression_" +
"id\030\002 \002(\005\"\034\n\013StringTable\022\r\n\005entry\030\001 \003(\t\"K" +
"\n\tNameTable\022>\n\005entry\030\001 \003(\0132/.org.jetbrai",
"ns.kotlin.serialization.js.ast.Name\"V\n\004N" +
"ame\022\021\n\ttemporary\030\001 \002(\010\022\022\n\nidentifier\030\002 \001" +
"(\005\022\025\n\rlocal_name_id\030\003 \001(\005\022\020\n\010imported\030\004 " +
"\001(\010\"\346\001\n\005Chunk\022L\n\014string_table\030\001 \002(\01326.or" +
"g.jetbrains.kotlin.serialization.js.ast." +
"StringTable\022H\n\nname_table\030\002 \002(\01324.org.je" +
"tbrains.kotlin.serialization.js.ast.Name" +
"Table\022E\n\010fragment\030\003 \002(\01323.org.jetbrains." +
"kotlin.serialization.js.ast.Fragment*@\n\013" +
"SideEffects\022\021\n\rAFFECTS_STATE\020\001\022\024\n\020DEPEND",
"S_ON_STATE\020\002\022\010\n\004PURE\020\003*?\n\016InlineStrategy" +
"\022\017\n\013AS_FUNCTION\020\000\022\014\n\010IN_PLACE\020\001\022\016\n\nNOT_I" +
"NLINE\020\002B\024B\022DebugJsAstProtoBuf"
"ns.kotlin.serialization.js.ast.Name\"\263\001\n\004" +
"Name\022\021\n\ttemporary\030\001 \002(\010\022\022\n\nidentifier\030\002 " +
"\001(\005\022\025\n\rlocal_name_id\030\003 \001(\005\022\027\n\010imported\030\004" +
" \001(\010:\005false\022T\n\020special_function\030\005 \001(\0162:." +
"org.jetbrains.kotlin.serialization.js.as" +
"t.SpecialFunction\"\346\001\n\005Chunk\022L\n\014string_ta" +
"ble\030\001 \002(\01326.org.jetbrains.kotlin.seriali" +
"zation.js.ast.StringTable\022H\n\nname_table\030" +
"\002 \002(\01324.org.jetbrains.kotlin.serializati" +
"on.js.ast.NameTable\022E\n\010fragment\030\003 \002(\01323.",
"org.jetbrains.kotlin.serialization.js.as" +
"t.Fragment*@\n\013SideEffects\022\021\n\rAFFECTS_STA" +
"TE\020\001\022\024\n\020DEPENDS_ON_STATE\020\002\022\010\n\004PURE\020\003*?\n\016" +
"InlineStrategy\022\017\n\013AS_FUNCTION\020\000\022\014\n\010IN_PL" +
"ACE\020\001\022\016\n\nNOT_INLINE\020\002*@\n\017SpecialFunction" +
"\022\032\n\026DEFINE_INLINE_FUNCTION\020\001\022\021\n\rWRAP_FUN" +
"CTION\020\002B\024B\022DebugJsAstProtoBuf"
};
org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
@@ -49509,7 +49682,7 @@ public final class DebugJsAstProtoBuf {
internal_static_org_jetbrains_kotlin_serialization_js_ast_Name_fieldAccessorTable = new
org.jetbrains.kotlin.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_org_jetbrains_kotlin_serialization_js_ast_Name_descriptor,
new java.lang.String[] { "Temporary", "Identifier", "LocalNameId", "Imported", });
new java.lang.String[] { "Temporary", "Identifier", "LocalNameId", "Imported", "SpecialFunction", });
internal_static_org_jetbrains_kotlin_serialization_js_ast_Chunk_descriptor =
getDescriptor().getMessageTypes().get(54);
internal_static_org_jetbrains_kotlin_serialization_js_ast_Chunk_fieldAccessorTable = new
@@ -31,6 +31,8 @@ var JsName.descriptor: DeclarationDescriptor? by MetadataProperty(default = null
var JsName.localAlias: JsName? by MetadataProperty(default = null)
var JsName.specialFunction: SpecialFunction? by MetadataProperty(default = null)
var JsExpression.localAlias: JsName? by MetadataProperty(default = null)
// TODO: move this to module 'js.inliner' and change dependency on 'frontend' to dependency on 'descriptors'
@@ -133,4 +135,9 @@ enum class SideEffectKind {
AFFECTS_STATE,
DEPENDS_ON_STATE,
PURE
}
enum class SpecialFunction(val suggestedName: String) {
DEFINE_INLINE_FUNCTION("defineInlineFunction"),
WRAP_FUNCTION("wrapFunction")
}
@@ -359,6 +359,7 @@ class Analyzer(private val context: Context) : JsVisitor() {
private fun enterFunction(function: JsFunction, arguments: List<JsExpression>) {
functionsToEnter += function
context.addNodesForLocalVars(function.collectLocalVariables())
context.markSpecialFunctions(function.body)
for ((param, arg) in function.parameters.zip(arguments)) {
if (arg is JsFunction && arg.name == null && isProperFunctionalParameter(arg.body, param)) {
@@ -377,6 +378,7 @@ class Analyzer(private val context: Context) : JsVisitor() {
private fun enterFunctionWithGivenNodes(function: JsFunction, arguments: List<Node>) {
functionsToEnter += function
context.addNodesForLocalVars(function.collectLocalVariables())
context.markSpecialFunctions(function.body)
for ((param, arg) in function.parameters.zip(arguments)) {
val paramNode = context.nodes[param.name]!!
@@ -17,6 +17,9 @@
package org.jetbrains.kotlin.js.dce
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction
import org.jetbrains.kotlin.js.backend.ast.metadata.specialFunction
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.array
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.index
@@ -32,6 +35,45 @@ class Context {
nodes += names.filter { it !in nodes }.associate { it to Node(it) }
}
fun markSpecialFunctions(root: JsNode) {
val candidates = mutableMapOf<JsName, SpecialFunction>()
val unsuitableNames = mutableSetOf<JsName>()
val assignedNames = mutableSetOf<JsName>()
root.accept(object : RecursiveJsVisitor() {
override fun visit(x: JsVars.JsVar) {
val name = x.name
if (!assignedNames.add(name)) {
unsuitableNames += name
}
val initializer = x.initExpression
if (initializer != null) {
val specialName = when {
isDefineInlineFunction(initializer) -> SpecialFunction.DEFINE_INLINE_FUNCTION
isWrapFunction(initializer) -> SpecialFunction.WRAP_FUNCTION
else -> null
}
specialName?.let { candidates[name] = specialName }
}
super.visit(x)
}
override fun visitBinaryExpression(x: JsBinaryOperation) {
JsAstUtils.decomposeAssignmentToVariable(x)?.let { (left, _) -> unsuitableNames += left }
}
override fun visitFunction(x: JsFunction) {
x.name?.let { unsuitableNames += it }
}
})
for ((name, function) in candidates) {
if (name !in unsuitableNames) {
name.specialFunction = function
}
}
}
fun extractNode(expression: JsExpression): Node? {
val node = extractNodeImpl(expression)?.original
return if (node != null && moduleExportsNode in generateSequence(node) { it.qualifier?.parent }) {
@@ -18,10 +18,7 @@ package org.jetbrains.kotlin.js.dce
import com.google.gwt.dev.js.rhino.CodePosition
import com.google.gwt.dev.js.rhino.ErrorReporter
import org.jetbrains.kotlin.js.backend.ast.JsBlock
import org.jetbrains.kotlin.js.backend.ast.JsGlobalBlock
import org.jetbrains.kotlin.js.backend.ast.JsNode
import org.jetbrains.kotlin.js.backend.ast.JsProgram
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.dce.Context.Node
import org.jetbrains.kotlin.js.inline.util.collectDefinedNames
import org.jetbrains.kotlin.js.inline.util.fixForwardNameReferences
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.js.dce
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction
import org.jetbrains.kotlin.js.backend.ast.metadata.specialFunction
import org.jetbrains.kotlin.js.dce.Context.Node
fun Context.isObjectDefineProperty(function: JsExpression) = isObjectFunction(function, "defineProperty")
@@ -25,9 +27,11 @@ fun Context.isObjectGetOwnPropertyDescriptor(function: JsExpression) = isObjectF
fun Context.isDefineModule(function: JsExpression): Boolean = isKotlinFunction(function, "defineModule")
fun Context.isDefineInlineFunction(function: JsExpression): Boolean = isKotlinFunction(function, "defineInlineFunction")
fun Context.isDefineInlineFunction(function: JsExpression): Boolean =
isKotlinFunction(function, "defineInlineFunction") || isSpecialFunction(function, SpecialFunction.DEFINE_INLINE_FUNCTION)
fun Context.isWrapFunction(function: JsExpression): Boolean = isKotlinFunction(function, "wrapFunction")
fun Context.isWrapFunction(function: JsExpression): Boolean =
isKotlinFunction(function, "wrapFunction") || isSpecialFunction(function, SpecialFunction.WRAP_FUNCTION)
fun Context.isObjectFunction(function: JsExpression, functionName: String): Boolean {
if (function !is JsNameRef) return false
@@ -45,6 +49,9 @@ fun Context.isKotlinFunction(function: JsExpression, name: String): Boolean {
return receiver in nodes && receiver.ident.toLowerCase() == "kotlin"
}
fun isSpecialFunction(expr: JsExpression, specialFunction: SpecialFunction): Boolean =
expr is JsNameRef && expr.qualifier == null && expr.name?.specialFunction == specialFunction
fun Context.isAmdDefine(function: JsExpression): Boolean = isTopLevelFunction(function, "define")
fun Context.isTopLevelFunction(function: JsExpression, name: String): Boolean {
@@ -22,10 +22,7 @@ import com.intellij.util.containers.SLRUCache
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind
import org.jetbrains.kotlin.js.backend.ast.metadata.imported
import org.jetbrains.kotlin.js.backend.ast.metadata.inlineStrategy
import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects
import org.jetbrains.kotlin.js.backend.ast.metadata.*
import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.js.inline.util.*
import org.jetbrains.kotlin.js.parser.OffsetToSourceMapping
@@ -51,6 +48,7 @@ private val JS_IDENTIFIER_PART = "$JS_IDENTIFIER_START\\p{Pc}\\p{Mc}\\p{Mn}\\d"
private val JS_IDENTIFIER="[$JS_IDENTIFIER_START][$JS_IDENTIFIER_PART]*"
private val DEFINE_MODULE_PATTERN = ("($JS_IDENTIFIER)\\.defineModule\\(\\s*(['\"])([^'\"]+)\\2\\s*,\\s*(\\w+)\\s*\\)").toRegex().toPattern()
private val DEFINE_MODULE_FIND_PATTERN = ".defineModule("
private val WRAP_FUNCTION_PATTERN = Regex("var\\s+($JS_IDENTIFIER)\\s*=\\s*($JS_IDENTIFIER)\\.wrapFunction\\s*;").toPattern()
class FunctionReader(
private val reporter: JsConfig.Reporter,
@@ -73,10 +71,13 @@ class FunctionReader(
val fileContent: String,
val moduleVariable: String,
val kotlinVariable: String,
val wrapFunctionVariable: String?,
offsetToSourceMappingProvider: () -> OffsetToSourceMapping,
val sourceMap: SourceMap?
) {
val offsetToSourceMapping by lazy(offsetToSourceMappingProvider)
val wrapFunctionRegex = wrapFunctionVariable?.let { Regex("\\s*$it\\s*\\(\\s*").toPattern() }
}
private val moduleNameToInfo by lazy {
@@ -98,6 +99,10 @@ class FunctionReader(
val moduleVariable = preciseMatcher.group(4)
val kotlinVariable = preciseMatcher.group(1)
val wrapFunctionVariable = WRAP_FUNCTION_PATTERN.matcher(content).let { matcher ->
if (matcher.find() && matcher.group(2) == kotlinVariable) matcher.group(1) else null
}
val sourceMap = sourceMapContent?.let {
val sourceMapResult = SourceMapParser.parse(StringReader(it))
when (sourceMapResult) {
@@ -114,6 +119,7 @@ class FunctionReader(
fileContent = content,
moduleVariable = moduleVariable,
kotlinVariable = kotlinVariable,
wrapFunctionVariable = wrapFunctionVariable,
offsetToSourceMappingProvider = { OffsetToSourceMapping(content) },
sourceMap = sourceMap
)
@@ -195,10 +201,11 @@ class FunctionReader(
offset++
}
val wrapFunctionMatcher = wrapFunctionRegex.matcher(ShallowSubSequence(source, offset, source.length))
val isWrapped = wrapFunctionMatcher.lookingAt()
val sourcePart = ShallowSubSequence(source, offset, source.length)
val wrapFunctionMatcher = info.wrapFunctionRegex?.matcher(sourcePart)
val isWrapped = wrapFunctionMatcher?.lookingAt() == true
if (isWrapped) {
offset += wrapFunctionMatcher.end()
offset += wrapFunctionMatcher!!.end()
}
val position = info.offsetToSourceMapping[offset]
@@ -220,12 +227,19 @@ class FunctionReader(
wrapperStatements?.forEach { remapper.remap(it) }
}
val allDefinedNames = collectDefinedNamesInAllScopes(function)
val replacements = hashMapOf(info.moduleVariable to moduleReference,
info.kotlinVariable to Namer.kotlinObject())
replaceExternalNames(function, replacements)
wrapperStatements?.forEach { replaceExternalNames(it, replacements) }
replaceExternalNames(function, replacements, allDefinedNames)
wrapperStatements?.forEach { replaceExternalNames(it, replacements, allDefinedNames) }
function.markInlineArguments(descriptor)
info.wrapFunctionVariable.let { wrapFunction ->
for (externalName in (collectReferencedNames(function) - allDefinedNames).filter { it.ident == wrapFunction }) {
externalName.specialFunction = SpecialFunction.WRAP_FUNCTION
}
}
val namesWithoutSizeEffects = wrapperStatements.orEmpty().asSequence()
.flatMap { collectDefinedNames(it).asSequence() }
.toSet()
@@ -283,12 +297,10 @@ private fun JsFunction.markInlineArguments(descriptor: CallableDescriptor) {
visitor.accept(this)
}
private fun replaceExternalNames(node: JsNode, replacements: Map<String, JsExpression>) {
val skipNames = collectDefinedNamesInAllScopes(node)
private fun replaceExternalNames(node: JsNode, replacements: Map<String, JsExpression>, definedNames: Set<JsName>) {
val visitor = object: JsVisitorWithContextImpl() {
override fun endVisit(x: JsNameRef, ctx: JsContext<JsNode>) {
if (x.qualifier != null || x.name in skipNames) return
if (x.qualifier != null || x.name in definedNames) return
replacements[x.ident]?.let {
ctx.replaceMe(it)
@@ -299,8 +311,6 @@ private fun replaceExternalNames(node: JsNode, replacements: Map<String, JsExpre
visitor.accept(node)
}
private val wrapFunctionRegex = Regex("\\s*[a-zA-Z_$][a-zA-Z0-9_$]*\\s*\\.\\s*wrapFunction\\s*\\(\\s*").toPattern()
private class ShallowSubSequence(private val underlying: CharSequence, private val start: Int, end: Int) : CharSequence {
override val length: Int = end - start
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
fun collectFunctionReferencesInside(scope: JsNode): List<JsName> =
collectReferencedNames(scope).filter { it.staticRef is JsFunction }
private fun collectReferencedNames(scope: JsNode): Set<JsName> {
fun collectReferencedNames(scope: JsNode): Set<JsName> {
val references = mutableSetOf<JsName>()
object : RecursiveJsVisitor() {
+6
View File
@@ -427,6 +427,12 @@ message Name {
optional int32 identifier = 2;
optional int32 local_name_id = 3;
optional bool imported = 4 [default = false];
optional SpecialFunction special_function = 5;
}
enum SpecialFunction {
DEFINE_INLINE_FUNCTION = 1;
WRAP_FUNCTION = 2;
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.serialization.js.ast
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.*
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction
import org.jetbrains.kotlin.protobuf.CodedInputStream
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.*
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Expression.ExpressionCase
@@ -443,6 +444,9 @@ class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable<Fi
if (nameProto.hasImported()) {
name.imported = nameProto.imported
}
if (nameProto.hasSpecialFunction()) {
name.specialFunction = map(nameProto.specialFunction)
}
nameCache[id] = name
name
}
@@ -513,6 +517,11 @@ class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable<Fi
InlineStrategy.NOT_INLINE -> KotlinInlineStrategy.NOT_INLINE
}
private fun map(specialFunction: JsAstProtoBuf.SpecialFunction) = when(specialFunction) {
JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION -> SpecialFunction.DEFINE_INLINE_FUNCTION
JsAstProtoBuf.SpecialFunction.WRAP_FUNCTION -> SpecialFunction.WRAP_FUNCTION
}
private fun <T : JsNode> withLocation(fileId: Int?, location: Location?, action: () -> T): T {
val deserializedFile = fileId?.let { deserializeString(it) }
val file = deserializedFile ?: fileStack.peek()
@@ -138,6 +138,62 @@ public final class JsAstProtoBuf {
// @@protoc_insertion_point(enum_scope:org.jetbrains.kotlin.serialization.js.ast.InlineStrategy)
}
/**
* Protobuf enum {@code org.jetbrains.kotlin.serialization.js.ast.SpecialFunction}
*/
public enum SpecialFunction
implements org.jetbrains.kotlin.protobuf.Internal.EnumLite {
/**
* <code>DEFINE_INLINE_FUNCTION = 1;</code>
*/
DEFINE_INLINE_FUNCTION(0, 1),
/**
* <code>WRAP_FUNCTION = 2;</code>
*/
WRAP_FUNCTION(1, 2),
;
/**
* <code>DEFINE_INLINE_FUNCTION = 1;</code>
*/
public static final int DEFINE_INLINE_FUNCTION_VALUE = 1;
/**
* <code>WRAP_FUNCTION = 2;</code>
*/
public static final int WRAP_FUNCTION_VALUE = 2;
public final int getNumber() { return value; }
public static SpecialFunction valueOf(int value) {
switch (value) {
case 1: return DEFINE_INLINE_FUNCTION;
case 2: return WRAP_FUNCTION;
default: return null;
}
}
public static org.jetbrains.kotlin.protobuf.Internal.EnumLiteMap<SpecialFunction>
internalGetValueMap() {
return internalValueMap;
}
private static org.jetbrains.kotlin.protobuf.Internal.EnumLiteMap<SpecialFunction>
internalValueMap =
new org.jetbrains.kotlin.protobuf.Internal.EnumLiteMap<SpecialFunction>() {
public SpecialFunction findValueByNumber(int number) {
return SpecialFunction.valueOf(number);
}
};
private final int value;
private SpecialFunction(int index, int value) {
this.value = value;
}
// @@protoc_insertion_point(enum_scope:org.jetbrains.kotlin.serialization.js.ast.SpecialFunction)
}
public interface LocationOrBuilder extends
// @@protoc_insertion_point(interface_extends:org.jetbrains.kotlin.serialization.js.ast.Location)
org.jetbrains.kotlin.protobuf.MessageLiteOrBuilder {
@@ -34765,13 +34821,22 @@ public final class JsAstProtoBuf {
int getLocalNameId();
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
boolean hasImported();
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
boolean getImported();
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
boolean hasSpecialFunction();
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction getSpecialFunction();
}
/**
* Protobuf type {@code org.jetbrains.kotlin.serialization.js.ast.Name}
@@ -34843,6 +34908,18 @@ public final class JsAstProtoBuf {
imported_ = input.readBool();
break;
}
case 40: {
int rawValue = input.readEnum();
org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction value = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction.valueOf(rawValue);
if (value == null) {
unknownFieldsCodedOutput.writeRawVarint32(tag);
unknownFieldsCodedOutput.writeRawVarint32(rawValue);
} else {
bitField0_ |= 0x00000010;
specialFunction_ = value;
}
break;
}
}
}
} catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
@@ -34925,23 +35002,39 @@ public final class JsAstProtoBuf {
public static final int IMPORTED_FIELD_NUMBER = 4;
private boolean imported_;
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
public boolean hasImported() {
return ((bitField0_ & 0x00000008) == 0x00000008);
}
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
public boolean getImported() {
return imported_;
}
public static final int SPECIAL_FUNCTION_FIELD_NUMBER = 5;
private org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction specialFunction_;
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
public boolean hasSpecialFunction() {
return ((bitField0_ & 0x00000010) == 0x00000010);
}
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction getSpecialFunction() {
return specialFunction_;
}
private void initFields() {
temporary_ = false;
identifier_ = 0;
localNameId_ = 0;
imported_ = false;
specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
@@ -34972,6 +35065,9 @@ public final class JsAstProtoBuf {
if (((bitField0_ & 0x00000008) == 0x00000008)) {
output.writeBool(4, imported_);
}
if (((bitField0_ & 0x00000010) == 0x00000010)) {
output.writeEnum(5, specialFunction_.getNumber());
}
output.writeRawBytes(unknownFields);
}
@@ -34997,6 +35093,10 @@ public final class JsAstProtoBuf {
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
.computeBoolSize(4, imported_);
}
if (((bitField0_ & 0x00000010) == 0x00000010)) {
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
.computeEnumSize(5, specialFunction_.getNumber());
}
size += unknownFields.size();
memoizedSerializedSize = size;
return size;
@@ -35099,6 +35199,8 @@ public final class JsAstProtoBuf {
bitField0_ = (bitField0_ & ~0x00000004);
imported_ = false;
bitField0_ = (bitField0_ & ~0x00000008);
specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
bitField0_ = (bitField0_ & ~0x00000010);
return this;
}
@@ -35138,6 +35240,10 @@ public final class JsAstProtoBuf {
to_bitField0_ |= 0x00000008;
}
result.imported_ = imported_;
if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
to_bitField0_ |= 0x00000010;
}
result.specialFunction_ = specialFunction_;
result.bitField0_ = to_bitField0_;
return result;
}
@@ -35156,6 +35262,9 @@ public final class JsAstProtoBuf {
if (other.hasImported()) {
setImported(other.getImported());
}
if (other.hasSpecialFunction()) {
setSpecialFunction(other.getSpecialFunction());
}
setUnknownFields(
getUnknownFields().concat(other.unknownFields));
return this;
@@ -35286,19 +35395,19 @@ public final class JsAstProtoBuf {
private boolean imported_ ;
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
public boolean hasImported() {
return ((bitField0_ & 0x00000008) == 0x00000008);
}
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
public boolean getImported() {
return imported_;
}
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
public Builder setImported(boolean value) {
bitField0_ |= 0x00000008;
@@ -35307,7 +35416,7 @@ public final class JsAstProtoBuf {
return this;
}
/**
* <code>optional bool imported = 4;</code>
* <code>optional bool imported = 4 [default = false];</code>
*/
public Builder clearImported() {
bitField0_ = (bitField0_ & ~0x00000008);
@@ -35316,6 +35425,41 @@ public final class JsAstProtoBuf {
return this;
}
private org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
public boolean hasSpecialFunction() {
return ((bitField0_ & 0x00000010) == 0x00000010);
}
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction getSpecialFunction() {
return specialFunction_;
}
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
public Builder setSpecialFunction(org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00000010;
specialFunction_ = value;
return this;
}
/**
* <code>optional .org.jetbrains.kotlin.serialization.js.ast.SpecialFunction special_function = 5;</code>
*/
public Builder clearSpecialFunction() {
bitField0_ = (bitField0_ & ~0x00000010);
specialFunction_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION;
return this;
}
// @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.serialization.js.ast.Name)
}
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.serialization.js.ast
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.*
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.*
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.BinaryOperation.Type.*
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.UnaryOperation.Type.*
@@ -552,6 +553,11 @@ class JsAstSerializer(private val pathResolver: (File) -> String) {
KotlinInlineStrategy.NOT_INLINE -> InlineStrategy.NOT_INLINE
}
private fun map(specialFunction: SpecialFunction) = when (specialFunction) {
SpecialFunction.DEFINE_INLINE_FUNCTION -> JsAstProtoBuf.SpecialFunction.DEFINE_INLINE_FUNCTION
SpecialFunction.WRAP_FUNCTION -> JsAstProtoBuf.SpecialFunction.WRAP_FUNCTION
}
private fun serialize(name: JsName): Int = nameMap.getOrPut(name) {
val builder = Name.newBuilder()
builder.identifier = serialize(name.ident)
@@ -564,6 +570,10 @@ class JsAstSerializer(private val pathResolver: (File) -> String) {
builder.imported = true
}
name.specialFunction?.let {
builder.specialFunction = map(it)
}
val result = nameTableBuilder.entryCount
nameTableBuilder.addEntry(builder)
result
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.js.backend.ast.*;
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind;
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction;
import org.jetbrains.kotlin.js.backend.ast.metadata.TypeCheck;
import org.jetbrains.kotlin.js.config.JsConfig;
import org.jetbrains.kotlin.js.naming.NameSuggestion;
@@ -361,6 +362,18 @@ public final class Namer {
return pureFqn(WRAP_FUNCTION, kotlinObject());
}
@NotNull
public static JsExpression createSpecialFunction(@NotNull SpecialFunction specialFunction) {
switch (specialFunction) {
case DEFINE_INLINE_FUNCTION:
return createInlineFunction();
case WRAP_FUNCTION:
return wrapFunction();
default:
throw new IllegalArgumentException("Unknown function: " + specialFunction);
}
}
@NotNull
public static String suggestedModuleName(@NotNull String id) {
if (id.isEmpty()) {
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
import org.jetbrains.kotlin.js.backend.ast.*;
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind;
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction;
import org.jetbrains.kotlin.js.config.JsConfig;
import org.jetbrains.kotlin.js.naming.NameSuggestion;
import org.jetbrains.kotlin.js.naming.NameSuggestionKt;
@@ -42,6 +43,7 @@ import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.js.translate.utils.SignatureUtilsKt;
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.resolve.BindingContext;
@@ -141,6 +143,8 @@ public final class StaticContext {
private final Map<String, JsExpression> modulesImportedForInline = new HashMap<>();
private final Map<SpecialFunction, JsName> specialFunctions = new EnumMap<>(SpecialFunction.class);
public StaticContext(
@NotNull BindingTrace bindingTrace,
@NotNull JsConfig config,
@@ -859,4 +863,14 @@ public final class StaticContext {
return moduleRef;
}).deepCopy();
}
@NotNull
public JsName getNameForSpecialFunction(@NotNull SpecialFunction specialFunction) {
return specialFunctions.computeIfAbsent(specialFunction, f -> {
JsExpression expression = Namer.createSpecialFunction(specialFunction);
JsName name = importDeclaration(f.getSuggestedName(), TranslationUtils.getTagForSpecialFunction(f), expression);
MetadataProperties.setSpecialFunction(name, f);
return name;
});
}
}
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.js.backend.ast.*;
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction;
import org.jetbrains.kotlin.js.config.JsConfig;
import org.jetbrains.kotlin.js.naming.SuggestedName;
import org.jetbrains.kotlin.js.translate.declaration.ClassModelGenerator;
@@ -819,4 +820,22 @@ public class TranslationContext {
public TranslationContext getParent() {
return parent;
}
@NotNull
public JsName getNameForSpecialFunction(@NotNull SpecialFunction function) {
if (inlineFunctionContext == null || !isPublicInlineFunction()) {
return staticContext.getNameForSpecialFunction(function);
}
else {
String tag = TranslationUtils.getTagForSpecialFunction(function);
return inlineFunctionContext.getImports().computeIfAbsent(tag, t -> {
JsExpression imported = Namer.createSpecialFunction(function);
JsName result = JsScope.declareTemporaryName(function.getSuggestedName());
MetadataProperties.setImported(result, true);
MetadataProperties.setSpecialFunction(result, function);
inlineFunctionContext.getImportBlock().getStatements().add(JsAstUtils.newVar(result, imported));
return result;
});
}
}
}
@@ -113,7 +113,7 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
function.body.statements += FunctionBodyTranslator.setDefaultValueForArguments(descriptor, innerContext)
}
innerContext.translateFunction(expression, function)
return innerContext.wrapWithInlineMetadata(function, descriptor)
return innerContext.wrapWithInlineMetadata(context, function, descriptor)
}
// used from kotlinx.serialization
@@ -101,11 +101,14 @@ fun TranslationContext.translateFunction(declaration: KtDeclarationWithBody, fun
function.functionDescriptor = descriptor
}
fun TranslationContext.wrapWithInlineMetadata(function: JsFunction, descriptor: FunctionDescriptor): JsExpression {
fun TranslationContext.wrapWithInlineMetadata(
outerContext: TranslationContext,
function: JsFunction, descriptor: FunctionDescriptor
): JsExpression {
val sourceInfo = descriptor.source.getPsi()
return if (descriptor.isInline && descriptor.isEffectivelyPublicApi) {
val metadata = InlineMetadata.compose(function, descriptor, this)
val functionWithMetadata = metadata.functionWithMetadata(sourceInfo)
val functionWithMetadata = metadata.functionWithMetadata(outerContext, sourceInfo)
config.configuration[JSConfigurationKeys.INCREMENTAL_RESULTS_CONSUMER]?.apply {
val psiFile = (descriptor.source.containingFile as? PsiSourceFile)?.psiFile ?: return@apply
@@ -136,6 +139,6 @@ fun TranslationContext.wrapWithInlineMetadata(function: JsFunction, descriptor:
else {
null
}
if (block != null) InlineMetadata.wrapFunction(FunctionWithWrapper(function, block), sourceInfo) else function
if (block != null) InlineMetadata.wrapFunction(outerContext, FunctionWithWrapper(function, block), sourceInfo) else function
}
}
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.js.translate.expression
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction
import org.jetbrains.kotlin.js.backend.ast.metadata.specialFunction
import org.jetbrains.kotlin.js.inline.util.FunctionWithWrapper
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext
@@ -43,8 +45,11 @@ class InlineMetadata(val tag: JsStringLiteral, val function: FunctionWithWrapper
}
private fun decomposeCreateFunctionCall(call: JsInvocation): InlineMetadata? {
val qualifier = call.qualifier
if (qualifier !is JsNameRef || qualifier.ident != Namer.DEFINE_INLINE_FUNCTION) return null
val qualifier = call.qualifier as? JsNameRef ?: return null
if (qualifier.ident != Namer.DEFINE_INLINE_FUNCTION &&
qualifier.name?.specialFunction != SpecialFunction.DEFINE_INLINE_FUNCTION) {
return null
}
val arguments = call.arguments
if (arguments.size != METADATA_PROPERTIES_COUNT) return null
@@ -61,8 +66,7 @@ class InlineMetadata(val tag: JsStringLiteral, val function: FunctionWithWrapper
if (callExpression !is JsInvocation) return null
val qualifier = callExpression.qualifier as? JsNameRef ?: return null
val qualifierQualifier = qualifier.qualifier as? JsNameRef ?: return null
if (qualifierQualifier.qualifier != null || qualifier.ident != Namer.WRAP_FUNCTION) return null
if (qualifier.name?.specialFunction != SpecialFunction.WRAP_FUNCTION) return null
if (callExpression.arguments.size != 1) return null
val argument = callExpression.arguments[0] as? JsFunction ?: return null
@@ -78,7 +82,7 @@ class InlineMetadata(val tag: JsStringLiteral, val function: FunctionWithWrapper
}
@JvmStatic
fun wrapFunction(function: FunctionWithWrapper, sourceInfo: Any?): JsExpression {
fun wrapFunction(context: TranslationContext, function: FunctionWithWrapper, sourceInfo: Any?): JsExpression {
val wrapperBody = function.wrapperBody ?: JsBlock(JsReturn(function.function))
val wrapper = JsFunction(function.function.scope, wrapperBody, "")
function.wrapperBody?.statements?.forEach {
@@ -90,10 +94,11 @@ class InlineMetadata(val tag: JsStringLiteral, val function: FunctionWithWrapper
}
}
return JsInvocation(Namer.wrapFunction(), wrapper).source(sourceInfo)
return JsInvocation(context.getNameForSpecialFunction(SpecialFunction.WRAP_FUNCTION).makeRef(), wrapper).source(sourceInfo)
}
}
fun functionWithMetadata(sourceInfo: Any?): JsExpression =
JsInvocation(Namer.createInlineFunction(), tag, wrapFunction(function, sourceInfo))
fun functionWithMetadata(context: TranslationContext, sourceInfo: Any?): JsExpression =
JsInvocation(context.getNameForSpecialFunction(SpecialFunction.DEFINE_INLINE_FUNCTION).makeRef(),
tag, wrapFunction(context, function, sourceInfo))
}
@@ -114,7 +114,7 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
private fun TranslationContext.addFunctionDeclaration(name: JsName, function: JsFunction, source: Any?) {
addFunctionButNotExport(name, if (isPublicInlineFunction) {
InlineMetadata.wrapFunction(FunctionWithWrapper(function, null), source)
InlineMetadata.wrapFunction(this, FunctionWithWrapper(function, null), source)
}
else {
function
@@ -127,7 +127,7 @@ fun JsFunction.withCapturedParameters(
invokingContext: TranslationContext,
source: KtDeclaration
): JsExpression {
context.addFunctionDeclaration(functionName, this, source)
invokingContext.addFunctionDeclaration(functionName, this, source)
val ref = JsAstUtils.pureFqn(functionName, null)
val invocation = JsInvocation(ref).apply { sideEffects = SideEffectKind.PURE }
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor;
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.js.backend.ast.*;
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction;
import org.jetbrains.kotlin.js.translate.context.Namer;
import org.jetbrains.kotlin.js.translate.context.TemporaryConstVariable;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
@@ -58,14 +59,15 @@ public final class TranslationUtils {
}
@NotNull
public static JsPropertyInitializer translateFunctionAsEcma5PropertyDescriptor(@NotNull JsFunction function,
@NotNull FunctionDescriptor descriptor,
@NotNull TranslationContext context) {
public static JsPropertyInitializer translateFunctionAsEcma5PropertyDescriptor(
@NotNull JsFunction function, @NotNull FunctionDescriptor descriptor,
@NotNull TranslationContext context
) {
JsExpression functionExpression = function;
if (InlineUtil.isInline(descriptor)) {
InlineMetadata metadata = InlineMetadata.compose(function, descriptor, context);
PsiElement sourceInfo = KotlinSourceElementKt.getPsi(descriptor.getSource());
functionExpression = metadata.functionWithMetadata(sourceInfo);
functionExpression = metadata.functionWithMetadata(context, sourceInfo);
}
if (DescriptorUtils.isExtension(descriptor) ||
@@ -414,4 +416,9 @@ public final class TranslationUtils {
}
return e;
}
@NotNull
public static String getTagForSpecialFunction(@NotNull SpecialFunction specialFunction) {
return "special:" + specialFunction.name();
}
}
@@ -1,3 +1,4 @@
// EXPECTED_REACHABLE_NODES: 994
// MODULE: lib
// FILE: lib.kt
fun foo(x: String) = "foo($x)"