]>
Commit | Line | Data |
---|---|---|
9c376795 | 1 | use crate::{FnCtxt, RawTy}; |
3dfed10e | 2 | use rustc_ast as ast; |
dfeec247 | 3 | use rustc_data_structures::fx::FxHashMap; |
5e7ed085 FG |
4 | use rustc_errors::{ |
5 | pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, | |
04454e1e | 6 | MultiSpan, |
5e7ed085 | 7 | }; |
dfeec247 XL |
8 | use rustc_hir as hir; |
9 | use rustc_hir::def::{CtorKind, DefKind, Res}; | |
10 | use rustc_hir::pat_util::EnumerateAndAdjustIterator; | |
11 | use rustc_hir::{HirId, Pat, PatKind}; | |
74b04a01 XL |
12 | use rustc_infer::infer; |
13 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; | |
5e7ed085 | 14 | use rustc_middle::middle::stability::EvalResult; |
9ffffee4 | 15 | use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeVisitableExt}; |
c295e0f8 | 16 | use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; |
9ffffee4 | 17 | use rustc_span::edit_distance::find_best_match_for_name; |
dfeec247 | 18 | use rustc_span::hygiene::DesugaringKind; |
74b04a01 | 19 | use rustc_span::source_map::{Span, Spanned}; |
5e7ed085 | 20 | use rustc_span::symbol::{kw, sym, Ident}; |
04454e1e | 21 | use rustc_span::{BytePos, DUMMY_SP}; |
353b0b11 | 22 | use rustc_target::abi::FieldIdx; |
ba9703b0 | 23 | use rustc_trait_selection::traits::{ObligationCause, Pattern}; |
6a06907d | 24 | use ty::VariantDef; |
e1599b0c | 25 | |
e1599b0c | 26 | use std::cmp; |
dfeec247 | 27 | use std::collections::hash_map::Entry::{Occupied, Vacant}; |
e1599b0c XL |
28 | |
29 | use super::report_unexpected_variant_res; | |
30 | ||
31 | const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ: &str = "\ | |
32 | This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \ | |
33 | pattern. Every trait defines a type, but because the size of trait implementors isn't fixed, \ | |
34 | this type has no compile-time size. Therefore, all accesses to trait types must be through \ | |
35 | pointers. If you encounter this error you should try to avoid dereferencing the pointer. | |
36 | ||
37 | You can read more about trait objects in the Trait Objects section of the Reference: \ | |
38 | https://doc.rust-lang.org/reference/types.html#trait-objects"; | |
39 | ||
353b0b11 FG |
40 | fn is_number(text: &str) -> bool { |
41 | text.chars().all(|c: char| c.is_digit(10)) | |
42 | } | |
43 | ||
dfeec247 XL |
44 | /// Information about the expected type at the top level of type checking a pattern. |
45 | /// | |
46 | /// **NOTE:** This is only for use by diagnostics. Do NOT use for type checking logic! | |
47 | #[derive(Copy, Clone)] | |
48 | struct TopInfo<'tcx> { | |
49 | /// The `expected` type at the top level of type checking a pattern. | |
50 | expected: Ty<'tcx>, | |
51 | /// Was the origin of the `span` from a scrutinee expression? | |
52 | /// | |
53 | /// Otherwise there is no scrutinee and it could be e.g. from the type of a formal parameter. | |
9ffffee4 | 54 | origin_expr: Option<&'tcx hir::Expr<'tcx>>, |
dfeec247 XL |
55 | /// The span giving rise to the `expected` type, if one could be provided. |
56 | /// | |
57 | /// If `origin_expr` is `true`, then this is the span of the scrutinee as in: | |
58 | /// | |
59 | /// - `match scrutinee { ... }` | |
60 | /// - `let _ = scrutinee;` | |
61 | /// | |
62 | /// This is used to point to add context in type errors. | |
63 | /// In the following example, `span` corresponds to the `a + b` expression: | |
e1599b0c XL |
64 | /// |
65 | /// ```text | |
66 | /// error[E0308]: mismatched types | |
dfeec247 | 67 | /// --> src/main.rs:L:C |
e1599b0c | 68 | /// | |
dfeec247 | 69 | /// L | let temp: usize = match a + b { |
e1599b0c | 70 | /// | ----- this expression has type `usize` |
dfeec247 | 71 | /// L | Ok(num) => num, |
60c5eb7d | 72 | /// | ^^^^^^^ expected `usize`, found enum `std::result::Result` |
e1599b0c XL |
73 | /// | |
74 | /// = note: expected type `usize` | |
75 | /// found type `std::result::Result<_, _>` | |
76 | /// ``` | |
dfeec247 XL |
77 | span: Option<Span>, |
78 | } | |
79 | ||
80 | impl<'tcx> FnCtxt<'_, 'tcx> { | |
74b04a01 | 81 | fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> { |
9ffffee4 FG |
82 | let code = |
83 | Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr.is_some() }; | |
74b04a01 XL |
84 | self.cause(cause_span, code) |
85 | } | |
86 | ||
dfeec247 XL |
87 | fn demand_eqtype_pat_diag( |
88 | &self, | |
89 | cause_span: Span, | |
90 | expected: Ty<'tcx>, | |
91 | actual: Ty<'tcx>, | |
92 | ti: TopInfo<'tcx>, | |
5e7ed085 | 93 | ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { |
9ffffee4 FG |
94 | let mut diag = |
95 | self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?; | |
96 | if let Some(expr) = ti.origin_expr { | |
97 | self.suggest_fn_call(&mut diag, expr, expected, |output| { | |
98 | self.can_eq(self.param_env, output, actual) | |
99 | }); | |
100 | } | |
101 | Some(diag) | |
dfeec247 XL |
102 | } |
103 | ||
104 | fn demand_eqtype_pat( | |
105 | &self, | |
106 | cause_span: Span, | |
107 | expected: Ty<'tcx>, | |
108 | actual: Ty<'tcx>, | |
109 | ti: TopInfo<'tcx>, | |
110 | ) { | |
f9f354fc XL |
111 | if let Some(mut err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) { |
112 | err.emit(); | |
113 | } | |
dfeec247 XL |
114 | } |
115 | } | |
116 | ||
74b04a01 XL |
117 | const INITIAL_BM: BindingMode = BindingMode::BindByValue(hir::Mutability::Not); |
118 | ||
119 | /// Mode for adjusting the expected type and binding mode. | |
120 | enum AdjustMode { | |
121 | /// Peel off all immediate reference types. | |
122 | Peel, | |
123 | /// Reset binding mode to the initial mode. | |
124 | Reset, | |
125 | /// Pass on the input binding mode and expected type. | |
126 | Pass, | |
127 | } | |
128 | ||
dfeec247 XL |
129 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
130 | /// Type check the given top level pattern against the `expected` type. | |
131 | /// | |
132 | /// If a `Some(span)` is provided and `origin_expr` holds, | |
133 | /// then the `span` represents the scrutinee's span. | |
134 | /// The scrutinee is found in e.g. `match scrutinee { ... }` and `let pat = scrutinee;`. | |
135 | /// | |
136 | /// Otherwise, `Some(span)` represents the span of a type expression | |
137 | /// which originated the `expected` type. | |
138 | pub fn check_pat_top( | |
139 | &self, | |
140 | pat: &'tcx Pat<'tcx>, | |
141 | expected: Ty<'tcx>, | |
142 | span: Option<Span>, | |
9ffffee4 | 143 | origin_expr: Option<&'tcx hir::Expr<'tcx>>, |
dfeec247 | 144 | ) { |
064997fb | 145 | let info = TopInfo { expected, origin_expr, span }; |
74b04a01 | 146 | self.check_pat(pat, expected, INITIAL_BM, info); |
dfeec247 XL |
147 | } |
148 | ||
149 | /// Type check the given `pat` against the `expected` type | |
150 | /// with the provided `def_bm` (default binding mode). | |
151 | /// | |
152 | /// Outside of this module, `check_pat_top` should always be used. | |
153 | /// Conversely, inside this module, `check_pat_top` should never be used. | |
6a06907d | 154 | #[instrument(level = "debug", skip(self, ti))] |
e1599b0c XL |
155 | fn check_pat( |
156 | &self, | |
dfeec247 | 157 | pat: &'tcx Pat<'tcx>, |
e1599b0c XL |
158 | expected: Ty<'tcx>, |
159 | def_bm: BindingMode, | |
dfeec247 | 160 | ti: TopInfo<'tcx>, |
e1599b0c | 161 | ) { |
74b04a01 | 162 | let path_res = match &pat.kind { |
136023e0 XL |
163 | PatKind::Path(qpath) => { |
164 | Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span)) | |
165 | } | |
e1599b0c XL |
166 | _ => None, |
167 | }; | |
74b04a01 XL |
168 | let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); |
169 | let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode); | |
e1599b0c | 170 | |
dfeec247 | 171 | let ty = match pat.kind { |
e1599b0c | 172 | PatKind::Wild => expected, |
dfeec247 XL |
173 | PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti), |
174 | PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti), | |
e1599b0c | 175 | PatKind::Binding(ba, var_id, _, sub) => { |
dfeec247 | 176 | self.check_pat_ident(pat, ba, var_id, sub, expected, def_bm, ti) |
e1599b0c | 177 | } |
dfeec247 XL |
178 | PatKind::TupleStruct(ref qpath, subpats, ddpos) => { |
179 | self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti) | |
e1599b0c | 180 | } |
064997fb FG |
181 | PatKind::Path(ref qpath) => { |
182 | self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti) | |
183 | } | |
c295e0f8 XL |
184 | PatKind::Struct(ref qpath, fields, has_rest_pat) => { |
185 | self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, def_bm, ti) | |
e1599b0c XL |
186 | } |
187 | PatKind::Or(pats) => { | |
e1599b0c | 188 | for pat in pats { |
064997fb | 189 | self.check_pat(pat, expected, def_bm, ti); |
e1599b0c | 190 | } |
e74abb32 | 191 | expected |
e1599b0c XL |
192 | } |
193 | PatKind::Tuple(elements, ddpos) => { | |
dfeec247 | 194 | self.check_pat_tuple(pat.span, elements, ddpos, expected, def_bm, ti) |
e1599b0c | 195 | } |
dfeec247 | 196 | PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, def_bm, ti), |
e1599b0c | 197 | PatKind::Ref(inner, mutbl) => { |
dfeec247 | 198 | self.check_pat_ref(pat, inner, mutbl, expected, def_bm, ti) |
e1599b0c XL |
199 | } |
200 | PatKind::Slice(before, slice, after) => { | |
dfeec247 | 201 | self.check_pat_slice(pat.span, before, slice, after, expected, def_bm, ti) |
e1599b0c XL |
202 | } |
203 | }; | |
204 | ||
205 | self.write_ty(pat.hir_id, ty); | |
206 | ||
207 | // (note_1): In most of the cases where (note_1) is referenced | |
208 | // (literals and constants being the exception), we relate types | |
209 | // using strict equality, even though subtyping would be sufficient. | |
210 | // There are a few reasons for this, some of which are fairly subtle | |
211 | // and which cost me (nmatsakis) an hour or two debugging to remember, | |
212 | // so I thought I'd write them down this time. | |
213 | // | |
214 | // 1. There is no loss of expressiveness here, though it does | |
215 | // cause some inconvenience. What we are saying is that the type | |
216 | // of `x` becomes *exactly* what is expected. This can cause unnecessary | |
217 | // errors in some cases, such as this one: | |
218 | // | |
219 | // ``` | |
f035d41b | 220 | // fn foo<'x>(x: &'x i32) { |
e1599b0c XL |
221 | // let a = 1; |
222 | // let mut z = x; | |
223 | // z = &a; | |
224 | // } | |
225 | // ``` | |
226 | // | |
227 | // The reason we might get an error is that `z` might be | |
f035d41b | 228 | // assigned a type like `&'x i32`, and then we would have |
e1599b0c XL |
229 | // a problem when we try to assign `&a` to `z`, because |
230 | // the lifetime of `&a` (i.e., the enclosing block) is | |
231 | // shorter than `'x`. | |
232 | // | |
233 | // HOWEVER, this code works fine. The reason is that the | |
234 | // expected type here is whatever type the user wrote, not | |
235 | // the initializer's type. In this case the user wrote | |
236 | // nothing, so we are going to create a type variable `Z`. | |
f035d41b XL |
237 | // Then we will assign the type of the initializer (`&'x i32`) |
238 | // as a subtype of `Z`: `&'x i32 <: Z`. And hence we | |
239 | // will instantiate `Z` as a type `&'0 i32` where `'0` is | |
240 | // a fresh region variable, with the constraint that `'x : '0`. | |
241 | // So basically we're all set. | |
e1599b0c XL |
242 | // |
243 | // Note that there are two tests to check that this remains true | |
244 | // (`regions-reassign-{match,let}-bound-pointer.rs`). | |
245 | // | |
353b0b11 | 246 | // 2. An outdated issue related to the old HIR borrowck. See the test |
e1599b0c | 247 | // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`, |
e1599b0c XL |
248 | } |
249 | ||
250 | /// Compute the new expected type and default binding mode from the old ones | |
251 | /// as well as the pattern form we are currently checking. | |
252 | fn calc_default_binding_mode( | |
253 | &self, | |
dfeec247 | 254 | pat: &'tcx Pat<'tcx>, |
e1599b0c XL |
255 | expected: Ty<'tcx>, |
256 | def_bm: BindingMode, | |
74b04a01 | 257 | adjust_mode: AdjustMode, |
e1599b0c | 258 | ) -> (Ty<'tcx>, BindingMode) { |
74b04a01 XL |
259 | match adjust_mode { |
260 | AdjustMode::Pass => (expected, def_bm), | |
261 | AdjustMode::Reset => (expected, INITIAL_BM), | |
262 | AdjustMode::Peel => self.peel_off_references(pat, expected, def_bm), | |
e1599b0c XL |
263 | } |
264 | } | |
265 | ||
74b04a01 XL |
266 | /// How should the binding mode and expected type be adjusted? |
267 | /// | |
e1599b0c | 268 | /// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`. |
74b04a01 | 269 | fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> AdjustMode { |
29967ef6 XL |
270 | // When we perform destructuring assignment, we disable default match bindings, which are |
271 | // unintuitive in this context. | |
272 | if !pat.default_binding_modes { | |
273 | return AdjustMode::Reset; | |
274 | } | |
74b04a01 XL |
275 | match &pat.kind { |
276 | // Type checking these product-like types successfully always require | |
277 | // that the expected type be of those types and not reference types. | |
dfeec247 XL |
278 | PatKind::Struct(..) |
279 | | PatKind::TupleStruct(..) | |
280 | | PatKind::Tuple(..) | |
281 | | PatKind::Box(_) | |
282 | | PatKind::Range(..) | |
74b04a01 XL |
283 | | PatKind::Slice(..) => AdjustMode::Peel, |
284 | // String and byte-string literals result in types `&str` and `&[u8]` respectively. | |
285 | // All other literals result in non-reference types. | |
286 | // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`. | |
3c0e092e XL |
287 | // |
288 | // Call `resolve_vars_if_possible` here for inline const blocks. | |
289 | PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() { | |
74b04a01 XL |
290 | ty::Ref(..) => AdjustMode::Pass, |
291 | _ => AdjustMode::Peel, | |
292 | }, | |
dfeec247 | 293 | PatKind::Path(_) => match opt_path_res.unwrap() { |
74b04a01 XL |
294 | // These constants can be of a reference type, e.g. `const X: &u8 = &0;`. |
295 | // Peeling the reference types too early will cause type checking failures. | |
296 | // Although it would be possible to *also* peel the types of the constants too. | |
ba9703b0 | 297 | Res::Def(DefKind::Const | DefKind::AssocConst, _) => AdjustMode::Pass, |
74b04a01 XL |
298 | // In the `ValueNS`, we have `SelfCtor(..) | Ctor(_, Const), _)` remaining which |
299 | // could successfully compile. The former being `Self` requires a unit struct. | |
300 | // In either case, and unlike constants, the pattern itself cannot be | |
5e7ed085 | 301 | // a reference type wherefore peeling doesn't give up any expressiveness. |
74b04a01 | 302 | _ => AdjustMode::Peel, |
dfeec247 | 303 | }, |
74b04a01 XL |
304 | // When encountering a `& mut? pat` pattern, reset to "by value". |
305 | // This is so that `x` and `y` here are by value, as they appear to be: | |
306 | // | |
e74abb32 | 307 | // ``` |
74b04a01 XL |
308 | // match &(&22, &44) { |
309 | // (&x, &y) => ... | |
e74abb32 XL |
310 | // } |
311 | // ``` | |
312 | // | |
74b04a01 XL |
313 | // See issue #46688. |
314 | PatKind::Ref(..) => AdjustMode::Reset, | |
315 | // A `_` pattern works with any expected type, so there's no need to do anything. | |
316 | PatKind::Wild | |
317 | // Bindings also work with whatever the expected type is, | |
318 | // and moreover if we peel references off, that will give us the wrong binding type. | |
319 | // Also, we can have a subpattern `binding @ pat`. | |
320 | // Each side of the `@` should be treated independently (like with OR-patterns). | |
321 | | PatKind::Binding(..) | |
322 | // An OR-pattern just propagates to each individual alternative. | |
323 | // This is maximally flexible, allowing e.g., `Some(mut x) | &Some(mut x)`. | |
324 | // In that example, `Some(mut x)` results in `Peel` whereas `&Some(mut x)` in `Reset`. | |
325 | | PatKind::Or(_) => AdjustMode::Pass, | |
e1599b0c XL |
326 | } |
327 | } | |
328 | ||
329 | /// Peel off as many immediately nested `& mut?` from the expected type as possible | |
330 | /// and return the new expected type and binding default binding mode. | |
331 | /// The adjustments vector, if non-empty is stored in a table. | |
332 | fn peel_off_references( | |
333 | &self, | |
dfeec247 | 334 | pat: &'tcx Pat<'tcx>, |
e1599b0c XL |
335 | expected: Ty<'tcx>, |
336 | mut def_bm: BindingMode, | |
337 | ) -> (Ty<'tcx>, BindingMode) { | |
c295e0f8 | 338 | let mut expected = self.resolve_vars_with_obligations(expected); |
e1599b0c XL |
339 | |
340 | // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, | |
341 | // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches | |
342 | // the `Some(5)` which is not of type Ref. | |
343 | // | |
344 | // For each ampersand peeled off, update the binding mode and push the original | |
345 | // type into the adjustments vector. | |
346 | // | |
347 | // See the examples in `ui/match-defbm*.rs`. | |
348 | let mut pat_adjustments = vec![]; | |
1b1a35ee | 349 | while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() { |
e1599b0c XL |
350 | debug!("inspecting {:?}", expected); |
351 | ||
352 | debug!("current discriminant is Ref, inserting implicit deref"); | |
3dfed10e | 353 | // Preserve the reference type. We'll need it later during THIR lowering. |
e1599b0c XL |
354 | pat_adjustments.push(expected); |
355 | ||
356 | expected = inner_ty; | |
357 | def_bm = ty::BindByReference(match def_bm { | |
358 | // If default binding mode is by value, make it `ref` or `ref mut` | |
359 | // (depending on whether we observe `&` or `&mut`). | |
360 | ty::BindByValue(_) | | |
361 | // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`). | |
dfeec247 | 362 | ty::BindByReference(hir::Mutability::Mut) => inner_mutability, |
e1599b0c XL |
363 | // Once a `ref`, always a `ref`. |
364 | // This is because a `& &mut` cannot mutate the underlying value. | |
dfeec247 | 365 | ty::BindByReference(m @ hir::Mutability::Not) => m, |
e1599b0c XL |
366 | }); |
367 | } | |
368 | ||
74b04a01 | 369 | if !pat_adjustments.is_empty() { |
e1599b0c | 370 | debug!("default binding mode is now {:?}", def_bm); |
3dfed10e XL |
371 | self.inh |
372 | .typeck_results | |
373 | .borrow_mut() | |
374 | .pat_adjustments_mut() | |
375 | .insert(pat.hir_id, pat_adjustments); | |
e1599b0c XL |
376 | } |
377 | ||
378 | (expected, def_bm) | |
379 | } | |
380 | ||
381 | fn check_pat_lit( | |
382 | &self, | |
383 | span: Span, | |
dfeec247 | 384 | lt: &hir::Expr<'tcx>, |
e1599b0c | 385 | expected: Ty<'tcx>, |
dfeec247 | 386 | ti: TopInfo<'tcx>, |
e1599b0c XL |
387 | ) -> Ty<'tcx> { |
388 | // We've already computed the type above (when checking for a non-ref pat), | |
389 | // so avoid computing it again. | |
390 | let ty = self.node_ty(lt.hir_id); | |
391 | ||
392 | // Byte string patterns behave the same way as array patterns | |
393 | // They can denote both statically and dynamically-sized byte arrays. | |
394 | let mut pat_ty = ty; | |
9c376795 | 395 | if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(..), .. }) = lt.kind { |
74b04a01 | 396 | let expected = self.structurally_resolved_type(span, expected); |
04454e1e FG |
397 | if let ty::Ref(_, inner_ty, _) = expected.kind() |
398 | && matches!(inner_ty.kind(), ty::Slice(_)) | |
399 | { | |
400 | let tcx = self.tcx; | |
401 | trace!(?lt.hir_id.local_id, "polymorphic byte string lit"); | |
402 | self.typeck_results | |
403 | .borrow_mut() | |
404 | .treat_byte_string_as_slice | |
405 | .insert(lt.hir_id.local_id); | |
406 | pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8)); | |
e1599b0c XL |
407 | } |
408 | } | |
409 | ||
487cf647 FG |
410 | if self.tcx.features().string_deref_patterns && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind { |
411 | let tcx = self.tcx; | |
412 | let expected = self.resolve_vars_if_possible(expected); | |
413 | pat_ty = match expected.kind() { | |
414 | ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => expected, | |
415 | ty::Str => tcx.mk_static_str(), | |
416 | _ => pat_ty, | |
417 | }; | |
418 | } | |
419 | ||
e1599b0c XL |
420 | // Somewhat surprising: in this case, the subtyping relation goes the |
421 | // opposite way as the other cases. Actually what we really want is not | |
422 | // a subtyping relation at all but rather that there exists a LUB | |
423 | // (so that they can be compared). However, in practice, constants are | |
424 | // always scalars or strings. For scalars subtyping is irrelevant, | |
425 | // and for strings `ty` is type is `&'static str`, so if we say that | |
426 | // | |
427 | // &'static str <: expected | |
428 | // | |
429 | // then that's equivalent to there existing a LUB. | |
74b04a01 XL |
430 | let cause = self.pattern_cause(ti, span); |
431 | if let Some(mut err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) { | |
dfeec247 XL |
432 | err.emit_unless( |
433 | ti.span | |
434 | .filter(|&s| { | |
435 | // In the case of `if`- and `while`-expressions we've already checked | |
436 | // that `scrutinee: bool`. We know that the pattern is `true`, | |
437 | // so an error here would be a duplicate and from the wrong POV. | |
438 | s.is_desugaring(DesugaringKind::CondTemporary) | |
439 | }) | |
440 | .is_some(), | |
441 | ); | |
e1599b0c XL |
442 | } |
443 | ||
444 | pat_ty | |
445 | } | |
446 | ||
447 | fn check_pat_range( | |
448 | &self, | |
449 | span: Span, | |
dfeec247 XL |
450 | lhs: Option<&'tcx hir::Expr<'tcx>>, |
451 | rhs: Option<&'tcx hir::Expr<'tcx>>, | |
e1599b0c | 452 | expected: Ty<'tcx>, |
dfeec247 XL |
453 | ti: TopInfo<'tcx>, |
454 | ) -> Ty<'tcx> { | |
455 | let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr { | |
c295e0f8 | 456 | None => None, |
dfeec247 XL |
457 | Some(expr) => { |
458 | let ty = self.check_expr(expr); | |
c295e0f8 XL |
459 | // Check that the end-point is possibly of numeric or char type. |
460 | // The early check here is not for correctness, but rather better | |
461 | // diagnostics (e.g. when `&str` is being matched, `expected` will | |
462 | // be peeled to `str` while ty here is still `&str`, if we don't | |
5e7ed085 | 463 | // err early here, a rather confusing unification error will be |
c295e0f8 XL |
464 | // emitted instead). |
465 | let fail = | |
466 | !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error()); | |
467 | Some((fail, ty, expr.span)) | |
dfeec247 | 468 | } |
e1599b0c | 469 | }; |
c295e0f8 XL |
470 | let mut lhs = calc_side(lhs); |
471 | let mut rhs = calc_side(rhs); | |
e1599b0c | 472 | |
dfeec247 XL |
473 | if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) { |
474 | // There exists a side that didn't meet our criteria that the end-point | |
475 | // be of a numeric or char type, as checked in `calc_side` above. | |
9ffffee4 FG |
476 | let guar = self.emit_err_pat_range(span, lhs, rhs); |
477 | return self.tcx.ty_error(guar); | |
e1599b0c XL |
478 | } |
479 | ||
c295e0f8 | 480 | // Unify each side with `expected`. |
e1599b0c | 481 | // Subtyping doesn't matter here, as the value is some kind of scalar. |
c295e0f8 | 482 | let demand_eqtype = |x: &mut _, y| { |
04454e1e FG |
483 | if let Some((ref mut fail, x_ty, x_span)) = *x |
484 | && let Some(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) | |
485 | { | |
486 | if let Some((_, y_ty, y_span)) = y { | |
487 | self.endpoint_has_type(&mut err, y_span, y_ty); | |
488 | } | |
489 | err.emit(); | |
490 | *fail = true; | |
dfeec247 XL |
491 | } |
492 | }; | |
c295e0f8 XL |
493 | demand_eqtype(&mut lhs, rhs); |
494 | demand_eqtype(&mut rhs, lhs); | |
495 | ||
496 | if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) { | |
9ffffee4 | 497 | return self.tcx.ty_error_misc(); |
c295e0f8 | 498 | } |
dfeec247 | 499 | |
c295e0f8 XL |
500 | // Find the unified type and check if it's of numeric or char type again. |
501 | // This check is needed if both sides are inference variables. | |
502 | // We require types to be resolved here so that we emit inference failure | |
503 | // rather than "_ is not a char or numeric". | |
504 | let ty = self.structurally_resolved_type(span, expected); | |
505 | if !(ty.is_numeric() || ty.is_char() || ty.references_error()) { | |
506 | if let Some((ref mut fail, _, _)) = lhs { | |
507 | *fail = true; | |
508 | } | |
509 | if let Some((ref mut fail, _, _)) = rhs { | |
510 | *fail = true; | |
511 | } | |
9ffffee4 FG |
512 | let guar = self.emit_err_pat_range(span, lhs, rhs); |
513 | return self.tcx.ty_error(guar); | |
c295e0f8 XL |
514 | } |
515 | ty | |
dfeec247 XL |
516 | } |
517 | ||
5e7ed085 | 518 | fn endpoint_has_type(&self, err: &mut Diagnostic, span: Span, ty: Ty<'_>) { |
dfeec247 XL |
519 | if !ty.references_error() { |
520 | err.span_label(span, &format!("this is of type `{}`", ty)); | |
521 | } | |
e1599b0c XL |
522 | } |
523 | ||
60c5eb7d XL |
524 | fn emit_err_pat_range( |
525 | &self, | |
526 | span: Span, | |
dfeec247 XL |
527 | lhs: Option<(bool, Ty<'tcx>, Span)>, |
528 | rhs: Option<(bool, Ty<'tcx>, Span)>, | |
9ffffee4 | 529 | ) -> ErrorGuaranteed { |
dfeec247 XL |
530 | let span = match (lhs, rhs) { |
531 | (Some((true, ..)), Some((true, ..))) => span, | |
532 | (Some((true, _, sp)), _) => sp, | |
533 | (_, Some((true, _, sp))) => sp, | |
534 | _ => span_bug!(span, "emit_err_pat_range: no side failed or exists but still error?"), | |
60c5eb7d | 535 | }; |
60c5eb7d XL |
536 | let mut err = struct_span_err!( |
537 | self.tcx.sess, | |
538 | span, | |
539 | E0029, | |
1b1a35ee | 540 | "only `char` and numeric types are allowed in range patterns" |
60c5eb7d | 541 | ); |
c295e0f8 XL |
542 | let msg = |ty| { |
543 | let ty = self.resolve_vars_if_possible(ty); | |
544 | format!("this is of type `{}` but it should be `char` or numeric", ty) | |
545 | }; | |
dfeec247 | 546 | let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| { |
60c5eb7d | 547 | err.span_label(first_span, &msg(first_ty)); |
dfeec247 | 548 | if let Some((_, ty, sp)) = second { |
c295e0f8 | 549 | let ty = self.resolve_vars_if_possible(ty); |
dfeec247 | 550 | self.endpoint_has_type(&mut err, sp, ty); |
60c5eb7d XL |
551 | } |
552 | }; | |
dfeec247 XL |
553 | match (lhs, rhs) { |
554 | (Some((true, lhs_ty, lhs_sp)), Some((true, rhs_ty, rhs_sp))) => { | |
555 | err.span_label(lhs_sp, &msg(lhs_ty)); | |
556 | err.span_label(rhs_sp, &msg(rhs_ty)); | |
557 | } | |
558 | (Some((true, lhs_ty, lhs_sp)), rhs) => one_side_err(lhs_sp, lhs_ty, rhs), | |
559 | (lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs), | |
560 | _ => span_bug!(span, "Impossible, verified above."), | |
60c5eb7d | 561 | } |
9c376795 FG |
562 | if (lhs, rhs).references_error() { |
563 | err.downgrade_to_delayed_bug(); | |
564 | } | |
60c5eb7d XL |
565 | if self.tcx.sess.teach(&err.get_code().unwrap()) { |
566 | err.note( | |
567 | "In a match expression, only numbers and characters can be matched \ | |
568 | against a range. This is because the compiler checks that the range \ | |
569 | is non-empty at compile-time, and is unable to evaluate arbitrary \ | |
570 | comparison functions. If you want to capture values of an orderable \ | |
dfeec247 XL |
571 | type between two end-points, you can use a guard.", |
572 | ); | |
60c5eb7d | 573 | } |
9ffffee4 | 574 | err.emit() |
60c5eb7d XL |
575 | } |
576 | ||
e1599b0c XL |
577 | fn check_pat_ident( |
578 | &self, | |
74b04a01 | 579 | pat: &'tcx Pat<'tcx>, |
e1599b0c XL |
580 | ba: hir::BindingAnnotation, |
581 | var_id: HirId, | |
dfeec247 | 582 | sub: Option<&'tcx Pat<'tcx>>, |
e1599b0c XL |
583 | expected: Ty<'tcx>, |
584 | def_bm: BindingMode, | |
dfeec247 | 585 | ti: TopInfo<'tcx>, |
e1599b0c XL |
586 | ) -> Ty<'tcx> { |
587 | // Determine the binding mode... | |
588 | let bm = match ba { | |
f2b60f7d | 589 | hir::BindingAnnotation::NONE => def_bm, |
e1599b0c XL |
590 | _ => BindingMode::convert(ba), |
591 | }; | |
592 | // ...and store it in a side table: | |
3dfed10e | 593 | self.inh.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm); |
e1599b0c XL |
594 | |
595 | debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); | |
596 | ||
597 | let local_ty = self.local_ty(pat.span, pat.hir_id).decl_ty; | |
598 | let eq_ty = match bm { | |
599 | ty::BindByReference(mutbl) => { | |
74b04a01 | 600 | // If the binding is like `ref x | ref mut x`, |
e1599b0c XL |
601 | // then `x` is assigned a value of type `&M T` where M is the |
602 | // mutability and T is the expected type. | |
e74abb32 | 603 | // |
e1599b0c XL |
604 | // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` |
605 | // is required. However, we use equality, which is stronger. | |
606 | // See (note_1) for an explanation. | |
e74abb32 | 607 | self.new_ref_ty(pat.span, mutbl, expected) |
e1599b0c XL |
608 | } |
609 | // Otherwise, the type of x is the expected type `T`. | |
610 | ty::BindByValue(_) => { | |
611 | // As above, `T <: typeof(x)` is required, but we use equality, see (note_1). | |
612 | expected | |
613 | } | |
614 | }; | |
dfeec247 | 615 | self.demand_eqtype_pat(pat.span, eq_ty, local_ty, ti); |
e1599b0c XL |
616 | |
617 | // If there are multiple arms, make sure they all agree on | |
618 | // what the type of the binding `x` ought to be. | |
619 | if var_id != pat.hir_id { | |
f2b60f7d | 620 | self.check_binding_alt_eq_ty(ba, pat.span, var_id, local_ty, ti); |
e1599b0c XL |
621 | } |
622 | ||
623 | if let Some(p) = sub { | |
064997fb | 624 | self.check_pat(p, expected, def_bm, ti); |
e1599b0c XL |
625 | } |
626 | ||
627 | local_ty | |
628 | } | |
629 | ||
f2b60f7d FG |
630 | fn check_binding_alt_eq_ty( |
631 | &self, | |
632 | ba: hir::BindingAnnotation, | |
633 | span: Span, | |
634 | var_id: HirId, | |
635 | ty: Ty<'tcx>, | |
636 | ti: TopInfo<'tcx>, | |
637 | ) { | |
74b04a01 XL |
638 | let var_ty = self.local_ty(span, var_id).decl_ty; |
639 | if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { | |
640 | let hir = self.tcx.hir(); | |
641 | let var_ty = self.resolve_vars_with_obligations(var_ty); | |
04454e1e | 642 | let msg = format!("first introduced with type `{var_ty}` here"); |
74b04a01 XL |
643 | err.span_label(hir.span(var_id), msg); |
644 | let in_match = hir.parent_iter(var_id).any(|(_, n)| { | |
645 | matches!( | |
646 | n, | |
647 | hir::Node::Expr(hir::Expr { | |
648 | kind: hir::ExprKind::Match(.., hir::MatchSource::Normal), | |
649 | .. | |
650 | }) | |
651 | ) | |
652 | }); | |
653 | let pre = if in_match { "in the same arm, " } else { "" }; | |
654 | err.note(&format!("{}a binding must have the same type in all alternatives", pre)); | |
f2b60f7d FG |
655 | self.suggest_adding_missing_ref_or_removing_ref( |
656 | &mut err, | |
657 | span, | |
658 | var_ty, | |
659 | self.resolve_vars_with_obligations(ty), | |
660 | ba, | |
661 | ); | |
74b04a01 XL |
662 | err.emit(); |
663 | } | |
664 | } | |
665 | ||
f2b60f7d FG |
666 | fn suggest_adding_missing_ref_or_removing_ref( |
667 | &self, | |
668 | err: &mut Diagnostic, | |
669 | span: Span, | |
670 | expected: Ty<'tcx>, | |
671 | actual: Ty<'tcx>, | |
672 | ba: hir::BindingAnnotation, | |
673 | ) { | |
674 | match (expected.kind(), actual.kind(), ba) { | |
675 | (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::NONE) | |
9ffffee4 | 676 | if self.can_eq(self.param_env, *inner_ty, actual) => |
f2b60f7d FG |
677 | { |
678 | err.span_suggestion_verbose( | |
679 | span.shrink_to_lo(), | |
680 | "consider adding `ref`", | |
681 | "ref ", | |
682 | Applicability::MaybeIncorrect, | |
683 | ); | |
684 | } | |
685 | (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::REF) | |
9ffffee4 | 686 | if self.can_eq(self.param_env, expected, *inner_ty) => |
f2b60f7d FG |
687 | { |
688 | err.span_suggestion_verbose( | |
689 | span.with_hi(span.lo() + BytePos(4)), | |
690 | "consider removing `ref`", | |
691 | "", | |
692 | Applicability::MaybeIncorrect, | |
693 | ); | |
694 | } | |
695 | _ => (), | |
696 | } | |
697 | } | |
698 | ||
923072b8 FG |
699 | // Precondition: pat is a Ref(_) pattern |
700 | fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) { | |
e1599b0c | 701 | let tcx = self.tcx; |
923072b8 FG |
702 | if let PatKind::Ref(inner, mutbl) = pat.kind |
703 | && let PatKind::Binding(_, _, binding, ..) = inner.kind { | |
9c376795 | 704 | let binding_parent_id = tcx.hir().parent_id(pat.hir_id); |
e1599b0c | 705 | let binding_parent = tcx.hir().get(binding_parent_id); |
923072b8 FG |
706 | debug!(?inner, ?pat, ?binding_parent); |
707 | ||
708 | let mutability = match mutbl { | |
709 | ast::Mutability::Mut => "mut", | |
710 | ast::Mutability::Not => "", | |
711 | }; | |
712 | ||
064997fb | 713 | let mut_var_suggestion = 'block: { |
487cf647 | 714 | if mutbl.is_not() { |
064997fb FG |
715 | break 'block None; |
716 | } | |
717 | ||
718 | let ident_kind = match binding_parent { | |
719 | hir::Node::Param(_) => "parameter", | |
720 | hir::Node::Local(_) => "variable", | |
721 | hir::Node::Arm(_) => "binding", | |
722 | ||
723 | // Provide diagnostics only if the parent pattern is struct-like, | |
724 | // i.e. where `mut binding` makes sense | |
725 | hir::Node::Pat(Pat { kind, .. }) => match kind { | |
726 | PatKind::Struct(..) | |
727 | | PatKind::TupleStruct(..) | |
728 | | PatKind::Or(..) | |
729 | | PatKind::Tuple(..) | |
730 | | PatKind::Slice(..) => "binding", | |
731 | ||
732 | PatKind::Wild | |
733 | | PatKind::Binding(..) | |
734 | | PatKind::Path(..) | |
735 | | PatKind::Box(..) | |
736 | | PatKind::Ref(..) | |
737 | | PatKind::Lit(..) | |
738 | | PatKind::Range(..) => break 'block None, | |
739 | }, | |
740 | ||
741 | // Don't provide suggestions in other cases | |
742 | _ => break 'block None, | |
743 | }; | |
744 | ||
745 | Some(( | |
746 | pat.span, | |
747 | format!("to declare a mutable {ident_kind} use"), | |
748 | format!("mut {binding}"), | |
749 | )) | |
750 | ||
751 | }; | |
752 | ||
e1599b0c | 753 | match binding_parent { |
923072b8 FG |
754 | // Check that there is explicit type (ie this is not a closure param with inferred type) |
755 | // so we don't suggest moving something to the type that does not exist | |
756 | hir::Node::Param(hir::Param { ty_span, .. }) if binding.span != *ty_span => { | |
757 | err.multipart_suggestion_verbose( | |
758 | format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"), | |
759 | vec![ | |
760 | (pat.span.until(inner.span), "".to_owned()), | |
487cf647 | 761 | (ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()), |
923072b8 FG |
762 | ], |
763 | Applicability::MachineApplicable | |
94222f64 | 764 | ); |
064997fb FG |
765 | |
766 | if let Some((sp, msg, sugg)) = mut_var_suggestion { | |
767 | err.span_note(sp, format!("{msg}: `{sugg}`")); | |
768 | } | |
e1599b0c | 769 | } |
9c376795 FG |
770 | hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => { |
771 | for i in pat_arr.iter() { | |
772 | if let PatKind::Ref(the_ref, _) = i.kind | |
773 | && let PatKind::Binding(mt, _, ident, _) = the_ref.kind { | |
774 | let hir::BindingAnnotation(_, mtblty) = mt; | |
775 | err.span_suggestion_verbose( | |
776 | i.span, | |
777 | format!("consider removing `&{mutability}` from the pattern"), | |
778 | mtblty.prefix_str().to_string() + &ident.name.to_string(), | |
779 | Applicability::MaybeIncorrect, | |
780 | ); | |
781 | } | |
782 | } | |
783 | if let Some((sp, msg, sugg)) = mut_var_suggestion { | |
784 | err.span_note(sp, format!("{msg}: `{sugg}`")); | |
785 | } | |
786 | } | |
923072b8 | 787 | hir::Node::Param(_) | hir::Node::Arm(_) | hir::Node::Pat(_) => { |
e1599b0c | 788 | // rely on match ergonomics or it might be nested `&&pat` |
923072b8 FG |
789 | err.span_suggestion_verbose( |
790 | pat.span.until(inner.span), | |
791 | format!("consider removing `&{mutability}` from the pattern"), | |
792 | "", | |
793 | Applicability::MaybeIncorrect, | |
794 | ); | |
064997fb FG |
795 | |
796 | if let Some((sp, msg, sugg)) = mut_var_suggestion { | |
797 | err.span_note(sp, format!("{msg}: `{sugg}`")); | |
798 | } | |
799 | } | |
800 | _ if let Some((sp, msg, sugg)) = mut_var_suggestion => { | |
801 | err.span_suggestion(sp, msg, sugg, Applicability::MachineApplicable); | |
e1599b0c XL |
802 | } |
803 | _ => {} // don't provide suggestions in other cases #55175 | |
804 | } | |
805 | } | |
806 | } | |
807 | ||
9ffffee4 FG |
808 | pub fn check_dereferenceable( |
809 | &self, | |
810 | span: Span, | |
811 | expected: Ty<'tcx>, | |
812 | inner: &Pat<'_>, | |
813 | ) -> Result<(), ErrorGuaranteed> { | |
5e7ed085 FG |
814 | if let PatKind::Binding(..) = inner.kind |
815 | && let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) | |
816 | && let ty::Dynamic(..) = mt.ty.kind() | |
817 | { | |
9ffffee4 FG |
818 | // This is "x = SomeTrait" being reduced from |
819 | // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error. | |
820 | let type_str = self.ty_to_string(expected); | |
821 | let mut err = struct_span_err!( | |
822 | self.tcx.sess, | |
823 | span, | |
824 | E0033, | |
825 | "type `{}` cannot be dereferenced", | |
826 | type_str | |
827 | ); | |
828 | err.span_label(span, format!("type `{type_str}` cannot be dereferenced")); | |
829 | if self.tcx.sess.teach(&err.get_code().unwrap()) { | |
830 | err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ); | |
831 | } | |
832 | return Err(err.emit()); | |
833 | } | |
834 | Ok(()) | |
e1599b0c XL |
835 | } |
836 | ||
837 | fn check_pat_struct( | |
838 | &self, | |
dfeec247 XL |
839 | pat: &'tcx Pat<'tcx>, |
840 | qpath: &hir::QPath<'_>, | |
6a06907d | 841 | fields: &'tcx [hir::PatField<'tcx>], |
c295e0f8 | 842 | has_rest_pat: bool, |
e1599b0c XL |
843 | expected: Ty<'tcx>, |
844 | def_bm: BindingMode, | |
dfeec247 | 845 | ti: TopInfo<'tcx>, |
e1599b0c XL |
846 | ) -> Ty<'tcx> { |
847 | // Resolve the path and check the definition for errors. | |
9ffffee4 FG |
848 | let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) { |
849 | Ok(data) => data, | |
850 | Err(guar) => { | |
851 | let err = self.tcx.ty_error(guar); | |
852 | for field in fields { | |
853 | let ti = ti; | |
854 | self.check_pat(field.pat, err, def_bm, ti); | |
855 | } | |
856 | return err; | |
e1599b0c | 857 | } |
e1599b0c XL |
858 | }; |
859 | ||
860 | // Type-check the path. | |
dfeec247 | 861 | self.demand_eqtype_pat(pat.span, expected, pat_ty, ti); |
e1599b0c XL |
862 | |
863 | // Type-check subpatterns. | |
c295e0f8 | 864 | if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, def_bm, ti) { |
e1599b0c XL |
865 | pat_ty |
866 | } else { | |
9ffffee4 | 867 | self.tcx.ty_error_misc() |
e1599b0c XL |
868 | } |
869 | } | |
870 | ||
064997fb | 871 | fn check_pat_path( |
e1599b0c | 872 | &self, |
064997fb FG |
873 | pat: &Pat<'tcx>, |
874 | qpath: &hir::QPath<'_>, | |
9c376795 | 875 | path_resolution: (Res, Option<RawTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]), |
e1599b0c | 876 | expected: Ty<'tcx>, |
74b04a01 | 877 | ti: TopInfo<'tcx>, |
e1599b0c XL |
878 | ) -> Ty<'tcx> { |
879 | let tcx = self.tcx; | |
880 | ||
881 | // We have already resolved the path. | |
882 | let (res, opt_ty, segments) = path_resolution; | |
883 | match res { | |
884 | Res::Err => { | |
487cf647 FG |
885 | let e = tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted"); |
886 | self.set_tainted_by_errors(e); | |
9ffffee4 | 887 | return tcx.ty_error(e); |
e1599b0c | 888 | } |
487cf647 FG |
889 | Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => { |
890 | let expected = "unit struct, unit variant or constant"; | |
891 | let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, "E0533", expected); | |
9ffffee4 | 892 | return tcx.ty_error(e); |
e1599b0c | 893 | } |
ba9703b0 XL |
894 | Res::SelfCtor(..) |
895 | | Res::Def( | |
896 | DefKind::Ctor(_, CtorKind::Const) | |
897 | | DefKind::Const | |
898 | | DefKind::AssocConst | |
899 | | DefKind::ConstParam, | |
900 | _, | |
901 | ) => {} // OK | |
dfeec247 | 902 | _ => bug!("unexpected pattern resolution: {:?}", res), |
e1599b0c XL |
903 | } |
904 | ||
905 | // Type-check the path. | |
74b04a01 XL |
906 | let (pat_ty, pat_res) = |
907 | self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id); | |
908 | if let Some(err) = | |
909 | self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty) | |
910 | { | |
064997fb | 911 | self.emit_bad_pat_path(err, pat, res, pat_res, pat_ty, segments); |
74b04a01 | 912 | } |
e1599b0c XL |
913 | pat_ty |
914 | } | |
915 | ||
1b1a35ee XL |
916 | fn maybe_suggest_range_literal( |
917 | &self, | |
5e7ed085 | 918 | e: &mut Diagnostic, |
1b1a35ee XL |
919 | opt_def_id: Option<hir::def_id::DefId>, |
920 | ident: Ident, | |
921 | ) -> bool { | |
922 | match opt_def_id { | |
923 | Some(def_id) => match self.tcx.hir().get_if_local(def_id) { | |
924 | Some(hir::Node::Item(hir::Item { | |
925 | kind: hir::ItemKind::Const(_, body_id), .. | |
926 | })) => match self.tcx.hir().get(body_id.hir_id) { | |
927 | hir::Node::Expr(expr) => { | |
928 | if hir::is_range_literal(expr) { | |
929 | let span = self.tcx.hir().span(body_id.hir_id); | |
930 | if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) { | |
931 | e.span_suggestion_verbose( | |
932 | ident.span, | |
933 | "you may want to move the range into the match block", | |
934 | snip, | |
935 | Applicability::MachineApplicable, | |
936 | ); | |
937 | return true; | |
938 | } | |
939 | } | |
940 | } | |
941 | _ => (), | |
942 | }, | |
943 | _ => (), | |
944 | }, | |
945 | _ => (), | |
946 | } | |
947 | false | |
948 | } | |
949 | ||
064997fb | 950 | fn emit_bad_pat_path( |
74b04a01 | 951 | &self, |
5e7ed085 | 952 | mut e: DiagnosticBuilder<'_, ErrorGuaranteed>, |
064997fb | 953 | pat: &hir::Pat<'tcx>, |
74b04a01 XL |
954 | res: Res, |
955 | pat_res: Res, | |
1b1a35ee | 956 | pat_ty: Ty<'tcx>, |
064997fb | 957 | segments: &'tcx [hir::PathSegment<'tcx>], |
74b04a01 | 958 | ) { |
064997fb | 959 | let pat_span = pat.span; |
74b04a01 XL |
960 | if let Some(span) = self.tcx.hir().res_span(pat_res) { |
961 | e.span_label(span, &format!("{} defined here", res.descr())); | |
962 | if let [hir::PathSegment { ident, .. }] = &*segments { | |
963 | e.span_label( | |
964 | pat_span, | |
965 | &format!( | |
966 | "`{}` is interpreted as {} {}, not a new binding", | |
967 | ident, | |
968 | res.article(), | |
969 | res.descr(), | |
970 | ), | |
971 | ); | |
9c376795 | 972 | match self.tcx.hir().get_parent(pat.hir_id) { |
f2b60f7d | 973 | hir::Node::PatField(..) => { |
ba9703b0 XL |
974 | e.span_suggestion_verbose( |
975 | ident.span.shrink_to_hi(), | |
976 | "bind the struct field to a different name instead", | |
977 | format!(": other_{}", ident.as_str().to_lowercase()), | |
978 | Applicability::HasPlaceholders, | |
979 | ); | |
980 | } | |
981 | _ => { | |
1b1a35ee XL |
982 | let (type_def_id, item_def_id) = match pat_ty.kind() { |
983 | Adt(def, _) => match res { | |
5e7ed085 | 984 | Res::Def(DefKind::Const, def_id) => (Some(def.did()), Some(def_id)), |
1b1a35ee XL |
985 | _ => (None, None), |
986 | }, | |
987 | _ => (None, None), | |
988 | }; | |
989 | ||
990 | let ranges = &[ | |
991 | self.tcx.lang_items().range_struct(), | |
992 | self.tcx.lang_items().range_from_struct(), | |
993 | self.tcx.lang_items().range_to_struct(), | |
994 | self.tcx.lang_items().range_full_struct(), | |
995 | self.tcx.lang_items().range_inclusive_struct(), | |
996 | self.tcx.lang_items().range_to_inclusive_struct(), | |
997 | ]; | |
998 | if type_def_id != None && ranges.contains(&type_def_id) { | |
999 | if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) { | |
1000 | let msg = "constants only support matching by type, \ | |
1001 | if you meant to match against a range of values, \ | |
1002 | consider using a range pattern like `min ..= max` in the match block"; | |
1003 | e.note(msg); | |
1004 | } | |
1005 | } else { | |
1006 | let msg = "introduce a new binding instead"; | |
1007 | let sugg = format!("other_{}", ident.as_str().to_lowercase()); | |
1008 | e.span_suggestion( | |
1009 | ident.span, | |
1010 | msg, | |
1011 | sugg, | |
1012 | Applicability::HasPlaceholders, | |
1013 | ); | |
1014 | } | |
ba9703b0 | 1015 | } |
74b04a01 | 1016 | }; |
74b04a01 XL |
1017 | } |
1018 | } | |
1019 | e.emit(); | |
1020 | } | |
1021 | ||
e1599b0c XL |
1022 | fn check_pat_tuple_struct( |
1023 | &self, | |
74b04a01 | 1024 | pat: &'tcx Pat<'tcx>, |
cdc7bbd5 | 1025 | qpath: &'tcx hir::QPath<'tcx>, |
136023e0 | 1026 | subpats: &'tcx [Pat<'tcx>], |
f2b60f7d | 1027 | ddpos: hir::DotDotPos, |
e1599b0c XL |
1028 | expected: Ty<'tcx>, |
1029 | def_bm: BindingMode, | |
dfeec247 | 1030 | ti: TopInfo<'tcx>, |
e1599b0c XL |
1031 | ) -> Ty<'tcx> { |
1032 | let tcx = self.tcx; | |
487cf647 | 1033 | let on_error = |e| { |
e1599b0c | 1034 | for pat in subpats { |
9ffffee4 | 1035 | self.check_pat(pat, tcx.ty_error(e), def_bm, ti); |
e1599b0c XL |
1036 | } |
1037 | }; | |
1038 | let report_unexpected_res = |res: Res| { | |
487cf647 FG |
1039 | let expected = "tuple struct or tuple variant"; |
1040 | let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, "E0164", expected); | |
1041 | on_error(e); | |
1042 | e | |
e1599b0c XL |
1043 | }; |
1044 | ||
1045 | // Resolve the path and check the definition for errors. | |
136023e0 XL |
1046 | let (res, opt_ty, segments) = |
1047 | self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span); | |
e1599b0c | 1048 | if res == Res::Err { |
9c376795 | 1049 | let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted"); |
487cf647 FG |
1050 | self.set_tainted_by_errors(e); |
1051 | on_error(e); | |
9ffffee4 | 1052 | return tcx.ty_error(e); |
e1599b0c XL |
1053 | } |
1054 | ||
1055 | // Type-check the path. | |
dfeec247 XL |
1056 | let (pat_ty, res) = |
1057 | self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id); | |
e1599b0c | 1058 | if !pat_ty.is_fn() { |
487cf647 | 1059 | let e = report_unexpected_res(res); |
9ffffee4 | 1060 | return tcx.ty_error(e); |
e1599b0c XL |
1061 | } |
1062 | ||
1063 | let variant = match res { | |
1064 | Res::Err => { | |
487cf647 FG |
1065 | let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted"); |
1066 | self.set_tainted_by_errors(e); | |
1067 | on_error(e); | |
9ffffee4 | 1068 | return tcx.ty_error(e); |
e1599b0c | 1069 | } |
ba9703b0 | 1070 | Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => { |
487cf647 | 1071 | let e = report_unexpected_res(res); |
9ffffee4 | 1072 | return tcx.ty_error(e); |
e1599b0c | 1073 | } |
dfeec247 XL |
1074 | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res), |
1075 | _ => bug!("unexpected pattern resolution: {:?}", res), | |
e1599b0c XL |
1076 | }; |
1077 | ||
1078 | // Replace constructor type with constructed type for tuple struct patterns. | |
1079 | let pat_ty = pat_ty.fn_sig(tcx).output(); | |
1080 | let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); | |
1081 | ||
e74abb32 | 1082 | // Type-check the tuple struct pattern against the expected type. |
dfeec247 | 1083 | let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, ti); |
f9f354fc XL |
1084 | let had_err = if let Some(mut err) = diag { |
1085 | err.emit(); | |
1086 | true | |
1087 | } else { | |
1088 | false | |
1089 | }; | |
e1599b0c XL |
1090 | |
1091 | // Type-check subpatterns. | |
1092 | if subpats.len() == variant.fields.len() | |
f2b60f7d | 1093 | || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some() |
e1599b0c | 1094 | { |
5e7ed085 FG |
1095 | let ty::Adt(_, substs) = pat_ty.kind() else { |
1096 | bug!("unexpected pattern type {:?}", pat_ty); | |
e1599b0c XL |
1097 | }; |
1098 | for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { | |
353b0b11 FG |
1099 | let field = &variant.fields[FieldIdx::from_usize(i)]; |
1100 | let field_ty = self.field_ty(subpat.span, field, substs); | |
064997fb | 1101 | self.check_pat(subpat, field_ty, def_bm, ti); |
e1599b0c | 1102 | |
17df50a5 | 1103 | self.tcx.check_stability( |
353b0b11 | 1104 | variant.fields[FieldIdx::from_usize(i)].did, |
17df50a5 XL |
1105 | Some(pat.hir_id), |
1106 | subpat.span, | |
1107 | None, | |
1108 | ); | |
e1599b0c XL |
1109 | } |
1110 | } else { | |
1111 | // Pattern has wrong number of fields. | |
353b0b11 FG |
1112 | let e = |
1113 | self.e0023(pat.span, res, qpath, subpats, &variant.fields.raw, expected, had_err); | |
487cf647 | 1114 | on_error(e); |
9ffffee4 | 1115 | return tcx.ty_error(e); |
e1599b0c XL |
1116 | } |
1117 | pat_ty | |
1118 | } | |
1119 | ||
1120 | fn e0023( | |
1121 | &self, | |
1122 | pat_span: Span, | |
1123 | res: Res, | |
dfeec247 | 1124 | qpath: &hir::QPath<'_>, |
136023e0 | 1125 | subpats: &'tcx [Pat<'tcx>], |
e74abb32 XL |
1126 | fields: &'tcx [ty::FieldDef], |
1127 | expected: Ty<'tcx>, | |
1128 | had_err: bool, | |
487cf647 | 1129 | ) -> ErrorGuaranteed { |
60c5eb7d XL |
1130 | let subpats_ending = pluralize!(subpats.len()); |
1131 | let fields_ending = pluralize!(fields.len()); | |
94222f64 XL |
1132 | |
1133 | let subpat_spans = if subpats.is_empty() { | |
1134 | vec![pat_span] | |
1135 | } else { | |
1136 | subpats.iter().map(|p| p.span).collect() | |
1137 | }; | |
1138 | let last_subpat_span = *subpat_spans.last().unwrap(); | |
e1599b0c | 1139 | let res_span = self.tcx.def_span(res.def_id()); |
94222f64 XL |
1140 | let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span); |
1141 | let field_def_spans = if fields.is_empty() { | |
1142 | vec![res_span] | |
1143 | } else { | |
5099ac24 | 1144 | fields.iter().map(|f| f.ident(self.tcx).span).collect() |
94222f64 XL |
1145 | }; |
1146 | let last_field_def_span = *field_def_spans.last().unwrap(); | |
1147 | ||
e1599b0c XL |
1148 | let mut err = struct_span_err!( |
1149 | self.tcx.sess, | |
94222f64 | 1150 | MultiSpan::from_spans(subpat_spans), |
e1599b0c XL |
1151 | E0023, |
1152 | "this pattern has {} field{}, but the corresponding {} has {} field{}", | |
1153 | subpats.len(), | |
1154 | subpats_ending, | |
1155 | res.descr(), | |
1156 | fields.len(), | |
1157 | fields_ending, | |
1158 | ); | |
dfeec247 | 1159 | err.span_label( |
94222f64 XL |
1160 | last_subpat_span, |
1161 | &format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()), | |
1162 | ); | |
1163 | if self.tcx.sess.source_map().is_multiline(qpath.span().between(last_subpat_span)) { | |
1164 | err.span_label(qpath.span(), ""); | |
1165 | } | |
1166 | if self.tcx.sess.source_map().is_multiline(def_ident_span.between(last_field_def_span)) { | |
1167 | err.span_label(def_ident_span, format!("{} defined here", res.descr())); | |
1168 | } | |
1169 | for span in &field_def_spans[..field_def_spans.len() - 1] { | |
1170 | err.span_label(*span, ""); | |
1171 | } | |
1172 | err.span_label( | |
1173 | last_field_def_span, | |
1174 | &format!("{} has {} field{}", res.descr(), fields.len(), fields_ending), | |
1175 | ); | |
e1599b0c XL |
1176 | |
1177 | // Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`. | |
1178 | // More generally, the expected type wants a tuple variant with one field of an | |
1179 | // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern | |
1180 | // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`. | |
5869c6ff | 1181 | let missing_parentheses = match (&expected.kind(), fields, had_err) { |
74b04a01 | 1182 | // #67037: only do this if we could successfully type-check the expected type against |
e74abb32 XL |
1183 | // the tuple struct pattern. Otherwise the substs could get out of range on e.g., |
1184 | // `let P() = U;` where `P != U` with `struct P<T>(T);`. | |
1185 | (ty::Adt(_, substs), [field], false) => { | |
1186 | let field_ty = self.field_ty(pat_span, field, substs); | |
1b1a35ee | 1187 | match field_ty.kind() { |
5e7ed085 | 1188 | ty::Tuple(fields) => fields.len() == subpats.len(), |
e1599b0c XL |
1189 | _ => false, |
1190 | } | |
1191 | } | |
1192 | _ => false, | |
1193 | }; | |
5869c6ff | 1194 | if missing_parentheses { |
e1599b0c XL |
1195 | let (left, right) = match subpats { |
1196 | // This is the zero case; we aim to get the "hi" part of the `QPath`'s | |
1197 | // span as the "lo" and then the "hi" part of the pattern's span as the "hi". | |
1198 | // This looks like: | |
1199 | // | |
5869c6ff | 1200 | // help: missing parentheses |
e1599b0c XL |
1201 | // | |
1202 | // L | let A(()) = A(()); | |
1203 | // | ^ ^ | |
3dfed10e | 1204 | [] => (qpath.span().shrink_to_hi(), pat_span), |
e1599b0c XL |
1205 | // Easy case. Just take the "lo" of the first sub-pattern and the "hi" of the |
1206 | // last sub-pattern. In the case of `A(x)` the first and last may coincide. | |
1207 | // This looks like: | |
1208 | // | |
5869c6ff | 1209 | // help: missing parentheses |
e1599b0c XL |
1210 | // | |
1211 | // L | let A((x, y)) = A((1, 2)); | |
1212 | // | ^ ^ | |
1213 | [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span), | |
1214 | }; | |
1215 | err.multipart_suggestion( | |
5869c6ff | 1216 | "missing parentheses", |
dfeec247 | 1217 | vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())], |
e1599b0c XL |
1218 | Applicability::MachineApplicable, |
1219 | ); | |
5869c6ff XL |
1220 | } else if fields.len() > subpats.len() && pat_span != DUMMY_SP { |
1221 | let after_fields_span = pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi(); | |
1222 | let all_fields_span = match subpats { | |
1223 | [] => after_fields_span, | |
1224 | [field] => field.span, | |
1225 | [first, .., last] => first.span.to(last.span), | |
1226 | }; | |
1227 | ||
1228 | // Check if all the fields in the pattern are wildcards. | |
1229 | let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild)); | |
1230 | let first_tail_wildcard = | |
1231 | subpats.iter().enumerate().fold(None, |acc, (pos, pat)| match (acc, &pat.kind) { | |
1232 | (None, PatKind::Wild) => Some(pos), | |
1233 | (Some(_), PatKind::Wild) => acc, | |
1234 | _ => None, | |
1235 | }); | |
1236 | let tail_span = match first_tail_wildcard { | |
1237 | None => after_fields_span, | |
1238 | Some(0) => subpats[0].span.to(after_fields_span), | |
1239 | Some(pos) => subpats[pos - 1].span.shrink_to_hi().to(after_fields_span), | |
1240 | }; | |
1241 | ||
1242 | // FIXME: heuristic-based suggestion to check current types for where to add `_`. | |
1243 | let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", "); | |
1244 | if !subpats.is_empty() { | |
1245 | wildcard_sugg = String::from(", ") + &wildcard_sugg; | |
1246 | } | |
1247 | ||
1248 | err.span_suggestion_verbose( | |
1249 | after_fields_span, | |
1250 | "use `_` to explicitly ignore each field", | |
1251 | wildcard_sugg, | |
1252 | Applicability::MaybeIncorrect, | |
1253 | ); | |
1254 | ||
1255 | // Only suggest `..` if more than one field is missing | |
1256 | // or the pattern consists of all wildcards. | |
1257 | if fields.len() - subpats.len() > 1 || all_wildcards { | |
1258 | if subpats.is_empty() || all_wildcards { | |
1259 | err.span_suggestion_verbose( | |
1260 | all_fields_span, | |
1261 | "use `..` to ignore all fields", | |
923072b8 | 1262 | "..", |
5869c6ff XL |
1263 | Applicability::MaybeIncorrect, |
1264 | ); | |
1265 | } else { | |
1266 | err.span_suggestion_verbose( | |
1267 | tail_span, | |
1268 | "use `..` to ignore the rest of the fields", | |
923072b8 | 1269 | ", ..", |
5869c6ff XL |
1270 | Applicability::MaybeIncorrect, |
1271 | ); | |
1272 | } | |
1273 | } | |
e1599b0c XL |
1274 | } |
1275 | ||
487cf647 | 1276 | err.emit() |
e1599b0c XL |
1277 | } |
1278 | ||
1279 | fn check_pat_tuple( | |
1280 | &self, | |
1281 | span: Span, | |
136023e0 | 1282 | elements: &'tcx [Pat<'tcx>], |
f2b60f7d | 1283 | ddpos: hir::DotDotPos, |
e1599b0c XL |
1284 | expected: Ty<'tcx>, |
1285 | def_bm: BindingMode, | |
dfeec247 | 1286 | ti: TopInfo<'tcx>, |
e1599b0c XL |
1287 | ) -> Ty<'tcx> { |
1288 | let tcx = self.tcx; | |
1289 | let mut expected_len = elements.len(); | |
f2b60f7d | 1290 | if ddpos.as_opt_usize().is_some() { |
e1599b0c | 1291 | // Require known type only when `..` is present. |
c295e0f8 | 1292 | if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() { |
e1599b0c XL |
1293 | expected_len = tys.len(); |
1294 | } | |
1295 | } | |
1296 | let max_len = cmp::max(expected_len, elements.len()); | |
1297 | ||
1298 | let element_tys_iter = (0..max_len).map(|_| { | |
5e7ed085 | 1299 | self.next_ty_var( |
e1599b0c XL |
1300 | // FIXME: `MiscVariable` for now -- obtaining the span and name information |
1301 | // from all tuple elements isn't trivial. | |
dfeec247 | 1302 | TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }, |
5e7ed085 | 1303 | ) |
e1599b0c | 1304 | }); |
9ffffee4 FG |
1305 | let element_tys = tcx.mk_type_list_from_iter(element_tys_iter); |
1306 | let pat_ty = tcx.mk_tup(element_tys); | |
74b04a01 | 1307 | if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) { |
487cf647 | 1308 | let reported = err.emit(); |
e1599b0c XL |
1309 | // Walk subpatterns with an expected type of `err` in this case to silence |
1310 | // further errors being emitted when using the bindings. #50333 | |
9ffffee4 | 1311 | let element_tys_iter = (0..max_len).map(|_| tcx.ty_error(reported)); |
e1599b0c | 1312 | for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { |
9ffffee4 | 1313 | self.check_pat(elem, tcx.ty_error(reported), def_bm, ti); |
e1599b0c | 1314 | } |
9ffffee4 | 1315 | tcx.mk_tup_from_iter(element_tys_iter) |
e1599b0c XL |
1316 | } else { |
1317 | for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { | |
5e7ed085 | 1318 | self.check_pat(elem, element_tys[i], def_bm, ti); |
e1599b0c XL |
1319 | } |
1320 | pat_ty | |
1321 | } | |
1322 | } | |
1323 | ||
1324 | fn check_struct_pat_fields( | |
1325 | &self, | |
1326 | adt_ty: Ty<'tcx>, | |
74b04a01 | 1327 | pat: &'tcx Pat<'tcx>, |
e1599b0c | 1328 | variant: &'tcx ty::VariantDef, |
6a06907d | 1329 | fields: &'tcx [hir::PatField<'tcx>], |
c295e0f8 | 1330 | has_rest_pat: bool, |
e1599b0c | 1331 | def_bm: BindingMode, |
dfeec247 | 1332 | ti: TopInfo<'tcx>, |
e1599b0c XL |
1333 | ) -> bool { |
1334 | let tcx = self.tcx; | |
1335 | ||
5e7ed085 FG |
1336 | let ty::Adt(adt, substs) = adt_ty.kind() else { |
1337 | span_bug!(pat.span, "struct pattern is not an ADT"); | |
e1599b0c | 1338 | }; |
e1599b0c XL |
1339 | |
1340 | // Index the struct fields' types. | |
dfeec247 XL |
1341 | let field_map = variant |
1342 | .fields | |
353b0b11 | 1343 | .iter_enumerated() |
5099ac24 | 1344 | .map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field))) |
e1599b0c XL |
1345 | .collect::<FxHashMap<_, _>>(); |
1346 | ||
1347 | // Keep track of which fields have already appeared in the pattern. | |
1348 | let mut used_fields = FxHashMap::default(); | |
1349 | let mut no_field_errors = true; | |
1350 | ||
1351 | let mut inexistent_fields = vec![]; | |
1352 | // Typecheck each field. | |
1353 | for field in fields { | |
1354 | let span = field.span; | |
1355 | let ident = tcx.adjust_ident(field.ident, variant.def_id); | |
1356 | let field_ty = match used_fields.entry(ident) { | |
1357 | Occupied(occupied) => { | |
e1599b0c | 1358 | no_field_errors = false; |
9ffffee4 FG |
1359 | let guar = self.error_field_already_bound(span, field.ident, *occupied.get()); |
1360 | tcx.ty_error(guar) | |
e1599b0c XL |
1361 | } |
1362 | Vacant(vacant) => { | |
1363 | vacant.insert(span); | |
dfeec247 XL |
1364 | field_map |
1365 | .get(&ident) | |
e1599b0c XL |
1366 | .map(|(i, f)| { |
1367 | self.write_field_index(field.hir_id, *i); | |
17df50a5 | 1368 | self.tcx.check_stability(f.did, Some(pat.hir_id), span, None); |
e1599b0c XL |
1369 | self.field_ty(span, f, substs) |
1370 | }) | |
1371 | .unwrap_or_else(|| { | |
5e7ed085 | 1372 | inexistent_fields.push(field); |
e1599b0c | 1373 | no_field_errors = false; |
9ffffee4 | 1374 | tcx.ty_error_misc() |
e1599b0c XL |
1375 | }) |
1376 | } | |
1377 | }; | |
1378 | ||
064997fb | 1379 | self.check_pat(field.pat, field_ty, def_bm, ti); |
e1599b0c XL |
1380 | } |
1381 | ||
dfeec247 XL |
1382 | let mut unmentioned_fields = variant |
1383 | .fields | |
1384 | .iter() | |
5099ac24 | 1385 | .map(|field| (field, field.ident(self.tcx).normalize_to_macros_2_0())) |
c295e0f8 | 1386 | .filter(|(_, ident)| !used_fields.contains_key(ident)) |
dfeec247 | 1387 | .collect::<Vec<_>>(); |
e1599b0c | 1388 | |
5e7ed085 FG |
1389 | let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered()) |
1390 | && !inexistent_fields.iter().any(|field| field.ident.name == kw::Underscore) | |
1391 | { | |
3dfed10e | 1392 | Some(self.error_inexistent_fields( |
ba9703b0 | 1393 | adt.variant_descr(), |
e1599b0c XL |
1394 | &inexistent_fields, |
1395 | &mut unmentioned_fields, | |
dfeec247 | 1396 | variant, |
5e7ed085 | 1397 | substs, |
3dfed10e XL |
1398 | )) |
1399 | } else { | |
1400 | None | |
1401 | }; | |
e1599b0c XL |
1402 | |
1403 | // Require `..` if struct has non_exhaustive attribute. | |
5e7ed085 | 1404 | let non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did().is_local(); |
c295e0f8 | 1405 | if non_exhaustive && !has_rest_pat { |
ba9703b0 | 1406 | self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty()); |
e1599b0c XL |
1407 | } |
1408 | ||
3dfed10e | 1409 | let mut unmentioned_err = None; |
fc512014 | 1410 | // Report an error if an incorrect number of fields was specified. |
ba9703b0 | 1411 | if adt.is_union() { |
e1599b0c | 1412 | if fields.len() != 1 { |
dfeec247 | 1413 | tcx.sess |
74b04a01 | 1414 | .struct_span_err(pat.span, "union patterns should have exactly one field") |
dfeec247 | 1415 | .emit(); |
e1599b0c | 1416 | } |
c295e0f8 | 1417 | if has_rest_pat { |
74b04a01 | 1418 | tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit(); |
e1599b0c | 1419 | } |
c295e0f8 | 1420 | } else if !unmentioned_fields.is_empty() { |
94222f64 XL |
1421 | let accessible_unmentioned_fields: Vec<_> = unmentioned_fields |
1422 | .iter() | |
1423 | .copied() | |
1424 | .filter(|(field, _)| { | |
f2b60f7d | 1425 | field.vis.is_accessible_from(tcx.parent_module(pat.hir_id), tcx) |
5e7ed085 FG |
1426 | && !matches!( |
1427 | tcx.eval_stability(field.did, None, DUMMY_SP, None), | |
1428 | EvalResult::Deny { .. } | |
1429 | ) | |
1430 | // We only want to report the error if it is hidden and not local | |
1431 | && !(tcx.is_doc_hidden(field.did) && !field.did.is_local()) | |
94222f64 XL |
1432 | }) |
1433 | .collect(); | |
1b1a35ee | 1434 | |
c295e0f8 XL |
1435 | if !has_rest_pat { |
1436 | if accessible_unmentioned_fields.is_empty() { | |
1437 | unmentioned_err = Some(self.error_no_accessible_fields(pat, fields)); | |
1438 | } else { | |
1439 | unmentioned_err = Some(self.error_unmentioned_fields( | |
1440 | pat, | |
1441 | &accessible_unmentioned_fields, | |
1442 | accessible_unmentioned_fields.len() != unmentioned_fields.len(), | |
1443 | fields, | |
1444 | )); | |
1445 | } | |
1446 | } else if non_exhaustive && !accessible_unmentioned_fields.is_empty() { | |
1447 | self.lint_non_exhaustive_omitted_patterns( | |
94222f64 XL |
1448 | pat, |
1449 | &accessible_unmentioned_fields, | |
c295e0f8 XL |
1450 | adt_ty, |
1451 | ) | |
1b1a35ee | 1452 | } |
3dfed10e XL |
1453 | } |
1454 | match (inexistent_fields_err, unmentioned_err) { | |
1455 | (Some(mut i), Some(mut u)) => { | |
1456 | if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { | |
5e7ed085 | 1457 | // We don't want to show the nonexistent fields error when this was |
3dfed10e XL |
1458 | // `Foo { a, b }` when it should have been `Foo(a, b)`. |
1459 | i.delay_as_bug(); | |
1460 | u.delay_as_bug(); | |
1461 | e.emit(); | |
1462 | } else { | |
1463 | i.emit(); | |
1464 | u.emit(); | |
1465 | } | |
1466 | } | |
6a06907d XL |
1467 | (None, Some(mut u)) => { |
1468 | if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { | |
1469 | u.delay_as_bug(); | |
1470 | e.emit(); | |
1471 | } else { | |
1472 | u.emit(); | |
1473 | } | |
1474 | } | |
1475 | (Some(mut err), None) => { | |
3dfed10e XL |
1476 | err.emit(); |
1477 | } | |
94222f64 XL |
1478 | (None, None) if let Some(mut err) = |
1479 | self.error_tuple_variant_index_shorthand(variant, pat, fields) => | |
1480 | { | |
1481 | err.emit(); | |
6a06907d | 1482 | } |
94222f64 | 1483 | (None, None) => {} |
e1599b0c XL |
1484 | } |
1485 | no_field_errors | |
1486 | } | |
1487 | ||
6a06907d XL |
1488 | fn error_tuple_variant_index_shorthand( |
1489 | &self, | |
1490 | variant: &VariantDef, | |
1491 | pat: &'_ Pat<'_>, | |
1492 | fields: &[hir::PatField<'_>], | |
5e7ed085 | 1493 | ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> { |
6a06907d XL |
1494 | // if this is a tuple struct, then all field names will be numbers |
1495 | // so if any fields in a struct pattern use shorthand syntax, they will | |
1496 | // be invalid identifiers (for example, Foo { 0, 1 }). | |
487cf647 FG |
1497 | if let (Some(CtorKind::Fn), PatKind::Struct(qpath, field_patterns, ..)) = |
1498 | (variant.ctor_kind(), &pat.kind) | |
6a06907d XL |
1499 | { |
1500 | let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand); | |
1501 | if has_shorthand_field_name { | |
1502 | let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { | |
1503 | s.print_qpath(qpath, false) | |
1504 | }); | |
1505 | let mut err = struct_span_err!( | |
1506 | self.tcx.sess, | |
1507 | pat.span, | |
1508 | E0769, | |
04454e1e | 1509 | "tuple variant `{path}` written as struct variant", |
6a06907d XL |
1510 | ); |
1511 | err.span_suggestion_verbose( | |
1512 | qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()), | |
1513 | "use the tuple variant pattern syntax instead", | |
1514 | format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)), | |
1515 | Applicability::MaybeIncorrect, | |
1516 | ); | |
1517 | return Some(err); | |
1518 | } | |
1519 | } | |
1520 | None | |
1521 | } | |
1522 | ||
ba9703b0 XL |
1523 | fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) { |
1524 | let sess = self.tcx.sess; | |
1525 | let sm = sess.source_map(); | |
1526 | let sp_brace = sm.end_point(pat.span); | |
1527 | let sp_comma = sm.end_point(pat.span.with_hi(sp_brace.hi())); | |
1528 | let sugg = if no_fields || sp_brace != sp_comma { ".. }" } else { ", .. }" }; | |
1529 | ||
1530 | let mut err = struct_span_err!( | |
1531 | sess, | |
1532 | pat.span, | |
1533 | E0638, | |
04454e1e | 1534 | "`..` required with {descr} marked as non-exhaustive", |
ba9703b0 XL |
1535 | ); |
1536 | err.span_suggestion_verbose( | |
1537 | sp_comma, | |
1538 | "add `..` at the end of the field list to ignore all other fields", | |
923072b8 | 1539 | sugg, |
ba9703b0 XL |
1540 | Applicability::MachineApplicable, |
1541 | ); | |
1542 | err.emit(); | |
1543 | } | |
1544 | ||
9ffffee4 FG |
1545 | fn error_field_already_bound( |
1546 | &self, | |
1547 | span: Span, | |
1548 | ident: Ident, | |
1549 | other_field: Span, | |
1550 | ) -> ErrorGuaranteed { | |
e1599b0c | 1551 | struct_span_err!( |
dfeec247 XL |
1552 | self.tcx.sess, |
1553 | span, | |
1554 | E0025, | |
e1599b0c XL |
1555 | "field `{}` bound multiple times in the pattern", |
1556 | ident | |
1557 | ) | |
04454e1e FG |
1558 | .span_label(span, format!("multiple uses of `{ident}` in pattern")) |
1559 | .span_label(other_field, format!("first use of `{ident}`")) | |
9ffffee4 | 1560 | .emit() |
e1599b0c XL |
1561 | } |
1562 | ||
1563 | fn error_inexistent_fields( | |
1564 | &self, | |
1565 | kind_name: &str, | |
5e7ed085 FG |
1566 | inexistent_fields: &[&hir::PatField<'tcx>], |
1567 | unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>, | |
e1599b0c | 1568 | variant: &ty::VariantDef, |
5e7ed085 FG |
1569 | substs: &'tcx ty::List<ty::subst::GenericArg<'tcx>>, |
1570 | ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { | |
e1599b0c XL |
1571 | let tcx = self.tcx; |
1572 | let (field_names, t, plural) = if inexistent_fields.len() == 1 { | |
5e7ed085 | 1573 | (format!("a field named `{}`", inexistent_fields[0].ident), "this", "") |
e1599b0c | 1574 | } else { |
dfeec247 XL |
1575 | ( |
1576 | format!( | |
1577 | "fields named {}", | |
1578 | inexistent_fields | |
1579 | .iter() | |
5e7ed085 | 1580 | .map(|field| format!("`{}`", field.ident)) |
e1599b0c | 1581 | .collect::<Vec<String>>() |
dfeec247 XL |
1582 | .join(", ") |
1583 | ), | |
1584 | "these", | |
1585 | "s", | |
1586 | ) | |
e1599b0c | 1587 | }; |
5e7ed085 | 1588 | let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>(); |
dfeec247 XL |
1589 | let mut err = struct_span_err!( |
1590 | tcx.sess, | |
1591 | spans, | |
1592 | E0026, | |
1593 | "{} `{}` does not have {}", | |
1594 | kind_name, | |
1595 | tcx.def_path_str(variant.def_id), | |
1596 | field_names | |
1597 | ); | |
5e7ed085 | 1598 | if let Some(pat_field) = inexistent_fields.last() { |
dfeec247 | 1599 | err.span_label( |
5e7ed085 | 1600 | pat_field.ident.span, |
dfeec247 XL |
1601 | format!( |
1602 | "{} `{}` does not have {} field{}", | |
1603 | kind_name, | |
1604 | tcx.def_path_str(variant.def_id), | |
1605 | t, | |
1606 | plural | |
1607 | ), | |
1608 | ); | |
c295e0f8 XL |
1609 | |
1610 | if unmentioned_fields.len() == 1 { | |
fc512014 XL |
1611 | let input = |
1612 | unmentioned_fields.iter().map(|(_, field)| field.name).collect::<Vec<_>>(); | |
5e7ed085 | 1613 | let suggested_name = find_best_match_for_name(&input, pat_field.ident.name, None); |
e1599b0c XL |
1614 | if let Some(suggested_name) = suggested_name { |
1615 | err.span_suggestion( | |
5e7ed085 | 1616 | pat_field.ident.span, |
e1599b0c | 1617 | "a field with a similar name exists", |
923072b8 | 1618 | suggested_name, |
e1599b0c XL |
1619 | Applicability::MaybeIncorrect, |
1620 | ); | |
1621 | ||
3dfed10e XL |
1622 | // When we have a tuple struct used with struct we don't want to suggest using |
1623 | // the (valid) struct syntax with numeric field names. Instead we want to | |
1624 | // suggest the expected syntax. We infer that this is the case by parsing the | |
1625 | // `Ident` into an unsized integer. The suggestion will be emitted elsewhere in | |
1626 | // `smart_resolve_context_dependent_help`. | |
1627 | if suggested_name.to_ident_string().parse::<usize>().is_err() { | |
1628 | // We don't want to throw `E0027` in case we have thrown `E0026` for them. | |
1b1a35ee | 1629 | unmentioned_fields.retain(|&(_, x)| x.name != suggested_name); |
3dfed10e | 1630 | } |
c295e0f8 | 1631 | } else if inexistent_fields.len() == 1 { |
5e7ed085 FG |
1632 | match pat_field.pat.kind { |
1633 | PatKind::Lit(expr) | |
1634 | if !self.can_coerce( | |
1635 | self.typeck_results.borrow().expr_ty(expr), | |
1636 | self.field_ty( | |
1637 | unmentioned_fields[0].1.span, | |
1638 | unmentioned_fields[0].0, | |
1639 | substs, | |
1640 | ), | |
1641 | ) => {} | |
1642 | _ => { | |
1643 | let unmentioned_field = unmentioned_fields[0].1.name; | |
1644 | err.span_suggestion_short( | |
1645 | pat_field.ident.span, | |
1646 | &format!( | |
1647 | "`{}` has a field named `{}`", | |
1648 | tcx.def_path_str(variant.def_id), | |
1649 | unmentioned_field | |
1650 | ), | |
1651 | unmentioned_field.to_string(), | |
1652 | Applicability::MaybeIncorrect, | |
1653 | ); | |
1654 | } | |
1655 | } | |
e1599b0c XL |
1656 | } |
1657 | } | |
1658 | } | |
1659 | if tcx.sess.teach(&err.get_code().unwrap()) { | |
1660 | err.note( | |
1661 | "This error indicates that a struct pattern attempted to \ | |
3dfed10e XL |
1662 | extract a non-existent field from a struct. Struct fields \ |
1663 | are identified by the name used before the colon : so struct \ | |
1664 | patterns should resemble the declaration of the struct type \ | |
1665 | being matched.\n\n\ | |
1666 | If you are using shorthand field patterns but want to refer \ | |
1667 | to the struct field by a different name, you should rename \ | |
1668 | it explicitly.", | |
e1599b0c XL |
1669 | ); |
1670 | } | |
3dfed10e XL |
1671 | err |
1672 | } | |
1673 | ||
1674 | fn error_tuple_variant_as_struct_pat( | |
1675 | &self, | |
1676 | pat: &Pat<'_>, | |
6a06907d | 1677 | fields: &'tcx [hir::PatField<'tcx>], |
3dfed10e | 1678 | variant: &ty::VariantDef, |
5e7ed085 | 1679 | ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { |
353b0b11 FG |
1680 | if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) = |
1681 | (variant.ctor_kind(), &pat.kind) | |
1682 | { | |
1683 | let is_tuple_struct_match = !pattern_fields.is_empty() | |
1684 | && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number); | |
1685 | if is_tuple_struct_match { | |
1686 | return None; | |
1687 | } | |
1688 | ||
3dfed10e XL |
1689 | let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { |
1690 | s.print_qpath(qpath, false) | |
1691 | }); | |
1692 | let mut err = struct_span_err!( | |
1693 | self.tcx.sess, | |
1694 | pat.span, | |
1695 | E0769, | |
1696 | "tuple variant `{}` written as struct variant", | |
1697 | path | |
1698 | ); | |
1699 | let (sugg, appl) = if fields.len() == variant.fields.len() { | |
1700 | ( | |
6a06907d | 1701 | self.get_suggested_tuple_struct_pattern(fields, variant), |
3dfed10e XL |
1702 | Applicability::MachineApplicable, |
1703 | ) | |
1704 | } else { | |
1705 | ( | |
1706 | variant.fields.iter().map(|_| "_").collect::<Vec<&str>>().join(", "), | |
1707 | Applicability::MaybeIncorrect, | |
1708 | ) | |
1709 | }; | |
6a06907d XL |
1710 | err.span_suggestion_verbose( |
1711 | qpath.span().shrink_to_hi().to(pat.span.shrink_to_hi()), | |
3dfed10e | 1712 | "use the tuple variant pattern syntax instead", |
6a06907d | 1713 | format!("({})", sugg), |
3dfed10e XL |
1714 | appl, |
1715 | ); | |
1716 | return Some(err); | |
1717 | } | |
1718 | None | |
e1599b0c XL |
1719 | } |
1720 | ||
6a06907d XL |
1721 | fn get_suggested_tuple_struct_pattern( |
1722 | &self, | |
1723 | fields: &[hir::PatField<'_>], | |
1724 | variant: &VariantDef, | |
1725 | ) -> String { | |
5099ac24 FG |
1726 | let variant_field_idents = |
1727 | variant.fields.iter().map(|f| f.ident(self.tcx)).collect::<Vec<Ident>>(); | |
6a06907d XL |
1728 | fields |
1729 | .iter() | |
1730 | .map(|field| { | |
1731 | match self.tcx.sess.source_map().span_to_snippet(field.pat.span) { | |
1732 | Ok(f) => { | |
1733 | // Field names are numbers, but numbers | |
1734 | // are not valid identifiers | |
1735 | if variant_field_idents.contains(&field.ident) { | |
1736 | String::from("_") | |
1737 | } else { | |
1738 | f | |
1739 | } | |
1740 | } | |
1741 | Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { | |
1742 | s.print_pat(field.pat) | |
1743 | }), | |
1744 | } | |
1745 | }) | |
1746 | .collect::<Vec<String>>() | |
1747 | .join(", ") | |
1748 | } | |
1749 | ||
1b1a35ee XL |
1750 | /// Returns a diagnostic reporting a struct pattern which is missing an `..` due to |
1751 | /// inaccessible fields. | |
1752 | /// | |
29967ef6 | 1753 | /// ```text |
1b1a35ee XL |
1754 | /// error: pattern requires `..` due to inaccessible fields |
1755 | /// --> src/main.rs:10:9 | |
1756 | /// | | |
1757 | /// LL | let foo::Foo {} = foo::Foo::default(); | |
1758 | /// | ^^^^^^^^^^^ | |
1759 | /// | | |
1760 | /// help: add a `..` | |
1761 | /// | | |
1762 | /// LL | let foo::Foo { .. } = foo::Foo::default(); | |
1763 | /// | ^^^^^^ | |
1764 | /// ``` | |
1765 | fn error_no_accessible_fields( | |
1766 | &self, | |
1767 | pat: &Pat<'_>, | |
6a06907d | 1768 | fields: &'tcx [hir::PatField<'tcx>], |
5e7ed085 | 1769 | ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { |
1b1a35ee XL |
1770 | let mut err = self |
1771 | .tcx | |
1772 | .sess | |
1773 | .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields"); | |
1774 | ||
1775 | if let Some(field) = fields.last() { | |
1776 | err.span_suggestion_verbose( | |
1777 | field.span.shrink_to_hi(), | |
1778 | "ignore the inaccessible and unused fields", | |
923072b8 | 1779 | ", ..", |
1b1a35ee XL |
1780 | Applicability::MachineApplicable, |
1781 | ); | |
1782 | } else { | |
1783 | let qpath_span = if let PatKind::Struct(qpath, ..) = &pat.kind { | |
1784 | qpath.span() | |
1785 | } else { | |
1786 | bug!("`error_no_accessible_fields` called on non-struct pattern"); | |
1787 | }; | |
1788 | ||
1789 | // Shrink the span to exclude the `foo:Foo` in `foo::Foo { }`. | |
1790 | let span = pat.span.with_lo(qpath_span.shrink_to_hi().hi()); | |
1791 | err.span_suggestion_verbose( | |
1792 | span, | |
1793 | "ignore the inaccessible and unused fields", | |
923072b8 | 1794 | " { .. }", |
1b1a35ee XL |
1795 | Applicability::MachineApplicable, |
1796 | ); | |
1797 | } | |
1798 | err | |
1799 | } | |
1800 | ||
c295e0f8 XL |
1801 | /// Report that a pattern for a `#[non_exhaustive]` struct marked with `non_exhaustive_omitted_patterns` |
1802 | /// is not exhaustive enough. | |
1803 | /// | |
1804 | /// Nb: the partner lint for enums lives in `compiler/rustc_mir_build/src/thir/pattern/usefulness.rs`. | |
1805 | fn lint_non_exhaustive_omitted_patterns( | |
1806 | &self, | |
1807 | pat: &Pat<'_>, | |
1808 | unmentioned_fields: &[(&ty::FieldDef, Ident)], | |
1809 | ty: Ty<'tcx>, | |
1810 | ) { | |
1811 | fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String { | |
1812 | const LIMIT: usize = 3; | |
1813 | match witnesses { | |
1814 | [] => bug!(), | |
1815 | [witness] => format!("`{}`", witness), | |
1816 | [head @ .., tail] if head.len() < LIMIT => { | |
1817 | let head: Vec<_> = head.iter().map(<_>::to_string).collect(); | |
1818 | format!("`{}` and `{}`", head.join("`, `"), tail) | |
1819 | } | |
1820 | _ => { | |
1821 | let (head, tail) = witnesses.split_at(LIMIT); | |
1822 | let head: Vec<_> = head.iter().map(<_>::to_string).collect(); | |
1823 | format!("`{}` and {} more", head.join("`, `"), tail.len()) | |
1824 | } | |
1825 | } | |
1826 | } | |
1827 | let joined_patterns = joined_uncovered_patterns( | |
1828 | &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(), | |
1829 | ); | |
1830 | ||
2b03887a | 1831 | self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, "some fields are not explicitly listed", |lint| { |
c295e0f8 | 1832 | lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns)); |
c295e0f8 XL |
1833 | lint.help( |
1834 | "ensure that all fields are mentioned explicitly by adding the suggested fields", | |
1835 | ); | |
1836 | lint.note(&format!( | |
1837 | "the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found", | |
1838 | ty, | |
1839 | )); | |
2b03887a FG |
1840 | |
1841 | lint | |
c295e0f8 XL |
1842 | }); |
1843 | } | |
1844 | ||
1b1a35ee XL |
1845 | /// Returns a diagnostic reporting a struct pattern which does not mention some fields. |
1846 | /// | |
29967ef6 | 1847 | /// ```text |
5869c6ff | 1848 | /// error[E0027]: pattern does not mention field `bar` |
1b1a35ee XL |
1849 | /// --> src/main.rs:15:9 |
1850 | /// | | |
1851 | /// LL | let foo::Foo {} = foo::Foo::new(); | |
5869c6ff | 1852 | /// | ^^^^^^^^^^^ missing field `bar` |
1b1a35ee | 1853 | /// ``` |
e1599b0c XL |
1854 | fn error_unmentioned_fields( |
1855 | &self, | |
3dfed10e | 1856 | pat: &Pat<'_>, |
1b1a35ee | 1857 | unmentioned_fields: &[(&ty::FieldDef, Ident)], |
94222f64 | 1858 | have_inaccessible_fields: bool, |
6a06907d | 1859 | fields: &'tcx [hir::PatField<'tcx>], |
5e7ed085 | 1860 | ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { |
94222f64 | 1861 | let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" }; |
e1599b0c | 1862 | let field_names = if unmentioned_fields.len() == 1 { |
94222f64 | 1863 | format!("field `{}`{}", unmentioned_fields[0].1, inaccessible) |
e1599b0c | 1864 | } else { |
dfeec247 XL |
1865 | let fields = unmentioned_fields |
1866 | .iter() | |
1b1a35ee | 1867 | .map(|(_, name)| format!("`{}`", name)) |
e1599b0c XL |
1868 | .collect::<Vec<String>>() |
1869 | .join(", "); | |
94222f64 | 1870 | format!("fields {}{}", fields, inaccessible) |
e1599b0c | 1871 | }; |
3dfed10e | 1872 | let mut err = struct_span_err!( |
dfeec247 | 1873 | self.tcx.sess, |
3dfed10e | 1874 | pat.span, |
dfeec247 | 1875 | E0027, |
e1599b0c XL |
1876 | "pattern does not mention {}", |
1877 | field_names | |
1878 | ); | |
3dfed10e | 1879 | err.span_label(pat.span, format!("missing {}", field_names)); |
1b1a35ee XL |
1880 | let len = unmentioned_fields.len(); |
1881 | let (prefix, postfix, sp) = match fields { | |
1882 | [] => match &pat.kind { | |
1883 | PatKind::Struct(path, [], false) => { | |
1884 | (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi())) | |
1885 | } | |
1886 | _ => return err, | |
1887 | }, | |
5869c6ff XL |
1888 | [.., field] => { |
1889 | // Account for last field having a trailing comma or parse recovery at the tail of | |
1890 | // the pattern to avoid invalid suggestion (#78511). | |
1891 | let tail = field.span.shrink_to_hi().with_hi(pat.span.hi()); | |
1892 | match &pat.kind { | |
1893 | PatKind::Struct(..) => (", ", " }", tail), | |
1894 | _ => return err, | |
1895 | } | |
1896 | } | |
1b1a35ee XL |
1897 | }; |
1898 | err.span_suggestion( | |
1899 | sp, | |
1900 | &format!( | |
94222f64 | 1901 | "include the missing field{} in the pattern{}", |
5e7ed085 | 1902 | pluralize!(len), |
94222f64 | 1903 | if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" } |
1b1a35ee XL |
1904 | ), |
1905 | format!( | |
94222f64 | 1906 | "{}{}{}{}", |
1b1a35ee XL |
1907 | prefix, |
1908 | unmentioned_fields | |
1909 | .iter() | |
353b0b11 FG |
1910 | .map(|(_, name)| { |
1911 | let field_name = name.to_string(); | |
1912 | if is_number(&field_name) { | |
1913 | format!("{}: _", field_name) | |
1914 | } else { | |
1915 | field_name | |
1916 | } | |
1917 | }) | |
1b1a35ee XL |
1918 | .collect::<Vec<_>>() |
1919 | .join(", "), | |
94222f64 | 1920 | if have_inaccessible_fields { ", .." } else { "" }, |
1b1a35ee XL |
1921 | postfix, |
1922 | ), | |
1923 | Applicability::MachineApplicable, | |
1924 | ); | |
1925 | err.span_suggestion( | |
1926 | sp, | |
1927 | &format!( | |
5e7ed085 FG |
1928 | "if you don't care about {these} missing field{s}, you can explicitly ignore {them}", |
1929 | these = pluralize!("this", len), | |
1930 | s = pluralize!(len), | |
1931 | them = if len == 1 { "it" } else { "them" }, | |
1b1a35ee XL |
1932 | ), |
1933 | format!("{}..{}", prefix, postfix), | |
1934 | Applicability::MachineApplicable, | |
1935 | ); | |
3dfed10e | 1936 | err |
e1599b0c XL |
1937 | } |
1938 | ||
1939 | fn check_pat_box( | |
1940 | &self, | |
1941 | span: Span, | |
dfeec247 | 1942 | inner: &'tcx Pat<'tcx>, |
e1599b0c XL |
1943 | expected: Ty<'tcx>, |
1944 | def_bm: BindingMode, | |
dfeec247 | 1945 | ti: TopInfo<'tcx>, |
e1599b0c XL |
1946 | ) -> Ty<'tcx> { |
1947 | let tcx = self.tcx; | |
9ffffee4 FG |
1948 | let (box_ty, inner_ty) = match self.check_dereferenceable(span, expected, inner) { |
1949 | Ok(()) => { | |
1950 | // Here, `demand::subtype` is good enough, but I don't | |
1951 | // think any errors can be introduced by using `demand::eqtype`. | |
1952 | let inner_ty = self.next_ty_var(TypeVariableOrigin { | |
1953 | kind: TypeVariableOriginKind::TypeInference, | |
1954 | span: inner.span, | |
1955 | }); | |
1956 | let box_ty = tcx.mk_box(inner_ty); | |
1957 | self.demand_eqtype_pat(span, expected, box_ty, ti); | |
1958 | (box_ty, inner_ty) | |
1959 | } | |
1960 | Err(guar) => { | |
1961 | let err = tcx.ty_error(guar); | |
1962 | (err, err) | |
1963 | } | |
e1599b0c | 1964 | }; |
c295e0f8 | 1965 | self.check_pat(inner, inner_ty, def_bm, ti); |
e1599b0c XL |
1966 | box_ty |
1967 | } | |
1968 | ||
923072b8 | 1969 | // Precondition: Pat is Ref(inner) |
e1599b0c XL |
1970 | fn check_pat_ref( |
1971 | &self, | |
74b04a01 | 1972 | pat: &'tcx Pat<'tcx>, |
dfeec247 | 1973 | inner: &'tcx Pat<'tcx>, |
e1599b0c XL |
1974 | mutbl: hir::Mutability, |
1975 | expected: Ty<'tcx>, | |
1976 | def_bm: BindingMode, | |
dfeec247 | 1977 | ti: TopInfo<'tcx>, |
e1599b0c XL |
1978 | ) -> Ty<'tcx> { |
1979 | let tcx = self.tcx; | |
1980 | let expected = self.shallow_resolve(expected); | |
9ffffee4 FG |
1981 | let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) { |
1982 | Ok(()) => { | |
1983 | // `demand::subtype` would be good enough, but using `eqtype` turns | |
1984 | // out to be equally general. See (note_1) for details. | |
1985 | ||
1986 | // Take region, inner-type from expected type if we can, | |
1987 | // to avoid creating needless variables. This also helps with | |
1988 | // the bad interactions of the given hack detailed in (note_1). | |
1989 | debug!("check_pat_ref: expected={:?}", expected); | |
1990 | match *expected.kind() { | |
1991 | ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty), | |
1992 | _ => { | |
1993 | let inner_ty = self.next_ty_var(TypeVariableOrigin { | |
1994 | kind: TypeVariableOriginKind::TypeInference, | |
1995 | span: inner.span, | |
1996 | }); | |
1997 | let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty); | |
1998 | debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty); | |
1999 | let err = self.demand_eqtype_pat_diag(pat.span, expected, ref_ty, ti); | |
2000 | ||
2001 | // Look for a case like `fn foo(&foo: u32)` and suggest | |
2002 | // `fn foo(foo: &u32)` | |
2003 | if let Some(mut err) = err { | |
2004 | self.borrow_pat_suggestion(&mut err, pat); | |
2005 | err.emit(); | |
2006 | } | |
2007 | (ref_ty, inner_ty) | |
e1599b0c | 2008 | } |
e1599b0c XL |
2009 | } |
2010 | } | |
9ffffee4 FG |
2011 | Err(guar) => { |
2012 | let err = tcx.ty_error(guar); | |
2013 | (err, err) | |
2014 | } | |
e1599b0c | 2015 | }; |
064997fb | 2016 | self.check_pat(inner, inner_ty, def_bm, ti); |
9c376795 | 2017 | ref_ty |
e1599b0c XL |
2018 | } |
2019 | ||
2020 | /// Create a reference type with a fresh region variable. | |
2021 | fn new_ref_ty(&self, span: Span, mutbl: hir::Mutability, ty: Ty<'tcx>) -> Ty<'tcx> { | |
2022 | let region = self.next_region_var(infer::PatternRegion(span)); | |
2023 | let mt = ty::TypeAndMut { ty, mutbl }; | |
2024 | self.tcx.mk_ref(region, mt) | |
2025 | } | |
2026 | ||
60c5eb7d XL |
2027 | /// Type check a slice pattern. |
2028 | /// | |
2029 | /// Syntactically, these look like `[pat_0, ..., pat_n]`. | |
2030 | /// Semantically, we are type checking a pattern with structure: | |
04454e1e | 2031 | /// ```ignore (not-rust) |
60c5eb7d XL |
2032 | /// [before_0, ..., before_n, (slice, after_0, ... after_n)?] |
2033 | /// ``` | |
2034 | /// The type of `slice`, if it is present, depends on the `expected` type. | |
2035 | /// If `slice` is missing, then so is `after_i`. | |
2036 | /// If `slice` is present, it can still represent 0 elements. | |
e1599b0c XL |
2037 | fn check_pat_slice( |
2038 | &self, | |
2039 | span: Span, | |
136023e0 | 2040 | before: &'tcx [Pat<'tcx>], |
dfeec247 | 2041 | slice: Option<&'tcx Pat<'tcx>>, |
136023e0 | 2042 | after: &'tcx [Pat<'tcx>], |
e1599b0c XL |
2043 | expected: Ty<'tcx>, |
2044 | def_bm: BindingMode, | |
dfeec247 | 2045 | ti: TopInfo<'tcx>, |
e1599b0c | 2046 | ) -> Ty<'tcx> { |
dfeec247 | 2047 | let expected = self.structurally_resolved_type(span, expected); |
1b1a35ee | 2048 | let (element_ty, opt_slice_ty, inferred) = match *expected.kind() { |
60c5eb7d | 2049 | // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`. |
ba9703b0 | 2050 | ty::Array(element_ty, len) => { |
dfeec247 | 2051 | let min = before.len() as u64 + after.len() as u64; |
ba9703b0 XL |
2052 | let (opt_slice_ty, expected) = |
2053 | self.check_array_pat_len(span, element_ty, expected, slice, len, min); | |
2054 | // `opt_slice_ty.is_none()` => `slice.is_none()`. | |
2055 | // Note, though, that opt_slice_ty could be `Some(error_ty)`. | |
2056 | assert!(opt_slice_ty.is_some() || slice.is_none()); | |
2057 | (element_ty, opt_slice_ty, expected) | |
e1599b0c | 2058 | } |
ba9703b0 | 2059 | ty::Slice(element_ty) => (element_ty, Some(expected), expected), |
60c5eb7d | 2060 | // The expected type must be an array or slice, but was neither, so error. |
e1599b0c | 2061 | _ => { |
9ffffee4 FG |
2062 | let guar = expected |
2063 | .error_reported() | |
2064 | .err() | |
2065 | .unwrap_or_else(|| self.error_expected_array_or_slice(span, expected, ti)); | |
2066 | let err = self.tcx.ty_error(guar); | |
ba9703b0 | 2067 | (err, Some(err), err) |
e1599b0c XL |
2068 | } |
2069 | }; | |
2070 | ||
60c5eb7d | 2071 | // Type check all the patterns before `slice`. |
e1599b0c | 2072 | for elt in before { |
c295e0f8 | 2073 | self.check_pat(elt, element_ty, def_bm, ti); |
e1599b0c | 2074 | } |
60c5eb7d | 2075 | // Type check the `slice`, if present, against its expected type. |
e1599b0c | 2076 | if let Some(slice) = slice { |
c295e0f8 | 2077 | self.check_pat(slice, opt_slice_ty.unwrap(), def_bm, ti); |
e1599b0c | 2078 | } |
60c5eb7d | 2079 | // Type check the elements after `slice`, if present. |
e1599b0c | 2080 | for elt in after { |
c295e0f8 | 2081 | self.check_pat(elt, element_ty, def_bm, ti); |
e1599b0c | 2082 | } |
ba9703b0 | 2083 | inferred |
dfeec247 XL |
2084 | } |
2085 | ||
2086 | /// Type check the length of an array pattern. | |
2087 | /// | |
ba9703b0 XL |
2088 | /// Returns both the type of the variable length pattern (or `None`), and the potentially |
2089 | /// inferred array type. We only return `None` for the slice type if `slice.is_none()`. | |
dfeec247 XL |
2090 | fn check_array_pat_len( |
2091 | &self, | |
2092 | span: Span, | |
ba9703b0 XL |
2093 | element_ty: Ty<'tcx>, |
2094 | arr_ty: Ty<'tcx>, | |
dfeec247 | 2095 | slice: Option<&'tcx Pat<'tcx>>, |
5099ac24 | 2096 | len: ty::Const<'tcx>, |
dfeec247 | 2097 | min_len: u64, |
ba9703b0 | 2098 | ) -> (Option<Ty<'tcx>>, Ty<'tcx>) { |
9ffffee4 | 2099 | let guar = if let Some(len) = len.try_eval_target_usize(self.tcx, self.param_env) { |
dfeec247 XL |
2100 | // Now we know the length... |
2101 | if slice.is_none() { | |
2102 | // ...and since there is no variable-length pattern, | |
2103 | // we require an exact match between the number of elements | |
2104 | // in the array pattern and as provided by the matched type. | |
ba9703b0 XL |
2105 | if min_len == len { |
2106 | return (None, arr_ty); | |
dfeec247 | 2107 | } |
ba9703b0 | 2108 | |
9ffffee4 | 2109 | self.error_scrutinee_inconsistent_length(span, min_len, len) |
ba9703b0 | 2110 | } else if let Some(pat_len) = len.checked_sub(min_len) { |
dfeec247 XL |
2111 | // The variable-length pattern was there, |
2112 | // so it has an array type with the remaining elements left as its size... | |
ba9703b0 | 2113 | return (Some(self.tcx.mk_array(element_ty, pat_len)), arr_ty); |
dfeec247 XL |
2114 | } else { |
2115 | // ...however, in this case, there were no remaining elements. | |
2116 | // That is, the slice pattern requires more than the array type offers. | |
9ffffee4 | 2117 | self.error_scrutinee_with_rest_inconsistent_length(span, min_len, len) |
dfeec247 | 2118 | } |
ba9703b0 XL |
2119 | } else if slice.is_none() { |
2120 | // We have a pattern with a fixed length, | |
2121 | // which we can use to infer the length of the array. | |
2122 | let updated_arr_ty = self.tcx.mk_array(element_ty, min_len); | |
2123 | self.demand_eqtype(span, updated_arr_ty, arr_ty); | |
2124 | return (None, updated_arr_ty); | |
dfeec247 | 2125 | } else { |
ba9703b0 XL |
2126 | // We have a variable-length pattern and don't know the array length. |
2127 | // This happens if we have e.g., | |
2128 | // `let [a, b, ..] = arr` where `arr: [T; N]` where `const N: usize`. | |
9ffffee4 FG |
2129 | self.error_scrutinee_unfixed_length(span) |
2130 | }; | |
ba9703b0 XL |
2131 | |
2132 | // If we get here, we must have emitted an error. | |
9ffffee4 | 2133 | (Some(self.tcx.ty_error(guar)), arr_ty) |
e1599b0c XL |
2134 | } |
2135 | ||
9ffffee4 FG |
2136 | fn error_scrutinee_inconsistent_length( |
2137 | &self, | |
2138 | span: Span, | |
2139 | min_len: u64, | |
2140 | size: u64, | |
2141 | ) -> ErrorGuaranteed { | |
e1599b0c XL |
2142 | struct_span_err!( |
2143 | self.tcx.sess, | |
2144 | span, | |
2145 | E0527, | |
2146 | "pattern requires {} element{} but array has {}", | |
2147 | min_len, | |
60c5eb7d | 2148 | pluralize!(min_len), |
e1599b0c XL |
2149 | size, |
2150 | ) | |
60c5eb7d | 2151 | .span_label(span, format!("expected {} element{}", size, pluralize!(size))) |
9ffffee4 | 2152 | .emit() |
e1599b0c XL |
2153 | } |
2154 | ||
9ffffee4 FG |
2155 | fn error_scrutinee_with_rest_inconsistent_length( |
2156 | &self, | |
2157 | span: Span, | |
2158 | min_len: u64, | |
2159 | size: u64, | |
2160 | ) -> ErrorGuaranteed { | |
e1599b0c XL |
2161 | struct_span_err!( |
2162 | self.tcx.sess, | |
2163 | span, | |
2164 | E0528, | |
2165 | "pattern requires at least {} element{} but array has {}", | |
2166 | min_len, | |
60c5eb7d | 2167 | pluralize!(min_len), |
e1599b0c | 2168 | size, |
dfeec247 XL |
2169 | ) |
2170 | .span_label( | |
e1599b0c | 2171 | span, |
dfeec247 XL |
2172 | format!("pattern cannot match array of {} element{}", size, pluralize!(size),), |
2173 | ) | |
9ffffee4 | 2174 | .emit() |
e1599b0c XL |
2175 | } |
2176 | ||
9ffffee4 | 2177 | fn error_scrutinee_unfixed_length(&self, span: Span) -> ErrorGuaranteed { |
e1599b0c | 2178 | struct_span_err!( |
dfeec247 XL |
2179 | self.tcx.sess, |
2180 | span, | |
2181 | E0730, | |
e1599b0c XL |
2182 | "cannot pattern-match on an array without a fixed length", |
2183 | ) | |
9ffffee4 | 2184 | .emit() |
e1599b0c XL |
2185 | } |
2186 | ||
9ffffee4 FG |
2187 | fn error_expected_array_or_slice( |
2188 | &self, | |
2189 | span: Span, | |
2190 | expected_ty: Ty<'tcx>, | |
2191 | ti: TopInfo<'tcx>, | |
2192 | ) -> ErrorGuaranteed { | |
e1599b0c | 2193 | let mut err = struct_span_err!( |
dfeec247 XL |
2194 | self.tcx.sess, |
2195 | span, | |
2196 | E0529, | |
04454e1e | 2197 | "expected an array or slice, found `{expected_ty}`" |
e1599b0c | 2198 | ); |
04454e1e FG |
2199 | if let ty::Ref(_, ty, _) = expected_ty.kind() |
2200 | && let ty::Array(..) | ty::Slice(..) = ty.kind() | |
2201 | { | |
2202 | err.help("the semantics of slice patterns changed recently; see issue #62254"); | |
487cf647 | 2203 | } else if self.autoderef(span, expected_ty) |
5099ac24 | 2204 | .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) |
9ffffee4 FG |
2205 | && let Some(span) = ti.span |
2206 | && let Some(_) = ti.origin_expr | |
04454e1e | 2207 | && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) |
94222f64 | 2208 | { |
04454e1e | 2209 | let ty = self.resolve_vars_if_possible(ti.expected); |
9c376795 | 2210 | let is_slice_or_array_or_vector = self.is_slice_or_array_or_vector(ty); |
04454e1e FG |
2211 | match is_slice_or_array_or_vector.1.kind() { |
2212 | ty::Adt(adt_def, _) | |
2213 | if self.tcx.is_diagnostic_item(sym::Option, adt_def.did()) | |
2214 | || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) => | |
2215 | { | |
2216 | // Slicing won't work here, but `.as_deref()` might (issue #91328). | |
2217 | err.span_suggestion( | |
5099ac24 | 2218 | span, |
04454e1e FG |
2219 | "consider using `as_deref` here", |
2220 | format!("{snippet}.as_deref()"), | |
2221 | Applicability::MaybeIncorrect, | |
2222 | ); | |
94222f64 | 2223 | } |
04454e1e FG |
2224 | _ => () |
2225 | } | |
2226 | if is_slice_or_array_or_vector.0 { | |
2227 | err.span_suggestion( | |
2228 | span, | |
2229 | "consider slicing here", | |
2230 | format!("{snippet}[..]"), | |
2231 | Applicability::MachineApplicable, | |
2232 | ); | |
94222f64 | 2233 | } |
e1599b0c | 2234 | } |
04454e1e | 2235 | err.span_label(span, format!("pattern cannot match with input type `{expected_ty}`")); |
9ffffee4 | 2236 | err.emit() |
e1599b0c | 2237 | } |
04454e1e | 2238 | |
9c376795 | 2239 | fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>) { |
04454e1e FG |
2240 | match ty.kind() { |
2241 | ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => { | |
2242 | (true, ty) | |
2243 | } | |
9c376795 | 2244 | ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty), |
04454e1e FG |
2245 | ty::Slice(..) | ty::Array(..) => (true, ty), |
2246 | _ => (false, ty), | |
2247 | } | |
2248 | } | |
e1599b0c | 2249 | } |