Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2d3dcfa

Browse files
authoredMar 18, 2024
Rollup merge of #121823 - Nadrieril:never-witnesses, r=compiler-errors
never patterns: suggest `!` patterns on non-exhaustive matches When a match is non-exhaustive we now suggest never patterns whenever it makes sense. r? ``@compiler-errors``
2 parents 05f7633 + 1b31e14 commit 2d3dcfa

File tree

11 files changed

+982
-242
lines changed

11 files changed

+982
-242
lines changed
 

‎compiler/rustc_mir_build/src/thir/pattern/check_match.rs

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -938,43 +938,30 @@ fn report_non_exhaustive_match<'p, 'tcx>(
938938
};
939939
// In the case of an empty match, replace the '`_` not covered' diagnostic with something more
940940
// informative.
941-
let mut err;
942-
let pattern;
943-
let patterns_len;
944941
if is_empty_match && !non_empty_enum {
945942
return cx.tcx.dcx().emit_err(NonExhaustivePatternsTypeNotEmpty {
946943
cx,
947944
expr_span,
948945
span: sp,
949946
ty: scrut_ty,
950947
});
951-
} else {
952-
// FIXME: migration of this diagnostic will require list support
953-
let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
954-
err = create_e0004(
955-
cx.tcx.sess,
956-
sp,
957-
format!("non-exhaustive patterns: {joined_patterns} not covered"),
958-
);
959-
err.span_label(
960-
sp,
961-
format!(
962-
"pattern{} {} not covered",
963-
rustc_errors::pluralize!(witnesses.len()),
964-
joined_patterns
965-
),
966-
);
967-
patterns_len = witnesses.len();
968-
pattern = if witnesses.len() < 4 {
969-
witnesses
970-
.iter()
971-
.map(|witness| cx.hoist_witness_pat(witness).to_string())
972-
.collect::<Vec<String>>()
973-
.join(" | ")
974-
} else {
975-
"_".to_string()
976-
};
977-
};
948+
}
949+
950+
// FIXME: migration of this diagnostic will require list support
951+
let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
952+
let mut err = create_e0004(
953+
cx.tcx.sess,
954+
sp,
955+
format!("non-exhaustive patterns: {joined_patterns} not covered"),
956+
);
957+
err.span_label(
958+
sp,
959+
format!(
960+
"pattern{} {} not covered",
961+
rustc_errors::pluralize!(witnesses.len()),
962+
joined_patterns
963+
),
964+
);
978965

979966
// Point at the definition of non-covered `enum` variants.
980967
if let Some(AdtDefinedHere { adt_def_span, ty, variants }) =
@@ -1021,6 +1008,23 @@ fn report_non_exhaustive_match<'p, 'tcx>(
10211008
}
10221009
}
10231010

1011+
// Whether we suggest the actual missing patterns or `_`.
1012+
let suggest_the_witnesses = witnesses.len() < 4;
1013+
let suggested_arm = if suggest_the_witnesses {
1014+
let pattern = witnesses
1015+
.iter()
1016+
.map(|witness| cx.hoist_witness_pat(witness).to_string())
1017+
.collect::<Vec<String>>()
1018+
.join(" | ");
1019+
if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns {
1020+
// Arms with a never pattern don't take a body.
1021+
pattern
1022+
} else {
1023+
format!("{pattern} => todo!()")
1024+
}
1025+
} else {
1026+
format!("_ => todo!()")
1027+
};
10241028
let mut suggestion = None;
10251029
let sm = cx.tcx.sess.source_map();
10261030
match arms {
@@ -1033,7 +1037,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
10331037
};
10341038
suggestion = Some((
10351039
sp.shrink_to_hi().with_hi(expr_span.hi()),
1036-
format!(" {{{indentation}{more}{pattern} => todo!(),{indentation}}}",),
1040+
format!(" {{{indentation}{more}{suggested_arm},{indentation}}}",),
10371041
));
10381042
}
10391043
[only] => {
@@ -1059,7 +1063,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
10591063
};
10601064
suggestion = Some((
10611065
only.span.shrink_to_hi(),
1062-
format!("{comma}{pre_indentation}{pattern} => todo!()"),
1066+
format!("{comma}{pre_indentation}{suggested_arm}"),
10631067
));
10641068
}
10651069
[.., prev, last] => {
@@ -1082,7 +1086,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
10821086
if let Some(spacing) = spacing {
10831087
suggestion = Some((
10841088
last.span.shrink_to_hi(),
1085-
format!("{comma}{spacing}{pattern} => todo!()"),
1089+
format!("{comma}{spacing}{suggested_arm}"),
10861090
));
10871091
}
10881092
}
@@ -1093,13 +1097,13 @@ fn report_non_exhaustive_match<'p, 'tcx>(
10931097
let msg = format!(
10941098
"ensure that all possible cases are being handled by adding a match arm with a wildcard \
10951099
pattern{}{}",
1096-
if patterns_len > 1 && patterns_len < 4 && suggestion.is_some() {
1100+
if witnesses.len() > 1 && suggest_the_witnesses && suggestion.is_some() {
10971101
", a match arm with multiple or-patterns"
10981102
} else {
10991103
// we are either not suggesting anything, or suggesting `_`
11001104
""
11011105
},
1102-
match patterns_len {
1106+
match witnesses.len() {
11031107
// non-exhaustive enum case
11041108
0 if suggestion.is_some() => " as shown",
11051109
0 => "",

‎compiler/rustc_pattern_analysis/src/constructor.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -678,15 +678,19 @@ pub enum Constructor<Cx: PatCx> {
678678
Or,
679679
/// Wildcard pattern.
680680
Wildcard,
681+
/// Never pattern. Only used in `WitnessPat`. An actual never pattern should be lowered as
682+
/// `Wildcard`.
683+
Never,
681684
/// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used
682-
/// for those types for which we cannot list constructors explicitly, like `f64` and `str`.
685+
/// for those types for which we cannot list constructors explicitly, like `f64` and `str`. Only
686+
/// used in `WitnessPat`.
683687
NonExhaustive,
684-
/// Fake extra constructor for variants that should not be mentioned in diagnostics.
685-
/// We use this for variants behind an unstable gate as well as
686-
/// `#[doc(hidden)]` ones.
688+
/// Fake extra constructor for variants that should not be mentioned in diagnostics. We use this
689+
/// for variants behind an unstable gate as well as `#[doc(hidden)]` ones. Only used in
690+
/// `WitnessPat`.
687691
Hidden,
688692
/// Fake extra constructor for constructors that are not seen in the matrix, as explained at the
689-
/// top of the file.
693+
/// top of the file. Only used for specialization.
690694
Missing,
691695
/// Fake extra constructor that indicates and empty field that is private. When we encounter one
692696
/// we skip the column entirely so we don't observe its emptiness. Only used for specialization.
@@ -708,6 +712,7 @@ impl<Cx: PatCx> Clone for Constructor<Cx> {
708712
Constructor::Str(value) => Constructor::Str(value.clone()),
709713
Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()),
710714
Constructor::Or => Constructor::Or,
715+
Constructor::Never => Constructor::Never,
711716
Constructor::Wildcard => Constructor::Wildcard,
712717
Constructor::NonExhaustive => Constructor::NonExhaustive,
713718
Constructor::Hidden => Constructor::Hidden,
@@ -1040,10 +1045,32 @@ impl<Cx: PatCx> ConstructorSet<Cx> {
10401045
// In a `MaybeInvalid` place even an empty pattern may be reachable. We therefore
10411046
// add a dummy empty constructor here, which will be ignored if the place is
10421047
// `ValidOnly`.
1043-
missing_empty.push(NonExhaustive);
1048+
missing_empty.push(Never);
10441049
}
10451050
}
10461051

10471052
SplitConstructorSet { present, missing, missing_empty }
10481053
}
1054+
1055+
/// Whether this set only contains empty constructors.
1056+
pub(crate) fn all_empty(&self) -> bool {
1057+
match self {
1058+
ConstructorSet::Bool
1059+
| ConstructorSet::Integers { .. }
1060+
| ConstructorSet::Ref
1061+
| ConstructorSet::Union
1062+
| ConstructorSet::Unlistable => false,
1063+
ConstructorSet::NoConstructors => true,
1064+
ConstructorSet::Struct { empty } => *empty,
1065+
ConstructorSet::Variants { variants, non_exhaustive } => {
1066+
!*non_exhaustive
1067+
&& variants
1068+
.iter()
1069+
.all(|visibility| matches!(visibility, VariantVisibility::Empty))
1070+
}
1071+
ConstructorSet::Slice { array_len, subtype_is_empty } => {
1072+
*subtype_is_empty && matches!(array_len, Some(1..))
1073+
}
1074+
}
1075+
}
10491076
}

‎compiler/rustc_pattern_analysis/src/pat.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ impl<Cx: PatCx> fmt::Debug for DeconstructedPat<Cx> {
208208
}
209209
Ok(())
210210
}
211+
Never => write!(f, "!"),
211212
Wildcard | Missing | NonExhaustive | Hidden | PrivateUninhabited => {
212213
write!(f, "_ : {:?}", pat.ty())
213214
}
@@ -311,18 +312,24 @@ impl<Cx: PatCx> WitnessPat<Cx> {
311312
pub(crate) fn new(ctor: Constructor<Cx>, fields: Vec<Self>, ty: Cx::Ty) -> Self {
312313
Self { ctor, fields, ty }
313314
}
314-
pub(crate) fn wildcard(ty: Cx::Ty) -> Self {
315-
Self::new(Wildcard, Vec::new(), ty)
315+
/// Create a wildcard pattern for this type. If the type is empty, we create a `!` pattern.
316+
pub(crate) fn wildcard(cx: &Cx, ty: Cx::Ty) -> Self {
317+
let is_empty = cx.ctors_for_ty(&ty).is_ok_and(|ctors| ctors.all_empty());
318+
let ctor = if is_empty { Never } else { Wildcard };
319+
Self::new(ctor, Vec::new(), ty)
316320
}
317321

318322
/// Construct a pattern that matches everything that starts with this constructor.
319323
/// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
320324
/// `Some(_)`.
321325
pub(crate) fn wild_from_ctor(cx: &Cx, ctor: Constructor<Cx>, ty: Cx::Ty) -> Self {
326+
if matches!(ctor, Wildcard) {
327+
return Self::wildcard(cx, ty);
328+
}
322329
let fields = cx
323330
.ctor_sub_tys(&ctor, &ty)
324331
.filter(|(_, PrivateUninhabitedField(skip))| !skip)
325-
.map(|(ty, _)| Self::wildcard(ty))
332+
.map(|(ty, _)| Self::wildcard(cx, ty))
326333
.collect();
327334
Self::new(ctor, fields, ty)
328335
}
@@ -334,6 +341,14 @@ impl<Cx: PatCx> WitnessPat<Cx> {
334341
&self.ty
335342
}
336343

344+
pub fn is_never_pattern(&self) -> bool {
345+
match self.ctor() {
346+
Never => true,
347+
Or => self.fields.iter().all(|p| p.is_never_pattern()),
348+
_ => self.fields.iter().any(|p| p.is_never_pattern()),
349+
}
350+
}
351+
337352
pub fn iter_fields(&self) -> impl Iterator<Item = &WitnessPat<Cx>> {
338353
self.fields.iter()
339354
}

‎compiler/rustc_pattern_analysis/src/rustc.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
247247
_ => bug!("bad slice pattern {:?} {:?}", ctor, ty),
248248
},
249249
Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..)
250-
| NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => &[],
250+
| Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => &[],
251251
Or => {
252252
bug!("called `Fields::wildcards` on an `Or` ctor")
253253
}
@@ -275,7 +275,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
275275
Ref => 1,
276276
Slice(slice) => slice.arity(),
277277
Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..)
278-
| NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => 0,
278+
| Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => 0,
279279
Or => bug!("The `Or` constructor doesn't have a fixed arity"),
280280
}
281281
}
@@ -824,7 +824,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
824824
}
825825
}
826826
&Str(value) => PatKind::Constant { value },
827-
Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild,
827+
Never if self.tcx.features().never_patterns => PatKind::Never,
828+
Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild,
828829
Missing { .. } => bug!(
829830
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
830831
`Missing` should have been processed in `apply_constructors`"

‎tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
error: unreachable pattern
2-
--> $DIR/empty-types.rs:49:9
2+
--> $DIR/empty-types.rs:51:9
33
|
44
LL | _ => {}
55
| ^
66
|
77
note: the lint level is defined here
8-
--> $DIR/empty-types.rs:15:9
8+
--> $DIR/empty-types.rs:17:9
99
|
1010
LL | #![deny(unreachable_patterns)]
1111
| ^^^^^^^^^^^^^^^^^^^^
1212

1313
error: unreachable pattern
14-
--> $DIR/empty-types.rs:52:9
14+
--> $DIR/empty-types.rs:54:9
1515
|
1616
LL | _x => {}
1717
| ^^
1818

1919
error[E0004]: non-exhaustive patterns: type `&!` is non-empty
20-
--> $DIR/empty-types.rs:56:11
20+
--> $DIR/empty-types.rs:58:11
2121
|
2222
LL | match ref_never {}
2323
| ^^^^^^^^^
@@ -32,31 +32,31 @@ LL + }
3232
|
3333

3434
error: unreachable pattern
35-
--> $DIR/empty-types.rs:71:9
35+
--> $DIR/empty-types.rs:73:9
3636
|
3737
LL | (_, _) => {}
3838
| ^^^^^^
3939

4040
error: unreachable pattern
41-
--> $DIR/empty-types.rs:78:9
41+
--> $DIR/empty-types.rs:80:9
4242
|
4343
LL | _ => {}
4444
| ^
4545

4646
error: unreachable pattern
47-
--> $DIR/empty-types.rs:81:9
47+
--> $DIR/empty-types.rs:83:9
4848
|
4949
LL | (_, _) => {}
5050
| ^^^^^^
5151

5252
error: unreachable pattern
53-
--> $DIR/empty-types.rs:85:9
53+
--> $DIR/empty-types.rs:87:9
5454
|
5555
LL | _ => {}
5656
| ^
5757

5858
error[E0004]: non-exhaustive patterns: `Ok(_)` not covered
59-
--> $DIR/empty-types.rs:89:11
59+
--> $DIR/empty-types.rs:91:11
6060
|
6161
LL | match res_u32_never {}
6262
| ^^^^^^^^^^^^^ pattern `Ok(_)` not covered
@@ -75,19 +75,19 @@ LL + }
7575
|
7676

7777
error: unreachable pattern
78-
--> $DIR/empty-types.rs:97:9
78+
--> $DIR/empty-types.rs:99:9
7979
|
8080
LL | Err(_) => {}
8181
| ^^^^^^
8282

8383
error: unreachable pattern
84-
--> $DIR/empty-types.rs:102:9
84+
--> $DIR/empty-types.rs:104:9
8585
|
8686
LL | Err(_) => {}
8787
| ^^^^^^
8888

8989
error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered
90-
--> $DIR/empty-types.rs:99:11
90+
--> $DIR/empty-types.rs:101:11
9191
|
9292
LL | match res_u32_never {
9393
| ^^^^^^^^^^^^^ pattern `Ok(1_u32..=u32::MAX)` not covered
@@ -105,7 +105,7 @@ LL ~ Ok(1_u32..=u32::MAX) => todo!()
105105
|
106106

107107
error[E0005]: refutable pattern in local binding
108-
--> $DIR/empty-types.rs:106:9
108+
--> $DIR/empty-types.rs:108:9
109109
|
110110
LL | let Ok(_x) = res_u32_never.as_ref();
111111
| ^^^^^^ pattern `Err(_)` not covered
@@ -119,121 +119,121 @@ LL | let Ok(_x) = res_u32_never.as_ref() else { todo!() };
119119
| ++++++++++++++++
120120

121121
error: unreachable pattern
122-
--> $DIR/empty-types.rs:117:9
122+
--> $DIR/empty-types.rs:119:9
123123
|
124124
LL | _ => {}
125125
| ^
126126

127127
error: unreachable pattern
128-
--> $DIR/empty-types.rs:121:9
128+
--> $DIR/empty-types.rs:123:9
129129
|
130130
LL | Ok(_) => {}
131131
| ^^^^^
132132

133133
error: unreachable pattern
134-
--> $DIR/empty-types.rs:124:9
134+
--> $DIR/empty-types.rs:126:9
135135
|
136136
LL | Ok(_) => {}
137137
| ^^^^^
138138

139139
error: unreachable pattern
140-
--> $DIR/empty-types.rs:125:9
140+
--> $DIR/empty-types.rs:127:9
141141
|
142142
LL | _ => {}
143143
| ^
144144

145145
error: unreachable pattern
146-
--> $DIR/empty-types.rs:128:9
146+
--> $DIR/empty-types.rs:130:9
147147
|
148148
LL | Ok(_) => {}
149149
| ^^^^^
150150

151151
error: unreachable pattern
152-
--> $DIR/empty-types.rs:129:9
152+
--> $DIR/empty-types.rs:131:9
153153
|
154154
LL | Err(_) => {}
155155
| ^^^^^^
156156

157157
error: unreachable pattern
158-
--> $DIR/empty-types.rs:138:13
158+
--> $DIR/empty-types.rs:140:13
159159
|
160160
LL | _ => {}
161161
| ^
162162

163163
error: unreachable pattern
164-
--> $DIR/empty-types.rs:141:13
164+
--> $DIR/empty-types.rs:143:13
165165
|
166166
LL | _ if false => {}
167167
| ^
168168

169169
error: unreachable pattern
170-
--> $DIR/empty-types.rs:150:13
170+
--> $DIR/empty-types.rs:152:13
171171
|
172172
LL | Some(_) => {}
173173
| ^^^^^^^
174174

175175
error: unreachable pattern
176-
--> $DIR/empty-types.rs:154:13
176+
--> $DIR/empty-types.rs:156:13
177177
|
178178
LL | _ => {}
179179
| ^
180180

181181
error: unreachable pattern
182-
--> $DIR/empty-types.rs:206:13
182+
--> $DIR/empty-types.rs:208:13
183183
|
184184
LL | _ => {}
185185
| ^
186186

187187
error: unreachable pattern
188-
--> $DIR/empty-types.rs:211:13
188+
--> $DIR/empty-types.rs:213:13
189189
|
190190
LL | _ => {}
191191
| ^
192192

193193
error: unreachable pattern
194-
--> $DIR/empty-types.rs:216:13
194+
--> $DIR/empty-types.rs:218:13
195195
|
196196
LL | _ => {}
197197
| ^
198198

199199
error: unreachable pattern
200-
--> $DIR/empty-types.rs:221:13
200+
--> $DIR/empty-types.rs:223:13
201201
|
202202
LL | _ => {}
203203
| ^
204204

205205
error: unreachable pattern
206-
--> $DIR/empty-types.rs:227:13
206+
--> $DIR/empty-types.rs:229:13
207207
|
208208
LL | _ => {}
209209
| ^
210210

211211
error: unreachable pattern
212-
--> $DIR/empty-types.rs:286:9
212+
--> $DIR/empty-types.rs:288:9
213213
|
214214
LL | _ => {}
215215
| ^
216216

217217
error: unreachable pattern
218-
--> $DIR/empty-types.rs:289:9
218+
--> $DIR/empty-types.rs:291:9
219219
|
220220
LL | (_, _) => {}
221221
| ^^^^^^
222222

223223
error: unreachable pattern
224-
--> $DIR/empty-types.rs:292:9
224+
--> $DIR/empty-types.rs:294:9
225225
|
226226
LL | Ok(_) => {}
227227
| ^^^^^
228228

229229
error: unreachable pattern
230-
--> $DIR/empty-types.rs:293:9
230+
--> $DIR/empty-types.rs:295:9
231231
|
232232
LL | Err(_) => {}
233233
| ^^^^^^
234234

235235
error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty
236-
--> $DIR/empty-types.rs:325:11
236+
--> $DIR/empty-types.rs:327:11
237237
|
238238
LL | match slice_never {}
239239
| ^^^^^^^^^^^
@@ -247,7 +247,7 @@ LL + }
247247
|
248248

249249
error[E0004]: non-exhaustive patterns: `&[]` not covered
250-
--> $DIR/empty-types.rs:336:11
250+
--> $DIR/empty-types.rs:338:11
251251
|
252252
LL | match slice_never {
253253
| ^^^^^^^^^^^ pattern `&[]` not covered
@@ -260,7 +260,7 @@ LL + &[] => todo!()
260260
|
261261

262262
error[E0004]: non-exhaustive patterns: `&[]` not covered
263-
--> $DIR/empty-types.rs:349:11
263+
--> $DIR/empty-types.rs:352:11
264264
|
265265
LL | match slice_never {
266266
| ^^^^^^^^^^^ pattern `&[]` not covered
@@ -274,7 +274,7 @@ LL + &[] => todo!()
274274
|
275275

276276
error[E0004]: non-exhaustive patterns: type `[!]` is non-empty
277-
--> $DIR/empty-types.rs:355:11
277+
--> $DIR/empty-types.rs:359:11
278278
|
279279
LL | match *slice_never {}
280280
| ^^^^^^^^^^^^
@@ -288,25 +288,25 @@ LL + }
288288
|
289289

290290
error: unreachable pattern
291-
--> $DIR/empty-types.rs:365:9
291+
--> $DIR/empty-types.rs:369:9
292292
|
293293
LL | _ => {}
294294
| ^
295295

296296
error: unreachable pattern
297-
--> $DIR/empty-types.rs:368:9
297+
--> $DIR/empty-types.rs:372:9
298298
|
299299
LL | [_, _, _] => {}
300300
| ^^^^^^^^^
301301

302302
error: unreachable pattern
303-
--> $DIR/empty-types.rs:371:9
303+
--> $DIR/empty-types.rs:375:9
304304
|
305305
LL | [_, ..] => {}
306306
| ^^^^^^^
307307

308308
error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
309-
--> $DIR/empty-types.rs:385:11
309+
--> $DIR/empty-types.rs:389:11
310310
|
311311
LL | match array_0_never {}
312312
| ^^^^^^^^^^^^^
@@ -320,13 +320,13 @@ LL + }
320320
|
321321

322322
error: unreachable pattern
323-
--> $DIR/empty-types.rs:392:9
323+
--> $DIR/empty-types.rs:396:9
324324
|
325325
LL | _ => {}
326326
| ^
327327

328328
error[E0004]: non-exhaustive patterns: `[]` not covered
329-
--> $DIR/empty-types.rs:394:11
329+
--> $DIR/empty-types.rs:398:11
330330
|
331331
LL | match array_0_never {
332332
| ^^^^^^^^^^^^^ pattern `[]` not covered
@@ -340,49 +340,49 @@ LL + [] => todo!()
340340
|
341341

342342
error: unreachable pattern
343-
--> $DIR/empty-types.rs:413:9
343+
--> $DIR/empty-types.rs:417:9
344344
|
345345
LL | Some(_) => {}
346346
| ^^^^^^^
347347

348348
error: unreachable pattern
349-
--> $DIR/empty-types.rs:418:9
349+
--> $DIR/empty-types.rs:422:9
350350
|
351351
LL | Some(_a) => {}
352352
| ^^^^^^^^
353353

354354
error: unreachable pattern
355-
--> $DIR/empty-types.rs:423:9
355+
--> $DIR/empty-types.rs:427:9
356356
|
357357
LL | _ => {}
358358
| ^
359359

360360
error: unreachable pattern
361-
--> $DIR/empty-types.rs:428:9
361+
--> $DIR/empty-types.rs:432:9
362362
|
363363
LL | _a => {}
364364
| ^^
365365

366366
error: unreachable pattern
367-
--> $DIR/empty-types.rs:600:9
367+
--> $DIR/empty-types.rs:604:9
368368
|
369369
LL | _ => {}
370370
| ^
371371

372372
error: unreachable pattern
373-
--> $DIR/empty-types.rs:603:9
373+
--> $DIR/empty-types.rs:607:9
374374
|
375375
LL | _x => {}
376376
| ^^
377377

378378
error: unreachable pattern
379-
--> $DIR/empty-types.rs:606:9
379+
--> $DIR/empty-types.rs:610:9
380380
|
381381
LL | _ if false => {}
382382
| ^
383383

384384
error: unreachable pattern
385-
--> $DIR/empty-types.rs:609:9
385+
--> $DIR/empty-types.rs:613:9
386386
|
387387
LL | _x if false => {}
388388
| ^^

‎tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr

Lines changed: 83 additions & 65 deletions
Large diffs are not rendered by default.

‎tests/ui/pattern/usefulness/empty-types.never_pats.stderr

Lines changed: 644 additions & 0 deletions
Large diffs are not rendered by default.

‎tests/ui/pattern/usefulness/empty-types.normal.stderr

Lines changed: 68 additions & 50 deletions
Large diffs are not rendered by default.

‎tests/ui/pattern/usefulness/empty-types.rs

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ revisions: normal min_exh_pats exhaustive_patterns
1+
//@ revisions: normal min_exh_pats exhaustive_patterns never_pats
22
// gate-test-min_exhaustive_patterns
33
//
44
// This tests correct handling of empty types in exhaustiveness checking.
@@ -11,6 +11,8 @@
1111
#![feature(never_type_fallback)]
1212
#![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
1313
#![cfg_attr(min_exh_pats, feature(min_exhaustive_patterns))]
14+
#![cfg_attr(never_pats, feature(never_patterns))]
15+
//[never_pats]~^ WARN the feature `never_patterns` is incomplete
1416
#![allow(dead_code, unreachable_code)]
1517
#![deny(unreachable_patterns)]
1618

@@ -66,14 +68,14 @@ fn basic(x: NeverBundle) {
6668

6769
let tuple_half_never: (u32, !) = x.tuple_half_never;
6870
match tuple_half_never {}
69-
//[normal]~^ ERROR non-empty
71+
//[normal,never_pats]~^ ERROR non-empty
7072
match tuple_half_never {
7173
(_, _) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
7274
}
7375

7476
let tuple_never: (!, !) = x.tuple_never;
7577
match tuple_never {}
76-
//[normal]~^ ERROR non-empty
78+
//[normal,never_pats]~^ ERROR non-empty
7779
match tuple_never {
7880
_ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
7981
}
@@ -89,7 +91,7 @@ fn basic(x: NeverBundle) {
8991
match res_u32_never {}
9092
//~^ ERROR non-exhaustive
9193
match res_u32_never {
92-
//[normal]~^ ERROR non-exhaustive
94+
//[normal,never_pats]~^ ERROR non-exhaustive
9395
Ok(_) => {}
9496
}
9597
match res_u32_never {
@@ -102,22 +104,22 @@ fn basic(x: NeverBundle) {
102104
Err(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
103105
}
104106
let Ok(_x) = res_u32_never;
105-
//[normal]~^ ERROR refutable
107+
//[normal,never_pats]~^ ERROR refutable
106108
let Ok(_x) = res_u32_never.as_ref();
107109
//~^ ERROR refutable
108110
// Non-obvious difference: here there's an implicit dereference in the patterns, which makes the
109111
// inner place !known_valid. `exhaustive_patterns` ignores this.
110112
let Ok(_x) = &res_u32_never;
111-
//[normal,min_exh_pats]~^ ERROR refutable
113+
//[normal,min_exh_pats,never_pats]~^ ERROR refutable
112114

113115
let result_never: Result<!, !> = x.result_never;
114116
match result_never {}
115-
//[normal]~^ ERROR non-exhaustive
117+
//[normal,never_pats]~^ ERROR non-exhaustive
116118
match result_never {
117119
_ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
118120
}
119121
match result_never {
120-
//[normal]~^ ERROR non-exhaustive
122+
//[normal,never_pats]~^ ERROR non-exhaustive
121123
Ok(_) => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
122124
}
123125
match result_never {
@@ -142,7 +144,7 @@ fn void_same_as_never(x: NeverBundle) {
142144
}
143145
let opt_void: Option<Void> = None;
144146
match opt_void {
145-
//[normal]~^ ERROR non-exhaustive
147+
//[normal,never_pats]~^ ERROR non-exhaustive
146148
None => {}
147149
}
148150
match opt_void {
@@ -161,7 +163,7 @@ fn void_same_as_never(x: NeverBundle) {
161163
}
162164
let ref_opt_void: &Option<Void> = &None;
163165
match *ref_opt_void {
164-
//[normal,min_exh_pats]~^ ERROR non-exhaustive
166+
//[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
165167
None => {}
166168
}
167169
match *ref_opt_void {
@@ -311,21 +313,21 @@ fn invalid_empty_match(bundle: NeverBundle) {
311313
match *x {}
312314

313315
let x: &(u32, !) = &bundle.tuple_half_never;
314-
match *x {} //[normal,min_exh_pats]~ ERROR non-exhaustive
316+
match *x {} //[normal,min_exh_pats,never_pats]~ ERROR non-exhaustive
315317
let x: &(!, !) = &bundle.tuple_never;
316-
match *x {} //[normal,min_exh_pats]~ ERROR non-exhaustive
318+
match *x {} //[normal,min_exh_pats,never_pats]~ ERROR non-exhaustive
317319
let x: &Result<!, !> = &bundle.result_never;
318-
match *x {} //[normal,min_exh_pats]~ ERROR non-exhaustive
320+
match *x {} //[normal,min_exh_pats,never_pats]~ ERROR non-exhaustive
319321
let x: &[!; 3] = &bundle.array_3_never;
320-
match *x {} //[normal,min_exh_pats]~ ERROR non-exhaustive
322+
match *x {} //[normal,min_exh_pats,never_pats]~ ERROR non-exhaustive
321323
}
322324

323325
fn arrays_and_slices(x: NeverBundle) {
324326
let slice_never: &[!] = &[];
325327
match slice_never {}
326328
//~^ ERROR non-empty
327329
match slice_never {
328-
//[normal,min_exh_pats]~^ ERROR not covered
330+
//[normal,min_exh_pats,never_pats]~^ ERROR not covered
329331
[] => {}
330332
}
331333
match slice_never {
@@ -336,6 +338,7 @@ fn arrays_and_slices(x: NeverBundle) {
336338
match slice_never {
337339
//[normal,min_exh_pats]~^ ERROR `&[]`, `&[_]` and `&[_, _]` not covered
338340
//[exhaustive_patterns]~^^ ERROR `&[]` not covered
341+
//[never_pats]~^^^ ERROR `&[]`, `&[!]` and `&[!, !]` not covered
339342
[_, _, _, ..] => {}
340343
}
341344
match slice_never {
@@ -349,6 +352,7 @@ fn arrays_and_slices(x: NeverBundle) {
349352
match slice_never {
350353
//[normal,min_exh_pats]~^ ERROR `&[]` and `&[_, ..]` not covered
351354
//[exhaustive_patterns]~^^ ERROR `&[]` not covered
355+
//[never_pats]~^^^ ERROR `&[]` and `&[!, ..]` not covered
352356
&[..] if false => {}
353357
}
354358

@@ -360,7 +364,7 @@ fn arrays_and_slices(x: NeverBundle) {
360364

361365
let array_3_never: [!; 3] = x.array_3_never;
362366
match array_3_never {}
363-
//[normal]~^ ERROR non-empty
367+
//[normal,never_pats]~^ ERROR non-empty
364368
match array_3_never {
365369
_ => {} //[exhaustive_patterns,min_exh_pats]~ ERROR unreachable pattern
366370
}
@@ -446,7 +450,7 @@ fn bindings(x: NeverBundle) {
446450
&_a => {}
447451
}
448452
match ref_opt_never {
449-
//[normal,min_exh_pats]~^ ERROR non-exhaustive
453+
//[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
450454
&None => {}
451455
}
452456
match ref_opt_never {
@@ -487,7 +491,7 @@ fn bindings(x: NeverBundle) {
487491
ref _a => {}
488492
}
489493
match *ref_opt_never {
490-
//[normal,min_exh_pats]~^ ERROR non-exhaustive
494+
//[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
491495
None => {}
492496
}
493497
match *ref_opt_never {
@@ -535,7 +539,7 @@ fn bindings(x: NeverBundle) {
535539

536540
let ref_res_never: &Result<!, !> = &x.result_never;
537541
match *ref_res_never {
538-
//[normal,min_exh_pats]~^ ERROR non-exhaustive
542+
//[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
539543
// useful, reachable
540544
Ok(_) => {}
541545
}
@@ -546,7 +550,7 @@ fn bindings(x: NeverBundle) {
546550
_ => {}
547551
}
548552
match *ref_res_never {
549-
//[normal,min_exh_pats]~^ ERROR non-exhaustive
553+
//[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
550554
// useful, !reachable
551555
Ok(_a) => {}
552556
}
@@ -565,7 +569,7 @@ fn bindings(x: NeverBundle) {
565569

566570
let ref_tuple_half_never: &(u32, !) = &x.tuple_half_never;
567571
match *ref_tuple_half_never {}
568-
//[normal,min_exh_pats]~^ ERROR non-empty
572+
//[normal,min_exh_pats,never_pats]~^ ERROR non-empty
569573
match *ref_tuple_half_never {
570574
// useful, reachable
571575
(_, _) => {}
@@ -632,7 +636,7 @@ fn guards_and_validity(x: NeverBundle) {
632636
_a if false => {}
633637
}
634638
match ref_never {
635-
//[normal,min_exh_pats]~^ ERROR non-exhaustive
639+
//[normal,min_exh_pats,never_pats]~^ ERROR non-exhaustive
636640
// useful, !reachable
637641
&_a if false => {}
638642
}
@@ -647,6 +651,14 @@ fn guards_and_validity(x: NeverBundle) {
647651
// useful, !reachable
648652
Err(_) => {}
649653
}
654+
match *ref_result_never {
655+
//[normal,min_exh_pats]~^ ERROR `Ok(_)` not covered
656+
//[never_pats]~^^ ERROR `Ok(!)` not covered
657+
// useful, reachable
658+
Ok(_) if false => {}
659+
// useful, reachable
660+
Err(_) => {}
661+
}
650662
let ref_tuple_never: &(!, !) = &x.tuple_never;
651663
match *ref_tuple_never {
652664
// useful, !reachable
@@ -661,6 +673,7 @@ fn diagnostics_subtlety(x: NeverBundle) {
661673
let x: &Option<Result<!, !>> = &None;
662674
match *x {
663675
//[normal,min_exh_pats]~^ ERROR `Some(_)` not covered
676+
//[never_pats]~^^ ERROR `Some(!)` not covered
664677
None => {}
665678
}
666679
}

‎tests/ui/rfcs/rfc-0000-never_patterns/check.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ fn no_arms_or_guards(x: Void) {
1515
//~^ ERROR a never pattern is always unreachable
1616
None => {}
1717
}
18-
match None::<Void> { //~ ERROR: `Some(_)` not covered
18+
match None::<Void> { //~ ERROR: `Some(!)` not covered
1919
Some(!) if true,
2020
//~^ ERROR guard on a never pattern
2121
None => {}
2222
}
23-
match None::<Void> { //~ ERROR: `Some(_)` not covered
23+
match None::<Void> { //~ ERROR: `Some(!)` not covered
2424
Some(!) if true => {}
2525
//~^ ERROR a never pattern is always unreachable
2626
None => {}

‎tests/ui/rfcs/rfc-0000-never_patterns/check.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ LL | Some(never!()) => {}
3131
| this will never be executed
3232
| help: remove this expression
3333

34-
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
34+
error[E0004]: non-exhaustive patterns: `Some(!)` not covered
3535
--> $DIR/check.rs:18:11
3636
|
3737
LL | match None::<Void> {
38-
| ^^^^^^^^^^^^ pattern `Some(_)` not covered
38+
| ^^^^^^^^^^^^ pattern `Some(!)` not covered
3939
|
4040
note: `Option<Void>` defined here
4141
--> $SRC_DIR/core/src/option.rs:LL:COL
@@ -46,14 +46,14 @@ note: `Option<Void>` defined here
4646
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
4747
|
4848
LL ~ None => {},
49-
LL + Some(_) => todo!()
49+
LL + Some(!)
5050
|
5151

52-
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
52+
error[E0004]: non-exhaustive patterns: `Some(!)` not covered
5353
--> $DIR/check.rs:23:11
5454
|
5555
LL | match None::<Void> {
56-
| ^^^^^^^^^^^^ pattern `Some(_)` not covered
56+
| ^^^^^^^^^^^^ pattern `Some(!)` not covered
5757
|
5858
note: `Option<Void>` defined here
5959
--> $SRC_DIR/core/src/option.rs:LL:COL
@@ -64,7 +64,7 @@ note: `Option<Void>` defined here
6464
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
6565
|
6666
LL ~ None => {},
67-
LL + Some(_) => todo!()
67+
LL + Some(!)
6868
|
6969

7070
error: aborting due to 6 previous errors

0 commit comments

Comments
 (0)
Please sign in to comment.