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