]>
Commit | Line | Data |
---|---|---|
1 | // Copyright 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 astconv::AstConv; | |
12 | use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck}; | |
13 | use constrained_type_params::{identify_constrained_type_params, Parameter}; | |
14 | use CrateCtxt; | |
15 | use middle::region; | |
16 | use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; | |
17 | use middle::traits; | |
18 | use middle::ty::{self, Ty}; | |
19 | use middle::ty::liberate_late_bound_regions; | |
20 | use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty}; | |
21 | ||
22 | use std::collections::HashSet; | |
23 | use syntax::ast; | |
24 | use syntax::ast_util::local_def; | |
25 | use syntax::codemap::{DUMMY_SP, Span}; | |
26 | use syntax::parse::token::{self, special_idents}; | |
27 | use syntax::visit; | |
28 | use syntax::visit::Visitor; | |
29 | ||
30 | pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> { | |
31 | ccx: &'ccx CrateCtxt<'ccx, 'tcx>, | |
32 | cache: HashSet<Ty<'tcx>> | |
33 | } | |
34 | ||
35 | impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { | |
36 | pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'tcx>) -> CheckTypeWellFormedVisitor<'ccx, 'tcx> { | |
37 | CheckTypeWellFormedVisitor { ccx: ccx, cache: HashSet::new() } | |
38 | } | |
39 | ||
40 | fn tcx(&self) -> &ty::ctxt<'tcx> { | |
41 | self.ccx.tcx | |
42 | } | |
43 | ||
44 | /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are | |
45 | /// well-formed, meaning that they do not require any constraints not declared in the struct | |
46 | /// definition itself. For example, this definition would be illegal: | |
47 | /// | |
48 | /// struct Ref<'a, T> { x: &'a T } | |
49 | /// | |
50 | /// because the type did not declare that `T:'a`. | |
51 | /// | |
52 | /// We do this check as a pre-pass before checking fn bodies because if these constraints are | |
53 | /// not included it frequently leads to confusing errors in fn bodies. So it's better to check | |
54 | /// the types first. | |
55 | fn check_item_well_formed(&mut self, item: &ast::Item) { | |
56 | let ccx = self.ccx; | |
57 | debug!("check_item_well_formed(it.id={}, it.ident={})", | |
58 | item.id, | |
59 | ty::item_path_str(ccx.tcx, local_def(item.id))); | |
60 | ||
61 | match item.node { | |
62 | /// Right now we check that every default trait implementation | |
63 | /// has an implementation of itself. Basically, a case like: | |
64 | /// | |
65 | /// `impl Trait for T {}` | |
66 | /// | |
67 | /// has a requirement of `T: Trait` which was required for default | |
68 | /// method implementations. Although this could be improved now that | |
69 | /// there's a better infrastructure in place for this, it's being left | |
70 | /// for a follow-up work. | |
71 | /// | |
72 | /// Since there's such a requirement, we need to check *just* positive | |
73 | /// implementations, otherwise things like: | |
74 | /// | |
75 | /// impl !Send for T {} | |
76 | /// | |
77 | /// won't be allowed unless there's an *explicit* implementation of `Send` | |
78 | /// for `T` | |
79 | ast::ItemImpl(_, ast::ImplPolarity::Positive, _, _, _, _) => { | |
80 | self.check_impl(item); | |
81 | } | |
82 | ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(_), _, _) => { | |
83 | let trait_ref = ty::impl_trait_ref(ccx.tcx, | |
84 | local_def(item.id)).unwrap(); | |
85 | ty::populate_implementations_for_trait_if_necessary(ccx.tcx, trait_ref.def_id); | |
86 | match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) { | |
87 | Some(ty::BoundSend) | Some(ty::BoundSync) => {} | |
88 | Some(_) | None => { | |
89 | if !ty::trait_has_default_impl(ccx.tcx, trait_ref.def_id) { | |
90 | span_err!(ccx.tcx.sess, item.span, E0192, | |
91 | "negative impls are only allowed for traits with \ | |
92 | default impls (e.g., `Send` and `Sync`)") | |
93 | } | |
94 | } | |
95 | } | |
96 | } | |
97 | ast::ItemFn(..) => { | |
98 | self.check_item_type(item); | |
99 | } | |
100 | ast::ItemStatic(..) => { | |
101 | self.check_item_type(item); | |
102 | } | |
103 | ast::ItemConst(..) => { | |
104 | self.check_item_type(item); | |
105 | } | |
106 | ast::ItemStruct(ref struct_def, ref ast_generics) => { | |
107 | self.check_type_defn(item, |fcx| { | |
108 | vec![struct_variant(fcx, &**struct_def)] | |
109 | }); | |
110 | ||
111 | self.check_variances_for_type_defn(item, ast_generics); | |
112 | } | |
113 | ast::ItemEnum(ref enum_def, ref ast_generics) => { | |
114 | self.check_type_defn(item, |fcx| { | |
115 | enum_variants(fcx, enum_def) | |
116 | }); | |
117 | ||
118 | self.check_variances_for_type_defn(item, ast_generics); | |
119 | } | |
120 | ast::ItemTrait(_, _, _, ref items) => { | |
121 | let trait_predicates = | |
122 | ty::lookup_predicates(ccx.tcx, local_def(item.id)); | |
123 | reject_non_type_param_bounds(ccx.tcx, item.span, &trait_predicates); | |
124 | if ty::trait_has_default_impl(ccx.tcx, local_def(item.id)) { | |
125 | if !items.is_empty() { | |
126 | span_err!(ccx.tcx.sess, item.span, E0380, | |
127 | "traits with default impls (`e.g. unsafe impl \ | |
128 | Trait for ..`) must have no methods or associated items") | |
129 | } | |
130 | } | |
131 | } | |
132 | _ => {} | |
133 | } | |
134 | } | |
135 | ||
136 | fn with_fcx<F>(&mut self, item: &ast::Item, mut f: F) where | |
137 | F: for<'fcx> FnMut(&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, &FnCtxt<'fcx, 'tcx>), | |
138 | { | |
139 | let ccx = self.ccx; | |
140 | let item_def_id = local_def(item.id); | |
141 | let type_scheme = ty::lookup_item_type(ccx.tcx, item_def_id); | |
142 | let type_predicates = ty::lookup_predicates(ccx.tcx, item_def_id); | |
143 | reject_non_type_param_bounds(ccx.tcx, item.span, &type_predicates); | |
144 | let param_env = | |
145 | ty::construct_parameter_environment(ccx.tcx, | |
146 | item.span, | |
147 | &type_scheme.generics, | |
148 | &type_predicates, | |
149 | item.id); | |
150 | let inh = Inherited::new(ccx.tcx, param_env); | |
151 | let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id); | |
152 | f(self, &fcx); | |
153 | fcx.select_all_obligations_or_error(); | |
154 | regionck::regionck_item(&fcx, item); | |
155 | } | |
156 | ||
157 | /// In a type definition, we check that to ensure that the types of the fields are well-formed. | |
158 | fn check_type_defn<F>(&mut self, item: &ast::Item, mut lookup_fields: F) where | |
159 | F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec<AdtVariant<'tcx>>, | |
160 | { | |
161 | self.with_fcx(item, |this, fcx| { | |
162 | let variants = lookup_fields(fcx); | |
163 | let mut bounds_checker = BoundsChecker::new(fcx, | |
164 | item.id, | |
165 | Some(&mut this.cache)); | |
166 | debug!("check_type_defn at bounds_checker.scope: {:?}", bounds_checker.scope); | |
167 | ||
168 | for variant in &variants { | |
169 | for field in &variant.fields { | |
170 | // Regions are checked below. | |
171 | bounds_checker.check_traits_in_ty(field.ty, field.span); | |
172 | } | |
173 | ||
174 | // For DST, all intermediate types must be sized. | |
175 | if !variant.fields.is_empty() { | |
176 | for field in variant.fields.init() { | |
177 | fcx.register_builtin_bound( | |
178 | field.ty, | |
179 | ty::BoundSized, | |
180 | traits::ObligationCause::new(field.span, | |
181 | fcx.body_id, | |
182 | traits::FieldSized)); | |
183 | } | |
184 | } | |
185 | } | |
186 | ||
187 | let field_tys: Vec<Ty> = | |
188 | variants.iter().flat_map(|v| v.fields.iter().map(|f| f.ty)).collect(); | |
189 | ||
190 | regionck::regionck_ensure_component_tys_wf( | |
191 | fcx, item.span, &field_tys); | |
192 | }); | |
193 | } | |
194 | ||
195 | fn check_item_type(&mut self, | |
196 | item: &ast::Item) | |
197 | { | |
198 | self.with_fcx(item, |this, fcx| { | |
199 | let mut bounds_checker = BoundsChecker::new(fcx, | |
200 | item.id, | |
201 | Some(&mut this.cache)); | |
202 | debug!("check_item_type at bounds_checker.scope: {:?}", bounds_checker.scope); | |
203 | ||
204 | let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id)); | |
205 | let item_ty = fcx.instantiate_type_scheme(item.span, | |
206 | &fcx.inh.param_env.free_substs, | |
207 | &type_scheme.ty); | |
208 | ||
209 | bounds_checker.check_traits_in_ty(item_ty, item.span); | |
210 | }); | |
211 | } | |
212 | ||
213 | fn check_impl(&mut self, | |
214 | item: &ast::Item) | |
215 | { | |
216 | self.with_fcx(item, |this, fcx| { | |
217 | let mut bounds_checker = BoundsChecker::new(fcx, | |
218 | item.id, | |
219 | Some(&mut this.cache)); | |
220 | debug!("check_impl at bounds_checker.scope: {:?}", bounds_checker.scope); | |
221 | ||
222 | // Find the impl self type as seen from the "inside" -- | |
223 | // that is, with all type parameters converted from bound | |
224 | // to free. | |
225 | let self_ty = ty::node_id_to_type(fcx.tcx(), item.id); | |
226 | let self_ty = fcx.instantiate_type_scheme(item.span, | |
227 | &fcx.inh.param_env.free_substs, | |
228 | &self_ty); | |
229 | ||
230 | bounds_checker.check_traits_in_ty(self_ty, item.span); | |
231 | ||
232 | // Similarly, obtain an "inside" reference to the trait | |
233 | // that the impl implements. | |
234 | let trait_ref = match ty::impl_trait_ref(fcx.tcx(), local_def(item.id)) { | |
235 | None => { return; } | |
236 | Some(t) => { t } | |
237 | }; | |
238 | ||
239 | let trait_ref = fcx.instantiate_type_scheme(item.span, | |
240 | &fcx.inh.param_env.free_substs, | |
241 | &trait_ref); | |
242 | ||
243 | // We are stricter on the trait-ref in an impl than the | |
244 | // self-type. In particular, we enforce region | |
245 | // relationships. The reason for this is that (at least | |
246 | // presently) "applying" an impl does not require that the | |
247 | // application site check the well-formedness constraints on the | |
248 | // trait reference. Instead, this is done at the impl site. | |
249 | // Arguably this is wrong and we should treat the trait-reference | |
250 | // the same way as we treat the self-type. | |
251 | bounds_checker.check_trait_ref(&trait_ref, item.span); | |
252 | ||
253 | let cause = | |
254 | traits::ObligationCause::new( | |
255 | item.span, | |
256 | fcx.body_id, | |
257 | traits::ItemObligation(trait_ref.def_id)); | |
258 | ||
259 | // Find the supertrait bounds. This will add `int:Bar`. | |
260 | let poly_trait_ref = ty::Binder(trait_ref); | |
261 | let predicates = ty::lookup_super_predicates(fcx.tcx(), poly_trait_ref.def_id()); | |
262 | let predicates = predicates.instantiate_supertrait(fcx.tcx(), &poly_trait_ref); | |
263 | let predicates = { | |
264 | let selcx = &mut traits::SelectionContext::new(fcx.infcx(), fcx); | |
265 | traits::normalize(selcx, cause.clone(), &predicates) | |
266 | }; | |
267 | for predicate in predicates.value.predicates { | |
268 | fcx.register_predicate(traits::Obligation::new(cause.clone(), predicate)); | |
269 | } | |
270 | for obligation in predicates.obligations { | |
271 | fcx.register_predicate(obligation); | |
272 | } | |
273 | }); | |
274 | } | |
275 | ||
276 | fn check_variances_for_type_defn(&self, | |
277 | item: &ast::Item, | |
278 | ast_generics: &ast::Generics) | |
279 | { | |
280 | let item_def_id = local_def(item.id); | |
281 | let ty_predicates = ty::lookup_predicates(self.tcx(), item_def_id); | |
282 | let variances = ty::item_variances(self.tcx(), item_def_id); | |
283 | ||
284 | let mut constrained_parameters: HashSet<_> = | |
285 | variances.types | |
286 | .iter_enumerated() | |
287 | .filter(|&(_, _, &variance)| variance != ty::Bivariant) | |
288 | .map(|(space, index, _)| self.param_ty(ast_generics, space, index)) | |
289 | .map(|p| Parameter::Type(p)) | |
290 | .collect(); | |
291 | ||
292 | identify_constrained_type_params(self.tcx(), | |
293 | ty_predicates.predicates.as_slice(), | |
294 | None, | |
295 | &mut constrained_parameters); | |
296 | ||
297 | for (space, index, _) in variances.types.iter_enumerated() { | |
298 | let param_ty = self.param_ty(ast_generics, space, index); | |
299 | if constrained_parameters.contains(&Parameter::Type(param_ty)) { | |
300 | continue; | |
301 | } | |
302 | let span = self.ty_param_span(ast_generics, item, space, index); | |
303 | self.report_bivariance(span, param_ty.name); | |
304 | } | |
305 | ||
306 | for (space, index, &variance) in variances.regions.iter_enumerated() { | |
307 | if variance != ty::Bivariant { | |
308 | continue; | |
309 | } | |
310 | ||
311 | assert_eq!(space, TypeSpace); | |
312 | let span = ast_generics.lifetimes[index].lifetime.span; | |
313 | let name = ast_generics.lifetimes[index].lifetime.name; | |
314 | self.report_bivariance(span, name); | |
315 | } | |
316 | } | |
317 | ||
318 | fn param_ty(&self, | |
319 | ast_generics: &ast::Generics, | |
320 | space: ParamSpace, | |
321 | index: usize) | |
322 | -> ty::ParamTy | |
323 | { | |
324 | let name = match space { | |
325 | TypeSpace => ast_generics.ty_params[index].ident.name, | |
326 | SelfSpace => special_idents::type_self.name, | |
327 | FnSpace => self.tcx().sess.bug("Fn space occupied?"), | |
328 | }; | |
329 | ||
330 | ty::ParamTy { space: space, idx: index as u32, name: name } | |
331 | } | |
332 | ||
333 | fn ty_param_span(&self, | |
334 | ast_generics: &ast::Generics, | |
335 | item: &ast::Item, | |
336 | space: ParamSpace, | |
337 | index: usize) | |
338 | -> Span | |
339 | { | |
340 | match space { | |
341 | TypeSpace => ast_generics.ty_params[index].span, | |
342 | SelfSpace => item.span, | |
343 | FnSpace => self.tcx().sess.span_bug(item.span, "Fn space occupied?"), | |
344 | } | |
345 | } | |
346 | ||
347 | fn report_bivariance(&self, | |
348 | span: Span, | |
349 | param_name: ast::Name) | |
350 | { | |
351 | span_err!(self.tcx().sess, span, E0392, | |
352 | "parameter `{}` is never used", param_name); | |
353 | ||
354 | let suggested_marker_id = self.tcx().lang_items.phantom_data(); | |
355 | match suggested_marker_id { | |
356 | Some(def_id) => { | |
357 | self.tcx().sess.fileline_help( | |
358 | span, | |
359 | &format!("consider removing `{}` or using a marker such as `{}`", | |
360 | param_name, | |
361 | ty::item_path_str(self.tcx(), def_id))); | |
362 | } | |
363 | None => { | |
364 | // no lang items, no help! | |
365 | } | |
366 | } | |
367 | } | |
368 | } | |
369 | ||
370 | // Reject any predicates that do not involve a type parameter. | |
371 | fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, | |
372 | span: Span, | |
373 | predicates: &ty::GenericPredicates<'tcx>) { | |
374 | for predicate in &predicates.predicates { | |
375 | match predicate { | |
376 | &ty::Predicate::Trait(ty::Binder(ref tr)) => { | |
377 | let found_param = tr.input_types().iter() | |
378 | .flat_map(|ty| ty.walk()) | |
379 | .any(is_ty_param); | |
380 | if !found_param { report_bound_error(tcx, span, tr.self_ty() )} | |
381 | } | |
382 | &ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(ty, _))) => { | |
383 | let found_param = ty.walk().any(|t| is_ty_param(t)); | |
384 | if !found_param { report_bound_error(tcx, span, ty) } | |
385 | } | |
386 | _ => {} | |
387 | }; | |
388 | } | |
389 | ||
390 | fn report_bound_error<'t>(tcx: &ty::ctxt<'t>, | |
391 | span: Span, | |
392 | bounded_ty: ty::Ty<'t>) { | |
393 | span_err!(tcx.sess, span, E0193, | |
394 | "cannot bound type `{}`, where clause \ | |
395 | bounds may only be attached to types involving \ | |
396 | type parameters", | |
397 | bounded_ty) | |
398 | } | |
399 | ||
400 | fn is_ty_param(ty: ty::Ty) -> bool { | |
401 | match &ty.sty { | |
402 | &ty::TyParam(_) => true, | |
403 | _ => false | |
404 | } | |
405 | } | |
406 | } | |
407 | ||
408 | fn reject_shadowing_type_parameters<'tcx>(tcx: &ty::ctxt<'tcx>, | |
409 | span: Span, | |
410 | generics: &ty::Generics<'tcx>) { | |
411 | let impl_params = generics.types.get_slice(subst::TypeSpace).iter() | |
412 | .map(|tp| tp.name).collect::<HashSet<_>>(); | |
413 | ||
414 | for method_param in generics.types.get_slice(subst::FnSpace) { | |
415 | if impl_params.contains(&method_param.name) { | |
416 | span_err!(tcx.sess, span, E0194, | |
417 | "type parameter `{}` shadows another type parameter of the same name", | |
418 | token::get_name(method_param.name)); | |
419 | } | |
420 | } | |
421 | } | |
422 | ||
423 | impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { | |
424 | fn visit_item(&mut self, i: &ast::Item) { | |
425 | self.check_item_well_formed(i); | |
426 | visit::walk_item(self, i); | |
427 | } | |
428 | ||
429 | fn visit_fn(&mut self, | |
430 | fk: visit::FnKind<'v>, fd: &'v ast::FnDecl, | |
431 | b: &'v ast::Block, span: Span, id: ast::NodeId) { | |
432 | match fk { | |
433 | visit::FkFnBlock | visit::FkItemFn(..) => {} | |
434 | visit::FkMethod(..) => { | |
435 | match ty::impl_or_trait_item(self.tcx(), local_def(id)) { | |
436 | ty::ImplOrTraitItem::MethodTraitItem(ty_method) => { | |
437 | reject_shadowing_type_parameters(self.tcx(), span, &ty_method.generics) | |
438 | } | |
439 | _ => {} | |
440 | } | |
441 | } | |
442 | } | |
443 | visit::walk_fn(self, fk, fd, b, span) | |
444 | } | |
445 | ||
446 | fn visit_trait_item(&mut self, trait_item: &'v ast::TraitItem) { | |
447 | if let ast::MethodTraitItem(_, None) = trait_item.node { | |
448 | match ty::impl_or_trait_item(self.tcx(), local_def(trait_item.id)) { | |
449 | ty::ImplOrTraitItem::MethodTraitItem(ty_method) => { | |
450 | reject_non_type_param_bounds( | |
451 | self.tcx(), | |
452 | trait_item.span, | |
453 | &ty_method.predicates); | |
454 | reject_shadowing_type_parameters( | |
455 | self.tcx(), | |
456 | trait_item.span, | |
457 | &ty_method.generics); | |
458 | } | |
459 | _ => {} | |
460 | } | |
461 | } | |
462 | ||
463 | visit::walk_trait_item(self, trait_item) | |
464 | } | |
465 | } | |
466 | ||
467 | pub struct BoundsChecker<'cx,'tcx:'cx> { | |
468 | fcx: &'cx FnCtxt<'cx,'tcx>, | |
469 | span: Span, | |
470 | ||
471 | // This field is often attached to item impls; it is not clear | |
472 | // that `CodeExtent` is well-defined for such nodes, so pnkfelix | |
473 | // has left it as a NodeId rather than porting to CodeExtent. | |
474 | scope: ast::NodeId, | |
475 | ||
476 | binding_count: usize, | |
477 | cache: Option<&'cx mut HashSet<Ty<'tcx>>>, | |
478 | } | |
479 | ||
480 | impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { | |
481 | pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>, | |
482 | scope: ast::NodeId, | |
483 | cache: Option<&'cx mut HashSet<Ty<'tcx>>>) | |
484 | -> BoundsChecker<'cx,'tcx> { | |
485 | BoundsChecker { fcx: fcx, span: DUMMY_SP, scope: scope, | |
486 | cache: cache, binding_count: 0 } | |
487 | } | |
488 | ||
489 | /// Given a trait ref like `A : Trait<B>`, where `Trait` is defined as (say): | |
490 | /// | |
491 | /// trait Trait<B:OtherTrait> : Copy { ... } | |
492 | /// | |
493 | /// This routine will check that `B : OtherTrait` and `A : Trait<B>`. It will also recursively | |
494 | /// check that the types `A` and `B` are well-formed. | |
495 | /// | |
496 | /// Note that it does not (currently, at least) check that `A : Copy` (that check is delegated | |
497 | /// to the point where impl `A : Trait<B>` is implemented). | |
498 | pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, span: Span) { | |
499 | let trait_predicates = ty::lookup_predicates(self.fcx.tcx(), trait_ref.def_id); | |
500 | ||
501 | let bounds = self.fcx.instantiate_bounds(span, | |
502 | trait_ref.substs, | |
503 | &trait_predicates); | |
504 | ||
505 | self.fcx.add_obligations_for_parameters( | |
506 | traits::ObligationCause::new( | |
507 | span, | |
508 | self.fcx.body_id, | |
509 | traits::ItemObligation(trait_ref.def_id)), | |
510 | &bounds); | |
511 | ||
512 | for &ty in &trait_ref.substs.types { | |
513 | self.check_traits_in_ty(ty, span); | |
514 | } | |
515 | } | |
516 | ||
517 | pub fn check_ty(&mut self, ty: Ty<'tcx>, span: Span) { | |
518 | self.span = span; | |
519 | ty.fold_with(self); | |
520 | } | |
521 | ||
522 | fn check_traits_in_ty(&mut self, ty: Ty<'tcx>, span: Span) { | |
523 | self.span = span; | |
524 | // When checking types outside of a type def'n, we ignore | |
525 | // region obligations. See discussion below in fold_ty(). | |
526 | self.binding_count += 1; | |
527 | ty.fold_with(self); | |
528 | self.binding_count -= 1; | |
529 | } | |
530 | } | |
531 | ||
532 | impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { | |
533 | fn tcx(&self) -> &ty::ctxt<'tcx> { | |
534 | self.fcx.tcx() | |
535 | } | |
536 | ||
537 | fn fold_binder<T>(&mut self, binder: &ty::Binder<T>) -> ty::Binder<T> | |
538 | where T : TypeFoldable<'tcx> | |
539 | { | |
540 | self.binding_count += 1; | |
541 | let value = liberate_late_bound_regions( | |
542 | self.fcx.tcx(), | |
543 | region::DestructionScopeData::new(self.scope), | |
544 | binder); | |
545 | debug!("BoundsChecker::fold_binder: late-bound regions replaced: {:?} at scope: {:?}", | |
546 | value, self.scope); | |
547 | let value = value.fold_with(self); | |
548 | self.binding_count -= 1; | |
549 | ty::Binder(value) | |
550 | } | |
551 | ||
552 | fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { | |
553 | debug!("BoundsChecker t={:?}", | |
554 | t); | |
555 | ||
556 | match self.cache { | |
557 | Some(ref mut cache) => { | |
558 | if !cache.insert(t) { | |
559 | // Already checked this type! Don't check again. | |
560 | debug!("cached"); | |
561 | return t; | |
562 | } | |
563 | } | |
564 | None => { } | |
565 | } | |
566 | ||
567 | match t.sty{ | |
568 | ty::TyStruct(type_id, substs) | | |
569 | ty::TyEnum(type_id, substs) => { | |
570 | let type_predicates = ty::lookup_predicates(self.fcx.tcx(), type_id); | |
571 | let bounds = self.fcx.instantiate_bounds(self.span, substs, | |
572 | &type_predicates); | |
573 | ||
574 | if self.binding_count == 0 { | |
575 | self.fcx.add_obligations_for_parameters( | |
576 | traits::ObligationCause::new(self.span, | |
577 | self.fcx.body_id, | |
578 | traits::ItemObligation(type_id)), | |
579 | &bounds); | |
580 | } else { | |
581 | // There are two circumstances in which we ignore | |
582 | // region obligations. | |
583 | // | |
584 | // The first is when we are inside of a closure | |
585 | // type. This is because in that case the region | |
586 | // obligations for the parameter types are things | |
587 | // that the closure body gets to assume and the | |
588 | // caller must prove at the time of call. In other | |
589 | // words, if there is a type like `<'a, 'b> | &'a | |
590 | // &'b int |`, it is well-formed, and caller will | |
591 | // have to show that `'b : 'a` at the time of | |
592 | // call. | |
593 | // | |
594 | // The second is when we are checking for | |
595 | // well-formedness outside of a type def'n or fn | |
596 | // body. This is for a similar reason: in general, | |
597 | // we only do WF checking for regions in the | |
598 | // result of expressions and type definitions, so | |
599 | // to as allow for implicit where clauses. | |
600 | // | |
601 | // (I believe we should do the same for traits, but | |
602 | // that will require an RFC. -nmatsakis) | |
603 | let bounds = filter_to_trait_obligations(bounds); | |
604 | self.fcx.add_obligations_for_parameters( | |
605 | traits::ObligationCause::new(self.span, | |
606 | self.fcx.body_id, | |
607 | traits::ItemObligation(type_id)), | |
608 | &bounds); | |
609 | } | |
610 | ||
611 | self.fold_substs(substs); | |
612 | } | |
613 | _ => { | |
614 | super_fold_ty(self, t); | |
615 | } | |
616 | } | |
617 | ||
618 | t // we're not folding to produce a new type, so just return `t` here | |
619 | } | |
620 | } | |
621 | ||
622 | /////////////////////////////////////////////////////////////////////////// | |
623 | // ADT | |
624 | ||
625 | struct AdtVariant<'tcx> { | |
626 | fields: Vec<AdtField<'tcx>>, | |
627 | } | |
628 | ||
629 | struct AdtField<'tcx> { | |
630 | ty: Ty<'tcx>, | |
631 | span: Span, | |
632 | } | |
633 | ||
634 | fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, | |
635 | struct_def: &ast::StructDef) | |
636 | -> AdtVariant<'tcx> { | |
637 | let fields = | |
638 | struct_def.fields | |
639 | .iter() | |
640 | .map(|field| { | |
641 | let field_ty = ty::node_id_to_type(fcx.tcx(), field.node.id); | |
642 | let field_ty = fcx.instantiate_type_scheme(field.span, | |
643 | &fcx.inh.param_env.free_substs, | |
644 | &field_ty); | |
645 | AdtField { ty: field_ty, span: field.span } | |
646 | }) | |
647 | .collect(); | |
648 | AdtVariant { fields: fields } | |
649 | } | |
650 | ||
651 | fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, | |
652 | enum_def: &ast::EnumDef) | |
653 | -> Vec<AdtVariant<'tcx>> { | |
654 | enum_def.variants.iter() | |
655 | .map(|variant| { | |
656 | match variant.node.kind { | |
657 | ast::TupleVariantKind(ref args) if !args.is_empty() => { | |
658 | let ctor_ty = ty::node_id_to_type(fcx.tcx(), variant.node.id); | |
659 | ||
660 | // the regions in the argument types come from the | |
661 | // enum def'n, and hence will all be early bound | |
662 | let arg_tys = | |
663 | ty::no_late_bound_regions( | |
664 | fcx.tcx(), &ty::ty_fn_args(ctor_ty)).unwrap(); | |
665 | AdtVariant { | |
666 | fields: args.iter().enumerate().map(|(index, arg)| { | |
667 | let arg_ty = arg_tys[index]; | |
668 | let arg_ty = | |
669 | fcx.instantiate_type_scheme(variant.span, | |
670 | &fcx.inh.param_env.free_substs, | |
671 | &arg_ty); | |
672 | AdtField { | |
673 | ty: arg_ty, | |
674 | span: arg.ty.span | |
675 | } | |
676 | }).collect() | |
677 | } | |
678 | } | |
679 | ast::TupleVariantKind(_) => { | |
680 | AdtVariant { | |
681 | fields: Vec::new() | |
682 | } | |
683 | } | |
684 | ast::StructVariantKind(ref struct_def) => { | |
685 | struct_variant(fcx, &**struct_def) | |
686 | } | |
687 | } | |
688 | }) | |
689 | .collect() | |
690 | } | |
691 | ||
692 | fn filter_to_trait_obligations<'tcx>(bounds: ty::InstantiatedPredicates<'tcx>) | |
693 | -> ty::InstantiatedPredicates<'tcx> | |
694 | { | |
695 | let mut result = ty::InstantiatedPredicates::empty(); | |
696 | for (space, _, predicate) in bounds.predicates.iter_enumerated() { | |
697 | match *predicate { | |
698 | ty::Predicate::Trait(..) | | |
699 | ty::Predicate::Projection(..) => { | |
700 | result.predicates.push(space, predicate.clone()) | |
701 | } | |
702 | ty::Predicate::Equate(..) | | |
703 | ty::Predicate::TypeOutlives(..) | | |
704 | ty::Predicate::RegionOutlives(..) => { | |
705 | } | |
706 | } | |
707 | } | |
708 | result | |
709 | } |