]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | use crate::check::{FnCtxt, Expectation, Diverges, Needs}; |
2 | use crate::check::coercion::CoerceMany; | |
3 | use crate::util::nodemap::FxHashMap; | |
48663c56 XL |
4 | use errors::{Applicability, DiagnosticBuilder}; |
5 | use rustc::hir::{self, PatKind, Pat, ExprKind}; | |
6 | use rustc::hir::def::{Res, DefKind, CtorKind}; | |
c30ab7b3 | 7 | use rustc::hir::pat_util::EnumerateAndAdjustIterator; |
476ff2be SL |
8 | use rustc::infer; |
9 | use rustc::infer::type_variable::TypeVariableOrigin; | |
48663c56 | 10 | use rustc::traits::{ObligationCause, ObligationCauseCode}; |
2c00a5a8 | 11 | use rustc::ty::{self, Ty, TypeFoldable}; |
48663c56 | 12 | use rustc::ty::subst::Kind; |
1a4d82fc | 13 | use syntax::ast; |
b7449926 | 14 | use syntax::source_map::Spanned; |
1a4d82fc | 15 | use syntax::ptr::P; |
0bf4aa26 | 16 | use syntax::util::lev_distance::find_best_match_for_name; |
3157f602 | 17 | use syntax_pos::Span; |
48663c56 | 18 | use syntax_pos::hygiene::CompilerDesugaringKind; |
0731742a XL |
19 | |
20 | use std::collections::hash_map::Entry::{Occupied, Vacant}; | |
21 | use std::cmp; | |
22 | ||
48663c56 | 23 | use super::report_unexpected_variant_res; |
1a4d82fc | 24 | |
3157f602 | 25 | impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { |
48663c56 XL |
26 | /// `discrim_span` argument having a `Span` indicates that this pattern is part of a match |
27 | /// expression arm guard, and it points to the match discriminant to add context in type errors. | |
28 | /// In the following example, `discrim_span` corresponds to the `a + b` expression: | |
0731742a XL |
29 | /// |
30 | /// ```text | |
31 | /// error[E0308]: mismatched types | |
32 | /// --> src/main.rs:5:9 | |
33 | /// | | |
34 | /// 4 | let temp: usize = match a + b { | |
35 | /// | ----- this expression has type `usize` | |
36 | /// 5 | Ok(num) => num, | |
37 | /// | ^^^^^^^ expected usize, found enum `std::result::Result` | |
38 | /// | | |
39 | /// = note: expected type `usize` | |
40 | /// found type `std::result::Result<_, _>` | |
41 | /// ``` | |
ea8adc8c XL |
42 | pub fn check_pat_walk( |
43 | &self, | |
44 | pat: &'gcx hir::Pat, | |
45 | mut expected: Ty<'tcx>, | |
46 | mut def_bm: ty::BindingMode, | |
48663c56 | 47 | discrim_span: Option<Span>, |
0731742a | 48 | ) { |
a7813a04 XL |
49 | let tcx = self.tcx; |
50 | ||
0731742a | 51 | debug!("check_pat_walk(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm); |
ea8adc8c XL |
52 | |
53 | let is_non_ref_pat = match pat.node { | |
54 | PatKind::Struct(..) | | |
55 | PatKind::TupleStruct(..) | | |
56 | PatKind::Tuple(..) | | |
57 | PatKind::Box(_) | | |
58 | PatKind::Range(..) | | |
59 | PatKind::Slice(..) => true, | |
60 | PatKind::Lit(ref lt) => { | |
61 | let ty = self.check_expr(lt); | |
62 | match ty.sty { | |
b7449926 | 63 | ty::Ref(..) => false, |
ea8adc8c XL |
64 | _ => true, |
65 | } | |
66 | } | |
67 | PatKind::Path(ref qpath) => { | |
48663c56 | 68 | let (def, _, _) = self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span); |
ea8adc8c | 69 | match def { |
48663c56 | 70 | Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssociatedConst, _) => false, |
ea8adc8c XL |
71 | _ => true, |
72 | } | |
73 | } | |
74 | PatKind::Wild | | |
75 | PatKind::Binding(..) | | |
76 | PatKind::Ref(..) => false, | |
77 | }; | |
abe05a73 | 78 | if is_non_ref_pat { |
ea8adc8c XL |
79 | debug!("pattern is non reference pattern"); |
80 | let mut exp_ty = self.resolve_type_vars_with_obligations(&expected); | |
81 | ||
82 | // Peel off as many `&` or `&mut` from the discriminant as possible. For example, | |
83 | // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches | |
b7449926 | 84 | // the `Some(5)` which is not of type Ref. |
ea8adc8c XL |
85 | // |
86 | // For each ampersand peeled off, update the binding mode and push the original | |
87 | // type into the adjustments vector. | |
88 | // | |
89 | // See the examples in `run-pass/match-defbm*.rs`. | |
90 | let mut pat_adjustments = vec![]; | |
0bf4aa26 | 91 | while let ty::Ref(_, inner_ty, inner_mutability) = exp_ty.sty { |
532ac7d7 | 92 | debug!("inspecting {:?}", exp_ty); |
0bf4aa26 XL |
93 | |
94 | debug!("current discriminant is Ref, inserting implicit deref"); | |
95 | // Preserve the reference type. We'll need it later during HAIR lowering. | |
96 | pat_adjustments.push(exp_ty); | |
97 | ||
98 | exp_ty = inner_ty; | |
99 | def_bm = match def_bm { | |
100 | // If default binding mode is by value, make it `ref` or `ref mut` | |
101 | // (depending on whether we observe `&` or `&mut`). | |
102 | ty::BindByValue(_) => | |
103 | ty::BindByReference(inner_mutability), | |
104 | ||
105 | // Once a `ref`, always a `ref`. This is because a `& &mut` can't mutate | |
106 | // the underlying value. | |
107 | ty::BindByReference(hir::Mutability::MutImmutable) => | |
108 | ty::BindByReference(hir::Mutability::MutImmutable), | |
109 | ||
110 | // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` | |
111 | // (on `&`). | |
112 | ty::BindByReference(hir::Mutability::MutMutable) => | |
113 | ty::BindByReference(inner_mutability), | |
114 | }; | |
115 | } | |
116 | expected = exp_ty; | |
117 | ||
ea8adc8c | 118 | if pat_adjustments.len() > 0 { |
0531ce1d XL |
119 | debug!("default binding mode is now {:?}", def_bm); |
120 | self.inh.tables.borrow_mut() | |
121 | .pat_adjustments_mut() | |
122 | .insert(pat.hir_id, pat_adjustments); | |
ea8adc8c | 123 | } |
0531ce1d XL |
124 | } else if let PatKind::Ref(..) = pat.node { |
125 | // When you encounter a `&pat` pattern, reset to "by | |
126 | // value". This is so that `x` and `y` here are by value, | |
127 | // as they appear to be: | |
128 | // | |
129 | // ``` | |
130 | // match &(&22, &44) { | |
131 | // (&x, &y) => ... | |
132 | // } | |
133 | // ``` | |
134 | // | |
135 | // cc #46688 | |
136 | def_bm = ty::BindByValue(hir::MutImmutable); | |
ea8adc8c XL |
137 | } |
138 | ||
139 | // Lose mutability now that we know binding mode and discriminant type. | |
140 | let def_bm = def_bm; | |
141 | let expected = expected; | |
a7813a04 | 142 | |
9e0c209e | 143 | let ty = match pat.node { |
a7813a04 | 144 | PatKind::Wild => { |
9e0c209e | 145 | expected |
a7813a04 XL |
146 | } |
147 | PatKind::Lit(ref lt) => { | |
ea8adc8c XL |
148 | // We've already computed the type above (when checking for a non-ref pat), so |
149 | // avoid computing it again. | |
150 | let ty = self.node_ty(lt.hir_id); | |
a7813a04 XL |
151 | |
152 | // Byte string patterns behave the same way as array patterns | |
153 | // They can denote both statically and dynamically sized byte arrays | |
9e0c209e | 154 | let mut pat_ty = ty; |
8faf50e0 | 155 | if let hir::ExprKind::Lit(ref lt) = lt.node { |
a7813a04 XL |
156 | if let ast::LitKind::ByteStr(_) = lt.node { |
157 | let expected_ty = self.structurally_resolved_type(pat.span, expected); | |
b7449926 XL |
158 | if let ty::Ref(_, r_ty, _) = expected_ty.sty { |
159 | if let ty::Slice(_) = r_ty.sty { | |
48663c56 | 160 | pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, |
0bf4aa26 | 161 | tcx.mk_slice(tcx.types.u8)) |
a7813a04 | 162 | } |
c34b1796 AL |
163 | } |
164 | } | |
165 | } | |
c34b1796 | 166 | |
a7813a04 XL |
167 | // somewhat surprising: in this case, the subtyping |
168 | // relation goes the opposite way as the other | |
169 | // cases. Actually what we really want is not a subtyping | |
170 | // relation at all but rather that there exists a LUB (so | |
171 | // that they can be compared). However, in practice, | |
172 | // constants are always scalars or strings. For scalars | |
9e0c209e | 173 | // subtyping is irrelevant, and for strings `ty` is |
a7813a04 XL |
174 | // type is `&'static str`, so if we say that |
175 | // | |
176 | // &'static str <: expected | |
177 | // | |
178 | // that's equivalent to there existing a LUB. | |
48663c56 XL |
179 | if let Some(mut err) = self.demand_suptype_diag(pat.span, expected, pat_ty) { |
180 | err.emit_unless(discrim_span | |
181 | .filter(|&s| s.is_compiler_desugaring(CompilerDesugaringKind::IfTemporary)) | |
182 | .is_some()); | |
183 | } | |
184 | ||
9e0c209e | 185 | pat_ty |
62682a34 | 186 | } |
32a655c1 | 187 | PatKind::Range(ref begin, ref end, _) => { |
9e0c209e SL |
188 | let lhs_ty = self.check_expr(begin); |
189 | let rhs_ty = self.check_expr(end); | |
a7813a04 XL |
190 | |
191 | // Check that both end-points are of numeric or char type. | |
9fa01778 | 192 | let numeric_or_char = |ty: Ty<'_>| ty.is_numeric() || ty.is_char(); |
a7813a04 XL |
193 | let lhs_compat = numeric_or_char(lhs_ty); |
194 | let rhs_compat = numeric_or_char(rhs_ty); | |
195 | ||
196 | if !lhs_compat || !rhs_compat { | |
197 | let span = if !lhs_compat && !rhs_compat { | |
198 | pat.span | |
199 | } else if !lhs_compat { | |
200 | begin.span | |
201 | } else { | |
202 | end.span | |
203 | }; | |
204 | ||
2c00a5a8 XL |
205 | let mut err = struct_span_err!( |
206 | tcx.sess, | |
207 | span, | |
208 | E0029, | |
209 | "only char and numeric types are allowed in range patterns" | |
210 | ); | |
211 | err.span_label(span, "ranges require char or numeric types"); | |
212 | err.note(&format!("start type: {}", self.ty_to_string(lhs_ty))); | |
213 | err.note(&format!("end type: {}", self.ty_to_string(rhs_ty))); | |
214 | if tcx.sess.teach(&err.get_code().unwrap()) { | |
215 | err.note( | |
216 | "In a match expression, only numbers and characters can be matched \ | |
217 | against a range. This is because the compiler checks that the range \ | |
218 | is non-empty at compile-time, and is unable to evaluate arbitrary \ | |
219 | comparison functions. If you want to capture values of an orderable \ | |
220 | type between two end-points, you can use a guard." | |
221 | ); | |
222 | } | |
223 | err.emit(); | |
a7813a04 XL |
224 | return; |
225 | } | |
1a4d82fc | 226 | |
a7813a04 XL |
227 | // Now that we know the types can be unified we find the unified type and use |
228 | // it to type the entire expression. | |
229 | let common_type = self.resolve_type_vars_if_possible(&lhs_ty); | |
62682a34 | 230 | |
a7813a04 | 231 | // subtyping doesn't matter here, as the value is some kind of scalar |
48663c56 XL |
232 | self.demand_eqtype_pat(pat.span, expected, lhs_ty, discrim_span); |
233 | self.demand_eqtype_pat(pat.span, expected, rhs_ty, discrim_span); | |
9e0c209e | 234 | common_type |
1a4d82fc | 235 | } |
532ac7d7 | 236 | PatKind::Binding(ba, var_id, _, ref sub) => { |
ea8adc8c XL |
237 | let bm = if ba == hir::BindingAnnotation::Unannotated { |
238 | def_bm | |
239 | } else { | |
240 | ty::BindingMode::convert(ba) | |
241 | }; | |
3b2f2976 XL |
242 | self.inh |
243 | .tables | |
244 | .borrow_mut() | |
245 | .pat_binding_modes_mut() | |
246 | .insert(pat.hir_id, bm); | |
2c912e08 | 247 | debug!("check_pat_walk: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); |
532ac7d7 | 248 | let local_ty = self.local_ty(pat.span, pat.hir_id).decl_ty; |
a7813a04 | 249 | match bm { |
3b2f2976 | 250 | ty::BindByReference(mutbl) => { |
a7813a04 XL |
251 | // if the binding is like |
252 | // ref x | ref const x | ref mut x | |
253 | // then `x` is assigned a value of type `&M T` where M is the mutability | |
254 | // and T is the expected type. | |
255 | let region_var = self.next_region_var(infer::PatternRegion(pat.span)); | |
256 | let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl }; | |
9e0c209e | 257 | let region_ty = tcx.mk_ref(region_var, mt); |
a7813a04 XL |
258 | |
259 | // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is | |
260 | // required. However, we use equality, which is stronger. See (*) for | |
261 | // an explanation. | |
48663c56 | 262 | self.demand_eqtype_pat(pat.span, region_ty, local_ty, discrim_span); |
a7813a04 XL |
263 | } |
264 | // otherwise the type of x is the expected type T | |
3b2f2976 | 265 | ty::BindByValue(_) => { |
a7813a04 XL |
266 | // As above, `T <: typeof(x)` is required but we |
267 | // use equality, see (*) below. | |
48663c56 | 268 | self.demand_eqtype_pat(pat.span, expected, local_ty, discrim_span); |
a7813a04 XL |
269 | } |
270 | } | |
1a4d82fc | 271 | |
a7813a04 XL |
272 | // if there are multiple arms, make sure they all agree on |
273 | // what the type of the binding `x` ought to be | |
532ac7d7 | 274 | if var_id != pat.hir_id { |
0bf4aa26 | 275 | let vt = self.local_ty(pat.span, var_id).decl_ty; |
48663c56 | 276 | self.demand_eqtype_pat(pat.span, vt, local_ty, discrim_span); |
3157f602 | 277 | } |
1a4d82fc | 278 | |
3157f602 | 279 | if let Some(ref p) = *sub { |
48663c56 | 280 | self.check_pat_walk(&p, expected, def_bm, discrim_span); |
9cc50fc6 | 281 | } |
9e0c209e | 282 | |
0bf4aa26 | 283 | local_ty |
1a4d82fc | 284 | } |
476ff2be | 285 | PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => { |
0731742a XL |
286 | self.check_pat_tuple_struct( |
287 | pat, | |
288 | qpath, | |
289 | &subpats, | |
290 | ddpos, | |
291 | expected, | |
292 | def_bm, | |
48663c56 | 293 | discrim_span, |
0731742a | 294 | ) |
a7813a04 | 295 | } |
476ff2be SL |
296 | PatKind::Path(ref qpath) => { |
297 | self.check_pat_path(pat, qpath, expected) | |
a7813a04 | 298 | } |
476ff2be | 299 | PatKind::Struct(ref qpath, ref fields, etc) => { |
48663c56 | 300 | self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, discrim_span) |
a7813a04 | 301 | } |
3157f602 XL |
302 | PatKind::Tuple(ref elements, ddpos) => { |
303 | let mut expected_len = elements.len(); | |
304 | if ddpos.is_some() { | |
0731742a | 305 | // Require known type only when `..` is present. |
b7449926 | 306 | if let ty::Tuple(ref tys) = |
3157f602 XL |
307 | self.structurally_resolved_type(pat.span, expected).sty { |
308 | expected_len = tys.len(); | |
309 | } | |
310 | } | |
311 | let max_len = cmp::max(expected_len, elements.len()); | |
312 | ||
48663c56 | 313 | let element_tys_iter = (0..max_len).map(|_| { |
0731742a XL |
314 | // FIXME: `MiscVariable` for now -- obtaining the span and name information |
315 | // from all tuple elements isn't trivial. | |
48663c56 XL |
316 | Kind::from(self.next_ty_var(TypeVariableOrigin::TypeInference(pat.span))) |
317 | }); | |
318 | let element_tys = tcx.mk_substs(element_tys_iter); | |
b7449926 XL |
319 | let pat_ty = tcx.mk_ty(ty::Tuple(element_tys)); |
320 | if let Some(mut err) = self.demand_eqtype_diag(pat.span, expected, pat_ty) { | |
321 | err.emit(); | |
322 | // Walk subpatterns with an expected type of `err` in this case to silence | |
323 | // further errors being emitted when using the bindings. #50333 | |
324 | let element_tys_iter = (0..max_len).map(|_| tcx.types.err); | |
325 | for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { | |
48663c56 | 326 | self.check_pat_walk(elem, &tcx.types.err, def_bm, discrim_span); |
b7449926 XL |
327 | } |
328 | tcx.mk_tup(element_tys_iter) | |
329 | } else { | |
330 | for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { | |
48663c56 XL |
331 | self.check_pat_walk( |
332 | elem, | |
333 | &element_tys[i].expect_ty(), | |
334 | def_bm, | |
335 | discrim_span, | |
336 | ); | |
b7449926 XL |
337 | } |
338 | pat_ty | |
d9579d0f | 339 | } |
a7813a04 XL |
340 | } |
341 | PatKind::Box(ref inner) => { | |
476ff2be | 342 | let inner_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(inner.span)); |
a7813a04 XL |
343 | let uniq_ty = tcx.mk_box(inner_ty); |
344 | ||
345 | if self.check_dereferencable(pat.span, expected, &inner) { | |
346 | // Here, `demand::subtype` is good enough, but I don't | |
347 | // think any errors can be introduced by using | |
348 | // `demand::eqtype`. | |
48663c56 XL |
349 | self.demand_eqtype_pat(pat.span, expected, uniq_ty, discrim_span); |
350 | self.check_pat_walk(&inner, inner_ty, def_bm, discrim_span); | |
9e0c209e | 351 | uniq_ty |
d9579d0f | 352 | } else { |
48663c56 | 353 | self.check_pat_walk(&inner, tcx.types.err, def_bm, discrim_span); |
9e0c209e | 354 | tcx.types.err |
d9579d0f AL |
355 | } |
356 | } | |
a7813a04 XL |
357 | PatKind::Ref(ref inner, mutbl) => { |
358 | let expected = self.shallow_resolve(expected); | |
359 | if self.check_dereferencable(pat.span, expected, &inner) { | |
360 | // `demand::subtype` would be good enough, but using | |
361 | // `eqtype` turns out to be equally general. See (*) | |
362 | // below for details. | |
363 | ||
364 | // Take region, inner-type from expected type if we | |
365 | // can, to avoid creating needless variables. This | |
366 | // also helps with the bad interactions of the given | |
367 | // hack detailed in (*) below. | |
ea8adc8c | 368 | debug!("check_pat_walk: expected={:?}", expected); |
a7813a04 | 369 | let (rptr_ty, inner_ty) = match expected.sty { |
b7449926 | 370 | ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => { |
94b46f34 | 371 | (expected, r_ty) |
a7813a04 XL |
372 | } |
373 | _ => { | |
476ff2be SL |
374 | let inner_ty = self.next_ty_var( |
375 | TypeVariableOrigin::TypeInference(inner.span)); | |
a7813a04 XL |
376 | let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; |
377 | let region = self.next_region_var(infer::PatternRegion(pat.span)); | |
9e0c209e | 378 | let rptr_ty = tcx.mk_ref(region, mt); |
ea8adc8c | 379 | debug!("check_pat_walk: demanding {:?} = {:?}", expected, rptr_ty); |
32a655c1 SL |
380 | let err = self.demand_eqtype_diag(pat.span, expected, rptr_ty); |
381 | ||
382 | // Look for a case like `fn foo(&foo: u32)` and suggest | |
383 | // `fn foo(foo: &u32)` | |
384 | if let Some(mut err) = err { | |
48663c56 | 385 | self.borrow_pat_suggestion(&mut err, &pat, &inner, &expected); |
32a655c1 SL |
386 | err.emit(); |
387 | } | |
a7813a04 XL |
388 | (rptr_ty, inner_ty) |
389 | } | |
390 | }; | |
b039eaaf | 391 | |
48663c56 | 392 | self.check_pat_walk(&inner, inner_ty, def_bm, discrim_span); |
9e0c209e | 393 | rptr_ty |
a7813a04 | 394 | } else { |
48663c56 | 395 | self.check_pat_walk(&inner, tcx.types.err, def_bm, discrim_span); |
9e0c209e | 396 | tcx.types.err |
a7813a04 XL |
397 | } |
398 | } | |
c30ab7b3 | 399 | PatKind::Slice(ref before, ref slice, ref after) => { |
a7813a04 | 400 | let expected_ty = self.structurally_resolved_type(pat.span, expected); |
3157f602 | 401 | let (inner_ty, slice_ty) = match expected_ty.sty { |
b7449926 | 402 | ty::Array(inner_ty, size) => { |
94b46f34 | 403 | let size = size.unwrap_usize(tcx); |
ea8adc8c | 404 | let min_len = before.len() as u64 + after.len() as u64; |
3157f602 XL |
405 | if slice.is_none() { |
406 | if min_len != size { | |
9e0c209e SL |
407 | struct_span_err!( |
408 | tcx.sess, pat.span, E0527, | |
409 | "pattern requires {} elements but array has {}", | |
410 | min_len, size) | |
0bf4aa26 | 411 | .span_label(pat.span, format!("expected {} elements", size)) |
9e0c209e | 412 | .emit(); |
3157f602 XL |
413 | } |
414 | (inner_ty, tcx.types.err) | |
415 | } else if let Some(rest) = size.checked_sub(min_len) { | |
416 | (inner_ty, tcx.mk_array(inner_ty, rest)) | |
417 | } else { | |
9e0c209e SL |
418 | struct_span_err!(tcx.sess, pat.span, E0528, |
419 | "pattern requires at least {} elements but array has {}", | |
420 | min_len, size) | |
421 | .span_label(pat.span, | |
7cac9316 | 422 | format!("pattern cannot match array of {} elements", size)) |
9e0c209e | 423 | .emit(); |
3157f602 | 424 | (inner_ty, tcx.types.err) |
a7813a04 | 425 | } |
3157f602 | 426 | } |
b7449926 | 427 | ty::Slice(inner_ty) => (inner_ty, expected_ty), |
b039eaaf | 428 | _ => { |
3157f602 XL |
429 | if !expected_ty.references_error() { |
430 | let mut err = struct_span_err!( | |
431 | tcx.sess, pat.span, E0529, | |
432 | "expected an array or slice, found `{}`", | |
433 | expected_ty); | |
b7449926 | 434 | if let ty::Ref(_, ty, _) = expected_ty.sty { |
3157f602 | 435 | match ty.sty { |
b7449926 | 436 | ty::Array(..) | ty::Slice(..) => { |
3157f602 XL |
437 | err.help("the semantics of slice patterns changed \ |
438 | recently; see issue #23121"); | |
439 | } | |
440 | _ => {} | |
441 | } | |
442 | } | |
9e0c209e SL |
443 | |
444 | err.span_label( pat.span, | |
7cac9316 | 445 | format!("pattern cannot match with input type `{}`", expected_ty) |
9e0c209e | 446 | ).emit(); |
3157f602 XL |
447 | } |
448 | (tcx.types.err, tcx.types.err) | |
b039eaaf SL |
449 | } |
450 | }; | |
451 | ||
a7813a04 | 452 | for elt in before { |
48663c56 | 453 | self.check_pat_walk(&elt, inner_ty, def_bm, discrim_span); |
a7813a04 XL |
454 | } |
455 | if let Some(ref slice) = *slice { | |
48663c56 | 456 | self.check_pat_walk(&slice, slice_ty, def_bm, discrim_span); |
a7813a04 XL |
457 | } |
458 | for elt in after { | |
48663c56 | 459 | self.check_pat_walk(&elt, inner_ty, def_bm, discrim_span); |
a7813a04 | 460 | } |
9e0c209e | 461 | expected_ty |
1a4d82fc | 462 | } |
9e0c209e SL |
463 | }; |
464 | ||
3b2f2976 | 465 | self.write_ty(pat.hir_id, ty); |
1a4d82fc | 466 | |
a7813a04 | 467 | // (*) In most of the cases above (literals and constants being |
ea8adc8c | 468 | // the exception), we relate types using strict equality, even |
a7813a04 XL |
469 | // though subtyping would be sufficient. There are a few reasons |
470 | // for this, some of which are fairly subtle and which cost me | |
471 | // (nmatsakis) an hour or two debugging to remember, so I thought | |
472 | // I'd write them down this time. | |
473 | // | |
474 | // 1. There is no loss of expressiveness here, though it does | |
475 | // cause some inconvenience. What we are saying is that the type | |
476 | // of `x` becomes *exactly* what is expected. This can cause unnecessary | |
477 | // errors in some cases, such as this one: | |
a7813a04 XL |
478 | // |
479 | // ``` | |
480 | // fn foo<'x>(x: &'x int) { | |
481 | // let a = 1; | |
482 | // let mut z = x; | |
483 | // z = &a; | |
484 | // } | |
485 | // ``` | |
486 | // | |
487 | // The reason we might get an error is that `z` might be | |
488 | // assigned a type like `&'x int`, and then we would have | |
489 | // a problem when we try to assign `&a` to `z`, because | |
490 | // the lifetime of `&a` (i.e., the enclosing block) is | |
491 | // shorter than `'x`. | |
492 | // | |
493 | // HOWEVER, this code works fine. The reason is that the | |
494 | // expected type here is whatever type the user wrote, not | |
495 | // the initializer's type. In this case the user wrote | |
496 | // nothing, so we are going to create a type variable `Z`. | |
497 | // Then we will assign the type of the initializer (`&'x | |
498 | // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we | |
499 | // will instantiate `Z` as a type `&'0 int` where `'0` is | |
500 | // a fresh region variable, with the constraint that `'x : | |
501 | // '0`. So basically we're all set. | |
502 | // | |
503 | // Note that there are two tests to check that this remains true | |
504 | // (`regions-reassign-{match,let}-bound-pointer.rs`). | |
505 | // | |
506 | // 2. Things go horribly wrong if we use subtype. The reason for | |
507 | // THIS is a fairly subtle case involving bound regions. See the | |
abe05a73 | 508 | // `givens` field in `region_constraints`, as well as the test |
a7813a04 XL |
509 | // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`, |
510 | // for details. Short version is that we must sometimes detect | |
511 | // relationships between specific region variables and regions | |
512 | // bound in a closure signature, and that detection gets thrown | |
513 | // off when we substitute fresh region variables here to enable | |
514 | // subtyping. | |
d9579d0f | 515 | } |
d9579d0f | 516 | |
48663c56 XL |
517 | fn borrow_pat_suggestion( |
518 | &self, | |
519 | err: &mut DiagnosticBuilder<'_>, | |
520 | pat: &Pat, | |
521 | inner: &Pat, | |
522 | expected: Ty<'tcx>, | |
523 | ) { | |
524 | let tcx = self.tcx; | |
525 | if let PatKind::Binding(..) = inner.node { | |
526 | let parent_id = tcx.hir().get_parent_node_by_hir_id(pat.hir_id); | |
527 | let parent = tcx.hir().get_by_hir_id(parent_id); | |
528 | debug!("inner {:?} pat {:?} parent {:?}", inner, pat, parent); | |
529 | match parent { | |
530 | hir::Node::Item(hir::Item { node: hir::ItemKind::Fn(..), .. }) | | |
531 | hir::Node::ForeignItem(hir::ForeignItem { | |
532 | node: hir::ForeignItemKind::Fn(..), .. | |
533 | }) | | |
534 | hir::Node::TraitItem(hir::TraitItem { node: hir::TraitItemKind::Method(..), .. }) | | |
535 | hir::Node::ImplItem(hir::ImplItem { node: hir::ImplItemKind::Method(..), .. }) => { | |
536 | // this pat is likely an argument | |
537 | if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { | |
538 | // FIXME: turn into structured suggestion, will need a span that also | |
539 | // includes the the arg's type. | |
540 | err.help(&format!("did you mean `{}: &{}`?", snippet, expected)); | |
541 | } | |
542 | } | |
543 | hir::Node::Expr(hir::Expr { node: hir::ExprKind::Match(..), .. }) | | |
544 | hir::Node::Pat(_) => { | |
545 | // rely on match ergonomics or it might be nested `&&pat` | |
546 | if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { | |
547 | err.span_suggestion( | |
548 | pat.span, | |
549 | "you can probably remove the explicit borrow", | |
550 | snippet, | |
551 | Applicability::MaybeIncorrect, | |
552 | ); | |
553 | } | |
554 | } | |
555 | _ => {} // don't provide suggestions in other cases #55175 | |
556 | } | |
557 | } | |
558 | } | |
559 | ||
a7813a04 | 560 | pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool { |
3157f602 | 561 | if let PatKind::Binding(..) = inner.node { |
2c00a5a8 | 562 | if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) { |
b7449926 | 563 | if let ty::Dynamic(..) = mt.ty.sty { |
a7813a04 XL |
564 | // This is "x = SomeTrait" being reduced from |
565 | // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error. | |
9e0c209e | 566 | let type_str = self.ty_to_string(expected); |
2c00a5a8 XL |
567 | let mut err = struct_span_err!( |
568 | self.tcx.sess, | |
569 | span, | |
570 | E0033, | |
571 | "type `{}` cannot be dereferenced", | |
572 | type_str | |
573 | ); | |
574 | err.span_label(span, format!("type `{}` cannot be dereferenced", type_str)); | |
575 | if self.tcx.sess.teach(&err.get_code().unwrap()) { | |
576 | err.note("\ | |
577 | This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \ | |
578 | pattern. Every trait defines a type, but because the size of trait implementors isn't fixed, \ | |
579 | this type has no compile-time size. Therefore, all accesses to trait types must be through \ | |
580 | pointers. If you encounter this error you should try to avoid dereferencing the pointer. | |
581 | ||
582 | You can read more about trait objects in the Trait Objects section of the Reference: \ | |
583 | https://doc.rust-lang.org/reference/types.html#trait-objects"); | |
584 | } | |
585 | err.emit(); | |
3157f602 | 586 | return false |
a7813a04 | 587 | } |
3157f602 | 588 | } |
54a0048b | 589 | } |
3157f602 | 590 | true |
a7813a04 | 591 | } |
54a0048b | 592 | |
0731742a XL |
593 | pub fn check_match( |
594 | &self, | |
595 | expr: &'gcx hir::Expr, | |
596 | discrim: &'gcx hir::Expr, | |
597 | arms: &'gcx [hir::Arm], | |
598 | expected: Expectation<'tcx>, | |
599 | match_src: hir::MatchSource, | |
600 | ) -> Ty<'tcx> { | |
a7813a04 XL |
601 | let tcx = self.tcx; |
602 | ||
48663c56 XL |
603 | use hir::MatchSource::*; |
604 | let (source_if, if_no_else, if_desugar) = match match_src { | |
605 | IfDesugar { contains_else_clause } => (true, !contains_else_clause, true), | |
606 | IfLetDesugar { contains_else_clause } => (true, !contains_else_clause, false), | |
607 | _ => (false, false, false), | |
608 | }; | |
609 | ||
610 | // Type check the descriminant and get its type. | |
611 | let discrim_ty = if if_desugar { | |
612 | // Here we want to ensure: | |
613 | // | |
614 | // 1. That default match bindings are *not* accepted in the condition of an | |
615 | // `if` expression. E.g. given `fn foo() -> &bool;` we reject `if foo() { .. }`. | |
616 | // | |
617 | // 2. By expecting `bool` for `expr` we get nice diagnostics for e.g. `if x = y { .. }`. | |
618 | // | |
619 | // FIXME(60707): Consider removing hack with principled solution. | |
620 | self.check_expr_has_type_or_error(discrim, self.tcx.types.bool) | |
54a0048b | 621 | } else { |
48663c56 | 622 | self.demand_discriminant_type(arms, discrim) |
54a0048b | 623 | }; |
cc61c64b | 624 | |
cc61c64b XL |
625 | // If there are no arms, that is a diverging match; a special case. |
626 | if arms.is_empty() { | |
627 | self.diverges.set(self.diverges.get() | Diverges::Always); | |
628 | return tcx.types.never; | |
629 | } | |
630 | ||
48663c56 | 631 | self.warn_arms_when_scrutinee_diverges(arms, source_if); |
0bf4aa26 | 632 | |
cc61c64b XL |
633 | // Otherwise, we have to union together the types that the |
634 | // arms produce and so forth. | |
476ff2be SL |
635 | let discrim_diverges = self.diverges.get(); |
636 | self.diverges.set(Diverges::Maybe); | |
1a4d82fc | 637 | |
13cf67c4 XL |
638 | // rust-lang/rust#55810: Typecheck patterns first (via eager |
639 | // collection into `Vec`), so we get types for all bindings. | |
640 | let all_arm_pats_diverge: Vec<_> = arms.iter().map(|arm| { | |
476ff2be | 641 | let mut all_pats_diverge = Diverges::WarnedAlways; |
a7813a04 | 642 | for p in &arm.pats { |
476ff2be | 643 | self.diverges.set(Diverges::Maybe); |
48663c56 XL |
644 | let binding_mode = ty::BindingMode::BindByValue(hir::Mutability::MutImmutable); |
645 | self.check_pat_walk(&p, discrim_ty, binding_mode, Some(discrim.span)); | |
476ff2be | 646 | all_pats_diverge &= self.diverges.get(); |
a7813a04 | 647 | } |
cc61c64b | 648 | |
32a655c1 SL |
649 | // As discussed with @eddyb, this is for disabling unreachable_code |
650 | // warnings on patterns (they're now subsumed by unreachable_patterns | |
651 | // warnings). | |
652 | match all_pats_diverge { | |
653 | Diverges::Maybe => Diverges::Maybe, | |
654 | Diverges::Always | Diverges::WarnedAlways => Diverges::WarnedAlways, | |
655 | } | |
13cf67c4 | 656 | }).collect(); |
1a4d82fc | 657 | |
a7813a04 XL |
658 | // Now typecheck the blocks. |
659 | // | |
660 | // The result of the match is the common supertype of all the | |
661 | // arms. Start out the value as bottom, since it's the, well, | |
662 | // bottom the type lattice, and we'll be moving up the lattice as | |
663 | // we process each arm. (Note that any match with 0 arms is matching | |
664 | // on any empty type and is therefore unreachable; should the flow | |
665 | // of execution reach it, we will panic, so bottom is an appropriate | |
666 | // type in that case) | |
476ff2be | 667 | let mut all_arms_diverge = Diverges::WarnedAlways; |
cc61c64b XL |
668 | |
669 | let expected = expected.adjust_for_branches(self); | |
670 | ||
671 | let mut coercion = { | |
672 | let coerce_first = match expected { | |
673 | // We don't coerce to `()` so that if the match expression is a | |
674 | // statement it's branches can have any consistent type. That allows | |
675 | // us to give better error messages (pointing to a usually better | |
676 | // arm for inconsistent arms or to the whole match when a `()` type | |
677 | // is required). | |
b7449926 | 678 | Expectation::ExpectHasType(ety) if ety != self.tcx.mk_unit() => ety, |
cc61c64b XL |
679 | _ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)), |
680 | }; | |
681 | CoerceMany::with_coercion_sites(coerce_first, arms) | |
54a0048b | 682 | }; |
9e0c209e | 683 | |
9fa01778 XL |
684 | let mut other_arms = vec![]; // used only for diagnostics |
685 | let mut prior_arm_ty = None; | |
476ff2be | 686 | for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { |
48663c56 | 687 | if let Some(g) = &arm.guard { |
476ff2be | 688 | self.diverges.set(pats_diverge); |
b7449926 XL |
689 | match g { |
690 | hir::Guard::If(e) => self.check_expr_has_type_or_error(e, tcx.types.bool), | |
691 | }; | |
a7813a04 | 692 | } |
476ff2be SL |
693 | |
694 | self.diverges.set(pats_diverge); | |
9e0c209e | 695 | let arm_ty = self.check_expr_with_expectation(&arm.body, expected); |
476ff2be | 696 | all_arms_diverge &= self.diverges.get(); |
1a4d82fc | 697 | |
48663c56 XL |
698 | let span = expr.span; |
699 | ||
700 | if source_if { | |
701 | let then_expr = &arms[0].body; | |
702 | match (i, if_no_else) { | |
703 | (0, _) => coercion.coerce(self, &self.misc(span), then_expr, arm_ty), | |
704 | (_, true) => self.if_fallback_coercion(span, then_expr, &mut coercion), | |
705 | (_, _) => { | |
706 | let then_ty = prior_arm_ty.unwrap(); | |
707 | let cause = self.if_cause(span, then_expr, &arm.body, then_ty, arm_ty); | |
708 | coercion.coerce(self, &cause, &arm.body, arm_ty); | |
709 | } | |
a7813a04 | 710 | } |
a7813a04 | 711 | } else { |
48663c56 XL |
712 | let arm_span = if let hir::ExprKind::Block(blk, _) = &arm.body.node { |
713 | // Point at the block expr instead of the entire block | |
714 | blk.expr.as_ref().map(|e| e.span).unwrap_or(arm.body.span) | |
715 | } else { | |
716 | arm.body.span | |
717 | }; | |
718 | let (span, code) = match i { | |
9fa01778 XL |
719 | // The reason for the first arm to fail is not that the match arms diverge, |
720 | // but rather that there's a prior obligation that doesn't hold. | |
48663c56 XL |
721 | 0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)), |
722 | _ => (span, ObligationCauseCode::MatchExpressionArm { | |
9fa01778 XL |
723 | arm_span, |
724 | source: match_src, | |
725 | prior_arms: other_arms.clone(), | |
726 | last_ty: prior_arm_ty.unwrap(), | |
48663c56 XL |
727 | discrim_hir_id: discrim.hir_id, |
728 | }), | |
9fa01778 | 729 | }; |
48663c56 | 730 | let cause = self.cause(span, code); |
94b46f34 | 731 | coercion.coerce(self, &cause, &arm.body, arm_ty); |
48663c56 XL |
732 | other_arms.push(arm_span); |
733 | if other_arms.len() > 5 { | |
734 | other_arms.remove(0); | |
735 | } | |
9fa01778 XL |
736 | } |
737 | prior_arm_ty = Some(arm_ty); | |
1a4d82fc | 738 | } |
1a4d82fc | 739 | |
476ff2be SL |
740 | // We won't diverge unless the discriminant or all arms diverge. |
741 | self.diverges.set(discrim_diverges | all_arms_diverge); | |
742 | ||
cc61c64b | 743 | coercion.complete(self) |
92a42be0 | 744 | } |
92a42be0 | 745 | |
48663c56 XL |
746 | /// When the previously checked expression (the scrutinee) diverges, |
747 | /// warn the user about the match arms being unreachable. | |
748 | fn warn_arms_when_scrutinee_diverges(&self, arms: &'gcx [hir::Arm], source_if: bool) { | |
749 | if self.diverges.get().always() { | |
750 | let msg = if source_if { "block in `if` expression" } else { "arm" }; | |
751 | for arm in arms { | |
752 | self.warn_if_unreachable(arm.body.hir_id, arm.body.span, msg); | |
753 | } | |
754 | } | |
755 | } | |
756 | ||
757 | /// Handle the fallback arm of a desugared if(-let) like a missing else. | |
758 | fn if_fallback_coercion( | |
759 | &self, | |
760 | span: Span, | |
761 | then_expr: &'gcx hir::Expr, | |
762 | coercion: &mut CoerceMany<'gcx, 'tcx, '_, rustc::hir::Arm>, | |
763 | ) { | |
764 | // If this `if` expr is the parent's function return expr, | |
765 | // the cause of the type coercion is the return type, point at it. (#25228) | |
766 | let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, span); | |
767 | let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse); | |
768 | coercion.coerce_forced_unit(self, &cause, &mut |err| { | |
769 | if let Some((span, msg)) = &ret_reason { | |
770 | err.span_label(*span, msg.as_str()); | |
771 | } else if let ExprKind::Block(block, _) = &then_expr.node { | |
772 | if let Some(expr) = &block.expr { | |
773 | err.span_label(expr.span, "found here".to_string()); | |
774 | } | |
775 | } | |
776 | err.note("`if` expressions without `else` evaluate to `()`"); | |
777 | err.help("consider adding an `else` block that evaluates to the expected type"); | |
778 | }, ret_reason.is_none()); | |
779 | } | |
780 | ||
781 | fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, span: Span) -> Option<(Span, String)> { | |
782 | use hir::Node::{Block, Item, Local}; | |
783 | ||
784 | let node = self.tcx.hir().get_by_hir_id(self.tcx.hir().get_parent_node_by_hir_id( | |
785 | self.tcx.hir().get_parent_node_by_hir_id(hir_id), | |
786 | )); | |
787 | if let Block(block) = node { | |
788 | // check that the body's parent is an fn | |
789 | let parent = self.tcx.hir().get_by_hir_id( | |
790 | self.tcx.hir().get_parent_node_by_hir_id( | |
791 | self.tcx.hir().get_parent_node_by_hir_id(block.hir_id), | |
792 | ), | |
793 | ); | |
794 | if let (Some(expr), Item(hir::Item { | |
795 | node: hir::ItemKind::Fn(..), .. | |
796 | })) = (&block.expr, parent) { | |
797 | // check that the `if` expr without `else` is the fn body's expr | |
798 | if expr.span == span { | |
799 | return self.get_fn_decl(hir_id).map(|(fn_decl, _)| ( | |
800 | fn_decl.output.span(), | |
801 | format!("expected `{}` because of this return type", fn_decl.output), | |
802 | )); | |
803 | } | |
804 | } | |
805 | } | |
806 | if let Local(hir::Local { ty: Some(_), pat, .. }) = node { | |
807 | return Some((pat.span, "expected because of this assignment".to_string())); | |
808 | } | |
809 | None | |
810 | } | |
811 | ||
812 | fn if_cause( | |
813 | &self, | |
814 | span: Span, | |
815 | then_expr: &'gcx hir::Expr, | |
816 | else_expr: &'gcx hir::Expr, | |
817 | then_ty: Ty<'tcx>, | |
818 | else_ty: Ty<'tcx>, | |
819 | ) -> ObligationCause<'tcx> { | |
820 | let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) { | |
821 | // The `if`/`else` isn't in one line in the output, include some context to make it | |
822 | // clear it is an if/else expression: | |
823 | // ``` | |
824 | // LL | let x = if true { | |
825 | // | _____________- | |
826 | // LL || 10i32 | |
827 | // || ----- expected because of this | |
828 | // LL || } else { | |
829 | // LL || 10u32 | |
830 | // || ^^^^^ expected i32, found u32 | |
831 | // LL || }; | |
832 | // ||_____- if and else have incompatible types | |
833 | // ``` | |
834 | Some(span) | |
835 | } else { | |
836 | // The entire expression is in one line, only point at the arms | |
837 | // ``` | |
838 | // LL | let x = if true { 10i32 } else { 10u32 }; | |
839 | // | ----- ^^^^^ expected i32, found u32 | |
840 | // | | | |
841 | // | expected because of this | |
842 | // ``` | |
843 | None | |
844 | }; | |
845 | ||
846 | let mut remove_semicolon = None; | |
847 | let error_sp = if let ExprKind::Block(block, _) = &else_expr.node { | |
848 | if let Some(expr) = &block.expr { | |
849 | expr.span | |
850 | } else if let Some(stmt) = block.stmts.last() { | |
851 | // possibly incorrect trailing `;` in the else arm | |
852 | remove_semicolon = self.could_remove_semicolon(block, then_ty); | |
853 | stmt.span | |
854 | } else { // empty block, point at its entirety | |
855 | // Avoid overlapping spans that aren't as readable: | |
856 | // ``` | |
857 | // 2 | let x = if true { | |
858 | // | _____________- | |
859 | // 3 | | 3 | |
860 | // | | - expected because of this | |
861 | // 4 | | } else { | |
862 | // | |____________^ | |
863 | // 5 | || | |
864 | // 6 | || }; | |
865 | // | || ^ | |
866 | // | ||_____| | |
867 | // | |______if and else have incompatible types | |
868 | // | expected integer, found () | |
869 | // ``` | |
870 | // by not pointing at the entire expression: | |
871 | // ``` | |
872 | // 2 | let x = if true { | |
873 | // | ------- if and else have incompatible types | |
874 | // 3 | 3 | |
875 | // | - expected because of this | |
876 | // 4 | } else { | |
877 | // | ____________^ | |
878 | // 5 | | | |
879 | // 6 | | }; | |
880 | // | |_____^ expected integer, found () | |
881 | // ``` | |
882 | if outer_sp.is_some() { | |
883 | outer_sp = Some(self.tcx.sess.source_map().def_span(span)); | |
884 | } | |
885 | else_expr.span | |
886 | } | |
887 | } else { // shouldn't happen unless the parser has done something weird | |
888 | else_expr.span | |
889 | }; | |
890 | ||
891 | // Compute `Span` of `then` part of `if`-expression: | |
892 | let then_sp = if let ExprKind::Block(block, _) = &then_expr.node { | |
893 | if let Some(expr) = &block.expr { | |
894 | expr.span | |
895 | } else if let Some(stmt) = block.stmts.last() { | |
896 | // possibly incorrect trailing `;` in the else arm | |
897 | remove_semicolon = remove_semicolon.or(self.could_remove_semicolon(block, else_ty)); | |
898 | stmt.span | |
899 | } else { // empty block, point at its entirety | |
900 | outer_sp = None; // same as in `error_sp`, cleanup output | |
901 | then_expr.span | |
902 | } | |
903 | } else { // shouldn't happen unless the parser has done something weird | |
904 | then_expr.span | |
905 | }; | |
906 | ||
907 | // Finally construct the cause: | |
908 | self.cause(error_sp, ObligationCauseCode::IfExpression { | |
909 | then: then_sp, | |
910 | outer: outer_sp, | |
911 | semicolon: remove_semicolon, | |
912 | }) | |
913 | } | |
914 | ||
915 | fn demand_discriminant_type( | |
916 | &self, | |
917 | arms: &'gcx [hir::Arm], | |
918 | discrim: &'gcx hir::Expr, | |
919 | ) -> Ty<'tcx> { | |
920 | // Not entirely obvious: if matches may create ref bindings, we want to | |
921 | // use the *precise* type of the discriminant, *not* some supertype, as | |
922 | // the "discriminant type" (issue #23116). | |
923 | // | |
924 | // arielb1 [writes here in this comment thread][c] that there | |
925 | // is certainly *some* potential danger, e.g., for an example | |
926 | // like: | |
927 | // | |
928 | // [c]: https://github.com/rust-lang/rust/pull/43399#discussion_r130223956 | |
929 | // | |
930 | // ``` | |
931 | // let Foo(x) = f()[0]; | |
932 | // ``` | |
933 | // | |
934 | // Then if the pattern matches by reference, we want to match | |
935 | // `f()[0]` as a lexpr, so we can't allow it to be | |
936 | // coerced. But if the pattern matches by value, `f()[0]` is | |
937 | // still syntactically a lexpr, but we *do* want to allow | |
938 | // coercions. | |
939 | // | |
940 | // However, *likely* we are ok with allowing coercions to | |
941 | // happen if there are no explicit ref mut patterns - all | |
942 | // implicit ref mut patterns must occur behind a reference, so | |
943 | // they will have the "correct" variance and lifetime. | |
944 | // | |
945 | // This does mean that the following pattern would be legal: | |
946 | // | |
947 | // ``` | |
948 | // struct Foo(Bar); | |
949 | // struct Bar(u32); | |
950 | // impl Deref for Foo { | |
951 | // type Target = Bar; | |
952 | // fn deref(&self) -> &Bar { &self.0 } | |
953 | // } | |
954 | // impl DerefMut for Foo { | |
955 | // fn deref_mut(&mut self) -> &mut Bar { &mut self.0 } | |
956 | // } | |
957 | // fn foo(x: &mut Foo) { | |
958 | // { | |
959 | // let Bar(z): &mut Bar = x; | |
960 | // *z = 42; | |
961 | // } | |
962 | // assert_eq!(foo.0.0, 42); | |
963 | // } | |
964 | // ``` | |
965 | // | |
966 | // FIXME(tschottdorf): don't call contains_explicit_ref_binding, which | |
967 | // is problematic as the HIR is being scraped, but ref bindings may be | |
968 | // implicit after #42640. We need to make sure that pat_adjustments | |
969 | // (once introduced) is populated by the time we get here. | |
970 | // | |
971 | // See #44848. | |
972 | let contains_ref_bindings = arms.iter() | |
973 | .filter_map(|a| a.contains_explicit_ref_binding()) | |
974 | .max_by_key(|m| match *m { | |
975 | hir::MutMutable => 1, | |
976 | hir::MutImmutable => 0, | |
977 | }); | |
978 | ||
979 | if let Some(m) = contains_ref_bindings { | |
980 | self.check_expr_with_needs(discrim, Needs::maybe_mut_place(m)) | |
981 | } else { | |
982 | // ...but otherwise we want to use any supertype of the | |
983 | // discriminant. This is sort of a workaround, see note (*) in | |
984 | // `check_pat` for some details. | |
985 | let discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span)); | |
986 | self.check_expr_has_type_or_error(discrim, discrim_ty); | |
987 | discrim_ty | |
988 | } | |
989 | } | |
990 | ||
0731742a XL |
991 | fn check_pat_struct( |
992 | &self, | |
993 | pat: &'gcx hir::Pat, | |
994 | qpath: &hir::QPath, | |
995 | fields: &'gcx [Spanned<hir::FieldPat>], | |
996 | etc: bool, | |
997 | expected: Ty<'tcx>, | |
998 | def_bm: ty::BindingMode, | |
48663c56 | 999 | discrim_span: Option<Span>, |
0731742a | 1000 | ) -> Ty<'tcx> |
5bcae85e SL |
1001 | { |
1002 | // Resolve the path and check the definition for errors. | |
532ac7d7 XL |
1003 | let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.hir_id) |
1004 | { | |
5bcae85e SL |
1005 | variant_ty |
1006 | } else { | |
5bcae85e | 1007 | for field in fields { |
48663c56 | 1008 | self.check_pat_walk(&field.node.pat, self.tcx.types.err, def_bm, discrim_span); |
9cc50fc6 | 1009 | } |
9e0c209e | 1010 | return self.tcx.types.err; |
a7813a04 | 1011 | }; |
9cc50fc6 | 1012 | |
0731742a | 1013 | // Type-check the path. |
48663c56 | 1014 | self.demand_eqtype_pat(pat.span, expected, pat_ty, discrim_span); |
5bcae85e | 1015 | |
0731742a | 1016 | // Type-check subpatterns. |
532ac7d7 XL |
1017 | if self.check_struct_pat_fields(pat_ty, pat.hir_id, pat.span, variant, fields, etc, def_bm) |
1018 | { | |
83c7162d XL |
1019 | pat_ty |
1020 | } else { | |
1021 | self.tcx.types.err | |
1022 | } | |
d9579d0f AL |
1023 | } |
1024 | ||
0731742a XL |
1025 | fn check_pat_path( |
1026 | &self, | |
1027 | pat: &hir::Pat, | |
1028 | qpath: &hir::QPath, | |
1029 | expected: Ty<'tcx>, | |
1030 | ) -> Ty<'tcx> { | |
a7813a04 | 1031 | let tcx = self.tcx; |
1a4d82fc | 1032 | |
5bcae85e | 1033 | // Resolve the path and check the definition for errors. |
48663c56 XL |
1034 | let (res, opt_ty, segments) = self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span); |
1035 | match res { | |
1036 | Res::Err => { | |
5bcae85e | 1037 | self.set_tainted_by_errors(); |
9e0c209e | 1038 | return tcx.types.err; |
5bcae85e | 1039 | } |
48663c56 XL |
1040 | Res::Def(DefKind::Method, _) => { |
1041 | report_unexpected_variant_res(tcx, res, pat.span, qpath); | |
0731742a XL |
1042 | return tcx.types.err; |
1043 | } | |
48663c56 XL |
1044 | Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) | |
1045 | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => { | |
1046 | report_unexpected_variant_res(tcx, res, pat.span, qpath); | |
9e0c209e | 1047 | return tcx.types.err; |
5bcae85e | 1048 | } |
48663c56 XL |
1049 | Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::SelfCtor(..) | |
1050 | Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssociatedConst, _) => {} // OK | |
1051 | _ => bug!("unexpected pattern resolution: {:?}", res) | |
1a4d82fc | 1052 | } |
1a4d82fc | 1053 | |
0731742a | 1054 | // Type-check the path. |
48663c56 | 1055 | let pat_ty = self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id).0; |
5bcae85e | 1056 | self.demand_suptype(pat.span, expected, pat_ty); |
9e0c209e | 1057 | pat_ty |
5bcae85e | 1058 | } |
7453a54e | 1059 | |
0731742a XL |
1060 | fn check_pat_tuple_struct( |
1061 | &self, | |
1062 | pat: &hir::Pat, | |
1063 | qpath: &hir::QPath, | |
1064 | subpats: &'gcx [P<hir::Pat>], | |
1065 | ddpos: Option<usize>, | |
1066 | expected: Ty<'tcx>, | |
1067 | def_bm: ty::BindingMode, | |
1068 | match_arm_pat_span: Option<Span>, | |
1069 | ) -> Ty<'tcx> { | |
5bcae85e SL |
1070 | let tcx = self.tcx; |
1071 | let on_error = || { | |
3157f602 | 1072 | for pat in subpats { |
0731742a | 1073 | self.check_pat_walk(&pat, tcx.types.err, def_bm, match_arm_pat_span); |
1a4d82fc | 1074 | } |
a7813a04 | 1075 | }; |
48663c56 | 1076 | let report_unexpected_res = |res: Res| { |
c30ab7b3 | 1077 | let msg = format!("expected tuple struct/variant, found {} `{}`", |
48663c56 | 1078 | res.descr(), |
0731742a | 1079 | hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false))); |
c30ab7b3 | 1080 | struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg) |
7cac9316 | 1081 | .span_label(pat.span, "not a tuple variant or struct").emit(); |
c30ab7b3 | 1082 | on_error(); |
5bcae85e | 1083 | }; |
a7813a04 | 1084 | |
5bcae85e | 1085 | // Resolve the path and check the definition for errors. |
48663c56 XL |
1086 | let (res, opt_ty, segments) = self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span); |
1087 | if res == Res::Err { | |
b7449926 XL |
1088 | self.set_tainted_by_errors(); |
1089 | on_error(); | |
1090 | return self.tcx.types.err; | |
1091 | } | |
1092 | ||
0731742a | 1093 | // Type-check the path. |
48663c56 | 1094 | let (pat_ty, res) = self.instantiate_value_path(segments, opt_ty, res, pat.span, |
532ac7d7 | 1095 | pat.hir_id); |
b7449926 | 1096 | if !pat_ty.is_fn() { |
48663c56 | 1097 | report_unexpected_res(res); |
b7449926 XL |
1098 | return self.tcx.types.err; |
1099 | } | |
b7449926 | 1100 | |
48663c56 XL |
1101 | let variant = match res { |
1102 | Res::Err => { | |
5bcae85e SL |
1103 | self.set_tainted_by_errors(); |
1104 | on_error(); | |
9e0c209e | 1105 | return tcx.types.err; |
1a4d82fc | 1106 | } |
48663c56 XL |
1107 | Res::Def(DefKind::AssociatedConst, _) | Res::Def(DefKind::Method, _) => { |
1108 | report_unexpected_res(res); | |
9e0c209e | 1109 | return tcx.types.err; |
a7813a04 | 1110 | } |
48663c56 XL |
1111 | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => { |
1112 | tcx.expect_variant_res(res) | |
a7813a04 | 1113 | } |
48663c56 | 1114 | _ => bug!("unexpected pattern resolution: {:?}", res) |
5bcae85e | 1115 | }; |
13cf67c4 XL |
1116 | |
1117 | // Replace constructor type with constructed type for tuple struct patterns. | |
1118 | let pat_ty = pat_ty.fn_sig(tcx).output(); | |
a1dfa0c6 | 1119 | let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); |
13cf67c4 | 1120 | |
0731742a | 1121 | self.demand_eqtype_pat(pat.span, expected, pat_ty, match_arm_pat_span); |
13cf67c4 | 1122 | |
0731742a | 1123 | // Type-check subpatterns. |
3157f602 XL |
1124 | if subpats.len() == variant.fields.len() || |
1125 | subpats.len() < variant.fields.len() && ddpos.is_some() { | |
5bcae85e | 1126 | let substs = match pat_ty.sty { |
b7449926 | 1127 | ty::Adt(_, substs) => substs, |
532ac7d7 | 1128 | _ => bug!("unexpected pattern type {:?}", pat_ty), |
5bcae85e | 1129 | }; |
3157f602 | 1130 | for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { |
5bcae85e | 1131 | let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs); |
0731742a | 1132 | self.check_pat_walk(&subpat, field_ty, def_bm, match_arm_pat_span); |
476ff2be | 1133 | |
532ac7d7 | 1134 | self.tcx.check_stability(variant.fields[i].did, Some(pat.hir_id), subpat.span); |
3157f602 XL |
1135 | } |
1136 | } else { | |
c30ab7b3 SL |
1137 | let subpats_ending = if subpats.len() == 1 { "" } else { "s" }; |
1138 | let fields_ending = if variant.fields.len() == 1 { "" } else { "s" }; | |
5bcae85e SL |
1139 | struct_span_err!(tcx.sess, pat.span, E0023, |
1140 | "this pattern has {} field{}, but the corresponding {} has {} field{}", | |
48663c56 | 1141 | subpats.len(), subpats_ending, res.descr(), |
5bcae85e | 1142 | variant.fields.len(), fields_ending) |
7cac9316 | 1143 | .span_label(pat.span, format!("expected {} field{}, found {}", |
0bf4aa26 | 1144 | variant.fields.len(), fields_ending, subpats.len())) |
5bcae85e SL |
1145 | .emit(); |
1146 | on_error(); | |
9e0c209e | 1147 | return tcx.types.err; |
a7813a04 | 1148 | } |
9e0c209e | 1149 | pat_ty |
1a4d82fc JJ |
1150 | } |
1151 | ||
532ac7d7 XL |
1152 | fn check_struct_pat_fields( |
1153 | &self, | |
1154 | adt_ty: Ty<'tcx>, | |
1155 | pat_id: hir::HirId, | |
1156 | span: Span, | |
1157 | variant: &'tcx ty::VariantDef, | |
1158 | fields: &'gcx [Spanned<hir::FieldPat>], | |
1159 | etc: bool, | |
1160 | def_bm: ty::BindingMode, | |
1161 | ) -> bool { | |
a7813a04 XL |
1162 | let tcx = self.tcx; |
1163 | ||
abe05a73 | 1164 | let (substs, adt) = match adt_ty.sty { |
b7449926 | 1165 | ty::Adt(adt, substs) => (substs, adt), |
9e0c209e SL |
1166 | _ => span_bug!(span, "struct pattern is not an ADT") |
1167 | }; | |
abe05a73 | 1168 | let kind_name = adt.variant_descr(); |
9e0c209e | 1169 | |
a7813a04 XL |
1170 | // Index the struct fields' types. |
1171 | let field_map = variant.fields | |
1a4d82fc | 1172 | .iter() |
83c7162d | 1173 | .enumerate() |
94b46f34 | 1174 | .map(|(i, field)| (field.ident.modern(), (i, field))) |
476ff2be | 1175 | .collect::<FxHashMap<_, _>>(); |
a7813a04 XL |
1176 | |
1177 | // Keep track of which fields have already appeared in the pattern. | |
0bf4aa26 | 1178 | let mut used_fields = FxHashMap::default(); |
83c7162d | 1179 | let mut no_field_errors = true; |
a7813a04 | 1180 | |
0531ce1d | 1181 | let mut inexistent_fields = vec![]; |
a7813a04 XL |
1182 | // Typecheck each field. |
1183 | for &Spanned { node: ref field, span } in fields { | |
532ac7d7 | 1184 | let ident = tcx.adjust_ident(field.ident, variant.def_id, self.body_id).0; |
83c7162d | 1185 | let field_ty = match used_fields.entry(ident) { |
a7813a04 | 1186 | Occupied(occupied) => { |
c30ab7b3 SL |
1187 | struct_span_err!(tcx.sess, span, E0025, |
1188 | "field `{}` bound multiple times \ | |
1189 | in the pattern", | |
94b46f34 | 1190 | field.ident) |
c30ab7b3 | 1191 | .span_label(span, |
94b46f34 XL |
1192 | format!("multiple uses of `{}` in pattern", field.ident)) |
1193 | .span_label(*occupied.get(), format!("first use of `{}`", field.ident)) | |
c30ab7b3 | 1194 | .emit(); |
83c7162d | 1195 | no_field_errors = false; |
a7813a04 XL |
1196 | tcx.types.err |
1197 | } | |
1198 | Vacant(vacant) => { | |
1199 | vacant.insert(span); | |
83c7162d XL |
1200 | field_map.get(&ident) |
1201 | .map(|(i, f)| { | |
532ac7d7 | 1202 | self.write_field_index(field.hir_id, *i); |
0531ce1d | 1203 | self.tcx.check_stability(f.did, Some(pat_id), span); |
476ff2be SL |
1204 | self.field_ty(span, f, substs) |
1205 | }) | |
a7813a04 | 1206 | .unwrap_or_else(|| { |
532ac7d7 | 1207 | inexistent_fields.push(field.ident); |
83c7162d | 1208 | no_field_errors = false; |
a7813a04 XL |
1209 | tcx.types.err |
1210 | }) | |
1211 | } | |
1212 | }; | |
1213 | ||
0731742a | 1214 | self.check_pat_walk(&field.pat, field_ty, def_bm, None); |
a7813a04 | 1215 | } |
0bf4aa26 XL |
1216 | let mut unmentioned_fields = variant.fields |
1217 | .iter() | |
1218 | .map(|field| field.ident.modern()) | |
1219 | .filter(|ident| !used_fields.contains_key(&ident)) | |
1220 | .collect::<Vec<_>>(); | |
532ac7d7 | 1221 | if inexistent_fields.len() > 0 && !variant.recovered { |
0531ce1d | 1222 | let (field_names, t, plural) = if inexistent_fields.len() == 1 { |
532ac7d7 | 1223 | (format!("a field named `{}`", inexistent_fields[0]), "this", "") |
0531ce1d XL |
1224 | } else { |
1225 | (format!("fields named {}", | |
1226 | inexistent_fields.iter() | |
532ac7d7 | 1227 | .map(|ident| format!("`{}`", ident)) |
0531ce1d XL |
1228 | .collect::<Vec<String>>() |
1229 | .join(", ")), "these", "s") | |
1230 | }; | |
532ac7d7 | 1231 | let spans = inexistent_fields.iter().map(|ident| ident.span).collect::<Vec<_>>(); |
0531ce1d XL |
1232 | let mut err = struct_span_err!(tcx.sess, |
1233 | spans, | |
1234 | E0026, | |
1235 | "{} `{}` does not have {}", | |
1236 | kind_name, | |
532ac7d7 | 1237 | tcx.def_path_str(variant.def_id), |
0531ce1d | 1238 | field_names); |
532ac7d7 XL |
1239 | if let Some(ident) = inexistent_fields.last() { |
1240 | err.span_label(ident.span, | |
0531ce1d XL |
1241 | format!("{} `{}` does not have {} field{}", |
1242 | kind_name, | |
532ac7d7 | 1243 | tcx.def_path_str(variant.def_id), |
0531ce1d XL |
1244 | t, |
1245 | plural)); | |
0bf4aa26 XL |
1246 | if plural == "" { |
1247 | let input = unmentioned_fields.iter().map(|field| &field.name); | |
1248 | let suggested_name = | |
0731742a | 1249 | find_best_match_for_name(input, &ident.as_str(), None); |
0bf4aa26 | 1250 | if let Some(suggested_name) = suggested_name { |
9fa01778 | 1251 | err.span_suggestion( |
532ac7d7 XL |
1252 | ident.span, |
1253 | "a field with a similar name exists", | |
9fa01778 XL |
1254 | suggested_name.to_string(), |
1255 | Applicability::MaybeIncorrect, | |
1256 | ); | |
1257 | ||
0bf4aa26 XL |
1258 | // we don't want to throw `E0027` in case we have thrown `E0026` for them |
1259 | unmentioned_fields.retain(|&x| x.as_str() != suggested_name.as_str()); | |
1260 | } | |
1261 | } | |
0531ce1d XL |
1262 | } |
1263 | if tcx.sess.teach(&err.get_code().unwrap()) { | |
1264 | err.note( | |
1265 | "This error indicates that a struct pattern attempted to \ | |
1266 | extract a non-existent field from a struct. Struct fields \ | |
1267 | are identified by the name used before the colon : so struct \ | |
1268 | patterns should resemble the declaration of the struct type \ | |
1269 | being matched.\n\n\ | |
1270 | If you are using shorthand field patterns but want to refer \ | |
1271 | to the struct field by a different name, you should rename \ | |
1272 | it explicitly." | |
1273 | ); | |
1274 | } | |
1275 | err.emit(); | |
1276 | } | |
1277 | ||
abe05a73 | 1278 | // Require `..` if struct has non_exhaustive attribute. |
b7449926 | 1279 | if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc { |
abe05a73 XL |
1280 | span_err!(tcx.sess, span, E0638, |
1281 | "`..` required with {} marked as non-exhaustive", | |
1282 | kind_name); | |
1283 | } | |
1284 | ||
9e0c209e SL |
1285 | // Report an error if incorrect number of the fields were specified. |
1286 | if kind_name == "union" { | |
1287 | if fields.len() != 1 { | |
1288 | tcx.sess.span_err(span, "union patterns should have exactly one field"); | |
1289 | } | |
1290 | if etc { | |
1291 | tcx.sess.span_err(span, "`..` cannot be used in union patterns"); | |
1292 | } | |
1293 | } else if !etc { | |
0531ce1d XL |
1294 | if unmentioned_fields.len() > 0 { |
1295 | let field_names = if unmentioned_fields.len() == 1 { | |
1296 | format!("field `{}`", unmentioned_fields[0]) | |
1297 | } else { | |
1298 | format!("fields {}", | |
1299 | unmentioned_fields.iter() | |
1300 | .map(|name| format!("`{}`", name)) | |
1301 | .collect::<Vec<String>>() | |
1302 | .join(", ")) | |
1303 | }; | |
ea8adc8c | 1304 | let mut diag = struct_span_err!(tcx.sess, span, E0027, |
0531ce1d XL |
1305 | "pattern does not mention {}", |
1306 | field_names); | |
1307 | diag.span_label(span, format!("missing {}", field_names)); | |
ea8adc8c XL |
1308 | if variant.ctor_kind == CtorKind::Fn { |
1309 | diag.note("trying to match a tuple variant with a struct variant pattern"); | |
1310 | } | |
2c00a5a8 XL |
1311 | if tcx.sess.teach(&diag.get_code().unwrap()) { |
1312 | diag.note( | |
1313 | "This error indicates that a pattern for a struct fails to specify a \ | |
1314 | sub-pattern for every one of the struct's fields. Ensure that each field \ | |
1315 | from the struct's definition is mentioned in the pattern, or use `..` to \ | |
1316 | ignore unwanted fields." | |
1317 | ); | |
1318 | } | |
ea8adc8c | 1319 | diag.emit(); |
a7813a04 | 1320 | } |
1a4d82fc | 1321 | } |
83c7162d | 1322 | no_field_errors |
1a4d82fc JJ |
1323 | } |
1324 | } |