Skip to content

Commit 1ec1e73

Browse files
scheglovCommit Queue
authored and
Commit Queue
committed
Changes for map pattern: report an error for rest elements, empty map pattern.
Bug: dart-lang/language#2861 Change-Id: I00ccb3ea03aa476f96c2ecf3e3a9e13bd4926193 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/291940 Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Johnni Winther <[email protected]> Reviewed-by: Marya Belanger <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent c566435 commit 1ec1e73

File tree

24 files changed

+389
-421
lines changed

24 files changed

+389
-421
lines changed

pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11176,26 +11176,12 @@ const MessageCode messageRequiredParameterWithDefault = const MessageCode(
1117611176
r"""Try removing the default value or making the parameter optional.""");
1117711177

1117811178
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
11179-
const Code<Null> codeRestElementWithSubpatternInMapPattern =
11180-
messageRestElementWithSubpatternInMapPattern;
11179+
const Code<Null> codeRestPatternInMapPattern = messageRestPatternInMapPattern;
1118111180

1118211181
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
11183-
const MessageCode messageRestElementWithSubpatternInMapPattern =
11184-
const MessageCode("RestElementWithSubpatternInMapPattern",
11185-
analyzerCodes: <String>["REST_ELEMENT_WITH_SUBPATTERN_IN_MAP_PATTERN"],
11186-
problemMessage:
11187-
r"""A rest element in a map pattern can't have a subpattern.""",
11188-
correctionMessage: r"""Try removing the subpattern.""");
11189-
11190-
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
11191-
const Code<Null> codeRestPatternNotLastInMapPattern =
11192-
messageRestPatternNotLastInMapPattern;
11193-
11194-
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
11195-
const MessageCode messageRestPatternNotLastInMapPattern = const MessageCode(
11196-
"RestPatternNotLastInMapPattern",
11197-
problemMessage:
11198-
r"""The '...' pattern can appear only at the end in map patterns.""");
11182+
const MessageCode messageRestPatternInMapPattern = const MessageCode(
11183+
"RestPatternInMapPattern",
11184+
problemMessage: r"""The '...' pattern can't appear in map patterns.""");
1119911185

1120011186
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
1120111187
const Code<Null> codeRethrowNotCatch = messageRethrowNotCatch;

pkg/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,20 +143,12 @@ class MapPatternResult<Type extends Object, Error> {
143143
/// The required type of the map pattern.
144144
final Type requiredType;
145145

146-
/// Errors for when multiple rest patterns occurred within the map pattern.
147-
///
148-
/// The key is the index of the pattern within the map pattern.
149-
///
150-
/// This is `null` if no such errors where found.
151-
final Map<int, Error>? duplicateRestPatternErrors;
152-
153146
/// Error for when the matched value type is not assignable to the required
154147
/// type in an irrefutable context.
155148
final Error? patternTypeMismatchInIrrefutableContextError;
156149

157150
MapPatternResult(
158151
{required this.requiredType,
159-
required this.duplicateRestPatternErrors,
160152
required this.patternTypeMismatchInIrrefutableContextError});
161153
}
162154

pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,21 +1068,10 @@ mixin TypeAnalyzer<
10681068
matchMayFailEvenIfCorrectType: true);
10691069
// Stack: ()
10701070

1071-
bool hasDuplicateRestPatternReported = false;
1072-
Node? previousRestPattern;
1073-
Map<int, Error>? duplicateRestPatternErrors;
10741071
for (int i = 0; i < elements.length; i++) {
10751072
Node element = elements[i];
10761073
if (isRestPatternElement(element)) {
1077-
if (previousRestPattern != null) {
1078-
(duplicateRestPatternErrors ??= {})[i] = errors.duplicateRestPattern(
1079-
mapOrListPattern: node,
1080-
original: previousRestPattern,
1081-
duplicate: element,
1082-
);
1083-
hasDuplicateRestPatternReported = true;
1084-
}
1085-
previousRestPattern = element;
1074+
errors.restPatternInMap(node: node, element: element);
10861075
}
10871076
}
10881077

@@ -1100,14 +1089,8 @@ mixin TypeAnalyzer<
11001089
flow.popSubpattern();
11011090
} else {
11021091
assert(isRestPatternElement(element));
1103-
if (!hasDuplicateRestPatternReported) {
1104-
if (i != elements.length - 1) {
1105-
errors.restPatternNotLastInMap(node: node, element: element);
1106-
}
1107-
}
11081092
Pattern? subPattern = getRestPatternElementPattern(element);
11091093
if (subPattern != null) {
1110-
errors.restPatternWithSubPatternInMap(node: node, element: element);
11111094
flow.pushSubpattern(dynamicType);
11121095
dispatchPattern(
11131096
context.withUnnecessaryWildcardKind(null),
@@ -1131,9 +1114,11 @@ mixin TypeAnalyzer<
11311114
requiredType: requiredType,
11321115
);
11331116
}
1117+
if (elements.isEmpty) {
1118+
errors.emptyMapPattern(pattern: node);
1119+
}
11341120
return new MapPatternResult(
11351121
requiredType: requiredType,
1136-
duplicateRestPatternErrors: duplicateRestPatternErrors,
11371122
patternTypeMismatchInIrrefutableContextError:
11381123
patternTypeMismatchInIrrefutableContextError);
11391124
}
@@ -2543,6 +2528,13 @@ abstract class TypeAnalyzerErrors<
25432528
required Node duplicate,
25442529
});
25452530

2531+
/// Called if a map pattern does not have elements.
2532+
///
2533+
/// [pattern] is the map pattern.
2534+
void emptyMapPattern({
2535+
required Pattern pattern,
2536+
});
2537+
25462538
/// Called when both branches have variables with the same name, but these
25472539
/// variables either don't have the same finality, or their `NORM` types
25482540
/// are not structurally equal.
@@ -2624,16 +2616,10 @@ abstract class TypeAnalyzerErrors<
26242616
required Type returnType,
26252617
});
26262618

2627-
/// Called if a rest pattern inside a map pattern is not the last element.
2628-
///
2629-
/// [node] is the map pattern. [element] is the rest pattern.
2630-
void restPatternNotLastInMap({required Pattern node, required Node element});
2631-
2632-
/// Called if a rest pattern inside a map pattern has a subpattern.
2619+
/// Called if a rest pattern found inside a map pattern.
26332620
///
26342621
/// [node] is the map pattern. [element] is the rest pattern.
2635-
void restPatternWithSubPatternInMap(
2636-
{required Pattern node, required Node element});
2622+
void restPatternInMap({required Pattern node, required Node element});
26372623

26382624
/// Called if one of the case bodies of a switch statement completes normally
26392625
/// (other than the last case body), and the "patterns" feature is not

pkg/_fe_analyzer_shared/test/exhaustiveness/data/map.dart

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ untypedMap(Map map) {
77
{} /*space={}*/ => 0,
88
{1: _} /*space={1: ()}*/ => 1,
99
{1: _, 2: _} /*space={1: (), 2: ()}*/ => 2,
10-
{1: _, 2: _, ...} /*space={1: (), 2: (), ...}*/ => 3,
11-
{...} /*space={...}*/ => 4,
10+
Map() /*space={...}*/ => 3,
1211
};
1312
var b = /*type=Map<dynamic, dynamic>*/ switch (map) {
14-
{...} /*space={...}*/ => 0,
13+
Map() /*space={...}*/ => 0,
1514
};
1615
}
1716

@@ -31,8 +30,8 @@ typedMap(Map<int, A> map) {
3130
{0: B b} /*space={0: B}*/ => 1,
3231
{0: C c} /*space={0: C}*/ => 2,
3332
{0: _, 1: _} /*space={0: A, 1: A}*/ => 3,
34-
{0: B b, ...} /*space={0: B, ...}*/ => 4,
35-
{0: C c, ..._} /*space={0: C, ...}*/ => 5,
33+
{0: B b} /*space={0: B, ...}*/ => 4,
34+
{0: C c} /*space={0: C, ...}*/ => 5,
3635
};
3736

3837
var b = /*type=Map<int, A>*/ switch (map) {
@@ -43,17 +42,17 @@ typedMap(Map<int, A> map) {
4342
type=Map<int, A>
4443
*/
4544
switch (map) {
46-
<int, B>{...} /*space=<int, B>{...}*/ => 0,
45+
Map<int, B>() /*space=<int, B>{...}*/ => 0,
4746
};
4847
var d = /*type=Map<int, B>*/ switch (map) {
49-
{...} /*space={...}*/ => 0,
48+
Map() /*space={...}*/ => 0,
5049
{1: _} /*
5150
error=unreachable,
5251
space={1: B}
5352
*/
5453
=>
5554
1,
56-
{2: _, ...} /*
55+
{2: _} /*
5756
error=unreachable,
5857
space={2: B, ...}
5958
*/
@@ -64,13 +63,13 @@ typedMap(Map<int, A> map) {
6463

6564
exhaustiveRestOnly(Map o) {
6665
return /*type=Map<dynamic, dynamic>*/ switch (o) {
67-
{...} /*space={...}*/ => 0,
66+
Map() /*space={...}*/ => 0,
6867
};
6968
}
7069

7170
unreachableAfterRestOnly(Map o) {
7271
return /*type=Map<dynamic, dynamic>*/ switch (o) {
73-
{...} /*space={...}*/ => 0,
72+
Map() /*space={...}*/ => 0,
7473
{0: _} /*
7574
error=unreachable,
7675
space={0: ()}
@@ -82,7 +81,7 @@ unreachableAfterRestOnly(Map o) {
8281

8382
unreachableAfterRestOnlyTyped(Map o) {
8483
return /*type=Map<dynamic, dynamic>*/ switch (o) {
85-
{...} /*space={...}*/ => 0,
84+
Map() /*space={...}*/ => 0,
8685
<int, String>{
8786
0: _
8887
} /*
@@ -96,7 +95,7 @@ unreachableAfterRestOnlyTyped(Map o) {
9695

9796
unreachableAfterRestOnlyEmpty(Map o) {
9897
return /*type=Map<dynamic, dynamic>*/ switch (o) {
99-
{...} /*space={...}*/ => 0,
98+
Map() /*space={...}*/ => 0,
10099
{} /*
101100
error=unreachable,
102101
space={}
@@ -108,14 +107,14 @@ unreachableAfterRestOnlyEmpty(Map o) {
108107

109108
unreachableAfterRestSameKeys(Map o) {
110109
return /*type=Map<dynamic, dynamic>*/ switch (o) {
111-
{0: _, ...} /*space={0: (), ...}*/ => 0,
110+
{0: _} /*space={0: (), ...}*/ => 0,
112111
{0: _} /*
113112
error=unreachable,
114113
space={0: ()}
115114
*/
116115
=>
117116
1,
118-
{...} /*space={...}*/ => 2,
117+
Map() /*space={...}*/ => 2,
119118
};
120119
}
121120

@@ -125,7 +124,7 @@ nonExhaustiveAfterRestSameKeys(Map o) {
125124
type=Map<dynamic, dynamic>
126125
*/
127126
switch (o) {
128-
{0: _, ...} /*space={0: (), ...}*/ => 0,
127+
{0: _} /*space={0: (), ...}*/ => 0,
129128
{0: _} /*
130129
error=unreachable,
131130
space={0: ()}
@@ -137,7 +136,7 @@ nonExhaustiveAfterRestSameKeys(Map o) {
137136

138137
unreachableAfterRestMoreKeys(Map o) {
139138
return /*type=Map<dynamic, dynamic>*/ switch (o) {
140-
{0: _, ...} /*space={0: (), ...}*/ => 0,
139+
{0: _} /*space={0: (), ...}*/ => 0,
141140
{
142141
0: _,
143142
1: _
@@ -147,7 +146,7 @@ unreachableAfterRestMoreKeys(Map o) {
147146
*/
148147
=>
149148
1,
150-
{...} /*space={...}*/ => 2,
149+
Map() /*space={...}*/ => 2,
151150
};
152151
}
153152

@@ -157,7 +156,7 @@ nonExhaustiveAfterRestMoreKeys(Map o) {
157156
type=Map<dynamic, dynamic>
158157
*/
159158
switch (o) {
160-
{0: _, ...} /*space={0: (), ...}*/ => 0,
159+
{0: _} /*space={0: (), ...}*/ => 0,
161160
{0: _, 1: _} /*
162161
error=unreachable,
163162
space={0: (), 1: ()}
@@ -176,7 +175,7 @@ unreachableAfterSameKeys(Map o) {
176175
*/
177176
=>
178177
1,
179-
{...} /*space={...}*/ => 2,
178+
Map() /*space={...}*/ => 2,
180179
};
181180
}
182181

@@ -200,7 +199,7 @@ reachableAfterRestOnlyDifferentTypes(Map o) {
200199
return /*type=Map<dynamic, dynamic>*/ switch (o) {
201200
<int, String>{...} /*space=<int, String>{...}*/ => 0,
202201
<int, bool>{0: _} /*space=<int, bool>{0: bool}*/ => 1,
203-
{...} /*space={...}*/ => 2,
202+
Map() /*space={...}*/ => 2,
204203
};
205204
}
206205

@@ -210,7 +209,7 @@ nonExhaustiveAfterRestOnlyDifferentTypes(Map o) {
210209
type=Map<dynamic, dynamic>
211210
*/
212211
switch (o) {
213-
<int, String>{...} /*space=<int, String>{...}*/ => 0,
212+
Map<int, String>() /*space=<int, String>{...}*/ => 0,
214213
<int, bool>{0: _} /*space=<int, bool>{0: bool}*/ => 1,
215214
};
216215
}
@@ -219,7 +218,7 @@ reachableAfterRestOnlyEmptyDifferentTypes(Map o) {
219218
return /*type=Map<dynamic, dynamic>*/ switch (o) {
220219
<int, String>{...} /*space=<int, String>{...}*/ => 0,
221220
<int, bool>{} /*space=<int, bool>{}*/ => 1,
222-
{...} /*space={...}*/ => 2,
221+
Map() /*space={...}*/ => 2,
223222
};
224223
}
225224

@@ -229,32 +228,32 @@ nonExhaustiveAfterRestOnlyEmptyDifferentTypes(Map o) {
229228
type=Map<dynamic, dynamic>
230229
*/
231230
switch (o) {
232-
<int, String>{...} /*space=<int, String>{...}*/ => 0,
231+
Map<int, String>() /*space=<int, String>{...}*/ => 0,
233232
<int, bool>{} /*space=<int, bool>{}*/ => 1,
234233
};
235234
}
236235

237236
reachableAfterRestDifferentTypes(Map o) {
238237
return /*type=Map<dynamic, dynamic>*/ switch (o) {
239-
<int, String>{0: _, ...} /*space=<int, String>{0: String, ...}*/ => 0,
238+
<int, String>{0: _} /*space=<int, String>{0: String, ...}*/ => 0,
240239
<int, bool>{0: _} /*space=<int, bool>{0: bool}*/ => 1,
241-
{...} /*space={...}*/ => 2,
240+
Map() /*space={...}*/ => 2,
242241
};
243242
}
244243

245244
nonExhaustiveAfterRestDifferentTypes(Map o) {
246245
return /*type=Map<dynamic, dynamic>*/ switch (o) {
247-
<int, String>{0: _, ...} /*space=<int, String>{0: String, ...}*/ => 0,
246+
<int, String>{0: _} /*space=<int, String>{0: String, ...}*/ => 0,
248247
<int, bool>{0: _} /*space=<int, bool>{0: bool}*/ => 1,
249-
{...} /*space={...}*/ => 2,
248+
Map() /*space={...}*/ => 2,
250249
};
251250
}
252251

253252
reachableAfterRestDifferentKeys(Map o) {
254253
return /*type=Map<dynamic, dynamic>*/ switch (o) {
255-
{0: _, ...} /*space={0: (), ...}*/ => 0,
254+
{0: _} /*space={0: (), ...}*/ => 0,
256255
{1: _} /*space={1: ()}*/ => 1,
257-
{...} /*space={...}*/ => 2,
256+
Map() /*space={...}*/ => 2,
258257
};
259258
}
260259

@@ -264,7 +263,7 @@ nonExhaustiveAfterRestDifferentKeys(Map o) {
264263
type=Map<dynamic, dynamic>
265264
*/
266265
switch (o) {
267-
{0: _, ...} /*space={0: (), ...}*/ => 0,
266+
{0: _} /*space={0: (), ...}*/ => 0,
268267
{1: _} /*space={1: ()}*/ => 1,
269268
};
270269
}
@@ -273,7 +272,7 @@ reachableAfterDifferentKeys(Map o) {
273272
return /*type=Map<dynamic, dynamic>*/ switch (o) {
274273
{0: _} /*space={0: ()}*/ => 0,
275274
{1: _} /*space={1: ()}*/ => 1,
276-
{...} /*space={...}*/ => 2,
275+
Map() /*space={...}*/ => 2,
277276
};
278277
}
279278

@@ -292,7 +291,7 @@ reachableAfterDifferentTypes(Map o) {
292291
return /*type=Map<dynamic, dynamic>*/ switch (o) {
293292
<int, String>{0: _} /*space=<int, String>{0: String}*/ => 0,
294293
<int, bool>{0: _} /*space=<int, bool>{0: bool}*/ => 1,
295-
{...} /*space={...}*/ => 2,
294+
Map() /*space={...}*/ => 2,
296295
};
297296
}
298297

0 commit comments

Comments
 (0)