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);
+ 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
- if self.tables.borrow().is_method_call(expr.id) {
- self.constrain_call(expr, Some(base),
- None::<hir::Expr>.iter(), true);
+ 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.
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,
- autoderefs: &[Option<ty::MethodCallee<'tcx>>])
- -> mc::McResult<mc::cmt<'tcx>>
- {
- debug!("constrain_autoderefs(deref_expr={:?}, autoderefs={:?})",
- deref_expr,
- autoderefs);
+ fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult<mc::cmt<'tcx>> {
+ debug!("constrain_adjustments(expr={:?})", expr);
let mut cmt = {
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
- mc.cat_expr_unadjusted(deref_expr)?
+ mc.cat_expr_unadjusted(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);
+ //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);
- let origin = infer::ParameterOrigin::OverloadedDeref;
- self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr);
+ // 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 self_ty = method.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.sig)
- }
- };
-
- 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),
- method.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);
+ }
+
+ 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);
}
{
let mc = mc::MemCategorizationContext::new(self, &self.region_maps);
- if let Some(method) = overloaded {
- cmt = mc.cat_overloaded_autoderef(deref_expr, method)?;
- } else {
- cmt = mc.cat_deref(deref_expr, cmt, false)?;
- }
+ cmt = 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={:?})",
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,
}
}
- /// 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,
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)