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