2014-01-17 16:50:54 -06:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2013-05-17 17:28:44 -05:00
|
|
|
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::freevars::freevar_entry;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::freevars;
|
2014-05-13 10:35:42 -05:00
|
|
|
use middle::subst;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::ty;
|
|
|
|
use middle::typeck;
|
2013-04-10 15:11:27 -05:00
|
|
|
use util::ppaux::{Repr, ty_to_str};
|
2013-05-07 16:30:21 -05:00
|
|
|
use util::ppaux::UserString;
|
2012-12-13 15:05:22 -06:00
|
|
|
|
|
|
|
use syntax::ast::*;
|
2013-07-19 06:51:37 -05:00
|
|
|
use syntax::attr;
|
2013-08-31 11:13:04 -05:00
|
|
|
use syntax::codemap::Span;
|
2014-04-23 18:57:22 -05:00
|
|
|
use syntax::print::pprust::{expr_to_str,path_to_str};
|
2014-05-14 14:31:30 -05:00
|
|
|
use syntax::{visit};
|
2013-08-13 07:11:34 -05:00
|
|
|
use syntax::visit::Visitor;
|
2011-11-15 11:15:35 -06:00
|
|
|
|
2012-05-24 16:33:21 -05:00
|
|
|
// Kind analysis pass.
|
2011-11-18 10:09:14 -06:00
|
|
|
//
|
2012-05-24 16:33:21 -05:00
|
|
|
// There are several kinds defined by various operations. The most restrictive
|
|
|
|
// kind is noncopyable. The noncopyable kind can be extended with any number
|
|
|
|
// of the following attributes.
|
|
|
|
//
|
2014-03-22 08:42:32 -05:00
|
|
|
// Send: Things that can be sent on channels or included in spawned closures. It
|
|
|
|
// includes scalar types as well as classes and unique types containing only
|
|
|
|
// sendable types.
|
2014-01-07 20:49:13 -06:00
|
|
|
// 'static: Things that do not contain references.
|
2012-05-24 16:33:21 -05:00
|
|
|
//
|
2011-11-18 10:09:14 -06:00
|
|
|
// This pass ensures that type parameters are only instantiated with types
|
|
|
|
// whose kinds are equal or less general than the way the type parameter was
|
2014-03-22 08:42:32 -05:00
|
|
|
// annotated (with the `Send` bound).
|
2011-11-18 10:09:14 -06:00
|
|
|
//
|
|
|
|
// It also verifies that noncopyable kinds are not copied. Sendability is not
|
|
|
|
// applied, since none of our language primitives send. Instead, the sending
|
|
|
|
// primitives in the stdlib are explicitly annotated to only take sendable
|
|
|
|
// types.
|
|
|
|
|
2013-07-02 14:47:32 -05:00
|
|
|
#[deriving(Clone)]
|
2014-03-05 21:07:47 -06:00
|
|
|
pub struct Context<'a> {
|
|
|
|
tcx: &'a ty::ctxt,
|
2013-02-19 01:40:42 -06:00
|
|
|
}
|
2011-11-15 11:15:35 -06:00
|
|
|
|
2014-03-05 21:07:47 -06:00
|
|
|
impl<'a> Visitor<()> for Context<'a> {
|
2013-08-13 07:11:34 -05:00
|
|
|
|
2014-01-06 06:00:46 -06:00
|
|
|
fn visit_expr(&mut self, ex: &Expr, _: ()) {
|
2013-09-25 04:00:36 -05:00
|
|
|
check_expr(self, ex);
|
2013-08-13 07:11:34 -05:00
|
|
|
}
|
|
|
|
|
2014-01-09 07:05:33 -06:00
|
|
|
fn visit_fn(&mut self, fk: &visit::FnKind, fd: &FnDecl,
|
2014-01-06 06:00:46 -06:00
|
|
|
b: &Block, s: Span, n: NodeId, _: ()) {
|
2013-09-25 04:00:36 -05:00
|
|
|
check_fn(self, fk, fd, b, s, n);
|
2013-08-13 07:11:34 -05:00
|
|
|
}
|
|
|
|
|
2014-01-06 06:00:46 -06:00
|
|
|
fn visit_ty(&mut self, t: &Ty, _: ()) {
|
2013-09-25 04:00:36 -05:00
|
|
|
check_ty(self, t);
|
2013-08-13 07:11:34 -05:00
|
|
|
}
|
2014-04-23 18:57:22 -05:00
|
|
|
|
2014-01-09 07:05:33 -06:00
|
|
|
fn visit_item(&mut self, i: &Item, _: ()) {
|
2013-09-25 04:00:36 -05:00
|
|
|
check_item(self, i);
|
2013-08-13 07:11:34 -05:00
|
|
|
}
|
2014-04-23 18:57:22 -05:00
|
|
|
|
|
|
|
fn visit_pat(&mut self, p: &Pat, _: ()) {
|
|
|
|
check_pat(self, p);
|
|
|
|
}
|
2013-08-13 07:11:34 -05:00
|
|
|
}
|
|
|
|
|
2014-03-05 21:07:47 -06:00
|
|
|
pub fn check_crate(tcx: &ty::ctxt,
|
2014-02-05 15:15:24 -06:00
|
|
|
krate: &Crate) {
|
2013-09-25 04:00:36 -05:00
|
|
|
let mut ctx = Context {
|
2013-02-19 01:40:42 -06:00
|
|
|
tcx: tcx,
|
|
|
|
};
|
2014-02-05 15:15:24 -06:00
|
|
|
visit::walk_crate(&mut ctx, krate, ());
|
2011-11-15 11:15:35 -06:00
|
|
|
tcx.sess.abort_if_errors();
|
|
|
|
}
|
|
|
|
|
2013-09-25 04:00:36 -05:00
|
|
|
fn check_struct_safe_for_destructor(cx: &mut Context,
|
2013-08-31 11:13:04 -05:00
|
|
|
span: Span,
|
2013-09-01 20:45:37 -05:00
|
|
|
struct_did: DefId) {
|
2013-03-20 20:18:57 -05:00
|
|
|
let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did);
|
2014-05-31 17:53:13 -05:00
|
|
|
if !struct_tpt.generics.has_type_params(subst::TypeSpace) {
|
|
|
|
let struct_ty = ty::mk_struct(cx.tcx, struct_did,
|
|
|
|
subst::Substs::empty());
|
2013-06-05 13:33:14 -05:00
|
|
|
if !ty::type_is_sendable(cx.tcx, struct_ty) {
|
2013-03-20 20:18:57 -05:00
|
|
|
cx.tcx.sess.span_err(span,
|
2013-06-05 13:33:14 -05:00
|
|
|
"cannot implement a destructor on a \
|
|
|
|
structure that does not satisfy Send");
|
2013-03-20 20:18:57 -05:00
|
|
|
cx.tcx.sess.span_note(span,
|
2013-04-30 11:47:52 -05:00
|
|
|
"use \"#[unsafe_destructor]\" on the \
|
|
|
|
implementation to force the compiler to \
|
|
|
|
allow this");
|
2013-03-20 20:18:57 -05:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cx.tcx.sess.span_err(span,
|
2013-06-05 13:33:14 -05:00
|
|
|
"cannot implement a destructor on a structure \
|
2013-04-30 11:47:52 -05:00
|
|
|
with type parameters");
|
2013-03-20 20:18:57 -05:00
|
|
|
cx.tcx.sess.span_note(span,
|
2013-04-30 11:47:52 -05:00
|
|
|
"use \"#[unsafe_destructor]\" on the \
|
|
|
|
implementation to force the compiler to \
|
|
|
|
allow this");
|
2013-03-20 20:18:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-09 07:05:33 -06:00
|
|
|
fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_type: &Ty) {
|
2014-03-20 21:49:20 -05:00
|
|
|
let ast_trait_def = *cx.tcx.def_map.borrow()
|
|
|
|
.find(&trait_ref.ref_id)
|
|
|
|
.expect("trait ref not in def map!");
|
2014-05-14 14:31:30 -05:00
|
|
|
let trait_def_id = ast_trait_def.def_id();
|
2014-04-21 18:21:52 -05:00
|
|
|
let trait_def = cx.tcx.trait_defs.borrow()
|
|
|
|
.find_copy(&trait_def_id)
|
|
|
|
.expect("trait def not in trait-defs map!");
|
2013-08-16 15:57:42 -05:00
|
|
|
|
|
|
|
// If this trait has builtin-kind supertraits, meet them.
|
|
|
|
let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("checking impl with self type {:?}", ty::get(self_ty).sty);
|
2013-11-21 17:42:55 -06:00
|
|
|
check_builtin_bounds(cx, self_ty, trait_def.bounds, |missing| {
|
2013-08-16 15:57:42 -05:00
|
|
|
cx.tcx.sess.span_err(self_type.span,
|
2013-09-28 00:38:08 -05:00
|
|
|
format!("the type `{}', which does not fulfill `{}`, cannot implement this \
|
2014-05-16 12:45:16 -05:00
|
|
|
trait",
|
|
|
|
ty_to_str(cx.tcx, self_ty),
|
|
|
|
missing.user_string(cx.tcx)).as_slice());
|
2013-08-16 15:57:42 -05:00
|
|
|
cx.tcx.sess.span_note(self_type.span,
|
2013-09-28 00:38:08 -05:00
|
|
|
format!("types implementing this trait must fulfill `{}`",
|
2014-05-16 12:45:16 -05:00
|
|
|
trait_def.bounds.user_string(cx.tcx)).as_slice());
|
2013-11-21 17:42:55 -06:00
|
|
|
});
|
2013-08-16 15:57:42 -05:00
|
|
|
|
|
|
|
// If this is a destructor, check kinds.
|
|
|
|
if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) {
|
|
|
|
match self_type.node {
|
2014-01-09 07:05:33 -06:00
|
|
|
TyPath(_, ref bounds, path_node_id) => {
|
2013-08-16 15:57:42 -05:00
|
|
|
assert!(bounds.is_none());
|
2014-03-20 21:49:20 -05:00
|
|
|
let struct_def = cx.tcx.def_map.borrow().get_copy(&path_node_id);
|
2014-05-14 14:31:30 -05:00
|
|
|
let struct_did = struct_def.def_id();
|
2013-08-16 15:57:42 -05:00
|
|
|
check_struct_safe_for_destructor(cx, self_type.span, struct_did);
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
cx.tcx.sess.span_bug(self_type.span,
|
|
|
|
"the self type for the Drop trait impl is not a path");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-20 20:18:57 -05:00
|
|
|
}
|
|
|
|
|
2014-01-09 07:05:33 -06:00
|
|
|
fn check_item(cx: &mut Context, item: &Item) {
|
2014-02-28 17:25:15 -06:00
|
|
|
if !attr::contains_name(item.attrs.as_slice(), "unsafe_destructor") {
|
2013-03-20 20:18:57 -05:00
|
|
|
match item.node {
|
2014-05-16 12:15:33 -05:00
|
|
|
ItemImpl(_, Some(ref trait_ref), ref self_type, _) => {
|
|
|
|
check_impl_of_trait(cx, item, trait_ref, &**self_type);
|
2013-03-20 20:18:57 -05:00
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-25 04:00:36 -05:00
|
|
|
visit::walk_item(cx, item, ());
|
2013-03-20 20:18:57 -05:00
|
|
|
}
|
|
|
|
|
2011-12-20 21:39:33 -06:00
|
|
|
// Yields the appropriate function to check the kind of closed over
|
2013-07-27 03:25:59 -05:00
|
|
|
// variables. `id` is the NodeId for some expression that creates the
|
2011-12-20 21:39:33 -06:00
|
|
|
// closure.
|
2013-11-19 15:22:03 -06:00
|
|
|
fn with_appropriate_checker(cx: &Context,
|
|
|
|
id: NodeId,
|
2014-04-14 09:43:57 -05:00
|
|
|
b: |checker: |&Context, &freevar_entry||) {
|
2013-09-25 04:00:36 -05:00
|
|
|
fn check_for_uniq(cx: &Context, fv: &freevar_entry, bounds: ty::BuiltinBounds) {
|
2013-02-07 21:33:12 -06:00
|
|
|
// all captured data must be owned, regardless of whether it is
|
|
|
|
// moved in or copied in.
|
2014-05-14 14:31:30 -05:00
|
|
|
let id = fv.def.def_id().node;
|
2013-01-10 12:59:58 -06:00
|
|
|
let var_t = ty::node_id_to_type(cx.tcx, id);
|
2013-06-13 18:37:18 -05:00
|
|
|
|
2013-06-21 16:58:21 -05:00
|
|
|
check_freevar_bounds(cx, fv.span, var_t, bounds, None);
|
2012-05-07 13:31:57 -05:00
|
|
|
}
|
|
|
|
|
2013-09-25 04:00:36 -05:00
|
|
|
fn check_for_block(cx: &Context, fv: &freevar_entry,
|
2013-06-21 16:58:21 -05:00
|
|
|
bounds: ty::BuiltinBounds, region: ty::Region) {
|
2014-05-14 14:31:30 -05:00
|
|
|
let id = fv.def.def_id().node;
|
2013-06-13 18:37:18 -05:00
|
|
|
let var_t = ty::node_id_to_type(cx.tcx, id);
|
2013-06-21 16:58:21 -05:00
|
|
|
// FIXME(#3569): Figure out whether the implicit borrow is actually
|
|
|
|
// mutable. Currently we assume all upvars are referenced mutably.
|
|
|
|
let implicit_borrowed_type = ty::mk_mut_rptr(cx.tcx, region, var_t);
|
|
|
|
check_freevar_bounds(cx, fv.span, implicit_borrowed_type,
|
|
|
|
bounds, Some(var_t));
|
2012-05-07 13:31:57 -05:00
|
|
|
}
|
|
|
|
|
2014-04-14 09:43:57 -05:00
|
|
|
fn check_for_bare(cx: &Context, fv: &freevar_entry) {
|
2013-01-10 12:59:58 -06:00
|
|
|
cx.tcx.sess.span_err(
|
|
|
|
fv.span,
|
2013-07-01 12:47:43 -05:00
|
|
|
"can't capture dynamic environment in a fn item; \
|
|
|
|
use the || { ... } closure form instead");
|
|
|
|
} // same check is done in resolve.rs, but shouldn't be done
|
2012-05-07 13:31:57 -05:00
|
|
|
|
2012-01-30 10:28:30 -06:00
|
|
|
let fty = ty::node_id_to_type(cx.tcx, id);
|
2013-01-31 19:12:29 -06:00
|
|
|
match ty::get(fty).sty {
|
2014-05-05 20:56:44 -05:00
|
|
|
ty::ty_closure(box ty::ClosureTy {
|
2014-04-11 10:03:10 -05:00
|
|
|
store: ty::UniqTraitStore, bounds, ..
|
|
|
|
}) => b(|cx, fv| check_for_uniq(cx, fv, bounds)),
|
|
|
|
|
2014-05-05 20:56:44 -05:00
|
|
|
ty::ty_closure(box ty::ClosureTy {
|
2014-04-11 10:03:10 -05:00
|
|
|
store: ty::RegionTraitStore(region, _), bounds, ..
|
|
|
|
}) => b(|cx, fv| check_for_block(cx, fv, bounds, region)),
|
|
|
|
|
2013-01-31 19:12:29 -06:00
|
|
|
ty::ty_bare_fn(_) => {
|
|
|
|
b(check_for_bare)
|
|
|
|
}
|
|
|
|
ref s => {
|
2014-05-16 12:45:16 -05:00
|
|
|
cx.tcx.sess.bug(format!("expect fn type in kind checker, not \
|
|
|
|
{:?}",
|
|
|
|
s).as_slice());
|
2013-01-31 19:12:29 -06:00
|
|
|
}
|
2011-12-20 21:39:33 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that the free variables used in a shared/sendable closure conform
|
|
|
|
// to the copy/move kind bounds. Then recursively check the function body.
|
2013-02-18 00:20:36 -06:00
|
|
|
fn check_fn(
|
2013-09-25 04:00:36 -05:00
|
|
|
cx: &mut Context,
|
2014-01-09 07:05:33 -06:00
|
|
|
fk: &visit::FnKind,
|
|
|
|
decl: &FnDecl,
|
2014-01-06 06:00:46 -06:00
|
|
|
body: &Block,
|
2013-08-31 11:13:04 -05:00
|
|
|
sp: Span,
|
2013-09-25 04:00:36 -05:00
|
|
|
fn_id: NodeId) {
|
2012-05-07 13:31:57 -05:00
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
// Check kinds on free variables:
|
2013-11-21 17:42:55 -06:00
|
|
|
with_appropriate_checker(cx, fn_id, |chk| {
|
2014-04-21 18:21:53 -05:00
|
|
|
freevars::with_freevars(cx.tcx, fn_id, |freevars| {
|
|
|
|
for fv in freevars.iter() {
|
2014-04-14 09:43:57 -05:00
|
|
|
chk(cx, fv);
|
|
|
|
}
|
2014-04-21 18:21:53 -05:00
|
|
|
});
|
2013-11-21 17:42:55 -06:00
|
|
|
});
|
2011-12-09 18:56:48 -06:00
|
|
|
|
2014-05-14 01:20:25 -05:00
|
|
|
visit::walk_fn(cx, fk, decl, body, sp, ());
|
2011-12-20 21:39:33 -06:00
|
|
|
}
|
|
|
|
|
2014-01-06 06:00:46 -06:00
|
|
|
pub fn check_expr(cx: &mut Context, e: &Expr) {
|
2014-02-13 23:07:09 -06:00
|
|
|
debug!("kind::check_expr({})", expr_to_str(e));
|
2013-01-10 12:59:58 -06:00
|
|
|
|
|
|
|
// Handle any kind bounds on type parameters
|
2014-05-31 17:53:13 -05:00
|
|
|
check_bounds_on_type_parameters(cx, e);
|
2012-08-16 18:44:22 -05:00
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
match e.node {
|
2014-06-11 21:33:52 -05:00
|
|
|
ExprBox(ref loc, ref interior) => {
|
|
|
|
let def = ty::resolve_expr(cx.tcx, &**loc);
|
|
|
|
if Some(def.def_id()) == cx.tcx.lang_items.managed_heap() {
|
|
|
|
let interior_type = ty::expr_ty(cx.tcx, &**interior);
|
|
|
|
let _ = check_static(cx.tcx, interior_type, interior.span);
|
|
|
|
}
|
2013-07-18 19:12:46 -05:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ExprCast(ref source, _) => {
|
|
|
|
let source_ty = ty::expr_ty(cx.tcx, &**source);
|
2013-12-26 12:54:41 -06:00
|
|
|
let target_ty = ty::expr_ty(cx.tcx, e);
|
|
|
|
check_trait_cast(cx, source_ty, target_ty, source.span);
|
2011-11-22 06:27:40 -06:00
|
|
|
}
|
2014-05-16 12:15:33 -05:00
|
|
|
ExprRepeat(ref element, ref count_expr) => {
|
|
|
|
let count = ty::eval_repeat_count(cx.tcx, &**count_expr);
|
2013-01-10 12:59:58 -06:00
|
|
|
if count > 1 {
|
2014-05-16 12:15:33 -05:00
|
|
|
let element_ty = ty::expr_ty(cx.tcx, &**element);
|
2013-01-10 12:59:58 -06:00
|
|
|
check_copy(cx, element_ty, element.span,
|
|
|
|
"repeated element will be copied");
|
2011-11-15 11:15:35 -06:00
|
|
|
}
|
|
|
|
}
|
2013-01-10 12:59:58 -06:00
|
|
|
_ => {}
|
2011-11-15 11:15:35 -06:00
|
|
|
}
|
2013-12-26 12:54:41 -06:00
|
|
|
|
|
|
|
// Search for auto-adjustments to find trait coercions.
|
2014-03-20 21:49:20 -05:00
|
|
|
match cx.tcx.adjustments.borrow().find(&e.id) {
|
2014-01-03 17:08:48 -06:00
|
|
|
Some(adjustment) => {
|
2014-04-10 08:26:26 -05:00
|
|
|
match *adjustment {
|
2014-01-03 17:08:48 -06:00
|
|
|
ty::AutoObject(..) => {
|
|
|
|
let source_ty = ty::expr_ty(cx.tcx, e);
|
2014-04-09 10:18:40 -05:00
|
|
|
let target_ty = ty::expr_ty_adjusted(cx.tcx, e);
|
2014-01-03 17:08:48 -06:00
|
|
|
check_trait_cast(cx, source_ty, target_ty, e.span);
|
|
|
|
}
|
|
|
|
ty::AutoAddEnv(..) |
|
|
|
|
ty::AutoDerefRef(..) => {}
|
|
|
|
}
|
2013-12-26 12:54:41 -06:00
|
|
|
}
|
2014-01-03 17:08:48 -06:00
|
|
|
None => {}
|
2013-12-26 12:54:41 -06:00
|
|
|
}
|
|
|
|
|
2013-09-25 04:00:36 -05:00
|
|
|
visit::walk_expr(cx, e, ());
|
2011-11-15 11:15:35 -06:00
|
|
|
}
|
|
|
|
|
2014-05-31 17:53:13 -05:00
|
|
|
fn check_bounds_on_type_parameters(cx: &mut Context, e: &Expr) {
|
|
|
|
let method_map = cx.tcx.method_map.borrow();
|
|
|
|
let method = method_map.find(&typeck::MethodCall::expr(e.id));
|
|
|
|
|
|
|
|
// Find the values that were provided (if any)
|
|
|
|
let item_substs = cx.tcx.item_substs.borrow();
|
|
|
|
let (types, is_object_call) = match method {
|
|
|
|
Some(method) => {
|
|
|
|
let is_object_call = match method.origin {
|
|
|
|
typeck::MethodObject(..) => true,
|
|
|
|
typeck::MethodStatic(..) | typeck::MethodParam(..) => false
|
|
|
|
};
|
|
|
|
(&method.substs.types, is_object_call)
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
match item_substs.find(&e.id) {
|
|
|
|
None => { return; }
|
|
|
|
Some(s) => { (&s.substs.types, false) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Find the relevant type parameter definitions
|
|
|
|
let def_map = cx.tcx.def_map.borrow();
|
|
|
|
let type_param_defs = match e.node {
|
|
|
|
ExprPath(_) => {
|
|
|
|
let did = def_map.get_copy(&e.id).def_id();
|
|
|
|
ty::lookup_item_type(cx.tcx, did).generics.types.clone()
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
// Type substitutions should only occur on paths and
|
|
|
|
// method calls, so this needs to be a method call.
|
|
|
|
|
|
|
|
// Even though the callee_id may have been the id with
|
|
|
|
// node_type_substs, e.id is correct here.
|
|
|
|
match method {
|
|
|
|
Some(method) => {
|
|
|
|
ty::method_call_type_param_defs(cx.tcx, method.origin)
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
cx.tcx.sess.span_bug(e.span,
|
|
|
|
"non path/method call expr has type substs??");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Check that the value provided for each definition meets the
|
|
|
|
// kind requirements
|
|
|
|
for type_param_def in type_param_defs.iter() {
|
|
|
|
let ty = *types.get(type_param_def.space, type_param_def.index);
|
|
|
|
|
|
|
|
// If this is a call to an object method (`foo.bar()` where
|
|
|
|
// `foo` has a type like `Trait`), then the self type is
|
|
|
|
// unknown (after all, this is a virtual call). In that case,
|
|
|
|
// we will have put a ty_err in the substitutions, and we can
|
|
|
|
// just skip over validating the bounds (because the bounds
|
|
|
|
// would have been enforced when the object instance was
|
|
|
|
// created).
|
|
|
|
if is_object_call && type_param_def.space == subst::SelfSpace {
|
|
|
|
assert_eq!(type_param_def.index, 0);
|
|
|
|
assert!(ty::type_is_error(ty));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
debug!("type_param_def space={} index={} ty={}",
|
|
|
|
type_param_def.space, type_param_def.index, ty.repr(cx.tcx));
|
|
|
|
check_typaram_bounds(cx, e.span, ty, type_param_def)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-26 12:54:41 -06:00
|
|
|
fn check_trait_cast(cx: &mut Context, source_ty: ty::t, target_ty: ty::t, span: Span) {
|
|
|
|
check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
|
|
|
|
match ty::get(target_ty).sty {
|
2014-06-11 00:18:57 -05:00
|
|
|
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => match ty::get(ty).sty {
|
|
|
|
ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
|
|
|
|
check_trait_cast_bounds(cx, span, source_ty, bounds);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
},
|
2013-12-26 12:54:41 -06:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-25 04:00:36 -05:00
|
|
|
fn check_ty(cx: &mut Context, aty: &Ty) {
|
2012-08-06 14:34:08 -05:00
|
|
|
match aty.node {
|
2014-01-09 07:05:33 -06:00
|
|
|
TyPath(_, _, id) => {
|
2014-05-07 06:20:15 -05:00
|
|
|
match cx.tcx.item_substs.borrow().find(&id) {
|
|
|
|
None => { }
|
|
|
|
Some(ref item_substs) => {
|
|
|
|
let def_map = cx.tcx.def_map.borrow();
|
2014-05-14 14:31:30 -05:00
|
|
|
let did = def_map.get_copy(&id).def_id();
|
2014-05-07 06:20:15 -05:00
|
|
|
let generics = ty::lookup_item_type(cx.tcx, did).generics;
|
2014-05-31 17:53:13 -05:00
|
|
|
for def in generics.types.iter() {
|
|
|
|
let ty = *item_substs.substs.types.get(def.space,
|
|
|
|
def.index);
|
|
|
|
check_typaram_bounds(cx, aty.span, ty, def)
|
2014-05-07 06:20:15 -05:00
|
|
|
}
|
2014-01-09 07:05:33 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
2012-03-19 04:45:29 -05:00
|
|
|
}
|
2013-09-25 04:00:36 -05:00
|
|
|
visit::walk_ty(cx, aty, ());
|
2012-03-19 04:45:29 -05:00
|
|
|
}
|
|
|
|
|
2013-06-19 16:58:04 -05:00
|
|
|
// Calls "any_missing" if any bounds were missing.
|
2013-11-19 15:22:03 -06:00
|
|
|
pub fn check_builtin_bounds(cx: &Context,
|
|
|
|
ty: ty::t,
|
|
|
|
bounds: ty::BuiltinBounds,
|
|
|
|
any_missing: |ty::BuiltinBounds|) {
|
2013-02-07 21:33:12 -06:00
|
|
|
let kind = ty::type_contents(cx.tcx, ty);
|
2014-05-28 14:36:05 -05:00
|
|
|
let mut missing = ty::empty_builtin_bounds();
|
2013-07-25 23:53:29 -05:00
|
|
|
for bound in bounds.iter() {
|
2013-05-07 16:30:21 -05:00
|
|
|
if !kind.meets_bound(cx.tcx, bound) {
|
|
|
|
missing.add(bound);
|
2012-05-29 18:22:22 -05:00
|
|
|
}
|
2013-07-25 23:53:29 -05:00
|
|
|
}
|
2013-06-19 16:58:04 -05:00
|
|
|
if !missing.is_empty() {
|
|
|
|
any_missing(missing);
|
|
|
|
}
|
2013-06-13 18:37:18 -05:00
|
|
|
}
|
|
|
|
|
2013-09-25 04:00:36 -05:00
|
|
|
pub fn check_typaram_bounds(cx: &Context,
|
2014-02-26 08:06:45 -06:00
|
|
|
sp: Span,
|
|
|
|
ty: ty::t,
|
|
|
|
type_param_def: &ty::TypeParameterDef) {
|
2013-11-21 17:42:55 -06:00
|
|
|
check_builtin_bounds(cx,
|
|
|
|
ty,
|
|
|
|
type_param_def.bounds.builtin_bounds,
|
|
|
|
|missing| {
|
2013-02-07 21:33:12 -06:00
|
|
|
cx.tcx.sess.span_err(
|
|
|
|
sp,
|
2013-09-28 00:38:08 -05:00
|
|
|
format!("instantiating a type parameter with an incompatible type \
|
2014-05-16 12:45:16 -05:00
|
|
|
`{}`, which does not fulfill `{}`",
|
|
|
|
ty_to_str(cx.tcx, ty),
|
|
|
|
missing.user_string(cx.tcx)).as_slice());
|
2013-11-21 17:42:55 -06:00
|
|
|
});
|
2012-03-19 04:45:29 -05:00
|
|
|
}
|
|
|
|
|
2013-09-25 04:00:36 -05:00
|
|
|
pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t,
|
2013-06-21 16:58:21 -05:00
|
|
|
bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>)
|
2013-06-13 18:37:18 -05:00
|
|
|
{
|
2013-11-21 17:42:55 -06:00
|
|
|
check_builtin_bounds(cx, ty, bounds, |missing| {
|
2013-06-21 16:58:21 -05:00
|
|
|
// Will be Some if the freevar is implicitly borrowed (stack closure).
|
|
|
|
// Emit a less mysterious error message in this case.
|
|
|
|
match referenced_ty {
|
2014-05-16 12:45:16 -05:00
|
|
|
Some(rty) => {
|
|
|
|
cx.tcx.sess.span_err(sp,
|
|
|
|
format!("cannot implicitly borrow variable of type `{}` in a \
|
|
|
|
bounded stack closure (implicit reference does not \
|
|
|
|
fulfill `{}`)",
|
|
|
|
ty_to_str(cx.tcx, rty),
|
|
|
|
missing.user_string(cx.tcx)).as_slice())
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
cx.tcx.sess.span_err(sp,
|
2013-09-28 00:38:08 -05:00
|
|
|
format!("cannot capture variable of type `{}`, which does \
|
2014-05-16 12:45:16 -05:00
|
|
|
not fulfill `{}`, in a bounded closure",
|
|
|
|
ty_to_str(cx.tcx, ty),
|
|
|
|
missing.user_string(cx.tcx)).as_slice())
|
|
|
|
}
|
2013-06-21 16:58:21 -05:00
|
|
|
}
|
2013-06-13 18:37:18 -05:00
|
|
|
cx.tcx.sess.span_note(
|
|
|
|
sp,
|
2013-09-28 00:38:08 -05:00
|
|
|
format!("this closure's environment must satisfy `{}`",
|
2014-05-16 12:45:16 -05:00
|
|
|
bounds.user_string(cx.tcx)).as_slice());
|
2013-11-21 17:42:55 -06:00
|
|
|
});
|
2013-06-13 18:37:18 -05:00
|
|
|
}
|
|
|
|
|
2013-09-25 04:00:36 -05:00
|
|
|
pub fn check_trait_cast_bounds(cx: &Context, sp: Span, ty: ty::t,
|
2013-06-19 21:06:50 -05:00
|
|
|
bounds: ty::BuiltinBounds) {
|
2013-11-21 17:42:55 -06:00
|
|
|
check_builtin_bounds(cx, ty, bounds, |missing| {
|
2013-06-19 16:58:04 -05:00
|
|
|
cx.tcx.sess.span_err(sp,
|
2013-09-28 00:38:08 -05:00
|
|
|
format!("cannot pack type `{}`, which does not fulfill \
|
2014-05-16 12:45:16 -05:00
|
|
|
`{}`, as a trait bounded by {}",
|
|
|
|
ty_to_str(cx.tcx, ty), missing.user_string(cx.tcx),
|
|
|
|
bounds.user_string(cx.tcx)).as_slice());
|
2013-11-21 17:42:55 -06:00
|
|
|
});
|
2013-06-19 16:58:04 -05:00
|
|
|
}
|
|
|
|
|
2013-09-25 04:00:36 -05:00
|
|
|
fn check_copy(cx: &Context, ty: ty::t, sp: Span, reason: &str) {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("type_contents({})={}",
|
2013-02-07 21:33:12 -06:00
|
|
|
ty_to_str(cx.tcx, ty),
|
|
|
|
ty::type_contents(cx.tcx, ty).to_str());
|
2013-07-10 18:00:11 -05:00
|
|
|
if ty::type_moves_by_default(cx.tcx, ty) {
|
2013-02-07 21:33:12 -06:00
|
|
|
cx.tcx.sess.span_err(
|
2014-05-16 12:45:16 -05:00
|
|
|
sp,
|
|
|
|
format!("copying a value of non-copyable type `{}`",
|
|
|
|
ty_to_str(cx.tcx, ty)).as_slice());
|
|
|
|
cx.tcx.sess.span_note(sp, format!("{}", reason).as_slice());
|
2011-11-15 11:15:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-05 21:07:47 -06:00
|
|
|
pub fn check_static(tcx: &ty::ctxt, ty: ty::t, sp: Span) -> bool {
|
2013-05-07 16:30:21 -05:00
|
|
|
if !ty::type_is_static(tcx, ty) {
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(ty).sty {
|
2013-11-28 14:22:53 -06:00
|
|
|
ty::ty_param(..) => {
|
2014-02-26 11:09:15 -06:00
|
|
|
tcx.sess.span_err(sp,
|
|
|
|
format!("value may contain references; \
|
2014-05-16 12:45:16 -05:00
|
|
|
add `'static` bound to `{}`",
|
|
|
|
ty_to_str(tcx, ty)).as_slice());
|
2012-07-18 13:01:54 -05:00
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => {
|
2014-01-07 20:49:13 -06:00
|
|
|
tcx.sess.span_err(sp, "value may contain references");
|
2012-07-18 13:01:54 -05:00
|
|
|
}
|
|
|
|
}
|
2012-07-16 22:17:57 -05:00
|
|
|
false
|
|
|
|
} else {
|
|
|
|
true
|
2011-12-09 18:56:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-30 12:29:35 -06:00
|
|
|
/// This is rather subtle. When we are casting a value to an instantiated
|
2014-01-07 20:49:13 -06:00
|
|
|
/// trait like `a as trait<'r>`, regionck already ensures that any references
|
|
|
|
/// that appear in the type of `a` are bounded by `'r` (ed.: rem
|
2013-04-02 00:32:37 -05:00
|
|
|
/// FIXME(#5723)). However, it is possible that there are *type parameters*
|
2014-01-07 20:49:13 -06:00
|
|
|
/// in the type of `a`, and those *type parameters* may have references
|
2013-04-02 00:32:37 -05:00
|
|
|
/// within them. We have to guarantee that the regions which appear in those
|
|
|
|
/// type parameters are not obscured.
|
2012-07-18 13:01:54 -05:00
|
|
|
///
|
|
|
|
/// Therefore, we ensure that one of three conditions holds:
|
|
|
|
///
|
2012-07-30 16:51:21 -05:00
|
|
|
/// (1) The trait instance cannot escape the current fn. This is
|
2012-07-18 13:01:54 -05:00
|
|
|
/// guaranteed if the region bound `&r` is some scope within the fn
|
2014-01-07 20:49:13 -06:00
|
|
|
/// itself. This case is safe because whatever references are
|
2012-07-18 13:01:54 -05:00
|
|
|
/// found within the type parameter, they must enclose the fn body
|
|
|
|
/// itself.
|
|
|
|
///
|
2012-07-30 16:51:21 -05:00
|
|
|
/// (2) The type parameter appears in the type of the trait. For
|
|
|
|
/// example, if the type parameter is `T` and the trait type is
|
2014-01-07 20:49:13 -06:00
|
|
|
/// `deque<T>`, then whatever references may appear in `T` also
|
2012-07-18 13:01:54 -05:00
|
|
|
/// appear in `deque<T>`.
|
|
|
|
///
|
2013-06-05 13:33:14 -05:00
|
|
|
/// (3) The type parameter is sendable (and therefore does not contain
|
2014-01-07 20:49:13 -06:00
|
|
|
/// references).
|
2013-04-02 00:32:37 -05:00
|
|
|
///
|
|
|
|
/// FIXME(#5723)---This code should probably move into regionck.
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn check_cast_for_escaping_regions(
|
2013-09-25 04:00:36 -05:00
|
|
|
cx: &Context,
|
2013-12-26 12:54:41 -06:00
|
|
|
source_ty: ty::t,
|
|
|
|
target_ty: ty::t,
|
|
|
|
source_span: Span)
|
2013-02-07 21:33:12 -06:00
|
|
|
{
|
2014-01-30 12:29:35 -06:00
|
|
|
// Determine what type we are casting to; if it is not a trait, then no
|
2012-07-18 13:01:54 -05:00
|
|
|
// worries.
|
2014-06-11 00:18:57 -05:00
|
|
|
if !ty::type_is_trait(target_ty) {
|
|
|
|
return;
|
2013-04-02 00:32:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Collect up the regions that appear in the target type. We want to
|
|
|
|
// ensure that these lifetimes are shorter than all lifetimes that are in
|
|
|
|
// the source type. See test `src/test/compile-fail/regions-trait-2.rs`
|
2014-03-04 12:02:49 -06:00
|
|
|
let mut target_regions = Vec::new();
|
2013-04-02 00:32:37 -05:00
|
|
|
ty::walk_regions_and_ty(
|
|
|
|
cx.tcx,
|
|
|
|
target_ty,
|
|
|
|
|r| {
|
|
|
|
if !r.is_bound() {
|
|
|
|
target_regions.push(r);
|
|
|
|
}
|
|
|
|
},
|
2013-10-29 05:03:32 -05:00
|
|
|
|_| ());
|
2012-07-18 13:01:54 -05:00
|
|
|
|
2012-07-30 16:51:21 -05:00
|
|
|
// Check, based on the region associated with the trait, whether it can
|
2012-07-18 13:01:54 -05:00
|
|
|
// possibly escape the enclosing fn item (note that all type parameters
|
2013-04-02 00:32:37 -05:00
|
|
|
// must have been declared on the enclosing fn item).
|
2013-10-29 09:34:11 -05:00
|
|
|
if target_regions.iter().any(|r| is_ReScope(*r)) {
|
2013-04-02 00:32:37 -05:00
|
|
|
return; /* case (1) */
|
2012-07-18 13:01:54 -05:00
|
|
|
}
|
|
|
|
|
2012-07-30 16:51:21 -05:00
|
|
|
// Assuming the trait instance can escape, then ensure that each parameter
|
2013-06-05 13:33:14 -05:00
|
|
|
// either appears in the trait type or is sendable.
|
2012-07-18 13:01:54 -05:00
|
|
|
let target_params = ty::param_tys_in_type(target_ty);
|
2013-04-02 00:32:37 -05:00
|
|
|
ty::walk_regions_and_ty(
|
|
|
|
cx.tcx,
|
|
|
|
source_ty,
|
|
|
|
|
|
|
|
|_r| {
|
|
|
|
// FIXME(#5723) --- turn this check on once &Objects are usable
|
|
|
|
//
|
2013-07-04 21:13:26 -05:00
|
|
|
// if !target_regions.iter().any(|t_r| is_subregion_of(cx, *t_r, r)) {
|
2013-04-02 00:32:37 -05:00
|
|
|
// cx.tcx.sess.span_err(
|
2013-12-26 12:54:41 -06:00
|
|
|
// source_span,
|
2014-01-07 20:49:13 -06:00
|
|
|
// format!("source contains reference with lifetime \
|
2013-09-28 00:38:08 -05:00
|
|
|
// not found in the target type `{}`",
|
2013-04-02 00:32:37 -05:00
|
|
|
// ty_to_str(cx.tcx, target_ty)));
|
|
|
|
// note_and_explain_region(
|
|
|
|
// cx.tcx, "source data is only valid for ", r, "");
|
|
|
|
// }
|
|
|
|
},
|
|
|
|
|
|
|
|
|ty| {
|
|
|
|
match ty::get(ty).sty {
|
|
|
|
ty::ty_param(source_param) => {
|
2014-05-31 17:53:13 -05:00
|
|
|
if source_param.space == subst::SelfSpace {
|
|
|
|
// FIXME (#5723) -- there is no reason that
|
|
|
|
// Self should be exempt from this check,
|
|
|
|
// except for historical accident. Bottom
|
|
|
|
// line, we need proper region bounding.
|
|
|
|
} else if target_params.iter().any(|x| x == &source_param) {
|
2013-04-02 00:32:37 -05:00
|
|
|
/* case (2) */
|
|
|
|
} else {
|
2014-02-26 11:09:15 -06:00
|
|
|
check_static(cx.tcx, ty, source_span); /* case (3) */
|
2013-04-02 00:32:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
2012-07-18 13:01:54 -05:00
|
|
|
}
|
2013-04-02 00:32:37 -05:00
|
|
|
});
|
|
|
|
|
2014-05-28 14:36:05 -05:00
|
|
|
#[allow(non_snake_case_functions)]
|
2013-10-29 09:34:11 -05:00
|
|
|
fn is_ReScope(r: ty::Region) -> bool {
|
2013-04-02 00:32:37 -05:00
|
|
|
match r {
|
2013-11-28 14:22:53 -06:00
|
|
|
ty::ReScope(..) => true,
|
2013-04-02 00:32:37 -05:00
|
|
|
_ => false
|
2012-07-18 13:01:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-04-23 18:57:22 -05:00
|
|
|
|
|
|
|
// Ensure that `ty` has a statically known size (i.e., it has the `Sized` bound).
|
2014-05-22 18:57:53 -05:00
|
|
|
fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) {
|
2014-04-23 18:57:22 -05:00
|
|
|
if !ty::type_is_sized(tcx, ty) {
|
2014-05-16 12:45:16 -05:00
|
|
|
tcx.sess.span_err(sp,
|
|
|
|
format!("variable `{}` has dynamically sized type \
|
|
|
|
`{}`",
|
|
|
|
name,
|
|
|
|
ty_to_str(tcx, ty)).as_slice());
|
2014-04-23 18:57:22 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that any variables in a pattern have types with statically known size.
|
|
|
|
fn check_pat(cx: &mut Context, pat: &Pat) {
|
|
|
|
let var_name = match pat.node {
|
2014-05-25 05:17:19 -05:00
|
|
|
PatWild => Some("_".to_string()),
|
|
|
|
PatIdent(_, ref path, _) => Some(path_to_str(path).to_string()),
|
2014-04-23 18:57:22 -05:00
|
|
|
_ => None
|
|
|
|
};
|
|
|
|
|
|
|
|
match var_name {
|
|
|
|
Some(name) => {
|
|
|
|
let types = cx.tcx.node_types.borrow();
|
|
|
|
let ty = types.find(&(pat.id as uint));
|
|
|
|
match ty {
|
|
|
|
Some(ty) => {
|
|
|
|
debug!("kind: checking sized-ness of variable {}: {}",
|
|
|
|
name, ty_to_str(cx.tcx, *ty));
|
|
|
|
check_sized(cx.tcx, *ty, name, pat.span);
|
|
|
|
}
|
|
|
|
None => {} // extern fn args
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
visit::walk_pat(cx, pat, ());
|
|
|
|
}
|