]>
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 | ||
3157f602 | 11 | use hir::def::Def; |
54a0048b | 12 | use rustc::infer::{self, InferOk, TypeOrigin}; |
5bcae85e | 13 | use hir::pat_util::EnumerateAndAdjustIterator; |
54a0048b | 14 | use rustc::ty::subst::Substs; |
5bcae85e | 15 | use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference, VariantKind}; |
a7813a04 | 16 | use check::{FnCtxt, Expectation}; |
92a42be0 | 17 | use lint; |
1a4d82fc | 18 | use util::nodemap::FnvHashMap; |
1a4d82fc | 19 | |
1a4d82fc | 20 | use std::collections::hash_map::Entry::{Occupied, Vacant}; |
3157f602 | 21 | use std::cmp; |
1a4d82fc | 22 | use syntax::ast; |
3157f602 | 23 | use syntax::codemap::Spanned; |
1a4d82fc | 24 | use syntax::ptr::P; |
3157f602 | 25 | use syntax_pos::Span; |
1a4d82fc | 26 | |
54a0048b SL |
27 | use rustc::hir::{self, PatKind}; |
28 | use rustc::hir::print as pprust; | |
e9174d1e | 29 | |
3157f602 | 30 | impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { |
a7813a04 XL |
31 | pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) { |
32 | let tcx = self.tcx; | |
33 | ||
34 | debug!("check_pat(pat={:?},expected={:?})", pat, expected); | |
35 | ||
36 | match pat.node { | |
37 | PatKind::Wild => { | |
38 | self.write_ty(pat.id, expected); | |
39 | } | |
40 | PatKind::Lit(ref lt) => { | |
41 | self.check_expr(<); | |
42 | let expr_ty = self.expr_ty(<); | |
43 | ||
44 | // Byte string patterns behave the same way as array patterns | |
45 | // They can denote both statically and dynamically sized byte arrays | |
46 | let mut pat_ty = expr_ty; | |
47 | if let hir::ExprLit(ref lt) = lt.node { | |
48 | if let ast::LitKind::ByteStr(_) = lt.node { | |
49 | let expected_ty = self.structurally_resolved_type(pat.span, expected); | |
50 | if let ty::TyRef(_, mt) = expected_ty.sty { | |
51 | if let ty::TySlice(_) = mt.ty.sty { | |
52 | pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), | |
53 | tcx.mk_slice(tcx.types.u8)) | |
54 | } | |
c34b1796 AL |
55 | } |
56 | } | |
57 | } | |
c34b1796 | 58 | |
a7813a04 XL |
59 | self.write_ty(pat.id, pat_ty); |
60 | ||
61 | // somewhat surprising: in this case, the subtyping | |
62 | // relation goes the opposite way as the other | |
63 | // cases. Actually what we really want is not a subtyping | |
64 | // relation at all but rather that there exists a LUB (so | |
65 | // that they can be compared). However, in practice, | |
66 | // constants are always scalars or strings. For scalars | |
67 | // subtyping is irrelevant, and for strings `expr_ty` is | |
68 | // type is `&'static str`, so if we say that | |
69 | // | |
70 | // &'static str <: expected | |
71 | // | |
72 | // that's equivalent to there existing a LUB. | |
73 | self.demand_suptype(pat.span, expected, pat_ty); | |
62682a34 | 74 | } |
a7813a04 XL |
75 | PatKind::Range(ref begin, ref end) => { |
76 | self.check_expr(begin); | |
77 | self.check_expr(end); | |
78 | ||
79 | let lhs_ty = self.expr_ty(begin); | |
80 | let rhs_ty = self.expr_ty(end); | |
81 | ||
82 | // Check that both end-points are of numeric or char type. | |
83 | let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char(); | |
84 | let lhs_compat = numeric_or_char(lhs_ty); | |
85 | let rhs_compat = numeric_or_char(rhs_ty); | |
86 | ||
87 | if !lhs_compat || !rhs_compat { | |
88 | let span = if !lhs_compat && !rhs_compat { | |
89 | pat.span | |
90 | } else if !lhs_compat { | |
91 | begin.span | |
92 | } else { | |
93 | end.span | |
94 | }; | |
95 | ||
5bcae85e SL |
96 | struct_span_err!(tcx.sess, span, E0029, |
97 | "only char and numeric types are allowed in range patterns") | |
98 | .span_label(span, &format!("ranges require char or numeric types")) | |
99 | .note(&format!("start type: {}", self.ty_to_string(lhs_ty))) | |
100 | .note(&format!("end type: {}", self.ty_to_string(rhs_ty))) | |
101 | .emit(); | |
a7813a04 XL |
102 | return; |
103 | } | |
1a4d82fc | 104 | |
a7813a04 XL |
105 | // Now that we know the types can be unified we find the unified type and use |
106 | // it to type the entire expression. | |
107 | let common_type = self.resolve_type_vars_if_possible(&lhs_ty); | |
62682a34 | 108 | |
a7813a04 | 109 | self.write_ty(pat.id, common_type); |
62682a34 | 110 | |
a7813a04 XL |
111 | // subtyping doesn't matter here, as the value is some kind of scalar |
112 | self.demand_eqtype(pat.span, expected, lhs_ty); | |
5bcae85e | 113 | self.demand_eqtype(pat.span, expected, rhs_ty); |
1a4d82fc | 114 | } |
3157f602 | 115 | PatKind::Binding(bm, _, ref sub) => { |
a7813a04 XL |
116 | let typ = self.local_ty(pat.span, pat.id); |
117 | match bm { | |
118 | hir::BindByRef(mutbl) => { | |
119 | // if the binding is like | |
120 | // ref x | ref const x | ref mut x | |
121 | // then `x` is assigned a value of type `&M T` where M is the mutability | |
122 | // and T is the expected type. | |
123 | let region_var = self.next_region_var(infer::PatternRegion(pat.span)); | |
124 | let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl }; | |
125 | let region_ty = tcx.mk_ref(tcx.mk_region(region_var), mt); | |
126 | ||
127 | // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is | |
128 | // required. However, we use equality, which is stronger. See (*) for | |
129 | // an explanation. | |
130 | self.demand_eqtype(pat.span, region_ty, typ); | |
131 | } | |
132 | // otherwise the type of x is the expected type T | |
133 | hir::BindByValue(_) => { | |
134 | // As above, `T <: typeof(x)` is required but we | |
135 | // use equality, see (*) below. | |
136 | self.demand_eqtype(pat.span, expected, typ); | |
137 | } | |
138 | } | |
1a4d82fc | 139 | |
a7813a04 | 140 | self.write_ty(pat.id, typ); |
1a4d82fc | 141 | |
a7813a04 XL |
142 | // if there are multiple arms, make sure they all agree on |
143 | // what the type of the binding `x` ought to be | |
3157f602 XL |
144 | match tcx.expect_def(pat.id) { |
145 | Def::Err => {} | |
146 | Def::Local(_, var_id) => { | |
147 | if var_id != pat.id { | |
148 | let vt = self.local_ty(pat.span, var_id); | |
149 | self.demand_eqtype(pat.span, vt, typ); | |
150 | } | |
a7813a04 | 151 | } |
3157f602 XL |
152 | d => bug!("bad def for pattern binding `{:?}`", d) |
153 | } | |
1a4d82fc | 154 | |
3157f602 XL |
155 | if let Some(ref p) = *sub { |
156 | self.check_pat(&p, expected); | |
9cc50fc6 | 157 | } |
1a4d82fc | 158 | } |
3157f602 | 159 | PatKind::TupleStruct(ref path, ref subpats, ddpos) => { |
5bcae85e | 160 | self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected); |
a7813a04 | 161 | } |
5bcae85e SL |
162 | PatKind::Path(ref opt_qself, ref path) => { |
163 | let opt_qself_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty)); | |
164 | self.check_pat_path(pat, opt_qself_ty, path, expected); | |
a7813a04 XL |
165 | } |
166 | PatKind::Struct(ref path, ref fields, etc) => { | |
167 | self.check_pat_struct(pat, path, fields, etc, expected); | |
168 | } | |
3157f602 XL |
169 | PatKind::Tuple(ref elements, ddpos) => { |
170 | let mut expected_len = elements.len(); | |
171 | if ddpos.is_some() { | |
172 | // Require known type only when `..` is present | |
173 | if let ty::TyTuple(ref tys) = | |
174 | self.structurally_resolved_type(pat.span, expected).sty { | |
175 | expected_len = tys.len(); | |
176 | } | |
177 | } | |
178 | let max_len = cmp::max(expected_len, elements.len()); | |
179 | ||
180 | let element_tys: Vec<_> = (0 .. max_len).map(|_| self.next_ty_var()).collect(); | |
a7813a04 XL |
181 | let pat_ty = tcx.mk_tup(element_tys.clone()); |
182 | self.write_ty(pat.id, pat_ty); | |
183 | self.demand_eqtype(pat.span, expected, pat_ty); | |
3157f602 XL |
184 | for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { |
185 | self.check_pat(elem, &element_tys[i]); | |
d9579d0f | 186 | } |
a7813a04 XL |
187 | } |
188 | PatKind::Box(ref inner) => { | |
189 | let inner_ty = self.next_ty_var(); | |
190 | let uniq_ty = tcx.mk_box(inner_ty); | |
191 | ||
192 | if self.check_dereferencable(pat.span, expected, &inner) { | |
193 | // Here, `demand::subtype` is good enough, but I don't | |
194 | // think any errors can be introduced by using | |
195 | // `demand::eqtype`. | |
196 | self.demand_eqtype(pat.span, expected, uniq_ty); | |
197 | self.write_ty(pat.id, uniq_ty); | |
198 | self.check_pat(&inner, inner_ty); | |
d9579d0f | 199 | } else { |
a7813a04 XL |
200 | self.write_error(pat.id); |
201 | self.check_pat(&inner, tcx.types.err); | |
d9579d0f AL |
202 | } |
203 | } | |
a7813a04 XL |
204 | PatKind::Ref(ref inner, mutbl) => { |
205 | let expected = self.shallow_resolve(expected); | |
206 | if self.check_dereferencable(pat.span, expected, &inner) { | |
207 | // `demand::subtype` would be good enough, but using | |
208 | // `eqtype` turns out to be equally general. See (*) | |
209 | // below for details. | |
210 | ||
211 | // Take region, inner-type from expected type if we | |
212 | // can, to avoid creating needless variables. This | |
213 | // also helps with the bad interactions of the given | |
214 | // hack detailed in (*) below. | |
215 | let (rptr_ty, inner_ty) = match expected.sty { | |
216 | ty::TyRef(_, mt) if mt.mutbl == mutbl => { | |
217 | (expected, mt.ty) | |
218 | } | |
219 | _ => { | |
220 | let inner_ty = self.next_ty_var(); | |
221 | let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; | |
222 | let region = self.next_region_var(infer::PatternRegion(pat.span)); | |
223 | let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt); | |
224 | self.demand_eqtype(pat.span, expected, rptr_ty); | |
225 | (rptr_ty, inner_ty) | |
226 | } | |
227 | }; | |
b039eaaf | 228 | |
a7813a04 XL |
229 | self.write_ty(pat.id, rptr_ty); |
230 | self.check_pat(&inner, inner_ty); | |
231 | } else { | |
232 | self.write_error(pat.id); | |
233 | self.check_pat(&inner, tcx.types.err); | |
234 | } | |
235 | } | |
236 | PatKind::Vec(ref before, ref slice, ref after) => { | |
237 | let expected_ty = self.structurally_resolved_type(pat.span, expected); | |
3157f602 XL |
238 | let (inner_ty, slice_ty) = match expected_ty.sty { |
239 | ty::TyArray(inner_ty, size) => { | |
a7813a04 | 240 | let min_len = before.len() + after.len(); |
3157f602 XL |
241 | if slice.is_none() { |
242 | if min_len != size { | |
243 | span_err!(tcx.sess, pat.span, E0527, | |
244 | "pattern requires {} elements but array has {}", | |
245 | min_len, size); | |
246 | } | |
247 | (inner_ty, tcx.types.err) | |
248 | } else if let Some(rest) = size.checked_sub(min_len) { | |
249 | (inner_ty, tcx.mk_array(inner_ty, rest)) | |
250 | } else { | |
251 | span_err!(tcx.sess, pat.span, E0528, | |
252 | "pattern requires at least {} elements but array has {}", | |
253 | min_len, size); | |
254 | (inner_ty, tcx.types.err) | |
a7813a04 | 255 | } |
3157f602 XL |
256 | } |
257 | ty::TySlice(inner_ty) => (inner_ty, expected_ty), | |
b039eaaf | 258 | _ => { |
3157f602 XL |
259 | if !expected_ty.references_error() { |
260 | let mut err = struct_span_err!( | |
261 | tcx.sess, pat.span, E0529, | |
262 | "expected an array or slice, found `{}`", | |
263 | expected_ty); | |
264 | if let ty::TyRef(_, ty::TypeAndMut { mutbl: _, ty }) = expected_ty.sty { | |
265 | match ty.sty { | |
266 | ty::TyArray(..) | ty::TySlice(..) => { | |
267 | err.help("the semantics of slice patterns changed \ | |
268 | recently; see issue #23121"); | |
269 | } | |
270 | _ => {} | |
271 | } | |
272 | } | |
273 | err.emit(); | |
274 | } | |
275 | (tcx.types.err, tcx.types.err) | |
b039eaaf SL |
276 | } |
277 | }; | |
278 | ||
3157f602 | 279 | self.write_ty(pat.id, expected_ty); |
1a4d82fc | 280 | |
a7813a04 XL |
281 | for elt in before { |
282 | self.check_pat(&elt, inner_ty); | |
283 | } | |
284 | if let Some(ref slice) = *slice { | |
a7813a04 XL |
285 | self.check_pat(&slice, slice_ty); |
286 | } | |
287 | for elt in after { | |
288 | self.check_pat(&elt, inner_ty); | |
289 | } | |
1a4d82fc JJ |
290 | } |
291 | } | |
1a4d82fc | 292 | |
a7813a04 XL |
293 | // (*) In most of the cases above (literals and constants being |
294 | // the exception), we relate types using strict equality, evewn | |
295 | // though subtyping would be sufficient. There are a few reasons | |
296 | // for this, some of which are fairly subtle and which cost me | |
297 | // (nmatsakis) an hour or two debugging to remember, so I thought | |
298 | // I'd write them down this time. | |
299 | // | |
300 | // 1. There is no loss of expressiveness here, though it does | |
301 | // cause some inconvenience. What we are saying is that the type | |
302 | // of `x` becomes *exactly* what is expected. This can cause unnecessary | |
303 | // errors in some cases, such as this one: | |
304 | // it will cause errors in a case like this: | |
305 | // | |
306 | // ``` | |
307 | // fn foo<'x>(x: &'x int) { | |
308 | // let a = 1; | |
309 | // let mut z = x; | |
310 | // z = &a; | |
311 | // } | |
312 | // ``` | |
313 | // | |
314 | // The reason we might get an error is that `z` might be | |
315 | // assigned a type like `&'x int`, and then we would have | |
316 | // a problem when we try to assign `&a` to `z`, because | |
317 | // the lifetime of `&a` (i.e., the enclosing block) is | |
318 | // shorter than `'x`. | |
319 | // | |
320 | // HOWEVER, this code works fine. The reason is that the | |
321 | // expected type here is whatever type the user wrote, not | |
322 | // the initializer's type. In this case the user wrote | |
323 | // nothing, so we are going to create a type variable `Z`. | |
324 | // Then we will assign the type of the initializer (`&'x | |
325 | // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we | |
326 | // will instantiate `Z` as a type `&'0 int` where `'0` is | |
327 | // a fresh region variable, with the constraint that `'x : | |
328 | // '0`. So basically we're all set. | |
329 | // | |
330 | // Note that there are two tests to check that this remains true | |
331 | // (`regions-reassign-{match,let}-bound-pointer.rs`). | |
332 | // | |
333 | // 2. Things go horribly wrong if we use subtype. The reason for | |
334 | // THIS is a fairly subtle case involving bound regions. See the | |
335 | // `givens` field in `region_inference`, as well as the test | |
336 | // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`, | |
337 | // for details. Short version is that we must sometimes detect | |
338 | // relationships between specific region variables and regions | |
339 | // bound in a closure signature, and that detection gets thrown | |
340 | // off when we substitute fresh region variables here to enable | |
341 | // subtyping. | |
d9579d0f | 342 | } |
d9579d0f | 343 | |
a7813a04 | 344 | pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool { |
3157f602 XL |
345 | if let PatKind::Binding(..) = inner.node { |
346 | if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true, ty::NoPreference) { | |
347 | if let ty::TyTrait(..) = mt.ty.sty { | |
a7813a04 XL |
348 | // This is "x = SomeTrait" being reduced from |
349 | // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error. | |
3157f602 | 350 | span_err!(self.tcx.sess, span, E0033, |
a7813a04 XL |
351 | "type `{}` cannot be dereferenced", |
352 | self.ty_to_string(expected)); | |
3157f602 | 353 | return false |
a7813a04 | 354 | } |
3157f602 | 355 | } |
54a0048b | 356 | } |
3157f602 | 357 | true |
a7813a04 XL |
358 | } |
359 | } | |
54a0048b | 360 | |
a7813a04 XL |
361 | impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { |
362 | pub fn check_match(&self, | |
363 | expr: &'gcx hir::Expr, | |
364 | discrim: &'gcx hir::Expr, | |
365 | arms: &'gcx [hir::Arm], | |
366 | expected: Expectation<'tcx>, | |
367 | match_src: hir::MatchSource) { | |
368 | let tcx = self.tcx; | |
369 | ||
370 | // Not entirely obvious: if matches may create ref bindings, we | |
371 | // want to use the *precise* type of the discriminant, *not* some | |
372 | // supertype, as the "discriminant type" (issue #23116). | |
373 | let contains_ref_bindings = arms.iter() | |
374 | .filter_map(|a| tcx.arm_contains_ref_binding(a)) | |
375 | .max_by_key(|m| match *m { | |
376 | hir::MutMutable => 1, | |
377 | hir::MutImmutable => 0, | |
378 | }); | |
379 | let discrim_ty; | |
380 | if let Some(m) = contains_ref_bindings { | |
381 | self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m)); | |
382 | discrim_ty = self.expr_ty(discrim); | |
54a0048b | 383 | } else { |
a7813a04 XL |
384 | // ...but otherwise we want to use any supertype of the |
385 | // discriminant. This is sort of a workaround, see note (*) in | |
386 | // `check_pat` for some details. | |
387 | discrim_ty = self.next_ty_var(); | |
388 | self.check_expr_has_type(discrim, discrim_ty); | |
54a0048b | 389 | }; |
1a4d82fc | 390 | |
a7813a04 XL |
391 | // Typecheck the patterns first, so that we get types for all the |
392 | // bindings. | |
393 | for arm in arms { | |
a7813a04 | 394 | for p in &arm.pats { |
3157f602 | 395 | self.check_pat(&p, discrim_ty); |
a7813a04 XL |
396 | } |
397 | } | |
1a4d82fc | 398 | |
a7813a04 XL |
399 | // Now typecheck the blocks. |
400 | // | |
401 | // The result of the match is the common supertype of all the | |
402 | // arms. Start out the value as bottom, since it's the, well, | |
403 | // bottom the type lattice, and we'll be moving up the lattice as | |
404 | // we process each arm. (Note that any match with 0 arms is matching | |
405 | // on any empty type and is therefore unreachable; should the flow | |
406 | // of execution reach it, we will panic, so bottom is an appropriate | |
407 | // type in that case) | |
408 | let expected = expected.adjust_for_branches(self); | |
409 | let mut result_ty = self.next_diverging_ty_var(); | |
410 | let coerce_first = match expected { | |
411 | // We don't coerce to `()` so that if the match expression is a | |
412 | // statement it's branches can have any consistent type. That allows | |
413 | // us to give better error messages (pointing to a usually better | |
414 | // arm for inconsistent arms or to the whole match when a `()` type | |
415 | // is required). | |
416 | Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => { | |
417 | ety | |
54a0048b | 418 | } |
a7813a04 | 419 | _ => result_ty |
54a0048b | 420 | }; |
a7813a04 XL |
421 | for (i, arm) in arms.iter().enumerate() { |
422 | if let Some(ref e) = arm.guard { | |
423 | self.check_expr_has_type(e, tcx.types.bool); | |
424 | } | |
425 | self.check_expr_with_expectation(&arm.body, expected); | |
426 | let arm_ty = self.expr_ty(&arm.body); | |
1a4d82fc | 427 | |
a7813a04 XL |
428 | if result_ty.references_error() || arm_ty.references_error() { |
429 | result_ty = tcx.types.err; | |
430 | continue; | |
431 | } | |
1a4d82fc | 432 | |
a7813a04 XL |
433 | // Handle the fallback arm of a desugared if-let like a missing else. |
434 | let is_if_let_fallback = match match_src { | |
435 | hir::MatchSource::IfLetDesugar { contains_else_clause: false } => { | |
436 | i == arms.len() - 1 && arm_ty.is_nil() | |
437 | } | |
438 | _ => false | |
439 | }; | |
1a4d82fc | 440 | |
a7813a04 XL |
441 | let origin = if is_if_let_fallback { |
442 | TypeOrigin::IfExpressionWithNoElse(expr.span) | |
443 | } else { | |
444 | TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src) | |
445 | }; | |
1a4d82fc | 446 | |
a7813a04 XL |
447 | let result = if is_if_let_fallback { |
448 | self.eq_types(true, origin, arm_ty, result_ty) | |
449 | .map(|InferOk { obligations, .. }| { | |
450 | // FIXME(#32730) propagate obligations | |
451 | assert!(obligations.is_empty()); | |
452 | arm_ty | |
453 | }) | |
454 | } else if i == 0 { | |
455 | // Special-case the first arm, as it has no "previous expressions". | |
456 | self.try_coerce(&arm.body, coerce_first) | |
457 | } else { | |
458 | let prev_arms = || arms[..i].iter().map(|arm| &*arm.body); | |
459 | self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body) | |
460 | }; | |
1a4d82fc | 461 | |
a7813a04 XL |
462 | result_ty = match result { |
463 | Ok(ty) => ty, | |
464 | Err(e) => { | |
465 | let (expected, found) = if is_if_let_fallback { | |
466 | (arm_ty, result_ty) | |
467 | } else { | |
468 | (result_ty, arm_ty) | |
469 | }; | |
470 | self.report_mismatched_types(origin, expected, found, e); | |
471 | self.tcx.types.err | |
472 | } | |
473 | }; | |
1a4d82fc | 474 | } |
1a4d82fc | 475 | |
a7813a04 | 476 | self.write_ty(expr.id, result_ty); |
92a42be0 SL |
477 | } |
478 | } | |
479 | ||
3157f602 | 480 | impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { |
5bcae85e SL |
481 | fn check_pat_struct(&self, |
482 | pat: &'gcx hir::Pat, | |
483 | path: &hir::Path, | |
484 | fields: &'gcx [Spanned<hir::FieldPat>], | |
485 | etc: bool, | |
486 | expected: Ty<'tcx>) | |
487 | { | |
488 | // Resolve the path and check the definition for errors. | |
489 | let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id, | |
490 | pat.span) { | |
491 | variant_ty | |
492 | } else { | |
493 | self.write_error(pat.id); | |
494 | for field in fields { | |
495 | self.check_pat(&field.node.pat, self.tcx.types.err); | |
9cc50fc6 | 496 | } |
5bcae85e | 497 | return; |
a7813a04 | 498 | }; |
9cc50fc6 | 499 | |
5bcae85e SL |
500 | // Type check the path. |
501 | self.demand_eqtype(pat.span, expected, pat_ty); | |
502 | ||
503 | // Type check subpatterns. | |
504 | let substs = match pat_ty.sty { | |
a7813a04 XL |
505 | ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, |
506 | _ => span_bug!(pat.span, "struct variant is not an ADT") | |
507 | }; | |
5bcae85e | 508 | self.check_struct_pat_fields(pat.span, fields, variant, substs, etc); |
d9579d0f AL |
509 | } |
510 | ||
5bcae85e | 511 | fn check_pat_path(&self, |
a7813a04 | 512 | pat: &hir::Pat, |
5bcae85e | 513 | opt_self_ty: Option<Ty<'tcx>>, |
a7813a04 | 514 | path: &hir::Path, |
5bcae85e | 515 | expected: Ty<'tcx>) |
a7813a04 | 516 | { |
a7813a04 | 517 | let tcx = self.tcx; |
5bcae85e SL |
518 | let report_unexpected_def = || { |
519 | span_err!(tcx.sess, pat.span, E0533, | |
520 | "`{}` does not name a unit variant, unit struct or a constant", | |
521 | pprust::path_to_string(path)); | |
3157f602 | 522 | self.write_error(pat.id); |
a7813a04 | 523 | }; |
1a4d82fc | 524 | |
5bcae85e SL |
525 | // Resolve the path and check the definition for errors. |
526 | let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path, | |
527 | pat.id, pat.span); | |
528 | match def { | |
529 | Def::Err => { | |
530 | self.set_tainted_by_errors(); | |
531 | self.write_error(pat.id); | |
532 | return; | |
533 | } | |
534 | Def::Method(..) => { | |
535 | report_unexpected_def(); | |
536 | return; | |
537 | } | |
538 | Def::Variant(..) | Def::Struct(..) => { | |
539 | let variant = tcx.expect_variant_def(def); | |
540 | if variant.kind != VariantKind::Unit { | |
541 | report_unexpected_def(); | |
542 | return; | |
543 | } | |
544 | } | |
545 | Def::Const(..) | Def::AssociatedConst(..) => {} // OK | |
546 | _ => bug!("unexpected pattern definition {:?}", def) | |
1a4d82fc | 547 | } |
1a4d82fc | 548 | |
5bcae85e SL |
549 | // Type check the path. |
550 | let scheme = tcx.lookup_item_type(def.def_id()); | |
551 | let predicates = tcx.lookup_predicates(def.def_id()); | |
552 | let pat_ty = self.instantiate_value_path(segments, scheme, &predicates, | |
553 | opt_ty, def, pat.span, pat.id); | |
554 | self.demand_suptype(pat.span, expected, pat_ty); | |
555 | } | |
7453a54e | 556 | |
5bcae85e SL |
557 | fn check_pat_tuple_struct(&self, |
558 | pat: &hir::Pat, | |
559 | path: &hir::Path, | |
560 | subpats: &'gcx [P<hir::Pat>], | |
561 | ddpos: Option<usize>, | |
562 | expected: Ty<'tcx>) | |
563 | { | |
564 | let tcx = self.tcx; | |
565 | let on_error = || { | |
a7813a04 | 566 | self.write_error(pat.id); |
3157f602 XL |
567 | for pat in subpats { |
568 | self.check_pat(&pat, tcx.types.err); | |
1a4d82fc | 569 | } |
a7813a04 | 570 | }; |
5bcae85e SL |
571 | let report_unexpected_def = |is_lint| { |
572 | let msg = format!("`{}` does not name a tuple variant or a tuple struct", | |
573 | pprust::path_to_string(path)); | |
574 | if is_lint { | |
575 | tcx.sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, | |
576 | pat.id, pat.span, msg); | |
a7813a04 | 577 | } else { |
5bcae85e SL |
578 | span_err!(tcx.sess, pat.span, E0164, "{}", msg); |
579 | on_error(); | |
1a4d82fc | 580 | } |
5bcae85e | 581 | }; |
a7813a04 | 582 | |
5bcae85e SL |
583 | // Resolve the path and check the definition for errors. |
584 | let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(None, path, pat.id, pat.span); | |
585 | let variant = match def { | |
586 | Def::Err => { | |
587 | self.set_tainted_by_errors(); | |
588 | on_error(); | |
a7813a04 | 589 | return; |
1a4d82fc | 590 | } |
5bcae85e SL |
591 | Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => { |
592 | report_unexpected_def(false); | |
593 | return; | |
a7813a04 | 594 | } |
5bcae85e SL |
595 | Def::Variant(..) | Def::Struct(..) => { |
596 | tcx.expect_variant_def(def) | |
a7813a04 | 597 | } |
5bcae85e SL |
598 | _ => bug!("unexpected pattern definition {:?}", def) |
599 | }; | |
600 | if variant.kind == VariantKind::Unit && subpats.is_empty() && ddpos.is_some() { | |
601 | // Matching unit structs with tuple variant patterns (`UnitVariant(..)`) | |
602 | // is allowed for backward compatibility. | |
603 | report_unexpected_def(true); | |
604 | } else if variant.kind != VariantKind::Tuple { | |
605 | report_unexpected_def(false); | |
606 | return; | |
a7813a04 XL |
607 | } |
608 | ||
5bcae85e SL |
609 | // Type check the path. |
610 | let scheme = tcx.lookup_item_type(def.def_id()); | |
611 | let scheme = if scheme.ty.is_fn() { | |
612 | // Replace constructor type with constructed type for tuple struct patterns. | |
613 | let fn_ret = tcx.no_late_bound_regions(&scheme.ty.fn_ret()).unwrap(); | |
614 | ty::TypeScheme { ty: fn_ret, generics: scheme.generics } | |
615 | } else { | |
616 | // Leave the type as is for unit structs (backward compatibility). | |
617 | scheme | |
618 | }; | |
619 | let predicates = tcx.lookup_predicates(def.def_id()); | |
620 | let pat_ty = self.instantiate_value_path(segments, scheme, &predicates, | |
621 | opt_ty, def, pat.span, pat.id); | |
622 | self.demand_eqtype(pat.span, expected, pat_ty); | |
623 | ||
624 | // Type check subpatterns. | |
3157f602 XL |
625 | if subpats.len() == variant.fields.len() || |
626 | subpats.len() < variant.fields.len() && ddpos.is_some() { | |
5bcae85e SL |
627 | let substs = match pat_ty.sty { |
628 | ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, | |
629 | ref ty => bug!("unexpected pattern type {:?}", ty), | |
630 | }; | |
3157f602 | 631 | for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { |
5bcae85e | 632 | let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs); |
3157f602 XL |
633 | self.check_pat(&subpat, field_ty); |
634 | } | |
635 | } else { | |
5bcae85e SL |
636 | let subpats_ending = if subpats.len() == 1 { |
637 | "" | |
638 | } else { | |
639 | "s" | |
640 | }; | |
641 | let fields_ending = if variant.fields.len() == 1 { | |
642 | "" | |
643 | } else { | |
644 | "s" | |
645 | }; | |
646 | struct_span_err!(tcx.sess, pat.span, E0023, | |
647 | "this pattern has {} field{}, but the corresponding {} has {} field{}", | |
648 | subpats.len(), subpats_ending, def.kind_name(), | |
649 | variant.fields.len(), fields_ending) | |
650 | .span_label(pat.span, &format!("expected {} field{}, found {}", | |
651 | variant.fields.len(), fields_ending, subpats.len())) | |
652 | .emit(); | |
653 | on_error(); | |
a7813a04 | 654 | } |
1a4d82fc JJ |
655 | } |
656 | ||
a7813a04 XL |
657 | /// `path` is the AST path item naming the type of this struct. |
658 | /// `fields` is the field patterns of the struct pattern. | |
659 | /// `struct_fields` describes the type of each field of the struct. | |
660 | /// `struct_id` is the ID of the struct. | |
661 | /// `etc` is true if the pattern said '...' and false otherwise. | |
662 | pub fn check_struct_pat_fields(&self, | |
663 | span: Span, | |
664 | fields: &'gcx [Spanned<hir::FieldPat>], | |
665 | variant: ty::VariantDef<'tcx>, | |
666 | substs: &Substs<'tcx>, | |
667 | etc: bool) { | |
668 | let tcx = self.tcx; | |
669 | ||
670 | // Index the struct fields' types. | |
671 | let field_map = variant.fields | |
1a4d82fc | 672 | .iter() |
a7813a04 XL |
673 | .map(|field| (field.name, field)) |
674 | .collect::<FnvHashMap<_, _>>(); | |
675 | ||
676 | // Keep track of which fields have already appeared in the pattern. | |
677 | let mut used_fields = FnvHashMap(); | |
678 | ||
679 | // Typecheck each field. | |
680 | for &Spanned { node: ref field, span } in fields { | |
681 | let field_ty = match used_fields.entry(field.name) { | |
682 | Occupied(occupied) => { | |
683 | let mut err = struct_span_err!(tcx.sess, span, E0025, | |
684 | "field `{}` bound multiple times \ | |
685 | in the pattern", | |
686 | field.name); | |
687 | span_note!(&mut err, *occupied.get(), | |
688 | "field `{}` previously bound here", | |
689 | field.name); | |
690 | err.emit(); | |
691 | tcx.types.err | |
692 | } | |
693 | Vacant(vacant) => { | |
694 | vacant.insert(span); | |
695 | field_map.get(&field.name) | |
696 | .map(|f| self.field_ty(span, f, substs)) | |
697 | .unwrap_or_else(|| { | |
5bcae85e SL |
698 | struct_span_err!(tcx.sess, span, E0026, |
699 | "struct `{}` does not have a field named `{}`", | |
700 | tcx.item_path_str(variant.did), | |
701 | field.name) | |
702 | .span_label(span, | |
703 | &format!("struct `{}` does not have field `{}`", | |
704 | tcx.item_path_str(variant.did), | |
705 | field.name)) | |
706 | .emit(); | |
707 | ||
a7813a04 XL |
708 | tcx.types.err |
709 | }) | |
710 | } | |
711 | }; | |
712 | ||
713 | self.check_pat(&field.pat, field_ty); | |
714 | } | |
715 | ||
716 | // Report an error if not all the fields were specified. | |
717 | if !etc { | |
718 | for field in variant.fields | |
719 | .iter() | |
720 | .filter(|field| !used_fields.contains_key(&field.name)) { | |
5bcae85e SL |
721 | struct_span_err!(tcx.sess, span, E0027, |
722 | "pattern does not mention field `{}`", | |
723 | field.name) | |
724 | .span_label(span, &format!("missing field `{}`", field.name)) | |
725 | .emit(); | |
a7813a04 | 726 | } |
1a4d82fc JJ |
727 | } |
728 | } | |
729 | } |