diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index c314fba91d59e..53249c724627e 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -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 \ diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index d16224ec5b8ac..9cb8674c3e1b7 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -99,7 +99,7 @@ impl<'a> FromIterator> 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); } diff --git a/src/librustc/middle/check_rvalues.rs b/src/librustc/middle/check_rvalues.rs index 3b4ea5234f43f..c383b1579ef84 100644 --- a/src/librustc/middle/check_rvalues.rs +++ b/src/librustc/middle/check_rvalues.rs @@ -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)); diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index fb20df020acf8..9c9e68002c980 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -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); diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index ff1ee39496626..acbb7d567dcea 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -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) | diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index d36c85342ce32..f5cf4af1230a4 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -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) { 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. - - let msg = format!("Pattern has unexpected def: {}", def); - tcx.sess.span_bug(pat.span, msg[]) + // 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. + + 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> { // 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 diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index df06b3b7789c9..2962b7b7c8e48 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -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>, + param_envs: Vec>, // 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>, 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); } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 70942a950e324..722fe82d41c32 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -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 { +pub fn deref_kind(t: Ty) -> McResult { 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 = Result; + /// 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>; + fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult>; + fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool; fn node_method_ty(&self, method_call: ty::MethodCall) -> Option>; fn node_method_origin(&self, method_call: ty::MethodCall) -> Option>; @@ -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> { 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> { + 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> { self.typer.node_ty(id) } - fn pat_ty(&self, pat: &ast::Pat) -> Ty<'tcx> { + fn pat_ty(&self, pat: &ast::Pat) -> McResult> { 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> { 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> { + 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> { 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> { 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> { // 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> { 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> + { + 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(&self, elt: &N, mut base_cmt: cmt<'tcx>) - -> cmt<'tcx> { + -> McResult> { //! 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(&self, elt: &N, base_cmt: cmt<'tcx>) - -> cmt<'tcx> { - match deref_kind(self.tcx(), base_cmt.ty) { + -> McResult> + { + 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(&self, cmt: cmt<'tcx>, pat: &ast::Pat, mut op: F) where - F: FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat), + pub fn cat_pattern(&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_(&self, cmt: cmt<'tcx>, pat: &ast::Pat, op: &mut F) where - F: FnMut(&MemCategorizationContext<'t, TYPER>, cmt<'tcx>, &ast::Pat), + fn cat_pattern_(&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> { diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 4aff36c262495..6a8b6d49cc0c5 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -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), diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index a0413701abcad..05ea2f9a7d258 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -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", diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 2dbb15b215ed0..e8a22e3d1d8f8 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -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>> { - try!(self.select_where_possible(infcx, param_env, typer)); + try!(self.select_where_possible(infcx, typer)); // Anything left is ambiguous. let errors: Vec = @@ -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>> { - 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>> { - let mut selcx = SelectionContext::new(infcx, param_env, typer); + let mut selcx = SelectionContext::new(infcx, typer); self.select(&mut selcx, false) } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index c83898bcd8ade..1a1d52a047c84 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -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) diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index d09f2a250b033..7da33babaeb60 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -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(); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 999bc23c27049..c720032bef264 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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,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,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() + } + + 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 node_ty(&self, id: ast::NodeId) -> Ty<'tcx> { - ty::node_id_to_type(self, id) + fn node_ty(&self, id: ast::NodeId) -> mc::McResult> { + Ok(ty::node_id_to_type(self.tcx, id)) } - fn expr_ty_adjusted(&self, expr: &ast::Expr) -> Ty<'tcx> { - ty::expr_ty_adjusted(self, expr) + fn expr_ty_adjusted(&self, expr: &ast::Expr) -> mc::McResult> { + Ok(ty::expr_ty_adjusted(self.tcx, expr)) } fn node_method_ty(&self, method_call: ty::MethodCall) -> Option> { - 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> { - 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>> { - &self.adjustments + fn adjustments(&self) -> &RefCell>> { + &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 { - self.region_maps.temporary_scope(rvalue_id) + self.tcx.region_maps.temporary_scope(rvalue_id) } fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option { - 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)) } } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 2062685f4c866..17a3f4a88e5c0 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -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); } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 7854c8acb4796..1e9e5b22aa0ed 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -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, diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index c27b7b30e1345..d81974d1ae038 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -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) } } diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index fc68d1d3258e1..19781a51d578b 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -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"); diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 24a3bb42c90f7..85a7ec3306950 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -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::>(); Univariant(mk_struct(cx, upvar_types[], false, t), false) } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index bf53885e9e50d..4c29467d93a44 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -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, diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index aa88224088063..6efdcc2f0fa0f 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -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, @@ -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> { + 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> { + Ok(expr_ty_adjusted(self, expr)) } fn node_method_ty(&self, method_call: ty::MethodCall) -> Option> { @@ -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()) { diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index 83bf06383a89c..72074040a2c67 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -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) } diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 7c8ba08d98750..cc259e6765c34 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -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 } diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs index 5e9843d0e00bf..6950850e5f3c1 100644 --- a/src/librustc_typeck/check/assoc.rs +++ b/src/librustc_typeck/check/assoc.rs @@ -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={}", diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 4e6593dedddf7..92b8c2bbcf718 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -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. diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 52860abb6f938..cd97d89b2465a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -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)) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 19ec85dc61eae..82525b71052d2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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>>, - param_env: ty::ParameterEnvironment<'tcx>, + param_env: ty::ParameterEnvironment<'a, 'tcx>, // Temporary tables: node_types: RefCell>>, @@ -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> { 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> { + 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> { @@ -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 { - self.tcx().temporary_scope(rvalue_id) + self.param_env().temporary_scope(rvalue_id) } fn upvar_borrow(&self, upvar_id: ty::UpvarId) -> Option { 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> { + 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, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index d01b79068aa2c..e97a29ec458c7 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -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>>>; - 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>, diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs new file mode 100644 index 0000000000000..a4c3550fcd676 --- /dev/null +++ b/src/librustc_typeck/check/upvar.rs @@ -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 or the MIT license +// , 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); + } +} + + diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 1ef6c11403218..8566d1f1e12b9 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -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); } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 79e1efa618f53..bb308198330f3 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -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 diff --git a/src/test/compile-fail/borrowck-closures-mut-of-imm.rs b/src/test/compile-fail/borrowck-closures-mut-of-imm.rs index 6360a9135005c..8163df5e967cd 100644 --- a/src/test/compile-fail/borrowck-closures-mut-of-imm.rs +++ b/src/test/compile-fail/borrowck-closures-mut-of-imm.rs @@ -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() { diff --git a/src/test/compile-fail/issue-17551.rs b/src/test/compile-fail/issue-17551.rs index e7f61a4f3ff5f..3889b6f4f7dce 100644 --- a/src/test/compile-fail/issue-17551.rs +++ b/src/test/compile-fail/issue-17551.rs @@ -13,6 +13,6 @@ struct B; 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 } diff --git a/src/test/compile-fail/privacy1.rs b/src/test/compile-fail/privacy1.rs index 50261839b16c6..41621a934d17a 100644 --- a/src/test/compile-fail/privacy1.rs +++ b/src/test/compile-fail/privacy1.rs @@ -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::*; diff --git a/src/test/compile-fail/privacy4.rs b/src/test/compile-fail/privacy4.rs index b65ad2a2e6aae..70e7e2df98a69 100644 --- a/src/test/compile-fail/privacy4.rs +++ b/src/test/compile-fail/privacy4.rs @@ -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.