JS backend: fix native spread call

This commit is contained in:
Erokhin Stanislav
2014-01-28 21:52:58 +04:00
parent 4bffff43aa
commit 42437eb755
5 changed files with 46 additions and 10 deletions
@@ -37,6 +37,7 @@ public final class Namer {
public static final String OUTER_CLASS_NAME = "$outer"; public static final String OUTER_CLASS_NAME = "$outer";
private static final String CALL_FUNCTION = "call"; private static final String CALL_FUNCTION = "call";
private static final String APPLY_FUNCTION = "apply";
private static final String CLASS_OBJECT_NAME = "createClass"; private static final String CLASS_OBJECT_NAME = "createClass";
private static final String TRAIT_OBJECT_NAME = "createTrait"; private static final String TRAIT_OBJECT_NAME = "createTrait";
private static final String OBJECT_OBJECT_NAME = "createObject"; private static final String OBJECT_OBJECT_NAME = "createObject";
@@ -139,6 +140,10 @@ public final class Namer {
public static JsNameRef getFunctionCallRef(@NotNull JsExpression functionExpression) { public static JsNameRef getFunctionCallRef(@NotNull JsExpression functionExpression) {
return new JsNameRef(CALL_FUNCTION, functionExpression); return new JsNameRef(CALL_FUNCTION, functionExpression);
} }
@NotNull
public static JsNameRef getFunctionApplyRef(@NotNull JsExpression functionExpression) {
return new JsNameRef(APPLY_FUNCTION, functionExpression);
}
@NotNull @NotNull
public static Namer newInstance(@NotNull JsScope rootScope) { public static Namer newInstance(@NotNull JsScope rootScope) {
@@ -505,7 +505,7 @@ public final class StaticContext {
return null; return null;
} }
}; };
//TODO: hack! //TODO: hack! it seems like needed, only for Inheritance from native class
Rule<Boolean> nativeObjectsHaveNoQualifiers = new Rule<Boolean>() { Rule<Boolean> nativeObjectsHaveNoQualifiers = new Rule<Boolean>() {
@Override @Override
public Boolean apply(@NotNull DeclarationDescriptor descriptor) { public Boolean apply(@NotNull DeclarationDescriptor descriptor) {
@@ -33,6 +33,7 @@ import org.jetbrains.k2js.translate.utils.TranslationUtils
import org.jetbrains.k2js.translate.general.Translation import org.jetbrains.k2js.translate.general.Translation
import org.jetbrains.k2js.translate.utils.PsiUtils import org.jetbrains.k2js.translate.utils.PsiUtils
import com.google.dart.compiler.backend.js.ast.JsLiteral import com.google.dart.compiler.backend.js.ast.JsLiteral
import com.google.dart.compiler.backend.js.ast.JsName
public fun addReceiverToArgs(receiver: JsExpression, arguments: List<JsExpression>) : List<JsExpression> { public fun addReceiverToArgs(receiver: JsExpression, arguments: List<JsExpression>) : List<JsExpression> {
if (arguments.isEmpty()) if (arguments.isEmpty())
@@ -53,35 +54,41 @@ class DefaultCallCase(callInfo: FunctionCallInfo): FunctionCallCase(callInfo) {
return JsInvocation(functionRef, addReceiverToArgs(receiverObject!!, argumentsInfo.getTranslateArguments())) return JsInvocation(functionRef, addReceiverToArgs(receiverObject!!, argumentsInfo.getTranslateArguments()))
} }
// TODO: refactor after fix ArgumentsInfo - duplicate code
private fun nativeSpreadFunWithThisObjectOrReceiver(argumentsInfo: CallArgumentTranslator.ArgumentsInfo, functionName: JsName): JsExpression {
val cachedReceiver = argumentsInfo.getCachedReceiver()!!
val functionCallRef = Namer.getFunctionApplyRef(JsNameRef(functionName, cachedReceiver.assignmentExpression()))
return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments())
}
override fun FunctionCallInfo.thisObject(): JsExpression { override fun FunctionCallInfo.thisObject(): JsExpression {
if (isNative() && hasSpreadOperator()) { if (isNative() && hasSpreadOperator()) {
val cachedReceiver = argumentsInfo.getCachedReceiver()!! return nativeSpreadFunWithThisObjectOrReceiver(argumentsInfo, functionName)
val functionCallRef = Namer.getFunctionCallRef(JsNameRef(functionName, cachedReceiver.assignmentExpression()))
return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments())
} }
val functionRef = JsNameRef(functionName, thisObject!!) val functionRef = JsNameRef(functionName, thisObject!!)
return JsInvocation(functionRef, argumentsInfo.getTranslateArguments()) return JsInvocation(functionRef, argumentsInfo.getTranslateArguments())
} }
// TODO: refactor after fix ArgumentsInfo - duplicate code
override fun FunctionCallInfo.receiverArgument(): JsExpression { override fun FunctionCallInfo.receiverArgument(): JsExpression {
val qualifierForFunction = context.getQualifierForDescriptor(callableDescriptor)
if (isNative() && hasSpreadOperator()) { if (isNative() && hasSpreadOperator()) {
val functionCallRef = Namer.getFunctionCallRef(JsNameRef(functionName, qualifierForFunction)) return nativeSpreadFunWithThisObjectOrReceiver(argumentsInfo, functionName)
return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments())
} }
if (isNative()) { if (isNative()) {
return JsInvocation(JsNameRef(functionName, receiverObject), argumentsInfo.getTranslateArguments()) return JsInvocation(JsNameRef(functionName, receiverObject), argumentsInfo.getTranslateArguments())
} }
val qualifierForFunction = context.getQualifierForDescriptor(callableDescriptor)
val functionCall = JsNameRef(functionName, qualifierForFunction) // TODO: remake to call val functionCall = JsNameRef(functionName, qualifierForFunction) // TODO: remake to call
return JsInvocation(functionCall, addReceiverToArgs(receiverObject!!, argumentsInfo.getTranslateArguments())) return JsInvocation(functionCall, addReceiverToArgs(receiverObject!!, argumentsInfo.getTranslateArguments()))
} }
override fun FunctionCallInfo.noReceivers(): JsExpression { override fun FunctionCallInfo.noReceivers(): JsExpression {
val qualifierForFunction = context.getQualifierForDescriptor(callableDescriptor)
if (isNative() && hasSpreadOperator()) { if (isNative() && hasSpreadOperator()) {
val functionCallRef = Namer.getFunctionCallRef(JsNameRef(functionName, qualifierForFunction)) val functionCallRef = Namer.getFunctionApplyRef(JsNameRef(functionName))
return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments()) return JsInvocation(functionCallRef, argumentsInfo.getTranslateArguments())
} }
if (isNative()) {
return JsInvocation(JsNameRef(functionName), argumentsInfo.getTranslateArguments())
}
val qualifierForFunction = context.getQualifierForDescriptor(callableDescriptor)
val functionCall = JsNameRef(functionName, qualifierForFunction) val functionCall = JsNameRef(functionName, qualifierForFunction)
return JsInvocation(functionCall, argumentsInfo.getTranslateArguments()) return JsInvocation(functionCall, argumentsInfo.getTranslateArguments())
} }
@@ -121,6 +128,9 @@ class InvokeIntrinsic(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) {
class ConstructorCallCase(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) { class ConstructorCallCase(callInfo: FunctionCallInfo) : FunctionCallCase(callInfo) {
override fun FunctionCallInfo.noReceivers(): JsExpression { override fun FunctionCallInfo.noReceivers(): JsExpression {
if (isNative()) {
return JsNew(JsNameRef(functionName), argumentsInfo.getTranslateArguments())
}
return JsNew(context.getQualifiedReference(callableDescriptor), argumentsInfo.getTranslateArguments()) return JsNew(context.getQualifiedReference(callableDescriptor), argumentsInfo.getTranslateArguments())
} }
} }
@@ -14,6 +14,12 @@ fun count(vararg a : Int) = paramCount(*a)
// test spread operator // test spread operator
fun anotherCount(vararg a : Int) = anotherParamCount(*a) fun anotherCount(vararg a : Int) = anotherParamCount(*a)
native
fun test3(bar:Bar, dummy: Int, vararg args: Int): Boolean = js.noImpl
native
fun Bar.test2(order: Int, dummy: Int, vararg args: Int): Boolean = js.noImpl
native native
class Bar(val size: Int, order: Int = 0) { class Bar(val size: Int, order: Int = 0) {
fun test(order: Int, dummy: Int, vararg args: Int): Boolean = js.noImpl fun test(order: Int, dummy: Int, vararg args: Int): Boolean = js.noImpl
@@ -32,6 +38,10 @@ fun spreadInMethodCall(size: Int, vararg args: Int) = Bar(size).test(0, 1, *args
fun spreadInObjectMethodCall(size: Int, vararg args: Int) = obj.test(size, *args) fun spreadInObjectMethodCall(size: Int, vararg args: Int) = obj.test(size, *args)
fun spreadInMethodCallWithReceiver(size: Int, vararg args: Int) = Bar(size).test2(0, 1, *args)
fun spreadInPackageMethodCall(size: Int, vararg args: Int) = test3(Bar(size), 1, *args)
native native
fun testNativeVarargWithFunLit(vararg args: Int, f: (a: IntArray) -> Boolean): Boolean = js.noImpl fun testNativeVarargWithFunLit(vararg args: Int, f: (a: IntArray) -> Boolean): Boolean = js.noImpl
@@ -79,6 +89,12 @@ fun box(): String {
if (!(spreadInObjectMethodCall(2, 1, 2))) if (!(spreadInObjectMethodCall(2, 1, 2)))
return "failed when call method of object using spread operator" return "failed when call method of object using spread operator"
if (!spreadInMethodCallWithReceiver(2, 1, 2))
return "failed when call method using spread operator with receiver"
if (!spreadInPackageMethodCall(2, 1, 2))
return "failed when call package method using spread operator"
if (!(testNativeVarargWithFunLit(1, 2, 3) { args -> args.size == 3 })) if (!(testNativeVarargWithFunLit(1, 2, 3) { args -> args.size == 3 }))
return "failed when call native function with vararg and fun literal" return "failed when call native function with vararg and fun literal"
@@ -41,6 +41,11 @@ Bar.prototype.test = function (order, dummy /*, args */) {
Bar.checkOrder(order); Bar.checkOrder(order);
return dummy === 1 && (arguments.length - 2) === this.size; return dummy === 1 && (arguments.length - 2) === this.size;
}; };
Bar.prototype.test2 = Bar.prototype.test;
function test3(bar, dummy /*, args */) {
return dummy === 1 && (arguments.length - 2) === bar.size;
}
var obj = { var obj = {
test : function (size /*, args */) { test : function (size /*, args */) {