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