JS backend: add super call support

This commit is contained in:
Erokhin Stanislav
2013-10-03 19:50:57 +04:00
parent 8e940244af
commit a70782aaf7
9 changed files with 176 additions and 5 deletions
@@ -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() {
+1
View File
@@ -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"
}