Ensure borrows of fn/closure params do not outlive invocations.

resolve_lifetime.rs: Switch from BlockScope to FnScope in ScopeChain
construction. Lifetimes introduced by a fn signature are scoped to the
call-site for that fn. (Note `add_scope_and_walk_fn` must only add
FnScope for the walk of body, *not* of the fn signature.)

region.rs: Introduce new CodeExtentData::CallSiteScope variant. Use
CodeExtentData as the cx.parent, rather than just a NodeId.  Change
DestructionScopeData to CallSiteScopeData.

regionck.rs: Thread call_site_scope via Rcx; constrain fn return
values.

(update; incorporated review feedback from niko.)
This commit is contained in:
Felix S. Klock II 2015-12-08 23:38:36 +01:00
parent 4dbdfb4933
commit c00574848b
16 changed files with 170 additions and 96 deletions

View File

@ -148,6 +148,9 @@ impl<'tcx> ty::ctxt<'tcx> {
};
let scope_decorated_tag = match self.region_maps.code_extent_data(scope) {
region::CodeExtentData::Misc(_) => tag,
region::CodeExtentData::CallSiteScope { .. } => {
"scope of call-site for function"
}
region::CodeExtentData::ParameterScope { .. } => {
"scope of parameters for function"
}

View File

@ -1466,10 +1466,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
entry_ln: LiveNode,
body: &hir::Block)
{
// within the fn body, late-bound regions are liberated:
// within the fn body, late-bound regions are liberated
// and must outlive the *call-site* of the function.
let fn_ret =
self.ir.tcx.liberate_late_bound_regions(
self.ir.tcx.region_maps.item_extent(body.id),
self.ir.tcx.region_maps.call_site_extent(id, body.id),
&self.fn_ret(id));
match fn_ret {

View File

@ -125,6 +125,10 @@ pub const DUMMY_CODE_EXTENT : CodeExtent = CodeExtent(1);
pub enum CodeExtentData {
Misc(ast::NodeId),
// extent of the call-site for a function or closure (outlives
// the parameters as well as the body).
CallSiteScope { fn_id: ast::NodeId, body_id: ast::NodeId },
// extent of parameters passed to a function or closure (they
// outlive its body)
ParameterScope { fn_id: ast::NodeId, body_id: ast::NodeId },
@ -136,20 +140,20 @@ pub enum CodeExtentData {
Remainder(BlockRemainder)
}
/// extent of destructors for temporaries of node-id
/// extent of call-site for a function/method.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
RustcDecodable, Debug, Copy)]
pub struct DestructionScopeData {
pub node_id: ast::NodeId
pub struct CallSiteScopeData {
pub fn_id: ast::NodeId, pub body_id: ast::NodeId,
}
impl DestructionScopeData {
pub fn new(node_id: ast::NodeId) -> DestructionScopeData {
DestructionScopeData { node_id: node_id }
}
impl CallSiteScopeData {
pub fn to_code_extent(&self, region_maps: &RegionMaps) -> CodeExtent {
region_maps.lookup_code_extent(
CodeExtentData::DestructionScope(self.node_id))
match *self {
CallSiteScopeData { fn_id, body_id } =>
CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id },
})
}
}
@ -190,6 +194,7 @@ impl CodeExtentData {
// precise extent denoted by `self`.
CodeExtentData::Remainder(br) => br.block,
CodeExtentData::DestructionScope(node_id) => node_id,
CodeExtentData::CallSiteScope { fn_id: _, body_id } |
CodeExtentData::ParameterScope { fn_id: _, body_id } => body_id,
}
}
@ -215,6 +220,7 @@ impl CodeExtent {
match ast_map.find(self.node_id(region_maps)) {
Some(ast_map::NodeBlock(ref blk)) => {
match region_maps.code_extent_data(*self) {
CodeExtentData::CallSiteScope { .. } |
CodeExtentData::ParameterScope { .. } |
CodeExtentData::Misc(_) |
CodeExtentData::DestructionScope(_) => Some(blk.span),
@ -346,6 +352,10 @@ impl RegionMaps {
pub fn item_extent(&self, n: ast::NodeId) -> CodeExtent {
self.lookup_code_extent(CodeExtentData::DestructionScope(n))
}
pub fn call_site_extent(&self, fn_id: ast::NodeId, body_id: ast::NodeId) -> CodeExtent {
assert!(fn_id != body_id);
self.lookup_code_extent(CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id })
}
pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option<CodeExtent> {
self.code_extent_interner.borrow().get(&CodeExtentData::DestructionScope(n)).cloned()
}
@ -1101,6 +1111,9 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
body.id,
visitor.cx.parent);
visitor.cx.parent = visitor.new_code_extent(
CodeExtentData::CallSiteScope { fn_id: id, body_id: body.id });
let fn_decl_scope = visitor.new_code_extent(
CodeExtentData::ParameterScope { fn_id: id, body_id: body.id });

View File

@ -42,7 +42,7 @@ pub enum DefRegion {
/* lifetime decl */ ast::NodeId),
DefLateBoundRegion(ty::DebruijnIndex,
/* lifetime decl */ ast::NodeId),
DefFreeRegion(/* block scope */ region::DestructionScopeData,
DefFreeRegion(region::CallSiteScopeData,
/* lifetime decl */ ast::NodeId),
}
@ -83,9 +83,9 @@ enum ScopeChain<'a> {
/// LateScope(['a, 'b, ...], s) extends s with late-bound
/// lifetimes introduced by the declaration binder_id.
LateScope(&'a Vec<hir::LifetimeDef>, Scope<'a>),
/// lifetimes introduced by items within a code block are scoped
/// to that block.
BlockScope(region::DestructionScopeData, Scope<'a>),
/// lifetimes introduced by a fn are scoped to the call-site for that fn.
FnScope { fn_id: ast::NodeId, body_id: ast::NodeId, s: Scope<'a> },
RootScope
}
@ -172,20 +172,20 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
}
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
b: &'v hir::Block, s: Span, _: ast::NodeId) {
b: &'v hir::Block, s: Span, fn_id: ast::NodeId) {
match fk {
FnKind::ItemFn(_, generics, _, _, _, _) => {
self.visit_early_late(subst::FnSpace, generics, |this| {
this.walk_fn(fk, fd, b, s)
this.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
})
}
FnKind::Method(_, sig, _) => {
self.visit_early_late(subst::FnSpace, &sig.generics, |this| {
this.walk_fn(fk, fd, b, s)
this.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
})
}
FnKind::Closure => {
self.walk_fn(fk, fd, b, s)
self.add_scope_and_walk_fn(fk, fd, b, s, fn_id)
}
}
}
@ -236,12 +236,6 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
replace(&mut self.labels_in_fn, saved);
}
fn visit_block(&mut self, b: &hir::Block) {
self.with(BlockScope(region::DestructionScopeData::new(b.id),
self.scope),
|_, this| intravisit::walk_block(this, b));
}
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
if lifetime_ref.name == special_idents::static_lifetime.name {
self.insert_lifetime(lifetime_ref, DefStaticRegion);
@ -437,7 +431,7 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) {
label_span: Span) {
loop {
match *scope {
BlockScope(_, s) => { scope = s; }
FnScope { s, .. } => { scope = s; }
RootScope => { return; }
EarlyScope(_, lifetimes, s) |
@ -461,14 +455,13 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) {
}
impl<'a> LifetimeContext<'a> {
// This is just like intravisit::walk_fn, except that it extracts the
// labels of the function body and swaps them in before visiting
// the function body itself.
fn walk_fn<'b>(&mut self,
fk: FnKind,
fd: &hir::FnDecl,
fb: &'b hir::Block,
_span: Span) {
fn add_scope_and_walk_fn<'b>(&mut self,
fk: FnKind,
fd: &hir::FnDecl,
fb: &'b hir::Block,
_span: Span,
fn_id: ast::NodeId) {
match fk {
FnKind::ItemFn(_, generics, _, _, _, _) => {
intravisit::walk_fn_decl(self, fd);
@ -488,7 +481,8 @@ impl<'a> LifetimeContext<'a> {
// `self.labels_in_fn`.
extract_labels(self, fb);
self.visit_block(fb);
self.with(FnScope { fn_id: fn_id, body_id: fb.id, s: self.scope },
|_old_scope, this| this.visit_block(fb))
}
fn with<F>(&mut self, wrap_scope: ScopeChain, f: F) where
@ -559,8 +553,11 @@ impl<'a> LifetimeContext<'a> {
let mut scope = self.scope;
loop {
match *scope {
BlockScope(blk_scope, s) => {
return self.resolve_free_lifetime_ref(blk_scope, lifetime_ref, s);
FnScope {fn_id, body_id, s } => {
return self.resolve_free_lifetime_ref(
region::CallSiteScopeData { fn_id: fn_id, body_id: body_id },
lifetime_ref,
s);
}
RootScope => {
@ -604,7 +601,7 @@ impl<'a> LifetimeContext<'a> {
}
fn resolve_free_lifetime_ref(&mut self,
scope_data: region::DestructionScopeData,
scope_data: region::CallSiteScopeData,
lifetime_ref: &hir::Lifetime,
scope: Scope) {
debug!("resolve_free_lifetime_ref \
@ -622,8 +619,10 @@ impl<'a> LifetimeContext<'a> {
scope_data: {:?} scope: {:?} search_result: {:?}",
scope_data, scope, search_result);
match *scope {
BlockScope(blk_scope_data, s) => {
scope_data = blk_scope_data;
FnScope { fn_id, body_id, s } => {
scope_data = region::CallSiteScopeData {
fn_id: fn_id, body_id: body_id
};
scope = s;
}
@ -711,7 +710,7 @@ impl<'a> LifetimeContext<'a> {
loop {
match *old_scope {
BlockScope(_, s) => {
FnScope { s, .. } => {
old_scope = s;
}
@ -864,7 +863,7 @@ impl<'a> fmt::Debug for ScopeChain<'a> {
match *self {
EarlyScope(space, defs, _) => write!(fmt, "EarlyScope({:?}, {:?})", space, defs),
LateScope(defs, _) => write!(fmt, "LateScope({:?})", defs),
BlockScope(id, _) => write!(fmt, "BlockScope({:?})", id),
FnScope { fn_id, body_id, s: _ } => write!(fmt, "FnScope({:?}, {:?})", fn_id, body_id),
RootScope => write!(fmt, "RootScope"),
}
}

View File

@ -192,7 +192,8 @@ fn generics_require_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
};
// Search for a predicate like `Self : Sized` amongst the trait bounds.
let free_substs = tcx.construct_free_substs(generics, ast::DUMMY_NODE_ID);
let free_substs = tcx.construct_free_substs(generics,
tcx.region_maps.node_extent(ast::DUMMY_NODE_ID));
let predicates = predicates.instantiate(tcx, &free_substs).predicates.into_vec();
elaborate_predicates(tcx, predicates)
.any(|predicate| {

View File

@ -26,6 +26,7 @@ use middle::cstore::{CrateStore, LOCAL_CRATE};
use middle::def::{self, ExportMap};
use middle::def_id::DefId;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::region::{CodeExtent};
use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
use middle::traits;
use middle::ty;
@ -1098,7 +1099,7 @@ pub struct ParameterEnvironment<'a, 'tcx:'a> {
/// FIXME(#3696). It would be nice to refactor so that free
/// regions don't have this implicit scope and instead introduce
/// relationships in the environment.
pub free_id: ast::NodeId,
pub free_id_outlive: CodeExtent,
}
impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
@ -1113,7 +1114,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
caller_bounds: caller_bounds,
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
free_id: self.free_id,
free_id_outlive: self.free_id_outlive,
}
}
@ -1131,7 +1132,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
cx.construct_parameter_environment(impl_item.span,
&scheme.generics,
&predicates,
id)
cx.region_maps.item_extent(id))
}
hir::ImplItemKind::Const(_, _) => {
let def_id = cx.map.local_def_id(id);
@ -1140,7 +1141,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
cx.construct_parameter_environment(impl_item.span,
&scheme.generics,
&predicates,
id)
cx.region_maps.item_extent(id))
}
hir::ImplItemKind::Method(_, ref body) => {
let method_def_id = cx.map.local_def_id(id);
@ -1152,7 +1153,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
impl_item.span,
method_generics,
method_bounds,
body.id)
cx.region_maps.call_site_extent(id, body.id))
}
_ => {
cx.sess
@ -1175,7 +1176,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
cx.construct_parameter_environment(trait_item.span,
&trait_def.generics,
&predicates,
id)
cx.region_maps.item_extent(id))
}
hir::ConstTraitItem(..) => {
let def_id = cx.map.local_def_id(id);
@ -1184,23 +1185,29 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
cx.construct_parameter_environment(trait_item.span,
&scheme.generics,
&predicates,
id)
cx.region_maps.item_extent(id))
}
hir::MethodTraitItem(_, ref body) => {
// for the body-id, use the id of the body
// block, unless this is a trait method with
// no default, then fallback to the method id.
let body_id = body.as_ref().map(|b| b.id).unwrap_or(id);
// Use call-site for extent (unless this is a
// trait method with no default; then fallback
// to the method id).
let method_def_id = cx.map.local_def_id(id);
match cx.impl_or_trait_item(method_def_id) {
MethodTraitItem(ref method_ty) => {
let method_generics = &method_ty.generics;
let method_bounds = &method_ty.predicates;
let extent = if let Some(ref body) = *body {
// default impl: use call_site extent as free_id_outlive bound.
cx.region_maps.call_site_extent(id, body.id)
} else {
// no default impl: use item extent as free_id_outlive bound.
cx.region_maps.item_extent(id)
};
cx.construct_parameter_environment(
trait_item.span,
method_generics,
method_bounds,
body_id)
extent)
}
_ => {
cx.sess
@ -1223,7 +1230,8 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
cx.construct_parameter_environment(item.span,
&fn_scheme.generics,
&fn_predicates,
body.id)
cx.region_maps.call_site_extent(id,
body.id))
}
hir::ItemEnum(..) |
hir::ItemStruct(..) |
@ -1236,7 +1244,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
cx.construct_parameter_environment(item.span,
&scheme.generics,
&predicates,
id)
cx.region_maps.item_extent(id))
}
hir::ItemTrait(..) => {
let def_id = cx.map.local_def_id(id);
@ -1245,7 +1253,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
cx.construct_parameter_environment(item.span,
&trait_def.generics,
&predicates,
id)
cx.region_maps.item_extent(id))
}
_ => {
cx.sess.span_bug(item.span,
@ -2576,18 +2584,17 @@ impl<'tcx> ctxt<'tcx> {
/// are no free type/lifetime parameters in scope.
pub fn empty_parameter_environment<'a>(&'a self)
-> ParameterEnvironment<'a,'tcx> {
// for an empty parameter environment, there ARE no free
// regions, so it shouldn't matter what we use for the free id
let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID);
ty::ParameterEnvironment { tcx: self,
free_substs: Substs::empty(),
caller_bounds: Vec::new(),
implicit_region_bound: ty::ReEmpty,
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
// for an empty parameter
// environment, there ARE no free
// regions, so it shouldn't matter
// what we use for the free id
free_id: ast::DUMMY_NODE_ID }
free_id_outlive: free_id_outlive }
}
/// Constructs and returns a substitution that can be applied to move from
@ -2596,7 +2603,7 @@ impl<'tcx> ctxt<'tcx> {
/// free parameters. Since we currently represent bound/free type
/// parameters in the same way, this only has an effect on regions.
pub fn construct_free_substs(&self, generics: &Generics<'tcx>,
free_id: NodeId) -> Substs<'tcx> {
free_id_outlive: CodeExtent) -> Substs<'tcx> {
// map T => T
let mut types = VecPerParamSpace::empty();
for def in generics.types.as_slice() {
@ -2605,8 +2612,6 @@ impl<'tcx> ctxt<'tcx> {
types.push(def.space, self.mk_param_from_def(def));
}
let free_id_outlive = self.region_maps.item_extent(free_id);
// map bound 'a => free 'a
let mut regions = VecPerParamSpace::empty();
for def in generics.regions.as_slice() {
@ -2623,20 +2628,21 @@ impl<'tcx> ctxt<'tcx> {
}
}
/// See `ParameterEnvironment` struct def'n for details
/// See `ParameterEnvironment` struct def'n for details.
/// If you were using `free_id: NodeId`, you might try `self.region_maps.item_extent(free_id)`
/// for the `free_id_outlive` parameter. (But note that that is not always quite right.)
pub fn construct_parameter_environment<'a>(&'a self,
span: Span,
generics: &ty::Generics<'tcx>,
generic_predicates: &ty::GenericPredicates<'tcx>,
free_id: NodeId)
free_id_outlive: CodeExtent)
-> ParameterEnvironment<'a, 'tcx>
{
//
// Construct the free substs.
//
let free_substs = self.construct_free_substs(generics, free_id);
let free_id_outlive = self.region_maps.item_extent(free_id);
let free_substs = self.construct_free_substs(generics, free_id_outlive);
//
// Compute the bounds on Self and the type parameters.
@ -2646,12 +2652,6 @@ impl<'tcx> ctxt<'tcx> {
let bounds = self.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds));
let predicates = bounds.predicates.into_vec();
debug!("construct_parameter_environment: free_id={:?} free_subst={:?} predicates={:?}",
free_id,
free_substs,
predicates);
//
// Finally, we have to normalize the bounds in the environment, in
// case they contain any associated type projections. This process
// can yield errors if the put in illegal associated types, like
@ -2672,10 +2672,10 @@ impl<'tcx> ctxt<'tcx> {
caller_bounds: predicates,
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
free_id: free_id,
free_id_outlive: free_id_outlive,
};
let cause = traits::ObligationCause::misc(span, free_id);
let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps));
traits::normalize_param_env_or_error(unnormalized_env, cause)
}

View File

@ -823,7 +823,7 @@ impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where '
caller_bounds: self.caller_bounds.fold_with(folder),
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
free_id: self.free_id,
free_id_outlive: self.free_id_outlive,
}
}
}

View File

@ -233,6 +233,17 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
// doesn't care about regions.
//
// May still be worth fixing though.
'C' => {
assert_eq!(self.next(), '[');
let fn_id = self.parse_uint() as ast::NodeId;
assert_eq!(self.next(), '|');
let body_id = self.parse_uint() as ast::NodeId;
assert_eq!(self.next(), ']');
region::CodeExtentData::CallSiteScope {
fn_id: fn_id, body_id: body_id
}
}
// This creates scopes with the wrong NodeId. (See note above.)
'P' => {
assert_eq!(self.next(), '[');
let fn_id = self.parse_uint() as ast::NodeId;

View File

@ -286,6 +286,8 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) {
fn enc_scope(w: &mut Encoder, cx: &ctxt, scope: region::CodeExtent) {
match cx.tcx.region_maps.code_extent_data(scope) {
region::CodeExtentData::CallSiteScope {
fn_id, body_id } => mywrite!(w, "C[{}|{}]", fn_id, body_id),
region::CodeExtentData::ParameterScope {
fn_id, body_id } => mywrite!(w, "P[{}|{}]", fn_id, body_id),
region::CodeExtentData::Misc(node_id) => mywrite!(w, "M{}", node_id),

View File

@ -181,7 +181,7 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &hir::Lifetime)
Some(&rl::DefFreeRegion(scope, id)) => {
ty::ReFree(ty::FreeRegion {
scope: tcx.region_maps.item_extent(scope.node_id),
scope: scope.to_code_extent(&tcx.region_maps),
bound_region: ty::BrNamed(tcx.map.local_def_id(id),
lifetime.name)
})

View File

@ -75,7 +75,7 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
fcx.write_ty(expr.id, closure_type);
let fn_sig = fcx.tcx().liberate_late_bound_regions(
fcx.tcx().region_maps.item_extent(body.id), &fn_ty.sig);
fcx.tcx().region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
check_fn(fcx.ccx,
hir::Unsafety::Normal,

View File

@ -456,7 +456,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let inh = Inherited::new(ccx.tcx, &tables, param_env);
// Compute the fty from point of view of inside fn.
let fn_scope = ccx.tcx.region_maps.item_extent(body.id);
let fn_scope = ccx.tcx.region_maps.call_site_extent(fn_id, body.id);
let fn_sig =
fn_ty.sig.subst(ccx.tcx, &inh.infcx.parameter_environment.free_substs);
let fn_sig =

View File

@ -89,7 +89,7 @@ use middle::free_region::FreeRegionMap;
use middle::implicator::{self, Implication};
use middle::mem_categorization as mc;
use middle::mem_categorization::Categorization;
use middle::region::CodeExtent;
use middle::region::{self, CodeExtent};
use middle::subst::Substs;
use middle::traits;
use middle::ty::{self, RegionEscape, ReScope, Ty, MethodCall, HasTypeFlags};
@ -180,6 +180,9 @@ pub struct Rcx<'a, 'tcx: 'a> {
// id of innermost fn body id
body_id: ast::NodeId,
// call_site scope of innermost fn
call_site_scope: Option<CodeExtent>,
// id of innermost fn or loop
repeating_scope: ast::NodeId,
@ -200,6 +203,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
Rcx { fcx: fcx,
repeating_scope: initial_repeating_scope,
body_id: initial_body_id,
call_site_scope: None,
subject: subject,
region_bound_pairs: Vec::new(),
free_region_map: FreeRegionMap::new(),
@ -214,6 +218,10 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
self.fcx.infcx()
}
fn set_call_site_scope(&mut self, call_site_scope: Option<CodeExtent>) -> Option<CodeExtent> {
mem::replace(&mut self.call_site_scope, call_site_scope)
}
fn set_body_id(&mut self, body_id: ast::NodeId) -> ast::NodeId {
mem::replace(&mut self.body_id, body_id)
}
@ -275,7 +283,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
}
fn visit_fn_body(&mut self,
id: ast::NodeId,
id: ast::NodeId, // the id of the fn itself
fn_decl: &hir::FnDecl,
body: &hir::Block,
span: Span)
@ -283,6 +291,10 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
// When we enter a function, we can derive
debug!("visit_fn_body(id={})", id);
let call_site = self.fcx.tcx().region_maps.lookup_code_extent(
region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body.id });
let old_call_site_scope = self.set_call_site_scope(Some(call_site));
let fn_sig = {
let fn_sig_map = &self.infcx().tables.borrow().liberated_fn_sigs;
match fn_sig_map.get(&id) {
@ -300,7 +312,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
// For the return type, if diverging, substitute `bool` just
// because it will have no effect.
//
// FIXME(#25759) return types should not be implied bounds
// FIXME(#27579) return types should not be implied bounds
let fn_sig_tys: Vec<_> =
fn_sig.inputs.iter()
.cloned()
@ -315,9 +327,18 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
self.visit_block(body);
self.visit_region_obligations(body.id);
let call_site_scope = self.call_site_scope.unwrap();
debug!("visit_fn_body body.id {} call_site_scope: {:?}",
body.id, call_site_scope);
type_of_node_must_outlive(self,
infer::CallReturn(span),
body.id,
ty::ReScope(call_site_scope));
self.region_bound_pairs.truncate(old_region_bounds_pairs_len);
self.set_body_id(old_body_id);
self.set_call_site_scope(old_call_site_scope);
}
fn visit_region_obligations(&mut self, node_id: ast::NodeId)
@ -834,6 +855,17 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
rcx.set_repeating_scope(repeating_scope);
}
hir::ExprRet(Some(ref ret_expr)) => {
let call_site_scope = rcx.call_site_scope;
debug!("visit_expr ExprRet ret_expr.id {} call_site_scope: {:?}",
ret_expr.id, call_site_scope);
type_of_node_must_outlive(rcx,
infer::CallReturn(ret_expr.span),
ret_expr.id,
ty::ReScope(call_site_scope.unwrap()));
intravisit::walk_expr(rcx, expr);
}
_ => {
intravisit::walk_expr(rcx, expr);
}

View File

@ -137,10 +137,11 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
let type_scheme = ccx.tcx.lookup_item_type(item_def_id);
let type_predicates = ccx.tcx.lookup_predicates(item_def_id);
reject_non_type_param_bounds(ccx.tcx, item.span, &type_predicates);
let free_id_outlive = ccx.tcx.region_maps.item_extent(item.id);
let param_env = ccx.tcx.construct_parameter_environment(item.span,
&type_scheme.generics,
&type_predicates,
item.id);
free_id_outlive);
let tables = RefCell::new(ty::Tables::empty());
let inh = Inherited::new(ccx.tcx, &tables, param_env);
let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id);

View File

@ -13,6 +13,7 @@ use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck};
use constrained_type_params::{identify_constrained_type_params, Parameter};
use CrateCtxt;
use middle::def_id::DefId;
use middle::region::{CodeExtent};
use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
use middle::traits;
use middle::ty::{self, Ty};
@ -134,7 +135,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
let code = self.code.clone();
self.with_fcx(item_id, span, |fcx, this| {
let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
let free_id = fcx.inh.infcx.parameter_environment.free_id;
let free_id_outlive = fcx.inh.infcx.parameter_environment.free_id_outlive;
let item = fcx.tcx().impl_or_trait_item(fcx.tcx().map.local_def_id(item_id));
@ -153,7 +154,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method.fty);
let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates);
this.check_fn_or_method(fcx, span, &method_ty, &predicates,
free_id, &mut implied_bounds);
free_id_outlive, &mut implied_bounds);
}
ty::TypeTraitItem(assoc_type) => {
if let Some(ref ty) = assoc_type.ty {
@ -263,8 +264,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
let mut implied_bounds = vec![];
let free_id_outlive = fcx.tcx().region_maps.call_site_extent(item.id, body.id);
this.check_fn_or_method(fcx, item.span, bare_fn_ty, &predicates,
body.id, &mut implied_bounds);
free_id_outlive, &mut implied_bounds);
implied_bounds
})
}
@ -355,12 +357,11 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
span: Span,
fty: &ty::BareFnTy<'tcx>,
predicates: &ty::InstantiatedPredicates<'tcx>,
free_id: ast::NodeId,
free_id_outlive: CodeExtent,
implied_bounds: &mut Vec<Ty<'tcx>>)
{
let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
let fty = fcx.instantiate_type_scheme(span, free_substs, fty);
let free_id_outlive = fcx.tcx().region_maps.item_extent(free_id);
let sig = fcx.tcx().liberate_late_bound_regions(free_id_outlive, &fty.sig);
for &input_ty in &sig.inputs {

View File

@ -889,11 +889,13 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
for impl_item in impl_items {
if let hir::ImplItemKind::Method(ref sig, ref body) = impl_item.node {
let body_id = body.id;
let body_scope = ccx.tcx.region_maps.call_site_extent(impl_item.id, body_id);
check_method_self_type(ccx,
&BindingRscope::new(),
ccx.method_ty(impl_item.id),
selfty,
&sig.explicit_self,
body_scope,
body_id);
}
}
@ -988,8 +990,16 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
// This must be done after `collect_trait_methods` so that
// we have a method type stored for every method.
for trait_item in trait_items {
let sig = match trait_item.node {
hir::MethodTraitItem(ref sig, _) => sig,
let (sig, the_scope, the_id) = match trait_item.node {
hir::MethodTraitItem(ref sig, Some(ref body)) => {
let body_scope =
ccx.tcx.region_maps.call_site_extent(trait_item.id, body.id);
(sig, body_scope, body.id)
}
hir::MethodTraitItem(ref sig, None) => {
let item_scope = ccx.tcx.region_maps.item_extent(trait_item.id);
(sig, item_scope, it.id)
}
_ => continue
};
check_method_self_type(ccx,
@ -997,7 +1007,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
ccx.method_ty(trait_item.id),
tcx.mk_self_type(),
&sig.explicit_self,
it.id)
the_scope,
the_id)
}
},
hir::ItemStruct(ref struct_def, _) => {
@ -2282,6 +2293,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
method_type: Rc<ty::Method<'tcx>>,
required_type: Ty<'tcx>,
explicit_self: &hir::ExplicitSelf,
body_scope: region::CodeExtent,
body_id: ast::NodeId)
{
let tcx = ccx.tcx;
@ -2293,8 +2305,6 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
_ => typ,
};
let body_scope = tcx.region_maps.item_extent(body_id);
// "Required type" comes from the trait definition. It may
// contain late-bound regions from the method, but not the
// trait (since traits only have early-bound region