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.
13 use middle::subst::{Subst};
15 use middle::ty::{mod, Ty};
16 use middle::ty::liberate_late_bound_regions;
17 use middle::ty_fold::{TypeFolder, TypeFoldable};
18 use middle::typeck::astconv::AstConv;
19 use middle::typeck::check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck};
20 use middle::typeck::CrateCtxt;
21 use util::ppaux::Repr;
23 use std::collections::HashSet;
25 use syntax::ast_util::{local_def};
27 use syntax::codemap::Span;
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 fn check_item_well_formed(&mut self, item: &ast::Item) {
43 * Checks that the field types (in a struct def'n) or
44 * argument types (in an enum def'n) are well-formed,
45 * meaning that they do not require any constraints not
46 * declared in the struct definition itself.
47 * For example, this definition would be illegal:
49 * struct Ref<'a, T> { x: &'a T }
51 * because the type did not declare that `T:'a`.
53 * We do this check as a pre-pass before checking fn bodies
54 * because if these constraints are not included it frequently
55 * leads to confusing errors in fn bodies. So it's better to check
60 debug!("check_item_well_formed(it.id={}, it.ident={})",
62 ty::item_path_str(ccx.tcx, local_def(item.id)));
65 ast::ItemImpl(..) => {
66 self.check_impl(item);
69 self.check_item_type(item);
71 ast::ItemStatic(..) => {
72 self.check_item_type(item);
74 ast::ItemConst(..) => {
75 self.check_item_type(item);
77 ast::ItemStruct(ref struct_def, _) => {
78 self.check_type_defn(item, |fcx| {
79 vec![struct_variant(fcx, &**struct_def)]
82 ast::ItemEnum(ref enum_def, _) => {
83 self.check_type_defn(item, |fcx| {
84 enum_variants(fcx, enum_def)
91 fn with_fcx(&mut self,
93 f: for<'fcx> |&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>,
94 &FnCtxt<'fcx, 'tcx>|) {
96 let item_def_id = local_def(item.id);
97 let polytype = ty::lookup_item_type(ccx.tcx, item_def_id);
99 ty::construct_parameter_environment(ccx.tcx,
103 let inh = Inherited::new(ccx.tcx, param_env);
104 let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(polytype.ty), item.id);
106 vtable::select_all_fcx_obligations_or_error(&fcx);
107 regionck::regionck_item(&fcx, item);
110 fn check_type_defn(&mut self,
112 lookup_fields: for<'fcx> |&FnCtxt<'fcx, 'tcx>|
113 -> Vec<AdtVariant<'tcx>>)
116 * In a type definition, we check that to ensure that the types of the fields are
120 self.with_fcx(item, |this, fcx| {
121 let variants = lookup_fields(fcx);
122 let mut bounds_checker = BoundsChecker::new(fcx,
124 region::CodeExtent::from_node_id(item.id),
125 Some(&mut this.cache));
126 for variant in variants.iter() {
127 for field in variant.fields.iter() {
128 // Regions are checked below.
129 bounds_checker.check_traits_in_ty(field.ty);
132 // For DST, all intermediate types must be sized.
133 if variant.fields.len() > 0 {
134 for field in variant.fields.init().iter() {
135 let cause = traits::ObligationCause::new(field.span, traits::FieldSized);
136 let obligation = traits::obligation_for_builtin_bound(fcx.tcx(),
141 Ok(obligation) => fcx.register_obligation(obligation),
148 let field_tys: Vec<Ty> =
149 variants.iter().flat_map(|v| v.fields.iter().map(|f| f.ty)).collect();
151 regionck::regionck_ensure_component_tys_wf(
152 fcx, item.span, field_tys.as_slice());
156 fn check_item_type(&mut self,
159 self.with_fcx(item, |this, fcx| {
160 let mut bounds_checker = BoundsChecker::new(fcx,
162 region::CodeExtent::from_node_id(item.id),
163 Some(&mut this.cache));
164 let polytype = ty::lookup_item_type(fcx.tcx(), local_def(item.id));
165 let item_ty = polytype.ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
166 bounds_checker.check_traits_in_ty(item_ty);
170 fn check_impl(&mut self,
173 self.with_fcx(item, |this, fcx| {
174 let item_scope = region::CodeExtent::from_node_id(item.id);
176 let mut bounds_checker = BoundsChecker::new(fcx,
179 Some(&mut this.cache));
181 // Find the impl self type as seen from the "inside" --
182 // that is, with all type parameters converted from bound
183 // to free, and any late-bound regions on the impl
185 let self_ty = ty::node_id_to_type(fcx.tcx(), item.id);
186 let self_ty = self_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
187 let self_ty = liberate_late_bound_regions(
188 fcx.tcx(), item_scope, &ty::bind(self_ty)).value;
190 bounds_checker.check_traits_in_ty(self_ty);
192 // Similarly, obtain an "inside" reference to the trait
193 // that the impl implements.
194 let trait_ref = match ty::impl_trait_ref(fcx.tcx(), local_def(item.id)) {
198 let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
199 let trait_ref = liberate_late_bound_regions(fcx.tcx(), item_scope, &trait_ref);
201 // There are special rules that apply to drop.
203 fcx.tcx().lang_items.drop_trait() == Some(trait_ref.def_id) &&
204 !attr::contains_name(item.attrs.as_slice(), "unsafe_destructor")
207 ty::ty_struct(def_id, _) |
208 ty::ty_enum(def_id, _) => {
209 check_struct_safe_for_destructor(fcx, item.span, self_ty, def_id);
212 // Coherence already reports an error in this case.
217 // We are stricter on the trait-ref in an impl than the
218 // self-type. In particular, we enforce region
219 // relationships. The reason for this is that (at least
220 // presently) "appyling" an impl does not require that the
221 // application site check the well-formedness constraints on the
222 // trait reference. Instead, this is done at the impl site.
223 // Arguably this is wrong and we should treat the trait-reference
224 // the same way as we treat the self-type.
225 bounds_checker.check_trait_ref(&trait_ref);
227 let trait_def = ty::lookup_trait_def(fcx.tcx(), trait_ref.def_id);
230 traits::ObligationCause::new(
232 traits::ItemObligation(trait_ref.def_id));
234 // Find the supertrait bounds. This will add `int:Bar`.
236 // FIXME -- This is a bit ill-factored. There is very similar
237 // code in traits::util::obligations_for_generics.
238 fcx.add_region_obligations_for_type_parameter(item.span,
240 trait_ref.self_ty());
241 for builtin_bound in trait_def.bounds.builtin_bounds.iter() {
242 let obligation = traits::obligation_for_builtin_bound(fcx.tcx(),
247 Ok (obligation) => fcx.register_obligation(obligation),
251 for trait_bound in trait_def.bounds.trait_bounds.iter() {
252 let trait_bound = trait_bound.subst(fcx.tcx(), &trait_ref.substs);
253 fcx.register_obligation(
254 traits::Obligation::new(cause, trait_bound));
260 impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
261 fn visit_item(&mut self, i: &ast::Item) {
262 self.check_item_well_formed(i);
263 visit::walk_item(self, i);
267 pub struct BoundsChecker<'cx,'tcx:'cx> {
268 fcx: &'cx FnCtxt<'cx,'tcx>,
270 scope: region::CodeExtent,
272 cache: Option<&'cx mut HashSet<Ty<'tcx>>>,
275 impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
276 pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>,
278 scope: region::CodeExtent,
279 cache: Option<&'cx mut HashSet<Ty<'tcx>>>)
280 -> BoundsChecker<'cx,'tcx> {
281 BoundsChecker { fcx: fcx, span: span, scope: scope,
282 cache: cache, binding_count: 0 }
285 pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
287 * Given a trait ref like `A : Trait<B>`, where `Trait` is
290 * trait Trait<B:OtherTrait> : Copy { ... }
292 * This routine will check that `B : OtherTrait` and `A :
293 * Trait<B>`. It will also recursively check that the types
294 * `A` and `B` are well-formed.
296 * Note that it does not (currently, at least)
297 * check that `A : Copy` (that check is delegated to the point
298 * where impl `A : Trait<B>` is implemented).
301 let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id);
303 let bounds = trait_def.generics.to_bounds(self.tcx(), &trait_ref.substs);
304 self.fcx.add_obligations_for_parameters(
305 traits::ObligationCause::new(
307 traits::ItemObligation(trait_ref.def_id)),
311 for &ty in trait_ref.substs.types.iter() {
312 self.check_traits_in_ty(ty);
316 pub fn check_ty(&mut self, ty: Ty<'tcx>) {
320 fn check_traits_in_ty(&mut self, ty: Ty<'tcx>) {
321 // When checking types outside of a type def'n, we ignore
322 // region obligations. See discussion below in fold_ty().
323 self.binding_count += 1;
325 self.binding_count -= 1;
329 impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
330 fn tcx(&self) -> &ty::ctxt<'tcx> {
334 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
335 debug!("BoundsChecker t={}",
339 Some(ref mut cache) => {
340 if !cache.insert(t) {
341 // Already checked this type! Don't check again.
350 ty::ty_struct(type_id, ref substs) |
351 ty::ty_enum(type_id, ref substs) => {
352 let polytype = ty::lookup_item_type(self.fcx.tcx(), type_id);
354 if self.binding_count == 0 {
355 self.fcx.add_obligations_for_parameters(
356 traits::ObligationCause::new(self.span,
357 traits::ItemObligation(type_id)),
359 &polytype.generics.to_bounds(self.tcx(), substs));
361 // There are two circumstances in which we ignore
362 // region obligations.
364 // The first is when we are inside of a closure
365 // type. This is because in that case the region
366 // obligations for the parameter types are things
367 // that the closure body gets to assume and the
368 // caller must prove at the time of call. In other
369 // words, if there is a type like `<'a, 'b> | &'a
370 // &'b int |`, it is well-formed, and caller will
371 // have to show that `'b : 'a` at the time of
374 // The second is when we are checking for
375 // well-formedness outside of a type def'n or fn
376 // body. This is for a similar reason: in general,
377 // we only do WF checking for regions in the
378 // result of expressions and type definitions, so
379 // to as allow for implicit where clauses.
381 // (I believe we should do the same for traits, but
382 // that will require an RFC. -nmatsakis)
383 self.fcx.add_trait_obligations_for_generics(
384 traits::ObligationCause::new(self.span,
385 traits::ItemObligation(type_id)),
387 &polytype.generics.to_bounds(self.tcx(), substs));
390 self.fold_substs(substs);
392 ty::ty_bare_fn(ty::BareFnTy{sig: ref fn_sig, ..}) |
393 ty::ty_closure(box ty::ClosureTy{sig: ref fn_sig, ..}) => {
394 self.binding_count += 1;
396 let fn_sig = liberate_late_bound_regions(self.fcx.tcx(), self.scope, fn_sig);
398 debug!("late-bound regions replaced: {}",
399 fn_sig.repr(self.tcx()));
401 self.fold_fn_sig(&fn_sig);
403 self.binding_count -= 1;
410 t // we're not folding to produce a new type, so just return `t` here
414 ///////////////////////////////////////////////////////////////////////////
417 struct AdtVariant<'tcx> {
418 fields: Vec<AdtField<'tcx>>,
421 struct AdtField<'tcx> {
426 fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
427 struct_def: &ast::StructDef)
428 -> AdtVariant<'tcx> {
433 let field_ty = ty::node_id_to_type(fcx.tcx(), field.node.id);
434 let field_ty = field_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
435 AdtField { ty: field_ty, span: field.span }
438 AdtVariant { fields: fields }
441 fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
442 enum_def: &ast::EnumDef)
443 -> Vec<AdtVariant<'tcx>> {
444 enum_def.variants.iter()
446 match variant.node.kind {
447 ast::TupleVariantKind(ref args) if args.len() > 0 => {
448 let ctor_ty = ty::node_id_to_type(fcx.tcx(), variant.node.id);
449 let arg_tys = ty::ty_fn_args(ctor_ty);
451 fields: args.iter().enumerate().map(|(index, arg)| {
452 let arg_ty = arg_tys[index];
453 let arg_ty = arg_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
461 ast::TupleVariantKind(_) => {
466 ast::StructVariantKind(ref struct_def) => {
467 struct_variant(fcx, &**struct_def)
474 ///////////////////////////////////////////////////////////////////////////
475 // Special drop trait checking
477 fn check_struct_safe_for_destructor<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
480 struct_did: ast::DefId) {
481 let struct_tpt = ty::lookup_item_type(fcx.tcx(), struct_did);
482 if !struct_tpt.generics.has_type_params(subst::TypeSpace)
483 && !struct_tpt.generics.has_region_params(subst::TypeSpace)
485 let cause = traits::ObligationCause::new(span, traits::DropTrait);
486 let obligation = traits::obligation_for_builtin_bound(fcx.tcx(),
491 Ok(obligation) => fcx.register_obligation(obligation),
495 span_err!(fcx.tcx().sess, span, E0141,
496 "cannot implement a destructor on a structure \
497 with type parameters");
498 span_note!(fcx.tcx().sess, span,
499 "use \"#[unsafe_destructor]\" on the implementation \
500 to force the compiler to allow this");