Drop identityEquals from builtins, compiler and tests.

This commit is contained in:
Ilya Gorbunov
2016-01-21 19:40:46 +03:00
parent f5f5a2dcc1
commit 4d5ec9be3f
44 changed files with 66 additions and 185 deletions
@@ -1,52 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.codegen.intrinsics
import org.jetbrains.kotlin.codegen.Callable
import org.jetbrains.kotlin.codegen.CallableMethod
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
class IdentityEquals : IntrinsicMethod() {
override fun toCallable(method: CallableMethod): Callable =
object : IntrinsicCallable(method) {
override fun invokeMethodWithArguments(
resolvedCall: ResolvedCall<*>,
receiver: StackValue,
codegen: ExpressionCodegen
): StackValue {
val element = resolvedCall.call.callElement
val left: StackValue
val right: StackValue
if (element is KtCallExpression) {
left = StackValue.receiver(resolvedCall, receiver, codegen, this)
right = codegen.gen(resolvedCall.valueArgumentsByIndex!!.single().arguments.single().getArgumentExpression())
}
else {
element as KtBinaryExpression
left = codegen.gen(element.left)
right = codegen.gen(element.right)
}
return StackValue.cmp(KtTokens.EQEQEQ, OBJECT_TYPE, left, right)
}
}
}
@@ -51,7 +51,6 @@ public class IntrinsicMethods {
private static final IntrinsicMethod ARRAY_SIZE = new ArraySize(); private static final IntrinsicMethod ARRAY_SIZE = new ArraySize();
private static final Equals EQUALS = new Equals(); private static final Equals EQUALS = new Equals();
private static final IdentityEquals IDENTITY_EQUALS = new IdentityEquals();
private static final IteratorNext ITERATOR_NEXT = new IteratorNext(); private static final IteratorNext ITERATOR_NEXT = new IteratorNext();
private static final ArraySet ARRAY_SET = new ArraySet(); private static final ArraySet ARRAY_SET = new ArraySet();
private static final ArrayGet ARRAY_GET = new ArrayGet(); private static final ArrayGet ARRAY_GET = new ArrayGet();
@@ -127,7 +126,6 @@ public class IntrinsicMethods {
declareIntrinsicFunction(FQ_NAMES.cloneable, "clone", 0, CLONE); declareIntrinsicFunction(FQ_NAMES.cloneable, "clone", 0, CLONE);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.any, "toString", 0, TO_STRING); intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.any, "toString", 0, TO_STRING);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.any, "identityEquals", 1, IDENTITY_EQUALS);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.string, "plus", 1, STRING_PLUS); intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.string, "plus", 1, STRING_PLUS);
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOfNulls", 1, new NewArray()); intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOfNulls", 1, new NewArray());
@@ -1109,7 +1109,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
result = visitEquality(expression, context, operationSign, left, right); result = visitEquality(expression, context, operationSign, left, right);
} }
else if (OperatorConventions.IDENTITY_EQUALS_OPERATIONS.contains(operationType)) { else if (OperatorConventions.IDENTITY_EQUALS_OPERATIONS.contains(operationType)) {
context.trace.record(REFERENCE_TARGET, operationSign, components.builtIns.getIdentityEquals());
ensureNonemptyIntersectionOfOperandTypes(expression, context); ensureNonemptyIntersectionOfOperandTypes(expression, context);
// TODO : Check comparison pointlessness // TODO : Check comparison pointlessness
result = TypeInfoFactoryKt.createTypeInfo(components.builtIns.getBooleanType(), context); result = TypeInfoFactoryKt.createTypeInfo(components.builtIns.getBooleanType(), context);
@@ -2,7 +2,6 @@ class Test {
fun check(a: Any?): String { fun check(a: Any?): String {
if (this === a) return "Fail 1" if (this === a) return "Fail 1"
if (!(this !== a)) return "Fail 2" if (!(this !== a)) return "Fail 2"
if (this.identityEquals(a)) return "Fail 3"
return "OK" return "OK"
} }
} }
+1 -1
View File
@@ -4,5 +4,5 @@ fun box(): String {
val r = object : Runnable { val r = object : Runnable {
override fun run() {} override fun run() {}
} }
return if (foo(r).identityEquals(r)) "OK" else "Fail" return if (foo(r) === r) "OK" else "Fail"
} }
+1 -1
View File
@@ -4,5 +4,5 @@ fun box(): String {
val r = object : Runnable { val r = object : Runnable {
override fun run() {} override fun run() {}
} }
return if (foo(r).identityEquals(r)) "OK" else "Fail" return if (foo(r) === r) "OK" else "Fail"
} }
+4 -4
View File
@@ -7,10 +7,10 @@ class Foo {
fun box() : String { fun box() : String {
val a = Foo() val a = Foo()
val b = Foo() val b = Foo()
if (!a.identityEquals(a)) return "fail 1" if (a !== a) return "fail 1"
if (!b.identityEquals(b)) return "fail 2" if (b !== b) return "fail 2"
if (b.identityEquals(a)) return "fail 3" if (b === a) return "fail 3"
if (a.identityEquals(b)) return "fail 4" if (a === b) return "fail 4"
if( a !=b ) return "fail5" if( a !=b ) return "fail5"
return "OK" return "OK"
} }
@@ -6,6 +6,6 @@ fun box(): String {
val a = A(42) val a = A(42)
val b = a.clone() val b = a.clone()
if (b != a) return "Fail equals" if (b != a) return "Fail equals"
if (b.identityEquals(a)) return "Fail identity" if (b === a) return "Fail identity"
return "OK" return "OK"
} }
@@ -6,6 +6,6 @@ fun box(): String {
val a = A(42) val a = A(42)
val b = a.clone() val b = a.clone()
if (a != b) return "Fail equals" if (a != b) return "Fail equals"
if (a.identityEquals(b)) return "Fail identity" if (a === b) return "Fail identity"
return "OK" return "OK"
} }
@@ -10,7 +10,7 @@ fun box(): String {
val a = A(42) val a = A(42)
val b = a.clone() val b = a.clone()
if (a == b) return "Fail: $a == $b" if (a == b) return "Fail: $a == $b"
if (a.identityEquals(b)) return "Fail: $a identityEquals $b" if (a === b) return "Fail: $a === $b"
if (b.x != 239) return "Fail: b.x = ${b.x}" if (b.x != 239) return "Fail: b.x = ${b.x}"
return "OK" return "OK"
} }
@@ -7,6 +7,6 @@ fun box(): String {
a.add("prosper") a.add("prosper")
val b = a.clone() val b = a.clone()
if (a != b) return "Fail equals" if (a != b) return "Fail equals"
if (a.identityEquals(b)) return "Fail identity" if (a === b) return "Fail identity"
return "OK" return "OK"
} }
@@ -25,8 +25,8 @@ fun box(): String {
if (c.s != d.s) return "Fail s: ${d.s}" if (c.s != d.s) return "Fail s: ${d.s}"
if (c.l != d.l) return "Fail l: ${d.l}" if (c.l != d.l) return "Fail l: ${d.l}"
if (c.l.identityEquals(d.l)) return "Fail list identity" if (c.l === d.l) return "Fail list identity"
if (c.identityEquals(d)) return "Fail identity" if (c === d) return "Fail identity"
return "OK" return "OK"
} }
@@ -6,6 +6,6 @@ fun box(): String {
val a = A("OK") val a = A("OK")
val b = a.externalClone() val b = a.externalClone()
if (a != b) return "Fail equals" if (a != b) return "Fail equals"
if (a.identityEquals(b)) return "Fail identity" if (a === b) return "Fail identity"
return b.s return b.s
} }
@@ -13,23 +13,23 @@ fun box(): String {
val a = original val a = original
a += 1 a += 1
if (!(a.identityEquals(original))) return "Fail 1: $a !== $original" if (a !== original) return "Fail 1: $a !== $original"
if (a.x != 1) return "Fail 2: ${a.x} != 1" if (a.x != 1) return "Fail 2: ${a.x} != 1"
a -= 2 a -= 2
if (!(a.identityEquals(original))) return "Fail 3: $a !== $original" if (a !== original) return "Fail 3: $a !== $original"
if (a.x != -1) return "Fail 4: ${a.x} != -1" if (a.x != -1) return "Fail 4: ${a.x} != -1"
a *= -10 a *= -10
if (!(a.identityEquals(original))) return "Fail 5: $a !== $original" if (a !== original) return "Fail 5: $a !== $original"
if (a.x != 10) return "Fail 6: ${a.x} != 10" if (a.x != 10) return "Fail 6: ${a.x} != 10"
a /= 3 a /= 3
if (!(a.identityEquals(original))) return "Fail 7: $a !== $original" if (a !== original) return "Fail 7: $a !== $original"
if (a.x != 3) return "Fail 8: ${a.x} != 3" if (a.x != 3) return "Fail 8: ${a.x} != 3"
a %= 2 a %= 2
if (!(a.identityEquals(original))) return "Fail 9: $a !== $original" if (a !== original) return "Fail 9: $a !== $original"
if (a.x != 1) return "Fail 10: ${a.x} != 1" if (a.x != 1) return "Fail 10: ${a.x} != 1"
return "OK" return "OK"
@@ -9,12 +9,5 @@ fun box(): String {
val x2 = l[0] === l[0] val x2 = l[0] === l[0]
if (!x2) return "Fail 2: $x" if (!x2) return "Fail 2: $x"
val y = l[0].identityEquals(1000)
if (y) return "Fail (y): $y"
val y1 = l[0].identityEquals(1)
if (y1) return "Fail (y1): $y"
val y2 = l[0].identityEquals(l[0])
if (!y2) return "Fail (y2): $y"
return "OK" return "OK"
} }
+2 -2
View File
@@ -1,6 +1,6 @@
fun box() : String { fun box() : String {
val a = "lala" val a = "lala"
if(!a.identityEquals(a)) return "fail 1" if(a !== a) return "fail 1"
if(a.identityEquals(a)) return "OK" if(a === a) return "OK"
return "fail 2" return "fail 2"
} }
+1 -1
View File
@@ -1,7 +1,7 @@
val f : (Any) -> String = { it.toString() } val f : (Any) -> String = { it.toString() }
fun box() : String { fun box() : String {
if(!(f.identityEquals(f))) return "fail 1" if(!(f === f)) return "fail 1"
if(!(f == f)) return "fail 2" if(!(f == f)) return "fail 2"
if(!(f.equals(f))) return "fail 3" if(!(f.equals(f))) return "fail 3"
return "OK" return "OK"
@@ -1,5 +1,5 @@
package test package test
inline fun <T> doSmth(a: T) : Boolean { inline fun <T> doSmth(a: T) : Boolean {
return a.identityEquals(a) return a === a
} }
@@ -4,12 +4,12 @@ fun box(): String {
val s = arrayOf("live", "long") val s = arrayOf("live", "long")
val t: Array<String> = s.clone() val t: Array<String> = s.clone()
if (!equals(s, t)) return "Fail string" if (!equals(s, t)) return "Fail string"
if (s.identityEquals(t)) return "Fail string identity" if (s === t) return "Fail string identity"
val ss = arrayOf(s, s) val ss = arrayOf(s, s)
val tt: Array<Array<String>> = ss.clone() val tt: Array<Array<String>> = ss.clone()
if (!equals(ss, tt)) return "Fail string[]" if (!equals(ss, tt)) return "Fail string[]"
if (ss.identityEquals(tt)) return "Fail string[] identity" if (ss === tt) return "Fail string[] identity"
return "OK" return "OK"
} }
@@ -3,35 +3,35 @@ import java.util.Arrays.equals
fun box(): String { fun box(): String {
val i = intArrayOf(1, 2) val i = intArrayOf(1, 2)
if (!equals(i, i.clone())) return "Fail int" if (!equals(i, i.clone())) return "Fail int"
if (i.clone().identityEquals(i)) return "Fail int identity" if (i.clone() === i) return "Fail int identity"
val j = longArrayOf(1L, 2L) val j = longArrayOf(1L, 2L)
if (!equals(j, j.clone())) return "Fail long" if (!equals(j, j.clone())) return "Fail long"
if (j.clone().identityEquals(j)) return "Fail long identity" if (j.clone() === j) return "Fail long identity"
val s = shortArrayOf(1.toShort(), 2.toShort()) val s = shortArrayOf(1.toShort(), 2.toShort())
if (!equals(s, s.clone())) return "Fail short" if (!equals(s, s.clone())) return "Fail short"
if (s.clone().identityEquals(s)) return "Fail short identity" if (s.clone() === s) return "Fail short identity"
val b = byteArrayOf(1.toByte(), 2.toByte()) val b = byteArrayOf(1.toByte(), 2.toByte())
if (!equals(b, b.clone())) return "Fail byte" if (!equals(b, b.clone())) return "Fail byte"
if (b.clone().identityEquals(b)) return "Fail byte identity" if (b.clone() === b) return "Fail byte identity"
val c = charArrayOf('a', 'b') val c = charArrayOf('a', 'b')
if (!equals(c, c.clone())) return "Fail char" if (!equals(c, c.clone())) return "Fail char"
if (c.clone().identityEquals(c)) return "Fail char identity" if (c.clone() === c) return "Fail char identity"
val d = doubleArrayOf(1.0, -1.0) val d = doubleArrayOf(1.0, -1.0)
if (!equals(d, d.clone())) return "Fail double" if (!equals(d, d.clone())) return "Fail double"
if (d.clone().identityEquals(d)) return "Fail double identity" if (d.clone() === d) return "Fail double identity"
val f = floatArrayOf(1f, -1f) val f = floatArrayOf(1f, -1f)
if (!equals(f, f.clone())) return "Fail float" if (!equals(f, f.clone())) return "Fail float"
if (f.clone().identityEquals(f)) return "Fail float identity" if (f.clone() === f) return "Fail float identity"
val z = booleanArrayOf(true, false) val z = booleanArrayOf(true, false)
if (!equals(z, z.clone())) return "Fail boolean" if (!equals(z, z.clone())) return "Fail boolean"
if (z.clone().identityEquals(z)) return "Fail boolean identity" if (z.clone() === z) return "Fail boolean identity"
return "OK" return "OK"
} }
@@ -23,7 +23,7 @@ fun box() : String {
val y: Int? = 1000 val y: Int? = 1000
val z: Int? = 1000 val z: Int? = 1000
val res = y.identityEquals(z) val res = y === z
val c1: Any = if (1 == 1) 0 else "abc" val c1: Any = if (1 == 1) 0 else "abc"
val c2: Any = if (1 != 1) 0 else "abc" val c2: Any = if (1 != 1) 0 else "abc"
@@ -8,7 +8,7 @@ fun box(): String {
} }
} }
catch (caught: Throwable) { catch (caught: Throwable) {
if (!(caught.identityEquals(e))) return "Fail: $caught" if (caught !== e) return "Fail: $caught"
} }
return "OK" return "OK"
@@ -8,7 +8,7 @@ fun box(): String {
} }
} }
catch (caught: Throwable) { catch (caught: Throwable) {
if (!(caught.identityEquals(e))) return "Fail: $caught" if (caught !== e) return "Fail: $caught"
// If monitorexit didn't happen (a finally block failed), this assertion would fail // If monitorexit didn't happen (a finally block failed), this assertion would fail
assertThatThreadDoesNotOwnMonitor(obj) assertThatThreadDoesNotOwnMonitor(obj)
} }
@@ -18,7 +18,7 @@ fun foo() {
val y: Int? = 7 val y: Int? = 7
val z: Int? = 8 val z: Int? = 8
val res = y.identityEquals(z) val res = y === z
val c1: Any = if (1 == 1) 0 else "abc" val c1: Any = if (1 == 1) 0 else "abc"
val c2: Any = if (1 != 1) 0 else "abc" val c2: Any = if (1 != 1) 0 else "abc"
@@ -1,6 +1,9 @@
// No supertype at all // No supertype at all
fun Any.extension(<!UNUSED_PARAMETER!>arg<!>: Any?) {}
class A1 { class A1 {
fun test() { fun test() {
<!SUPER_CANT_BE_EXTENSION_RECEIVER!>super<!>.<!DEPRECATION!>identityEquals<!>(null) // Call to an extension function <!SUPER_CANT_BE_EXTENSION_RECEIVER!>super<!>.extension(null) // Call to an extension function
} }
} }
@@ -1,5 +1,7 @@
package package
public fun kotlin.Any.extension(/*0*/ arg: kotlin.Any?): kotlin.Unit
public final class A1 { public final class A1 {
public constructor A1() public constructor A1()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
-7
View File
@@ -16,13 +16,6 @@
package kotlin package kotlin
/**
* Returns true if the receiver and the [other] object are the same object instance, or if they
* are both null.
*/
@Deprecated("This function is deprecated, use === instead", ReplaceWith("this === other"))
public fun Any?.identityEquals(other: Any?): Boolean // = this === other
/** /**
* Returns a string representation of the object. Can be called with a null receiver, in which case * Returns a string representation of the object. Can be called with a null receiver, in which case
* it returns the string "null". * it returns the string "null".
@@ -1176,15 +1176,5 @@ public abstract class KotlinBuiltIns {
return getNullableAnyType(); return getNullableAnyType();
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GET FUNCTION
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@NotNull
public FunctionDescriptor getIdentityEquals() {
return first(getBuiltInsPackageFragment().getMemberScope().getContributedFunctions(Name.identifier("identityEquals"),
NoLookupLocation.FROM_BUILTINS));
}
} }
@@ -23,7 +23,6 @@ object OperatorNameConventions {
@JvmField val SET_VALUE = Name.identifier("setValue") @JvmField val SET_VALUE = Name.identifier("setValue")
@JvmField val EQUALS = Name.identifier("equals") @JvmField val EQUALS = Name.identifier("equals")
@JvmField val IDENTITY_EQUALS = Name.identifier("identityEquals")
@JvmField val COMPARE_TO = Name.identifier("compareTo") @JvmField val COMPARE_TO = Name.identifier("compareTo")
@JvmField val CONTAINS = Name.identifier("contains") @JvmField val CONTAINS = Name.identifier("contains")
@JvmField val INVOKE = Name.identifier("invoke") @JvmField val INVOKE = Name.identifier("invoke")
@@ -32,7 +32,6 @@ val ALL_SEARCHABLE_OPERATIONS: ImmutableSet<KtToken> = ImmutableSet
.addAll(ASSIGNMENT_OPERATIONS.keys) .addAll(ASSIGNMENT_OPERATIONS.keys)
.addAll(COMPARISON_OPERATIONS) .addAll(COMPARISON_OPERATIONS)
.addAll(EQUALS_OPERATIONS) .addAll(EQUALS_OPERATIONS)
.addAll(IDENTITY_EQUALS_OPERATIONS)
.addAll(IN_OPERATIONS) .addAll(IN_OPERATIONS)
.add(KtTokens.LBRACKET) .add(KtTokens.LBRACKET)
.add(KtTokens.BY_KEYWORD) .add(KtTokens.BY_KEYWORD)
@@ -50,7 +49,6 @@ fun Name.getOperationSymbolsToSearch(): Set<KtToken> {
when (this) { when (this) {
OperatorNameConventions.COMPARE_TO -> return COMPARISON_OPERATIONS_TO_SEARCH OperatorNameConventions.COMPARE_TO -> return COMPARISON_OPERATIONS_TO_SEARCH
OperatorNameConventions.EQUALS -> return EQUALS_OPERATIONS OperatorNameConventions.EQUALS -> return EQUALS_OPERATIONS
OperatorNameConventions.IDENTITY_EQUALS -> return IDENTITY_EQUALS_OPERATIONS
OperatorNameConventions.CONTAINS -> return IN_OPERATIONS_TO_SEARCH OperatorNameConventions.CONTAINS -> return IN_OPERATIONS_TO_SEARCH
OperatorNameConventions.ITERATOR -> return IN_OPERATIONS_TO_SEARCH OperatorNameConventions.ITERATOR -> return IN_OPERATIONS_TO_SEARCH
in INDEXING_OPERATION_NAMES -> return setOf(KtTokens.LBRACKET) in INDEXING_OPERATION_NAMES -> return setOf(KtTokens.LBRACKET)
@@ -32,7 +32,7 @@ class SwapBinaryExpressionIntention : SelfTargetingIntention<KtBinaryExpression>
private val SUPPORTED_OPERATIONS = setOf(PLUS, MUL, OROR, ANDAND, EQEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ, GT, LT, GTEQ, LTEQ) private val SUPPORTED_OPERATIONS = setOf(PLUS, MUL, OROR, ANDAND, EQEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ, GT, LT, GTEQ, LTEQ)
private val SUPPORTED_OPERATION_NAMES = SUPPORTED_OPERATIONS.mapNotNull { OperatorConventions.BINARY_OPERATION_NAMES[it]?.asString() }.toSet() + private val SUPPORTED_OPERATION_NAMES = SUPPORTED_OPERATIONS.mapNotNull { OperatorConventions.BINARY_OPERATION_NAMES[it]?.asString() }.toSet() +
setOf("xor", "or", "and", "equals", "identityEquals") setOf("xor", "or", "and", "equals")
} }
override fun isApplicableTo(element: KtBinaryExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtBinaryExpression, caretOffset: Int): Boolean {
@@ -1,16 +0,0 @@
// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtNamedFunction
// OPTIONS: usages
// FIND_BY_REF
class A(val n: Int) {
override fun equals(other: Any?): Boolean = other is A && other.n == n
}
fun test() {
A(0) == A(1)
A(0) != A(1)
A(0) equals A(1)
A(0) <caret>identityEquals A(1)
A(0) === A(1)
A(0) !== A(1)
}
@@ -1,3 +0,0 @@
Function call (13: 10) A(0) identityEquals A(1)
Function call (14: 10) A(0) === A(1)
Function call (15: 10) A(0) !== A(1)
-2
View File
@@ -16,8 +16,6 @@ fun foo() {
oldFun1(oldFun2(10)) oldFun1(oldFun2(10))
oldFun2() oldFun2()
1.identityEquals(2)
} }
fun unnecessarySafeCall(x: String) { fun unnecessarySafeCall(x: String) {
-2
View File
@@ -15,8 +15,6 @@ fun foo() {
bar(bar(10 + 2) + 1) bar(bar(10 + 2) + 1)
oldFun2() oldFun2()
1 === 2
} }
fun unnecessarySafeCall(x: String) { fun unnecessarySafeCall(x: String) {
@@ -126,12 +126,6 @@ public class FindUsagesTestGenerated extends AbstractFindUsagesTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("identityEquals.0.kt")
public void testIdentityEquals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/conventions/identityEquals.0.kt");
doTest(fileName);
}
@TestMetadata("inc.0.kt") @TestMetadata("inc.0.kt")
public void testInc() throws Exception { public void testInc() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/conventions/inc.0.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/conventions/inc.0.kt");
@@ -52,17 +52,6 @@ public final class TopLevelFIF extends CompositeFIF {
public static final DescriptorPredicate EQUALS_IN_ANY = pattern("kotlin", "Any", "equals"); public static final DescriptorPredicate EQUALS_IN_ANY = pattern("kotlin", "Any", "equals");
@NotNull @NotNull
public static final KotlinFunctionIntrinsic KOTLIN_EQUALS = new KotlinFunctionIntrinsic("equals"); public static final KotlinFunctionIntrinsic KOTLIN_EQUALS = new KotlinFunctionIntrinsic("equals");
@NotNull
public static final FunctionIntrinsic IDENTITY_EQUALS = new FunctionIntrinsic() {
@NotNull
@Override
public JsExpression apply(
@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments, @NotNull TranslationContext context
) {
assert arguments.size() == 1 : "Unexpected argument size for kotlin.identityEquals: " + arguments.size();
return new JsBinaryOperation(JsBinaryOperator.REF_EQ, receiver, arguments.get(0));
}
};
@NotNull @NotNull
public static final DescriptorPredicate HASH_CODE_IN_ANY = pattern("kotlin", "Any", "hashCode"); public static final DescriptorPredicate HASH_CODE_IN_ANY = pattern("kotlin", "Any", "hashCode");
@@ -141,7 +130,6 @@ public final class TopLevelFIF extends CompositeFIF {
add(EQUALS_IN_ANY, KOTLIN_EQUALS); add(EQUALS_IN_ANY, KOTLIN_EQUALS);
add(pattern("kotlin", "toString").isExtensionOf(FQ_NAMES.any.asString()), TO_STRING); add(pattern("kotlin", "toString").isExtensionOf(FQ_NAMES.any.asString()), TO_STRING);
add(pattern("kotlin", "equals").isExtensionOf(FQ_NAMES.any.asString()), KOTLIN_EQUALS); add(pattern("kotlin", "equals").isExtensionOf(FQ_NAMES.any.asString()), KOTLIN_EQUALS);
add(pattern("kotlin", "identityEquals").isExtensionOf("kotlin.Any"), IDENTITY_EQUALS);
add(HASH_CODE_IN_ANY, KOTLIN_HASH_CODE); add(HASH_CODE_IN_ANY, KOTLIN_HASH_CODE);
add(pattern(NamePredicate.PRIMITIVE_NUMBERS, "equals"), KOTLIN_EQUALS); add(pattern(NamePredicate.PRIMITIVE_NUMBERS, "equals"), KOTLIN_EQUALS);
add(pattern("String|Boolean|Char|Number.equals"), KOTLIN_EQUALS); add(pattern("String|Boolean|Char|Number.equals"), KOTLIN_EQUALS);
+1 -1
View File
@@ -24,7 +24,7 @@ fun box(): String {
val ok2 = Simple.valueOf("OK") val ok2 = Simple.valueOf("OK")
if (!ok2.equals(ok)) return "ok2 not equal ok" if (!ok2.equals(ok)) return "ok2 not equal ok"
if (ok2.hashCode() != ok.hashCode()) return "hash(ok2) not equal hash(ok)" if (ok2.hashCode() != ok.hashCode()) return "hash(ok2) not equal hash(ok)"
if (!ok2.identityEquals(ok)) return "ok2 not identity equal ok" if (ok2 !== ok) return "ok2 not identity equal ok"
if (EmptyEnum.values().size != 0) return "EmptyEnum.values().size != 0" if (EmptyEnum.values().size != 0) return "EmptyEnum.values().size != 0"
@@ -5,13 +5,13 @@ public fun hashCode(): Int = 0
public fun toString(): String = "" public fun toString(): String = ""
public class PublicClass { public class PublicClass {
override fun equals(a: Any?): Boolean = this.identityEquals(a) override fun equals(a: Any?): Boolean = this === a
override fun hashCode(): Int = 0 override fun hashCode(): Int = 0
override fun toString(): String = "PublicClass" override fun toString(): String = "PublicClass"
} }
internal class InternalClass { internal class InternalClass {
override fun equals(a: Any?): Boolean = this.identityEquals(a) override fun equals(a: Any?): Boolean = this === a
override fun hashCode(): Int = 1 override fun hashCode(): Int = 1
override fun toString(): String = "InternalClass" override fun toString(): String = "InternalClass"
@@ -22,7 +22,7 @@ internal class InternalClass {
} }
private class PrivateClass { private class PrivateClass {
override fun equals(a: Any?): Boolean = this.identityEquals(a) override fun equals(a: Any?): Boolean = this === a
override fun hashCode(): Int = 2 override fun hashCode(): Int = 2
override fun toString(): String = "InternalClass" override fun toString(): String = "InternalClass"
@@ -5,17 +5,17 @@ class X
fun box(): String { fun box(): String {
val a = X() val a = X()
val b = X() val b = X()
if (!a.identityEquals(a)) return "a !== a" if (a !== a) return "a !== a"
if (a.identityEquals(b)) return "X() === X()" if (a === b) return "X() === X()"
val c = a val c = a
if (!c.identityEquals(a)) return "c = a; c !== a" if (c !== a) return "c = a; c !== a"
if (X().identityEquals(a)) return "X() identityEquals a" if (X() === a) return "X() === a"
val t = !(X().identityEquals(a)) val t = !(X() === a)
if (!t) return "t = !(X() identityEquals a); t == false" if (!t) return "t = !(X() === a); t == false"
val f = !!(X().identityEquals(a)) val f = !!(X() === a)
if (f) return "f = !!(X() identityEquals null); f == true" if (f) return "f = !!(X() === null); f == true"
return "OK"; return "OK";
} }
@@ -1,13 +1,13 @@
package foo package foo
fun box(): String { fun box(): String {
if (!null.identityEquals(null)) return "null !== null" if (null !== null) return "null !== null"
if (!("ab".identityEquals("ab"))) return "ab !== ab" if (!("ab" === "ab")) return "ab !== ab"
if (("ab".identityEquals("a"))) return "ab === a" if ("ab" === "a") return "ab === a"
if ("0".identityEquals(0)) return "'0' === 0" if ("0" as Any === 0) return "'0' === 0"
if (!(0.identityEquals(0))) return "0 !== 0" if (!(0 === 0)) return "0 !== 0"
if (0.identityEquals(1)) return "0 === 1" if (0 === 1) return "0 === 1"
return "OK"; return "OK";
@@ -17,7 +17,7 @@ fun String.myHashCode(): Int {
class Foo(val name: String) { class Foo(val name: String) {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (other is Foo) return name == other.name if (other is Foo) return name == other.name
return this.identityEquals(other) return this === other
} }
override fun hashCode(): Int = name.myHashCode() override fun hashCode(): Int = name.myHashCode()
override fun toString(): String = "Foo($name)" override fun toString(): String = "Foo($name)"
+2 -2
View File
@@ -3,11 +3,11 @@ package foo
class A class A
inline fun compare1(a: A): Boolean { inline fun compare1(a: A): Boolean {
return a.identityEquals(a) return a === a
} }
inline fun compare2(a1: A, a2: A): Boolean { inline fun compare2(a1: A, a2: A): Boolean {
return a1.identityEquals(a2) return a1 === a2
} }
fun box(): String { fun box(): String {
+2 -2
View File
@@ -76,8 +76,8 @@ For `in` and `!in` the procedure is the same, but the order of arguments is reve
| Expression | Translated to | | Expression | Translated to |
|------------|---------------| |------------|---------------|
| `a == b` | `a?.equals(b) ?: b.identityEquals(null)` | | `a == b` | `a?.equals(b) ?: b === null` |
| `a != b` | `!(a?.equals(b) ?: b.identityEquals(null))` | | `a != b` | `!(a?.equals(b) ?: b === null)` |
*Note*: `===` and `!==` (identity checks) are not overloadable, so no conventions exist for them *Note*: `===` and `!==` (identity checks) are not overloadable, so no conventions exist for them