1 // Copyright 2012-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 middle::freevars::freevar_entry;
17 use util::ppaux::{Repr, ty_to_str};
18 use util::ppaux::UserString;
22 use syntax::codemap::Span;
23 use syntax::print::pprust::{expr_to_str, ident_to_str};
25 use syntax::visit::Visitor;
27 // Kind analysis pass.
29 // There are several kinds defined by various operations. The most restrictive
30 // kind is noncopyable. The noncopyable kind can be extended with any number
31 // of the following attributes.
33 // Send: Things that can be sent on channels or included in spawned closures. It
34 // includes scalar types as well as classes and unique types containing only
36 // 'static: Things that do not contain references.
38 // This pass ensures that type parameters are only instantiated with types
39 // whose kinds are equal or less general than the way the type parameter was
40 // annotated (with the `Send` bound).
42 // It also verifies that noncopyable kinds are not copied. Sendability is not
43 // applied, since none of our language primitives send. Instead, the sending
44 // primitives in the stdlib are explicitly annotated to only take sendable
48 pub struct Context<'a> {
52 impl<'a> Visitor<()> for Context<'a> {
54 fn visit_expr(&mut self, ex: &Expr, _: ()) {
58 fn visit_fn(&mut self, fk: &visit::FnKind, fd: &FnDecl,
59 b: &Block, s: Span, n: NodeId, _: ()) {
60 check_fn(self, fk, fd, b, s, n);
63 fn visit_ty(&mut self, t: &Ty, _: ()) {
67 fn visit_item(&mut self, i: &Item, _: ()) {
71 fn visit_pat(&mut self, p: &Pat, _: ()) {
76 pub fn check_crate(tcx: &ty::ctxt,
78 let mut ctx = Context {
81 visit::walk_crate(&mut ctx, krate, ());
82 tcx.sess.abort_if_errors();
85 fn check_struct_safe_for_destructor(cx: &mut Context,
88 let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did);
89 if !struct_tpt.generics.has_type_params(subst::TypeSpace) {
90 let struct_ty = ty::mk_struct(cx.tcx, struct_did,
91 subst::Substs::empty());
92 if !ty::type_is_sendable(cx.tcx, struct_ty) {
93 cx.tcx.sess.span_err(span,
94 "cannot implement a destructor on a \
95 structure that does not satisfy Send");
96 cx.tcx.sess.span_note(span,
97 "use \"#[unsafe_destructor]\" on the \
98 implementation to force the compiler to \
102 cx.tcx.sess.span_err(span,
103 "cannot implement a destructor on a structure \
104 with type parameters");
105 cx.tcx.sess.span_note(span,
106 "use \"#[unsafe_destructor]\" on the \
107 implementation to force the compiler to \
112 fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_type: &Ty) {
113 let ast_trait_def = *cx.tcx.def_map.borrow()
114 .find(&trait_ref.ref_id)
115 .expect("trait ref not in def map!");
116 let trait_def_id = ast_trait_def.def_id();
117 let trait_def = cx.tcx.trait_defs.borrow()
118 .find_copy(&trait_def_id)
119 .expect("trait def not in trait-defs map!");
121 // If this trait has builtin-kind supertraits, meet them.
122 let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
123 debug!("checking impl with self type {:?}", ty::get(self_ty).sty);
124 check_builtin_bounds(cx, self_ty, trait_def.bounds, |missing| {
125 cx.tcx.sess.span_err(self_type.span,
126 format!("the type `{}', which does not fulfill `{}`, cannot implement this \
128 ty_to_str(cx.tcx, self_ty),
129 missing.user_string(cx.tcx)).as_slice());
130 cx.tcx.sess.span_note(self_type.span,
131 format!("types implementing this trait must fulfill `{}`",
132 trait_def.bounds.user_string(cx.tcx)).as_slice());
135 // If this is a destructor, check kinds.
136 if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) {
137 match self_type.node {
138 TyPath(_, ref bounds, path_node_id) => {
139 assert!(bounds.is_none());
140 let struct_def = cx.tcx.def_map.borrow().get_copy(&path_node_id);
141 let struct_did = struct_def.def_id();
142 check_struct_safe_for_destructor(cx, self_type.span, struct_did);
145 cx.tcx.sess.span_bug(self_type.span,
146 "the self type for the Drop trait impl is not a path");
152 fn check_item(cx: &mut Context, item: &Item) {
153 if !attr::contains_name(item.attrs.as_slice(), "unsafe_destructor") {
155 ItemImpl(_, Some(ref trait_ref), ref self_type, _) => {
156 check_impl_of_trait(cx, item, trait_ref, &**self_type);
162 visit::walk_item(cx, item, ());
165 // Yields the appropriate function to check the kind of closed over
166 // variables. `id` is the NodeId for some expression that creates the
168 fn with_appropriate_checker(cx: &Context,
170 b: |checker: |&Context, &freevar_entry||) {
171 fn check_for_uniq(cx: &Context, fv: &freevar_entry, bounds: ty::BuiltinBounds) {
172 // all captured data must be owned, regardless of whether it is
173 // moved in or copied in.
174 let id = fv.def.def_id().node;
175 let var_t = ty::node_id_to_type(cx.tcx, id);
177 check_freevar_bounds(cx, fv.span, var_t, bounds, None);
180 fn check_for_block(cx: &Context, fv: &freevar_entry,
181 bounds: ty::BuiltinBounds, region: ty::Region) {
182 let id = fv.def.def_id().node;
183 let var_t = ty::node_id_to_type(cx.tcx, id);
184 // FIXME(#3569): Figure out whether the implicit borrow is actually
185 // mutable. Currently we assume all upvars are referenced mutably.
186 let implicit_borrowed_type = ty::mk_mut_rptr(cx.tcx, region, var_t);
187 check_freevar_bounds(cx, fv.span, implicit_borrowed_type,
188 bounds, Some(var_t));
191 fn check_for_bare(cx: &Context, fv: &freevar_entry) {
192 cx.tcx.sess.span_err(
194 "can't capture dynamic environment in a fn item; \
195 use the || { ... } closure form instead");
196 } // same check is done in resolve.rs, but shouldn't be done
198 let fty = ty::node_id_to_type(cx.tcx, id);
199 match ty::get(fty).sty {
200 ty::ty_closure(box ty::ClosureTy {
201 store: ty::UniqTraitStore,
202 bounds: mut bounds, ..
204 // Procs can't close over non-static references!
205 bounds.add(ty::BoundStatic);
207 b(|cx, fv| check_for_uniq(cx, fv, bounds))
210 ty::ty_closure(box ty::ClosureTy {
211 store: ty::RegionTraitStore(region, _), bounds, ..
212 }) => b(|cx, fv| check_for_block(cx, fv, bounds, region)),
214 ty::ty_bare_fn(_) => {
218 cx.tcx.sess.bug(format!("expect fn type in kind checker, not \
225 // Check that the free variables used in a shared/sendable closure conform
226 // to the copy/move kind bounds. Then recursively check the function body.
235 // Check kinds on free variables:
236 with_appropriate_checker(cx, fn_id, |chk| {
237 freevars::with_freevars(cx.tcx, fn_id, |freevars| {
238 for fv in freevars.iter() {
244 visit::walk_fn(cx, fk, decl, body, sp, ());
247 pub fn check_expr(cx: &mut Context, e: &Expr) {
248 debug!("kind::check_expr({})", expr_to_str(e));
250 // Handle any kind bounds on type parameters
251 check_bounds_on_type_parameters(cx, e);
254 ExprBox(ref loc, ref interior) => {
255 let def = ty::resolve_expr(cx.tcx, &**loc);
256 if Some(def.def_id()) == cx.tcx.lang_items.managed_heap() {
257 let interior_type = ty::expr_ty(cx.tcx, &**interior);
258 let _ = check_static(cx.tcx, interior_type, interior.span);
261 ExprCast(ref source, _) => {
262 let source_ty = ty::expr_ty(cx.tcx, &**source);
263 let target_ty = ty::expr_ty(cx.tcx, e);
264 check_trait_cast(cx, source_ty, target_ty, source.span);
266 ExprRepeat(ref element, ref count_expr) => {
267 let count = ty::eval_repeat_count(cx.tcx, &**count_expr);
269 let element_ty = ty::expr_ty(cx.tcx, &**element);
270 check_copy(cx, element_ty, element.span,
271 "repeated element will be copied");
277 // Search for auto-adjustments to find trait coercions.
278 match cx.tcx.adjustments.borrow().find(&e.id) {
279 Some(adjustment) => {
281 ty::AutoObject(..) => {
282 let source_ty = ty::expr_ty(cx.tcx, e);
283 let target_ty = ty::expr_ty_adjusted(cx.tcx, e);
284 check_trait_cast(cx, source_ty, target_ty, e.span);
287 ty::AutoDerefRef(..) => {}
293 visit::walk_expr(cx, e, ());
296 fn check_bounds_on_type_parameters(cx: &mut Context, e: &Expr) {
297 let method_map = cx.tcx.method_map.borrow();
298 let method = method_map.find(&typeck::MethodCall::expr(e.id));
300 // Find the values that were provided (if any)
301 let item_substs = cx.tcx.item_substs.borrow();
302 let (types, is_object_call) = match method {
304 let is_object_call = match method.origin {
305 typeck::MethodObject(..) => true,
306 typeck::MethodStatic(..) | typeck::MethodParam(..) => false
308 (&method.substs.types, is_object_call)
311 match item_substs.find(&e.id) {
313 Some(s) => { (&s.substs.types, false) }
318 // Find the relevant type parameter definitions
319 let def_map = cx.tcx.def_map.borrow();
320 let type_param_defs = match e.node {
322 let did = def_map.get_copy(&e.id).def_id();
323 ty::lookup_item_type(cx.tcx, did).generics.types.clone()
326 // Type substitutions should only occur on paths and
327 // method calls, so this needs to be a method call.
329 // Even though the callee_id may have been the id with
330 // node_type_substs, e.id is correct here.
333 ty::method_call_type_param_defs(cx.tcx, method.origin)
336 cx.tcx.sess.span_bug(e.span,
337 "non path/method call expr has type substs??");
343 // Check that the value provided for each definition meets the
345 for type_param_def in type_param_defs.iter() {
346 let ty = *types.get(type_param_def.space, type_param_def.index);
348 // If this is a call to an object method (`foo.bar()` where
349 // `foo` has a type like `Trait`), then the self type is
350 // unknown (after all, this is a virtual call). In that case,
351 // we will have put a ty_err in the substitutions, and we can
352 // just skip over validating the bounds (because the bounds
353 // would have been enforced when the object instance was
355 if is_object_call && type_param_def.space == subst::SelfSpace {
356 assert_eq!(type_param_def.index, 0);
357 assert!(ty::type_is_error(ty));
361 debug!("type_param_def space={} index={} ty={}",
362 type_param_def.space, type_param_def.index, ty.repr(cx.tcx));
363 check_typaram_bounds(cx, e.span, ty, type_param_def)
367 fn check_trait_cast(cx: &mut Context, source_ty: ty::t, target_ty: ty::t, span: Span) {
368 check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
369 match ty::get(target_ty).sty {
370 ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => match ty::get(ty).sty {
371 ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
372 check_trait_cast_bounds(cx, span, source_ty, bounds);
380 fn check_ty(cx: &mut Context, aty: &Ty) {
382 TyPath(_, _, id) => {
383 match cx.tcx.item_substs.borrow().find(&id) {
385 Some(ref item_substs) => {
386 let def_map = cx.tcx.def_map.borrow();
387 let did = def_map.get_copy(&id).def_id();
388 let generics = ty::lookup_item_type(cx.tcx, did).generics;
389 for def in generics.types.iter() {
390 let ty = *item_substs.substs.types.get(def.space,
392 check_typaram_bounds(cx, aty.span, ty, def)
399 visit::walk_ty(cx, aty, ());
402 // Calls "any_missing" if any bounds were missing.
403 pub fn check_builtin_bounds(cx: &Context,
405 bounds: ty::BuiltinBounds,
406 any_missing: |ty::BuiltinBounds|) {
407 let kind = ty::type_contents(cx.tcx, ty);
408 let mut missing = ty::empty_builtin_bounds();
409 for bound in bounds.iter() {
410 if !kind.meets_bound(cx.tcx, bound) {
414 if !missing.is_empty() {
415 any_missing(missing);
419 pub fn check_typaram_bounds(cx: &Context,
422 type_param_def: &ty::TypeParameterDef) {
423 check_builtin_bounds(cx,
425 type_param_def.bounds.builtin_bounds,
427 cx.tcx.sess.span_err(
429 format!("instantiating a type parameter with an incompatible type \
430 `{}`, which does not fulfill `{}`",
431 ty_to_str(cx.tcx, ty),
432 missing.user_string(cx.tcx)).as_slice());
436 pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t,
437 bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>)
439 check_builtin_bounds(cx, ty, bounds, |missing| {
440 // Will be Some if the freevar is implicitly borrowed (stack closure).
441 // Emit a less mysterious error message in this case.
442 match referenced_ty {
444 cx.tcx.sess.span_err(sp,
445 format!("cannot implicitly borrow variable of type `{}` in a \
446 bounded stack closure (implicit reference does not \
448 ty_to_str(cx.tcx, rty),
449 missing.user_string(cx.tcx)).as_slice())
452 cx.tcx.sess.span_err(sp,
453 format!("cannot capture variable of type `{}`, which does \
454 not fulfill `{}`, in a bounded closure",
455 ty_to_str(cx.tcx, ty),
456 missing.user_string(cx.tcx)).as_slice())
459 cx.tcx.sess.span_note(
461 format!("this closure's environment must satisfy `{}`",
462 bounds.user_string(cx.tcx)).as_slice());
466 pub fn check_trait_cast_bounds(cx: &Context, sp: Span, ty: ty::t,
467 bounds: ty::BuiltinBounds) {
468 check_builtin_bounds(cx, ty, bounds, |missing| {
469 cx.tcx.sess.span_err(sp,
470 format!("cannot pack type `{}`, which does not fulfill \
471 `{}`, as a trait bounded by {}",
472 ty_to_str(cx.tcx, ty), missing.user_string(cx.tcx),
473 bounds.user_string(cx.tcx)).as_slice());
477 fn check_copy(cx: &Context, ty: ty::t, sp: Span, reason: &str) {
478 debug!("type_contents({})={}",
479 ty_to_str(cx.tcx, ty),
480 ty::type_contents(cx.tcx, ty).to_str());
481 if ty::type_moves_by_default(cx.tcx, ty) {
482 cx.tcx.sess.span_err(
484 format!("copying a value of non-copyable type `{}`",
485 ty_to_str(cx.tcx, ty)).as_slice());
486 cx.tcx.sess.span_note(sp, format!("{}", reason).as_slice());
490 pub fn check_static(tcx: &ty::ctxt, ty: ty::t, sp: Span) -> bool {
491 if !ty::type_is_static(tcx, ty) {
492 match ty::get(ty).sty {
493 ty::ty_param(..) => {
494 tcx.sess.span_err(sp,
495 format!("value may contain references; \
496 add `'static` bound to `{}`",
497 ty_to_str(tcx, ty)).as_slice());
500 tcx.sess.span_err(sp, "value may contain references");
509 /// This is rather subtle. When we are casting a value to an instantiated
510 /// trait like `a as trait<'r>`, regionck already ensures that any references
511 /// that appear in the type of `a` are bounded by `'r` (ed.: rem
512 /// FIXME(#5723)). However, it is possible that there are *type parameters*
513 /// in the type of `a`, and those *type parameters* may have references
514 /// within them. We have to guarantee that the regions which appear in those
515 /// type parameters are not obscured.
517 /// Therefore, we ensure that one of three conditions holds:
519 /// (1) The trait instance cannot escape the current fn. This is
520 /// guaranteed if the region bound `&r` is some scope within the fn
521 /// itself. This case is safe because whatever references are
522 /// found within the type parameter, they must enclose the fn body
525 /// (2) The type parameter appears in the type of the trait. For
526 /// example, if the type parameter is `T` and the trait type is
527 /// `deque<T>`, then whatever references may appear in `T` also
528 /// appear in `deque<T>`.
530 /// (3) The type parameter is sendable (and therefore does not contain
533 /// FIXME(#5723)---This code should probably move into regionck.
534 pub fn check_cast_for_escaping_regions(
540 // Determine what type we are casting to; if it is not a trait, then no
542 if !ty::type_is_trait(target_ty) {
546 // Collect up the regions that appear in the target type. We want to
547 // ensure that these lifetimes are shorter than all lifetimes that are in
548 // the source type. See test `src/test/compile-fail/regions-trait-2.rs`
549 let mut target_regions = Vec::new();
550 ty::walk_regions_and_ty(
555 target_regions.push(r);
560 // Check, based on the region associated with the trait, whether it can
561 // possibly escape the enclosing fn item (note that all type parameters
562 // must have been declared on the enclosing fn item).
563 if target_regions.iter().any(|r| is_ReScope(*r)) {
564 return; /* case (1) */
567 // Assuming the trait instance can escape, then ensure that each parameter
568 // either appears in the trait type or is sendable.
569 let target_params = ty::param_tys_in_type(target_ty);
570 ty::walk_regions_and_ty(
575 // FIXME(#5723) --- turn this check on once &Objects are usable
577 // if !target_regions.iter().any(|t_r| is_subregion_of(cx, *t_r, r)) {
578 // cx.tcx.sess.span_err(
580 // format!("source contains reference with lifetime \
581 // not found in the target type `{}`",
582 // ty_to_str(cx.tcx, target_ty)));
583 // note_and_explain_region(
584 // cx.tcx, "source data is only valid for ", r, "");
589 match ty::get(ty).sty {
590 ty::ty_param(source_param) => {
591 if source_param.space == subst::SelfSpace {
592 // FIXME (#5723) -- there is no reason that
593 // Self should be exempt from this check,
594 // except for historical accident. Bottom
595 // line, we need proper region bounding.
596 } else if target_params.iter().any(|x| x == &source_param) {
599 check_static(cx.tcx, ty, source_span); /* case (3) */
606 #[allow(non_snake_case_functions)]
607 fn is_ReScope(r: ty::Region) -> bool {
609 ty::ReScope(..) => true,
615 // Ensure that `ty` has a statically known size (i.e., it has the `Sized` bound).
616 fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) {
617 if !ty::type_is_sized(tcx, ty) {
618 tcx.sess.span_err(sp,
619 format!("variable `{}` has dynamically sized type \
622 ty_to_str(tcx, ty)).as_slice());
626 // Check that any variables in a pattern have types with statically known size.
627 fn check_pat(cx: &mut Context, pat: &Pat) {
628 let var_name = match pat.node {
629 PatWild => Some("_".to_string()),
630 PatIdent(_, ref path1, _) => Some(ident_to_str(&path1.node).to_string()),
636 let types = cx.tcx.node_types.borrow();
637 let ty = types.find(&(pat.id as uint));
640 debug!("kind: checking sized-ness of variable {}: {}",
641 name, ty_to_str(cx.tcx, *ty));
642 check_sized(cx.tcx, *ty, name, pat.span);
644 None => {} // extern fn args
650 visit::walk_pat(cx, pat, ());