2012-12-03 18:48:01 -06:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// 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-01-08 21:37:25 -06:00
|
|
|
use core::prelude::*;
|
2013-01-07 16:16:52 -06: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;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::lint::{non_implicitly_copyable_typarams, implicit_copies};
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::liveness;
|
|
|
|
use middle::pat_util;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::ty::{Kind, kind_copyable, kind_noncopyable, kind_const};
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::ty;
|
|
|
|
use middle::typeck;
|
|
|
|
use middle;
|
2012-09-04 13:54:36 -05:00
|
|
|
use util::ppaux::{ty_to_str, tys_to_str};
|
2012-12-13 15:05:22 -06:00
|
|
|
|
2012-12-23 16:41:37 -06:00
|
|
|
use core::option;
|
|
|
|
use core::str;
|
|
|
|
use core::vec;
|
2013-02-01 01:13:36 -06:00
|
|
|
use std::oldmap::HashMap;
|
2012-12-13 15:05:22 -06:00
|
|
|
use syntax::ast::*;
|
2013-01-30 11:56:33 -06:00
|
|
|
use syntax::codemap::{span, spanned};
|
2012-09-04 13:54:36 -05:00
|
|
|
use syntax::print::pprust::expr_to_str;
|
2012-12-13 15:05:22 -06:00
|
|
|
use syntax::{visit, ast_util};
|
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.
|
|
|
|
//
|
|
|
|
// send: Things that can be sent on channels or included in spawned closures.
|
|
|
|
// copy: Things that can be copied.
|
|
|
|
// const: Things thare are deeply immutable. They are guaranteed never to
|
|
|
|
// change, and can be safely shared without copying between tasks.
|
2012-07-16 22:17:57 -05:00
|
|
|
// owned: Things that do not contain borrowed pointers.
|
2012-05-24 16:33:21 -05:00
|
|
|
//
|
2012-06-24 17:09:57 -05:00
|
|
|
// Send includes scalar types as well as classes and unique types containing
|
|
|
|
// only sendable types.
|
2012-05-24 16:33:21 -05:00
|
|
|
//
|
|
|
|
// Copy includes boxes, closure and unique types containing copyable types.
|
|
|
|
//
|
|
|
|
// Const include scalar types, things without non-const fields, and pointers
|
|
|
|
// to const things.
|
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
|
2012-05-24 16:33:21 -05:00
|
|
|
// annotated (with the `send`, `copy` or `const` keyword).
|
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-01-30 15:44:24 -06:00
|
|
|
pub const try_adding: &str = "Try adding a move";
|
2012-10-13 00:15:13 -05:00
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn kind_to_str(k: Kind) -> ~str {
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut kinds = ~[];
|
2012-07-16 22:17:57 -05:00
|
|
|
|
2012-05-24 17:04:59 -05:00
|
|
|
if ty::kind_lteq(kind_const(), k) {
|
2012-09-26 19:33:34 -05:00
|
|
|
kinds.push(~"const");
|
2012-05-22 16:10:32 -05:00
|
|
|
}
|
2012-07-16 22:17:57 -05:00
|
|
|
|
2012-05-24 16:24:09 -05:00
|
|
|
if ty::kind_can_be_copied(k) {
|
2012-09-26 19:33:34 -05:00
|
|
|
kinds.push(~"copy");
|
2012-05-24 16:24:09 -05:00
|
|
|
}
|
2012-07-16 22:17:57 -05:00
|
|
|
|
2012-05-24 16:24:09 -05:00
|
|
|
if ty::kind_can_be_sent(k) {
|
2012-12-11 15:50:04 -06:00
|
|
|
kinds.push(~"owned");
|
2012-12-11 13:59:45 -06:00
|
|
|
} else if ty::kind_is_durable(k) {
|
2013-01-10 13:16:54 -06:00
|
|
|
kinds.push(~"&static");
|
2012-05-24 16:24:09 -05:00
|
|
|
}
|
2012-07-16 22:17:57 -05:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
str::connect(kinds, ~" ")
|
2011-11-15 11:15:35 -06:00
|
|
|
}
|
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub type rval_map = HashMap<node_id, ()>;
|
2011-11-15 11:15:35 -06:00
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub type ctx = {
|
|
|
|
tcx: ty::ctxt,
|
|
|
|
method_map: typeck::method_map,
|
|
|
|
last_use_map: liveness::last_use_map,
|
|
|
|
current_item: node_id
|
|
|
|
};
|
2011-11-15 11:15:35 -06:00
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn check_crate(tcx: ty::ctxt,
|
|
|
|
method_map: typeck::method_map,
|
|
|
|
last_use_map: liveness::last_use_map,
|
|
|
|
crate: @crate) {
|
2011-11-15 11:15:35 -06:00
|
|
|
let ctx = {tcx: tcx,
|
2011-12-14 07:38:25 -06:00
|
|
|
method_map: method_map,
|
2012-05-29 18:22:22 -05:00
|
|
|
last_use_map: last_use_map,
|
|
|
|
current_item: -1};
|
2013-01-08 16:00:45 -06:00
|
|
|
let visit = visit::mk_vt(@visit::Visitor {
|
2012-08-24 14:24:04 -05:00
|
|
|
visit_arm: check_arm,
|
2011-11-15 11:15:35 -06:00
|
|
|
visit_expr: check_expr,
|
2012-03-19 04:45:29 -05:00
|
|
|
visit_fn: check_fn,
|
2012-05-29 18:22:22 -05:00
|
|
|
visit_ty: check_ty,
|
|
|
|
visit_item: fn@(i: @item, cx: ctx, v: visit::vt<ctx>) {
|
2012-09-04 15:29:32 -05:00
|
|
|
visit::visit_item(i, {current_item: i.id,.. cx}, v);
|
|
|
|
},
|
|
|
|
.. *visit::default_visitor()
|
2011-11-15 11:15:35 -06:00
|
|
|
});
|
|
|
|
visit::visit_crate(*crate, ctx, visit);
|
|
|
|
tcx.sess.abort_if_errors();
|
|
|
|
}
|
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
type check_fn = fn@(ctx, @freevar_entry);
|
2012-05-07 13:31:57 -05:00
|
|
|
|
2011-12-20 21:39:33 -06:00
|
|
|
// Yields the appropriate function to check the kind of closed over
|
|
|
|
// variables. `id` is the node_id for some expression that creates the
|
|
|
|
// closure.
|
2013-01-10 12:59:58 -06:00
|
|
|
fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
|
|
|
|
fn check_for_uniq(cx: ctx, fv: @freevar_entry) {
|
2012-05-07 13:31:57 -05:00
|
|
|
// all captured data must be sendable, regardless of whether it is
|
2012-07-16 22:17:57 -05:00
|
|
|
// moved in or copied in. Note that send implies owned.
|
2013-01-10 12:59:58 -06:00
|
|
|
let id = ast_util::def_id_of_def(fv.def).node;
|
|
|
|
let var_t = ty::node_id_to_type(cx.tcx, id);
|
|
|
|
if !check_send(cx, var_t, fv.span) { return; }
|
|
|
|
|
2012-05-07 13:31:57 -05:00
|
|
|
// check that only immutable variables are implicitly copied in
|
2013-01-10 12:59:58 -06:00
|
|
|
check_imm_free_var(cx, fv.def, fv.span);
|
2012-05-07 13:31:57 -05:00
|
|
|
}
|
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
fn check_for_box(cx: ctx, fv: @freevar_entry) {
|
2012-07-16 22:17:57 -05:00
|
|
|
// all captured data must be owned
|
2013-01-10 12:59:58 -06:00
|
|
|
let id = ast_util::def_id_of_def(fv.def).node;
|
|
|
|
let var_t = ty::node_id_to_type(cx.tcx, id);
|
|
|
|
if !check_durable(cx.tcx, var_t, fv.span) { return; }
|
|
|
|
|
2012-05-07 13:31:57 -05:00
|
|
|
// check that only immutable variables are implicitly copied in
|
2013-01-10 12:59:58 -06:00
|
|
|
check_imm_free_var(cx, fv.def, fv.span);
|
2012-05-07 13:31:57 -05:00
|
|
|
}
|
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
fn check_for_block(_cx: ctx, _fv: @freevar_entry) {
|
|
|
|
// no restrictions
|
2012-05-07 13:31:57 -05:00
|
|
|
}
|
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
fn check_for_bare(cx: ctx, fv: @freevar_entry) {
|
|
|
|
cx.tcx.sess.span_err(
|
|
|
|
fv.span,
|
|
|
|
~"attempted dynamic environment capture");
|
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 {
|
|
|
|
ty::ty_closure(ty::ClosureTy {sigil: OwnedSigil, _}) => {
|
|
|
|
b(check_for_uniq)
|
|
|
|
}
|
|
|
|
ty::ty_closure(ty::ClosureTy {sigil: ManagedSigil, _}) => {
|
|
|
|
b(check_for_box)
|
|
|
|
}
|
|
|
|
ty::ty_closure(ty::ClosureTy {sigil: BorrowedSigil, _}) => {
|
|
|
|
b(check_for_block)
|
|
|
|
}
|
|
|
|
ty::ty_bare_fn(_) => {
|
|
|
|
b(check_for_bare)
|
|
|
|
}
|
|
|
|
ref s => {
|
|
|
|
cx.tcx.sess.bug(
|
|
|
|
fmt!("expect fn type in kind checker, not %?", s));
|
|
|
|
}
|
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-01-10 12:59:58 -06:00
|
|
|
fn check_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, sp: span,
|
|
|
|
fn_id: node_id, cx: ctx, v: visit::vt<ctx>) {
|
2012-05-07 13:31:57 -05:00
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
// Check kinds on free variables:
|
|
|
|
do with_appropriate_checker(cx, fn_id) |chk| {
|
2012-09-18 23:41:13 -05:00
|
|
|
for vec::each(*freevars::get_freevars(cx.tcx, fn_id)) |fv| {
|
2013-01-10 12:59:58 -06:00
|
|
|
chk(cx, *fv);
|
2011-12-09 18:56:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-29 11:53:30 -06:00
|
|
|
visit::visit_fn(fk, decl, body, sp, fn_id, cx, v);
|
2011-12-20 21:39:33 -06:00
|
|
|
}
|
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
fn check_arm(a: arm, cx: ctx, v: visit::vt<ctx>) {
|
2012-09-18 23:41:13 -05:00
|
|
|
for vec::each(a.pats) |p| {
|
2012-09-18 23:41:37 -05:00
|
|
|
do pat_util::pat_bindings(cx.tcx.def_map, *p) |mode, id, span, _pth| {
|
2013-01-10 12:59:58 -06:00
|
|
|
if mode == bind_by_copy {
|
2012-08-24 14:24:04 -05:00
|
|
|
let t = ty::node_id_to_type(cx.tcx, id);
|
|
|
|
let reason = "consider binding with `ref` or `move` instead";
|
2013-01-10 12:59:58 -06:00
|
|
|
check_copy(cx, t, span, reason);
|
2012-08-24 14:24:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
visit::visit_arm(a, cx, v);
|
|
|
|
}
|
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
2012-08-22 19:24:52 -05:00
|
|
|
debug!("kind::check_expr(%s)", expr_to_str(e, cx.tcx.sess.intr()));
|
2013-01-10 12:59:58 -06:00
|
|
|
|
|
|
|
// Handle any kind bounds on type parameters
|
|
|
|
let type_parameter_id = match e.node {
|
2012-09-06 17:42:59 -05:00
|
|
|
expr_index(*)|expr_assign_op(*)|
|
2012-12-03 17:28:51 -06:00
|
|
|
expr_unary(*)|expr_binary(*)|expr_method_call(*) => e.callee_id,
|
2012-09-06 17:42:59 -05:00
|
|
|
_ => e.id
|
|
|
|
};
|
2013-02-05 21:41:45 -06:00
|
|
|
do option::iter(&cx.tcx.node_type_substs.find(&type_parameter_id)) |ts| {
|
2012-08-21 19:22:45 -05:00
|
|
|
let bounds = match e.node {
|
2012-08-16 18:44:22 -05:00
|
|
|
expr_path(_) => {
|
2013-02-05 21:41:45 -06:00
|
|
|
let did = ast_util::def_id_of_def(cx.tcx.def_map.get(&e.id));
|
2012-08-16 18:44:22 -05:00
|
|
|
ty::lookup_item_type(cx.tcx, did).bounds
|
|
|
|
}
|
|
|
|
_ => {
|
2012-09-06 17:42:59 -05:00
|
|
|
// Type substitutions should only occur on paths and
|
2012-08-16 18:44:22 -05:00
|
|
|
// method calls, so this needs to be a method call.
|
2012-09-06 17:42:59 -05:00
|
|
|
|
|
|
|
// Even though the callee_id may have been the id with
|
|
|
|
// node_type_substs, e.id is correct here.
|
2012-08-20 15:36:15 -05:00
|
|
|
ty::method_call_bounds(cx.tcx, cx.method_map, e.id).expect(
|
|
|
|
~"non path/method call expr has type substs??")
|
2012-08-16 18:44:22 -05:00
|
|
|
}
|
|
|
|
};
|
2012-09-27 19:01:28 -05:00
|
|
|
if vec::len(*ts) != vec::len(*bounds) {
|
2012-08-16 18:44:22 -05:00
|
|
|
// Fail earlier to make debugging easier
|
2013-01-31 19:51:01 -06:00
|
|
|
die!(fmt!("internal error: in kind::check_expr, length \
|
2012-08-16 18:44:22 -05:00
|
|
|
mismatch between actual and declared bounds: actual = \
|
|
|
|
%s (%u tys), declared = %? (%u tys)",
|
2012-09-27 19:01:28 -05:00
|
|
|
tys_to_str(cx.tcx, *ts), ts.len(),
|
2013-01-31 19:51:01 -06:00
|
|
|
*bounds, (*bounds).len()));
|
2012-08-16 18:44:22 -05:00
|
|
|
}
|
2012-09-28 17:48:25 -05:00
|
|
|
for vec::each2(*ts, *bounds) |ty, bound| {
|
2013-01-10 12:59:58 -06:00
|
|
|
check_bounds(cx, type_parameter_id, e.span, *ty, *bound)
|
2012-08-16 18:44:22 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
match e.node {
|
|
|
|
expr_cast(source, _) => {
|
|
|
|
check_cast_for_escaping_regions(cx, source, e);
|
|
|
|
check_kind_bounds_of_cast(cx, source, e);
|
2011-11-22 06:27:40 -06:00
|
|
|
}
|
2013-01-10 12:59:58 -06:00
|
|
|
expr_copy(expr) => {
|
|
|
|
// Note: This is the only place where we must check whether the
|
|
|
|
// argument is copyable. This is not because this is the only
|
|
|
|
// kind of expression that may copy things, but rather because all
|
|
|
|
// other copies will have been converted to moves by by the
|
|
|
|
// `moves` pass if the value is not copyable.
|
|
|
|
check_copy(cx,
|
|
|
|
ty::expr_ty(cx.tcx, expr),
|
|
|
|
expr.span,
|
|
|
|
"explicit copy requires a copyable argument");
|
2011-11-18 03:20:51 -06:00
|
|
|
}
|
2013-01-10 12:59:58 -06:00
|
|
|
expr_repeat(element, count_expr, _) => {
|
|
|
|
let count = ty::eval_repeat_count(cx.tcx, count_expr, e.span);
|
|
|
|
if count > 1 {
|
|
|
|
let element_ty = ty::expr_ty(cx.tcx, element);
|
|
|
|
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-01-10 12:59:58 -06:00
|
|
|
visit::visit_expr(e, cx, v);
|
2011-11-15 11:15:35 -06:00
|
|
|
}
|
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
fn check_ty(aty: @Ty, cx: ctx, v: visit::vt<ctx>) {
|
2012-08-06 14:34:08 -05:00
|
|
|
match aty.node {
|
2012-08-03 21:59:04 -05:00
|
|
|
ty_path(_, id) => {
|
2013-02-05 21:41:45 -06:00
|
|
|
do option::iter(&cx.tcx.node_type_substs.find(&id)) |ts| {
|
|
|
|
let did = ast_util::def_id_of_def(cx.tcx.def_map.get(&id));
|
2012-03-19 04:45:29 -05:00
|
|
|
let bounds = ty::lookup_item_type(cx.tcx, did).bounds;
|
2012-09-28 17:48:25 -05:00
|
|
|
for vec::each2(*ts, *bounds) |ty, bound| {
|
2012-09-28 00:20:47 -05:00
|
|
|
check_bounds(cx, aty.id, aty.span, *ty, *bound)
|
2012-03-19 04:45:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => {}
|
2012-03-19 04:45:29 -05:00
|
|
|
}
|
|
|
|
visit::visit_ty(aty, cx, v);
|
|
|
|
}
|
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn check_bounds(cx: ctx, id: node_id, sp: span,
|
|
|
|
ty: ty::t, bounds: ty::param_bounds) {
|
2012-03-19 04:45:29 -05:00
|
|
|
let kind = ty::type_kind(cx.tcx, ty);
|
|
|
|
let p_kind = ty::param_bounds_to_kind(bounds);
|
|
|
|
if !ty::kind_lteq(p_kind, kind) {
|
2012-05-29 18:22:22 -05:00
|
|
|
// If the only reason the kind check fails is because the
|
|
|
|
// argument type isn't implicitly copyable, consult the warning
|
|
|
|
// settings to figure out what to do.
|
|
|
|
let implicit = ty::kind_implicitly_copyable() - ty::kind_copyable();
|
|
|
|
if ty::kind_lteq(p_kind, kind | implicit) {
|
|
|
|
cx.tcx.sess.span_lint(
|
|
|
|
non_implicitly_copyable_typarams,
|
|
|
|
id, cx.current_item, sp,
|
2012-07-14 00:57:48 -05:00
|
|
|
~"instantiating copy type parameter with a \
|
2012-05-29 18:22:22 -05:00
|
|
|
not implicitly copyable type");
|
|
|
|
} else {
|
|
|
|
cx.tcx.sess.span_err(
|
|
|
|
sp,
|
2012-07-14 00:57:48 -05:00
|
|
|
~"instantiating a type parameter with an incompatible type " +
|
|
|
|
~"(needs `" + kind_to_str(p_kind) +
|
|
|
|
~"`, got `" + kind_to_str(kind) +
|
|
|
|
~"`, missing `" + kind_to_str(p_kind - kind) + ~"`)");
|
2012-05-29 18:22:22 -05:00
|
|
|
}
|
2012-03-19 04:45:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
fn is_nullary_variant(cx: ctx, ex: @expr) -> bool {
|
2012-08-06 14:34:08 -05:00
|
|
|
match ex.node {
|
2012-08-03 21:59:04 -05:00
|
|
|
expr_path(_) => {
|
2013-02-05 21:41:45 -06:00
|
|
|
match cx.tcx.def_map.get(&ex.id) {
|
2012-08-03 21:59:04 -05:00
|
|
|
def_variant(edid, vdid) => {
|
2012-01-31 05:34:22 -06:00
|
|
|
vec::len(ty::enum_variant_with_id(cx.tcx, edid, vdid).args) == 0u
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => false
|
2012-01-31 05:34:22 -06:00
|
|
|
}
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => false
|
2012-01-31 05:34:22 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
fn check_imm_free_var(cx: ctx, def: def, sp: span) {
|
|
|
|
match def {
|
|
|
|
def_local(_, is_mutbl) => {
|
|
|
|
if is_mutbl {
|
|
|
|
cx.tcx.sess.span_err(
|
|
|
|
sp,
|
|
|
|
~"mutable variables cannot be implicitly captured");
|
2012-12-04 17:38:04 -06:00
|
|
|
}
|
|
|
|
}
|
2013-01-10 12:59:58 -06:00
|
|
|
def_arg(*) => { /* ok */ }
|
|
|
|
def_upvar(_, def1, _, _) => { check_imm_free_var(cx, *def1, sp); }
|
|
|
|
def_binding(*) | def_self(*) => { /*ok*/ }
|
|
|
|
_ => {
|
|
|
|
cx.tcx.sess.span_bug(
|
|
|
|
sp,
|
|
|
|
fmt!("unknown def for free variable: %?", def));
|
2012-05-07 13:31:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-10 12:59:58 -06:00
|
|
|
fn check_copy(cx: ctx, ty: ty::t, sp: span, reason: &str) {
|
2012-05-23 20:57:56 -05:00
|
|
|
let k = ty::type_kind(cx.tcx, ty);
|
|
|
|
if !ty::kind_can_be_copied(k) {
|
2012-07-14 00:57:48 -05:00
|
|
|
cx.tcx.sess.span_err(sp, ~"copying a noncopyable value");
|
2013-01-10 12:59:58 -06:00
|
|
|
cx.tcx.sess.span_note(sp, fmt!("%s", reason));
|
2011-11-15 11:15:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn check_send(cx: ctx, ty: ty::t, sp: span) -> bool {
|
2011-12-28 11:11:33 -06:00
|
|
|
if !ty::kind_can_be_sent(ty::type_kind(cx.tcx, ty)) {
|
2012-07-14 00:57:48 -05:00
|
|
|
cx.tcx.sess.span_err(sp, ~"not a sendable value");
|
2012-07-16 22:17:57 -05:00
|
|
|
false
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-18 13:01:54 -05:00
|
|
|
// note: also used from middle::typeck::regionck!
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool {
|
2012-12-11 13:59:45 -06:00
|
|
|
if !ty::kind_is_durable(ty::type_kind(tcx, ty)) {
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(ty).sty {
|
2012-08-03 21:59:04 -05:00
|
|
|
ty::ty_param(*) => {
|
2012-07-18 13:01:54 -05:00
|
|
|
tcx.sess.span_err(sp, ~"value may contain borrowed \
|
2013-01-10 13:16:54 -06:00
|
|
|
pointers; use `&static` bound");
|
2012-07-18 13:01:54 -05:00
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => {
|
2012-07-18 13:01:54 -05:00
|
|
|
tcx.sess.span_err(sp, ~"value may contain borrowed \
|
|
|
|
pointers");
|
|
|
|
}
|
|
|
|
}
|
2012-07-16 22:17:57 -05:00
|
|
|
false
|
|
|
|
} else {
|
|
|
|
true
|
2011-12-09 18:56:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-18 13:01:54 -05:00
|
|
|
/// This is rather subtle. When we are casting a value to a
|
2012-07-30 16:51:21 -05:00
|
|
|
/// instantiated trait like `a as trait/&r`, regionck already ensures
|
2012-07-18 13:01:54 -05:00
|
|
|
/// that any borrowed pointers that appear in the type of `a` are
|
|
|
|
/// bounded by `&r`. However, it is possible that there are *type
|
|
|
|
/// parameters* in the type of `a`, and those *type parameters* may
|
|
|
|
/// have borrowed pointers within them. We have to guarantee that the
|
|
|
|
/// regions which appear in those type parameters are not obscured.
|
|
|
|
///
|
|
|
|
/// 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
|
|
|
|
/// itself. This case is safe because whatever borrowed pointers are
|
|
|
|
/// 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
|
2012-07-18 13:01:54 -05:00
|
|
|
/// `deque<T>`, then whatever borrowed ptrs may appear in `T` also
|
|
|
|
/// appear in `deque<T>`.
|
|
|
|
///
|
|
|
|
/// (3) The type parameter is owned (and therefore does not contain
|
|
|
|
/// borrowed ptrs).
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn check_cast_for_escaping_regions(
|
2012-07-18 13:01:54 -05:00
|
|
|
cx: ctx,
|
|
|
|
source: @expr,
|
|
|
|
target: @expr) {
|
|
|
|
|
2012-07-30 16:51:21 -05:00
|
|
|
// Determine what type we are casting to; if it is not an trait, then no
|
2012-07-18 13:01:54 -05:00
|
|
|
// worries.
|
|
|
|
let target_ty = ty::expr_ty(cx.tcx, target);
|
2012-09-11 18:20:31 -05:00
|
|
|
let target_substs = match ty::get(target_ty).sty {
|
2013-01-07 16:16:52 -06:00
|
|
|
ty::ty_trait(_, ref substs, _) => {(/*bad*/copy *substs)}
|
2012-08-01 19:30:05 -05:00
|
|
|
_ => { return; /* not a cast to a trait */ }
|
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
|
|
|
|
// must have been declared on the enclosing fn item):
|
2012-08-06 14:34:08 -05:00
|
|
|
match target_substs.self_r {
|
2012-08-20 14:23:37 -05:00
|
|
|
Some(ty::re_scope(*)) => { return; /* case (1) */ }
|
|
|
|
None | Some(ty::re_static) | Some(ty::re_free(*)) => {}
|
2012-10-19 08:01:01 -05:00
|
|
|
Some(ty::re_bound(*)) | Some(ty::re_infer(*)) => {
|
2012-07-18 13:01:54 -05:00
|
|
|
cx.tcx.sess.span_bug(
|
|
|
|
source.span,
|
2012-08-22 19:24:52 -05:00
|
|
|
fmt!("bad region found in kind: %?", target_substs.self_r));
|
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
|
|
|
|
// either appears in the trait type or is owned:
|
2012-07-18 13:01:54 -05:00
|
|
|
let target_params = ty::param_tys_in_type(target_ty);
|
|
|
|
let source_ty = ty::expr_ty(cx.tcx, source);
|
|
|
|
do ty::walk_ty(source_ty) |ty| {
|
2012-09-11 18:20:31 -05:00
|
|
|
match ty::get(ty).sty {
|
2012-07-18 13:01:54 -05:00
|
|
|
ty::ty_param(source_param) => {
|
2012-09-25 19:39:22 -05:00
|
|
|
if target_params.contains(&source_param) {
|
2012-07-18 13:01:54 -05:00
|
|
|
/* case (2) */
|
|
|
|
} else {
|
2012-12-11 13:59:45 -06:00
|
|
|
check_durable(cx.tcx, ty, source.span); /* case (3) */
|
2012-07-18 13:01:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-31 17:09:26 -05:00
|
|
|
/// Ensures that values placed into a ~Trait are copyable and sendable.
|
2013-01-30 15:44:24 -06:00
|
|
|
pub fn check_kind_bounds_of_cast(cx: ctx, source: @expr, target: @expr) {
|
2012-10-31 17:09:26 -05:00
|
|
|
let target_ty = ty::expr_ty(cx.tcx, target);
|
|
|
|
match ty::get(target_ty).sty {
|
|
|
|
ty::ty_trait(_, _, ty::vstore_uniq) => {
|
|
|
|
let source_ty = ty::expr_ty(cx.tcx, source);
|
|
|
|
let source_kind = ty::type_kind(cx.tcx, source_ty);
|
|
|
|
if !ty::kind_can_be_copied(source_kind) {
|
|
|
|
cx.tcx.sess.span_err(target.span,
|
|
|
|
~"uniquely-owned trait objects must be copyable");
|
|
|
|
}
|
|
|
|
if !ty::kind_can_be_sent(source_kind) {
|
|
|
|
cx.tcx.sess.span_err(target.span,
|
|
|
|
~"uniquely-owned trait objects must be sendable");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {} // Nothing to do.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-27 19:49:00 -05:00
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// End:
|
|
|
|
//
|