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