introduce fn-ctxt so we can invoke regionck code
This commit is contained in:
parent
ac968c4664
commit
f3cc374927
3 changed files with 91 additions and 52 deletions
|
@ -8,7 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use middle::free_region::FreeRegionMap;
|
|
||||||
use rustc::infer::{self, InferOk, TypeOrigin};
|
use rustc::infer::{self, InferOk, TypeOrigin};
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
use rustc::traits::{self, Reveal};
|
use rustc::traits::{self, Reveal};
|
||||||
|
@ -21,6 +20,7 @@ use syntax_pos::Span;
|
||||||
|
|
||||||
use CrateCtxt;
|
use CrateCtxt;
|
||||||
use super::assoc;
|
use super::assoc;
|
||||||
|
use super::{Inherited, FnCtxt};
|
||||||
|
|
||||||
/// Checks that a method from an impl conforms to the signature of
|
/// Checks that a method from an impl conforms to the signature of
|
||||||
/// the same method as declared in the trait.
|
/// the same method as declared in the trait.
|
||||||
|
@ -313,9 +313,6 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|mut infcx| {
|
|
||||||
let mut fulfillment_cx = traits::FulfillmentContext::new();
|
|
||||||
|
|
||||||
// Create obligations for each predicate declared by the impl
|
// Create obligations for each predicate declared by the impl
|
||||||
// definition in the context of the trait's parameter
|
// definition in the context of the trait's parameter
|
||||||
// environment. We can't just use `impl_env.caller_bounds`,
|
// environment. We can't just use `impl_env.caller_bounds`,
|
||||||
|
@ -341,10 +338,14 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
// the new hybrid bounds we computed.
|
// the new hybrid bounds we computed.
|
||||||
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
|
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
|
||||||
let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates);
|
let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates);
|
||||||
let trait_param_env =
|
let trait_param_env = traits::normalize_param_env_or_error(tcx,
|
||||||
traits::normalize_param_env_or_error(tcx, trait_param_env, normalize_cause.clone());
|
trait_param_env,
|
||||||
// FIXME(@jroesch) this seems ugly, but is a temporary change
|
normalize_cause.clone());
|
||||||
infcx.parameter_environment = trait_param_env;
|
|
||||||
|
tcx.infer_ctxt(None, Some(trait_param_env), Reveal::NotSpecializable).enter(|infcx| {
|
||||||
|
let inh = Inherited::new(ccx, infcx);
|
||||||
|
let infcx = &inh.infcx;
|
||||||
|
let fulfillment_cx = &inh.fulfillment_cx;
|
||||||
|
|
||||||
debug!("compare_impl_method: caller_bounds={:?}",
|
debug!("compare_impl_method: caller_bounds={:?}",
|
||||||
infcx.parameter_environment.caller_bounds);
|
infcx.parameter_environment.caller_bounds);
|
||||||
|
@ -365,7 +366,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
code: traits::ObligationCauseCode::CompareImplMethodObligation,
|
code: traits::ObligationCauseCode::CompareImplMethodObligation,
|
||||||
};
|
};
|
||||||
|
|
||||||
fulfillment_cx.register_predicate_obligation(
|
fulfillment_cx.borrow_mut().register_predicate_obligation(
|
||||||
&infcx,
|
&infcx,
|
||||||
traits::Obligation::new(cause, predicate));
|
traits::Obligation::new(cause, predicate));
|
||||||
}
|
}
|
||||||
|
@ -387,15 +388,18 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
let tcx = infcx.tcx;
|
let tcx = infcx.tcx;
|
||||||
let origin = TypeOrigin::MethodCompatCheck(impl_m_span);
|
let origin = TypeOrigin::MethodCompatCheck(impl_m_span);
|
||||||
|
|
||||||
let (impl_sig, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
|
let (impl_sig, _) =
|
||||||
infer::HigherRankedType,
|
infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
|
||||||
&impl_m.fty.sig);
|
infer::HigherRankedType,
|
||||||
let impl_sig = impl_sig.subst(tcx, impl_to_skol_substs);
|
&impl_m.fty.sig);
|
||||||
let impl_sig = assoc::normalize_associated_types_in(&infcx,
|
let impl_sig =
|
||||||
&mut fulfillment_cx,
|
impl_sig.subst(tcx, impl_to_skol_substs);
|
||||||
impl_m_span,
|
let impl_sig =
|
||||||
impl_m_body_id,
|
assoc::normalize_associated_types_in(&infcx,
|
||||||
&impl_sig);
|
&mut fulfillment_cx.borrow_mut(),
|
||||||
|
impl_m_span,
|
||||||
|
impl_m_body_id,
|
||||||
|
&impl_sig);
|
||||||
let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
||||||
unsafety: impl_m.fty.unsafety,
|
unsafety: impl_m.fty.unsafety,
|
||||||
abi: impl_m.fty.abi,
|
abi: impl_m.fty.abi,
|
||||||
|
@ -403,14 +407,17 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
}));
|
}));
|
||||||
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
|
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
|
||||||
|
|
||||||
let trait_sig = tcx.liberate_late_bound_regions(infcx.parameter_environment.free_id_outlive,
|
let trait_sig = tcx.liberate_late_bound_regions(
|
||||||
&trait_m.fty.sig);
|
infcx.parameter_environment.free_id_outlive,
|
||||||
let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs);
|
&trait_m.fty.sig);
|
||||||
let trait_sig = assoc::normalize_associated_types_in(&infcx,
|
let trait_sig =
|
||||||
&mut fulfillment_cx,
|
trait_sig.subst(tcx, trait_to_skol_substs);
|
||||||
impl_m_span,
|
let trait_sig =
|
||||||
impl_m_body_id,
|
assoc::normalize_associated_types_in(&infcx,
|
||||||
&trait_sig);
|
&mut fulfillment_cx.borrow_mut(),
|
||||||
|
impl_m_span,
|
||||||
|
impl_m_body_id,
|
||||||
|
&trait_sig);
|
||||||
let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
|
||||||
unsafety: trait_m.fty.unsafety,
|
unsafety: trait_m.fty.unsafety,
|
||||||
abi: trait_m.fty.abi,
|
abi: trait_m.fty.abi,
|
||||||
|
@ -454,25 +461,15 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
|
|
||||||
// Check that all obligations are satisfied by the implementation's
|
// Check that all obligations are satisfied by the implementation's
|
||||||
// version.
|
// version.
|
||||||
if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
|
if let Err(ref errors) = fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
|
||||||
infcx.report_fulfillment_errors(errors);
|
infcx.report_fulfillment_errors(errors);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, resolve all regions. This catches wily misuses of
|
// Finally, resolve all regions. This catches wily misuses of
|
||||||
// lifetime parameters. We have to build up a plausible lifetime
|
// lifetime parameters.
|
||||||
// environment based on what we find in the trait. We could also
|
let fcx = FnCtxt::new(&inh, tcx.types.err, impl_m_body_id);
|
||||||
// include the obligations derived from the method argument types,
|
fcx.regionck_item(impl_m_body_id, impl_m_span, &[]);
|
||||||
// but I don't think it's necessary -- after all, those are still
|
|
||||||
// in effect when type-checking the body, and all the
|
|
||||||
// where-clauses in the header etc should be implied by the trait
|
|
||||||
// anyway, so it shouldn't be needed there either. Anyway, we can
|
|
||||||
// always add more relations later (it's backwards compat).
|
|
||||||
let mut free_regions = FreeRegionMap::new();
|
|
||||||
free_regions.relate_free_regions_from_predicates(
|
|
||||||
&infcx.parameter_environment.caller_bounds);
|
|
||||||
|
|
||||||
infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
|
|
|
@ -407,22 +407,26 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> {
|
||||||
where F: for<'b> FnOnce(Inherited<'b, 'gcx, 'tcx>) -> R
|
where F: for<'b> FnOnce(Inherited<'b, 'gcx, 'tcx>) -> R
|
||||||
{
|
{
|
||||||
let ccx = self.ccx;
|
let ccx = self.ccx;
|
||||||
self.infcx.enter(|infcx| {
|
self.infcx.enter(|infcx| f(Inherited::new(ccx, infcx)))
|
||||||
f(Inherited {
|
|
||||||
ccx: ccx,
|
|
||||||
infcx: infcx,
|
|
||||||
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
|
|
||||||
locals: RefCell::new(NodeMap()),
|
|
||||||
deferred_call_resolutions: RefCell::new(DefIdMap()),
|
|
||||||
deferred_cast_checks: RefCell::new(Vec::new()),
|
|
||||||
anon_types: RefCell::new(DefIdMap()),
|
|
||||||
deferred_obligations: RefCell::new(Vec::new()),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
|
||||||
|
pub fn new(ccx: &'a CrateCtxt<'a, 'gcx>,
|
||||||
|
infcx: InferCtxt<'a, 'gcx, 'tcx>)
|
||||||
|
-> Self {
|
||||||
|
Inherited {
|
||||||
|
ccx: ccx,
|
||||||
|
infcx: infcx,
|
||||||
|
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
|
||||||
|
locals: RefCell::new(NodeMap()),
|
||||||
|
deferred_call_resolutions: RefCell::new(DefIdMap()),
|
||||||
|
deferred_cast_checks: RefCell::new(Vec::new()),
|
||||||
|
anon_types: RefCell::new(DefIdMap()),
|
||||||
|
deferred_obligations: RefCell::new(Vec::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn normalize_associated_types_in<T>(&self,
|
fn normalize_associated_types_in<T>(&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
body_id: ast::NodeId,
|
body_id: ast::NodeId,
|
||||||
|
|
38
src/test/compile-fail/issue-18937.rs
Normal file
38
src/test/compile-fail/issue-18937.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct MyString<'a>(&'a String);
|
||||||
|
|
||||||
|
struct B {
|
||||||
|
list: Vec<Box<fmt::Debug>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait A<'a> {
|
||||||
|
fn foo<F>(&mut self, f: F)
|
||||||
|
where F: fmt::Debug + 'a,
|
||||||
|
Self: Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> A<'a> for B {
|
||||||
|
fn foo<F>(&mut self, f: F) //~ ERROR parameter type `F` may not live long enough
|
||||||
|
where F: fmt::Debug + 'static,
|
||||||
|
{
|
||||||
|
self.list.push(Box::new(f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut b = B { list: Vec::new() };
|
||||||
|
|
||||||
|
// Create a borrowed pointer, put it in `b`, then drop what's borrowing it
|
||||||
|
let a = "hello".to_string();
|
||||||
|
b.foo(MyString(&a));
|
||||||
|
|
||||||
|
// Drop the data which `b` has a reference to
|
||||||
|
drop(a);
|
||||||
|
|
||||||
|
// Use the data, probably segfaulting
|
||||||
|
for b in b.list.iter() {
|
||||||
|
println!("{:?}", b);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue