]> git.proxmox.com Git - rustc.git/blame - src/librustc_typeck/check/wf.rs
Imported Upstream version 1.2.0+dfsg1
[rustc.git] / src / librustc_typeck / check / wf.rs
CommitLineData
1a4d82fc
JJ
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
11use astconv::AstConv;
d9579d0f 12use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck};
9346a6ac 13use constrained_type_params::{identify_constrained_type_params, Parameter};
1a4d82fc
JJ
14use CrateCtxt;
15use middle::region;
85aaf69f 16use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
1a4d82fc
JJ
17use middle::traits;
18use middle::ty::{self, Ty};
19use middle::ty::liberate_late_bound_regions;
20use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty};
1a4d82fc
JJ
21
22use std::collections::HashSet;
23use syntax::ast;
c34b1796 24use syntax::ast_util::local_def;
62682a34 25use syntax::codemap::{DUMMY_SP, Span};
85aaf69f 26use syntax::parse::token::{self, special_idents};
1a4d82fc
JJ
27use syntax::visit;
28use syntax::visit::Visitor;
29
30pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
31 ccx: &'ccx CrateCtxt<'ccx, 'tcx>,
32 cache: HashSet<Ty<'tcx>>
33}
34
35impl<'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
85aaf69f
SL
40 fn tcx(&self) -> &ty::ctxt<'tcx> {
41 self.ccx.tcx
42 }
43
1a4d82fc
JJ
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 {
85aaf69f
SL
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, _, _, _, _) => {
1a4d82fc
JJ
80 self.check_impl(item);
81 }
c34b1796 82 ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(_), _, _) => {
62682a34
SL
83 let trait_ref = ty::impl_trait_ref(ccx.tcx,
84 local_def(item.id)).unwrap();
c34b1796 85 ty::populate_implementations_for_trait_if_necessary(ccx.tcx, trait_ref.def_id);
85aaf69f
SL
86 match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
87 Some(ty::BoundSend) | Some(ty::BoundSync) => {}
88 Some(_) | None => {
c34b1796
AL
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 }
85aaf69f
SL
94 }
95 }
96 }
1a4d82fc
JJ
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 }
85aaf69f 106 ast::ItemStruct(ref struct_def, ref ast_generics) => {
1a4d82fc
JJ
107 self.check_type_defn(item, |fcx| {
108 vec![struct_variant(fcx, &**struct_def)]
109 });
85aaf69f
SL
110
111 self.check_variances_for_type_defn(item, ast_generics);
1a4d82fc 112 }
85aaf69f 113 ast::ItemEnum(ref enum_def, ref ast_generics) => {
1a4d82fc
JJ
114 self.check_type_defn(item, |fcx| {
115 enum_variants(fcx, enum_def)
116 });
85aaf69f
SL
117
118 self.check_variances_for_type_defn(item, ast_generics);
1a4d82fc 119 }
9346a6ac 120 ast::ItemTrait(_, _, _, ref items) => {
85aaf69f
SL
121 let trait_predicates =
122 ty::lookup_predicates(ccx.tcx, local_def(item.id));
9346a6ac 123 reject_non_type_param_bounds(ccx.tcx, item.span, &trait_predicates);
c34b1796
AL
124 if ty::trait_has_default_impl(ccx.tcx, local_def(item.id)) {
125 if !items.is_empty() {
62682a34
SL
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")
c34b1796
AL
129 }
130 }
1a4d82fc
JJ
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);
85aaf69f
SL
142 let type_predicates = ty::lookup_predicates(ccx.tcx, item_def_id);
143 reject_non_type_param_bounds(ccx.tcx, item.span, &type_predicates);
1a4d82fc
JJ
144 let param_env =
145 ty::construct_parameter_environment(ccx.tcx,
85aaf69f 146 item.span,
1a4d82fc 147 &type_scheme.generics,
85aaf69f 148 &type_predicates,
1a4d82fc
JJ
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);
d9579d0f 153 fcx.select_all_obligations_or_error();
1a4d82fc
JJ
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,
85aaf69f 164 item.id,
1a4d82fc 165 Some(&mut this.cache));
85aaf69f
SL
166 debug!("check_type_defn at bounds_checker.scope: {:?}", bounds_checker.scope);
167
62682a34 168 for variant in &variants {
85aaf69f 169 for field in &variant.fields {
1a4d82fc 170 // Regions are checked below.
62682a34 171 bounds_checker.check_traits_in_ty(field.ty, field.span);
1a4d82fc
JJ
172 }
173
174 // For DST, all intermediate types must be sized.
9346a6ac 175 if !variant.fields.is_empty() {
85aaf69f 176 for field in variant.fields.init() {
1a4d82fc
JJ
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(
85aaf69f 191 fcx, item.span, &field_tys);
1a4d82fc
JJ
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,
85aaf69f 200 item.id,
1a4d82fc 201 Some(&mut this.cache));
85aaf69f 202 debug!("check_item_type at bounds_checker.scope: {:?}", bounds_checker.scope);
1a4d82fc
JJ
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
62682a34 209 bounds_checker.check_traits_in_ty(item_ty, item.span);
1a4d82fc
JJ
210 });
211 }
212
213 fn check_impl(&mut self,
214 item: &ast::Item)
215 {
216 self.with_fcx(item, |this, fcx| {
1a4d82fc 217 let mut bounds_checker = BoundsChecker::new(fcx,
85aaf69f 218 item.id,
1a4d82fc 219 Some(&mut this.cache));
85aaf69f 220 debug!("check_impl at bounds_checker.scope: {:?}", bounds_checker.scope);
1a4d82fc
JJ
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
62682a34 230 bounds_checker.check_traits_in_ty(self_ty, item.span);
1a4d82fc
JJ
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
1a4d82fc
JJ
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.
62682a34 251 bounds_checker.check_trait_ref(&trait_ref, item.span);
1a4d82fc
JJ
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);
c34b1796
AL
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);
1a4d82fc
JJ
263 let predicates = {
264 let selcx = &mut traits::SelectionContext::new(fcx.infcx(), fcx);
265 traits::normalize(selcx, cause.clone(), &predicates)
266 };
c34b1796 267 for predicate in predicates.value.predicates {
1a4d82fc
JJ
268 fcx.register_predicate(traits::Obligation::new(cause.clone(), predicate));
269 }
85aaf69f 270 for obligation in predicates.obligations {
1a4d82fc
JJ
271 fcx.register_predicate(obligation);
272 }
273 });
274 }
85aaf69f
SL
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);
9346a6ac 281 let ty_predicates = ty::lookup_predicates(self.tcx(), item_def_id);
85aaf69f
SL
282 let variances = ty::item_variances(self.tcx(), item_def_id);
283
284 let mut constrained_parameters: HashSet<_> =
285 variances.types
9346a6ac
AL
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();
85aaf69f
SL
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);
9346a6ac 299 if constrained_parameters.contains(&Parameter::Type(param_ty)) {
85aaf69f
SL
300 continue;
301 }
302 let span = self.ty_param_span(ast_generics, item, space, index);
9346a6ac 303 self.report_bivariance(span, param_ty.name);
85aaf69f
SL
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;
9346a6ac 314 self.report_bivariance(span, name);
85aaf69f
SL
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,
9346a6ac 349 param_name: ast::Name)
85aaf69f 350 {
62682a34
SL
351 span_err!(self.tcx().sess, span, E0392,
352 "parameter `{}` is never used", param_name);
85aaf69f 353
9346a6ac 354 let suggested_marker_id = self.tcx().lang_items.phantom_data();
85aaf69f
SL
355 match suggested_marker_id {
356 Some(def_id) => {
c34b1796 357 self.tcx().sess.fileline_help(
85aaf69f 358 span,
c34b1796 359 &format!("consider removing `{}` or using a marker such as `{}`",
62682a34 360 param_name,
c34b1796 361 ty::item_path_str(self.tcx(), def_id)));
85aaf69f
SL
362 }
363 None => {
364 // no lang items, no help!
365 }
366 }
367 }
1a4d82fc
JJ
368}
369
370// Reject any predicates that do not involve a type parameter.
371fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>,
372 span: Span,
85aaf69f 373 predicates: &ty::GenericPredicates<'tcx>) {
62682a34 374 for predicate in &predicates.predicates {
1a4d82fc
JJ
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>) {
85aaf69f
SL
393 span_err!(tcx.sess, span, E0193,
394 "cannot bound type `{}`, where clause \
1a4d82fc
JJ
395 bounds may only be attached to types involving \
396 type parameters",
62682a34 397 bounded_ty)
1a4d82fc
JJ
398 }
399
400 fn is_ty_param(ty: ty::Ty) -> bool {
401 match &ty.sty {
62682a34 402 &ty::TyParam(_) => true,
1a4d82fc
JJ
403 _ => false
404 }
405 }
406}
407
408fn 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
85aaf69f 414 for method_param in generics.types.get_slice(subst::FnSpace) {
1a4d82fc 415 if impl_params.contains(&method_param.name) {
85aaf69f
SL
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));
1a4d82fc
JJ
419 }
420 }
421}
422
423impl<'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(..) => {
85aaf69f 435 match ty::impl_or_trait_item(self.tcx(), local_def(id)) {
1a4d82fc 436 ty::ImplOrTraitItem::MethodTraitItem(ty_method) => {
85aaf69f 437 reject_shadowing_type_parameters(self.tcx(), span, &ty_method.generics)
1a4d82fc
JJ
438 }
439 _ => {}
440 }
441 }
442 }
443 visit::walk_fn(self, fk, fd, b, span)
444 }
445
c34b1796
AL
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);
1a4d82fc 458 }
c34b1796 459 _ => {}
1a4d82fc
JJ
460 }
461 }
462
c34b1796 463 visit::walk_trait_item(self, trait_item)
1a4d82fc
JJ
464 }
465}
466
467pub struct BoundsChecker<'cx,'tcx:'cx> {
468 fcx: &'cx FnCtxt<'cx,'tcx>,
469 span: Span,
85aaf69f
SL
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
c34b1796 476 binding_count: usize,
1a4d82fc
JJ
477 cache: Option<&'cx mut HashSet<Ty<'tcx>>>,
478}
479
480impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
481 pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>,
85aaf69f 482 scope: ast::NodeId,
1a4d82fc
JJ
483 cache: Option<&'cx mut HashSet<Ty<'tcx>>>)
484 -> BoundsChecker<'cx,'tcx> {
62682a34 485 BoundsChecker { fcx: fcx, span: DUMMY_SP, scope: scope,
1a4d82fc
JJ
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).
62682a34 498 pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, span: Span) {
85aaf69f 499 let trait_predicates = ty::lookup_predicates(self.fcx.tcx(), trait_ref.def_id);
1a4d82fc 500
62682a34 501 let bounds = self.fcx.instantiate_bounds(span,
85aaf69f
SL
502 trait_ref.substs,
503 &trait_predicates);
1a4d82fc
JJ
504
505 self.fcx.add_obligations_for_parameters(
506 traits::ObligationCause::new(
62682a34 507 span,
1a4d82fc
JJ
508 self.fcx.body_id,
509 traits::ItemObligation(trait_ref.def_id)),
510 &bounds);
511
62682a34
SL
512 for &ty in &trait_ref.substs.types {
513 self.check_traits_in_ty(ty, span);
1a4d82fc
JJ
514 }
515 }
516
62682a34
SL
517 pub fn check_ty(&mut self, ty: Ty<'tcx>, span: Span) {
518 self.span = span;
1a4d82fc
JJ
519 ty.fold_with(self);
520 }
521
62682a34
SL
522 fn check_traits_in_ty(&mut self, ty: Ty<'tcx>, span: Span) {
523 self.span = span;
1a4d82fc
JJ
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
532impl<'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>
62682a34 538 where T : TypeFoldable<'tcx>
1a4d82fc
JJ
539 {
540 self.binding_count += 1;
85aaf69f
SL
541 let value = liberate_late_bound_regions(
542 self.fcx.tcx(),
543 region::DestructionScopeData::new(self.scope),
544 binder);
62682a34
SL
545 debug!("BoundsChecker::fold_binder: late-bound regions replaced: {:?} at scope: {:?}",
546 value, self.scope);
1a4d82fc
JJ
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> {
62682a34
SL
553 debug!("BoundsChecker t={:?}",
554 t);
1a4d82fc
JJ
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{
62682a34
SL
568 ty::TyStruct(type_id, substs) |
569 ty::TyEnum(type_id, substs) => {
85aaf69f
SL
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);
1a4d82fc
JJ
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
625struct AdtVariant<'tcx> {
626 fields: Vec<AdtField<'tcx>>,
627}
628
629struct AdtField<'tcx> {
630 ty: Ty<'tcx>,
631 span: Span,
632}
633
634fn 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
651fn 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 {
9346a6ac 657 ast::TupleVariantKind(ref args) if !args.is_empty() => {
1a4d82fc
JJ
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 =
85aaf69f
SL
663 ty::no_late_bound_regions(
664 fcx.tcx(), &ty::ty_fn_args(ctor_ty)).unwrap();
1a4d82fc
JJ
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
85aaf69f
SL
692fn filter_to_trait_obligations<'tcx>(bounds: ty::InstantiatedPredicates<'tcx>)
693 -> ty::InstantiatedPredicates<'tcx>
1a4d82fc 694{
85aaf69f 695 let mut result = ty::InstantiatedPredicates::empty();
1a4d82fc
JJ
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}