Skip to content

Commit 680749e

Browse files
rakudramaCommit Queue
authored andcommitted
Add test for #47852
Bug: #47852 Change-Id: If17635dfcf9794edc2cf23ad5219ed87fda41fcb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/393182 Reviewed-by: Lasse Nielsen <[email protected]> Commit-Queue: Stephen Adams <[email protected]>
1 parent fbf331e commit 680749e

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:collection';
6+
7+
import 'package:expect/expect.dart';
8+
9+
/// Bug in dev-compiler's [putIfAbsent](https://dartbug.com/47852).
10+
void originalError() {
11+
final map = {};
12+
final key = DateTime.now(); // Overrides Object.==/hashCode
13+
bool wasAbsent = false;
14+
map.putIfAbsent(key, () {
15+
wasAbsent = true;
16+
Expect.isFalse(
17+
map.containsKey(key), 'containsKey should be false in putIfAbsent');
18+
return key;
19+
});
20+
Expect.isTrue(wasAbsent);
21+
}
22+
23+
enum AnEnum { element1, element2 }
24+
25+
class Dumb {
26+
final Object field;
27+
Dumb(this.field);
28+
29+
// Dumb hashCode to stress same-bucket paths.
30+
int get hashCode => 0;
31+
bool operator ==(Object other) => other is Dumb && this.field == other.field;
32+
33+
String toString() => 'Dumb($field)';
34+
}
35+
36+
// Test keys. These instances of classes that do and don't override `==` and
37+
// `hashCode`, and a variety of primitive values since we generally don't know
38+
// whether they have overrides.
39+
final keys = [
40+
123,
41+
3.14,
42+
10.0, // int or double depending on platform.
43+
'aString',
44+
#someSymbol,
45+
true,
46+
false,
47+
null,
48+
AnEnum.element1,
49+
AnEnum.element2,
50+
DateTime.now(),
51+
Dumb(1),
52+
Dumb(2),
53+
Dumb(3),
54+
Object(),
55+
const [1],
56+
const {1},
57+
const {'x'},
58+
// const maps have different implementation types depending on keys.
59+
const {'x': 1},
60+
const {123: 1},
61+
const {AnEnum.element1: 1, #foo: 2},
62+
];
63+
64+
void testMap(Map<Object?, Object?> map) {
65+
for (final key in keys) {
66+
bool wasAbsent = false;
67+
map.putIfAbsent(key, () {
68+
wasAbsent = true;
69+
Expect.isFalse(map.containsKey(key),
70+
'containsKey should be false in putIfAbsent. key = $key');
71+
return key;
72+
});
73+
Expect.isTrue(wasAbsent);
74+
Expect.isTrue(map.containsKey(key), 'Key was not added. key = $key');
75+
}
76+
}
77+
78+
void main() {
79+
originalError();
80+
81+
testMap({});
82+
testMap(Map()); // Should be same as `{}`.
83+
testMap(HashMap());
84+
testMap(LinkedHashMap()); // Should be same as `{}`.
85+
86+
testMap(Map.identity());
87+
testMap(HashMap.identity());
88+
testMap(LinkedHashMap.identity()); // Should be same as `Map.identity()`.
89+
90+
// Custom maps:
91+
testMap(HashMap(
92+
equals: (k1, k2) => k2 == k1,
93+
hashCode: (key) => key.hashCode + 1,
94+
isValidKey: (_) => true));
95+
testMap(LinkedHashMap(
96+
equals: (k1, k2) => k2 == k1,
97+
hashCode: (key) => key.hashCode + 1,
98+
isValidKey: (_) => true));
99+
}

0 commit comments

Comments
 (0)