]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
c30ab7b3 SL |
11 | use rustc::hir::{self, PatKind}; |
12 | use rustc::hir::def::{Def, CtorKind}; | |
13 | use rustc::hir::pat_util::EnumerateAndAdjustIterator; | |
476ff2be SL |
14 | use rustc::infer; |
15 | use rustc::infer::type_variable::TypeVariableOrigin; | |
16 | use rustc::traits::ObligationCauseCode; | |
c30ab7b3 | 17 | use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; |
476ff2be | 18 | use check::{FnCtxt, Expectation, Diverges}; |
cc61c64b | 19 | use check::coercion::CoerceMany; |
476ff2be | 20 | use util::nodemap::FxHashMap; |
1a4d82fc | 21 | |
1a4d82fc | 22 | use std::collections::hash_map::Entry::{Occupied, Vacant}; |
3157f602 | 23 | use std::cmp; |
1a4d82fc | 24 | use syntax::ast; |
3157f602 | 25 | use syntax::codemap::Spanned; |
abe05a73 | 26 | use syntax::feature_gate; |
1a4d82fc | 27 | use syntax::ptr::P; |
3157f602 | 28 | use syntax_pos::Span; |
1a4d82fc | 29 | |
3157f602 | 30 | impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { |
32a655c1 SL |
31 | /// The `is_arg` argument indicates whether this pattern is the |
32 | /// *outermost* pattern in an argument (e.g., in `fn foo(&x: | |
33 | /// &u32)`, it is true for the `&x` pattern but not `x`). This is | |
34 | /// used to tailor error reporting. | |
ea8adc8c XL |
35 | pub fn check_pat_walk( |
36 | &self, | |
37 | pat: &'gcx hir::Pat, | |
38 | mut expected: Ty<'tcx>, | |
39 | mut def_bm: ty::BindingMode, | |
40 | is_arg: bool) | |
41 | { | |
a7813a04 XL |
42 | let tcx = self.tcx; |
43 | ||
ea8adc8c XL |
44 | debug!("check_pat_walk(pat={:?},expected={:?},def_bm={:?},is_arg={})", |
45 | pat, expected, def_bm, is_arg); | |
46 | ||
47 | let is_non_ref_pat = match pat.node { | |
48 | PatKind::Struct(..) | | |
49 | PatKind::TupleStruct(..) | | |
50 | PatKind::Tuple(..) | | |
51 | PatKind::Box(_) | | |
52 | PatKind::Range(..) | | |
53 | PatKind::Slice(..) => true, | |
54 | PatKind::Lit(ref lt) => { | |
55 | let ty = self.check_expr(lt); | |
56 | match ty.sty { | |
57 | ty::TypeVariants::TyRef(..) => false, | |
58 | _ => true, | |
59 | } | |
60 | } | |
61 | PatKind::Path(ref qpath) => { | |
62 | let (def, _, _) = self.resolve_ty_and_def_ufcs(qpath, pat.id, pat.span); | |
63 | match def { | |
64 | Def::Const(..) | Def::AssociatedConst(..) => false, | |
65 | _ => true, | |
66 | } | |
67 | } | |
68 | PatKind::Wild | | |
69 | PatKind::Binding(..) | | |
70 | PatKind::Ref(..) => false, | |
71 | }; | |
abe05a73 | 72 | if is_non_ref_pat { |
ea8adc8c XL |
73 | debug!("pattern is non reference pattern"); |
74 | let mut exp_ty = self.resolve_type_vars_with_obligations(&expected); | |
75 | ||
76 | // Peel off as many `&` or `&mut` from the discriminant as possible. For example, | |
77 | // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches | |
78 | // the `Some(5)` which is not of type TyRef. | |
79 | // | |
80 | // For each ampersand peeled off, update the binding mode and push the original | |
81 | // type into the adjustments vector. | |
82 | // | |
83 | // See the examples in `run-pass/match-defbm*.rs`. | |
84 | let mut pat_adjustments = vec![]; | |
85 | expected = loop { | |
86 | debug!("inspecting {:?} with type {:?}", exp_ty, exp_ty.sty); | |
87 | match exp_ty.sty { | |
88 | ty::TypeVariants::TyRef(_, ty::TypeAndMut{ | |
89 | ty: inner_ty, mutbl: inner_mutability, | |
90 | }) => { | |
91 | debug!("current discriminant is TyRef, inserting implicit deref"); | |
92 | // Preserve the reference type. We'll need it later during HAIR lowering. | |
93 | pat_adjustments.push(exp_ty); | |
94 | ||
95 | exp_ty = inner_ty; | |
96 | def_bm = match def_bm { | |
97 | // If default binding mode is by value, make it `ref` or `ref mut` | |
98 | // (depending on whether we observe `&` or `&mut`). | |
99 | ty::BindByValue(_) => | |
100 | ty::BindByReference(inner_mutability), | |
101 | ||
102 | // Once a `ref`, always a `ref`. This is because a `& &mut` can't mutate | |
103 | // the underlying value. | |
104 | ty::BindByReference(hir::Mutability::MutImmutable) => | |
105 | ty::BindByReference(hir::Mutability::MutImmutable), | |
106 | ||
107 | // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` | |
108 | // (on `&`). | |
109 | ty::BindByReference(hir::Mutability::MutMutable) => | |
110 | ty::BindByReference(inner_mutability), | |
111 | }; | |
112 | }, | |
113 | _ => break exp_ty, | |
114 | } | |
115 | }; | |
116 | if pat_adjustments.len() > 0 { | |
abe05a73 XL |
117 | if tcx.sess.features.borrow().match_default_bindings { |
118 | debug!("default binding mode is now {:?}", def_bm); | |
119 | self.inh.tables.borrow_mut() | |
120 | .pat_adjustments_mut() | |
121 | .insert(pat.hir_id, pat_adjustments); | |
122 | } else { | |
123 | let mut err = feature_gate::feature_err( | |
124 | &tcx.sess.parse_sess, | |
125 | "match_default_bindings", | |
126 | pat.span, | |
127 | feature_gate::GateIssue::Language, | |
128 | "non-reference pattern used to match a reference", | |
129 | ); | |
130 | if let Ok(snippet) = tcx.sess.codemap().span_to_snippet(pat.span) { | |
131 | err.span_suggestion(pat.span, "consider using", format!("&{}", &snippet)); | |
132 | } | |
133 | err.emit(); | |
134 | } | |
ea8adc8c XL |
135 | } |
136 | } | |
137 | ||
138 | // Lose mutability now that we know binding mode and discriminant type. | |
139 | let def_bm = def_bm; | |
140 | let expected = expected; | |
a7813a04 | 141 | |
9e0c209e | 142 | let ty = match pat.node { |
a7813a04 | 143 | PatKind::Wild => { |
9e0c209e | 144 | expected |
a7813a04 XL |
145 | } |
146 | PatKind::Lit(ref lt) => { | |
ea8adc8c XL |
147 | // We've already computed the type above (when checking for a non-ref pat), so |
148 | // avoid computing it again. | |
149 | let ty = self.node_ty(lt.hir_id); | |
a7813a04 XL |
150 | |
151 | // Byte string patterns behave the same way as array patterns | |
152 | // They can denote both statically and dynamically sized byte arrays | |
9e0c209e | 153 | let mut pat_ty = ty; |
a7813a04 XL |
154 | if let hir::ExprLit(ref lt) = lt.node { |
155 | if let ast::LitKind::ByteStr(_) = lt.node { | |
156 | let expected_ty = self.structurally_resolved_type(pat.span, expected); | |
157 | if let ty::TyRef(_, mt) = expected_ty.sty { | |
158 | if let ty::TySlice(_) = mt.ty.sty { | |
cc61c64b | 159 | pat_ty = tcx.mk_imm_ref(tcx.types.re_static, |
a7813a04 XL |
160 | tcx.mk_slice(tcx.types.u8)) |
161 | } | |
c34b1796 AL |
162 | } |
163 | } | |
164 | } | |
c34b1796 | 165 | |
a7813a04 XL |
166 | // somewhat surprising: in this case, the subtyping |
167 | // relation goes the opposite way as the other | |
168 | // cases. Actually what we really want is not a subtyping | |
169 | // relation at all but rather that there exists a LUB (so | |
170 | // that they can be compared). However, in practice, | |
171 | // constants are always scalars or strings. For scalars | |
9e0c209e | 172 | // subtyping is irrelevant, and for strings `ty` is |
a7813a04 XL |
173 | // type is `&'static str`, so if we say that |
174 | // | |
175 | // &'static str <: expected | |
176 | // | |
177 | // that's equivalent to there existing a LUB. | |
178 | self.demand_suptype(pat.span, expected, pat_ty); | |
9e0c209e | 179 | pat_ty |
62682a34 | 180 | } |
32a655c1 | 181 | PatKind::Range(ref begin, ref end, _) => { |
9e0c209e SL |
182 | let lhs_ty = self.check_expr(begin); |
183 | let rhs_ty = self.check_expr(end); | |
a7813a04 XL |
184 | |
185 | // Check that both end-points are of numeric or char type. | |
186 | let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char(); | |
187 | let lhs_compat = numeric_or_char(lhs_ty); | |
188 | let rhs_compat = numeric_or_char(rhs_ty); | |
189 | ||
190 | if !lhs_compat || !rhs_compat { | |
191 | let span = if !lhs_compat && !rhs_compat { | |
192 | pat.span | |
193 | } else if !lhs_compat { | |
194 | begin.span | |
195 | } else { | |
196 | end.span | |
197 | }; | |
198 | ||
5bcae85e SL |
199 | struct_span_err!(tcx.sess, span, E0029, |
200 | "only char and numeric types are allowed in range patterns") | |
7cac9316 | 201 | .span_label(span, "ranges require char or numeric types") |
5bcae85e SL |
202 | .note(&format!("start type: {}", self.ty_to_string(lhs_ty))) |
203 | .note(&format!("end type: {}", self.ty_to_string(rhs_ty))) | |
204 | .emit(); | |
a7813a04 XL |
205 | return; |
206 | } | |
1a4d82fc | 207 | |
a7813a04 XL |
208 | // Now that we know the types can be unified we find the unified type and use |
209 | // it to type the entire expression. | |
210 | let common_type = self.resolve_type_vars_if_possible(&lhs_ty); | |
62682a34 | 211 | |
a7813a04 XL |
212 | // subtyping doesn't matter here, as the value is some kind of scalar |
213 | self.demand_eqtype(pat.span, expected, lhs_ty); | |
5bcae85e | 214 | self.demand_eqtype(pat.span, expected, rhs_ty); |
9e0c209e | 215 | common_type |
1a4d82fc | 216 | } |
ea8adc8c XL |
217 | PatKind::Binding(ba, var_id, _, ref sub) => { |
218 | let bm = if ba == hir::BindingAnnotation::Unannotated { | |
219 | def_bm | |
220 | } else { | |
221 | ty::BindingMode::convert(ba) | |
222 | }; | |
3b2f2976 XL |
223 | self.inh |
224 | .tables | |
225 | .borrow_mut() | |
226 | .pat_binding_modes_mut() | |
227 | .insert(pat.hir_id, bm); | |
a7813a04 XL |
228 | let typ = self.local_ty(pat.span, pat.id); |
229 | match bm { | |
3b2f2976 | 230 | ty::BindByReference(mutbl) => { |
a7813a04 XL |
231 | // if the binding is like |
232 | // ref x | ref const x | ref mut x | |
233 | // then `x` is assigned a value of type `&M T` where M is the mutability | |
234 | // and T is the expected type. | |
235 | let region_var = self.next_region_var(infer::PatternRegion(pat.span)); | |
236 | let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl }; | |
9e0c209e | 237 | let region_ty = tcx.mk_ref(region_var, mt); |
a7813a04 XL |
238 | |
239 | // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is | |
240 | // required. However, we use equality, which is stronger. See (*) for | |
241 | // an explanation. | |
242 | self.demand_eqtype(pat.span, region_ty, typ); | |
243 | } | |
244 | // otherwise the type of x is the expected type T | |
3b2f2976 | 245 | ty::BindByValue(_) => { |
a7813a04 XL |
246 | // As above, `T <: typeof(x)` is required but we |
247 | // use equality, see (*) below. | |
248 | self.demand_eqtype(pat.span, expected, typ); | |
249 | } | |
250 | } | |
1a4d82fc | 251 | |
a7813a04 XL |
252 | // if there are multiple arms, make sure they all agree on |
253 | // what the type of the binding `x` ought to be | |
476ff2be SL |
254 | if var_id != pat.id { |
255 | let vt = self.local_ty(pat.span, var_id); | |
256 | self.demand_eqtype(pat.span, vt, typ); | |
3157f602 | 257 | } |
1a4d82fc | 258 | |
3157f602 | 259 | if let Some(ref p) = *sub { |
ea8adc8c | 260 | self.check_pat_walk(&p, expected, def_bm, true); |
9cc50fc6 | 261 | } |
9e0c209e SL |
262 | |
263 | typ | |
1a4d82fc | 264 | } |
476ff2be | 265 | PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => { |
ea8adc8c | 266 | self.check_pat_tuple_struct(pat, qpath, &subpats, ddpos, expected, def_bm) |
a7813a04 | 267 | } |
476ff2be SL |
268 | PatKind::Path(ref qpath) => { |
269 | self.check_pat_path(pat, qpath, expected) | |
a7813a04 | 270 | } |
476ff2be | 271 | PatKind::Struct(ref qpath, ref fields, etc) => { |
ea8adc8c | 272 | self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm) |
a7813a04 | 273 | } |
3157f602 XL |
274 | PatKind::Tuple(ref elements, ddpos) => { |
275 | let mut expected_len = elements.len(); | |
276 | if ddpos.is_some() { | |
277 | // Require known type only when `..` is present | |
8bb4bdeb | 278 | if let ty::TyTuple(ref tys, _) = |
3157f602 XL |
279 | self.structurally_resolved_type(pat.span, expected).sty { |
280 | expected_len = tys.len(); | |
281 | } | |
282 | } | |
283 | let max_len = cmp::max(expected_len, elements.len()); | |
284 | ||
476ff2be SL |
285 | let element_tys_iter = (0..max_len).map(|_| self.next_ty_var( |
286 | // FIXME: MiscVariable for now, obtaining the span and name information | |
287 | // from all tuple elements isn't trivial. | |
288 | TypeVariableOrigin::TypeInference(pat.span))); | |
c30ab7b3 | 289 | let element_tys = tcx.mk_type_list(element_tys_iter); |
8bb4bdeb | 290 | let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys, false)); |
a7813a04 | 291 | self.demand_eqtype(pat.span, expected, pat_ty); |
3157f602 | 292 | for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { |
ea8adc8c | 293 | self.check_pat_walk(elem, &element_tys[i], def_bm, true); |
d9579d0f | 294 | } |
9e0c209e | 295 | pat_ty |
a7813a04 XL |
296 | } |
297 | PatKind::Box(ref inner) => { | |
476ff2be | 298 | let inner_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(inner.span)); |
a7813a04 XL |
299 | let uniq_ty = tcx.mk_box(inner_ty); |
300 | ||
301 | if self.check_dereferencable(pat.span, expected, &inner) { | |
302 | // Here, `demand::subtype` is good enough, but I don't | |
303 | // think any errors can be introduced by using | |
304 | // `demand::eqtype`. | |
305 | self.demand_eqtype(pat.span, expected, uniq_ty); | |
ea8adc8c | 306 | self.check_pat_walk(&inner, inner_ty, def_bm, true); |
9e0c209e | 307 | uniq_ty |
d9579d0f | 308 | } else { |
ea8adc8c | 309 | self.check_pat_walk(&inner, tcx.types.err, def_bm, true); |
9e0c209e | 310 | tcx.types.err |
d9579d0f AL |
311 | } |
312 | } | |
a7813a04 XL |
313 | PatKind::Ref(ref inner, mutbl) => { |
314 | let expected = self.shallow_resolve(expected); | |
315 | if self.check_dereferencable(pat.span, expected, &inner) { | |
316 | // `demand::subtype` would be good enough, but using | |
317 | // `eqtype` turns out to be equally general. See (*) | |
318 | // below for details. | |
319 | ||
320 | // Take region, inner-type from expected type if we | |
321 | // can, to avoid creating needless variables. This | |
322 | // also helps with the bad interactions of the given | |
323 | // hack detailed in (*) below. | |
ea8adc8c | 324 | debug!("check_pat_walk: expected={:?}", expected); |
a7813a04 XL |
325 | let (rptr_ty, inner_ty) = match expected.sty { |
326 | ty::TyRef(_, mt) if mt.mutbl == mutbl => { | |
327 | (expected, mt.ty) | |
328 | } | |
329 | _ => { | |
476ff2be SL |
330 | let inner_ty = self.next_ty_var( |
331 | TypeVariableOrigin::TypeInference(inner.span)); | |
a7813a04 XL |
332 | let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; |
333 | let region = self.next_region_var(infer::PatternRegion(pat.span)); | |
9e0c209e | 334 | let rptr_ty = tcx.mk_ref(region, mt); |
ea8adc8c | 335 | debug!("check_pat_walk: demanding {:?} = {:?}", expected, rptr_ty); |
32a655c1 SL |
336 | let err = self.demand_eqtype_diag(pat.span, expected, rptr_ty); |
337 | ||
338 | // Look for a case like `fn foo(&foo: u32)` and suggest | |
339 | // `fn foo(foo: &u32)` | |
340 | if let Some(mut err) = err { | |
341 | if is_arg { | |
342 | if let PatKind::Binding(..) = inner.node { | |
abe05a73 XL |
343 | if let Ok(snippet) = tcx.sess.codemap() |
344 | .span_to_snippet(pat.span) | |
32a655c1 SL |
345 | { |
346 | err.help(&format!("did you mean `{}: &{}`?", | |
347 | &snippet[1..], | |
348 | expected)); | |
349 | } | |
350 | } | |
351 | } | |
352 | err.emit(); | |
353 | } | |
a7813a04 XL |
354 | (rptr_ty, inner_ty) |
355 | } | |
356 | }; | |
b039eaaf | 357 | |
ea8adc8c | 358 | self.check_pat_walk(&inner, inner_ty, def_bm, true); |
9e0c209e | 359 | rptr_ty |
a7813a04 | 360 | } else { |
ea8adc8c | 361 | self.check_pat_walk(&inner, tcx.types.err, def_bm, true); |
9e0c209e | 362 | tcx.types.err |
a7813a04 XL |
363 | } |
364 | } | |
c30ab7b3 | 365 | PatKind::Slice(ref before, ref slice, ref after) => { |
a7813a04 | 366 | let expected_ty = self.structurally_resolved_type(pat.span, expected); |
3157f602 XL |
367 | let (inner_ty, slice_ty) = match expected_ty.sty { |
368 | ty::TyArray(inner_ty, size) => { | |
ea8adc8c XL |
369 | let size = size.val.to_const_int().unwrap().to_u64().unwrap(); |
370 | let min_len = before.len() as u64 + after.len() as u64; | |
3157f602 XL |
371 | if slice.is_none() { |
372 | if min_len != size { | |
9e0c209e SL |
373 | struct_span_err!( |
374 | tcx.sess, pat.span, E0527, | |
375 | "pattern requires {} elements but array has {}", | |
376 | min_len, size) | |
7cac9316 | 377 | .span_label(pat.span, format!("expected {} elements",size)) |
9e0c209e | 378 | .emit(); |
3157f602 XL |
379 | } |
380 | (inner_ty, tcx.types.err) | |
381 | } else if let Some(rest) = size.checked_sub(min_len) { | |
382 | (inner_ty, tcx.mk_array(inner_ty, rest)) | |
383 | } else { | |
9e0c209e SL |
384 | struct_span_err!(tcx.sess, pat.span, E0528, |
385 | "pattern requires at least {} elements but array has {}", | |
386 | min_len, size) | |
387 | .span_label(pat.span, | |
7cac9316 | 388 | format!("pattern cannot match array of {} elements", size)) |
9e0c209e | 389 | .emit(); |
3157f602 | 390 | (inner_ty, tcx.types.err) |
a7813a04 | 391 | } |
3157f602 XL |
392 | } |
393 | ty::TySlice(inner_ty) => (inner_ty, expected_ty), | |
b039eaaf | 394 | _ => { |
3157f602 XL |
395 | if !expected_ty.references_error() { |
396 | let mut err = struct_span_err!( | |
397 | tcx.sess, pat.span, E0529, | |
398 | "expected an array or slice, found `{}`", | |
399 | expected_ty); | |
400 | if let ty::TyRef(_, ty::TypeAndMut { mutbl: _, ty }) = expected_ty.sty { | |
401 | match ty.sty { | |
402 | ty::TyArray(..) | ty::TySlice(..) => { | |
403 | err.help("the semantics of slice patterns changed \ | |
404 | recently; see issue #23121"); | |
405 | } | |
406 | _ => {} | |
407 | } | |
408 | } | |
9e0c209e SL |
409 | |
410 | err.span_label( pat.span, | |
7cac9316 | 411 | format!("pattern cannot match with input type `{}`", expected_ty) |
9e0c209e | 412 | ).emit(); |
3157f602 XL |
413 | } |
414 | (tcx.types.err, tcx.types.err) | |
b039eaaf SL |
415 | } |
416 | }; | |
417 | ||
a7813a04 | 418 | for elt in before { |
ea8adc8c | 419 | self.check_pat_walk(&elt, inner_ty, def_bm, true); |
a7813a04 XL |
420 | } |
421 | if let Some(ref slice) = *slice { | |
ea8adc8c | 422 | self.check_pat_walk(&slice, slice_ty, def_bm, true); |
a7813a04 XL |
423 | } |
424 | for elt in after { | |
ea8adc8c | 425 | self.check_pat_walk(&elt, inner_ty, def_bm, true); |
a7813a04 | 426 | } |
9e0c209e | 427 | expected_ty |
1a4d82fc | 428 | } |
9e0c209e SL |
429 | }; |
430 | ||
3b2f2976 | 431 | self.write_ty(pat.hir_id, ty); |
1a4d82fc | 432 | |
a7813a04 | 433 | // (*) In most of the cases above (literals and constants being |
ea8adc8c | 434 | // the exception), we relate types using strict equality, even |
a7813a04 XL |
435 | // though subtyping would be sufficient. There are a few reasons |
436 | // for this, some of which are fairly subtle and which cost me | |
437 | // (nmatsakis) an hour or two debugging to remember, so I thought | |
438 | // I'd write them down this time. | |
439 | // | |
440 | // 1. There is no loss of expressiveness here, though it does | |
441 | // cause some inconvenience. What we are saying is that the type | |
442 | // of `x` becomes *exactly* what is expected. This can cause unnecessary | |
443 | // errors in some cases, such as this one: | |
a7813a04 XL |
444 | // |
445 | // ``` | |
446 | // fn foo<'x>(x: &'x int) { | |
447 | // let a = 1; | |
448 | // let mut z = x; | |
449 | // z = &a; | |
450 | // } | |
451 | // ``` | |
452 | // | |
453 | // The reason we might get an error is that `z` might be | |
454 | // assigned a type like `&'x int`, and then we would have | |
455 | // a problem when we try to assign `&a` to `z`, because | |
456 | // the lifetime of `&a` (i.e., the enclosing block) is | |
457 | // shorter than `'x`. | |
458 | // | |
459 | // HOWEVER, this code works fine. The reason is that the | |
460 | // expected type here is whatever type the user wrote, not | |
461 | // the initializer's type. In this case the user wrote | |
462 | // nothing, so we are going to create a type variable `Z`. | |
463 | // Then we will assign the type of the initializer (`&'x | |
464 | // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we | |
465 | // will instantiate `Z` as a type `&'0 int` where `'0` is | |
466 | // a fresh region variable, with the constraint that `'x : | |
467 | // '0`. So basically we're all set. | |
468 | // | |
469 | // Note that there are two tests to check that this remains true | |
470 | // (`regions-reassign-{match,let}-bound-pointer.rs`). | |
471 | // | |
472 | // 2. Things go horribly wrong if we use subtype. The reason for | |
473 | // THIS is a fairly subtle case involving bound regions. See the | |
abe05a73 | 474 | // `givens` field in `region_constraints`, as well as the test |
a7813a04 XL |
475 | // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`, |
476 | // for details. Short version is that we must sometimes detect | |
477 | // relationships between specific region variables and regions | |
478 | // bound in a closure signature, and that detection gets thrown | |
479 | // off when we substitute fresh region variables here to enable | |
480 | // subtyping. | |
d9579d0f | 481 | } |
d9579d0f | 482 | |
a7813a04 | 483 | pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool { |
3157f602 XL |
484 | if let PatKind::Binding(..) = inner.node { |
485 | if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true, ty::NoPreference) { | |
476ff2be | 486 | if let ty::TyDynamic(..) = mt.ty.sty { |
a7813a04 XL |
487 | // This is "x = SomeTrait" being reduced from |
488 | // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error. | |
9e0c209e SL |
489 | let type_str = self.ty_to_string(expected); |
490 | struct_span_err!(self.tcx.sess, span, E0033, | |
491 | "type `{}` cannot be dereferenced", type_str) | |
7cac9316 | 492 | .span_label(span, format!("type `{}` cannot be dereferenced", type_str)) |
9e0c209e | 493 | .emit(); |
3157f602 | 494 | return false |
a7813a04 | 495 | } |
3157f602 | 496 | } |
54a0048b | 497 | } |
3157f602 | 498 | true |
a7813a04 | 499 | } |
54a0048b | 500 | |
a7813a04 XL |
501 | pub fn check_match(&self, |
502 | expr: &'gcx hir::Expr, | |
503 | discrim: &'gcx hir::Expr, | |
504 | arms: &'gcx [hir::Arm], | |
505 | expected: Expectation<'tcx>, | |
9e0c209e | 506 | match_src: hir::MatchSource) -> Ty<'tcx> { |
a7813a04 XL |
507 | let tcx = self.tcx; |
508 | ||
3b2f2976 XL |
509 | // Not entirely obvious: if matches may create ref bindings, we want to |
510 | // use the *precise* type of the discriminant, *not* some supertype, as | |
511 | // the "discriminant type" (issue #23116). | |
512 | // | |
3b2f2976 XL |
513 | // arielb1 [writes here in this comment thread][c] that there |
514 | // is certainly *some* potential danger, e.g. for an example | |
515 | // like: | |
516 | // | |
517 | // [c]: https://github.com/rust-lang/rust/pull/43399#discussion_r130223956 | |
518 | // | |
519 | // ``` | |
520 | // let Foo(x) = f()[0]; | |
521 | // ``` | |
522 | // | |
523 | // Then if the pattern matches by reference, we want to match | |
524 | // `f()[0]` as a lexpr, so we can't allow it to be | |
525 | // coerced. But if the pattern matches by value, `f()[0]` is | |
526 | // still syntactically a lexpr, but we *do* want to allow | |
527 | // coercions. | |
528 | // | |
529 | // However, *likely* we are ok with allowing coercions to | |
530 | // happen if there are no explicit ref mut patterns - all | |
531 | // implicit ref mut patterns must occur behind a reference, so | |
532 | // they will have the "correct" variance and lifetime. | |
533 | // | |
534 | // This does mean that the following pattern would be legal: | |
535 | // | |
536 | // ``` | |
537 | // struct Foo(Bar); | |
538 | // struct Bar(u32); | |
539 | // impl Deref for Foo { | |
540 | // type Target = Bar; | |
541 | // fn deref(&self) -> &Bar { &self.0 } | |
542 | // } | |
543 | // impl DerefMut for Foo { | |
544 | // fn deref_mut(&mut self) -> &mut Bar { &mut self.0 } | |
545 | // } | |
546 | // fn foo(x: &mut Foo) { | |
547 | // { | |
548 | // let Bar(z): &mut Bar = x; | |
549 | // *z = 42; | |
550 | // } | |
551 | // assert_eq!(foo.0.0, 42); | |
552 | // } | |
553 | // ``` | |
ea8adc8c XL |
554 | // |
555 | // FIXME(tschottdorf): don't call contains_explicit_ref_binding, which | |
556 | // is problematic as the HIR is being scraped, but ref bindings may be | |
557 | // implicit after #42640. We need to make sure that pat_adjustments | |
558 | // (once introduced) is populated by the time we get here. | |
559 | // | |
560 | // See #44848. | |
a7813a04 | 561 | let contains_ref_bindings = arms.iter() |
3b2f2976 | 562 | .filter_map(|a| a.contains_explicit_ref_binding()) |
a7813a04 XL |
563 | .max_by_key(|m| match *m { |
564 | hir::MutMutable => 1, | |
565 | hir::MutImmutable => 0, | |
566 | }); | |
567 | let discrim_ty; | |
568 | if let Some(m) = contains_ref_bindings { | |
9e0c209e | 569 | discrim_ty = self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m)); |
54a0048b | 570 | } else { |
a7813a04 XL |
571 | // ...but otherwise we want to use any supertype of the |
572 | // discriminant. This is sort of a workaround, see note (*) in | |
573 | // `check_pat` for some details. | |
476ff2be | 574 | discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span)); |
041b39d2 | 575 | self.check_expr_has_type_or_error(discrim, discrim_ty); |
54a0048b | 576 | }; |
cc61c64b XL |
577 | |
578 | // If the discriminant diverges, the match is pointless (e.g., | |
579 | // `match (return) { }`). | |
580 | self.warn_if_unreachable(expr.id, expr.span, "expression"); | |
581 | ||
582 | // If there are no arms, that is a diverging match; a special case. | |
583 | if arms.is_empty() { | |
584 | self.diverges.set(self.diverges.get() | Diverges::Always); | |
585 | return tcx.types.never; | |
586 | } | |
587 | ||
588 | // Otherwise, we have to union together the types that the | |
589 | // arms produce and so forth. | |
590 | ||
476ff2be SL |
591 | let discrim_diverges = self.diverges.get(); |
592 | self.diverges.set(Diverges::Maybe); | |
1a4d82fc | 593 | |
a7813a04 XL |
594 | // Typecheck the patterns first, so that we get types for all the |
595 | // bindings. | |
476ff2be SL |
596 | let all_arm_pats_diverge: Vec<_> = arms.iter().map(|arm| { |
597 | let mut all_pats_diverge = Diverges::WarnedAlways; | |
a7813a04 | 598 | for p in &arm.pats { |
476ff2be | 599 | self.diverges.set(Diverges::Maybe); |
ea8adc8c XL |
600 | self.check_pat_walk(&p, discrim_ty, |
601 | ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), true); | |
476ff2be | 602 | all_pats_diverge &= self.diverges.get(); |
a7813a04 | 603 | } |
cc61c64b | 604 | |
32a655c1 SL |
605 | // As discussed with @eddyb, this is for disabling unreachable_code |
606 | // warnings on patterns (they're now subsumed by unreachable_patterns | |
607 | // warnings). | |
608 | match all_pats_diverge { | |
609 | Diverges::Maybe => Diverges::Maybe, | |
610 | Diverges::Always | Diverges::WarnedAlways => Diverges::WarnedAlways, | |
611 | } | |
476ff2be | 612 | }).collect(); |
1a4d82fc | 613 | |
a7813a04 XL |
614 | // Now typecheck the blocks. |
615 | // | |
616 | // The result of the match is the common supertype of all the | |
617 | // arms. Start out the value as bottom, since it's the, well, | |
618 | // bottom the type lattice, and we'll be moving up the lattice as | |
619 | // we process each arm. (Note that any match with 0 arms is matching | |
620 | // on any empty type and is therefore unreachable; should the flow | |
621 | // of execution reach it, we will panic, so bottom is an appropriate | |
622 | // type in that case) | |
476ff2be | 623 | let mut all_arms_diverge = Diverges::WarnedAlways; |
cc61c64b XL |
624 | |
625 | let expected = expected.adjust_for_branches(self); | |
626 | ||
627 | let mut coercion = { | |
628 | let coerce_first = match expected { | |
629 | // We don't coerce to `()` so that if the match expression is a | |
630 | // statement it's branches can have any consistent type. That allows | |
631 | // us to give better error messages (pointing to a usually better | |
632 | // arm for inconsistent arms or to the whole match when a `()` type | |
633 | // is required). | |
634 | Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => ety, | |
635 | _ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)), | |
636 | }; | |
637 | CoerceMany::with_coercion_sites(coerce_first, arms) | |
54a0048b | 638 | }; |
9e0c209e | 639 | |
476ff2be | 640 | for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { |
a7813a04 | 641 | if let Some(ref e) = arm.guard { |
476ff2be | 642 | self.diverges.set(pats_diverge); |
041b39d2 | 643 | self.check_expr_has_type_or_error(e, tcx.types.bool); |
a7813a04 | 644 | } |
476ff2be SL |
645 | |
646 | self.diverges.set(pats_diverge); | |
9e0c209e | 647 | let arm_ty = self.check_expr_with_expectation(&arm.body, expected); |
476ff2be | 648 | all_arms_diverge &= self.diverges.get(); |
1a4d82fc | 649 | |
a7813a04 XL |
650 | // Handle the fallback arm of a desugared if-let like a missing else. |
651 | let is_if_let_fallback = match match_src { | |
652 | hir::MatchSource::IfLetDesugar { contains_else_clause: false } => { | |
653 | i == arms.len() - 1 && arm_ty.is_nil() | |
654 | } | |
655 | _ => false | |
656 | }; | |
1a4d82fc | 657 | |
cc61c64b XL |
658 | if is_if_let_fallback { |
659 | let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse); | |
660 | assert!(arm_ty.is_nil()); | |
7cac9316 | 661 | coercion.coerce_forced_unit(self, &cause, &mut |_| (), true); |
a7813a04 | 662 | } else { |
cc61c64b | 663 | let cause = self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { |
476ff2be SL |
664 | arm_span: arm.body.span, |
665 | source: match_src | |
cc61c64b XL |
666 | }); |
667 | coercion.coerce(self, &cause, &arm.body, arm_ty, self.diverges.get()); | |
668 | } | |
1a4d82fc | 669 | } |
1a4d82fc | 670 | |
476ff2be SL |
671 | // We won't diverge unless the discriminant or all arms diverge. |
672 | self.diverges.set(discrim_diverges | all_arms_diverge); | |
673 | ||
cc61c64b | 674 | coercion.complete(self) |
92a42be0 | 675 | } |
92a42be0 | 676 | |
5bcae85e SL |
677 | fn check_pat_struct(&self, |
678 | pat: &'gcx hir::Pat, | |
476ff2be | 679 | qpath: &hir::QPath, |
5bcae85e SL |
680 | fields: &'gcx [Spanned<hir::FieldPat>], |
681 | etc: bool, | |
ea8adc8c XL |
682 | expected: Ty<'tcx>, |
683 | def_bm: ty::BindingMode) -> Ty<'tcx> | |
5bcae85e SL |
684 | { |
685 | // Resolve the path and check the definition for errors. | |
476ff2be | 686 | let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.id) { |
5bcae85e SL |
687 | variant_ty |
688 | } else { | |
5bcae85e | 689 | for field in fields { |
ea8adc8c | 690 | self.check_pat_walk(&field.node.pat, self.tcx.types.err, def_bm, true); |
9cc50fc6 | 691 | } |
9e0c209e | 692 | return self.tcx.types.err; |
a7813a04 | 693 | }; |
9cc50fc6 | 694 | |
5bcae85e SL |
695 | // Type check the path. |
696 | self.demand_eqtype(pat.span, expected, pat_ty); | |
697 | ||
698 | // Type check subpatterns. | |
ea8adc8c | 699 | self.check_struct_pat_fields(pat_ty, pat.id, pat.span, variant, fields, etc, def_bm); |
9e0c209e | 700 | pat_ty |
d9579d0f AL |
701 | } |
702 | ||
5bcae85e | 703 | fn check_pat_path(&self, |
a7813a04 | 704 | pat: &hir::Pat, |
476ff2be | 705 | qpath: &hir::QPath, |
9e0c209e | 706 | expected: Ty<'tcx>) -> Ty<'tcx> |
a7813a04 | 707 | { |
a7813a04 | 708 | let tcx = self.tcx; |
c30ab7b3 | 709 | let report_unexpected_def = |def: Def| { |
5bcae85e | 710 | span_err!(tcx.sess, pat.span, E0533, |
c30ab7b3 | 711 | "expected unit struct/variant or constant, found {} `{}`", |
32a655c1 SL |
712 | def.kind_name(), |
713 | hir::print::to_string(&tcx.hir, |s| s.print_qpath(qpath, false))); | |
a7813a04 | 714 | }; |
1a4d82fc | 715 | |
5bcae85e | 716 | // Resolve the path and check the definition for errors. |
476ff2be | 717 | let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(qpath, pat.id, pat.span); |
5bcae85e SL |
718 | match def { |
719 | Def::Err => { | |
720 | self.set_tainted_by_errors(); | |
9e0c209e | 721 | return tcx.types.err; |
5bcae85e SL |
722 | } |
723 | Def::Method(..) => { | |
c30ab7b3 | 724 | report_unexpected_def(def); |
9e0c209e | 725 | return tcx.types.err; |
5bcae85e | 726 | } |
c30ab7b3 SL |
727 | Def::VariantCtor(_, CtorKind::Const) | |
728 | Def::StructCtor(_, CtorKind::Const) | | |
5bcae85e | 729 | Def::Const(..) | Def::AssociatedConst(..) => {} // OK |
c30ab7b3 | 730 | _ => bug!("unexpected pattern definition: {:?}", def) |
1a4d82fc | 731 | } |
1a4d82fc | 732 | |
5bcae85e | 733 | // Type check the path. |
9e0c209e | 734 | let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id); |
5bcae85e | 735 | self.demand_suptype(pat.span, expected, pat_ty); |
9e0c209e | 736 | pat_ty |
5bcae85e | 737 | } |
7453a54e | 738 | |
5bcae85e SL |
739 | fn check_pat_tuple_struct(&self, |
740 | pat: &hir::Pat, | |
476ff2be | 741 | qpath: &hir::QPath, |
5bcae85e SL |
742 | subpats: &'gcx [P<hir::Pat>], |
743 | ddpos: Option<usize>, | |
ea8adc8c XL |
744 | expected: Ty<'tcx>, |
745 | def_bm: ty::BindingMode) -> Ty<'tcx> | |
5bcae85e SL |
746 | { |
747 | let tcx = self.tcx; | |
748 | let on_error = || { | |
3157f602 | 749 | for pat in subpats { |
ea8adc8c | 750 | self.check_pat_walk(&pat, tcx.types.err, def_bm, true); |
1a4d82fc | 751 | } |
a7813a04 | 752 | }; |
c30ab7b3 SL |
753 | let report_unexpected_def = |def: Def| { |
754 | let msg = format!("expected tuple struct/variant, found {} `{}`", | |
32a655c1 SL |
755 | def.kind_name(), |
756 | hir::print::to_string(&tcx.hir, |s| s.print_qpath(qpath, false))); | |
c30ab7b3 | 757 | struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg) |
7cac9316 | 758 | .span_label(pat.span, "not a tuple variant or struct").emit(); |
c30ab7b3 | 759 | on_error(); |
5bcae85e | 760 | }; |
a7813a04 | 761 | |
5bcae85e | 762 | // Resolve the path and check the definition for errors. |
476ff2be | 763 | let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(qpath, pat.id, pat.span); |
5bcae85e SL |
764 | let variant = match def { |
765 | Def::Err => { | |
766 | self.set_tainted_by_errors(); | |
767 | on_error(); | |
9e0c209e | 768 | return tcx.types.err; |
1a4d82fc | 769 | } |
c30ab7b3 SL |
770 | Def::AssociatedConst(..) | Def::Method(..) => { |
771 | report_unexpected_def(def); | |
9e0c209e | 772 | return tcx.types.err; |
a7813a04 | 773 | } |
c30ab7b3 SL |
774 | Def::VariantCtor(_, CtorKind::Fn) | |
775 | Def::StructCtor(_, CtorKind::Fn) => { | |
5bcae85e | 776 | tcx.expect_variant_def(def) |
a7813a04 | 777 | } |
c30ab7b3 | 778 | _ => bug!("unexpected pattern definition: {:?}", def) |
5bcae85e | 779 | }; |
a7813a04 | 780 | |
5bcae85e | 781 | // Type check the path. |
9e0c209e | 782 | let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id); |
c30ab7b3 | 783 | // Replace constructor type with constructed type for tuple struct patterns. |
041b39d2 | 784 | let pat_ty = pat_ty.fn_sig(tcx).output(); |
7cac9316 | 785 | let pat_ty = tcx.no_late_bound_regions(&pat_ty).expect("expected fn type"); |
ea8adc8c | 786 | |
5bcae85e SL |
787 | self.demand_eqtype(pat.span, expected, pat_ty); |
788 | ||
789 | // Type check subpatterns. | |
3157f602 XL |
790 | if subpats.len() == variant.fields.len() || |
791 | subpats.len() < variant.fields.len() && ddpos.is_some() { | |
5bcae85e | 792 | let substs = match pat_ty.sty { |
9e0c209e | 793 | ty::TyAdt(_, substs) => substs, |
5bcae85e SL |
794 | ref ty => bug!("unexpected pattern type {:?}", ty), |
795 | }; | |
3157f602 | 796 | for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { |
5bcae85e | 797 | let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs); |
ea8adc8c | 798 | self.check_pat_walk(&subpat, field_ty, def_bm, true); |
476ff2be SL |
799 | |
800 | self.tcx.check_stability(variant.fields[i].did, pat.id, subpat.span); | |
3157f602 XL |
801 | } |
802 | } else { | |
c30ab7b3 SL |
803 | let subpats_ending = if subpats.len() == 1 { "" } else { "s" }; |
804 | let fields_ending = if variant.fields.len() == 1 { "" } else { "s" }; | |
5bcae85e SL |
805 | struct_span_err!(tcx.sess, pat.span, E0023, |
806 | "this pattern has {} field{}, but the corresponding {} has {} field{}", | |
807 | subpats.len(), subpats_ending, def.kind_name(), | |
808 | variant.fields.len(), fields_ending) | |
7cac9316 | 809 | .span_label(pat.span, format!("expected {} field{}, found {}", |
5bcae85e SL |
810 | variant.fields.len(), fields_ending, subpats.len())) |
811 | .emit(); | |
812 | on_error(); | |
9e0c209e | 813 | return tcx.types.err; |
a7813a04 | 814 | } |
9e0c209e | 815 | pat_ty |
1a4d82fc JJ |
816 | } |
817 | ||
9e0c209e SL |
818 | fn check_struct_pat_fields(&self, |
819 | adt_ty: Ty<'tcx>, | |
476ff2be | 820 | pat_id: ast::NodeId, |
9e0c209e | 821 | span: Span, |
476ff2be | 822 | variant: &'tcx ty::VariantDef, |
9e0c209e | 823 | fields: &'gcx [Spanned<hir::FieldPat>], |
ea8adc8c XL |
824 | etc: bool, |
825 | def_bm: ty::BindingMode) { | |
a7813a04 XL |
826 | let tcx = self.tcx; |
827 | ||
abe05a73 XL |
828 | let (substs, adt) = match adt_ty.sty { |
829 | ty::TyAdt(adt, substs) => (substs, adt), | |
9e0c209e SL |
830 | _ => span_bug!(span, "struct pattern is not an ADT") |
831 | }; | |
abe05a73 | 832 | let kind_name = adt.variant_descr(); |
9e0c209e | 833 | |
a7813a04 XL |
834 | // Index the struct fields' types. |
835 | let field_map = variant.fields | |
1a4d82fc | 836 | .iter() |
a7813a04 | 837 | .map(|field| (field.name, field)) |
476ff2be | 838 | .collect::<FxHashMap<_, _>>(); |
a7813a04 XL |
839 | |
840 | // Keep track of which fields have already appeared in the pattern. | |
476ff2be | 841 | let mut used_fields = FxHashMap(); |
a7813a04 XL |
842 | |
843 | // Typecheck each field. | |
844 | for &Spanned { node: ref field, span } in fields { | |
845 | let field_ty = match used_fields.entry(field.name) { | |
846 | Occupied(occupied) => { | |
c30ab7b3 SL |
847 | struct_span_err!(tcx.sess, span, E0025, |
848 | "field `{}` bound multiple times \ | |
849 | in the pattern", | |
850 | field.name) | |
851 | .span_label(span, | |
7cac9316 XL |
852 | format!("multiple uses of `{}` in pattern", field.name)) |
853 | .span_label(*occupied.get(), format!("first use of `{}`", field.name)) | |
c30ab7b3 | 854 | .emit(); |
a7813a04 XL |
855 | tcx.types.err |
856 | } | |
857 | Vacant(vacant) => { | |
858 | vacant.insert(span); | |
859 | field_map.get(&field.name) | |
476ff2be SL |
860 | .map(|f| { |
861 | self.tcx.check_stability(f.did, pat_id, span); | |
862 | ||
863 | self.field_ty(span, f, substs) | |
864 | }) | |
a7813a04 | 865 | .unwrap_or_else(|| { |
5bcae85e | 866 | struct_span_err!(tcx.sess, span, E0026, |
9e0c209e SL |
867 | "{} `{}` does not have a field named `{}`", |
868 | kind_name, | |
5bcae85e SL |
869 | tcx.item_path_str(variant.did), |
870 | field.name) | |
871 | .span_label(span, | |
7cac9316 | 872 | format!("{} `{}` does not have field `{}`", |
9e0c209e | 873 | kind_name, |
5bcae85e SL |
874 | tcx.item_path_str(variant.did), |
875 | field.name)) | |
876 | .emit(); | |
877 | ||
a7813a04 XL |
878 | tcx.types.err |
879 | }) | |
880 | } | |
881 | }; | |
882 | ||
ea8adc8c | 883 | self.check_pat_walk(&field.pat, field_ty, def_bm, true); |
a7813a04 XL |
884 | } |
885 | ||
abe05a73 XL |
886 | // Require `..` if struct has non_exhaustive attribute. |
887 | if adt.is_struct() && adt.is_non_exhaustive() && !adt.did.is_local() && !etc { | |
888 | span_err!(tcx.sess, span, E0638, | |
889 | "`..` required with {} marked as non-exhaustive", | |
890 | kind_name); | |
891 | } | |
892 | ||
9e0c209e SL |
893 | // Report an error if incorrect number of the fields were specified. |
894 | if kind_name == "union" { | |
895 | if fields.len() != 1 { | |
896 | tcx.sess.span_err(span, "union patterns should have exactly one field"); | |
897 | } | |
898 | if etc { | |
899 | tcx.sess.span_err(span, "`..` cannot be used in union patterns"); | |
900 | } | |
901 | } else if !etc { | |
a7813a04 XL |
902 | for field in variant.fields |
903 | .iter() | |
904 | .filter(|field| !used_fields.contains_key(&field.name)) { | |
ea8adc8c XL |
905 | let mut diag = struct_span_err!(tcx.sess, span, E0027, |
906 | "pattern does not mention field `{}`", | |
907 | field.name); | |
908 | diag.span_label(span, format!("missing field `{}`", field.name)); | |
909 | if variant.ctor_kind == CtorKind::Fn { | |
910 | diag.note("trying to match a tuple variant with a struct variant pattern"); | |
911 | } | |
912 | diag.emit(); | |
a7813a04 | 913 | } |
1a4d82fc JJ |
914 | } |
915 | } | |
916 | } |