diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EqualsTest.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EqualsTest.java index 2b451f7eec1..417773c3a84 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EqualsTest.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/EqualsTest.java @@ -65,4 +65,8 @@ public final class EqualsTest extends AbstractExpressionTest { public void testEqualsBehaviorOnNull() throws Exception { checkFooBoxIsOk(); } + + public void testSuperEquals() throws Exception { + checkFooBoxIsOk(); + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfo.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfo.kt index 56c3ffe9717..c4c8139ebdd 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfo.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfo.kt @@ -16,27 +16,21 @@ package org.jetbrains.kotlin.js.translate.callTranslator -import com.google.dart.compiler.backend.js.ast.JsExpression -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.js.translate.context.TranslationContext -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue -import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getReceiverParameterForReceiver -import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.* -import org.jetbrains.kotlin.diagnostics.DiagnosticUtils -import org.jetbrains.kotlin.js.translate.utils.JsAstUtils -import org.jetbrains.kotlin.js.translate.reference.CallArgumentTranslator -import org.jetbrains.kotlin.js.translate.utils.TranslationUtils -import com.google.dart.compiler.backend.js.ast.JsLiteral -import com.google.dart.compiler.backend.js.ast.JsConditional import com.google.dart.compiler.backend.js.ast.JsBlock -import org.jetbrains.kotlin.js.translate.general.Translation -import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils -import org.jetbrains.kotlin.psi.KtSuperExpression -import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver -import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver -import org.jetbrains.kotlin.resolve.scopes.receivers.ThisClassReceiver +import com.google.dart.compiler.backend.js.ast.JsConditional +import com.google.dart.compiler.backend.js.ast.JsExpression +import com.google.dart.compiler.backend.js.ast.JsLiteral +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticUtils +import org.jetbrains.kotlin.js.translate.context.TranslationContext +import org.jetbrains.kotlin.js.translate.reference.CallArgumentTranslator +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils +import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getReceiverParameterForReceiver +import org.jetbrains.kotlin.js.translate.utils.TranslationUtils +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.* +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue interface CallInfo { val context: TranslationContext @@ -61,33 +55,6 @@ class VariableAccessInfo(callInfo: CallInfo, val value: JsExpression? = null) : class FunctionCallInfo(callInfo: CallInfo, val argumentsInfo: CallArgumentTranslator.ArgumentsInfo) : AbstractCallInfo(), CallInfo by callInfo -val CallInfo.superCallReceiver : JsExpression? - get() { - val receiver = this.resolvedCall.dispatchReceiver - return when (receiver) { - is ExpressionReceiver -> { - val expr = receiver.expression - when (expr) { - is KtSuperExpression -> { - val superDescriptor = context.getSuperTarget(expr); - context.getDispatchReceiver(JsDescriptorUtils.getReceiverParameterForDeclaration(superDescriptor)) - } - else -> { - Translation.translateAsExpression(receiver.expression, context) - } - } - } - is ThisClassReceiver -> { - JsLiteral.THIS - } - is ExtensionReceiver -> { - JsLiteral.THIS - } - else -> { - null - } - } - } /** * no receivers - extensionOrDispatchReceiver = null, extensionReceiver = null @@ -101,10 +68,6 @@ fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall, extensionOrDispatchReceiver: JsExpression?): FunctionCallInfo { - return getCallInfo(resolvedCall, ExplicitReceivers(extensionOrDispatchReceiver)); -} - // two receiver need only for FunctionCall in VariableAsFunctionResolvedCall fun TranslationContext.getCallInfo(resolvedCall: ResolvedCall, explicitReceivers: ExplicitReceivers): FunctionCallInfo { val argsBlock = JsBlock() diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfoExtensions.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfoExtensions.kt index 01a2ffe1022..e12f8cbffd7 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfoExtensions.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfoExtensions.kt @@ -16,18 +16,19 @@ package org.jetbrains.kotlin.js.translate.callTranslator -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils -import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver -import org.jetbrains.kotlin.psi.KtSuperExpression import com.google.dart.compiler.backend.js.ast.JsExpression -import org.jetbrains.kotlin.descriptors.VariableDescriptor import com.google.dart.compiler.backend.js.ast.JsName -import org.jetbrains.kotlin.js.translate.context.Namer -import org.jetbrains.kotlin.js.translate.utils.JsAstUtils -import org.jetbrains.kotlin.js.translate.context.TranslationContext +import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.js.translate.context.Namer +import org.jetbrains.kotlin.js.translate.context.TranslationContext +import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator +import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils +import org.jetbrains.kotlin.psi.KtSuperExpression import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver val CallInfo.callableDescriptor: CallableDescriptor @@ -35,8 +36,6 @@ val CallInfo.callableDescriptor: CallableDescriptor fun CallInfo.isExtension(): Boolean = extensionReceiver != null -fun CallInfo.isMemberCall(): Boolean = dispatchReceiver != null - fun CallInfo.isNative(): Boolean = AnnotationsUtils.isNativeObject(callableDescriptor) fun CallInfo.isSuperInvocation(): Boolean { @@ -44,6 +43,12 @@ fun CallInfo.isSuperInvocation(): Boolean { return dispatchReceiver is ExpressionReceiver && dispatchReceiver.expression is KtSuperExpression } +val CallInfo.calleeOwner: JsExpression + get() { + val calleeOwner = resolvedCall.resultingDescriptor.containingDeclaration + return ReferenceTranslator.translateAsFQReference(calleeOwner, context) + } + val VariableAccessInfo.variableDescriptor: VariableDescriptor get() = callableDescriptor as VariableDescriptor 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 0dcfe8b2fa2..fa5d4d8edc3 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 @@ -203,21 +203,14 @@ object ConstructorCallCase : FunctionCallCase() { return callInfo.callableDescriptor is ConstructorDescriptor } - override fun FunctionCallInfo.noReceivers(): JsExpression { - return receiver { it } - } + override fun FunctionCallInfo.noReceivers() = doTranslate { translateArguments } - override fun FunctionCallInfo.dispatchReceiver(): JsExpression { - return receiver { - val receiver = superCallReceiver - if (receiver != null) (sequenceOf(receiver) + it).toList() else it - } - } + override fun FunctionCallInfo.dispatchReceiver() = doTranslate { argsWithReceiver(dispatchReceiver!!) } - private inline fun FunctionCallInfo.receiver(argumentTranslator: (List) -> List): JsExpression { + private inline fun FunctionCallInfo.doTranslate(getArguments: CallArgumentTranslator.ArgumentsInfo.() -> List): JsExpression { val fqName = context.getQualifiedReference(callableDescriptor) val functionRef = if (isNative()) fqName else context.aliasOrValue(callableDescriptor) { fqName } - val arguments = argumentTranslator(argumentsInfo.translateArguments) + val arguments = argumentsInfo.getArguments() val constructorDescriptor = callableDescriptor as ConstructorDescriptor if (constructorDescriptor.isPrimary || AnnotationsUtils.isNativeObject(constructorDescriptor)) { @@ -236,10 +229,9 @@ object SuperCallCase : FunctionCallCase() { override fun FunctionCallInfo.dispatchReceiver(): JsExpression { // TODO: spread operator - val prototypeClass = JsNameRef(Namer.getPrototypeName(), dispatchReceiver!!) + val prototypeClass = JsNameRef(Namer.getPrototypeName(), calleeOwner) val functionRef = Namer.getFunctionCallRef(JsNameRef(functionName, prototypeClass)) - val receiver = superCallReceiver ?: JsLiteral.THIS; - return JsInvocation(functionRef, argumentsInfo.argsWithReceiver(receiver)) + return JsInvocation(functionRef, argumentsInfo.argsWithReceiver(dispatchReceiver!!)) } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt index 6e218c5402f..9c7b64093cc 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt @@ -17,14 +17,13 @@ package org.jetbrains.kotlin.js.translate.callTranslator import com.google.dart.compiler.backend.js.ast.JsExpression -import com.google.dart.compiler.backend.js.ast.JsNameRef -import com.google.dart.compiler.backend.js.ast.JsLiteral import com.google.dart.compiler.backend.js.ast.JsInvocation +import com.google.dart.compiler.backend.js.ast.JsNameRef import org.jetbrains.kotlin.descriptors.CallableDescriptor -import java.util.Collections import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure import org.jetbrains.kotlin.js.translate.context.Namer.getCapturedVarAccessor +import org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure +import java.util.* object NativeVariableAccessCase : VariableAccessCase() { @@ -110,15 +109,11 @@ object DelegatePropertyAccessIntrinsic : DelegateIntrinsic { object SuperPropertyAccessCase : VariableAccessCase() { override fun VariableAccessInfo.dispatchReceiver(): JsExpression { val variableName = context.program().getStringLiteral(this.variableName.ident) - val jsReceiver = superCallReceiver - var propertyOwner = when (jsReceiver) { - null -> JsLiteral.THIS - else -> jsReceiver - } + return if (isGetAccess()) - JsInvocation(context.namer().callGetProperty, propertyOwner, dispatchReceiver!!, variableName) + JsInvocation(context.namer().callGetProperty, dispatchReceiver!!, calleeOwner, variableName) else - JsInvocation(context.namer().callSetProperty, propertyOwner, dispatchReceiver!!, variableName, value!!) + JsInvocation(context.namer().callSetProperty, dispatchReceiver!!, calleeOwner, variableName, value!!) } } 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 72eab5767b0..a1e47f2393d 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 @@ -27,8 +27,6 @@ import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics; import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.KtExpression; -import org.jetbrains.kotlin.psi.KtSuperExpression; -import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.DescriptorUtils; @@ -38,7 +36,6 @@ import java.util.Map; import static org.jetbrains.kotlin.js.translate.context.UsageTrackerKt.getNameForCapturedDescriptor; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForElement; -import static org.jetbrains.kotlin.resolve.BindingContext.*; /** * All the info about the state of the translation process. @@ -433,16 +430,4 @@ public class TranslationContext { } return null; } - - @NotNull - public DeclarationDescriptor getSuperTarget(KtSuperExpression expression) { - PsiElement labelPsi = bindingContext().get(LABEL_TARGET, expression.getTargetLabel()); - ClassDescriptor labelTarget = (ClassDescriptor) bindingContext().get(DECLARATION_TO_DESCRIPTOR, labelPsi); - if (labelTarget != null) { - return labelTarget; - } - DeclarationDescriptor descriptor = bindingContext().get(REFERENCE_TARGET, expression.getInstanceReference()); - assert descriptor != null : "Missing declaration descriptor: " + PsiUtilsKt.getTextWithLocation(expression); - return descriptor; - } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java index d834d0f8982..72ac9aed74c 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java @@ -18,13 +18,11 @@ package org.jetbrains.kotlin.js.translate.expression; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties; +import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.descriptors.ClassifierDescriptor; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.descriptors.FunctionDescriptor; -import org.jetbrains.kotlin.descriptors.VariableDescriptor; +import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention; import org.jetbrains.kotlin.js.translate.context.Namer; @@ -40,6 +38,7 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.psi.*; +import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContextUtils; import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt; @@ -56,13 +55,15 @@ import java.util.List; import static org.jetbrains.kotlin.js.translate.context.Namer.getCapturedVarAccessor; import static org.jetbrains.kotlin.js.translate.general.Translation.translateAsExpression; -import static org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator.translateAsFQReference; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.*; import static org.jetbrains.kotlin.js.translate.utils.ErrorReportingUtils.message; import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.convertToStatement; import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.newVar; import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getReceiverParameterForDeclaration; import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateInitializerForProperty; +import static org.jetbrains.kotlin.resolve.BindingContext.DECLARATION_TO_DESCRIPTOR; +import static org.jetbrains.kotlin.resolve.BindingContext.LABEL_TARGET; +import static org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET; import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure; public final class ExpressionVisitor extends TranslatorVisitor { @@ -454,9 +455,9 @@ public final class ExpressionVisitor extends TranslatorVisitor { @Override @NotNull public JsNode visitSuperExpression(@NotNull KtSuperExpression expression, @NotNull TranslationContext context) { - DeclarationDescriptor superClassDescriptor = context.bindingContext().get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference()); - assert superClassDescriptor != null: message(expression); - return translateAsFQReference(superClassDescriptor, context); + DeclarationDescriptor superTarget = getSuperTarget(context, expression); + ReceiverParameterDescriptor receiver = getReceiverParameterForDeclaration(superTarget); + return context.getDispatchReceiver(receiver); } @Override @@ -522,4 +523,16 @@ public final class ExpressionVisitor extends TranslatorVisitor { return super.visitAnnotatedExpression(expression, context); } + + @NotNull + private static DeclarationDescriptor getSuperTarget(TranslationContext context, KtSuperExpression expression) { + BindingContext bindingContext = context.bindingContext(); + PsiElement labelPsi = bindingContext.get(LABEL_TARGET, expression.getTargetLabel()); + ClassDescriptor labelTarget = (ClassDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, labelPsi); + if (labelTarget != null) return labelTarget; + + DeclarationDescriptor descriptor = bindingContext.get(REFERENCE_TARGET, expression.getInstanceReference()); + assert descriptor != null : "Missing declaration descriptor: " + PsiUtilsKt.getTextWithLocation(expression); + return descriptor; + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/KotlinFunctionIntrinsic.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/KotlinFunctionIntrinsic.java index f41b41848fb..b279fe84bc4 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/KotlinFunctionIntrinsic.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/KotlinFunctionIntrinsic.java @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; import java.util.List; -public final class KotlinFunctionIntrinsic extends FunctionIntrinsic { +public class KotlinFunctionIntrinsic extends FunctionIntrinsic { @NotNull private final JsNameRef function; diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java index 5f715da58bd..832a319e7b1 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TopLevelFIF.java @@ -16,7 +16,10 @@ package org.jetbrains.kotlin.js.translate.intrinsic.functions.factories; -import com.google.dart.compiler.backend.js.ast.*; +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.JsNameRef; +import com.google.dart.compiler.backend.js.ast.JsNew; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.PrimitiveType; @@ -27,10 +30,12 @@ import org.jetbrains.kotlin.js.patterns.DescriptorPredicate; import org.jetbrains.kotlin.js.patterns.NamePredicate; import org.jetbrains.kotlin.js.resolve.JsPlatform; import org.jetbrains.kotlin.js.translate.callTranslator.CallInfo; +import org.jetbrains.kotlin.js.translate.callTranslator.CallInfoExtensionsKt; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic; import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils; import org.jetbrains.kotlin.js.translate.utils.BindingUtils; +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.psi.KtQualifiedExpression; @@ -50,13 +55,30 @@ import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getStableMan public final class TopLevelFIF extends CompositeFIF { public static final DescriptorPredicate EQUALS_IN_ANY = pattern("kotlin", "Any", "equals"); + @NotNull + private static final KotlinFunctionIntrinsic KOTLIN_ANY_EQUALS = new KotlinFunctionIntrinsic("equals") { + @NotNull + @Override + public JsExpression apply( + @NotNull CallInfo callInfo, @NotNull List arguments, @NotNull TranslationContext context + ) { + if (CallInfoExtensionsKt.isSuperInvocation(callInfo)) { + JsExpression dispatchReceiver = callInfo.getDispatchReceiver(); + assert arguments.size() == 1 && dispatchReceiver != null; + return JsAstUtils.equality(dispatchReceiver, arguments.get(0)); + } + + return super.apply(callInfo, arguments, context); + } + }; + @NotNull public static final KotlinFunctionIntrinsic KOTLIN_EQUALS = new KotlinFunctionIntrinsic("equals"); @NotNull - public static final DescriptorPredicate HASH_CODE_IN_ANY = pattern("kotlin", "Any", "hashCode"); + private static final DescriptorPredicate HASH_CODE_IN_ANY = pattern("kotlin", "Any", "hashCode"); @NotNull - public static final KotlinFunctionIntrinsic KOTLIN_HASH_CODE = new KotlinFunctionIntrinsic("hashCode"); + private static final KotlinFunctionIntrinsic KOTLIN_HASH_CODE = new KotlinFunctionIntrinsic("hashCode"); @NotNull private static final FunctionIntrinsic RETURN_RECEIVER_INTRINSIC = new FunctionIntrinsic() { @@ -127,7 +149,7 @@ public final class TopLevelFIF extends CompositeFIF { public static final FunctionIntrinsicFactory INSTANCE = new TopLevelFIF(); private TopLevelFIF() { - add(EQUALS_IN_ANY, KOTLIN_EQUALS); + add(EQUALS_IN_ANY, KOTLIN_ANY_EQUALS); add(pattern("kotlin", "toString").isExtensionOf(FQ_NAMES.any.asString()), TO_STRING); add(pattern("kotlin", "equals").isExtensionOf(FQ_NAMES.any.asString()), KOTLIN_EQUALS); add(HASH_CODE_IN_ANY, KOTLIN_HASH_CODE); diff --git a/js/js.translator/testData/_commonFiles/asserts.kt b/js/js.translator/testData/_commonFiles/asserts.kt index f40b21da3bd..d5cfb0520d4 100644 --- a/js/js.translator/testData/_commonFiles/asserts.kt +++ b/js/js.translator/testData/_commonFiles/asserts.kt @@ -2,7 +2,7 @@ package kotlin // This file should be excluded from tests using StdLib, as these methods conflict with corresponding methods from kotlin.test // see StdLibTestBase.removeAdHocAssertions -fun fail(message: String? = null): Nothing = throw Exception(message) +fun fail(message: String? = null): Nothing = js("throw new Error(message)") fun assertEquals(expected: T, actual: T, message: String? = null) { if (expected != actual) { diff --git a/js/js.translator/testData/dynamic/cases/equals.kt b/js/js.translator/testData/dynamic/cases/equals.kt index a0e7d3465cc..802bac02c2d 100644 --- a/js/js.translator/testData/dynamic/cases/equals.kt +++ b/js/js.translator/testData/dynamic/cases/equals.kt @@ -1,10 +1,11 @@ package foo object f { - var equalsCalled = false + var equalsCalled = 0 override fun equals(other: Any?): Boolean { - equalsCalled = true + equalsCalled++ + if (equalsCalled > 1) return false return super.equals(other) } } @@ -40,7 +41,7 @@ fun box(): String { val ff: dynamic = f testFalse { ff.equals(v) } - assertTrue(f.equalsCalled, "f.equalsCalled") + assertEquals(1, f.equalsCalled) return "OK" } diff --git a/js/js.translator/testData/expression/equals/cases/superEquals.kt b/js/js.translator/testData/expression/equals/cases/superEquals.kt new file mode 100644 index 00000000000..1c2eb24d3e7 --- /dev/null +++ b/js/js.translator/testData/expression/equals/cases/superEquals.kt @@ -0,0 +1,51 @@ +package foo + +open class A { + var log = "" + + var called = false + + override fun equals(other: Any?): Boolean { + if (called) fail("recursion detected") + + log += "A.equals;" + + called = true + val result = super.equals(other) + called = false + return result + } +} + +class B : A() { + override fun equals(other: Any?): Boolean { + log += "B.equals;" + if (other == null) return false + return super.equals(other) + } +} + + +fun box(): String { + val a = A() + testFalse { a == A() } + assertEquals("A.equals;", a.log) + + val b1 = B() + testTrue { b1 == b1 } + assertEquals("B.equals;A.equals;", b1.log) + + val b2 = B() + testFalse { b2 == B() } + assertEquals("B.equals;A.equals;", b2.log) + + val b3 = B() + testFalse { b3 == null } + assertEquals("", b3.log) + + val b4 = B() + testFalse { b4.equals(null) } + assertEquals("B.equals;", b4.log) + + return "OK" +}