JS backend: add super call support
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.k2js.test.semantics;
|
||||
|
||||
import org.jetbrains.k2js.test.SingleFileTranslationTest;
|
||||
|
||||
public class SuperCallTest extends SingleFileTranslationTest {
|
||||
public SuperCallTest() {
|
||||
super("superCall/");
|
||||
}
|
||||
|
||||
public void testTraitSuperCall() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testClassSuperCall() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
public void testNativeSuperClass() throws Exception {
|
||||
checkFooBoxIsOk();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,6 +49,7 @@ public final class Namer {
|
||||
private static final String THROW_NPE_FUN_NAME = "throwNPE";
|
||||
private static final String CLASS_OBJECT_GETTER = "object";
|
||||
private static final String CLASS_OBJECT_INITIALIZER = "object_initializer$";
|
||||
private static final String PROTOTYPE_NAME = "prototype";
|
||||
|
||||
|
||||
private static final String DELEGATE_POSTFIX = "$delegate";
|
||||
@@ -113,6 +114,16 @@ public final class Namer {
|
||||
return CLASS_OBJECT_INITIALIZER;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getPrototypeName() {
|
||||
return PROTOTYPE_NAME;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsNameRef getRefToPrototype(@NotNull JsExpression classOrTraitExpression) {
|
||||
return new JsNameRef(getPrototypeName(), classOrTraitExpression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getDelegateName(@NotNull String propertyName) {
|
||||
return propertyName + DELEGATE_POSTFIX;
|
||||
@@ -243,7 +254,7 @@ public final class Namer {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static String generateNamespaceName(DeclarationDescriptor descriptor) {
|
||||
static String generateNamespaceName(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (DescriptorUtils.isRootNamespace((NamespaceDescriptor) descriptor)) {
|
||||
return getRootNamespaceName();
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ import org.jetbrains.k2js.translate.utils.mutator.AssignToExpressionMutator;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.general.Translation.translateAsExpression;
|
||||
import static org.jetbrains.k2js.translate.reference.ReferenceTranslator.translateAsFQReference;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.ErrorReportingUtils.message;
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
|
||||
@@ -430,6 +431,14 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
return AccessTranslationUtils.translateAsGet(expression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitSuperExpression(@NotNull JetSuperExpression expression, @NotNull TranslationContext context) {
|
||||
DeclarationDescriptor superClassDescriptor = context.bindingContext().get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
|
||||
assert superClassDescriptor != null: message(expression);
|
||||
return translateAsFQReference(superClassDescriptor, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitForExpression(@NotNull JetForExpression expression,
|
||||
|
||||
@@ -16,16 +16,17 @@
|
||||
|
||||
package org.jetbrains.k2js.translate.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.HasArguments;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsInvocation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNew;
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.JetSuperExpression;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.k2js.translate.context.Namer;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic;
|
||||
@@ -33,6 +34,7 @@ import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
|
||||
import org.jetbrains.k2js.translate.utils.ErrorReportingUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.reference.CallParametersResolver.resolveCallParameters;
|
||||
@@ -94,6 +96,10 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
if (isExpressionAsFunction()) {
|
||||
return expressionAsFunctionCall();
|
||||
}
|
||||
if (isSuperInvocation()) {
|
||||
return superMethodCall(getThisObjectOrQualifier());
|
||||
}
|
||||
|
||||
return methodCall(getThisObjectOrQualifier());
|
||||
}
|
||||
|
||||
@@ -170,6 +176,28 @@ public final class CallTranslator extends AbstractTranslator {
|
||||
return TranslationUtils.generateInvocationArguments(receiver, arguments);
|
||||
}
|
||||
|
||||
private boolean isSuperInvocation() {
|
||||
ReceiverValue thisObject = resolvedCall.getThisObject();
|
||||
return thisObject instanceof ExpressionReceiver && ((ExpressionReceiver) thisObject).getExpression() instanceof JetSuperExpression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression superMethodCall(@Nullable JsExpression receiver) {
|
||||
return callType.constructCall(receiver, new CallType.CallConstructor() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression construct(@Nullable JsExpression receiver) { // TODO: support super val access
|
||||
assert receiver != null;
|
||||
JsExpression qualifiedCallee = getQualifiedCallee(Namer.getRefToPrototype(receiver));
|
||||
qualifiedCallee = Namer.getFunctionCallRef(qualifiedCallee);
|
||||
List<JsExpression> arguments = new ArrayList<JsExpression>(CallTranslator.this.arguments.size() + 1);
|
||||
arguments.add(JsLiteral.THIS);
|
||||
arguments.addAll(CallTranslator.this.arguments);
|
||||
return new JsInvocation(qualifiedCallee, arguments);
|
||||
}
|
||||
}, context());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression methodCall(@Nullable JsExpression receiver) {
|
||||
return callType.constructCall(receiver, new CallType.CallConstructor() {
|
||||
|
||||
@@ -266,6 +266,7 @@ String.prototype.contains = function (s) {
|
||||
},
|
||||
add: function (element) {
|
||||
this.array[this.$size++] = element;
|
||||
return true;
|
||||
},
|
||||
addAt: function (index, element) {
|
||||
this.array.splice(index, 0, element);
|
||||
|
||||
@@ -229,6 +229,10 @@ var Kotlin = {};
|
||||
|
||||
obj.$metadata$ = computeMetadata(bases, properties);
|
||||
obj.$metadata$.type = Kotlin.TYPE.TRAIT;
|
||||
|
||||
obj.prototype = {};
|
||||
Object.defineProperties(obj.prototype, obj.$metadata$.properties);
|
||||
copyProperties(obj.prototype, obj.$metadata$.functions);
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package foo
|
||||
|
||||
open class A(val barVal: Int) {
|
||||
open fun bar(): Int = 1
|
||||
open fun bar2(): Int = barVal + 1
|
||||
open fun bar3(t: Int) = t + 2
|
||||
open fun bar4(t: Int = 1) = t + 3 + barVal
|
||||
}
|
||||
|
||||
class B: A(1) {
|
||||
override fun bar(): Int {
|
||||
return super.bar() + 10;
|
||||
}
|
||||
override fun bar2(): Int {
|
||||
return super<A>.bar2() + 10;
|
||||
}
|
||||
override fun bar3(t: Int): Int {
|
||||
return super.bar3(t + 10);
|
||||
}
|
||||
override fun bar4(t: Int): Int {
|
||||
return super<A>.bar4() + 10;
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val b = B()
|
||||
if (b.bar() != 11) return "Simple call fail. b.bar() is ${b.bar()}"
|
||||
if (b.bar2() != 12) return "Wrong 'this' in supercall. b.bar2() is ${b.bar2()}"
|
||||
if (b.bar3(2) != 14) return "Supercall with parameter fail. b.bar3(2) is ${b.bar3(2)}"
|
||||
if (b.bar4() != 15) return "Supercall with default parameter & this fault. b.bar4() is ${b.bar4()}"
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package foo
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
class N() : ArrayList<Any>() {
|
||||
override fun add(el: Any) : Boolean {
|
||||
if (!super<ArrayList>.add(el)) {
|
||||
throw Exception()
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val n = N()
|
||||
if (n.add("239")) return "fail"
|
||||
if (n.get(0) == "239") return "OK";
|
||||
return "fail";
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package foo
|
||||
|
||||
trait A {
|
||||
fun bar(): Int = 2
|
||||
fun foo(t: Int): Int = t + 1
|
||||
}
|
||||
|
||||
trait B : A {
|
||||
override fun bar(): Int = 3
|
||||
}
|
||||
|
||||
class C : B, A {
|
||||
|
||||
override fun bar(): Int {
|
||||
return super<B>.bar() + super<A>.bar()
|
||||
}
|
||||
|
||||
override fun foo(t: Int): Int {
|
||||
return super<A>.foo(1) + t
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun box(): String {
|
||||
val c = C()
|
||||
if (c.foo(3) != 5) return "Trait super call fail. c.foo(3) is ${c.foo(3)}"
|
||||
if (c.bar() != 5) return "Trait super call fail. c.bar() is ${c.bar()}"
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user