@@ -2809,24 +2809,44 @@ To match a pattern `p` against a value `v`:
2809
2809
1. Evaluate the key `expression` to `k` and call `containsKey(k)` on
2810
2810
the value. If this returns `false`, the map does not match.
2811
2811
2812
- 2. Otherwise, evaluate `v[k]` and match the resulting value against
2813
- this entry's value subpattern. If it does not match, the map does
2814
- not match.
2812
+ 2. Otherwise, evaluate `v[k]` to `r`.
2815
2813
2816
- A compiler is free to call `v[k]` and `containsKey()` in either order,
2817
- or to elide calling one or both if it determines that doing so will
2818
- produce the same result. It may assume that the map adheres to the
2819
- following protocol:
2814
+ 3. If `r != null || (null is V) && v.containsKey(k)` evaluates to
2815
+ `false` then the map does not match.
2820
2816
2821
- * If `containsKey(k)` returns `false` for some key, then `v[k]` will
2822
- return `null`.
2817
+ *Note:*
2823
2818
2824
- * If `containsKey(k) ` returns `true` for some key, then `v[k]` returns
2825
- an instance of the map's value type.
2819
+ * *When `v[k] ` returns a non-null value, we know the key is
2820
+ present and we short-circuit the `containsKey()` call.*
2826
2821
2827
- *In particular, if the map's value type is non-nullable, then when
2828
- `v[k]` returns `null`, the compiler can assume that the key is absent
2829
- and `containsKey(k)` would return `false` too.*
2822
+ * *If `V` is known to be a non-nullable type, then `null is V` is
2823
+ always `false` and the expression simplifies to:*
2824
+
2825
+ ```dart
2826
+ r != null
2827
+ ```
2828
+
2829
+ * *Conversely, if `V` is known to be a nullable type, then `null
2830
+ is V` is always `true` and the expression simplifies to:*
2831
+
2832
+ ```dart
2833
+ r != null || v.containsKey(k)
2834
+ ```
2835
+
2836
+ * *When `V` is a potentially nullable type, the `null is V` test
2837
+ must be performed but can be hoisted out and shared across all
2838
+ entries since it doesn't depend on `k`.*
2839
+
2840
+ * *If `v` is a poorly behaved `Map` whose `v[k]` and
2841
+ `containsKey(k)` results don't agree (i.e. a non-`null` `v[k]`
2842
+ and `false` `containsKey(k)` or vice versa) we do not detect
2843
+ that mismatch. Since badly behaved maps are rare, this is
2844
+ allowed. Even if `v` is poorly behaved, a `null` value will only
2845
+ be passed to the subpattern if `null is V`, so soundness is
2846
+ preserved.*
2847
+
2848
+ 4. Else, match `r` against this entry's value subpattern. If it does
2849
+ not match, the map does not match.
2830
2850
2831
2851
5. The match succeeds if all entry subpatterns match.
2832
2852
@@ -3256,6 +3276,8 @@ Here is one way it could be broken down into separate pieces:
3256
3276
3257
3277
### 2.20
3258
3278
3279
+ - Fix soundness hole in map patterns with badly behaved maps (#2685).
3280
+
3259
3281
- Clarify which variables are valid in pattern assignments.
3260
3282
3261
3283
- Clarify when primitive `==` for map pattern keys comes into play (#2690).
0 commit comments