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