Skip to content

Commit 0056242

Browse files
authored
Record.equals must accept null without an error (#10016)
Fixes #10015
1 parent b47d247 commit 0056242

File tree

2 files changed

+17
-4
lines changed

2 files changed

+17
-4
lines changed

dev/core/src/com/google/gwt/dev/jjs/impl/ImplementRecordComponents.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,21 +154,30 @@ private void implementEquals(JRecordType type, JMethod method, SourceInfo info)
154154
JMethodBody body = new JMethodBody(info);
155155
JParameter otherParam = method.getParams().get(0);
156156

157-
// Equals is built from first == check between this and other, as a fast path for the same
158-
// object and also to ensure that other isn't null. Then MyRecord.class == other.getClass(),
159-
// and now we know they're the same type and can cast safely to access fields for the rest.
157+
// if (this == other) return true;
160158
JBinaryOperation eq =
161159
new JBinaryOperation(info, JPrimitiveType.BOOLEAN, JBinaryOperator.EQ,
162160
new JThisRef(info, type),
163161
otherParam.createRef(info));
164162
body.getBlock().addStmt(new JIfStatement(info, eq,
165163
JBooleanLiteral.TRUE.makeReturnStatement(), null));
166164

165+
// other == null
166+
JBinaryOperation nonNullCheck =
167+
new JBinaryOperation(info, JPrimitiveType.BOOLEAN, JBinaryOperator.EQ,
168+
otherParam.createRef(info), JNullLiteral.INSTANCE);
169+
// MyRecordType.class != other.getClass()
167170
JBinaryOperation sameTypeCheck =
168171
new JBinaryOperation(info, JPrimitiveType.BOOLEAN, JBinaryOperator.NEQ,
169172
new JClassLiteral(info, type),
170173
new JMethodCall(info, otherParam.createRef(info), getClassMethod));
171-
body.getBlock().addStmt(new JIfStatement(info, sameTypeCheck,
174+
// other == null || MyRecordType.class != other.getClass()
175+
JBinaryOperation nullAndTypeCheck =
176+
new JBinaryOperation(info, JPrimitiveType.BOOLEAN, JBinaryOperator.OR,
177+
nonNullCheck, sameTypeCheck);
178+
179+
// if (other == null || MyRecordType.class != other.getClass()) return false;
180+
body.getBlock().addStmt(new JIfStatement(info, nullAndTypeCheck,
172181
JBooleanLiteral.FALSE.makeReturnStatement(), null));
173182

174183
// Create a local to assign to and compare each component

user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java17Test.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ public String toString() {
171171
assertFalse(0 == new TopLevelRecord("Pear", 0).hashCode());
172172

173173
assertFalse(new InnerRecord().equals(new LocalRecord()));
174+
assertFalse(new InnerRecord().equals(null));
175+
assertFalse(new LocalRecord().equals(null));
174176

175177
RecordWithReferenceType sameA = new RecordWithReferenceType(new TopLevelRecord("a", 1));
176178
RecordWithReferenceType sameB = new RecordWithReferenceType(new TopLevelRecord("a", 1));
@@ -184,6 +186,8 @@ public String toString() {
184186

185187
assertFalse(sameA.equals(different));
186188
assertFalse(sameA.hashCode() == different.hashCode());
189+
190+
assertFalse(sameA.equals(null));
187191
}
188192

189193
/**

0 commit comments

Comments
 (0)