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 opt_method_callee = self.tables.borrow().method_map.get(&expr.id).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 { ref autoderefs, ref autoref, .. } => {
- let cmt = ignore_err!(self.constrain_autoderefs(expr, autoderefs));
- if let Some(ref autoref) = *autoref {
- self.link_autoref(expr, cmt, 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 base_ty = match self.tables.borrow().method_map.get(&expr.id) {
- 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
- /// dereferenced, the lifetime of the pointer includes the deref expr.
- fn constrain_autoderefs(&mut self,
- deref_expr: &hir::Expr,
- autoderefs: &[Option<ty::MethodCallee<'tcx>>])
- -> mc::McResult<mc::cmt<'tcx>>
+ /// Create a temporary `MemCategorizationContext` and pass it to the closure.
+ fn with_mc<F, R>(&self, f: F) -> R
+ where F: for<'b> FnOnce(mc::MemCategorizationContext<'b, 'gcx, 'tcx>) -> R
{
- debug!("constrain_autoderefs(deref_expr={:?}, autoderefs={:?})",
- deref_expr,
- autoderefs);
+ f(mc::MemCategorizationContext::new(&self.infcx,
+ &self.region_maps,
+ &self.tables.borrow()))
+ }
- let mut cmt = {
- let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
- mc.cat_expr_unadjusted(deref_expr)?
- };
+ /// 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_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult<mc::cmt<'tcx>> {
+ debug!("constrain_adjustments(expr={:?})", expr);
- let r_deref_expr = self.tcx.node_scope_region(deref_expr.id);
- for &overloaded in autoderefs {
- if let Some(method) = overloaded {
- debug!("constrain_autoderefs: overloaded, method={:?}", method);
+ let mut cmt = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?;
+
+ let tables = self.tables.borrow();
+ let adjustments = tables.expr_adjustments(&expr);
+ if adjustments.is_empty() {
+ return Ok(cmt);
+ }
- let origin = infer::ParameterOrigin::OverloadedDeref;
- self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr);
+ 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 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 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,
+ });
- debug!("constrain_autoderefs: self_cmt={:?}", cmt);
- self.link_region(deref_expr.span, r,
- ty::BorrowKind::from_mutbl(m), cmt.clone());
+ 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(deref_expr.span),
- self_ty, r_deref_expr);
- self.type_must_outlive(infer::CallReturn(deref_expr.span),
- fn_sig.output(), r_deref_expr);
+ self.type_must_outlive(infer::CallRcvr(expr.span),
+ input, expr_region);
+ self.type_must_outlive(infer::CallReturn(expr.span),
+ output, expr_region);
}
- {
- let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
- cmt = mc.cat_deref(deref_expr, cmt, overloaded)?;
+ if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind {
+ self.link_autoref(expr, cmt.clone(), 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);
}
+ cmt = self.with_mc(|mc| mc.cat_expr_adjusted(expr, cmt, &adjustment))?;
+
if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat {
- self.mk_subregion_due_to_dereference(deref_expr.span,
- r_deref_expr, r_ptr);
+ self.mk_subregion_due_to_dereference(expr.span,
+ expr_region, r_ptr);
}
}
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={:?})",
mutability: hir::Mutability, base: &hir::Expr) {
debug!("link_addr_of(expr={:?}, base={:?})", expr, base);
- let cmt = {
- let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
- ignore_err!(mc.cat_expr(base))
- };
+ let cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(base)));
debug!("link_addr_of: cmt={:?}", cmt);
None => { return; }
Some(ref expr) => &**expr,
};
- let mc = &mc::MemCategorizationContext::new(self, &self.region_maps);
- let discr_cmt = ignore_err!(mc.cat_expr(init_expr));
- self.link_pattern(mc, discr_cmt, &local.pat);
+ let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr)));
+ self.link_pattern(discr_cmt, &local.pat);
}
/// Computes the guarantors for any ref bindings in a match and
/// linked to the lifetime of its guarantor (if any).
fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) {
debug!("regionck::for_match()");
- let mc = &mc::MemCategorizationContext::new(self, &self.region_maps);
- let discr_cmt = ignore_err!(mc.cat_expr(discr));
+ let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr)));
debug!("discr_cmt={:?}", discr_cmt);
for arm in arms {
for root_pat in &arm.pats {
- self.link_pattern(mc, discr_cmt.clone(), &root_pat);
+ self.link_pattern(discr_cmt.clone(), &root_pat);
}
}
}
/// linked to the lifetime of its guarantor (if any).
fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) {
debug!("regionck::link_fn_args(body_scope={:?})", body_scope);
- let mc = &mc::MemCategorizationContext::new(self, &self.region_maps);
for arg in args {
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);
+ let arg_cmt = self.with_mc(|mc| {
+ mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty)
+ });
debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
arg_ty,
arg_cmt,
arg);
- self.link_pattern(mc, arg_cmt, &arg.pat);
+ self.link_pattern(arg_cmt, &arg.pat);
}
}
/// Link lifetimes of any ref bindings in `root_pat` to the pointers found
/// in the discriminant, if needed.
- fn link_pattern<'t>(&self,
- mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx>,
- discr_cmt: mc::cmt<'tcx>,
- root_pat: &hir::Pat) {
+ fn link_pattern(&self, discr_cmt: mc::cmt<'tcx>, root_pat: &hir::Pat) {
debug!("link_pattern(discr_cmt={:?}, root_pat={:?})",
discr_cmt,
root_pat);
- let _ = mc.cat_pattern(discr_cmt, root_pat, |_, sub_cmt, sub_pat| {
+ let _ = self.with_mc(|mc| {
+ mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, sub_pat| {
match sub_pat.node {
// `ref x` pattern
PatKind::Binding(hir::BindByRef(mutbl), ..) => {
}
_ => {}
}
- });
+ })
+ });
}
/// Link lifetime of borrowed pointer resulting from autoref to lifetimes in the value being
}
}
- /// 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,
// Detect by-ref upvar `x`:
let cause = match note {
mc::NoteUpvarRef(ref upvar_id) => {
- let upvar_capture_map = &self.tables.borrow_mut().upvar_capture_map;
- match upvar_capture_map.get(upvar_id) {
+ match self.tables.borrow().upvar_capture_map.get(upvar_id) {
Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => {
// The mutability of the upvar may have been modified
// by the above adjustment, so update our local variable.
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)
{
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)