diff --git a/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/metadata/metadataProperties.kt b/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/metadata/metadataProperties.kt index e638a71ef5e..2aba228f01c 100644 --- a/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/metadata/metadataProperties.kt +++ b/js/js.dart-ast/src/com/google/dart/compiler/backend/js/ast/metadata/metadataProperties.kt @@ -19,11 +19,14 @@ package com.google.dart.compiler.backend.js.ast.metadata import com.google.dart.compiler.backend.js.ast.* import org.jetbrains.kotlin.builtins.InlineStrategy import kotlin.properties.Delegates +import org.jetbrains.kotlin.descriptors.CallableDescriptor public var JsName.staticRef: JsNode? by MetadataProperty(default = null) public var JsInvocation.inlineStrategy: InlineStrategy? by MetadataProperty(default = null) +public var JsInvocation.descriptor: CallableDescriptor? by MetadataProperty(default = null) + public var JsFunction.isLocal: Boolean by MetadataProperty(default = false) public var JsParameter.hasDefaultValue: Boolean by MetadataProperty(default = false) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallExpressionTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallExpressionTranslator.java index 519207c54eb..7ce224f08ff 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallExpressionTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallExpressionTranslator.java @@ -17,13 +17,11 @@ package org.jetbrains.kotlin.js.translate.reference; import com.google.dart.compiler.backend.js.ast.*; -import com.google.dart.compiler.backend.js.ast.metadata.MetadataPackage; import com.google.dart.compiler.common.SourceInfoImpl; import com.google.gwt.dev.js.JsParser; import com.google.gwt.dev.js.ThrowExceptionOnErrorReporter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.builtins.InlineStrategy; import org.jetbrains.kotlin.builtins.InlineUtil; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.*; @@ -47,6 +45,7 @@ import java.io.StringReader; import java.util.ArrayList; import java.util.List; +import static org.jetbrains.kotlin.js.translate.utils.UtilsPackage.setInlineCallMetadata; import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getFunctionResolvedCallWithAssert; import static org.jetbrains.kotlin.js.resolve.diagnostics.JsCallChecker.isJsCall; @@ -65,11 +64,10 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl } JsExpression callExpression = (new CallExpressionTranslator(expression, receiver, context)).translate(); + CallableDescriptor descriptor = getFunctionDescriptor(expression, context); - if (shouldBeInlined(expression, context) - && callExpression instanceof JsInvocation) { - - MetadataPackage.setInlineStrategy((JsInvocation) callExpression, InlineStrategy.IN_PLACE); + if (shouldBeInlined(expression, context)) { + setInlineCallMetadata(callExpression, descriptor, context); } return callExpression; @@ -78,17 +76,7 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl public static boolean shouldBeInlined(@NotNull JetCallExpression expression, @NotNull TranslationContext context) { if (!context.getConfig().isInlineEnabled()) return false; - ResolvedCall resolvedCall = CallUtilPackage.getResolvedCall(expression, context.bindingContext()); - assert resolvedCall != null; - - CallableDescriptor descriptor; - - if (resolvedCall instanceof VariableAsFunctionResolvedCall) { - descriptor = ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall().getCandidateDescriptor(); - } else { - descriptor = resolvedCall.getCandidateDescriptor(); - } - + CallableDescriptor descriptor = getFunctionDescriptor(expression, context); return shouldBeInlined(descriptor); } @@ -106,6 +94,21 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl return false; } + @NotNull + private static CallableDescriptor getFunctionDescriptor( + @NotNull JetCallExpression expression, + @NotNull TranslationContext context + ) { + ResolvedCall resolvedCall = CallUtilPackage.getResolvedCall(expression, context.bindingContext()); + assert resolvedCall != null; + + if (resolvedCall instanceof VariableAsFunctionResolvedCall) { + return ((VariableAsFunctionResolvedCall) resolvedCall).getVariableCall().getCandidateDescriptor(); + } + + return resolvedCall.getCandidateDescriptor(); + } + private CallExpressionTranslator( @NotNull JetCallExpression expression, @Nullable JsExpression receiver, diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/inlineUtils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/inlineUtils.kt new file mode 100644 index 00000000000..606502bbbe1 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/inlineUtils.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.js.translate.utils + +import com.google.dart.compiler.backend.js.ast.* +import com.google.dart.compiler.backend.js.ast.metadata.* +import org.jetbrains.kotlin.builtins.InlineStrategy +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.js.inline.util.isCallInvocation +import org.jetbrains.kotlin.js.translate.context.TranslationContext +import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor + +/** + * Recursively walks expression and sets metadata for all invocations of descriptor. + * + * When JetExpression is compiled, the resulting JsExpression + * might not be JsInvocation. + * + * For example, extension call with nullable receiver: + * x?.fn(y) + * will compile to: + * (x != null) ? fn.call(x, y) : null + */ +fun setInlineCallMetadata( + expression: JsExpression, + descriptor: CallableDescriptor, + context: TranslationContext +) { + assert(CallExpressionTranslator.shouldBeInlined(descriptor)) { + "Expected descriptor of callable, that should be inlined, but got: $descriptor" + } + + val name = context.aliasedName(descriptor) + + val visitor = object : RecursiveJsVisitor() { + override fun visitInvocation(invocation: JsInvocation?) { + if (invocation == null) return + + super.visitInvocation(invocation) + + if (name == invocation.name) { + invocation.descriptor = descriptor + invocation.inlineStrategy = InlineStrategy.IN_PLACE + } + } + } + + visitor.accept(expression) +} + +fun TranslationContext.aliasedName(descriptor: CallableDescriptor): JsName { + val alias = getAliasForDescriptor(descriptor) + val aliasName = (alias as? JsNameRef)?.getName() + + return aliasName ?: getNameForDescriptor(descriptor) +} + +val JsExpression?.name: JsName? + get() = when (this) { + is JsInvocation -> { + val qualifier = this.getQualifier() + + when { + isCallInvocation(this) -> (qualifier as JsNameRef).getQualifier().name + else -> qualifier.name + } + } + is JsNameRef -> this.getName() + else -> null + }