diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTest.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTest.java index 278f65a6adf..fd3dc1bd07f 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTest.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTest.java @@ -30,4 +30,24 @@ public class NestedTypesTest extends SingleFileTranslationTest { public void testInner() throws Exception { checkFooBoxIsOk(); } + + public void testOuterThis() throws Exception { + checkFooBoxIsOk(); + } + + public void testInstantiateInDerived() throws Exception { + checkFooBoxIsOk(); + } + + public void testInstantiateInDerivedLabeled() throws Exception { + checkFooBoxIsOk(); + } + + public void testInstantiateInSameClass() throws Exception { + checkFooBoxIsOk(); + } + + public void testProperOuter() throws Exception { + checkFooBoxIsOk(); + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt index 209eefc5a6a..f05e8374fe9 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt @@ -28,12 +28,15 @@ import org.jetbrains.kotlin.js.translate.operation.OperatorTable import org.jetbrains.kotlin.js.translate.reference.CallArgumentTranslator import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.js.translate.utils.JsAstUtils +import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils import org.jetbrains.kotlin.js.translate.utils.PsiUtils import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ThisClassReceiver import org.jetbrains.kotlin.util.OperatorNameConventions import java.util.ArrayList @@ -227,8 +230,21 @@ object ConstructorCallCase : FunctionCallCase() { val receiver = this.resolvedCall.dispatchReceiver var allArguments = when (receiver) { is ExpressionReceiver -> { - val jsReceiver = Translation.translateAsExpression(receiver.expression, context) - (sequenceOf(jsReceiver) + argumentsInfo.translateArguments).toList() + val expr = receiver.expression + when (expr) { + is KtSuperExpression -> { + val superDescriptor = context.bindingContext().get(BindingContext.REFERENCE_TARGET, expr.instanceReference) + val jsReceiver = context.getDispatchReceiver(JsDescriptorUtils.getReceiverParameterForDeclaration(superDescriptor)) + (sequenceOf(jsReceiver) + argumentsInfo.translateArguments).toList() + } + else -> { + val jsReceiver = Translation.translateAsExpression(receiver.expression, context) + (sequenceOf(jsReceiver) + argumentsInfo.translateArguments).toList() + } + } + } + is ThisClassReceiver -> { + (sequenceOf(JsLiteral.THIS) + argumentsInfo.translateArguments).toList() } else -> argumentsInfo.translateArguments } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index 3b9dc1a9c9d..a106c5d9ec1 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -349,7 +349,7 @@ public class TranslationContext { return alias; } } - if (cls == classDescriptor || parent == null) { + if (DescriptorUtils.isSubclass(classDescriptor, cls) || parent == null) { return JsLiteral.THIS; } ClassDescriptor parentDescriptor = parent.classDescriptor; diff --git a/js/js.translator/testData/nestedTypes/cases/instantiateInDerived.kt b/js/js.translator/testData/nestedTypes/cases/instantiateInDerived.kt new file mode 100644 index 00000000000..7c1d58721f6 --- /dev/null +++ b/js/js.translator/testData/nestedTypes/cases/instantiateInDerived.kt @@ -0,0 +1,42 @@ +package foo + +open class A(val value: String) { + inner class B(val s: String) { + val result = value + "_" + s + } +} + +class C : A("fromC") { + fun classReceiver() = B("OK") + fun superReceiver() = super.B("OK") + + fun newAReceiver() = A("fromA").B("OK") + fun aReceiver(): B { + val a = A("fromA") + return a.B("OK") + } + + fun A.extReceiver() = this.B("OK") + fun extReceiver() = A("fromA").extReceiver() +} + +fun box(): String { + val receiver = C() + var result = receiver.classReceiver().result + if (result != "fromC_OK") return "fail 1: $result" + + result = receiver.superReceiver().result + if (result != "fromC_OK") return "fail 2: $result" + + + result = receiver.aReceiver().result + if (result != "fromA_OK") return "fail 3: $result" + + result = receiver.newAReceiver().result + if (result != "fromA_OK") return "fail 3: $result" + + result = receiver.extReceiver().result + if (result != "fromA_OK") return "fail 3: $result" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/nestedTypes/cases/instantiateInDerivedLabeled.kt b/js/js.translator/testData/nestedTypes/cases/instantiateInDerivedLabeled.kt new file mode 100644 index 00000000000..663cc946fa8 --- /dev/null +++ b/js/js.translator/testData/nestedTypes/cases/instantiateInDerivedLabeled.kt @@ -0,0 +1,44 @@ +package foo + +open class A(val value: String) { + inner class B(val s: String) { + val result = value + "_" + s + } +} + +class C : A("fromC") { + + inner class X: A("fromX") { + fun classReceiver() = B("OK") + fun superReceiver() = super.B("OK") + fun superXReceiver() = super@X.B("OK") + fun superXCastReceiver() = (this@X as A).B("OK") + + fun superCReceiver() = super@C.B("OK") + fun superCCastReceiver() = (this@C as A).B("OK") + } +} + +fun box(): String { + val receiver = C().X() + var result = receiver.classReceiver().result + if (result != "fromX_OK") return "fail 1: $result" + + result = receiver.superReceiver().result + if (result != "fromX_OK") return "fail 2: $result" + + result = receiver.superXReceiver().result + if (result != "fromX_OK") return "fail 3: $result" + + result = receiver.superXCastReceiver().result + if (result != "fromX_OK") return "fail 4: $result" + + + result = receiver.superCReceiver().result + if (result != "fromC_OK") return "fail 5: $result" + + result = receiver.superCCastReceiver().result + if (result != "fromC_OK") return "fail 6: $result" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/nestedTypes/cases/instantiateInSameClass.kt b/js/js.translator/testData/nestedTypes/cases/instantiateInSameClass.kt new file mode 100644 index 00000000000..60b9915aa4a --- /dev/null +++ b/js/js.translator/testData/nestedTypes/cases/instantiateInSameClass.kt @@ -0,0 +1,36 @@ +package foo + +class C(val value: String = "C") { + + inner class B(val s: String) { + val result = value + "_" + s + } + + fun classReceiver() = B("OK") + + fun newCReceiver() = C("newC").B("OK") + fun cReceiver(): B { + val c = C("newC") + return c.B("OK") + } + + fun C.extReceiver1() = this.B("OK") + fun extReceiver() = C("newC").extReceiver1() +} + +fun box(): String { + val receiver = C() + var result = receiver.classReceiver().result + if (result != "C_OK") return "fail 1: $result" + + result = receiver.cReceiver().result + if (result != "newC_OK") return "fail 3: $result" + + result = receiver.newCReceiver().result + if (result != "newC_OK") return "fail 3: $result" + + result = receiver.extReceiver().result + if (result != "newC_OK") return "fail 3: $result" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/nestedTypes/cases/outerThis.kt b/js/js.translator/testData/nestedTypes/cases/outerThis.kt new file mode 100644 index 00000000000..e3c40e71bfa --- /dev/null +++ b/js/js.translator/testData/nestedTypes/cases/outerThis.kt @@ -0,0 +1,14 @@ +package foo + +class Outer() { + inner class Inner() { + val outer: Outer get() = this@Outer + } + + public val x : Inner = Inner() +} + +fun box() : String { + val o = Outer() + return if (o === o.x.outer) "OK" else "fail" +} diff --git a/js/js.translator/testData/nestedTypes/cases/properOuter.kt b/js/js.translator/testData/nestedTypes/cases/properOuter.kt new file mode 100644 index 00000000000..660a19b8119 --- /dev/null +++ b/js/js.translator/testData/nestedTypes/cases/properOuter.kt @@ -0,0 +1,17 @@ +package foo + +open class A(val s: String) { + open inner class B(val s: String) { + fun testB() = s + this@A.s + } + + open inner class C(): A("C") { + fun testC() = + B("B_").testB() + } +} + +fun box(): String { + val res = A("A").C().testC() + return if (res == "B_C") "OK" else res; +} \ No newline at end of file