auto merge of #20432 : nikomatsakis/rust/fn-inference-2, r=eddyb
Previously, the borrow mode of each upvar was inferred as part of regionck. This PR moves it into its own separate step. It also employs the `ExprUseVisitor`, further simplifying the code. The eventual goal is to support better inference of `Fn` vs `FnMut` vs `FnOnce` that is not based on the expected type, as well as supporting individual by-move upvars. r? @eddyb
This commit is contained in:
commit
fe7e285d0c
35 changed files with 1063 additions and 856 deletions
|
@ -1612,15 +1612,11 @@ impl LintPass for MissingCopyImplementations {
|
|||
}
|
||||
_ => return,
|
||||
};
|
||||
let parameter_environment = ty::empty_parameter_environment();
|
||||
if !ty::type_moves_by_default(cx.tcx,
|
||||
ty,
|
||||
¶meter_environment) {
|
||||
let parameter_environment = ty::empty_parameter_environment(cx.tcx);
|
||||
if !ty::type_moves_by_default(¶meter_environment, item.span, ty) {
|
||||
return
|
||||
}
|
||||
if ty::can_type_implement_copy(cx.tcx,
|
||||
ty,
|
||||
¶meter_environment).is_ok() {
|
||||
if ty::can_type_implement_copy(¶meter_environment, item.span, ty).is_ok() {
|
||||
cx.span_lint(MISSING_COPY_IMPLEMENTATIONS,
|
||||
item.span,
|
||||
"type could implement `Copy`; consider adding `impl \
|
||||
|
|
|
@ -99,7 +99,7 @@ impl<'a> FromIterator<Vec<&'a Pat>> for Matrix<'a> {
|
|||
|
||||
pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
|
||||
pub tcx: &'a ty::ctxt<'tcx>,
|
||||
pub param_env: ParameterEnvironment<'tcx>,
|
||||
pub param_env: ParameterEnvironment<'a, 'tcx>,
|
||||
}
|
||||
|
||||
#[deriving(Clone, PartialEq)]
|
||||
|
@ -148,7 +148,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchCheckCtxt<'a, 'tcx> {
|
|||
pub fn check_crate(tcx: &ty::ctxt) {
|
||||
visit::walk_crate(&mut MatchCheckCtxt {
|
||||
tcx: tcx,
|
||||
param_env: ty::empty_parameter_environment(),
|
||||
param_env: ty::empty_parameter_environment(tcx),
|
||||
}, tcx.map.krate());
|
||||
tcx.sess.abort_if_errors();
|
||||
}
|
||||
|
@ -1032,9 +1032,7 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
|
|||
match p.node {
|
||||
ast::PatIdent(ast::BindByValue(_), _, ref sub) => {
|
||||
let pat_ty = ty::node_id_to_type(tcx, p.id);
|
||||
if ty::type_moves_by_default(tcx,
|
||||
pat_ty,
|
||||
&cx.param_env) {
|
||||
if ty::type_moves_by_default(&cx.param_env, pat.span, pat_ty) {
|
||||
check_move(p, sub.as_ref().map(|p| &**p));
|
||||
}
|
||||
}
|
||||
|
@ -1063,8 +1061,7 @@ fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>,
|
|||
cx: cx,
|
||||
};
|
||||
let mut visitor = ExprUseVisitor::new(&mut checker,
|
||||
checker.cx.tcx,
|
||||
&cx.param_env);
|
||||
&checker.cx.param_env);
|
||||
visitor.walk_expr(guard);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> {
|
|||
{
|
||||
let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
|
||||
let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: ¶m_env };
|
||||
let mut euv = euv::ExprUseVisitor::new(&mut delegate, self.tcx, ¶m_env);
|
||||
let mut euv = euv::ExprUseVisitor::new(&mut delegate, ¶m_env);
|
||||
euv.walk_fn(fd, b);
|
||||
}
|
||||
visit::walk_fn(self, fk, fd, b, s)
|
||||
|
@ -50,7 +50,7 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> {
|
|||
|
||||
struct RvalueContextDelegate<'a, 'tcx: 'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
param_env: &'a ty::ParameterEnvironment<'tcx>,
|
||||
param_env: &'a ty::ParameterEnvironment<'a,'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
|
||||
|
@ -60,7 +60,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
|
|||
cmt: mc::cmt<'tcx>,
|
||||
_: euv::ConsumeMode) {
|
||||
debug!("consume; cmt: {}; type: {}", *cmt, ty_to_string(self.tcx, cmt.ty));
|
||||
if !ty::type_is_sized(self.tcx, cmt.ty, self.param_env) {
|
||||
if !ty::type_is_sized(self.param_env, span, cmt.ty) {
|
||||
span_err!(self.tcx.sess, span, E0161,
|
||||
"cannot move a value of type {0}: the size of {0} cannot be statically determined",
|
||||
ty_to_string(self.tcx, cmt.ty));
|
||||
|
|
|
@ -54,7 +54,7 @@ struct CheckStaticVisitor<'a, 'tcx: 'a> {
|
|||
}
|
||||
|
||||
struct GlobalVisitor<'a,'b,'tcx:'a+'b>(
|
||||
euv::ExprUseVisitor<'a,'b,'tcx,ty::ctxt<'tcx>>);
|
||||
euv::ExprUseVisitor<'a,'b,'tcx,ty::ParameterEnvironment<'b,'tcx>>);
|
||||
struct GlobalChecker {
|
||||
static_consumptions: NodeSet,
|
||||
const_borrows: NodeSet,
|
||||
|
@ -70,8 +70,8 @@ pub fn check_crate(tcx: &ty::ctxt) {
|
|||
static_local_borrows: NodeSet::new(),
|
||||
};
|
||||
{
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let visitor = euv::ExprUseVisitor::new(&mut checker, tcx, ¶m_env);
|
||||
let param_env = ty::empty_parameter_environment(tcx);
|
||||
let visitor = euv::ExprUseVisitor::new(&mut checker, ¶m_env);
|
||||
visit::walk_crate(&mut GlobalVisitor(visitor), tcx.map.krate());
|
||||
}
|
||||
visit::walk_crate(&mut CheckStaticVisitor {
|
||||
|
@ -121,8 +121,8 @@ impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> {
|
|||
let mut fulfill_cx = traits::FulfillmentContext::new();
|
||||
let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
|
||||
fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
|
||||
let env = ty::empty_parameter_environment();
|
||||
match fulfill_cx.select_all_or_error(&infcx, &env, self.tcx) {
|
||||
let env = ty::empty_parameter_environment(self.tcx);
|
||||
match fulfill_cx.select_all_or_error(&infcx, &env) {
|
||||
Ok(()) => { },
|
||||
Err(ref errors) => {
|
||||
traits::report_fulfillment_errors(&infcx, errors);
|
||||
|
|
|
@ -126,6 +126,12 @@ impl TraitItemKind {
|
|||
}
|
||||
|
||||
impl Def {
|
||||
pub fn local_node_id(&self) -> ast::NodeId {
|
||||
let def_id = self.def_id();
|
||||
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
|
||||
def_id.node
|
||||
}
|
||||
|
||||
pub fn def_id(&self) -> ast::DefId {
|
||||
match *self {
|
||||
DefFn(id, _) | DefStaticMethod(id, _) | DefMod(id) |
|
||||
|
|
|
@ -23,7 +23,7 @@ use self::OverloadedCallType::*;
|
|||
use middle::{def, region, pat_util};
|
||||
use middle::mem_categorization as mc;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::ty::{mod, ParameterEnvironment, Ty};
|
||||
use middle::ty::{mod};
|
||||
use middle::ty::{MethodCall, MethodObject, MethodTraitObject};
|
||||
use middle::ty::{MethodOrigin, MethodParam, MethodTypeParam};
|
||||
use middle::ty::{MethodStatic, MethodStaticUnboxedClosure};
|
||||
|
@ -299,7 +299,22 @@ pub struct ExprUseVisitor<'d,'t,'tcx:'t,TYPER:'t> {
|
|||
typer: &'t TYPER,
|
||||
mc: mc::MemCategorizationContext<'t,TYPER>,
|
||||
delegate: &'d mut (Delegate<'tcx>+'d),
|
||||
param_env: &'t ParameterEnvironment<'tcx>,
|
||||
}
|
||||
|
||||
// If the TYPER results in an error, it's because the type check
|
||||
// failed (or will fail, when the error is uncovered and reported
|
||||
// during writeback). In this case, we just ignore this part of the
|
||||
// code.
|
||||
//
|
||||
// Note that this macro appears similar to try!(), but, unlike try!(),
|
||||
// it does not propagate the error.
|
||||
macro_rules! return_if_err {
|
||||
($inp: expr) => (
|
||||
match $inp {
|
||||
Ok(v) => v,
|
||||
Err(()) => return
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Whether the elements of an overloaded operation are passed by value or by reference
|
||||
|
@ -310,14 +325,12 @@ enum PassArgs {
|
|||
|
||||
impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
||||
pub fn new(delegate: &'d mut Delegate<'tcx>,
|
||||
typer: &'t TYPER,
|
||||
param_env: &'t ParameterEnvironment<'tcx>)
|
||||
typer: &'t TYPER)
|
||||
-> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
||||
ExprUseVisitor {
|
||||
typer: typer,
|
||||
mc: mc::MemCategorizationContext::new(typer),
|
||||
delegate: delegate,
|
||||
param_env: param_env,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,7 +345,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
decl: &ast::FnDecl,
|
||||
body: &ast::Block) {
|
||||
for arg in decl.inputs.iter() {
|
||||
let arg_ty = self.typer.node_ty(arg.pat.id);
|
||||
let arg_ty = return_if_err!(self.typer.node_ty(arg.pat.id));
|
||||
|
||||
let fn_body_scope = region::CodeExtent::from_node_id(body.id);
|
||||
let arg_cmt = self.mc.cat_rvalue(
|
||||
|
@ -353,10 +366,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
consume_id: ast::NodeId,
|
||||
consume_span: Span,
|
||||
cmt: mc::cmt<'tcx>) {
|
||||
let mode = copy_or_move(self.tcx(),
|
||||
cmt.ty,
|
||||
self.param_env,
|
||||
DirectRefMove);
|
||||
let mode = copy_or_move(self.typer, &cmt, DirectRefMove);
|
||||
self.delegate.consume(consume_id, consume_span, cmt, mode);
|
||||
}
|
||||
|
||||
|
@ -369,7 +379,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
pub fn consume_expr(&mut self, expr: &ast::Expr) {
|
||||
debug!("consume_expr(expr={})", expr.repr(self.tcx()));
|
||||
|
||||
let cmt = self.mc.cat_expr(expr);
|
||||
let cmt = return_if_err!(self.mc.cat_expr(expr));
|
||||
self.delegate_consume(expr.id, expr.span, cmt);
|
||||
self.walk_expr(expr);
|
||||
}
|
||||
|
@ -378,7 +388,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
assignment_expr: &ast::Expr,
|
||||
expr: &ast::Expr,
|
||||
mode: MutateMode) {
|
||||
let cmt = self.mc.cat_expr(expr);
|
||||
let cmt = return_if_err!(self.mc.cat_expr(expr));
|
||||
self.delegate.mutate(assignment_expr.id, assignment_expr.span, cmt, mode);
|
||||
self.walk_expr(expr);
|
||||
}
|
||||
|
@ -391,7 +401,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
debug!("borrow_expr(expr={}, r={}, bk={})",
|
||||
expr.repr(self.tcx()), r.repr(self.tcx()), bk.repr(self.tcx()));
|
||||
|
||||
let cmt = self.mc.cat_expr(expr);
|
||||
let cmt = return_if_err!(self.mc.cat_expr(expr));
|
||||
self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause);
|
||||
|
||||
// Note: Unlike consume, we can ignore ExprParen. cat_expr
|
||||
|
@ -491,7 +501,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
}
|
||||
|
||||
ast::ExprMatch(ref discr, ref arms, _) => {
|
||||
let discr_cmt = self.mc.cat_expr(&**discr);
|
||||
let discr_cmt = return_if_err!(self.mc.cat_expr(&**discr));
|
||||
self.borrow_expr(&**discr, ty::ReEmpty, ty::ImmBorrow, MatchDiscriminant);
|
||||
|
||||
// treatment of the discriminant is handled while walking the arms.
|
||||
|
@ -509,7 +519,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
ast::ExprAddrOf(m, ref base) => { // &base
|
||||
// make sure that the thing we are pointing out stays valid
|
||||
// for the lifetime `scope_r` of the resulting ptr:
|
||||
let expr_ty = ty::expr_ty(self.tcx(), expr);
|
||||
let expr_ty = return_if_err!(self.typer.node_ty(expr.id));
|
||||
let r = ty::ty_region(self.tcx(), expr.span, expr_ty);
|
||||
let bk = ty::BorrowKind::from_mutbl(m);
|
||||
self.borrow_expr(&**base, r, bk, AddrOf);
|
||||
|
@ -550,7 +560,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
|
||||
// Fetch the type of the value that the iteration yields to
|
||||
// produce the pattern's categorized mutable type.
|
||||
let pattern_type = self.typer.node_ty(pat.id);
|
||||
let pattern_type = return_if_err!(self.typer.node_ty(pat.id));
|
||||
let blk_scope = region::CodeExtent::from_node_id(blk.id);
|
||||
let pat_cmt = self.mc.cat_rvalue(pat.id,
|
||||
pat.span,
|
||||
|
@ -638,7 +648,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
}
|
||||
|
||||
fn walk_callee(&mut self, call: &ast::Expr, callee: &ast::Expr) {
|
||||
let callee_ty = self.typer.expr_ty_adjusted(callee);
|
||||
let callee_ty = return_if_err!(self.typer.expr_ty_adjusted(callee));
|
||||
debug!("walk_callee: callee={} callee_ty={}",
|
||||
callee.repr(self.tcx()), callee_ty.repr(self.tcx()));
|
||||
let call_scope = region::CodeExtent::from_node_id(call.id);
|
||||
|
@ -659,6 +669,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
}
|
||||
}
|
||||
}
|
||||
ty::ty_err => { }
|
||||
_ => {
|
||||
let overloaded_call_type =
|
||||
match self.typer.node_method_origin(MethodCall::expr(call.id)) {
|
||||
|
@ -735,7 +746,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
// "assigns", which is handled by
|
||||
// `walk_pat`:
|
||||
self.walk_expr(&**expr);
|
||||
let init_cmt = self.mc.cat_expr(&**expr);
|
||||
let init_cmt = return_if_err!(self.mc.cat_expr(&**expr));
|
||||
self.walk_irrefutable_pat(init_cmt, &*local.pat);
|
||||
}
|
||||
}
|
||||
|
@ -769,7 +780,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
None => { return; }
|
||||
};
|
||||
|
||||
let with_cmt = self.mc.cat_expr(&*with_expr);
|
||||
let with_cmt = return_if_err!(self.mc.cat_expr(&*with_expr));
|
||||
|
||||
// Select just those fields of the `with`
|
||||
// expression that will actually be used
|
||||
|
@ -778,9 +789,17 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
ty::struct_fields(self.tcx(), did, substs)
|
||||
}
|
||||
_ => {
|
||||
self.tcx().sess.span_bug(
|
||||
with_expr.span,
|
||||
"with expression doesn't evaluate to a struct");
|
||||
// the base expression should always evaluate to a
|
||||
// struct; however, when EUV is run during typeck, it
|
||||
// may not. This will generate an error earlier in typeck,
|
||||
// so we can just ignore it.
|
||||
if !self.tcx().sess.has_errors() {
|
||||
self.tcx().sess.span_bug(
|
||||
with_expr.span,
|
||||
"with expression doesn't evaluate to a struct");
|
||||
}
|
||||
assert!(self.tcx().sess.has_errors());
|
||||
vec!()
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -824,7 +843,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
// rvalue.
|
||||
debug!("walk_adjustment(AutoAddEnv|AdjustReifyFnPointer)");
|
||||
let cmt_unadjusted =
|
||||
self.mc.cat_expr_unadjusted(expr);
|
||||
return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
||||
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
||||
}
|
||||
ty::AdjustDerefRef(ty::AutoDerefRef {
|
||||
|
@ -858,7 +877,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
match self.typer.node_method_ty(deref_id) {
|
||||
None => {}
|
||||
Some(method_ty) => {
|
||||
let cmt = self.mc.cat_expr_autoderefd(expr, i);
|
||||
let cmt = return_if_err!(self.mc.cat_expr_autoderefd(expr, i));
|
||||
let self_ty = ty::ty_fn_args(method_ty)[0];
|
||||
let (m, r) = match self_ty.sty {
|
||||
ty::ty_rptr(r, ref m) => (m.mutbl, r),
|
||||
|
@ -888,14 +907,15 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
assert!(n == 1, format!("Expected exactly 1 deref with Uniq \
|
||||
AutoRefs, found: {}", n));
|
||||
let cmt_unadjusted =
|
||||
self.mc.cat_expr_unadjusted(expr);
|
||||
return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
||||
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let cmt_derefd = self.mc.cat_expr_autoderefd(expr, n);
|
||||
let cmt_derefd = return_if_err!(
|
||||
self.mc.cat_expr_autoderefd(expr, n));
|
||||
debug!("walk_adjustment: cmt_derefd={}",
|
||||
cmt_derefd.repr(self.tcx()));
|
||||
|
||||
|
@ -988,18 +1008,15 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
mode: &mut TrackMatchMode<Span>) {
|
||||
debug!("determine_pat_move_mode cmt_discr={} pat={}", cmt_discr.repr(self.tcx()),
|
||||
pat.repr(self.tcx()));
|
||||
self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
|
||||
let tcx = self.typer.tcx();
|
||||
let def_map = &self.typer.tcx().def_map;
|
||||
return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
|
||||
let tcx = self.tcx();
|
||||
let def_map = &self.tcx().def_map;
|
||||
if pat_util::pat_is_binding(def_map, pat) {
|
||||
match pat.node {
|
||||
ast::PatIdent(ast::BindByRef(_), _, _) =>
|
||||
mode.lub(BorrowingMatch),
|
||||
ast::PatIdent(ast::BindByValue(_), _, _) => {
|
||||
match copy_or_move(tcx,
|
||||
cmt_pat.ty,
|
||||
self.param_env,
|
||||
PatBindingMove) {
|
||||
match copy_or_move(self.typer, &cmt_pat, PatBindingMove) {
|
||||
Copy => mode.lub(CopyingMatch),
|
||||
Move(_) => mode.lub(MovingMatch),
|
||||
}
|
||||
|
@ -1011,7 +1028,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
/// The core driver for walking a pattern; `match_mode` must be
|
||||
|
@ -1026,10 +1043,9 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
|
||||
let mc = &self.mc;
|
||||
let typer = self.typer;
|
||||
let def_map = &self.typer.tcx().def_map;
|
||||
let def_map = &self.tcx().def_map;
|
||||
let delegate = &mut self.delegate;
|
||||
let param_env = self.param_env;
|
||||
mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
|
||||
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
|
||||
if pat_util::pat_is_binding(def_map, pat) {
|
||||
let tcx = typer.tcx();
|
||||
|
||||
|
@ -1039,13 +1055,17 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
match_mode);
|
||||
|
||||
// pat_ty: the type of the binding being produced.
|
||||
let pat_ty = typer.node_ty(pat.id);
|
||||
let pat_ty = return_if_err!(typer.node_ty(pat.id));
|
||||
|
||||
// Each match binding is effectively an assignment to the
|
||||
// binding being produced.
|
||||
let def = def_map.borrow()[pat.id].clone();
|
||||
let binding_cmt = mc.cat_def(pat.id, pat.span, pat_ty, def);
|
||||
delegate.mutate(pat.id, pat.span, binding_cmt, Init);
|
||||
match mc.cat_def(pat.id, pat.span, pat_ty, def) {
|
||||
Ok(binding_cmt) => {
|
||||
delegate.mutate(pat.id, pat.span, binding_cmt, Init);
|
||||
}
|
||||
Err(_) => { }
|
||||
}
|
||||
|
||||
// It is also a borrow or copy/move of the value being matched.
|
||||
match pat.node {
|
||||
|
@ -1058,15 +1078,12 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
r, bk, RefBinding);
|
||||
}
|
||||
ast::PatIdent(ast::BindByValue(_), _, _) => {
|
||||
let mode = copy_or_move(typer.tcx(),
|
||||
cmt_pat.ty,
|
||||
param_env,
|
||||
PatBindingMove);
|
||||
let mode = copy_or_move(typer, &cmt_pat, PatBindingMove);
|
||||
debug!("walk_pat binding consuming pat");
|
||||
delegate.consume_pat(pat, cmt_pat, mode);
|
||||
}
|
||||
_ => {
|
||||
typer.tcx().sess.span_bug(
|
||||
tcx.sess.span_bug(
|
||||
pat.span,
|
||||
"binding pattern not an identifier");
|
||||
}
|
||||
|
@ -1080,7 +1097,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
// matched.
|
||||
|
||||
let (slice_cmt, slice_mutbl, slice_r) =
|
||||
mc.cat_slice_pattern(cmt_pat, &**slice_pat);
|
||||
return_if_err!(mc.cat_slice_pattern(cmt_pat, &**slice_pat));
|
||||
|
||||
// Note: We declare here that the borrow
|
||||
// occurs upon entering the `[...]`
|
||||
|
@ -1110,13 +1127,13 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
_ => { }
|
||||
}
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
// Do a second pass over the pattern, calling `matched_pat` on
|
||||
// the interior nodes (enum variants and structs), as opposed
|
||||
// to the above loop's visit of than the bindings that form
|
||||
// the leaves of the pattern tree structure.
|
||||
mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
|
||||
return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
|
||||
let def_map = def_map.borrow();
|
||||
let tcx = typer.tcx();
|
||||
|
||||
|
@ -1167,17 +1184,29 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
// An enum's type -- should never be in a
|
||||
// pattern.
|
||||
|
||||
let msg = format!("Pattern has unexpected type: {}", def);
|
||||
tcx.sess.span_bug(pat.span, msg[])
|
||||
if !tcx.sess.has_errors() {
|
||||
let msg = format!("Pattern has unexpected type: {} and type {}",
|
||||
def,
|
||||
cmt_pat.ty.repr(tcx));
|
||||
tcx.sess.span_bug(pat.span, msg[])
|
||||
}
|
||||
}
|
||||
|
||||
Some(def) => {
|
||||
// Remaining cases are e.g. DefFn, to
|
||||
// which identifiers within patterns
|
||||
// should not resolve.
|
||||
// should not resolve. However, we do
|
||||
// encouter this when using the
|
||||
// expr-use-visitor during typeck. So just
|
||||
// ignore it, an error should have been
|
||||
// reported.
|
||||
|
||||
let msg = format!("Pattern has unexpected def: {}", def);
|
||||
tcx.sess.span_bug(pat.span, msg[])
|
||||
if !tcx.sess.has_errors() {
|
||||
let msg = format!("Pattern has unexpected def: {} and type {}",
|
||||
def,
|
||||
cmt_pat.ty.repr(tcx));
|
||||
tcx.sess.span_bug(pat.span, msg[])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1197,14 +1226,13 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
// cases either.
|
||||
}
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
fn walk_captures(&mut self, closure_expr: &ast::Expr) {
|
||||
debug!("walk_captures({})", closure_expr.repr(self.tcx()));
|
||||
|
||||
let tcx = self.typer.tcx();
|
||||
ty::with_freevars(tcx, closure_expr.id, |freevars| {
|
||||
ty::with_freevars(self.tcx(), closure_expr.id, |freevars| {
|
||||
match self.tcx().capture_mode(closure_expr.id) {
|
||||
ast::CaptureByRef => {
|
||||
self.walk_by_ref_captures(closure_expr, freevars);
|
||||
|
@ -1221,9 +1249,9 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
freevars: &[ty::Freevar]) {
|
||||
for freevar in freevars.iter() {
|
||||
let id_var = freevar.def.def_id().node;
|
||||
let cmt_var = self.cat_captured_var(closure_expr.id,
|
||||
closure_expr.span,
|
||||
freevar.def);
|
||||
let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
|
||||
closure_expr.span,
|
||||
freevar.def));
|
||||
|
||||
// Lookup the kind of borrow the callee requires, as
|
||||
// inferred by regionbk
|
||||
|
@ -1244,11 +1272,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
closure_expr: &ast::Expr,
|
||||
freevars: &[ty::Freevar]) {
|
||||
for freevar in freevars.iter() {
|
||||
let cmt_var = self.cat_captured_var(closure_expr.id,
|
||||
closure_expr.span,
|
||||
freevar.def);
|
||||
let mode = copy_or_move(self.tcx(), cmt_var.ty,
|
||||
self.param_env, CaptureMove);
|
||||
let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
|
||||
closure_expr.span,
|
||||
freevar.def));
|
||||
let mode = copy_or_move(self.typer, &cmt_var, CaptureMove);
|
||||
self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode);
|
||||
}
|
||||
}
|
||||
|
@ -1257,21 +1284,21 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
closure_id: ast::NodeId,
|
||||
closure_span: Span,
|
||||
upvar_def: def::Def)
|
||||
-> mc::cmt<'tcx> {
|
||||
-> mc::McResult<mc::cmt<'tcx>> {
|
||||
// Create the cmt for the variable being borrowed, from the
|
||||
// caller's perspective
|
||||
let var_id = upvar_def.def_id().node;
|
||||
let var_ty = self.typer.node_ty(var_id);
|
||||
let var_ty = try!(self.typer.node_ty(var_id));
|
||||
self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def)
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_or_move<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
param_env: &ParameterEnvironment<'tcx>,
|
||||
fn copy_or_move<'tcx>(typer: &mc::Typer<'tcx>,
|
||||
cmt: &mc::cmt<'tcx>,
|
||||
move_reason: MoveReason)
|
||||
-> ConsumeMode {
|
||||
if ty::type_moves_by_default(tcx, ty, param_env) {
|
||||
-> ConsumeMode
|
||||
{
|
||||
if typer.type_moves_by_default(cmt.span, cmt.ty) {
|
||||
Move(move_reason)
|
||||
} else {
|
||||
Copy
|
||||
|
|
|
@ -41,7 +41,7 @@ struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> {
|
|||
// environments for each function we encounter. When we find a
|
||||
// call to `transmute`, we can check it in the context of the top
|
||||
// of the stack (which ought not to be empty).
|
||||
param_envs: Vec<ty::ParameterEnvironment<'tcx>>,
|
||||
param_envs: Vec<ty::ParameterEnvironment<'a,'tcx>>,
|
||||
|
||||
// Dummy sized/unsized types that use to substitute for type
|
||||
// parameters in order to estimate how big a type will be for any
|
||||
|
@ -170,6 +170,7 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
|
|||
|
||||
let mut substs = param_env.free_substs.clone();
|
||||
self.with_each_combination(
|
||||
span,
|
||||
param_env,
|
||||
param_env.free_substs.types.iter_enumerated(),
|
||||
&mut substs,
|
||||
|
@ -187,7 +188,8 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn with_each_combination(&self,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
span: Span,
|
||||
param_env: &ty::ParameterEnvironment<'a,'tcx>,
|
||||
mut types_in_scope: EnumeratedItems<Ty<'tcx>>,
|
||||
substs: &mut Substs<'tcx>,
|
||||
callback: &mut FnMut(&Substs<'tcx>))
|
||||
|
@ -210,15 +212,17 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
|
|||
debug!("with_each_combination: space={}, index={}, param_ty={}",
|
||||
space, index, param_ty.repr(self.tcx));
|
||||
|
||||
if !ty::type_is_sized(self.tcx, param_ty, param_env) {
|
||||
if !ty::type_is_sized(param_env, span, param_ty) {
|
||||
debug!("with_each_combination: param_ty is not known to be sized");
|
||||
|
||||
substs.types.get_mut_slice(space)[index] = self.dummy_unsized_ty;
|
||||
self.with_each_combination(param_env, types_in_scope.clone(), substs, callback);
|
||||
self.with_each_combination(span, param_env, types_in_scope.clone(),
|
||||
substs, callback);
|
||||
}
|
||||
|
||||
substs.types.get_mut_slice(space)[index] = self.dummy_sized_ty;
|
||||
self.with_each_combination(param_env, types_in_scope, substs, callback);
|
||||
self.with_each_combination(span, param_env, types_in_scope,
|
||||
substs, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ use middle::def;
|
|||
use middle::region;
|
||||
use middle::ty::{mod, Ty};
|
||||
use util::nodemap::{NodeMap};
|
||||
use util::ppaux::{ty_to_string, Repr};
|
||||
use util::ppaux::{Repr};
|
||||
|
||||
use syntax::ast::{MutImmutable, MutMutable};
|
||||
use syntax::ast;
|
||||
|
@ -195,51 +195,39 @@ pub enum deref_kind {
|
|||
// Categorizes a derefable type. Note that we include vectors and strings as
|
||||
// derefable (we model an index as the combination of a deref and then a
|
||||
// pointer adjustment).
|
||||
pub fn opt_deref_kind(t: Ty) -> Option<deref_kind> {
|
||||
pub fn deref_kind(t: Ty) -> McResult<deref_kind> {
|
||||
match t.sty {
|
||||
ty::ty_uniq(_) |
|
||||
ty::ty_closure(box ty::ClosureTy {store: ty::UniqTraitStore, ..}) => {
|
||||
Some(deref_ptr(Unique))
|
||||
Ok(deref_ptr(Unique))
|
||||
}
|
||||
|
||||
ty::ty_rptr(r, mt) => {
|
||||
let kind = ty::BorrowKind::from_mutbl(mt.mutbl);
|
||||
Some(deref_ptr(BorrowedPtr(kind, *r)))
|
||||
Ok(deref_ptr(BorrowedPtr(kind, *r)))
|
||||
}
|
||||
|
||||
ty::ty_closure(box ty::ClosureTy {
|
||||
store: ty::RegionTraitStore(r, _),
|
||||
..
|
||||
}) => {
|
||||
Some(deref_ptr(BorrowedPtr(ty::ImmBorrow, r)))
|
||||
Ok(deref_ptr(BorrowedPtr(ty::ImmBorrow, r)))
|
||||
}
|
||||
|
||||
ty::ty_ptr(ref mt) => {
|
||||
Some(deref_ptr(UnsafePtr(mt.mutbl)))
|
||||
Ok(deref_ptr(UnsafePtr(mt.mutbl)))
|
||||
}
|
||||
|
||||
ty::ty_enum(..) |
|
||||
ty::ty_struct(..) => { // newtype
|
||||
Some(deref_interior(InteriorField(PositionalField(0))))
|
||||
Ok(deref_interior(InteriorField(PositionalField(0))))
|
||||
}
|
||||
|
||||
ty::ty_vec(_, _) | ty::ty_str => {
|
||||
Some(deref_interior(InteriorElement(element_kind(t))))
|
||||
Ok(deref_interior(InteriorElement(element_kind(t))))
|
||||
}
|
||||
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deref_kind<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> deref_kind {
|
||||
debug!("deref_kind {}", ty_to_string(tcx, t));
|
||||
match opt_deref_kind(t) {
|
||||
Some(k) => k,
|
||||
None => {
|
||||
tcx.sess.bug(
|
||||
format!("deref_kind() invoked on non-derefable type {}",
|
||||
ty_to_string(tcx, t))[]);
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,6 +252,8 @@ pub struct MemCategorizationContext<'t,TYPER:'t> {
|
|||
|
||||
impl<'t,TYPER:'t> Copy for MemCategorizationContext<'t,TYPER> {}
|
||||
|
||||
pub type McResult<T> = Result<T, ()>;
|
||||
|
||||
/// The `Typer` trait provides the interface for the mem-categorization
|
||||
/// module to the results of the type check. It can be used to query
|
||||
/// the type assigned to an expression node, to inquire after adjustments,
|
||||
|
@ -282,8 +272,9 @@ impl<'t,TYPER:'t> Copy for MemCategorizationContext<'t,TYPER> {}
|
|||
/// can be sure that only `Ok` results will occur.
|
||||
pub trait Typer<'tcx> : ty::UnboxedClosureTyper<'tcx> {
|
||||
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
|
||||
fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx>;
|
||||
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx>;
|
||||
fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>>;
|
||||
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>>;
|
||||
fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool;
|
||||
fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>>;
|
||||
fn node_method_origin(&self, method_call: ty::MethodCall)
|
||||
-> Option<ty::MethodOrigin<'tcx>>;
|
||||
|
@ -382,24 +373,24 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
self.typer.tcx()
|
||||
}
|
||||
|
||||
fn expr_ty(&self, expr: &ast::Expr) -> Ty<'tcx> {
|
||||
fn expr_ty(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
|
||||
self.typer.node_ty(expr.id)
|
||||
}
|
||||
|
||||
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx> {
|
||||
let unadjusted_ty = self.expr_ty(expr);
|
||||
ty::adjust_ty(self.tcx(), expr.span, expr.id, unadjusted_ty,
|
||||
self.typer.adjustments().borrow().get(&expr.id),
|
||||
|method_call| self.typer.node_method_ty(method_call))
|
||||
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
|
||||
let unadjusted_ty = try!(self.expr_ty(expr));
|
||||
Ok(ty::adjust_ty(self.tcx(), expr.span, expr.id, unadjusted_ty,
|
||||
self.typer.adjustments().borrow().get(&expr.id),
|
||||
|method_call| self.typer.node_method_ty(method_call)))
|
||||
}
|
||||
|
||||
fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
|
||||
fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
|
||||
self.typer.node_ty(id)
|
||||
}
|
||||
|
||||
fn pat_ty(&self, pat: &ast::Pat) -> Ty<'tcx> {
|
||||
fn pat_ty(&self, pat: &ast::Pat) -> McResult<Ty<'tcx>> {
|
||||
let tcx = self.typer.tcx();
|
||||
let base_ty = self.typer.node_ty(pat.id);
|
||||
let base_ty = try!(self.typer.node_ty(pat.id));
|
||||
// FIXME (Issue #18207): This code detects whether we are
|
||||
// looking at a `ref x`, and if so, figures out what the type
|
||||
// *being borrowed* is. But ideally we would put in a more
|
||||
|
@ -409,18 +400,19 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
// a bind-by-ref means that the base_ty will be the type of the ident itself,
|
||||
// but what we want here is the type of the underlying value being borrowed.
|
||||
// So peel off one-level, turning the &T into T.
|
||||
ty::deref(base_ty, false).unwrap_or_else(|| {
|
||||
panic!("encountered BindByRef with non &-type");
|
||||
}).ty
|
||||
match ty::deref(base_ty, false) {
|
||||
Some(t) => t.ty,
|
||||
None => { return Err(()); }
|
||||
}
|
||||
}
|
||||
_ => base_ty,
|
||||
};
|
||||
debug!("pat_ty(pat={}) base_ty={} ret_ty={}",
|
||||
pat.repr(tcx), base_ty.repr(tcx), ret_ty.repr(tcx));
|
||||
ret_ty
|
||||
Ok(ret_ty)
|
||||
}
|
||||
|
||||
pub fn cat_expr(&self, expr: &ast::Expr) -> cmt<'tcx> {
|
||||
pub fn cat_expr(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
|
||||
match self.typer.adjustments().borrow().get(&expr.id) {
|
||||
None => {
|
||||
// No adjustments.
|
||||
|
@ -434,8 +426,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
expr.repr(self.tcx()));
|
||||
// Convert a bare fn to a closure by adding NULL env.
|
||||
// Result is an rvalue.
|
||||
let expr_ty = self.expr_ty_adjusted(expr);
|
||||
self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)
|
||||
let expr_ty = try!(self.expr_ty_adjusted(expr));
|
||||
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
|
||||
}
|
||||
|
||||
ty::AdjustDerefRef(
|
||||
|
@ -445,8 +437,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
expr.repr(self.tcx()));
|
||||
// Equivalent to &*expr or something similar.
|
||||
// Result is an rvalue.
|
||||
let expr_ty = self.expr_ty_adjusted(expr);
|
||||
self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)
|
||||
let expr_ty = try!(self.expr_ty_adjusted(expr));
|
||||
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
|
||||
}
|
||||
|
||||
ty::AdjustDerefRef(
|
||||
|
@ -463,46 +455,46 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
pub fn cat_expr_autoderefd(&self,
|
||||
expr: &ast::Expr,
|
||||
autoderefs: uint)
|
||||
-> cmt<'tcx> {
|
||||
let mut cmt = self.cat_expr_unadjusted(expr);
|
||||
-> McResult<cmt<'tcx>> {
|
||||
let mut cmt = try!(self.cat_expr_unadjusted(expr));
|
||||
debug!("cat_expr_autoderefd: autoderefs={}, cmt={}",
|
||||
autoderefs,
|
||||
cmt.repr(self.tcx()));
|
||||
for deref in range(1u, autoderefs + 1) {
|
||||
cmt = self.cat_deref(expr, cmt, deref, false);
|
||||
cmt = try!(self.cat_deref(expr, cmt, deref, false));
|
||||
}
|
||||
return cmt;
|
||||
return Ok(cmt);
|
||||
}
|
||||
|
||||
pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> cmt<'tcx> {
|
||||
pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
|
||||
debug!("cat_expr: id={} expr={}", expr.id, expr.repr(self.tcx()));
|
||||
|
||||
let expr_ty = self.expr_ty(expr);
|
||||
let expr_ty = try!(self.expr_ty(expr));
|
||||
match expr.node {
|
||||
ast::ExprUnary(ast::UnDeref, ref e_base) => {
|
||||
let base_cmt = self.cat_expr(&**e_base);
|
||||
let base_cmt = try!(self.cat_expr(&**e_base));
|
||||
self.cat_deref(expr, base_cmt, 0, false)
|
||||
}
|
||||
|
||||
ast::ExprField(ref base, f_name) => {
|
||||
let base_cmt = self.cat_expr(&**base);
|
||||
let base_cmt = try!(self.cat_expr(&**base));
|
||||
debug!("cat_expr(cat_field): id={} expr={} base={}",
|
||||
expr.id,
|
||||
expr.repr(self.tcx()),
|
||||
base_cmt.repr(self.tcx()));
|
||||
self.cat_field(expr, base_cmt, f_name.node.name, expr_ty)
|
||||
Ok(self.cat_field(expr, base_cmt, f_name.node.name, expr_ty))
|
||||
}
|
||||
|
||||
ast::ExprTupField(ref base, idx) => {
|
||||
let base_cmt = self.cat_expr(&**base);
|
||||
self.cat_tup_field(expr, base_cmt, idx.node, expr_ty)
|
||||
let base_cmt = try!(self.cat_expr(&**base));
|
||||
Ok(self.cat_tup_field(expr, base_cmt, idx.node, expr_ty))
|
||||
}
|
||||
|
||||
ast::ExprIndex(ref base, ref idx) => {
|
||||
match idx.node {
|
||||
ast::ExprRange(..) => {
|
||||
// Slicing syntax special case (KILLME).
|
||||
self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)
|
||||
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
|
||||
}
|
||||
_ => {
|
||||
let method_call = ty::MethodCall::expr(expr.id());
|
||||
|
@ -517,7 +509,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
ret_ty), 1, true)
|
||||
}
|
||||
None => {
|
||||
self.cat_index(expr, self.cat_expr(&**base))
|
||||
self.cat_index(expr, try!(self.cat_expr(&**base)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -545,7 +537,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) |
|
||||
ast::ExprInlineAsm(..) | ast::ExprBox(..) |
|
||||
ast::ExprForLoop(..) => {
|
||||
self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)
|
||||
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
|
||||
}
|
||||
|
||||
ast::ExprIfLet(..) => {
|
||||
|
@ -562,43 +554,43 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
span: Span,
|
||||
expr_ty: Ty<'tcx>,
|
||||
def: def::Def)
|
||||
-> cmt<'tcx> {
|
||||
-> McResult<cmt<'tcx>> {
|
||||
debug!("cat_def: id={} expr={} def={}",
|
||||
id, expr_ty.repr(self.tcx()), def);
|
||||
|
||||
match def {
|
||||
def::DefStruct(..) | def::DefVariant(..) | def::DefFn(..) |
|
||||
def::DefStaticMethod(..) | def::DefConst(..) => {
|
||||
self.cat_rvalue_node(id, span, expr_ty)
|
||||
Ok(self.cat_rvalue_node(id, span, expr_ty))
|
||||
}
|
||||
def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
|
||||
def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
|
||||
def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) |
|
||||
def::DefLabel(_) | def::DefSelfTy(..) | def::DefMethod(..) |
|
||||
def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> {
|
||||
Rc::new(cmt_ {
|
||||
Ok(Rc::new(cmt_ {
|
||||
id:id,
|
||||
span:span,
|
||||
cat:cat_static_item,
|
||||
mutbl: McImmutable,
|
||||
ty:expr_ty,
|
||||
note: NoteNone
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
def::DefStatic(_, mutbl) => {
|
||||
Rc::new(cmt_ {
|
||||
Ok(Rc::new(cmt_ {
|
||||
id:id,
|
||||
span:span,
|
||||
cat:cat_static_item,
|
||||
mutbl: if mutbl { McDeclared } else { McImmutable},
|
||||
ty:expr_ty,
|
||||
note: NoteNone
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
def::DefUpvar(var_id, fn_node_id, _) => {
|
||||
let ty = self.node_ty(fn_node_id);
|
||||
let ty = try!(self.node_ty(fn_node_id));
|
||||
match ty.sty {
|
||||
ty::ty_closure(ref closure_ty) => {
|
||||
// Translate old closure type info into unboxed
|
||||
|
@ -635,14 +627,14 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
}
|
||||
|
||||
def::DefLocal(vid) => {
|
||||
Rc::new(cmt_ {
|
||||
Ok(Rc::new(cmt_ {
|
||||
id: id,
|
||||
span: span,
|
||||
cat: cat_local(vid),
|
||||
mutbl: MutabilityCategory::from_local(self.tcx(), vid),
|
||||
ty: expr_ty,
|
||||
note: NoteNone
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -657,7 +649,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
kind: ty::UnboxedClosureKind,
|
||||
mode: ast::CaptureClause,
|
||||
is_unboxed: bool)
|
||||
-> cmt<'tcx> {
|
||||
-> McResult<cmt<'tcx>> {
|
||||
// An upvar can have up to 3 components. The base is a
|
||||
// `cat_upvar`. Next, we add a deref through the implicit
|
||||
// environment pointer with an anonymous free region 'env and
|
||||
|
@ -679,7 +671,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
// FnOnce | copied | upvar -> &'up bk
|
||||
// old stack | N/A | upvar -> &'env mut -> &'up bk
|
||||
// old proc/once | copied | N/A
|
||||
let var_ty = self.node_ty(var_id);
|
||||
let var_ty = try!(self.node_ty(var_id));
|
||||
|
||||
let upvar_id = ty::UpvarId { var_id: var_id,
|
||||
closure_expr_id: fn_node_id };
|
||||
|
@ -727,7 +719,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
});
|
||||
|
||||
// First, switch by capture mode
|
||||
match mode {
|
||||
Ok(match mode {
|
||||
ast::CaptureByValue => {
|
||||
let mut base = cmt_ {
|
||||
id: id,
|
||||
|
@ -809,7 +801,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
note: NoteUpvarRef(upvar_id)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn cat_rvalue_node(&self,
|
||||
|
@ -882,7 +874,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
base_cmt: cmt<'tcx>,
|
||||
deref_cnt: uint,
|
||||
implicit: bool)
|
||||
-> cmt<'tcx> {
|
||||
-> McResult<cmt<'tcx>> {
|
||||
let adjustment = match self.typer.adjustments().borrow().get(&node.id()) {
|
||||
Some(adj) if ty::adjust_is_object(adj) => ty::AutoObject,
|
||||
_ if deref_cnt != 0 => ty::AutoDeref(deref_cnt),
|
||||
|
@ -896,7 +888,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
let method_ty = self.typer.node_method_ty(method_call);
|
||||
|
||||
debug!("cat_deref: method_call={} method_ty={}",
|
||||
method_call, method_ty.map(|ty| ty.repr(self.tcx())));
|
||||
method_call, method_ty.map(|ty| ty.repr(self.tcx())));
|
||||
|
||||
let base_cmt = match method_ty {
|
||||
Some(method_ty) => {
|
||||
|
@ -905,13 +897,13 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
}
|
||||
None => base_cmt
|
||||
};
|
||||
match ty::deref(base_cmt.ty, true) {
|
||||
let base_cmt_ty = base_cmt.ty;
|
||||
match ty::deref(base_cmt_ty, true) {
|
||||
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, implicit),
|
||||
None => {
|
||||
self.tcx().sess.span_bug(
|
||||
node.span(),
|
||||
format!("Explicit deref of non-derefable type: {}",
|
||||
base_cmt.ty.repr(self.tcx()))[]);
|
||||
debug!("Explicit deref of non-derefable type: {}",
|
||||
base_cmt_ty.repr(self.tcx()));
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -922,8 +914,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
deref_cnt: uint,
|
||||
deref_ty: Ty<'tcx>,
|
||||
implicit: bool)
|
||||
-> cmt<'tcx> {
|
||||
let (m, cat) = match deref_kind(self.tcx(), base_cmt.ty) {
|
||||
-> McResult<cmt<'tcx>>
|
||||
{
|
||||
let (m, cat) = match try!(deref_kind(base_cmt.ty)) {
|
||||
deref_ptr(ptr) => {
|
||||
let ptr = if implicit {
|
||||
match ptr {
|
||||
|
@ -943,20 +936,20 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
(base_cmt.mutbl.inherit(), cat_interior(base_cmt, interior))
|
||||
}
|
||||
};
|
||||
Rc::new(cmt_ {
|
||||
Ok(Rc::new(cmt_ {
|
||||
id: node.id(),
|
||||
span: node.span(),
|
||||
cat: cat,
|
||||
mutbl: m,
|
||||
ty: deref_ty,
|
||||
note: NoteNone
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn cat_index<N:ast_node>(&self,
|
||||
elt: &N,
|
||||
mut base_cmt: cmt<'tcx>)
|
||||
-> cmt<'tcx> {
|
||||
-> McResult<cmt<'tcx>> {
|
||||
//! Creates a cmt for an indexing operation (`[]`).
|
||||
//!
|
||||
//! One subtle aspect of indexing that may not be
|
||||
|
@ -987,17 +980,14 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
match ty::array_element_ty(self.tcx(), base_cmt.ty) {
|
||||
Some(ty) => ty,
|
||||
None => {
|
||||
self.tcx().sess.span_bug(
|
||||
elt.span(),
|
||||
format!("Explicit index of non-index type `{}`",
|
||||
base_cmt.ty.repr(self.tcx()))[]);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let m = base_cmt.mutbl.inherit();
|
||||
return interior(elt, base_cmt.clone(), base_cmt.ty, m, element_ty);
|
||||
return Ok(interior(elt, base_cmt.clone(), base_cmt.ty, m, element_ty));
|
||||
|
||||
fn interior<'tcx, N: ast_node>(elt: &N,
|
||||
of_cmt: cmt<'tcx>,
|
||||
|
@ -1021,15 +1011,16 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
fn deref_vec<N:ast_node>(&self,
|
||||
elt: &N,
|
||||
base_cmt: cmt<'tcx>)
|
||||
-> cmt<'tcx> {
|
||||
match deref_kind(self.tcx(), base_cmt.ty) {
|
||||
-> McResult<cmt<'tcx>>
|
||||
{
|
||||
match try!(deref_kind(base_cmt.ty)) {
|
||||
deref_ptr(ptr) => {
|
||||
// for unique ptrs, we inherit mutability from the
|
||||
// owning reference.
|
||||
let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr);
|
||||
|
||||
// the deref is explicit in the resulting cmt
|
||||
Rc::new(cmt_ {
|
||||
Ok(Rc::new(cmt_ {
|
||||
id:elt.id(),
|
||||
span:elt.span(),
|
||||
cat:cat_deref(base_cmt.clone(), 0, ptr),
|
||||
|
@ -1039,11 +1030,11 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
None => self.tcx().sess.bug("Found non-derefable type")
|
||||
},
|
||||
note: NoteNone
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
deref_interior(_) => {
|
||||
base_cmt
|
||||
Ok(base_cmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1058,13 +1049,13 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
pub fn cat_slice_pattern(&self,
|
||||
vec_cmt: cmt<'tcx>,
|
||||
slice_pat: &ast::Pat)
|
||||
-> (cmt<'tcx>, ast::Mutability, ty::Region) {
|
||||
let slice_ty = self.node_ty(slice_pat.id);
|
||||
-> McResult<(cmt<'tcx>, ast::Mutability, ty::Region)> {
|
||||
let slice_ty = try!(self.node_ty(slice_pat.id));
|
||||
let (slice_mutbl, slice_r) = vec_slice_info(self.tcx(),
|
||||
slice_pat,
|
||||
slice_ty);
|
||||
let cmt_slice = self.cat_index(slice_pat, self.deref_vec(slice_pat, vec_cmt));
|
||||
return (cmt_slice, slice_mutbl, slice_r);
|
||||
let cmt_slice = try!(self.cat_index(slice_pat, try!(self.deref_vec(slice_pat, vec_cmt))));
|
||||
return Ok((cmt_slice, slice_mutbl, slice_r));
|
||||
|
||||
/// In a pattern like [a, b, ..c], normally `c` has slice type, but if you have [a, b,
|
||||
/// ..ref c], then the type of `ref c` will be `&&[]`, so to extract the slice details we
|
||||
|
@ -1119,15 +1110,16 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn cat_pattern<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, mut op: F) where
|
||||
F: FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat),
|
||||
pub fn cat_pattern<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, mut op: F) -> McResult<()>
|
||||
where F: FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat),
|
||||
{
|
||||
self.cat_pattern_(cmt, pat, &mut op)
|
||||
}
|
||||
|
||||
// FIXME(#19596) This is a workaround, but there should be a better way to do this
|
||||
fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, op: &mut F) where
|
||||
F: FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat),
|
||||
fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, op: &mut F)
|
||||
-> McResult<()>
|
||||
where F : FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat),
|
||||
{
|
||||
// Here, `cmt` is the categorization for the value being
|
||||
// matched and pat is the pattern it is being matched against.
|
||||
|
@ -1208,29 +1200,29 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
Some(&def::DefVariant(..)) => {
|
||||
// variant(x, y, z)
|
||||
for (i, subpat) in subpats.iter().enumerate() {
|
||||
let subpat_ty = self.pat_ty(&**subpat); // see (*2)
|
||||
let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
|
||||
|
||||
let subcmt =
|
||||
self.cat_imm_interior(
|
||||
pat, cmt.clone(), subpat_ty,
|
||||
InteriorField(PositionalField(i)));
|
||||
|
||||
self.cat_pattern_(subcmt, &**subpat, op);
|
||||
try!(self.cat_pattern_(subcmt, &**subpat, op));
|
||||
}
|
||||
}
|
||||
Some(&def::DefStruct(..)) => {
|
||||
for (i, subpat) in subpats.iter().enumerate() {
|
||||
let subpat_ty = self.pat_ty(&**subpat); // see (*2)
|
||||
let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
|
||||
let cmt_field =
|
||||
self.cat_imm_interior(
|
||||
pat, cmt.clone(), subpat_ty,
|
||||
InteriorField(PositionalField(i)));
|
||||
self.cat_pattern_(cmt_field, &**subpat, op);
|
||||
try!(self.cat_pattern_(cmt_field, &**subpat, op));
|
||||
}
|
||||
}
|
||||
Some(&def::DefConst(..)) => {
|
||||
for subpat in subpats.iter() {
|
||||
self.cat_pattern_(cmt.clone(), &**subpat, op);
|
||||
try!(self.cat_pattern_(cmt.clone(), &**subpat, op));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
@ -1242,7 +1234,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
}
|
||||
|
||||
ast::PatIdent(_, _, Some(ref subpat)) => {
|
||||
self.cat_pattern_(cmt, &**subpat, op);
|
||||
try!(self.cat_pattern_(cmt, &**subpat, op));
|
||||
}
|
||||
|
||||
ast::PatIdent(_, _, None) => {
|
||||
|
@ -1252,42 +1244,42 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
ast::PatStruct(_, ref field_pats, _) => {
|
||||
// {f1: p1, ..., fN: pN}
|
||||
for fp in field_pats.iter() {
|
||||
let field_ty = self.pat_ty(&*fp.node.pat); // see (*2)
|
||||
let field_ty = try!(self.pat_ty(&*fp.node.pat)); // see (*2)
|
||||
let cmt_field = self.cat_field(pat, cmt.clone(), fp.node.ident.name, field_ty);
|
||||
self.cat_pattern_(cmt_field, &*fp.node.pat, op);
|
||||
try!(self.cat_pattern_(cmt_field, &*fp.node.pat, op));
|
||||
}
|
||||
}
|
||||
|
||||
ast::PatTup(ref subpats) => {
|
||||
// (p1, ..., pN)
|
||||
for (i, subpat) in subpats.iter().enumerate() {
|
||||
let subpat_ty = self.pat_ty(&**subpat); // see (*2)
|
||||
let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
|
||||
let subcmt =
|
||||
self.cat_imm_interior(
|
||||
pat, cmt.clone(), subpat_ty,
|
||||
InteriorField(PositionalField(i)));
|
||||
self.cat_pattern_(subcmt, &**subpat, op);
|
||||
try!(self.cat_pattern_(subcmt, &**subpat, op));
|
||||
}
|
||||
}
|
||||
|
||||
ast::PatBox(ref subpat) | ast::PatRegion(ref subpat) => {
|
||||
// @p1, ~p1, ref p1
|
||||
let subcmt = self.cat_deref(pat, cmt, 0, false);
|
||||
self.cat_pattern_(subcmt, &**subpat, op);
|
||||
let subcmt = try!(self.cat_deref(pat, cmt, 0, false));
|
||||
try!(self.cat_pattern_(subcmt, &**subpat, op));
|
||||
}
|
||||
|
||||
ast::PatVec(ref before, ref slice, ref after) => {
|
||||
let elt_cmt = self.cat_index(pat, self.deref_vec(pat, cmt));
|
||||
let elt_cmt = try!(self.cat_index(pat, try!(self.deref_vec(pat, cmt))));
|
||||
for before_pat in before.iter() {
|
||||
self.cat_pattern_(elt_cmt.clone(), &**before_pat, op);
|
||||
try!(self.cat_pattern_(elt_cmt.clone(), &**before_pat, op));
|
||||
}
|
||||
for slice_pat in slice.iter() {
|
||||
let slice_ty = self.pat_ty(&**slice_pat);
|
||||
let slice_ty = try!(self.pat_ty(&**slice_pat));
|
||||
let slice_cmt = self.cat_rvalue_node(pat.id(), pat.span(), slice_ty);
|
||||
self.cat_pattern_(slice_cmt, &**slice_pat, op);
|
||||
try!(self.cat_pattern_(slice_cmt, &**slice_pat, op));
|
||||
}
|
||||
for after_pat in after.iter() {
|
||||
self.cat_pattern_(elt_cmt.clone(), &**after_pat, op);
|
||||
try!(self.cat_pattern_(elt_cmt.clone(), &**after_pat, op));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1299,77 +1291,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
self.tcx().sess.span_bug(pat.span, "unexpanded macro");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cmt_to_string(&self, cmt: &cmt_<'tcx>) -> String {
|
||||
fn upvar_to_string(upvar: &Upvar, is_copy: bool) -> String {
|
||||
if upvar.is_unboxed {
|
||||
let kind = match upvar.kind {
|
||||
ty::FnUnboxedClosureKind => "Fn",
|
||||
ty::FnMutUnboxedClosureKind => "FnMut",
|
||||
ty::FnOnceUnboxedClosureKind => "FnOnce"
|
||||
};
|
||||
format!("captured outer variable in an `{}` closure", kind)
|
||||
} else {
|
||||
(match (upvar.kind, is_copy) {
|
||||
(ty::FnOnceUnboxedClosureKind, true) => "captured outer variable in a proc",
|
||||
_ => "captured outer variable"
|
||||
}).to_string()
|
||||
}
|
||||
}
|
||||
|
||||
match cmt.cat {
|
||||
cat_static_item => {
|
||||
"static item".to_string()
|
||||
}
|
||||
cat_rvalue(..) => {
|
||||
"non-lvalue".to_string()
|
||||
}
|
||||
cat_local(vid) => {
|
||||
match self.tcx().map.find(vid) {
|
||||
Some(ast_map::NodeArg(_)) => {
|
||||
"argument".to_string()
|
||||
}
|
||||
_ => "local variable".to_string()
|
||||
}
|
||||
}
|
||||
cat_deref(_, _, pk) => {
|
||||
let upvar = cmt.upvar();
|
||||
match upvar.as_ref().map(|i| &i.cat) {
|
||||
Some(&cat_upvar(ref var)) => {
|
||||
upvar_to_string(var, false)
|
||||
}
|
||||
Some(_) => unreachable!(),
|
||||
None => {
|
||||
match pk {
|
||||
Implicit(..) => {
|
||||
"dereference (dereference is implicit, due to indexing)".to_string()
|
||||
}
|
||||
Unique => format!("dereference of `{}`", ptr_sigil(pk)),
|
||||
_ => format!("dereference of `{}`-pointer", ptr_sigil(pk))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cat_interior(_, InteriorField(NamedField(_))) => {
|
||||
"field".to_string()
|
||||
}
|
||||
cat_interior(_, InteriorField(PositionalField(_))) => {
|
||||
"anonymous field".to_string()
|
||||
}
|
||||
cat_interior(_, InteriorElement(VecElement)) => {
|
||||
"vec content".to_string()
|
||||
}
|
||||
cat_interior(_, InteriorElement(OtherElement)) => {
|
||||
"indexed content".to_string()
|
||||
}
|
||||
cat_upvar(ref var) => {
|
||||
upvar_to_string(var, true)
|
||||
}
|
||||
cat_downcast(ref cmt, _) => {
|
||||
self.cmt_to_string(&**cmt)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1481,6 +1404,78 @@ impl<'tcx> cmt_<'tcx> {
|
|||
NoteNone => None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn descriptive_string(&self, tcx: &ty::ctxt) -> String {
|
||||
fn upvar_to_string(upvar: &Upvar, is_copy: bool) -> String {
|
||||
if upvar.is_unboxed {
|
||||
let kind = match upvar.kind {
|
||||
ty::FnUnboxedClosureKind => "Fn",
|
||||
ty::FnMutUnboxedClosureKind => "FnMut",
|
||||
ty::FnOnceUnboxedClosureKind => "FnOnce"
|
||||
};
|
||||
format!("captured outer variable in an `{}` closure", kind)
|
||||
} else {
|
||||
(match (upvar.kind, is_copy) {
|
||||
(ty::FnOnceUnboxedClosureKind, true) => "captured outer variable in a proc",
|
||||
_ => "captured outer variable"
|
||||
}).to_string()
|
||||
}
|
||||
}
|
||||
|
||||
match self.cat {
|
||||
cat_static_item => {
|
||||
"static item".to_string()
|
||||
}
|
||||
cat_rvalue(..) => {
|
||||
"non-lvalue".to_string()
|
||||
}
|
||||
cat_local(vid) => {
|
||||
match tcx.map.find(vid) {
|
||||
Some(ast_map::NodeArg(_)) => {
|
||||
"argument".to_string()
|
||||
}
|
||||
_ => "local variable".to_string()
|
||||
}
|
||||
}
|
||||
cat_deref(_, _, pk) => {
|
||||
let upvar = self.upvar();
|
||||
match upvar.as_ref().map(|i| &i.cat) {
|
||||
Some(&cat_upvar(ref var)) => {
|
||||
upvar_to_string(var, false)
|
||||
}
|
||||
Some(_) => unreachable!(),
|
||||
None => {
|
||||
match pk {
|
||||
Implicit(..) => {
|
||||
"dereference (dereference is implicit, due to indexing)".to_string()
|
||||
}
|
||||
Unique => format!("dereference of `{}`", ptr_sigil(pk)),
|
||||
_ => format!("dereference of `{}`-pointer", ptr_sigil(pk))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cat_interior(_, InteriorField(NamedField(_))) => {
|
||||
"field".to_string()
|
||||
}
|
||||
cat_interior(_, InteriorField(PositionalField(_))) => {
|
||||
"anonymous field".to_string()
|
||||
}
|
||||
cat_interior(_, InteriorElement(VecElement)) => {
|
||||
"vec content".to_string()
|
||||
}
|
||||
cat_interior(_, InteriorElement(OtherElement)) => {
|
||||
"indexed content".to_string()
|
||||
}
|
||||
cat_upvar(ref var) => {
|
||||
upvar_to_string(var, true)
|
||||
}
|
||||
cat_downcast(ref cmt, _) => {
|
||||
cmt.descriptive_string(tcx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for cmt_<'tcx> {
|
||||
|
|
|
@ -42,8 +42,8 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
|
|||
|
||||
// Determine whether `impl2` can provide an implementation for those
|
||||
// same types.
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let mut selcx = SelectionContext::intercrate(infcx, ¶m_env, infcx.tcx);
|
||||
let param_env = ty::empty_parameter_environment(infcx.tcx);
|
||||
let mut selcx = SelectionContext::intercrate(infcx, ¶m_env);
|
||||
let obligation = Obligation::new(ObligationCause::dummy(),
|
||||
ty::Binder(ty::TraitPredicate {
|
||||
trait_ref: Rc::new(impl1_trait_ref),
|
||||
|
|
|
@ -77,7 +77,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
"overflow evaluating the requirement `{}`",
|
||||
predicate.user_string(infcx.tcx)).as_slice());
|
||||
|
||||
suggest_new_overflow_limit(infcx, obligation.cause.span);
|
||||
suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
|
||||
|
||||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
|
@ -332,10 +332,10 @@ fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
pub fn suggest_new_overflow_limit(infcx: &InferCtxt, span: Span) {
|
||||
let current_limit = infcx.tcx.sess.recursion_limit.get();
|
||||
pub fn suggest_new_overflow_limit(tcx: &ty::ctxt, span: Span) {
|
||||
let current_limit = tcx.sess.recursion_limit.get();
|
||||
let suggested_limit = current_limit * 2;
|
||||
infcx.tcx.sess.span_note(
|
||||
tcx.sess.span_note(
|
||||
span,
|
||||
format!(
|
||||
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
|
||||
|
|
|
@ -109,7 +109,6 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
/// `projection_ty` again.
|
||||
pub fn normalize_projection_type<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
typer: &ty::UnboxedClosureTyper<'tcx>,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
cause: ObligationCause<'tcx>)
|
||||
|
@ -122,7 +121,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
|
||||
// FIXME(#20304) -- cache
|
||||
|
||||
let mut selcx = SelectionContext::new(infcx, param_env, typer);
|
||||
let mut selcx = SelectionContext::new(infcx, typer);
|
||||
let normalized = project::normalize_projection_type(&mut selcx, projection_ty, cause, 0);
|
||||
|
||||
for obligation in normalized.obligations.into_iter() {
|
||||
|
@ -186,11 +185,10 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
|
||||
pub fn select_all_or_error<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
typer: &ty::UnboxedClosureTyper<'tcx>)
|
||||
-> Result<(),Vec<FulfillmentError<'tcx>>>
|
||||
{
|
||||
try!(self.select_where_possible(infcx, param_env, typer));
|
||||
try!(self.select_where_possible(infcx, typer));
|
||||
|
||||
// Anything left is ambiguous.
|
||||
let errors: Vec<FulfillmentError> =
|
||||
|
@ -212,21 +210,19 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
/// results in `O(n^2)` performance (#18208).
|
||||
pub fn select_new_obligations<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
typer: &ty::UnboxedClosureTyper<'tcx>)
|
||||
-> Result<(),Vec<FulfillmentError<'tcx>>>
|
||||
{
|
||||
let mut selcx = SelectionContext::new(infcx, param_env, typer);
|
||||
let mut selcx = SelectionContext::new(infcx, typer);
|
||||
self.select(&mut selcx, true)
|
||||
}
|
||||
|
||||
pub fn select_where_possible<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
typer: &ty::UnboxedClosureTyper<'tcx>)
|
||||
-> Result<(),Vec<FulfillmentError<'tcx>>>
|
||||
{
|
||||
let mut selcx = SelectionContext::new(infcx, param_env, typer);
|
||||
let mut selcx = SelectionContext::new(infcx, typer);
|
||||
self.select(&mut selcx, false)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ pub use self::FulfillmentErrorCode::*;
|
|||
pub use self::Vtable::*;
|
||||
pub use self::ObligationCauseCode::*;
|
||||
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::subst;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::infer::InferCtxt;
|
||||
|
@ -22,9 +23,10 @@ use std::slice::Iter;
|
|||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
use util::ppaux::Repr;
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
pub use self::error_reporting::report_fulfillment_errors;
|
||||
pub use self::error_reporting::suggest_new_overflow_limit;
|
||||
pub use self::coherence::orphan_check;
|
||||
pub use self::coherence::OrphanCheckErr;
|
||||
pub use self::fulfill::{FulfillmentContext, RegionObligation};
|
||||
|
@ -288,11 +290,12 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
/// `bound` or is not known to meet bound (note that this is
|
||||
/// conservative towards *no impl*, which is the opposite of the
|
||||
/// `evaluate` methods).
|
||||
pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
bound: ty::BuiltinBound)
|
||||
-> bool
|
||||
pub fn evaluate_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
typer: &ty::UnboxedClosureTyper<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
bound: ty::BuiltinBound,
|
||||
span: Span)
|
||||
-> SelectionResult<'tcx, ()>
|
||||
{
|
||||
debug!("type_known_to_meet_builtin_bound(ty={}, bound={})",
|
||||
ty.repr(infcx.tcx),
|
||||
|
@ -300,17 +303,49 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
|||
|
||||
let mut fulfill_cx = FulfillmentContext::new();
|
||||
|
||||
// We can use dummy values here because we won't report any errors
|
||||
// that result nor will we pay any mind to region obligations that arise
|
||||
// (there shouldn't really be any anyhow).
|
||||
let cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID);
|
||||
// We can use a dummy node-id here because we won't pay any mind
|
||||
// to region obligations that arise (there shouldn't really be any
|
||||
// anyhow).
|
||||
let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
|
||||
|
||||
fulfill_cx.register_builtin_bound(infcx, ty, bound, cause);
|
||||
|
||||
// Note: we only assume something is `Copy` if we can
|
||||
// *definitively* show that it implements `Copy`. Otherwise,
|
||||
// assume it is move; linear is always ok.
|
||||
let result = fulfill_cx.select_all_or_error(infcx, param_env, infcx.tcx).is_ok();
|
||||
let result = match fulfill_cx.select_all_or_error(infcx, typer) {
|
||||
Ok(()) => Ok(Some(())), // Success, we know it implements Copy.
|
||||
Err(errors) => {
|
||||
// Check if overflow occurred anywhere and propagate that.
|
||||
if errors.iter().any(
|
||||
|err| match err.code { CodeSelectionError(Overflow) => true, _ => false })
|
||||
{
|
||||
return Err(Overflow);
|
||||
}
|
||||
|
||||
// Otherwise, if there were any hard errors, propagate an
|
||||
// arbitrary one of those. If no hard errors at all,
|
||||
// report ambiguity.
|
||||
let sel_error =
|
||||
errors.iter()
|
||||
.filter_map(|err| {
|
||||
match err.code {
|
||||
CodeAmbiguity => None,
|
||||
CodeSelectionError(ref e) => Some(e.clone()),
|
||||
CodeProjectionError(_) => {
|
||||
infcx.tcx.sess.span_bug(
|
||||
span,
|
||||
"projection error while selecting?")
|
||||
}
|
||||
}
|
||||
})
|
||||
.next();
|
||||
match sel_error {
|
||||
None => { Ok(None) }
|
||||
Some(e) => { Err(e) }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
debug!("type_known_to_meet_builtin_bound: ty={} bound={} result={}",
|
||||
ty.repr(infcx.tcx),
|
||||
|
@ -320,6 +355,40 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
|||
result
|
||||
}
|
||||
|
||||
pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
typer: &ty::UnboxedClosureTyper<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
bound: ty::BuiltinBound,
|
||||
span: Span)
|
||||
-> bool
|
||||
{
|
||||
match evaluate_builtin_bound(infcx, typer, ty, bound, span) {
|
||||
Ok(Some(())) => {
|
||||
// definitely impl'd
|
||||
true
|
||||
}
|
||||
Ok(None) => {
|
||||
// ambiguous: if coherence check was successful, shouldn't
|
||||
// happen, but we might have reported an error and been
|
||||
// soldering on, so just treat this like not implemented
|
||||
false
|
||||
}
|
||||
Err(Overflow) => {
|
||||
infcx.tcx.sess.span_err(
|
||||
span,
|
||||
format!("overflow evaluating whether `{}` is `{}`",
|
||||
ty.user_string(infcx.tcx),
|
||||
bound.user_string(infcx.tcx))[]);
|
||||
suggest_new_overflow_limit(infcx.tcx, span);
|
||||
false
|
||||
}
|
||||
Err(_) => {
|
||||
// other errors: not implemented.
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx,O> Obligation<'tcx,O> {
|
||||
pub fn new(cause: ObligationCause<'tcx>,
|
||||
trait_ref: O)
|
||||
|
|
|
@ -46,7 +46,6 @@ use util::ppaux::Repr;
|
|||
|
||||
pub struct SelectionContext<'cx, 'tcx:'cx> {
|
||||
infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||
param_env: &'cx ty::ParameterEnvironment<'tcx>,
|
||||
closure_typer: &'cx (ty::UnboxedClosureTyper<'tcx>+'cx),
|
||||
|
||||
/// Freshener used specifically for skolemizing entries on the
|
||||
|
@ -181,12 +180,10 @@ enum EvaluationResult<'tcx> {
|
|||
|
||||
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||
param_env: &'cx ty::ParameterEnvironment<'tcx>,
|
||||
closure_typer: &'cx ty::UnboxedClosureTyper<'tcx>)
|
||||
-> SelectionContext<'cx, 'tcx> {
|
||||
SelectionContext {
|
||||
infcx: infcx,
|
||||
param_env: param_env,
|
||||
closure_typer: closure_typer,
|
||||
freshener: infcx.freshener(),
|
||||
intercrate: false,
|
||||
|
@ -194,12 +191,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||
param_env: &'cx ty::ParameterEnvironment<'tcx>,
|
||||
closure_typer: &'cx ty::UnboxedClosureTyper<'tcx>)
|
||||
-> SelectionContext<'cx, 'tcx> {
|
||||
SelectionContext {
|
||||
infcx: infcx,
|
||||
param_env: param_env,
|
||||
closure_typer: closure_typer,
|
||||
freshener: infcx.freshener(),
|
||||
intercrate: true,
|
||||
|
@ -210,14 +205,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
self.infcx
|
||||
}
|
||||
|
||||
pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'tcx> {
|
||||
self.param_env
|
||||
}
|
||||
|
||||
pub fn tcx(&self) -> &'cx ty::ctxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'cx, 'tcx> {
|
||||
self.closure_typer.param_env()
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Selection
|
||||
//
|
||||
|
@ -650,7 +645,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// it's not worth going to more trouble to increase the
|
||||
// hit-rate I don't think.
|
||||
if self.intercrate {
|
||||
return &self.param_env.selection_cache;
|
||||
return &self.param_env().selection_cache;
|
||||
}
|
||||
|
||||
// If the trait refers to any parameters in scope, then use
|
||||
|
@ -659,7 +654,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
cache_fresh_trait_pred.0.input_types().iter().any(
|
||||
|&t| ty::type_has_self(t) || ty::type_has_params(t))
|
||||
{
|
||||
return &self.param_env.selection_cache;
|
||||
return &self.param_env().selection_cache;
|
||||
}
|
||||
|
||||
// If the trait refers to unbound type variables, and there
|
||||
|
@ -668,11 +663,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// common case, then we can use the global environment.
|
||||
// See the discussion in doc.rs for more details.
|
||||
if
|
||||
!self.param_env.caller_bounds.is_empty() &&
|
||||
!self.param_env().caller_bounds.is_empty() &&
|
||||
cache_fresh_trait_pred.0.input_types().iter().any(
|
||||
|&t| ty::type_has_ty_infer(t))
|
||||
{
|
||||
return &self.param_env.selection_cache;
|
||||
return &self.param_env().selection_cache;
|
||||
}
|
||||
|
||||
// Otherwise, we can use the global cache.
|
||||
|
@ -902,7 +897,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligation.repr(self.tcx()));
|
||||
|
||||
let caller_trait_refs: Vec<_> =
|
||||
self.param_env.caller_bounds.predicates.iter()
|
||||
self.param_env().caller_bounds.predicates.iter()
|
||||
.filter_map(|o| o.to_opt_poly_trait_ref())
|
||||
.collect();
|
||||
|
||||
|
|
|
@ -2058,7 +2058,9 @@ impl<'tcx> TraitRef<'tcx> {
|
|||
/// future I hope to refine the representation of types so as to make
|
||||
/// more distinctions clearer.
|
||||
#[deriving(Clone)]
|
||||
pub struct ParameterEnvironment<'tcx> {
|
||||
pub struct ParameterEnvironment<'a, 'tcx:'a> {
|
||||
pub tcx: &'a ctxt<'tcx>,
|
||||
|
||||
/// A substitution that can be applied to move from
|
||||
/// the "outer" view of a type or method to the "inner" view.
|
||||
/// In general, this means converting from bound parameters to
|
||||
|
@ -2082,8 +2084,8 @@ pub struct ParameterEnvironment<'tcx> {
|
|||
pub selection_cache: traits::SelectionCache<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ParameterEnvironment<'tcx> {
|
||||
pub fn for_item(cx: &ctxt<'tcx>, id: NodeId) -> ParameterEnvironment<'tcx> {
|
||||
impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
|
||||
pub fn for_item(cx: &'a ctxt<'tcx>, id: NodeId) -> ParameterEnvironment<'a, 'tcx> {
|
||||
match cx.map.find(id) {
|
||||
Some(ast_map::NodeImplItem(ref impl_item)) => {
|
||||
match **impl_item {
|
||||
|
@ -2272,6 +2274,8 @@ impl UnboxedClosureKind {
|
|||
}
|
||||
|
||||
pub trait UnboxedClosureTyper<'tcx> {
|
||||
fn param_env<'a>(&'a self) -> &'a ty::ParameterEnvironment<'a, 'tcx>;
|
||||
|
||||
fn unboxed_closure_kind(&self,
|
||||
def_id: ast::DefId)
|
||||
-> ty::UnboxedClosureKind;
|
||||
|
@ -2424,6 +2428,21 @@ impl<'tcx> ctxt<'tcx> {
|
|||
self.region_interner.borrow_mut().insert(region, region);
|
||||
region
|
||||
}
|
||||
|
||||
pub fn unboxed_closure_kind(&self,
|
||||
def_id: ast::DefId)
|
||||
-> ty::UnboxedClosureKind
|
||||
{
|
||||
self.unboxed_closures.borrow()[def_id].kind
|
||||
}
|
||||
|
||||
pub fn unboxed_closure_type(&self,
|
||||
def_id: ast::DefId,
|
||||
substs: &subst::Substs<'tcx>)
|
||||
-> ty::ClosureTy<'tcx>
|
||||
{
|
||||
self.unboxed_closures.borrow()[def_id].closure_type.subst(self, substs)
|
||||
}
|
||||
}
|
||||
|
||||
// Interns a type/name combination, stores the resulting box in cx.interner,
|
||||
|
@ -3377,7 +3396,8 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
|
|||
ty_unboxed_closure(did, r, substs) => {
|
||||
// FIXME(#14449): `borrowed_contents` below assumes `&mut`
|
||||
// unboxed closure.
|
||||
let upvars = unboxed_closure_upvars(cx, did, substs).unwrap();
|
||||
let param_env = ty::empty_parameter_environment(cx);
|
||||
let upvars = unboxed_closure_upvars(¶m_env, did, substs).unwrap();
|
||||
TypeContents::union(upvars.as_slice(),
|
||||
|f| tc_ty(cx, f.ty, cache))
|
||||
| borrowed_contents(*r, MutMutable)
|
||||
|
@ -3526,12 +3546,12 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
|
|||
}
|
||||
}
|
||||
|
||||
fn type_impls_bound<'tcx>(cx: &ctxt<'tcx>,
|
||||
cache: &RefCell<HashMap<Ty<'tcx>,bool>>,
|
||||
param_env: &ParameterEnvironment<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
bound: ty::BuiltinBound)
|
||||
-> bool
|
||||
fn type_impls_bound<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
|
||||
cache: &RefCell<HashMap<Ty<'tcx>,bool>>,
|
||||
ty: Ty<'tcx>,
|
||||
bound: ty::BuiltinBound,
|
||||
span: Span)
|
||||
-> bool
|
||||
{
|
||||
assert!(!ty::type_needs_infer(ty));
|
||||
|
||||
|
@ -3540,7 +3560,7 @@ fn type_impls_bound<'tcx>(cx: &ctxt<'tcx>,
|
|||
None => {}
|
||||
Some(&result) => {
|
||||
debug!("type_impls_bound({}, {}) = {} (cached)",
|
||||
ty_to_string(cx, ty),
|
||||
ty.repr(param_env.tcx),
|
||||
bound,
|
||||
result);
|
||||
return result
|
||||
|
@ -3548,11 +3568,12 @@ fn type_impls_bound<'tcx>(cx: &ctxt<'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
let infcx = infer::new_infer_ctxt(cx);
|
||||
let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound);
|
||||
let infcx = infer::new_infer_ctxt(param_env.tcx);
|
||||
|
||||
let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound, span);
|
||||
|
||||
debug!("type_impls_bound({}, {}) = {}",
|
||||
ty_to_string(cx, ty),
|
||||
ty.repr(param_env.tcx),
|
||||
bound,
|
||||
is_impld);
|
||||
|
||||
|
@ -3564,20 +3585,22 @@ fn type_impls_bound<'tcx>(cx: &ctxt<'tcx>,
|
|||
is_impld
|
||||
}
|
||||
|
||||
pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
param_env: &ParameterEnvironment<'tcx>)
|
||||
-> bool
|
||||
pub fn type_moves_by_default<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
!type_impls_bound(cx, &cx.type_impls_copy_cache, param_env, ty, ty::BoundCopy)
|
||||
let tcx = param_env.tcx;
|
||||
!type_impls_bound(param_env, &tcx.type_impls_copy_cache, ty, ty::BoundCopy, span)
|
||||
}
|
||||
|
||||
pub fn type_is_sized<'tcx>(cx: &ctxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
param_env: &ParameterEnvironment<'tcx>)
|
||||
-> bool
|
||||
pub fn type_is_sized<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
type_impls_bound(cx, &cx.type_impls_sized_cache, param_env, ty, ty::BoundSized)
|
||||
let tcx = param_env.tcx;
|
||||
type_impls_bound(param_env, &tcx.type_impls_sized_cache, ty, ty::BoundSized, span)
|
||||
}
|
||||
|
||||
pub fn is_ffi_safe<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
|
@ -3622,8 +3645,6 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool {
|
|||
ty_str |
|
||||
ty_bare_fn(..) |
|
||||
ty_closure(_) |
|
||||
ty_infer(_) |
|
||||
ty_err |
|
||||
ty_param(_) |
|
||||
ty_projection(_) |
|
||||
ty_vec(_, None) => {
|
||||
|
@ -3656,9 +3677,12 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool {
|
|||
r
|
||||
}
|
||||
|
||||
ty_unboxed_closure(did, _, substs) => {
|
||||
let upvars = unboxed_closure_upvars(cx, did, substs).unwrap();
|
||||
upvars.iter().any(|f| type_requires(cx, seen, r_ty, f.ty))
|
||||
ty_err |
|
||||
ty_infer(_) |
|
||||
ty_unboxed_closure(..) => {
|
||||
// this check is run on type definitions, so we don't expect to see
|
||||
// inference by-products or unboxed closure types
|
||||
cx.sess.bug(format!("requires check invoked on inapplicable type: {}", ty)[])
|
||||
}
|
||||
|
||||
ty_tup(ref ts) => {
|
||||
|
@ -3748,9 +3772,10 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>)
|
|||
|
||||
find_nonrepresentable(cx, sp, seen, iter)
|
||||
}
|
||||
ty_unboxed_closure(did, _, substs) => {
|
||||
let upvars = unboxed_closure_upvars(cx, did, substs).unwrap();
|
||||
find_nonrepresentable(cx, sp, seen, upvars.iter().map(|f| f.ty))
|
||||
ty_unboxed_closure(..) => {
|
||||
// this check is run on type definitions, so we don't expect to see
|
||||
// unboxed closure types
|
||||
cx.sess.bug(format!("requires check invoked on inapplicable type: {}", ty)[])
|
||||
}
|
||||
_ => Representable,
|
||||
}
|
||||
|
@ -5708,7 +5733,10 @@ pub fn unboxed_closure_upvars<'tcx>(typer: &mc::Typer<'tcx>,
|
|||
freevars.iter()
|
||||
.map(|freevar| {
|
||||
let freevar_def_id = freevar.def.def_id();
|
||||
let freevar_ty = typer.node_ty(freevar_def_id.node);
|
||||
let freevar_ty = match typer.node_ty(freevar_def_id.node) {
|
||||
Ok(t) => { t }
|
||||
Err(()) => { return None; }
|
||||
};
|
||||
let freevar_ty = freevar_ty.subst(tcx, substs);
|
||||
|
||||
match capture_mode {
|
||||
|
@ -6371,19 +6399,20 @@ impl Variance {
|
|||
|
||||
/// Construct a parameter environment suitable for static contexts or other contexts where there
|
||||
/// are no free type/lifetime parameters in scope.
|
||||
pub fn empty_parameter_environment<'tcx>() -> ParameterEnvironment<'tcx> {
|
||||
ty::ParameterEnvironment { free_substs: Substs::empty(),
|
||||
pub fn empty_parameter_environment<'a,'tcx>(cx: &'a ctxt<'tcx>) -> ParameterEnvironment<'a,'tcx> {
|
||||
ty::ParameterEnvironment { tcx: cx,
|
||||
free_substs: Substs::empty(),
|
||||
caller_bounds: GenericBounds::empty(),
|
||||
implicit_region_bound: ty::ReEmpty,
|
||||
selection_cache: traits::SelectionCache::new(), }
|
||||
}
|
||||
|
||||
/// See `ParameterEnvironment` struct def'n for details
|
||||
pub fn construct_parameter_environment<'tcx>(
|
||||
tcx: &ctxt<'tcx>,
|
||||
pub fn construct_parameter_environment<'a,'tcx>(
|
||||
tcx: &'a ctxt<'tcx>,
|
||||
generics: &ty::Generics<'tcx>,
|
||||
free_id: ast::NodeId)
|
||||
-> ParameterEnvironment<'tcx>
|
||||
-> ParameterEnvironment<'a, 'tcx>
|
||||
{
|
||||
|
||||
//
|
||||
|
@ -6426,6 +6455,7 @@ pub fn construct_parameter_environment<'tcx>(
|
|||
bounds.repr(tcx));
|
||||
|
||||
return ty::ParameterEnvironment {
|
||||
tcx: tcx,
|
||||
free_substs: free_substs,
|
||||
implicit_region_bound: ty::ReScope(free_id_scope),
|
||||
caller_bounds: bounds,
|
||||
|
@ -6516,57 +6546,76 @@ impl BorrowKind {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> mc::Typer<'tcx> for ty::ctxt<'tcx> {
|
||||
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
|
||||
self
|
||||
impl<'tcx> ctxt<'tcx> {
|
||||
pub fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
||||
-> ast::CaptureClause {
|
||||
self.capture_modes.borrow()[closure_expr_id].clone()
|
||||
}
|
||||
|
||||
fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
|
||||
ty::node_id_to_type(self, id)
|
||||
pub fn is_method_call(&self, expr_id: ast::NodeId) -> bool {
|
||||
self.method_map.borrow().contains_key(&MethodCall::expr(expr_id))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx> mc::Typer<'tcx> for ParameterEnvironment<'a,'tcx> {
|
||||
fn tcx(&self) -> &ty::ctxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx> {
|
||||
ty::expr_ty_adjusted(self, expr)
|
||||
fn node_ty(&self, id: ast::NodeId) -> mc::McResult<Ty<'tcx>> {
|
||||
Ok(ty::node_id_to_type(self.tcx, id))
|
||||
}
|
||||
|
||||
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> mc::McResult<Ty<'tcx>> {
|
||||
Ok(ty::expr_ty_adjusted(self.tcx, expr))
|
||||
}
|
||||
|
||||
fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>> {
|
||||
self.method_map.borrow().get(&method_call).map(|method| method.ty)
|
||||
self.tcx.method_map.borrow().get(&method_call).map(|method| method.ty)
|
||||
}
|
||||
|
||||
fn node_method_origin(&self, method_call: ty::MethodCall)
|
||||
-> Option<ty::MethodOrigin<'tcx>>
|
||||
{
|
||||
self.method_map.borrow().get(&method_call).map(|method| method.origin.clone())
|
||||
self.tcx.method_map.borrow().get(&method_call).map(|method| method.origin.clone())
|
||||
}
|
||||
|
||||
fn adjustments<'a>(&'a self) -> &'a RefCell<NodeMap<ty::AutoAdjustment<'tcx>>> {
|
||||
&self.adjustments
|
||||
fn adjustments(&self) -> &RefCell<NodeMap<ty::AutoAdjustment<'tcx>>> {
|
||||
&self.tcx.adjustments
|
||||
}
|
||||
|
||||
fn is_method_call(&self, id: ast::NodeId) -> bool {
|
||||
self.method_map.borrow().contains_key(&MethodCall::expr(id))
|
||||
self.tcx.is_method_call(id)
|
||||
}
|
||||
|
||||
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<region::CodeExtent> {
|
||||
self.region_maps.temporary_scope(rvalue_id)
|
||||
self.tcx.region_maps.temporary_scope(rvalue_id)
|
||||
}
|
||||
|
||||
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow> {
|
||||
Some(self.upvar_borrow_map.borrow()[upvar_id].clone())
|
||||
Some(self.tcx.upvar_borrow_map.borrow()[upvar_id].clone())
|
||||
}
|
||||
|
||||
fn capture_mode(&self, closure_expr_id: ast::NodeId)
|
||||
-> ast::CaptureClause {
|
||||
self.capture_modes.borrow()[closure_expr_id].clone()
|
||||
self.tcx.capture_mode(closure_expr_id)
|
||||
}
|
||||
|
||||
fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
|
||||
type_moves_by_default(self, span, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UnboxedClosureTyper<'tcx> for ty::ctxt<'tcx> {
|
||||
impl<'a,'tcx> UnboxedClosureTyper<'tcx> for ty::ParameterEnvironment<'a,'tcx> {
|
||||
fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> {
|
||||
self
|
||||
}
|
||||
|
||||
fn unboxed_closure_kind(&self,
|
||||
def_id: ast::DefId)
|
||||
-> ty::UnboxedClosureKind
|
||||
{
|
||||
self.unboxed_closures.borrow()[def_id].kind
|
||||
self.tcx.unboxed_closure_kind(def_id)
|
||||
}
|
||||
|
||||
fn unboxed_closure_type(&self,
|
||||
|
@ -6574,7 +6623,7 @@ impl<'tcx> UnboxedClosureTyper<'tcx> for ty::ctxt<'tcx> {
|
|||
substs: &subst::Substs<'tcx>)
|
||||
-> ty::ClosureTy<'tcx>
|
||||
{
|
||||
self.unboxed_closures.borrow()[def_id].closure_type.subst(self, substs)
|
||||
self.tcx.unboxed_closure_type(def_id, substs)
|
||||
}
|
||||
|
||||
fn unboxed_closure_upvars(&self,
|
||||
|
@ -6941,15 +6990,18 @@ pub enum CopyImplementationError {
|
|||
TypeIsStructural,
|
||||
}
|
||||
|
||||
pub fn can_type_implement_copy<'tcx>(tcx: &ctxt<'tcx>,
|
||||
self_type: Ty<'tcx>,
|
||||
param_env: &ParameterEnvironment<'tcx>)
|
||||
-> Result<(),CopyImplementationError> {
|
||||
pub fn can_type_implement_copy<'a,'tcx>(param_env: &ParameterEnvironment<'a, 'tcx>,
|
||||
span: Span,
|
||||
self_type: Ty<'tcx>)
|
||||
-> Result<(),CopyImplementationError>
|
||||
{
|
||||
let tcx = param_env.tcx;
|
||||
|
||||
match self_type.sty {
|
||||
ty::ty_struct(struct_did, substs) => {
|
||||
let fields = ty::struct_fields(tcx, struct_did, substs);
|
||||
for field in fields.iter() {
|
||||
if type_moves_by_default(tcx, field.mt.ty, param_env) {
|
||||
if type_moves_by_default(param_env, span, field.mt.ty) {
|
||||
return Err(FieldDoesNotImplementCopy(field.name))
|
||||
}
|
||||
}
|
||||
|
@ -6960,9 +7012,7 @@ pub fn can_type_implement_copy<'tcx>(tcx: &ctxt<'tcx>,
|
|||
for variant_arg_type in variant.args.iter() {
|
||||
let substd_arg_type =
|
||||
variant_arg_type.subst(tcx, substs);
|
||||
if type_moves_by_default(tcx,
|
||||
substd_arg_type,
|
||||
param_env) {
|
||||
if type_moves_by_default(param_env, span, substd_arg_type) {
|
||||
return Err(VariantDoesNotImplementCopy(variant.name))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ struct CheckLoanCtxt<'a, 'tcx: 'a> {
|
|||
dfcx_loans: &'a LoanDataFlow<'a, 'tcx>,
|
||||
move_data: move_data::FlowedMoveData<'a, 'tcx>,
|
||||
all_loans: &'a [Loan<'tcx>],
|
||||
param_env: &'a ty::ParameterEnvironment<'tcx>,
|
||||
param_env: &'a ty::ParameterEnvironment<'a, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
|
||||
|
@ -208,9 +208,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
|||
};
|
||||
|
||||
{
|
||||
let mut euv = euv::ExprUseVisitor::new(&mut clcx,
|
||||
bccx.tcx,
|
||||
¶m_env);
|
||||
let mut euv = euv::ExprUseVisitor::new(&mut clcx, ¶m_env);
|
||||
euv.walk_fn(decl, body);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,9 +51,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
|||
let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
|
||||
|
||||
{
|
||||
let mut euv = euv::ExprUseVisitor::new(&mut glcx,
|
||||
bccx.tcx,
|
||||
¶m_env);
|
||||
let mut euv = euv::ExprUseVisitor::new(&mut glcx, ¶m_env);
|
||||
euv.walk_fn(decl, body);
|
||||
}
|
||||
|
||||
|
@ -485,13 +483,15 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
|
|||
/// This visitor walks static initializer's expressions and makes
|
||||
/// sure the loans being taken are sound.
|
||||
struct StaticInitializerCtxt<'a, 'tcx: 'a> {
|
||||
bccx: &'a BorrowckCtxt<'a, 'tcx>
|
||||
bccx: &'a BorrowckCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &Expr) {
|
||||
if let ast::ExprAddrOf(mutbl, ref base) = ex.node {
|
||||
let base_cmt = self.bccx.cat_expr(&**base);
|
||||
let param_env = ty::empty_parameter_environment(self.bccx.tcx);
|
||||
let mc = mc::MemCategorizationContext::new(¶m_env);
|
||||
let base_cmt = mc.cat_expr(&**base).unwrap();
|
||||
let borrow_kind = ty::BorrowKind::from_mutbl(mutbl);
|
||||
// Check that we don't allow borrows of unsafe static items.
|
||||
if check_aliasability(self.bccx, ex.span, euv::AddrOf,
|
||||
|
|
|
@ -511,14 +511,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
self.tcx.region_maps.is_subregion_of(r_sub, r_sup)
|
||||
}
|
||||
|
||||
pub fn mc(&self) -> mc::MemCategorizationContext<'a, ty::ctxt<'tcx>> {
|
||||
mc::MemCategorizationContext::new(self.tcx)
|
||||
}
|
||||
|
||||
pub fn cat_expr(&self, expr: &ast::Expr) -> mc::cmt<'tcx> {
|
||||
self.mc().cat_expr(expr)
|
||||
}
|
||||
|
||||
pub fn report(&self, err: BckError<'tcx>) {
|
||||
self.span_err(
|
||||
err.span,
|
||||
|
@ -526,13 +518,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
self.note_and_explain_bckerr(err);
|
||||
}
|
||||
|
||||
pub fn report_use_of_moved_value(&self,
|
||||
use_span: Span,
|
||||
use_kind: MovedValueUseKind,
|
||||
lp: &LoanPath<'tcx>,
|
||||
the_move: &move_data::Move,
|
||||
moved_lp: &LoanPath<'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>) {
|
||||
pub fn report_use_of_moved_value<'b>(&self,
|
||||
use_span: Span,
|
||||
use_kind: MovedValueUseKind,
|
||||
lp: &LoanPath<'tcx>,
|
||||
the_move: &move_data::Move,
|
||||
moved_lp: &LoanPath<'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'b,'tcx>) {
|
||||
let verb = match use_kind {
|
||||
MovedInUse => "use",
|
||||
MovedInCapture => "capture",
|
||||
|
@ -608,8 +600,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
r)[])
|
||||
}
|
||||
};
|
||||
let (suggestion, _) = move_suggestion(self.tcx, param_env, expr_ty,
|
||||
("moved by default", ""));
|
||||
let (suggestion, _) =
|
||||
move_suggestion(param_env, expr_span, expr_ty, ("moved by default", ""));
|
||||
self.tcx.sess.span_note(
|
||||
expr_span,
|
||||
format!("`{}` moved here{} because it has type `{}`, which is {}",
|
||||
|
@ -646,11 +638,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
r)[])
|
||||
}
|
||||
};
|
||||
let (suggestion, help) = move_suggestion(self.tcx,
|
||||
param_env,
|
||||
expr_ty,
|
||||
("moved by default", "make a copy and \
|
||||
capture that instead to override"));
|
||||
let (suggestion, help) =
|
||||
move_suggestion(param_env,
|
||||
expr_span,
|
||||
expr_ty,
|
||||
("moved by default",
|
||||
"make a copy and capture that instead to override"));
|
||||
self.tcx.sess.span_note(
|
||||
expr_span,
|
||||
format!("`{}` moved into closure environment here{} because it \
|
||||
|
@ -663,22 +656,27 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn move_suggestion<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
default_msgs: (&'static str, &'static str))
|
||||
-> (&'static str, &'static str) {
|
||||
fn move_suggestion<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
default_msgs: (&'static str, &'static str))
|
||||
-> (&'static str, &'static str) {
|
||||
match ty.sty {
|
||||
ty::ty_closure(box ty::ClosureTy {
|
||||
store: ty::RegionTraitStore(..),
|
||||
..
|
||||
}) =>
|
||||
store: ty::RegionTraitStore(..),
|
||||
..
|
||||
}) => {
|
||||
("a non-copyable stack closure",
|
||||
"capture it in a new closure, e.g. `|x| f(x)`, to override"),
|
||||
_ if ty::type_moves_by_default(tcx, ty, param_env) =>
|
||||
("non-copyable",
|
||||
"perhaps you meant to use `clone()`?"),
|
||||
_ => default_msgs,
|
||||
"capture it in a new closure, e.g. `|x| f(x)`, to override")
|
||||
}
|
||||
_ => {
|
||||
if ty::type_moves_by_default(param_env, span, ty) {
|
||||
("non-copyable",
|
||||
"perhaps you meant to use `clone()`?")
|
||||
} else {
|
||||
default_msgs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -991,7 +989,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn cmt_to_string(&self, cmt: &mc::cmt_<'tcx>) -> String {
|
||||
self.mc().cmt_to_string(cmt)
|
||||
cmt.descriptive_string(self.tcx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -542,7 +542,7 @@ fn enter_opt<'a, 'p, 'blk, 'tcx>(
|
|||
check_match::Constructor::Variant(def_id)
|
||||
};
|
||||
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let param_env = ty::empty_parameter_environment(bcx.tcx());
|
||||
let mcx = check_match::MatchCheckCtxt {
|
||||
tcx: bcx.tcx(),
|
||||
param_env: param_env,
|
||||
|
@ -1008,7 +1008,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|||
|
||||
let mcx = check_match::MatchCheckCtxt {
|
||||
tcx: bcx.tcx(),
|
||||
param_env: ty::empty_parameter_environment(),
|
||||
param_env: ty::empty_parameter_environment(bcx.tcx()),
|
||||
};
|
||||
let adt_vals = if any_irrefutable_adt_pat(bcx.tcx(), m, col) {
|
||||
let repr = adt::represent_type(bcx.ccx(), left_ty);
|
||||
|
@ -1262,8 +1262,7 @@ fn is_discr_reassigned(bcx: Block, discr: &ast::Expr, body: &ast::Expr) -> bool
|
|||
reassigned: false
|
||||
};
|
||||
{
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let mut visitor = euv::ExprUseVisitor::new(&mut rc, bcx, ¶m_env);
|
||||
let mut visitor = euv::ExprUseVisitor::new(&mut rc, bcx);
|
||||
visitor.walk_expr(body);
|
||||
}
|
||||
rc.reassigned
|
||||
|
@ -1321,15 +1320,14 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &ast::Pat,
|
|||
let variable_ty = node_id_type(bcx, p_id);
|
||||
let llvariable_ty = type_of::type_of(ccx, variable_ty);
|
||||
let tcx = bcx.tcx();
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let param_env = ty::empty_parameter_environment(tcx);
|
||||
|
||||
let llmatch;
|
||||
let trmode;
|
||||
match bm {
|
||||
ast::BindByValue(_)
|
||||
if !ty::type_moves_by_default(tcx,
|
||||
variable_ty,
|
||||
¶m_env) || reassigned => {
|
||||
if !ty::type_moves_by_default(¶m_env, span, variable_ty) || reassigned =>
|
||||
{
|
||||
llmatch = alloca_no_lifetime(bcx,
|
||||
llvariable_ty.ptr_to(),
|
||||
"__llmatch");
|
||||
|
|
|
@ -61,7 +61,7 @@ use trans::datum;
|
|||
use trans::machine;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, Ty, UnboxedClosureTyper};
|
||||
use middle::ty::Disr;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
|
@ -168,7 +168,8 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
Univariant(mk_struct(cx, ftys[], packed, t), dtor)
|
||||
}
|
||||
ty::ty_unboxed_closure(def_id, _, substs) => {
|
||||
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs).unwrap();
|
||||
let typer = NormalizingUnboxedClosureTyper::new(cx.tcx());
|
||||
let upvars = typer.unboxed_closure_upvars(def_id, substs).unwrap();
|
||||
let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
|
||||
Univariant(mk_struct(cx, upvar_types[], false, t), false)
|
||||
}
|
||||
|
|
|
@ -731,7 +731,8 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
|
|||
}
|
||||
ty::ty_unboxed_closure(def_id, _, substs) => {
|
||||
let repr = adt::represent_type(cx.ccx(), t);
|
||||
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs).unwrap();
|
||||
let typer = common::NormalizingUnboxedClosureTyper::new(cx.tcx());
|
||||
let upvars = typer.unboxed_closure_upvars(def_id, substs).unwrap();
|
||||
for (i, upvar) in upvars.iter().enumerate() {
|
||||
let llupvar = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i);
|
||||
cx = f(cx, llupvar, upvar.ty);
|
||||
|
@ -1451,6 +1452,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
|||
llfn: llfndecl,
|
||||
llenv: None,
|
||||
llretslotptr: Cell::new(None),
|
||||
param_env: ty::empty_parameter_environment(ccx.tcx()),
|
||||
alloca_insert_pt: Cell::new(None),
|
||||
llreturn: Cell::new(None),
|
||||
needs_ret_allocas: nested_returns,
|
||||
|
|
|
@ -302,6 +302,9 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
|
|||
// section of the executable we're generating.
|
||||
pub llfn: ValueRef,
|
||||
|
||||
// always an empty parameter-environment
|
||||
pub param_env: ty::ParameterEnvironment<'a, 'tcx>,
|
||||
|
||||
// The environment argument in a closure.
|
||||
pub llenv: Option<ValueRef>,
|
||||
|
||||
|
@ -579,12 +582,12 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
|
|||
self.tcx()
|
||||
}
|
||||
|
||||
fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
|
||||
node_id_type(self, id)
|
||||
fn node_ty(&self, id: ast::NodeId) -> mc::McResult<Ty<'tcx>> {
|
||||
Ok(node_id_type(self, id))
|
||||
}
|
||||
|
||||
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx> {
|
||||
expr_ty_adjusted(self, expr)
|
||||
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> mc::McResult<Ty<'tcx>> {
|
||||
Ok(expr_ty_adjusted(self, expr))
|
||||
}
|
||||
|
||||
fn node_method_ty(&self, method_call: ty::MethodCall) -> Option<Ty<'tcx>> {
|
||||
|
@ -625,9 +628,17 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
|
|||
-> ast::CaptureClause {
|
||||
self.tcx().capture_modes.borrow()[closure_expr_id].clone()
|
||||
}
|
||||
|
||||
fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
|
||||
self.fcx.param_env.type_moves_by_default(span, ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'blk, 'tcx> ty::UnboxedClosureTyper<'tcx> for BlockS<'blk, 'tcx> {
|
||||
fn param_env<'a>(&'a self) -> &'a ty::ParameterEnvironment<'a, 'tcx> {
|
||||
&self.fcx.param_env
|
||||
}
|
||||
|
||||
fn unboxed_closure_kind(&self,
|
||||
def_id: ast::DefId)
|
||||
-> ty::UnboxedClosureKind
|
||||
|
@ -941,14 +952,10 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id());
|
||||
let infcx = infer::new_infer_ctxt(tcx);
|
||||
|
||||
// Parameter environment is used to give details about type parameters,
|
||||
// but since we are in trans, everything is fully monomorphized.
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
|
||||
// Do the initial selection for the obligation. This yields the
|
||||
// shallow result we are looking for -- that is, what specific impl.
|
||||
let typer = NormalizingUnboxedClosureTyper::new(infcx.tcx);
|
||||
let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, &typer);
|
||||
let typer = NormalizingUnboxedClosureTyper::new(tcx);
|
||||
let mut selcx = traits::SelectionContext::new(&infcx, &typer);
|
||||
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
|
||||
trait_ref.to_poly_trait_predicate());
|
||||
let selection = match selcx.select(&obligation) {
|
||||
|
@ -983,7 +990,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
let vtable = selection.map_move_nested(|predicate| {
|
||||
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
||||
});
|
||||
let vtable = drain_fulfillment_cx(span, &infcx, ¶m_env, &mut fulfill_cx, &vtable);
|
||||
let vtable = drain_fulfillment_cx(span, &infcx, &mut fulfill_cx, &vtable);
|
||||
|
||||
info!("Cache miss: {}", trait_ref.repr(ccx.tcx()));
|
||||
ccx.trait_cache().borrow_mut().insert(trait_ref,
|
||||
|
@ -993,21 +1000,27 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
|
||||
pub struct NormalizingUnboxedClosureTyper<'a,'tcx:'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>
|
||||
param_env: ty::ParameterEnvironment<'a, 'tcx>
|
||||
}
|
||||
|
||||
impl<'a,'tcx> NormalizingUnboxedClosureTyper<'a,'tcx> {
|
||||
pub fn new(tcx: &'a ty::ctxt<'tcx>) -> NormalizingUnboxedClosureTyper<'a,'tcx> {
|
||||
NormalizingUnboxedClosureTyper { tcx: tcx }
|
||||
// Parameter environment is used to give details about type parameters,
|
||||
// but since we are in trans, everything is fully monomorphized.
|
||||
NormalizingUnboxedClosureTyper { param_env: ty::empty_parameter_environment(tcx) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx> ty::UnboxedClosureTyper<'tcx> for NormalizingUnboxedClosureTyper<'a,'tcx> {
|
||||
fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> {
|
||||
&self.param_env
|
||||
}
|
||||
|
||||
fn unboxed_closure_kind(&self,
|
||||
def_id: ast::DefId)
|
||||
-> ty::UnboxedClosureKind
|
||||
{
|
||||
self.tcx.unboxed_closure_kind(def_id)
|
||||
self.param_env.tcx.unboxed_closure_kind(def_id)
|
||||
}
|
||||
|
||||
fn unboxed_closure_type(&self,
|
||||
|
@ -1017,8 +1030,8 @@ impl<'a,'tcx> ty::UnboxedClosureTyper<'tcx> for NormalizingUnboxedClosureTyper<'
|
|||
{
|
||||
// the substitutions in `substs` are already monomorphized,
|
||||
// but we still must normalize associated types
|
||||
let closure_ty = self.tcx.unboxed_closure_type(def_id, substs);
|
||||
monomorphize::normalize_associated_type(self.tcx, &closure_ty)
|
||||
let closure_ty = self.param_env.tcx.unboxed_closure_type(def_id, substs);
|
||||
monomorphize::normalize_associated_type(self.param_env.tcx, &closure_ty)
|
||||
}
|
||||
|
||||
fn unboxed_closure_upvars(&self,
|
||||
|
@ -1028,14 +1041,13 @@ impl<'a,'tcx> ty::UnboxedClosureTyper<'tcx> for NormalizingUnboxedClosureTyper<'
|
|||
{
|
||||
// the substitutions in `substs` are already monomorphized,
|
||||
// but we still must normalize associated types
|
||||
let result = ty::unboxed_closure_upvars(self.tcx, def_id, substs);
|
||||
monomorphize::normalize_associated_type(self.tcx, &result)
|
||||
let result = ty::unboxed_closure_upvars(&self.param_env, def_id, substs);
|
||||
monomorphize::normalize_associated_type(self.param_env.tcx, &result)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
|
||||
infcx: &infer::InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
|
||||
result: &T)
|
||||
-> T
|
||||
|
@ -1048,7 +1060,7 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
|
|||
// contains unbound type parameters. It could be a slight
|
||||
// optimization to stop iterating early.
|
||||
let typer = NormalizingUnboxedClosureTyper::new(infcx.tcx);
|
||||
match fulfill_cx.select_all_or_error(infcx, param_env, &typer) {
|
||||
match fulfill_cx.select_all_or_error(infcx, &typer) {
|
||||
Ok(()) => { }
|
||||
Err(errors) => {
|
||||
if errors.iter().all(|e| e.is_overflow()) {
|
||||
|
|
|
@ -28,6 +28,7 @@ use util::ppaux::{ty_to_string};
|
|||
|
||||
use std::fmt;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
|
||||
/// A `Datum` encapsulates the result of evaluating an expression. It
|
||||
/// describes where the value is stored, what Rust type the value has,
|
||||
|
@ -543,8 +544,9 @@ impl<'tcx, K: KindOps + fmt::Show> Datum<'tcx, K> {
|
|||
* affine values (since they must never be duplicated).
|
||||
*/
|
||||
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
assert!(!ty::type_moves_by_default(bcx.tcx(), self.ty, ¶m_env));
|
||||
assert!(!ty::type_moves_by_default(&ty::empty_parameter_environment(bcx.tcx()),
|
||||
DUMMY_SP,
|
||||
self.ty));
|
||||
self.shallow_copy_raw(bcx, dst)
|
||||
}
|
||||
|
||||
|
|
|
@ -322,9 +322,8 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
|
|||
// FIXME(#20304) -- cache
|
||||
|
||||
let infcx = infer::new_infer_ctxt(tcx);
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let typer = NormalizingUnboxedClosureTyper::new(infcx.tcx);
|
||||
let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, &typer);
|
||||
let typer = NormalizingUnboxedClosureTyper::new(tcx);
|
||||
let mut selcx = traits::SelectionContext::new(&infcx, &typer);
|
||||
let cause = traits::ObligationCause::dummy();
|
||||
let traits::Normalized { value: result, obligations } =
|
||||
traits::normalize(&mut selcx, cause, value);
|
||||
|
@ -337,7 +336,7 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
|
|||
for obligation in obligations.into_iter() {
|
||||
fulfill_cx.register_predicate_obligation(&infcx, obligation);
|
||||
}
|
||||
let result = drain_fulfillment_cx(DUMMY_SP, &infcx, ¶m_env, &mut fulfill_cx, &result);
|
||||
let result = drain_fulfillment_cx(DUMMY_SP, &infcx, &mut fulfill_cx, &result);
|
||||
|
||||
result
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ use syntax::codemap::Span;
|
|||
use util::ppaux::Repr;
|
||||
|
||||
pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
typer: &(ty::UnboxedClosureTyper<'tcx>+'a),
|
||||
fulfillment_cx: &mut FulfillmentContext<'tcx>,
|
||||
span: Span,
|
||||
|
@ -28,7 +27,7 @@ pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
|||
where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
|
||||
{
|
||||
debug!("normalize_associated_types_in(value={})", value.repr(infcx.tcx));
|
||||
let mut selcx = SelectionContext::new(infcx, param_env, typer);
|
||||
let mut selcx = SelectionContext::new(infcx, typer);
|
||||
let cause = ObligationCause::new(span, body_id, MiscObligation);
|
||||
let Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value);
|
||||
debug!("normalize_associated_types_in: result={} predicates={}",
|
||||
|
|
|
@ -169,9 +169,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
|
|||
poly_trait_ref.as_predicate());
|
||||
|
||||
// Now we want to know if this can be matched
|
||||
let mut selcx = traits::SelectionContext::new(fcx.infcx(),
|
||||
&fcx.inh.param_env,
|
||||
fcx);
|
||||
let mut selcx = traits::SelectionContext::new(fcx.infcx(), fcx);
|
||||
if !selcx.evaluate_obligation(&obligation) {
|
||||
debug!("--> Cannot match obligation");
|
||||
return None; // Cannot be matched, no such method resolution is possible.
|
||||
|
|
|
@ -788,9 +788,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
debug!("impl_obligations={}", obligations.repr(self.tcx()));
|
||||
|
||||
// Evaluate those obligations to see if they might possibly hold.
|
||||
let mut selcx = traits::SelectionContext::new(self.infcx(),
|
||||
&self.fcx.inh.param_env,
|
||||
self.fcx);
|
||||
let mut selcx = traits::SelectionContext::new(self.infcx(), self.fcx);
|
||||
obligations.all(|o| selcx.evaluate_obligation(o))
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ use middle::{const_eval, def};
|
|||
use middle::infer;
|
||||
use middle::lang_items::IteratorItem;
|
||||
use middle::mem_categorization as mc;
|
||||
use middle::mem_categorization::McResult;
|
||||
use middle::pat_util::{mod, pat_id_map};
|
||||
use middle::region::CodeExtent;
|
||||
use middle::subst::{mod, Subst, Substs, VecPerParamSpace, ParamSpace};
|
||||
|
@ -129,6 +130,7 @@ pub mod regionmanip;
|
|||
pub mod regionck;
|
||||
pub mod demand;
|
||||
pub mod method;
|
||||
mod upvar;
|
||||
pub mod wf;
|
||||
mod closure;
|
||||
mod callee;
|
||||
|
@ -146,7 +148,7 @@ mod callee;
|
|||
pub struct Inherited<'a, 'tcx: 'a> {
|
||||
infcx: infer::InferCtxt<'a, 'tcx>,
|
||||
locals: RefCell<NodeMap<Ty<'tcx>>>,
|
||||
param_env: ty::ParameterEnvironment<'tcx>,
|
||||
param_env: ty::ParameterEnvironment<'a, 'tcx>,
|
||||
|
||||
// Temporary tables:
|
||||
node_types: RefCell<NodeMap<Ty<'tcx>>>,
|
||||
|
@ -288,13 +290,17 @@ impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxt<'a, 'tcx> {
|
|||
fn tcx(&self) -> &ty::ctxt<'tcx> {
|
||||
self.ccx.tcx
|
||||
}
|
||||
fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> {
|
||||
fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
|
||||
let ty = self.node_ty(id);
|
||||
self.infcx().resolve_type_vars_if_possible(&ty)
|
||||
self.resolve_type_vars_or_error(&ty)
|
||||
}
|
||||
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx> {
|
||||
let ty = self.expr_ty_adjusted(expr);
|
||||
self.infcx().resolve_type_vars_if_possible(&ty)
|
||||
fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
|
||||
let ty = self.adjust_expr_ty(expr, self.inh.adjustments.borrow().get(&expr.id));
|
||||
self.resolve_type_vars_or_error(&ty)
|
||||
}
|
||||
fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool {
|
||||
let ty = self.infcx().resolve_type_vars_if_possible(&ty);
|
||||
traits::type_known_to_meet_builtin_bound(self.infcx(), self, ty, ty::BoundCopy, span)
|
||||
}
|
||||
fn node_method_ty(&self, method_call: ty::MethodCall)
|
||||
-> Option<Ty<'tcx>> {
|
||||
|
@ -317,7 +323,7 @@ impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxt<'a, 'tcx> {
|
|||
self.inh.method_map.borrow().contains_key(&ty::MethodCall::expr(id))
|
||||
}
|
||||
fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option<CodeExtent> {
|
||||
self.tcx().temporary_scope(rvalue_id)
|
||||
self.param_env().temporary_scope(rvalue_id)
|
||||
}
|
||||
fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarBorrow> {
|
||||
self.inh.upvar_borrow_map.borrow().get(&upvar_id).cloned()
|
||||
|
@ -329,6 +335,10 @@ impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> ty::UnboxedClosureTyper<'tcx> for FnCtxt<'a, 'tcx> {
|
||||
fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> {
|
||||
&self.inh.param_env
|
||||
}
|
||||
|
||||
fn unboxed_closure_kind(&self,
|
||||
def_id: ast::DefId)
|
||||
-> ty::UnboxedClosureKind
|
||||
|
@ -355,7 +365,7 @@ impl<'a, 'tcx> ty::UnboxedClosureTyper<'tcx> for FnCtxt<'a, 'tcx> {
|
|||
|
||||
impl<'a, 'tcx> Inherited<'a, 'tcx> {
|
||||
fn new(tcx: &'a ty::ctxt<'tcx>,
|
||||
param_env: ty::ParameterEnvironment<'tcx>)
|
||||
param_env: ty::ParameterEnvironment<'a, 'tcx>)
|
||||
-> Inherited<'a, 'tcx> {
|
||||
Inherited {
|
||||
infcx: infer::new_infer_ctxt(tcx),
|
||||
|
@ -383,7 +393,6 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
|
|||
{
|
||||
let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
|
||||
assoc::normalize_associated_types_in(&self.infcx,
|
||||
&self.param_env,
|
||||
typer,
|
||||
&mut *fulfillment_cx, span,
|
||||
body_id,
|
||||
|
@ -413,7 +422,7 @@ fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>)
|
|||
-> Inherited<'a, 'tcx> {
|
||||
// It's kind of a kludge to manufacture a fake function context
|
||||
// and statement context, but we might as well do write the code only once
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let param_env = ty::empty_parameter_environment(ccx.tcx);
|
||||
Inherited::new(ccx.tcx, param_env)
|
||||
}
|
||||
|
||||
|
@ -457,7 +466,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
body: &ast::Block,
|
||||
id: ast::NodeId,
|
||||
raw_fty: Ty<'tcx>,
|
||||
param_env: ty::ParameterEnvironment<'tcx>) {
|
||||
param_env: ty::ParameterEnvironment<'a, 'tcx>) {
|
||||
match raw_fty.sty {
|
||||
ty::ty_bare_fn(_, ref fn_ty) => {
|
||||
let inh = Inherited::new(ccx.tcx, param_env);
|
||||
|
@ -468,12 +477,13 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
let fn_sig =
|
||||
liberate_late_bound_regions(ccx.tcx, CodeExtent::from_node_id(body.id), &fn_sig);
|
||||
let fn_sig =
|
||||
inh.normalize_associated_types_in(ccx.tcx, body.span, body.id, &fn_sig);
|
||||
inh.normalize_associated_types_in(&inh.param_env, body.span, body.id, &fn_sig);
|
||||
|
||||
let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_sig,
|
||||
decl, id, body, &inh);
|
||||
|
||||
vtable::select_all_fcx_obligations_or_error(&fcx);
|
||||
upvar::closure_analyze_fn(&fcx, id, decl, body);
|
||||
regionck::regionck_fn(&fcx, id, decl, body);
|
||||
writeback::resolve_type_vars_in_fn(&fcx, decl, body);
|
||||
}
|
||||
|
@ -1220,7 +1230,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
let impl_sig =
|
||||
assoc::normalize_associated_types_in(&infcx,
|
||||
&impl_param_env,
|
||||
infcx.tcx,
|
||||
&mut fulfillment_cx,
|
||||
impl_m_span,
|
||||
impl_m_body_id,
|
||||
|
@ -1241,7 +1250,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
let trait_sig =
|
||||
assoc::normalize_associated_types_in(&infcx,
|
||||
&impl_param_env,
|
||||
infcx.tcx,
|
||||
&mut fulfillment_cx,
|
||||
impl_m_span,
|
||||
impl_m_body_id,
|
||||
|
@ -1277,7 +1285,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
|
||||
// Run the fulfillment context to completion to accommodate any
|
||||
// associated type normalizations that may have occurred.
|
||||
match fulfillment_cx.select_all_or_error(&infcx, &impl_param_env, tcx) {
|
||||
match fulfillment_cx.select_all_or_error(&infcx, &impl_param_env) {
|
||||
Ok(()) => { }
|
||||
Err(errors) => {
|
||||
traits::report_fulfillment_errors(&infcx, &errors);
|
||||
|
@ -1457,7 +1465,7 @@ fn check_cast(fcx: &FnCtxt,
|
|||
return
|
||||
}
|
||||
|
||||
if !fcx.type_is_known_to_be_sized(t_1) {
|
||||
if !fcx.type_is_known_to_be_sized(t_1, cast_expr.span) {
|
||||
let tstr = fcx.infcx().ty_to_string(t_1);
|
||||
fcx.type_error_message(span, |actual| {
|
||||
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
|
||||
|
@ -1655,11 +1663,11 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
|||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx }
|
||||
|
||||
pub fn infcx(&self) -> &infer::InferCtxt<'a, 'tcx> {
|
||||
pub fn infcx(&self) -> &infer::InferCtxt<'a,'tcx> {
|
||||
&self.inh.infcx
|
||||
}
|
||||
|
||||
pub fn param_env(&self) -> &ty::ParameterEnvironment<'tcx> {
|
||||
pub fn param_env(&self) -> &ty::ParameterEnvironment<'a,'tcx> {
|
||||
&self.inh.param_env
|
||||
}
|
||||
|
||||
|
@ -1671,6 +1679,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.ccx.tcx.sess.err_count() - self.err_count_on_creation
|
||||
}
|
||||
|
||||
/// Resolves all type variables in `t` and then, if any were left
|
||||
/// unresolved, substitutes an error type. This is used after the
|
||||
/// main checking when doing a second pass before writeback. The
|
||||
/// justification is that writeback will produce an error for
|
||||
/// these unconstrained type variables.
|
||||
fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult<Ty<'tcx>> {
|
||||
let t = self.infcx().resolve_type_vars_if_possible(t);
|
||||
if ty::type_has_ty_infer(t) || ty::type_is_error(t) { Err(()) } else { Ok(t) }
|
||||
}
|
||||
|
||||
pub fn tag(&self) -> String {
|
||||
format!("{}", self as *const FnCtxt)
|
||||
}
|
||||
|
@ -1820,7 +1838,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.normalize_projection_type(self.infcx(),
|
||||
&self.inh.param_env,
|
||||
self,
|
||||
ty::ProjectionTy {
|
||||
trait_ref: trait_ref,
|
||||
|
@ -1966,13 +1983,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn type_is_known_to_be_sized(&self,
|
||||
ty: Ty<'tcx>)
|
||||
ty: Ty<'tcx>,
|
||||
span: Span)
|
||||
-> bool
|
||||
{
|
||||
traits::type_known_to_meet_builtin_bound(self.infcx(),
|
||||
self.param_env(),
|
||||
ty,
|
||||
ty::BoundSized)
|
||||
ty::BoundSized,
|
||||
span)
|
||||
}
|
||||
|
||||
pub fn register_builtin_bound(&self,
|
||||
|
|
|
@ -81,38 +81,6 @@
|
|||
//! traversed. This is essentially the same as the ownership
|
||||
//! relation, except that a borrowed pointer never owns its
|
||||
//! contents.
|
||||
//!
|
||||
//! ### Inferring borrow kinds for upvars
|
||||
//!
|
||||
//! Whenever there is a closure expression, we need to determine how each
|
||||
//! upvar is used. We do this by initially assigning each upvar an
|
||||
//! immutable "borrow kind" (see `ty::BorrowKind` for details) and then
|
||||
//! "escalating" the kind as needed. The borrow kind proceeds according to
|
||||
//! the following lattice:
|
||||
//!
|
||||
//! ty::ImmBorrow -> ty::UniqueImmBorrow -> ty::MutBorrow
|
||||
//!
|
||||
//! So, for example, if we see an assignment `x = 5` to an upvar `x`, we
|
||||
//! will promote its borrow kind to mutable borrow. If we see an `&mut x`
|
||||
//! we'll do the same. Naturally, this applies not just to the upvar, but
|
||||
//! to everything owned by `x`, so the result is the same for something
|
||||
//! like `x.f = 5` and so on (presuming `x` is not a borrowed pointer to a
|
||||
//! struct). These adjustments are performed in
|
||||
//! `adjust_upvar_borrow_kind()` (you can trace backwards through the code
|
||||
//! from there).
|
||||
//!
|
||||
//! The fact that we are inferring borrow kinds as we go results in a
|
||||
//! semi-hacky interaction with mem-categorization. In particular,
|
||||
//! mem-categorization will query the current borrow kind as it
|
||||
//! categorizes, and we'll return the *current* value, but this may get
|
||||
//! adjusted later. Therefore, in this module, we generally ignore the
|
||||
//! borrow kind (and derived mutabilities) that are returned from
|
||||
//! mem-categorization, since they may be inaccurate. (Another option
|
||||
//! would be to use a unification scheme, where instead of returning a
|
||||
//! concrete borrow kind like `ty::ImmBorrow`, we return a
|
||||
//! `ty::InferBorrow(upvar_id)` or something like that, but this would
|
||||
//! then mean that all later passes would have to check for these figments
|
||||
//! and report an error, and it just seems like more mess in the end.)
|
||||
|
||||
use astconv::AstConv;
|
||||
use check::FnCtxt;
|
||||
|
@ -126,7 +94,6 @@ use middle::ty::{ReScope};
|
|||
use middle::ty::{mod, Ty, MethodCall};
|
||||
use middle::infer;
|
||||
use middle::pat_util;
|
||||
use util::nodemap::{FnvHashMap};
|
||||
use util::ppaux::{ty_to_string, Repr};
|
||||
|
||||
use syntax::{ast, ast_util};
|
||||
|
@ -134,12 +101,13 @@ use syntax::codemap::Span;
|
|||
use syntax::visit;
|
||||
use syntax::visit::Visitor;
|
||||
|
||||
use std::cell::{RefCell};
|
||||
use std::collections::hash_map::Entry::{Vacant, Occupied};
|
||||
|
||||
use self::RepeatingScope::Repeating;
|
||||
use self::SubjectNode::Subject;
|
||||
|
||||
// a variation on try that just returns unit
|
||||
macro_rules! ignore_err {
|
||||
($e:expr) => (match $e { Ok(e) => e, Err(_) => return () })
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC ENTRY POINTS
|
||||
|
@ -193,19 +161,6 @@ pub fn regionck_ensure_component_tys_wf<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// INTERNALS
|
||||
|
||||
// Stores parameters for a potential call to link_region()
|
||||
// to perform if an upvar reference is marked unique/mutable after
|
||||
// it has already been processed before.
|
||||
struct MaybeLink<'tcx> {
|
||||
span: Span,
|
||||
borrow_region: ty::Region,
|
||||
borrow_kind: ty::BorrowKind,
|
||||
borrow_cmt: mc::cmt<'tcx>
|
||||
}
|
||||
|
||||
// A map associating an upvar ID to a vector of the above
|
||||
type MaybeLinkMap<'tcx> = RefCell<FnvHashMap<ty::UpvarId, Vec<MaybeLink<'tcx>>>>;
|
||||
|
||||
pub struct Rcx<'a, 'tcx: 'a> {
|
||||
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
|
||||
|
@ -216,10 +171,6 @@ pub struct Rcx<'a, 'tcx: 'a> {
|
|||
|
||||
// id of AST node being analyzed (the subject of the analysis).
|
||||
subject: SubjectNode,
|
||||
|
||||
// Possible region links we will establish if an upvar
|
||||
// turns out to be unique/mutable
|
||||
maybe_links: MaybeLinkMap<'tcx>
|
||||
}
|
||||
|
||||
/// Returns the validity region of `def` -- that is, how long is `def` valid?
|
||||
|
@ -254,8 +205,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
|
|||
Rcx { fcx: fcx,
|
||||
repeating_scope: initial_repeating_scope,
|
||||
subject: subject,
|
||||
region_param_pairs: Vec::new(),
|
||||
maybe_links: RefCell::new(FnvHashMap::new()) }
|
||||
region_param_pairs: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
|
||||
|
@ -586,19 +536,12 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
|||
visit::walk_expr(rcx, expr);
|
||||
}
|
||||
|
||||
ast::ExprAssign(ref lhs, _) => {
|
||||
adjust_borrow_kind_for_assignment_lhs(rcx, &**lhs);
|
||||
visit::walk_expr(rcx, expr);
|
||||
}
|
||||
|
||||
ast::ExprAssignOp(_, ref lhs, ref rhs) => {
|
||||
if has_method_map {
|
||||
constrain_call(rcx, expr, Some(&**lhs),
|
||||
Some(&**rhs).into_iter(), true);
|
||||
}
|
||||
|
||||
adjust_borrow_kind_for_assignment_lhs(rcx, &**lhs);
|
||||
|
||||
visit::walk_expr(rcx, expr);
|
||||
}
|
||||
|
||||
|
@ -834,22 +777,6 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||
visit::walk_expr(rcx, expr);
|
||||
rcx.set_repeating_scope(repeating_scope);
|
||||
|
||||
match function_type.sty {
|
||||
ty::ty_closure(box ty::ClosureTy { store: ty::RegionTraitStore(..), .. }) => {
|
||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||
propagate_upupvar_borrow_kind(rcx, expr, freevars);
|
||||
})
|
||||
}
|
||||
ty::ty_unboxed_closure(..) => {
|
||||
if tcx.capture_modes.borrow()[expr.id].clone() == ast::CaptureByRef {
|
||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||
propagate_upupvar_borrow_kind(rcx, expr, freevars);
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match function_type.sty {
|
||||
ty::ty_closure(box ty::ClosureTy {ref bounds, ..}) => {
|
||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||
|
@ -926,7 +853,6 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||
freevars: &[ty::Freevar])
|
||||
{
|
||||
let tcx = rcx.fcx.ccx.tcx;
|
||||
let infcx = rcx.fcx.infcx();
|
||||
debug!("constrain_free_variables({}, {})",
|
||||
region_bound.repr(tcx), expr.repr(tcx));
|
||||
for freevar in freevars.iter() {
|
||||
|
@ -942,20 +868,10 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||
let upvar_id = ty::UpvarId { var_id: var_node_id,
|
||||
closure_expr_id: expr.id };
|
||||
|
||||
// Create a region variable to represent this borrow. This borrow
|
||||
// must outlive the region on the closure.
|
||||
let origin = infer::UpvarRegion(upvar_id, expr.span);
|
||||
let freevar_region = infcx.next_region_var(origin);
|
||||
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
|
||||
region_bound, freevar_region);
|
||||
let upvar_borrow = rcx.fcx.inh.upvar_borrow_map.borrow()[upvar_id];
|
||||
|
||||
// Create a UpvarBorrow entry. Note that we begin with a
|
||||
// const borrow_kind, but change it to either mut or
|
||||
// immutable as dictated by the uses.
|
||||
let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
|
||||
region: freevar_region };
|
||||
rcx.fcx.inh.upvar_borrow_map.borrow_mut().insert(upvar_id,
|
||||
upvar_borrow);
|
||||
rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id),
|
||||
region_bound, upvar_borrow.region);
|
||||
|
||||
// Guarantee that the closure does not outlive the variable itself.
|
||||
let enclosing_region = region_of_def(rcx.fcx, def);
|
||||
|
@ -964,52 +880,6 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||
region_bound, enclosing_region);
|
||||
}
|
||||
}
|
||||
|
||||
fn propagate_upupvar_borrow_kind(rcx: &mut Rcx,
|
||||
expr: &ast::Expr,
|
||||
freevars: &[ty::Freevar]) {
|
||||
let tcx = rcx.fcx.ccx.tcx;
|
||||
debug!("propagate_upupvar_borrow_kind({})", expr.repr(tcx));
|
||||
for freevar in freevars.iter() {
|
||||
// Because of the semi-hokey way that we are doing
|
||||
// borrow_kind inference, we need to check for
|
||||
// indirect dependencies, like so:
|
||||
//
|
||||
// let mut x = 0;
|
||||
// outer_call(|| {
|
||||
// inner_call(|| {
|
||||
// x = 1;
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// Here, the `inner_call` is basically "reborrowing" the
|
||||
// outer pointer. With no other changes, `inner_call`
|
||||
// would infer that it requires a mutable borrow, but
|
||||
// `outer_call` would infer that a const borrow is
|
||||
// sufficient. This is because we haven't linked the
|
||||
// borrow_kind of the borrow that occurs in the inner
|
||||
// closure to the borrow_kind of the borrow in the outer
|
||||
// closure. Note that regions *are* naturally linked
|
||||
// because we have a proper inference scheme there.
|
||||
//
|
||||
// Anyway, for borrow_kind, we basically go back over now
|
||||
// after checking the inner closure (and hence
|
||||
// determining the final borrow_kind) and propagate that as
|
||||
// a constraint on the outer closure.
|
||||
if let def::DefUpvar(var_id, outer_closure_id, _) = freevar.def {
|
||||
// thing being captured is itself an upvar:
|
||||
let outer_upvar_id = ty::UpvarId {
|
||||
var_id: var_id,
|
||||
closure_expr_id: outer_closure_id };
|
||||
let inner_upvar_id = ty::UpvarId {
|
||||
var_id: var_id,
|
||||
closure_expr_id: expr.id };
|
||||
link_upvar_borrow_kind_for_nested_closures(rcx,
|
||||
inner_upvar_id,
|
||||
outer_upvar_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn constrain_callee(rcx: &mut Rcx,
|
||||
|
@ -1027,7 +897,7 @@ fn constrain_callee(rcx: &mut Rcx,
|
|||
// While we're here, link the closure's region with a unique
|
||||
// immutable borrow (gathered later in borrowck)
|
||||
let mc = mc::MemCategorizationContext::new(rcx.fcx);
|
||||
let expr_cmt = mc.cat_expr(callee_expr);
|
||||
let expr_cmt = ignore_err!(mc.cat_expr(callee_expr));
|
||||
link_region(rcx, callee_expr.span, call_region,
|
||||
ty::UniqueImmBorrow, expr_cmt);
|
||||
r
|
||||
|
@ -1136,7 +1006,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
|
|||
};
|
||||
{
|
||||
let mc = mc::MemCategorizationContext::new(rcx.fcx);
|
||||
let self_cmt = mc.cat_expr_autoderefd(deref_expr, i);
|
||||
let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
|
||||
link_region(rcx, deref_expr.span, *r,
|
||||
ty::BorrowKind::from_mutbl(m), self_cmt);
|
||||
}
|
||||
|
@ -1232,7 +1102,7 @@ fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
|
|||
|
||||
let cmt = {
|
||||
let mc = mc::MemCategorizationContext::new(rcx.fcx);
|
||||
mc.cat_expr(base)
|
||||
ignore_err!(mc.cat_expr(base))
|
||||
};
|
||||
link_region_from_node_type(rcx, expr.span, expr.id, mutability, cmt);
|
||||
}
|
||||
|
@ -1247,7 +1117,7 @@ fn link_local(rcx: &Rcx, local: &ast::Local) {
|
|||
Some(ref expr) => &**expr,
|
||||
};
|
||||
let mc = mc::MemCategorizationContext::new(rcx.fcx);
|
||||
let discr_cmt = mc.cat_expr(init_expr);
|
||||
let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
|
||||
link_pattern(rcx, mc, discr_cmt, &*local.pat);
|
||||
}
|
||||
|
||||
|
@ -1257,7 +1127,7 @@ fn link_local(rcx: &Rcx, local: &ast::Local) {
|
|||
fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) {
|
||||
debug!("regionck::for_match()");
|
||||
let mc = mc::MemCategorizationContext::new(rcx.fcx);
|
||||
let discr_cmt = mc.cat_expr(discr);
|
||||
let discr_cmt = ignore_err!(mc.cat_expr(discr));
|
||||
debug!("discr_cmt={}", discr_cmt.repr(rcx.tcx()));
|
||||
for arm in arms.iter() {
|
||||
for root_pat in arm.pats.iter() {
|
||||
|
@ -1303,11 +1173,14 @@ fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
|||
|
||||
// `[_, ..slice, _]` pattern
|
||||
ast::PatVec(_, Some(ref slice_pat), _) => {
|
||||
let (slice_cmt, slice_mutbl, slice_r) =
|
||||
mc.cat_slice_pattern(sub_cmt, &**slice_pat);
|
||||
link_region(rcx, sub_pat.span, slice_r,
|
||||
ty::BorrowKind::from_mutbl(slice_mutbl),
|
||||
slice_cmt);
|
||||
match mc.cat_slice_pattern(sub_cmt, &**slice_pat) {
|
||||
Ok((slice_cmt, slice_mutbl, slice_r)) => {
|
||||
link_region(rcx, sub_pat.span, slice_r,
|
||||
ty::BorrowKind::from_mutbl(slice_mutbl),
|
||||
slice_cmt);
|
||||
}
|
||||
Err(()) => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -1323,7 +1196,7 @@ fn link_autoref(rcx: &Rcx,
|
|||
|
||||
debug!("link_autoref(autoref={})", autoref);
|
||||
let mc = mc::MemCategorizationContext::new(rcx.fcx);
|
||||
let expr_cmt = mc.cat_expr_autoderefd(expr, autoderefs);
|
||||
let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
|
||||
debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx()));
|
||||
|
||||
match *autoref {
|
||||
|
@ -1345,7 +1218,7 @@ fn link_by_ref(rcx: &Rcx,
|
|||
debug!("link_by_ref(expr={}, callee_scope={})",
|
||||
expr.repr(tcx), callee_scope);
|
||||
let mc = mc::MemCategorizationContext::new(rcx.fcx);
|
||||
let expr_cmt = mc.cat_expr(expr);
|
||||
let expr_cmt = ignore_err!(mc.cat_expr(expr));
|
||||
let borrow_region = ty::ReScope(callee_scope);
|
||||
link_region(rcx, expr.span, borrow_region, ty::ImmBorrow, expr_cmt);
|
||||
}
|
||||
|
@ -1484,14 +1357,6 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
|||
rcx.fcx.inh.upvar_borrow_map.borrow_mut();
|
||||
match upvar_borrow_map.get_mut(upvar_id) {
|
||||
Some(upvar_borrow) => {
|
||||
// Adjust mutability that we infer for the upvar
|
||||
// so it can accommodate being borrowed with
|
||||
// mutability `kind`:
|
||||
adjust_upvar_borrow_kind_for_loan(rcx,
|
||||
*upvar_id,
|
||||
upvar_borrow,
|
||||
borrow_kind);
|
||||
|
||||
// The mutability of the upvar may have been modified
|
||||
// by the above adjustment, so update our local variable.
|
||||
ref_kind = upvar_borrow.kind;
|
||||
|
@ -1576,27 +1441,6 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
|||
// else the user is borrowed imm memory as mut memory,
|
||||
// which means they'll get an error downstream in borrowck
|
||||
// anyhow.)
|
||||
//
|
||||
// If mutability was inferred from an upvar, we may be
|
||||
// forced to revisit this decision later if processing
|
||||
// another borrow or nested closure ends up converting the
|
||||
// upvar borrow kind to mutable/unique. Record the
|
||||
// information needed to perform the recursive link in the
|
||||
// maybe link map.
|
||||
if let mc::NoteUpvarRef(upvar_id) = note {
|
||||
let link = MaybeLink {
|
||||
span: span,
|
||||
borrow_region: borrow_region,
|
||||
borrow_kind: new_borrow_kind,
|
||||
borrow_cmt: ref_cmt
|
||||
};
|
||||
|
||||
match rcx.maybe_links.borrow_mut().entry(upvar_id) {
|
||||
Vacant(entry) => { entry.set(vec![link]); }
|
||||
Occupied(entry) => { entry.into_mut().push(link); }
|
||||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -1608,178 +1452,6 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
/// Adjusts the inferred borrow_kind as needed to account for upvars that are assigned to in an
|
||||
/// assignment expression.
|
||||
fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
|
||||
lhs: &ast::Expr) {
|
||||
let mc = mc::MemCategorizationContext::new(rcx.fcx);
|
||||
let cmt = mc.cat_expr(lhs);
|
||||
adjust_upvar_borrow_kind_for_mut(rcx, cmt);
|
||||
}
|
||||
|
||||
/// Indicates that `cmt` is being directly mutated (e.g., assigned to). If cmt contains any by-ref
|
||||
/// upvars, this implies that those upvars must be borrowed using an `&mut` borow.
|
||||
fn adjust_upvar_borrow_kind_for_mut<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
||||
cmt: mc::cmt<'tcx>) {
|
||||
let mut cmt = cmt;
|
||||
loop {
|
||||
debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",
|
||||
cmt.repr(rcx.tcx()));
|
||||
|
||||
match cmt.cat.clone() {
|
||||
mc::cat_deref(base, _, mc::Unique) |
|
||||
mc::cat_interior(base, _) |
|
||||
mc::cat_downcast(base, _) => {
|
||||
// Interior or owned data is mutable if base is
|
||||
// mutable, so iterate to the base.
|
||||
cmt = base;
|
||||
continue;
|
||||
}
|
||||
|
||||
mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
|
||||
mc::cat_deref(base, _, mc::Implicit(..)) => {
|
||||
if let mc::NoteUpvarRef(ref upvar_id) = cmt.note {
|
||||
// if this is an implicit deref of an
|
||||
// upvar, then we need to modify the
|
||||
// borrow_kind of the upvar to make sure it
|
||||
// is inferred to mutable if necessary
|
||||
let mut upvar_borrow_map =
|
||||
rcx.fcx.inh.upvar_borrow_map.borrow_mut();
|
||||
let ub = &mut (*upvar_borrow_map)[*upvar_id];
|
||||
return adjust_upvar_borrow_kind(rcx, *upvar_id, ub, ty::MutBorrow);
|
||||
}
|
||||
|
||||
// assignment to deref of an `&mut`
|
||||
// borrowed pointer implies that the
|
||||
// pointer itself must be unique, but not
|
||||
// necessarily *mutable*
|
||||
return adjust_upvar_borrow_kind_for_unique(rcx, base);
|
||||
}
|
||||
|
||||
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
|
||||
mc::cat_static_item |
|
||||
mc::cat_rvalue(_) |
|
||||
mc::cat_local(_) |
|
||||
mc::cat_upvar(..) => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn adjust_upvar_borrow_kind_for_unique<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, cmt: mc::cmt<'tcx>) {
|
||||
let mut cmt = cmt;
|
||||
loop {
|
||||
debug!("adjust_upvar_borrow_kind_for_unique(cmt={})",
|
||||
cmt.repr(rcx.tcx()));
|
||||
|
||||
match cmt.cat.clone() {
|
||||
mc::cat_deref(base, _, mc::Unique) |
|
||||
mc::cat_interior(base, _) |
|
||||
mc::cat_downcast(base, _) => {
|
||||
// Interior or owned data is unique if base is
|
||||
// unique.
|
||||
cmt = base;
|
||||
continue;
|
||||
}
|
||||
|
||||
mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
|
||||
mc::cat_deref(base, _, mc::Implicit(..)) => {
|
||||
if let mc::NoteUpvarRef(ref upvar_id) = cmt.note {
|
||||
// if this is an implicit deref of an
|
||||
// upvar, then we need to modify the
|
||||
// borrow_kind of the upvar to make sure it
|
||||
// is inferred to unique if necessary
|
||||
let mut ub = rcx.fcx.inh.upvar_borrow_map.borrow_mut();
|
||||
let ub = &mut (*ub)[*upvar_id];
|
||||
return adjust_upvar_borrow_kind(rcx, *upvar_id, ub, ty::UniqueImmBorrow);
|
||||
}
|
||||
|
||||
// for a borrowed pointer to be unique, its
|
||||
// base must be unique
|
||||
return adjust_upvar_borrow_kind_for_unique(rcx, base);
|
||||
}
|
||||
|
||||
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
|
||||
mc::cat_static_item |
|
||||
mc::cat_rvalue(_) |
|
||||
mc::cat_local(_) |
|
||||
mc::cat_upvar(..) => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates that the borrow_kind of `outer_upvar_id` must permit a reborrowing with the
|
||||
/// borrow_kind of `inner_upvar_id`. This occurs in nested closures, see comment above at the call
|
||||
/// to this function.
|
||||
fn link_upvar_borrow_kind_for_nested_closures(rcx: &mut Rcx,
|
||||
inner_upvar_id: ty::UpvarId,
|
||||
outer_upvar_id: ty::UpvarId) {
|
||||
debug!("link_upvar_borrow_kind: inner_upvar_id={} outer_upvar_id={}",
|
||||
inner_upvar_id, outer_upvar_id);
|
||||
|
||||
let mut upvar_borrow_map = rcx.fcx.inh.upvar_borrow_map.borrow_mut();
|
||||
let inner_borrow = upvar_borrow_map[inner_upvar_id].clone();
|
||||
match upvar_borrow_map.get_mut(&outer_upvar_id) {
|
||||
Some(outer_borrow) => {
|
||||
adjust_upvar_borrow_kind(rcx, outer_upvar_id, outer_borrow, inner_borrow.kind);
|
||||
}
|
||||
None => { /* outer closure is not a stack closure */ }
|
||||
}
|
||||
}
|
||||
|
||||
fn adjust_upvar_borrow_kind_for_loan(rcx: &Rcx,
|
||||
upvar_id: ty::UpvarId,
|
||||
upvar_borrow: &mut ty::UpvarBorrow,
|
||||
kind: ty::BorrowKind) {
|
||||
debug!("adjust_upvar_borrow_kind_for_loan: upvar_id={} kind={} -> {}",
|
||||
upvar_id, upvar_borrow.kind, kind);
|
||||
|
||||
adjust_upvar_borrow_kind(rcx, upvar_id, upvar_borrow, kind)
|
||||
}
|
||||
|
||||
/// We infer the borrow_kind with which to borrow upvars in a stack closure. The borrow_kind
|
||||
/// basically follows a lattice of `imm < unique-imm < mut`, moving from left to right as needed
|
||||
/// (but never right to left). Here the argument `mutbl` is the borrow_kind that is required by
|
||||
/// some particular use.
|
||||
fn adjust_upvar_borrow_kind(rcx: &Rcx,
|
||||
upvar_id: ty::UpvarId,
|
||||
upvar_borrow: &mut ty::UpvarBorrow,
|
||||
kind: ty::BorrowKind) {
|
||||
debug!("adjust_upvar_borrow_kind: id={} kind=({} -> {})",
|
||||
upvar_id, upvar_borrow.kind, kind);
|
||||
|
||||
match (upvar_borrow.kind, kind) {
|
||||
// Take RHS:
|
||||
(ty::ImmBorrow, ty::UniqueImmBorrow) |
|
||||
(ty::ImmBorrow, ty::MutBorrow) |
|
||||
(ty::UniqueImmBorrow, ty::MutBorrow) => {
|
||||
upvar_borrow.kind = kind;
|
||||
|
||||
// Check if there are any region links we now need to
|
||||
// establish due to adjusting the borrow kind of the upvar
|
||||
match rcx.maybe_links.borrow_mut().entry(upvar_id) {
|
||||
Occupied(entry) => {
|
||||
for MaybeLink { span, borrow_region,
|
||||
borrow_kind, borrow_cmt } in entry.take().into_iter()
|
||||
{
|
||||
link_region(rcx, span, borrow_region, borrow_kind, borrow_cmt);
|
||||
}
|
||||
}
|
||||
Vacant(_) => {}
|
||||
}
|
||||
}
|
||||
// Take LHS:
|
||||
(ty::ImmBorrow, ty::ImmBorrow) |
|
||||
(ty::UniqueImmBorrow, ty::ImmBorrow) |
|
||||
(ty::UniqueImmBorrow, ty::UniqueImmBorrow) |
|
||||
(ty::MutBorrow, _) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures that all borrowed data reachable via `ty` outlives `region`.
|
||||
fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
|
||||
origin: infer::SubregionOrigin<'tcx>,
|
||||
|
|
373
src/librustc_typeck/check/upvar.rs
Normal file
373
src/librustc_typeck/check/upvar.rs
Normal file
|
@ -0,0 +1,373 @@
|
|||
// Copyright 2012-2014 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.
|
||||
|
||||
//! ### Inferring borrow kinds for upvars
|
||||
//!
|
||||
//! Whenever there is a closure expression, we need to determine how each
|
||||
//! upvar is used. We do this by initially assigning each upvar an
|
||||
//! immutable "borrow kind" (see `ty::BorrowKind` for details) and then
|
||||
//! "escalating" the kind as needed. The borrow kind proceeds according to
|
||||
//! the following lattice:
|
||||
//!
|
||||
//! ty::ImmBorrow -> ty::UniqueImmBorrow -> ty::MutBorrow
|
||||
//!
|
||||
//! So, for example, if we see an assignment `x = 5` to an upvar `x`, we
|
||||
//! will promote its borrow kind to mutable borrow. If we see an `&mut x`
|
||||
//! we'll do the same. Naturally, this applies not just to the upvar, but
|
||||
//! to everything owned by `x`, so the result is the same for something
|
||||
//! like `x.f = 5` and so on (presuming `x` is not a borrowed pointer to a
|
||||
//! struct). These adjustments are performed in
|
||||
//! `adjust_upvar_borrow_kind()` (you can trace backwards through the code
|
||||
//! from there).
|
||||
//!
|
||||
//! The fact that we are inferring borrow kinds as we go results in a
|
||||
//! semi-hacky interaction with mem-categorization. In particular,
|
||||
//! mem-categorization will query the current borrow kind as it
|
||||
//! categorizes, and we'll return the *current* value, but this may get
|
||||
//! adjusted later. Therefore, in this module, we generally ignore the
|
||||
//! borrow kind (and derived mutabilities) that are returned from
|
||||
//! mem-categorization, since they may be inaccurate. (Another option
|
||||
//! would be to use a unification scheme, where instead of returning a
|
||||
//! concrete borrow kind like `ty::ImmBorrow`, we return a
|
||||
//! `ty::InferBorrow(upvar_id)` or something like that, but this would
|
||||
//! then mean that all later passes would have to check for these figments
|
||||
//! and report an error, and it just seems like more mess in the end.)
|
||||
|
||||
use super::FnCtxt;
|
||||
|
||||
use middle::expr_use_visitor as euv;
|
||||
use middle::mem_categorization as mc;
|
||||
use middle::ty::{mod};
|
||||
use middle::infer::{InferCtxt, UpvarRegion};
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::visit::{mod, Visitor};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC ENTRY POINTS
|
||||
|
||||
pub fn closure_analyze_fn(fcx: &FnCtxt,
|
||||
_id: ast::NodeId,
|
||||
decl: &ast::FnDecl,
|
||||
body: &ast::Block) {
|
||||
let mut seed = SeedBorrowKind::new(fcx);
|
||||
seed.visit_block(body);
|
||||
|
||||
let mut adjust = AdjustBorrowKind::new(fcx);
|
||||
adjust.analyze_fn(decl, body);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// SEED BORROW KIND
|
||||
|
||||
struct SeedBorrowKind<'a,'tcx:'a> {
|
||||
fcx: &'a FnCtxt<'a,'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &ast::Expr) {
|
||||
match expr.node {
|
||||
ast::ExprClosure(cc, _, _, ref body) => {
|
||||
self.check_closure(expr, cc, &**body);
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self,
|
||||
fn_kind: visit::FnKind<'v>,
|
||||
decl: &'v ast::FnDecl,
|
||||
block: &'v ast::Block,
|
||||
span: Span,
|
||||
_id: ast::NodeId)
|
||||
{
|
||||
match fn_kind {
|
||||
visit::FkItemFn(..) | visit::FkMethod(..) => {
|
||||
// ignore nested fn items
|
||||
}
|
||||
visit::FkFnBlock => {
|
||||
visit::walk_fn(self, fn_kind, decl, block, span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx> SeedBorrowKind<'a,'tcx> {
|
||||
fn new(fcx: &'a FnCtxt<'a,'tcx>) -> SeedBorrowKind<'a,'tcx> {
|
||||
SeedBorrowKind { fcx: fcx }
|
||||
}
|
||||
|
||||
fn tcx(&self) -> &'a ty::ctxt<'tcx> {
|
||||
self.fcx.tcx()
|
||||
}
|
||||
|
||||
fn infcx(&self) -> &'a InferCtxt<'a,'tcx> {
|
||||
self.fcx.infcx()
|
||||
}
|
||||
|
||||
fn check_closure(&mut self,
|
||||
expr: &ast::Expr,
|
||||
capture_clause: ast::CaptureClause,
|
||||
_body: &ast::Block)
|
||||
{
|
||||
let is_old_skool_closure = match self.fcx.expr_ty(expr).sty {
|
||||
ty::ty_closure(..) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
match capture_clause {
|
||||
ast::CaptureByValue if !is_old_skool_closure => {
|
||||
}
|
||||
_ => {
|
||||
ty::with_freevars(self.tcx(), expr.id, |freevars| {
|
||||
for freevar in freevars.iter() {
|
||||
let var_node_id = freevar.def.local_node_id();
|
||||
let upvar_id = ty::UpvarId { var_id: var_node_id,
|
||||
closure_expr_id: expr.id };
|
||||
debug!("seed upvar_id {}", upvar_id);
|
||||
let origin = UpvarRegion(upvar_id, expr.span);
|
||||
let freevar_region = self.infcx().next_region_var(origin);
|
||||
let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow,
|
||||
region: freevar_region };
|
||||
self.fcx.inh.upvar_borrow_map.borrow_mut().insert(upvar_id,
|
||||
upvar_borrow);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ADJUST BORROW KIND
|
||||
|
||||
struct AdjustBorrowKind<'a,'tcx:'a> {
|
||||
fcx: &'a FnCtxt<'a,'tcx>
|
||||
}
|
||||
|
||||
impl<'a,'tcx> AdjustBorrowKind<'a,'tcx>{
|
||||
fn new(fcx: &'a FnCtxt<'a,'tcx>) -> AdjustBorrowKind<'a,'tcx> {
|
||||
AdjustBorrowKind { fcx: fcx }
|
||||
}
|
||||
|
||||
fn tcx(&self) -> &'a ty::ctxt<'tcx> {
|
||||
self.fcx.tcx()
|
||||
}
|
||||
|
||||
fn analyze_fn(&mut self, decl: &ast::FnDecl, body: &ast::Block) {
|
||||
/*!
|
||||
* Analysis starting point.
|
||||
*/
|
||||
|
||||
self.visit_block(body);
|
||||
|
||||
debug!("analyzing fn body with id {}", body.id);
|
||||
|
||||
let mut euv = euv::ExprUseVisitor::new(self, self.fcx);
|
||||
euv.walk_fn(decl, body);
|
||||
}
|
||||
|
||||
/// Indicates that `cmt` is being directly mutated (e.g., assigned
|
||||
/// to). If cmt contains any by-ref upvars, this implies that
|
||||
/// those upvars must be borrowed using an `&mut` borow.
|
||||
fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) {
|
||||
debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",
|
||||
cmt.repr(self.tcx()));
|
||||
|
||||
match cmt.cat.clone() {
|
||||
mc::cat_deref(base, _, mc::Unique) |
|
||||
mc::cat_interior(base, _) |
|
||||
mc::cat_downcast(base, _) => {
|
||||
// Interior or owned data is mutable if base is
|
||||
// mutable, so iterate to the base.
|
||||
self.adjust_upvar_borrow_kind_for_mut(base);
|
||||
}
|
||||
|
||||
mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
|
||||
mc::cat_deref(base, _, mc::Implicit(..)) => {
|
||||
if let mc::NoteUpvarRef(upvar_id) = cmt.note {
|
||||
// if this is an implicit deref of an
|
||||
// upvar, then we need to modify the
|
||||
// borrow_kind of the upvar to make sure it
|
||||
// is inferred to mutable if necessary
|
||||
let mut upvar_borrow_map = self.fcx.inh.upvar_borrow_map.borrow_mut();
|
||||
let ub = &mut upvar_borrow_map[upvar_id];
|
||||
self.adjust_upvar_borrow_kind(upvar_id, ub, ty::MutBorrow);
|
||||
} else {
|
||||
// assignment to deref of an `&mut`
|
||||
// borrowed pointer implies that the
|
||||
// pointer itself must be unique, but not
|
||||
// necessarily *mutable*
|
||||
self.adjust_upvar_borrow_kind_for_unique(base);
|
||||
}
|
||||
}
|
||||
|
||||
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
|
||||
mc::cat_static_item |
|
||||
mc::cat_rvalue(_) |
|
||||
mc::cat_local(_) |
|
||||
mc::cat_upvar(..) => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn adjust_upvar_borrow_kind_for_unique(&self, cmt: mc::cmt<'tcx>) {
|
||||
debug!("adjust_upvar_borrow_kind_for_unique(cmt={})",
|
||||
cmt.repr(self.tcx()));
|
||||
|
||||
match cmt.cat.clone() {
|
||||
mc::cat_deref(base, _, mc::Unique) |
|
||||
mc::cat_interior(base, _) |
|
||||
mc::cat_downcast(base, _) => {
|
||||
// Interior or owned data is unique if base is
|
||||
// unique.
|
||||
self.adjust_upvar_borrow_kind_for_unique(base);
|
||||
}
|
||||
|
||||
mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
|
||||
mc::cat_deref(base, _, mc::Implicit(..)) => {
|
||||
if let mc::NoteUpvarRef(upvar_id) = cmt.note {
|
||||
// if this is an implicit deref of an
|
||||
// upvar, then we need to modify the
|
||||
// borrow_kind of the upvar to make sure it
|
||||
// is inferred to unique if necessary
|
||||
let mut ub = self.fcx.inh.upvar_borrow_map.borrow_mut();
|
||||
let ub = &mut ub[upvar_id];
|
||||
self.adjust_upvar_borrow_kind(upvar_id, ub, ty::UniqueImmBorrow);
|
||||
} else {
|
||||
// for a borrowed pointer to be unique, its
|
||||
// base must be unique
|
||||
self.adjust_upvar_borrow_kind_for_unique(base);
|
||||
}
|
||||
}
|
||||
|
||||
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
|
||||
mc::cat_static_item |
|
||||
mc::cat_rvalue(_) |
|
||||
mc::cat_local(_) |
|
||||
mc::cat_upvar(..) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// We infer the borrow_kind with which to borrow upvars in a stack closure. The borrow_kind
|
||||
/// basically follows a lattice of `imm < unique-imm < mut`, moving from left to right as needed
|
||||
/// (but never right to left). Here the argument `mutbl` is the borrow_kind that is required by
|
||||
/// some particular use.
|
||||
fn adjust_upvar_borrow_kind(&self,
|
||||
upvar_id: ty::UpvarId,
|
||||
upvar_borrow: &mut ty::UpvarBorrow,
|
||||
kind: ty::BorrowKind) {
|
||||
debug!("adjust_upvar_borrow_kind: id={} kind=({} -> {})",
|
||||
upvar_id, upvar_borrow.kind, kind);
|
||||
|
||||
match (upvar_borrow.kind, kind) {
|
||||
// Take RHS:
|
||||
(ty::ImmBorrow, ty::UniqueImmBorrow) |
|
||||
(ty::ImmBorrow, ty::MutBorrow) |
|
||||
(ty::UniqueImmBorrow, ty::MutBorrow) => {
|
||||
upvar_borrow.kind = kind;
|
||||
}
|
||||
// Take LHS:
|
||||
(ty::ImmBorrow, ty::ImmBorrow) |
|
||||
(ty::UniqueImmBorrow, ty::ImmBorrow) |
|
||||
(ty::UniqueImmBorrow, ty::UniqueImmBorrow) |
|
||||
(ty::MutBorrow, _) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'tcx> {
|
||||
fn visit_fn(&mut self,
|
||||
fn_kind: visit::FnKind<'v>,
|
||||
decl: &'v ast::FnDecl,
|
||||
body: &'v ast::Block,
|
||||
span: Span,
|
||||
_id: ast::NodeId)
|
||||
{
|
||||
match fn_kind {
|
||||
visit::FkItemFn(..) | visit::FkMethod(..) => {
|
||||
// ignore nested fn items
|
||||
}
|
||||
visit::FkFnBlock => {
|
||||
self.analyze_fn(decl, body);
|
||||
visit::walk_fn(self, fn_kind, decl, body, span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a,'tcx> {
|
||||
fn consume(&mut self,
|
||||
_consume_id: ast::NodeId,
|
||||
_consume_span: Span,
|
||||
_cmt: mc::cmt<'tcx>,
|
||||
_mode: euv::ConsumeMode)
|
||||
{}
|
||||
|
||||
fn matched_pat(&mut self,
|
||||
_matched_pat: &ast::Pat,
|
||||
_cmt: mc::cmt<'tcx>,
|
||||
_mode: euv::MatchMode)
|
||||
{}
|
||||
|
||||
fn consume_pat(&mut self,
|
||||
_consume_pat: &ast::Pat,
|
||||
_cmt: mc::cmt<'tcx>,
|
||||
_mode: euv::ConsumeMode)
|
||||
{}
|
||||
|
||||
fn borrow(&mut self,
|
||||
borrow_id: ast::NodeId,
|
||||
_borrow_span: Span,
|
||||
cmt: mc::cmt<'tcx>,
|
||||
_loan_region: ty::Region,
|
||||
bk: ty::BorrowKind,
|
||||
_loan_cause: euv::LoanCause)
|
||||
{
|
||||
debug!("borrow(borrow_id={}, cmt={}, bk={})",
|
||||
borrow_id, cmt.repr(self.tcx()), bk);
|
||||
|
||||
match bk {
|
||||
ty::ImmBorrow => { }
|
||||
ty::UniqueImmBorrow => {
|
||||
self.adjust_upvar_borrow_kind_for_unique(cmt);
|
||||
}
|
||||
ty::MutBorrow => {
|
||||
self.adjust_upvar_borrow_kind_for_mut(cmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decl_without_init(&mut self,
|
||||
_id: ast::NodeId,
|
||||
_span: Span)
|
||||
{}
|
||||
|
||||
fn mutate(&mut self,
|
||||
_assignment_id: ast::NodeId,
|
||||
_assignment_span: Span,
|
||||
assignee_cmt: mc::cmt<'tcx>,
|
||||
_mode: euv::MutateMode)
|
||||
{
|
||||
debug!("mutate(assignee_cmt={})",
|
||||
assignee_cmt.repr(self.tcx()));
|
||||
|
||||
self.adjust_upvar_borrow_kind_for_mut(assignee_cmt);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -287,9 +287,7 @@ pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
|
|||
fcx.default_type_parameters();
|
||||
|
||||
let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
|
||||
let r = fulfillment_cx.select_all_or_error(fcx.infcx(),
|
||||
&fcx.inh.param_env,
|
||||
fcx);
|
||||
let r = fulfillment_cx.select_all_or_error(fcx.infcx(), fcx);
|
||||
match r {
|
||||
Ok(()) => { }
|
||||
Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
|
||||
|
@ -302,7 +300,7 @@ pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt)
|
|||
match
|
||||
fcx.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.select_where_possible(fcx.infcx(), &fcx.inh.param_env, fcx)
|
||||
.select_where_possible(fcx.infcx(), fcx)
|
||||
{
|
||||
Ok(()) => { }
|
||||
Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
|
||||
|
@ -316,7 +314,7 @@ pub fn select_new_fcx_obligations(fcx: &FnCtxt) {
|
|||
match
|
||||
fcx.inh.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.select_new_obligations(fcx.infcx(), &fcx.inh.param_env, fcx)
|
||||
.select_new_obligations(fcx.infcx(), fcx)
|
||||
{
|
||||
Ok(()) => { }
|
||||
Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
|
||||
|
|
|
@ -482,7 +482,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
|||
debug!("check_implementations_of_copy: self_type={} (free)",
|
||||
self_type.repr(tcx));
|
||||
|
||||
match ty::can_type_implement_copy(tcx, self_type, ¶m_env) {
|
||||
match ty::can_type_implement_copy(¶m_env, span, self_type) {
|
||||
Ok(()) => {}
|
||||
Err(ty::FieldDoesNotImplementCopy(name)) => {
|
||||
tcx.sess
|
||||
|
|
|
@ -24,6 +24,7 @@ fn a(x: &int) {
|
|||
//~^ ERROR cannot borrow
|
||||
let c2 = || set(&mut *x);
|
||||
//~^ ERROR cannot borrow
|
||||
//~| ERROR closure requires unique access
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -13,6 +13,6 @@
|
|||
struct B<T>;
|
||||
|
||||
fn main() {
|
||||
let foo = B; //~ ERROR unable to infer enough type information
|
||||
let closure = |:| foo;
|
||||
let foo = B;
|
||||
let closure = |:| foo; //~ ERROR unable to infer enough type information
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
#[lang="sized"]
|
||||
pub trait Sized {}
|
||||
|
||||
#[lang="copy"]
|
||||
pub trait Copy {}
|
||||
|
||||
mod bar {
|
||||
// shouldn't bring in too much
|
||||
pub use self::glob::*;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#![no_std] // makes debugging this test *a lot* easier (during resolve)
|
||||
|
||||
#[lang = "sized"] pub trait Sized for Sized? {}
|
||||
#[lang="copy"] pub trait Copy {}
|
||||
|
||||
// Test to make sure that private items imported through globs remain private
|
||||
// when they're used.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue