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.
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.
12 use check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck};
17 use middle::ty::{self, Ty};
18 use middle::ty::liberate_late_bound_regions;
19 use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty};
20 use util::ppaux::Repr;
22 use std::collections::HashSet;
24 use syntax::ast_util::{local_def};
26 use syntax::codemap::Span;
27 use syntax::parse::token;
29 use syntax::visit::Visitor;
31 pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
32 ccx: &'ccx CrateCtxt<'ccx, 'tcx>,
33 cache: HashSet<Ty<'tcx>>
36 impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
37 pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'tcx>) -> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
38 CheckTypeWellFormedVisitor { ccx: ccx, cache: HashSet::new() }
41 /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are
42 /// well-formed, meaning that they do not require any constraints not declared in the struct
43 /// definition itself. For example, this definition would be illegal:
45 /// struct Ref<'a, T> { x: &'a T }
47 /// because the type did not declare that `T:'a`.
49 /// We do this check as a pre-pass before checking fn bodies because if these constraints are
50 /// not included it frequently leads to confusing errors in fn bodies. So it's better to check
52 fn check_item_well_formed(&mut self, item: &ast::Item) {
54 debug!("check_item_well_formed(it.id={}, it.ident={})",
56 ty::item_path_str(ccx.tcx, local_def(item.id)));
59 /// Right now we check that every default trait implementation
60 /// has an implementation of itself. Basically, a case like:
62 /// `impl Trait for T {}`
64 /// has a requirement of `T: Trait` which was required for default
65 /// method implementations. Although this could be improved now that
66 /// there's a better infrastructure in place for this, it's being left
67 /// for a follow-up work.
69 /// Since there's such a requirement, we need to check *just* positive
70 /// implementations, otherwise things like:
72 /// impl !Send for T {}
74 /// won't be allowed unless there's an *explicit* implementation of `Send`
76 ast::ItemImpl(_, ast::ImplPolarity::Positive, _, _, _, _) => {
77 self.check_impl(item);
79 ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(ref tref), _, _) => {
80 let trait_ref = ty::node_id_to_trait_ref(ccx.tcx, tref.ref_id);
81 match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
82 Some(ty::BoundSend) | Some(ty::BoundSync) => {}
84 ccx.tcx.sess.span_err(
86 format!("negative impls are currently \
87 allowed just for `Send` and `Sync`").as_slice())
92 self.check_item_type(item);
94 ast::ItemStatic(..) => {
95 self.check_item_type(item);
97 ast::ItemConst(..) => {
98 self.check_item_type(item);
100 ast::ItemStruct(ref struct_def, _) => {
101 self.check_type_defn(item, |fcx| {
102 vec![struct_variant(fcx, &**struct_def)]
105 ast::ItemEnum(ref enum_def, _) => {
106 self.check_type_defn(item, |fcx| {
107 enum_variants(fcx, enum_def)
110 ast::ItemTrait(..) => {
112 ty::lookup_trait_def(ccx.tcx, local_def(item.id));
113 reject_non_type_param_bounds(
116 &trait_def.generics);
122 fn with_fcx<F>(&mut self, item: &ast::Item, mut f: F) where
123 F: for<'fcx> FnMut(&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, &FnCtxt<'fcx, 'tcx>),
126 let item_def_id = local_def(item.id);
127 let type_scheme = ty::lookup_item_type(ccx.tcx, item_def_id);
128 reject_non_type_param_bounds(ccx.tcx, item.span, &type_scheme.generics);
130 ty::construct_parameter_environment(ccx.tcx,
131 &type_scheme.generics,
133 let inh = Inherited::new(ccx.tcx, param_env);
134 let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id);
136 vtable::select_all_fcx_obligations_or_error(&fcx);
137 regionck::regionck_item(&fcx, item);
140 /// In a type definition, we check that to ensure that the types of the fields are well-formed.
141 fn check_type_defn<F>(&mut self, item: &ast::Item, mut lookup_fields: F) where
142 F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec<AdtVariant<'tcx>>,
144 self.with_fcx(item, |this, fcx| {
145 let variants = lookup_fields(fcx);
146 let mut bounds_checker = BoundsChecker::new(fcx,
148 region::CodeExtent::from_node_id(item.id),
149 Some(&mut this.cache));
150 for variant in variants.iter() {
151 for field in variant.fields.iter() {
152 // Regions are checked below.
153 bounds_checker.check_traits_in_ty(field.ty);
156 // For DST, all intermediate types must be sized.
157 if variant.fields.len() > 0 {
158 for field in variant.fields.init().iter() {
159 fcx.register_builtin_bound(
162 traits::ObligationCause::new(field.span,
164 traits::FieldSized));
169 let field_tys: Vec<Ty> =
170 variants.iter().flat_map(|v| v.fields.iter().map(|f| f.ty)).collect();
172 regionck::regionck_ensure_component_tys_wf(
173 fcx, item.span, field_tys.as_slice());
177 fn check_item_type(&mut self,
180 self.with_fcx(item, |this, fcx| {
181 let mut bounds_checker = BoundsChecker::new(fcx,
183 region::CodeExtent::from_node_id(item.id),
184 Some(&mut this.cache));
186 let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id));
187 let item_ty = fcx.instantiate_type_scheme(item.span,
188 &fcx.inh.param_env.free_substs,
191 bounds_checker.check_traits_in_ty(item_ty);
195 fn check_impl(&mut self,
198 self.with_fcx(item, |this, fcx| {
199 let item_scope = region::CodeExtent::from_node_id(item.id);
201 let mut bounds_checker = BoundsChecker::new(fcx,
204 Some(&mut this.cache));
206 // Find the impl self type as seen from the "inside" --
207 // that is, with all type parameters converted from bound
209 let self_ty = ty::node_id_to_type(fcx.tcx(), item.id);
210 let self_ty = fcx.instantiate_type_scheme(item.span,
211 &fcx.inh.param_env.free_substs,
214 bounds_checker.check_traits_in_ty(self_ty);
216 // Similarly, obtain an "inside" reference to the trait
217 // that the impl implements.
218 let trait_ref = match ty::impl_trait_ref(fcx.tcx(), local_def(item.id)) {
223 let trait_ref = fcx.instantiate_type_scheme(item.span,
224 &fcx.inh.param_env.free_substs,
227 // There are special rules that apply to drop.
229 fcx.tcx().lang_items.drop_trait() == Some(trait_ref.def_id) &&
230 !attr::contains_name(item.attrs.as_slice(), "unsafe_destructor")
233 ty::ty_struct(def_id, _) |
234 ty::ty_enum(def_id, _) => {
235 check_struct_safe_for_destructor(fcx, item.span, def_id);
238 // Coherence already reports an error in this case.
243 if fcx.tcx().lang_items.copy_trait() == Some(trait_ref.def_id) {
244 // This is checked in coherence.
248 // We are stricter on the trait-ref in an impl than the
249 // self-type. In particular, we enforce region
250 // relationships. The reason for this is that (at least
251 // presently) "applying" an impl does not require that the
252 // application site check the well-formedness constraints on the
253 // trait reference. Instead, this is done at the impl site.
254 // Arguably this is wrong and we should treat the trait-reference
255 // the same way as we treat the self-type.
256 bounds_checker.check_trait_ref(&*trait_ref);
259 traits::ObligationCause::new(
262 traits::ItemObligation(trait_ref.def_id));
264 // Find the supertrait bounds. This will add `int:Bar`.
265 let poly_trait_ref = ty::Binder(trait_ref);
266 let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &poly_trait_ref);
268 let selcx = &mut traits::SelectionContext::new(fcx.infcx(), fcx);
269 traits::normalize(selcx, cause.clone(), &predicates)
271 for predicate in predicates.value.into_iter() {
272 fcx.register_predicate(traits::Obligation::new(cause.clone(), predicate));
274 for obligation in predicates.obligations.into_iter() {
275 fcx.register_predicate(obligation);
281 // Reject any predicates that do not involve a type parameter.
282 fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>,
284 generics: &ty::Generics<'tcx>) {
286 for predicate in generics.predicates.iter() {
288 &ty::Predicate::Trait(ty::Binder(ref tr)) => {
289 let found_param = tr.input_types().iter()
290 .flat_map(|ty| ty.walk())
292 if !found_param { report_bound_error(tcx, span, tr.self_ty() )}
294 &ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(ty, _))) => {
295 let found_param = ty.walk().any(|t| is_ty_param(t));
296 if !found_param { report_bound_error(tcx, span, ty) }
302 fn report_bound_error<'t>(tcx: &ty::ctxt<'t>,
304 bounded_ty: ty::Ty<'t>) {
307 format!("cannot bound type `{}`, where clause \
308 bounds may only be attached to types involving \
310 bounded_ty.repr(tcx)).as_slice())
313 fn is_ty_param(ty: ty::Ty) -> bool {
315 &ty::sty::ty_param(_) => true,
321 fn reject_shadowing_type_parameters<'tcx>(tcx: &ty::ctxt<'tcx>,
323 generics: &ty::Generics<'tcx>) {
324 let impl_params = generics.types.get_slice(subst::TypeSpace).iter()
325 .map(|tp| tp.name).collect::<HashSet<_>>();
327 for method_param in generics.types.get_slice(subst::FnSpace).iter() {
328 if impl_params.contains(&method_param.name) {
331 &*format!("type parameter `{}` shadows another type parameter of the same name",
332 token::get_name(method_param.name)));
337 impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
338 fn visit_item(&mut self, i: &ast::Item) {
339 self.check_item_well_formed(i);
340 visit::walk_item(self, i);
343 fn visit_fn(&mut self,
344 fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
345 b: &'v ast::Block, span: Span, id: ast::NodeId) {
347 visit::FkFnBlock | visit::FkItemFn(..) => {}
348 visit::FkMethod(..) => {
349 match ty::impl_or_trait_item(self.ccx.tcx, local_def(id)) {
350 ty::ImplOrTraitItem::MethodTraitItem(ty_method) => {
351 reject_shadowing_type_parameters(self.ccx.tcx, span, &ty_method.generics)
357 visit::walk_fn(self, fk, fd, b, span)
360 fn visit_trait_item(&mut self, t: &'v ast::TraitItem) {
362 &ast::TraitItem::ProvidedMethod(_) |
363 &ast::TraitItem::TypeTraitItem(_) => {},
364 &ast::TraitItem::RequiredMethod(ref method) => {
365 match ty::impl_or_trait_item(self.ccx.tcx, local_def(method.id)) {
366 ty::ImplOrTraitItem::MethodTraitItem(ty_method) => {
367 reject_non_type_param_bounds(
370 &ty_method.generics);
371 reject_shadowing_type_parameters(
374 &ty_method.generics);
381 visit::walk_trait_item(self, t)
385 pub struct BoundsChecker<'cx,'tcx:'cx> {
386 fcx: &'cx FnCtxt<'cx,'tcx>,
388 scope: region::CodeExtent,
390 cache: Option<&'cx mut HashSet<Ty<'tcx>>>,
393 impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
394 pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>,
396 scope: region::CodeExtent,
397 cache: Option<&'cx mut HashSet<Ty<'tcx>>>)
398 -> BoundsChecker<'cx,'tcx> {
399 BoundsChecker { fcx: fcx, span: span, scope: scope,
400 cache: cache, binding_count: 0 }
403 /// Given a trait ref like `A : Trait<B>`, where `Trait` is defined as (say):
405 /// trait Trait<B:OtherTrait> : Copy { ... }
407 /// This routine will check that `B : OtherTrait` and `A : Trait<B>`. It will also recursively
408 /// check that the types `A` and `B` are well-formed.
410 /// Note that it does not (currently, at least) check that `A : Copy` (that check is delegated
411 /// to the point where impl `A : Trait<B>` is implemented).
412 pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
413 let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id);
415 let bounds = self.fcx.instantiate_bounds(self.span, trait_ref.substs, &trait_def.generics);
417 self.fcx.add_obligations_for_parameters(
418 traits::ObligationCause::new(
421 traits::ItemObligation(trait_ref.def_id)),
424 for &ty in trait_ref.substs.types.iter() {
425 self.check_traits_in_ty(ty);
429 pub fn check_ty(&mut self, ty: Ty<'tcx>) {
433 fn check_traits_in_ty(&mut self, ty: Ty<'tcx>) {
434 // When checking types outside of a type def'n, we ignore
435 // region obligations. See discussion below in fold_ty().
436 self.binding_count += 1;
438 self.binding_count -= 1;
442 impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
443 fn tcx(&self) -> &ty::ctxt<'tcx> {
447 fn fold_binder<T>(&mut self, binder: &ty::Binder<T>) -> ty::Binder<T>
448 where T : TypeFoldable<'tcx> + Repr<'tcx>
450 self.binding_count += 1;
451 let value = liberate_late_bound_regions(self.fcx.tcx(), self.scope, binder);
452 debug!("BoundsChecker::fold_binder: late-bound regions replaced: {}",
453 value.repr(self.tcx()));
454 let value = value.fold_with(self);
455 self.binding_count -= 1;
459 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
460 debug!("BoundsChecker t={}",
464 Some(ref mut cache) => {
465 if !cache.insert(t) {
466 // Already checked this type! Don't check again.
475 ty::ty_struct(type_id, substs) |
476 ty::ty_enum(type_id, substs) => {
477 let type_scheme = ty::lookup_item_type(self.fcx.tcx(), type_id);
478 let bounds = self.fcx.instantiate_bounds(self.span, substs, &type_scheme.generics);
480 if self.binding_count == 0 {
481 self.fcx.add_obligations_for_parameters(
482 traits::ObligationCause::new(self.span,
484 traits::ItemObligation(type_id)),
487 // There are two circumstances in which we ignore
488 // region obligations.
490 // The first is when we are inside of a closure
491 // type. This is because in that case the region
492 // obligations for the parameter types are things
493 // that the closure body gets to assume and the
494 // caller must prove at the time of call. In other
495 // words, if there is a type like `<'a, 'b> | &'a
496 // &'b int |`, it is well-formed, and caller will
497 // have to show that `'b : 'a` at the time of
500 // The second is when we are checking for
501 // well-formedness outside of a type def'n or fn
502 // body. This is for a similar reason: in general,
503 // we only do WF checking for regions in the
504 // result of expressions and type definitions, so
505 // to as allow for implicit where clauses.
507 // (I believe we should do the same for traits, but
508 // that will require an RFC. -nmatsakis)
509 let bounds = filter_to_trait_obligations(bounds);
510 self.fcx.add_obligations_for_parameters(
511 traits::ObligationCause::new(self.span,
513 traits::ItemObligation(type_id)),
517 self.fold_substs(substs);
520 super_fold_ty(self, t);
524 t // we're not folding to produce a new type, so just return `t` here
528 ///////////////////////////////////////////////////////////////////////////
531 struct AdtVariant<'tcx> {
532 fields: Vec<AdtField<'tcx>>,
535 struct AdtField<'tcx> {
540 fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
541 struct_def: &ast::StructDef)
542 -> AdtVariant<'tcx> {
547 let field_ty = ty::node_id_to_type(fcx.tcx(), field.node.id);
548 let field_ty = fcx.instantiate_type_scheme(field.span,
549 &fcx.inh.param_env.free_substs,
551 AdtField { ty: field_ty, span: field.span }
554 AdtVariant { fields: fields }
557 fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
558 enum_def: &ast::EnumDef)
559 -> Vec<AdtVariant<'tcx>> {
560 enum_def.variants.iter()
562 match variant.node.kind {
563 ast::TupleVariantKind(ref args) if args.len() > 0 => {
564 let ctor_ty = ty::node_id_to_type(fcx.tcx(), variant.node.id);
566 // the regions in the argument types come from the
567 // enum def'n, and hence will all be early bound
569 ty::assert_no_late_bound_regions(
570 fcx.tcx(), &ty::ty_fn_args(ctor_ty));
572 fields: args.iter().enumerate().map(|(index, arg)| {
573 let arg_ty = arg_tys[index];
575 fcx.instantiate_type_scheme(variant.span,
576 &fcx.inh.param_env.free_substs,
585 ast::TupleVariantKind(_) => {
590 ast::StructVariantKind(ref struct_def) => {
591 struct_variant(fcx, &**struct_def)
598 fn filter_to_trait_obligations<'tcx>(bounds: ty::GenericBounds<'tcx>)
599 -> ty::GenericBounds<'tcx>
601 let mut result = ty::GenericBounds::empty();
602 for (space, _, predicate) in bounds.predicates.iter_enumerated() {
604 ty::Predicate::Trait(..) |
605 ty::Predicate::Projection(..) => {
606 result.predicates.push(space, predicate.clone())
608 ty::Predicate::Equate(..) |
609 ty::Predicate::TypeOutlives(..) |
610 ty::Predicate::RegionOutlives(..) => {
617 ///////////////////////////////////////////////////////////////////////////
618 // Special drop trait checking
620 fn check_struct_safe_for_destructor<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
622 struct_did: ast::DefId) {
623 let struct_tpt = ty::lookup_item_type(fcx.tcx(), struct_did);
624 if struct_tpt.generics.has_type_params(subst::TypeSpace)
625 || struct_tpt.generics.has_region_params(subst::TypeSpace)
627 span_err!(fcx.tcx().sess, span, E0141,
628 "cannot implement a destructor on a structure \
629 with type parameters");
630 span_note!(fcx.tcx().sess, span,
631 "use \"#[unsafe_destructor]\" on the implementation \
632 to force the compiler to allow this");