use rustc::hir::def_id::DefId;
use rustc::ty::subst::Substs;
use rustc::traits;
-use rustc::ty::{self, Ty, MethodCall, TypeFoldable};
+use rustc::ty::{self, Ty, TypeFoldable};
use rustc::infer::{self, GenericKind, SubregionOrigin, VerifyBound};
use rustc::ty::adjustment;
use rustc::ty::wf::ImpliedBound;
let subject = self.tcx.hir.local_def_id(item_id);
let mut rcx = RegionCtxt::new(self, RepeatingScope(item_id), item_id, Subject(subject));
rcx.free_region_map.relate_free_regions_from_predicates(
- &self.parameter_environment.caller_bounds);
+ &self.param_env.caller_bounds);
rcx.relate_free_regions(wf_tys, item_id, span);
rcx.visit_region_obligations(item_id);
rcx.resolve_regions_and_report_errors();
}
rcx.free_region_map.relate_free_regions_from_predicates(
- &self.parameter_environment.caller_bounds);
+ &self.param_env.caller_bounds);
rcx.resolve_regions_and_report_errors();
for &ty in fn_sig_tys {
let ty = self.resolve_type(ty);
debug!("relate_free_regions(t={:?})", ty);
- let implied_bounds = ty::wf::implied_bounds(self, body_id, ty, span);
+ let implied_bounds =
+ ty::wf::implied_bounds(self, self.fcx.param_env, body_id, ty, span);
// Record any relations between free regions that we observe into the free-region-map.
self.free_region_map.relate_free_regions_from_implied_bounds(&implied_bounds);
self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span),
expr_ty, expr_region);
- let method_call = MethodCall::expr(expr.id);
- let opt_method_callee = self.tables.borrow().method_map.get(&method_call).cloned();
- let has_method_map = opt_method_callee.is_some();
+ let is_method_call = self.tables.borrow().is_method_call(expr);
// If we are calling a method (either explicitly or via an
// overloaded operator), check that all of the types provided as
// arguments for its type parameters are well-formed, and all the regions
// provided as arguments outlive the call.
- if let Some(callee) = opt_method_callee {
+ if is_method_call {
let origin = match expr.node {
hir::ExprMethodCall(..) =>
infer::ParameterOrigin::MethodCall,
infer::ParameterOrigin::OverloadedOperator
};
- self.substs_wf_in_scope(origin, &callee.substs, expr.span, expr_region);
- self.type_must_outlive(infer::ExprTypeIsNotInScope(callee.ty, expr.span),
- callee.ty, expr_region);
+ let substs = self.tables.borrow().node_substs(expr.id);
+ self.substs_wf_in_scope(origin, substs, expr.span, expr_region);
+ // Arguments (sub-expressions) are checked via `constrain_call`, below.
}
// Check any autoderefs or autorefs that appear.
- let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone());
- if let Some(adjustment) = adjustment {
- debug!("adjustment={:?}", adjustment);
- match adjustment.kind {
- adjustment::Adjust::DerefRef { autoderefs, ref autoref, .. } => {
- let expr_ty = self.resolve_node_type(expr.id);
- self.constrain_autoderefs(expr, autoderefs, expr_ty);
- if let Some(ref autoref) = *autoref {
- self.link_autoref(expr, autoderefs, autoref);
-
- // Require that the resulting region encompasses
- // the current node.
- //
- // FIXME(#6268) remove to support nested method calls
- self.type_of_node_must_outlive(infer::AutoBorrow(expr.span),
- expr.id, expr_region);
- }
- }
- /*
- adjustment::AutoObject(_, ref bounds, ..) => {
- // Determine if we are casting `expr` to a trait
- // instance. If so, we have to be sure that the type
- // of the source obeys the new region bound.
- let source_ty = self.resolve_node_type(expr.id);
- self.type_must_outlive(infer::RelateObjectBound(expr.span),
- source_ty, bounds.region_bound);
- }
- */
- _ => {}
- }
-
- // If necessary, constrain destructors in the unadjusted form of this
- // expression.
- let cmt_result = {
- let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
- mc.cat_expr_unadjusted(expr)
- };
- match cmt_result {
- Ok(head_cmt) => {
- self.check_safety_of_rvalue_destructor_if_necessary(head_cmt,
- expr.span);
- }
- Err(..) => {
- self.tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd");
- }
- }
- }
+ let cmt_result = self.constrain_adjustments(expr);
// If necessary, constrain destructors in this expression. This will be
// the adjusted form if there is an adjustment.
- let cmt_result = {
- let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
- mc.cat_expr(expr)
- };
match cmt_result {
Ok(head_cmt) => {
self.check_safety_of_rvalue_destructor_if_necessary(head_cmt, expr.span);
expr, self.repeating_scope);
match expr.node {
hir::ExprPath(_) => {
- self.fcx.opt_node_ty_substs(expr.id, |item_substs| {
- let origin = infer::ParameterOrigin::Path;
- self.substs_wf_in_scope(origin, &item_substs.substs, expr.span, expr_region);
- });
+ let substs = self.tables.borrow().node_substs(expr.id);
+ let origin = infer::ParameterOrigin::Path;
+ self.substs_wf_in_scope(origin, substs, expr.span, expr_region);
}
hir::ExprCall(ref callee, ref args) => {
- if has_method_map {
- self.constrain_call(expr, Some(&callee),
- args.iter().map(|e| &*e), false);
+ if is_method_call {
+ self.constrain_call(expr, Some(&callee), args.iter().map(|e| &*e));
} else {
self.constrain_callee(callee.id, expr, &callee);
- self.constrain_call(expr, None,
- args.iter().map(|e| &*e), false);
+ self.constrain_call(expr, None, args.iter().map(|e| &*e));
}
intravisit::walk_expr(self, expr);
}
hir::ExprMethodCall(.., ref args) => {
- self.constrain_call(expr, Some(&args[0]),
- args[1..].iter().map(|e| &*e), false);
+ self.constrain_call(expr, Some(&args[0]), args[1..].iter().map(|e| &*e));
intravisit::walk_expr(self, expr);
}
hir::ExprAssignOp(_, ref lhs, ref rhs) => {
- if has_method_map {
- self.constrain_call(expr, Some(&lhs),
- Some(&**rhs).into_iter(), false);
+ if is_method_call {
+ self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter());
}
intravisit::walk_expr(self, expr);
}
- hir::ExprIndex(ref lhs, ref rhs) if has_method_map => {
- self.constrain_call(expr, Some(&lhs),
- Some(&**rhs).into_iter(), true);
+ hir::ExprIndex(ref lhs, ref rhs) if is_method_call => {
+ self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter());
intravisit::walk_expr(self, expr);
},
- hir::ExprBinary(op, ref lhs, ref rhs) if has_method_map => {
- let implicitly_ref_args = !op.node.is_by_value();
-
- // As `expr_method_call`, but the call is via an
- // overloaded op. Note that we (sadly) currently use an
- // implicit "by ref" sort of passing style here. This
- // should be converted to an adjustment!
- self.constrain_call(expr, Some(&lhs),
- Some(&**rhs).into_iter(), implicitly_ref_args);
+ hir::ExprBinary(_, ref lhs, ref rhs) if is_method_call => {
+ // As `ExprMethodCall`, but the call is via an overloaded op.
+ self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter());
intravisit::walk_expr(self, expr);
}
intravisit::walk_expr(self, expr);
}
- hir::ExprUnary(op, ref lhs) if has_method_map => {
- let implicitly_ref_args = !op.is_by_value();
-
- // As above.
- self.constrain_call(expr, Some(&lhs),
- None::<hir::Expr>.iter(), implicitly_ref_args);
-
- intravisit::walk_expr(self, expr);
- }
-
hir::ExprUnary(hir::UnDeref, ref base) => {
// For *a, the lifetime of a must enclose the deref
- let method_call = MethodCall::expr(expr.id);
- let base_ty = match self.tables.borrow().method_map.get(&method_call) {
- Some(method) => {
- self.constrain_call(expr, Some(&base),
- None::<hir::Expr>.iter(), true);
- // late-bound regions in overloaded method calls are instantiated
- let fn_ret = self.tcx.no_late_bound_regions(&method.ty.fn_ret());
- fn_ret.unwrap()
- }
- None => self.resolve_node_type(base.id)
- };
+ if is_method_call {
+ self.constrain_call(expr, Some(base), None::<hir::Expr>.iter());
+ }
+ // For overloaded derefs, base_ty is the input to `Deref::deref`,
+ // but it's a reference type uing the same region as the output.
+ let base_ty = self.resolve_expr_type_adjusted(base);
if let ty::TyRef(r_ptr, _) = base_ty.sty {
self.mk_subregion_due_to_dereference(expr.span, expr_region, r_ptr);
}
intravisit::walk_expr(self, expr);
}
+ hir::ExprUnary(_, ref lhs) if is_method_call => {
+ // As above.
+ self.constrain_call(expr, Some(&lhs), None::<hir::Expr>.iter());
+
+ intravisit::walk_expr(self, expr);
+ }
+
hir::ExprIndex(ref vec_expr, _) => {
// For a[b], the lifetime of a must enclose the deref
let vec_type = self.resolve_expr_type_adjusted(&vec_expr);
fn constrain_call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
call_expr: &hir::Expr,
receiver: Option<&hir::Expr>,
- arg_exprs: I,
- implicitly_ref_args: bool) {
+ arg_exprs: I) {
//! Invoked on every call site (i.e., normal calls, method calls,
//! and overloaded operators). Constrains the regions which appear
//! in the type of the function. Also constrains the regions that
//! appear in the arguments appropriately.
- debug!("constrain_call(call_expr={:?}, \
- receiver={:?}, \
- implicitly_ref_args={})",
+ debug!("constrain_call(call_expr={:?}, receiver={:?})",
call_expr,
- receiver,
- implicitly_ref_args);
+ receiver);
// `callee_region` is the scope representing the time in which the
// call occurs.
// valid for at least the lifetime of the function:
self.type_of_node_must_outlive(infer::CallArg(arg_expr.span),
arg_expr.id, callee_region);
-
- // unfortunately, there are two means of taking implicit
- // references, and we need to propagate constraints as a
- // result. modes are going away and the "DerefArgs" code
- // should be ported to use adjustments
- if implicitly_ref_args {
- self.link_by_ref(arg_expr, callee_scope);
- }
}
// as loop above, but for receiver
debug!("receiver: {:?}", r);
self.type_of_node_must_outlive(infer::CallRcvr(r.span),
r.id, callee_region);
- if implicitly_ref_args {
- self.link_by_ref(&r, callee_scope);
- }
}
}
- /// Invoked on any auto-dereference that occurs. Checks that if this is a region pointer being
+ /// Invoked on any adjustments that occur. Checks that if this is a region pointer being
/// dereferenced, the lifetime of the pointer includes the deref expr.
- fn constrain_autoderefs(&mut self,
- deref_expr: &hir::Expr,
- derefs: usize,
- mut derefd_ty: Ty<'tcx>)
- {
- debug!("constrain_autoderefs(deref_expr={:?}, derefs={}, derefd_ty={:?})",
- deref_expr,
- derefs,
- derefd_ty);
-
- let r_deref_expr = self.tcx.node_scope_region(deref_expr.id);
- for i in 0..derefs {
- let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
- debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
-
- let method = self.tables.borrow().method_map.get(&method_call).map(|m| m.clone());
-
- derefd_ty = match method {
- Some(method) => {
- debug!("constrain_autoderefs: #{} is overloaded, method={:?}",
- i, method);
-
- let origin = infer::ParameterOrigin::OverloadedDeref;
- self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr);
-
- // Treat overloaded autoderefs as if an AutoBorrow adjustment
- // was applied on the base type, as that is always the case.
- let fn_sig = method.ty.fn_sig();
- let fn_sig = // late-bound regions should have been instantiated
- self.tcx.no_late_bound_regions(&fn_sig).unwrap();
- let self_ty = fn_sig.inputs()[0];
- let (m, r) = match self_ty.sty {
- ty::TyRef(r, ref m) => (m.mutbl, r),
- _ => {
- span_bug!(
- deref_expr.span,
- "bad overloaded deref type {:?}",
- method.ty)
- }
- };
-
- debug!("constrain_autoderefs: receiver r={:?} m={:?}",
- r, m);
-
- {
- let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
- let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
- debug!("constrain_autoderefs: self_cmt={:?}",
- self_cmt);
- self.link_region(deref_expr.span, r,
- ty::BorrowKind::from_mutbl(m), self_cmt);
- }
+ fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult<mc::cmt<'tcx>> {
+ debug!("constrain_adjustments(expr={:?})", expr);
- // Specialized version of constrain_call.
- self.type_must_outlive(infer::CallRcvr(deref_expr.span),
- self_ty, r_deref_expr);
- self.type_must_outlive(infer::CallReturn(deref_expr.span),
- fn_sig.output(), r_deref_expr);
- fn_sig.output()
- }
- None => derefd_ty
- };
+ let mut cmt = {
+ let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
+ mc.cat_expr_unadjusted(expr)?
+ };
+
+ //NOTE(@jroesch): mixed RefCell borrow causes crash
+ let adjustments = self.tables.borrow().expr_adjustments(&expr).to_vec();
+ if adjustments.is_empty() {
+ return Ok(cmt);
+ }
+
+ debug!("constrain_adjustments: adjustments={:?}", adjustments);
+
+ // If necessary, constrain destructors in the unadjusted form of this
+ // expression.
+ self.check_safety_of_rvalue_destructor_if_necessary(cmt.clone(), expr.span);
+
+ let expr_region = self.tcx.node_scope_region(expr.id);
+ for adjustment in adjustments {
+ debug!("constrain_adjustments: adjustment={:?}, cmt={:?}",
+ adjustment, cmt);
+
+ if let adjustment::Adjust::Deref(Some(deref)) = adjustment.kind {
+ debug!("constrain_adjustments: overloaded deref: {:?}", deref);
+
+ // Treat overloaded autoderefs as if an AutoBorrow adjustment
+ // was applied on the base type, as that is always the case.
+ let input = self.tcx.mk_ref(deref.region, ty::TypeAndMut {
+ ty: cmt.ty,
+ mutbl: deref.mutbl,
+ });
+ let output = self.tcx.mk_ref(deref.region, ty::TypeAndMut {
+ ty: adjustment.target,
+ mutbl: deref.mutbl,
+ });
+
+ self.link_region(expr.span, deref.region,
+ ty::BorrowKind::from_mutbl(deref.mutbl), cmt.clone());
+
+ // Specialized version of constrain_call.
+ self.type_must_outlive(infer::CallRcvr(expr.span),
+ input, expr_region);
+ self.type_must_outlive(infer::CallReturn(expr.span),
+ output, expr_region);
+ }
+
+ if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind {
+ self.link_autoref(expr, cmt.clone(), autoref);
- if let ty::TyRef(r_ptr, _) = derefd_ty.sty {
- self.mk_subregion_due_to_dereference(deref_expr.span,
- r_deref_expr, r_ptr);
+ // Require that the resulting region encompasses
+ // the current node.
+ //
+ // FIXME(#6268) remove to support nested method calls
+ self.type_of_node_must_outlive(infer::AutoBorrow(expr.span),
+ expr.id, expr_region);
}
- match derefd_ty.builtin_deref(true, ty::NoPreference) {
- Some(mt) => derefd_ty = mt.ty,
- /* if this type can't be dereferenced, then there's already an error
- in the session saying so. Just bail out for now */
- None => break
+ {
+ let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
+ cmt = mc.cat_expr_adjusted(expr, cmt, &adjustment)?;
+ }
+
+ if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat {
+ self.mk_subregion_due_to_dereference(expr.span,
+ expr_region, r_ptr);
}
}
+
+ Ok(cmt)
}
pub fn mk_subregion_due_to_dereference(&mut self,
cmt: mc::cmt<'tcx>,
span: Span) {
match cmt.cat {
- Categorization::Rvalue(region, _) => {
+ Categorization::Rvalue(region) => {
match *region {
ty::ReScope(rvalue_scope) => {
let typ = self.resolve_type(cmt.ty);
// is going to fail anyway, so just stop here and let typeck
// report errors later on in the writeback phase.
let ty0 = self.resolve_node_type(id);
- let ty = self.tables.borrow().adjustments.get(&id).map_or(ty0, |adj| adj.target);
+ let ty = self.tables.borrow().adjustments.get(&id)
+ .and_then(|adj| adj.last())
+ .map_or(ty0, |adj| adj.target);
let ty = self.resolve_type(ty);
debug!("constrain_regions_in_type_of_node(\
ty={}, ty0={}, id={}, minimum_lifetime={:?})",
let arg_ty = self.node_ty(arg.id);
let re_scope = self.tcx.mk_region(ty::ReScope(body_scope));
let arg_cmt = mc.cat_rvalue(
- arg.id, arg.pat.span, re_scope, re_scope, arg_ty);
+ arg.id, arg.pat.span, re_scope, arg_ty);
debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
arg_ty,
arg_cmt,
/// autoref'd.
fn link_autoref(&self,
expr: &hir::Expr,
- autoderefs: usize,
+ expr_cmt: mc::cmt<'tcx>,
autoref: &adjustment::AutoBorrow<'tcx>)
{
- debug!("link_autoref(autoderefs={}, autoref={:?})", autoderefs, autoref);
- let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
- let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
- debug!("expr_cmt={:?}", expr_cmt);
+ debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt);
match *autoref {
adjustment::AutoBorrow::Ref(r, m) => {
}
}
- /// Computes the guarantor for cases where the `expr` is being passed by implicit reference and
- /// must outlive `callee_scope`.
- fn link_by_ref(&self,
- expr: &hir::Expr,
- callee_scope: CodeExtent) {
- debug!("link_by_ref(expr={:?}, callee_scope={:?})",
- expr, callee_scope);
- let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
- let expr_cmt = ignore_err!(mc.cat_expr(expr));
- let borrow_region = self.tcx.mk_region(ty::ReScope(callee_scope));
- self.link_region(expr.span, borrow_region, ty::ImmBorrow, expr_cmt);
- }
-
/// Like `link_region()`, except that the region is extracted from the type of `id`,
/// which must be some reference (`&T`, `&str`, etc).
fn link_region_from_node_type(&self,
borrow_kind,
borrow_cmt);
match borrow_cmt.cat.clone() {
- Categorization::Deref(ref_cmt, _,
- mc::Implicit(ref_kind, ref_region)) |
- Categorization::Deref(ref_cmt, _,
- mc::BorrowedPtr(ref_kind, ref_region)) => {
+ Categorization::Deref(ref_cmt, mc::Implicit(ref_kind, ref_region)) |
+ Categorization::Deref(ref_cmt, mc::BorrowedPtr(ref_kind, ref_region)) => {
match self.link_reborrowed_region(span,
borrow_region, borrow_kind,
ref_cmt, ref_region, ref_kind,
}
Categorization::Downcast(cmt_base, _) |
- Categorization::Deref(cmt_base, _, mc::Unique) |
+ Categorization::Deref(cmt_base, mc::Unique) |
Categorization::Interior(cmt_base, _) => {
// Borrowing interior or owned data requires the base
// to be valid and borrowable in the same fashion.
borrow_kind = borrow_kind;
}
- Categorization::Deref(.., mc::UnsafePtr(..)) |
+ Categorization::Deref(_, mc::UnsafePtr(..)) |
Categorization::StaticItem |
Categorization::Upvar(..) |
Categorization::Local(..) |
declared_bounds, projection_ty);
// see the extensive comment in projection_must_outlive
-
- let ty = self.tcx.mk_projection(projection_ty.trait_ref, projection_ty.item_name);
+ let item_name = projection_ty.item_name(self.tcx);
+ let ty = self.tcx.mk_projection(projection_ty.trait_ref, item_name);
let recursive_bound = self.recursive_type_bound(span, ty);
VerifyBound::AnyRegion(declared_bounds).or(recursive_bound)
fn declared_generic_bounds_from_env(&self, generic: GenericKind<'tcx>)
-> Vec<ty::Region<'tcx>>
{
- let param_env = &self.parameter_environment;
+ let param_env = &self.param_env;
// To start, collect bounds from user:
let mut param_bounds = self.tcx.required_region_bounds(generic.to_ty(self.tcx),
{
debug!("projection_bounds(projection_ty={:?})",
projection_ty);
-
+ let item_name = projection_ty.item_name(self.tcx);
let ty = self.tcx.mk_projection(projection_ty.trait_ref.clone(),
- projection_ty.item_name);
+ item_name);
// Say we have a projection `<T as SomeTrait<'a>>::SomeType`. We are interested
// in looking for a trait definition like:
let (outlives, _) =
self.replace_late_bound_regions_with_fresh_var(
span,
- infer::AssocTypeProjection(projection_ty.item_name),
+ infer::AssocTypeProjection(projection_ty.item_name(self.tcx)),
&outlives);
debug!("projection_bounds: outlives={:?} (3)",
// check whether this predicate applies to our current projection
let cause = self.fcx.misc(span);
- match self.eq_types(false, &cause, ty, outlives.0) {
+ match self.at(&cause, self.fcx.param_env).eq(outlives.0, ty) {
Ok(ok) => {
self.register_infer_ok_obligations(ok);
Ok(outlives.1)