Auto merge of #46733 - nikomatsakis:nll-master-to-rust-master-5, r=arielb1
nll part 5 Next round of changes from the nll-master branch. Extensions: - we now propagate ty-region-outlives constraints out of closures and into their creator when necessary - we fix a few ICEs that can occur by doing liveness analysis (and the resulting normalization) during type-checking - we handle the implicit region bound that assumes that each type `T` outlives the fn body - we handle normalization of inputs/outputs in fn signatures Not included in this PR (will come next): - handling `impl Trait` - tracking causal information - extended errors r? @arielb1
This commit is contained in:
commit
588f7db8ef
78 changed files with 4056 additions and 645 deletions
|
|
@ -536,14 +536,29 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Literal<'gcx> {
|
|||
|
||||
impl_stable_hash_for!(struct mir::Location { block, statement_index });
|
||||
|
||||
impl_stable_hash_for!(struct mir::ClosureRegionRequirements {
|
||||
impl_stable_hash_for!(struct mir::ClosureRegionRequirements<'tcx> {
|
||||
num_external_vids,
|
||||
outlives_requirements
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement {
|
||||
free_region,
|
||||
impl_stable_hash_for!(struct mir::ClosureOutlivesRequirement<'tcx> {
|
||||
subject,
|
||||
outlived_free_region,
|
||||
blame_span
|
||||
});
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::ClosureOutlivesSubject<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
mir::ClosureOutlivesSubject::Ty(ref ty) => {
|
||||
ty.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::ClosureOutlivesSubject::Region(ref region) => {
|
||||
region.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,6 +75,9 @@ for ty::RegionKind {
|
|||
ty::ReFree(ref free_region) => {
|
||||
free_region.hash_stable(hcx, hasher);
|
||||
}
|
||||
ty::ReClosureBound(vid) => {
|
||||
vid.hash_stable(hcx, hasher);
|
||||
}
|
||||
ty::ReLateBound(..) |
|
||||
ty::ReVar(..) |
|
||||
ty::ReSkolemized(..) => {
|
||||
|
|
|
|||
|
|
@ -475,6 +475,14 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
|
|||
ty::Bivariant | ty::Covariant | ty::Contravariant => (),
|
||||
}
|
||||
}
|
||||
|
||||
ty::ReClosureBound(..) => {
|
||||
span_bug!(
|
||||
self.span,
|
||||
"encountered unexpected ReClosureBound: {:?}",
|
||||
r,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This is non-ideal because we don't give a
|
||||
|
|
|
|||
|
|
@ -240,6 +240,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
ty::ReErased => {
|
||||
(format!("lifetime {:?}", region), None)
|
||||
}
|
||||
|
||||
// We shouldn't encounter an error message with ReClosureBound.
|
||||
ty::ReClosureBound(..) => {
|
||||
bug!(
|
||||
"encountered unexpected ReClosureBound: {:?}",
|
||||
region,
|
||||
);
|
||||
}
|
||||
};
|
||||
let message = format!("{}{}{}", prefix, description, suffix);
|
||||
if let Some(span) = span {
|
||||
|
|
|
|||
|
|
@ -113,6 +113,13 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
|
|||
// replace all free regions with 'erased
|
||||
self.tcx().types.re_erased
|
||||
}
|
||||
|
||||
ty::ReClosureBound(..) => {
|
||||
bug!(
|
||||
"encountered unexpected ReClosureBound: {:?}",
|
||||
r,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -258,7 +258,12 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
|
|||
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
|
||||
let tcx = self.region_rels.tcx;
|
||||
match (a, b) {
|
||||
(&ReLateBound(..), _) | (_, &ReLateBound(..)) | (&ReErased, _) | (_, &ReErased) => {
|
||||
(&ty::ReClosureBound(..), _) |
|
||||
(_, &ty::ReClosureBound(..)) |
|
||||
(&ReLateBound(..), _) |
|
||||
(_, &ReLateBound(..)) |
|
||||
(&ReErased, _) |
|
||||
(_, &ReErased) => {
|
||||
bug!("cannot relate region: LUB({:?}, {:?})", a, b);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1832,8 +1832,17 @@ pub struct GeneratorLayout<'tcx> {
|
|||
/// instance of the closure is created, the corresponding free regions
|
||||
/// can be extracted from its type and constrained to have the given
|
||||
/// outlives relationship.
|
||||
///
|
||||
/// In some cases, we have to record outlives requirements between
|
||||
/// types and regions as well. In that case, if those types include
|
||||
/// any regions, those regions are recorded as `ReClosureBound`
|
||||
/// instances assigned one of these same indices. Those regions will
|
||||
/// be substituted away by the creator. We use `ReClosureBound` in
|
||||
/// that case because the regions must be allocated in the global
|
||||
/// TyCtxt, and hence we cannot use `ReVar` (which is what we use
|
||||
/// internally within the rest of the NLL code).
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct ClosureRegionRequirements {
|
||||
pub struct ClosureRegionRequirements<'gcx> {
|
||||
/// The number of external regions defined on the closure. In our
|
||||
/// example above, it would be 3 -- one for `'static`, then `'1`
|
||||
/// and `'2`. This is just used for a sanity check later on, to
|
||||
|
|
@ -1843,15 +1852,15 @@ pub struct ClosureRegionRequirements {
|
|||
|
||||
/// Requirements between the various free regions defined in
|
||||
/// indices.
|
||||
pub outlives_requirements: Vec<ClosureOutlivesRequirement>,
|
||||
pub outlives_requirements: Vec<ClosureOutlivesRequirement<'gcx>>,
|
||||
}
|
||||
|
||||
/// Indicates an outlives constraint between two free-regions declared
|
||||
/// on the closure.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct ClosureOutlivesRequirement {
|
||||
// This region ...
|
||||
pub free_region: ty::RegionVid,
|
||||
/// Indicates an outlives constraint between a type or between two
|
||||
/// free-regions declared on the closure.
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct ClosureOutlivesRequirement<'tcx> {
|
||||
// This region or type ...
|
||||
pub subject: ClosureOutlivesSubject<'tcx>,
|
||||
|
||||
// .. must outlive this one.
|
||||
pub outlived_free_region: ty::RegionVid,
|
||||
|
|
@ -1860,6 +1869,23 @@ pub struct ClosureOutlivesRequirement {
|
|||
pub blame_span: Span,
|
||||
}
|
||||
|
||||
/// The subject of a ClosureOutlivesRequirement -- that is, the thing
|
||||
/// that must outlive some region.
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum ClosureOutlivesSubject<'tcx> {
|
||||
/// Subject is a type, typically a type parameter, but could also
|
||||
/// be a projection. Indicates a requirement like `T: 'a` being
|
||||
/// passed to the caller, where the type here is `T`.
|
||||
///
|
||||
/// The type here is guaranteed not to contain any free regions at
|
||||
/// present.
|
||||
Ty(Ty<'tcx>),
|
||||
|
||||
/// Subject is a free region from the closure. Indicates a requirement
|
||||
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
|
||||
Region(ty::RegionVid),
|
||||
}
|
||||
|
||||
/*
|
||||
* TypeFoldable implementations for MIR types
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -97,14 +97,19 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
|
|||
fn has_closure_types(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_TY_CLOSURE)
|
||||
}
|
||||
fn has_erasable_regions(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND |
|
||||
TypeFlags::HAS_RE_INFER |
|
||||
TypeFlags::HAS_FREE_REGIONS)
|
||||
/// "Free" regions in this context means that it has any region
|
||||
/// that is not (a) erased or (b) late-bound.
|
||||
fn has_free_regions(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
|
||||
}
|
||||
|
||||
/// True if there any any un-erased free regions.
|
||||
fn has_erasable_regions(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
|
||||
}
|
||||
|
||||
fn is_normalized_for_trans(&self) -> bool {
|
||||
!self.has_type_flags(TypeFlags::HAS_RE_EARLY_BOUND |
|
||||
TypeFlags::HAS_RE_INFER |
|
||||
!self.has_type_flags(TypeFlags::HAS_RE_INFER |
|
||||
TypeFlags::HAS_FREE_REGIONS |
|
||||
TypeFlags::HAS_TY_INFER |
|
||||
TypeFlags::HAS_PARAMS |
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ define_maps! { <'tcx>
|
|||
|
||||
/// Borrow checks the function body. If this is a closure, returns
|
||||
/// additional requirements that the closure's creator must verify.
|
||||
[] fn mir_borrowck: MirBorrowCheck(DefId) -> Option<mir::ClosureRegionRequirements>,
|
||||
[] fn mir_borrowck: MirBorrowCheck(DefId) -> Option<mir::ClosureRegionRequirements<'tcx>>,
|
||||
|
||||
/// Gets a complete map from all types to their inherent impls.
|
||||
/// Not meant to be used directly outside of coherence.
|
||||
|
|
|
|||
|
|
@ -421,8 +421,18 @@ bitflags! {
|
|||
const HAS_TY_INFER = 1 << 2;
|
||||
const HAS_RE_INFER = 1 << 3;
|
||||
const HAS_RE_SKOL = 1 << 4;
|
||||
|
||||
/// Does this have any `ReEarlyBound` regions? Used to
|
||||
/// determine whether substitition is required, since those
|
||||
/// represent regions that are bound in a `ty::Generics` and
|
||||
/// hence may be substituted.
|
||||
const HAS_RE_EARLY_BOUND = 1 << 5;
|
||||
|
||||
/// Does this have any region that "appears free" in the type?
|
||||
/// Basically anything but `ReLateBound` and `ReErased`.
|
||||
const HAS_FREE_REGIONS = 1 << 6;
|
||||
|
||||
/// Is an error type reachable?
|
||||
const HAS_TY_ERR = 1 << 7;
|
||||
const HAS_PROJECTION = 1 << 8;
|
||||
|
||||
|
|
|
|||
|
|
@ -1036,6 +1036,12 @@ pub enum RegionKind {
|
|||
|
||||
/// Erased region, used by trait selection, in MIR and during trans.
|
||||
ReErased,
|
||||
|
||||
/// These are regions bound in the "defining type" for a
|
||||
/// closure. They are used ONLY as part of the
|
||||
/// `ClosureRegionRequirements` that are produced by MIR borrowck.
|
||||
/// See `ClosureRegionRequirements` for more details.
|
||||
ReClosureBound(RegionVid),
|
||||
}
|
||||
|
||||
impl<'tcx> serialize::UseSpecializedDecodable for Region<'tcx> {}
|
||||
|
|
@ -1184,18 +1190,32 @@ impl RegionKind {
|
|||
|
||||
match *self {
|
||||
ty::ReVar(..) => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_RE_INFER;
|
||||
flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX;
|
||||
}
|
||||
ty::ReSkolemized(..) => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_RE_INFER;
|
||||
flags = flags | TypeFlags::HAS_RE_SKOL;
|
||||
flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX;
|
||||
}
|
||||
ty::ReLateBound(..) => { }
|
||||
ty::ReEarlyBound(..) => { flags = flags | TypeFlags::HAS_RE_EARLY_BOUND; }
|
||||
ty::ReStatic | ty::ReErased => { }
|
||||
_ => { flags = flags | TypeFlags::HAS_FREE_REGIONS; }
|
||||
ty::ReEarlyBound(..) => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
flags = flags | TypeFlags::HAS_RE_EARLY_BOUND;
|
||||
}
|
||||
ty::ReEmpty |
|
||||
ty::ReStatic |
|
||||
ty::ReFree { .. } |
|
||||
ty::ReScope { .. } => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
}
|
||||
ty::ReErased => {
|
||||
}
|
||||
ty::ReClosureBound(..) => {
|
||||
flags = flags | TypeFlags::HAS_FREE_REGIONS;
|
||||
}
|
||||
}
|
||||
|
||||
match *self {
|
||||
|
|
|
|||
|
|
@ -822,6 +822,8 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
|
|||
ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. }) => {
|
||||
self.def_id(def_id);
|
||||
}
|
||||
|
||||
ty::ReClosureBound(..) |
|
||||
ty::ReLateBound(..) |
|
||||
ty::ReFree(..) |
|
||||
ty::ReScope(..) |
|
||||
|
|
|
|||
|
|
@ -733,6 +733,9 @@ define_print! {
|
|||
ty::ReErased => Ok(()),
|
||||
ty::ReStatic => write!(f, "'static"),
|
||||
ty::ReEmpty => write!(f, "'<empty>"),
|
||||
|
||||
// The user should never encounter these in unsubstituted form.
|
||||
ty::ReClosureBound(vid) => write!(f, "{:?}", vid),
|
||||
}
|
||||
}
|
||||
debug {
|
||||
|
|
@ -743,6 +746,11 @@ define_print! {
|
|||
data.name)
|
||||
}
|
||||
|
||||
ty::ReClosureBound(ref vid) => {
|
||||
write!(f, "ReClosureBound({:?})",
|
||||
vid)
|
||||
}
|
||||
|
||||
ty::ReLateBound(binder_id, ref bound_region) => {
|
||||
write!(f, "ReLateBound({:?}, {:?})",
|
||||
binder_id,
|
||||
|
|
|
|||
|
|
@ -367,6 +367,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
|
|||
ty::ReStatic => self.item_ub,
|
||||
|
||||
ty::ReEmpty |
|
||||
ty::ReClosureBound(..) |
|
||||
ty::ReLateBound(..) |
|
||||
ty::ReVar(..) |
|
||||
ty::ReSkolemized(..) |
|
||||
|
|
|
|||
|
|
@ -381,6 +381,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
},
|
||||
(RegionKind::ReLateBound(_, _), _) |
|
||||
(RegionKind::ReSkolemized(_, _), _) |
|
||||
(RegionKind::ReClosureBound(_), _) |
|
||||
(RegionKind::ReErased, _) => {
|
||||
span_bug!(drop_span, "region does not make sense in this context");
|
||||
},
|
||||
|
|
|
|||
|
|
@ -22,16 +22,16 @@ use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind};
|
|||
use rustc::mir::ClosureRegionRequirements;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::indexed_set::{IdxSetBuf};
|
||||
use rustc_data_structures::indexed_set::IdxSetBuf;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use dataflow::{do_dataflow, DebugFormatted};
|
||||
use dataflow::FlowAtLocation;
|
||||
use dataflow::MoveDataParamEnv;
|
||||
use dataflow::{DataflowAnalysis, DataflowResultsConsumer};
|
||||
use dataflow::{FlowAtLocation, FlowsAtLocation};
|
||||
use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
|
||||
use dataflow::{EverInitializedLvals, MovingOutStatements};
|
||||
use dataflow::{Borrows, BorrowData, ReserveOrActivateIndex};
|
||||
|
|
@ -65,7 +65,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
fn mir_borrowck<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
) -> Option<ClosureRegionRequirements> {
|
||||
) -> Option<ClosureRegionRequirements<'tcx>> {
|
||||
let input_mir = tcx.mir_validated(def_id);
|
||||
debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id));
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
|||
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
input_mir: &Mir<'gcx>,
|
||||
def_id: DefId,
|
||||
) -> Option<ClosureRegionRequirements> {
|
||||
) -> Option<ClosureRegionRequirements<'gcx>> {
|
||||
let tcx = infcx.tcx;
|
||||
let attributes = tcx.get_attrs(def_id);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
|
|
|
|||
|
|
@ -12,21 +12,13 @@ use rustc::hir;
|
|||
use rustc::mir::{BasicBlock, BasicBlockData, Location, Place, Mir, Rvalue};
|
||||
use rustc::mir::visit::Visitor;
|
||||
use rustc::mir::Place::Projection;
|
||||
use rustc::mir::{Local, PlaceProjection, ProjectionElem};
|
||||
use rustc::mir::{PlaceProjection, ProjectionElem};
|
||||
use rustc::mir::visit::TyContext;
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::traits::{self, ObligationCause};
|
||||
use rustc::ty::{self, ClosureSubsts, Ty};
|
||||
use rustc::ty::{self, ClosureSubsts};
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::util::common::ErrorReported;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
use borrow_check::{FlowAtLocation, FlowsAtLocation};
|
||||
use dataflow::MaybeInitializedLvals;
|
||||
use dataflow::move_paths::{HasMoveData, MoveData};
|
||||
|
||||
use super::LivenessResults;
|
||||
use super::ToRegionVid;
|
||||
use super::region_infer::RegionInferenceContext;
|
||||
|
||||
|
|
@ -34,19 +26,11 @@ pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
|
|||
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
regioncx: &mut RegionInferenceContext<'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
liveness: &LivenessResults,
|
||||
flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
) {
|
||||
let mut cg = ConstraintGeneration {
|
||||
infcx,
|
||||
regioncx,
|
||||
mir,
|
||||
liveness,
|
||||
param_env,
|
||||
flow_inits,
|
||||
move_data,
|
||||
};
|
||||
|
||||
for (bb, data) in mir.basic_blocks().iter_enumerated() {
|
||||
|
|
@ -59,16 +43,10 @@ struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> {
|
|||
infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
regioncx: &'cg mut RegionInferenceContext<'tcx>,
|
||||
mir: &'cg Mir<'tcx>,
|
||||
liveness: &'cg LivenessResults,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
flow_inits: &'cg mut FlowAtLocation<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
|
||||
move_data: &'cg MoveData<'tcx>,
|
||||
}
|
||||
|
||||
|
||||
impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> {
|
||||
fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
|
||||
self.add_liveness_constraints(bb);
|
||||
self.super_basic_block_data(bb, data);
|
||||
}
|
||||
|
||||
|
|
@ -130,84 +108,6 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
|
|||
}
|
||||
|
||||
impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
|
||||
/// Liveness constraints:
|
||||
///
|
||||
/// > If a variable V is live at point P, then all regions R in the type of V
|
||||
/// > must include the point P.
|
||||
fn add_liveness_constraints(&mut self, bb: BasicBlock) {
|
||||
debug!("add_liveness_constraints(bb={:?})", bb);
|
||||
|
||||
self.liveness
|
||||
.regular
|
||||
.simulate_block(self.mir, bb, |location, live_locals| {
|
||||
for live_local in live_locals.iter() {
|
||||
let live_local_ty = self.mir.local_decls[live_local].ty;
|
||||
self.add_regular_live_constraint(live_local_ty, location);
|
||||
}
|
||||
});
|
||||
|
||||
let mut all_live_locals: Vec<(Location, Vec<Local>)> = vec![];
|
||||
self.liveness
|
||||
.drop
|
||||
.simulate_block(self.mir, bb, |location, live_locals| {
|
||||
all_live_locals.push((location, live_locals.iter().collect()));
|
||||
});
|
||||
debug!(
|
||||
"add_liveness_constraints: all_live_locals={:#?}",
|
||||
all_live_locals
|
||||
);
|
||||
|
||||
let terminator_index = self.mir.basic_blocks()[bb].statements.len();
|
||||
self.flow_inits.reset_to_entry_of(bb);
|
||||
while let Some((location, live_locals)) = all_live_locals.pop() {
|
||||
for live_local in live_locals {
|
||||
debug!(
|
||||
"add_liveness_constraints: location={:?} live_local={:?}",
|
||||
location,
|
||||
live_local
|
||||
);
|
||||
|
||||
self.flow_inits.each_state_bit(|mpi_init| {
|
||||
debug!(
|
||||
"add_liveness_constraints: location={:?} initialized={:?}",
|
||||
location,
|
||||
&self.flow_inits
|
||||
.operator()
|
||||
.move_data()
|
||||
.move_paths[mpi_init]
|
||||
);
|
||||
});
|
||||
|
||||
let mpi = self.move_data.rev_lookup.find_local(live_local);
|
||||
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
|
||||
debug!(
|
||||
"add_liveness_constraints: mpi={:?} has initialized child {:?}",
|
||||
self.move_data.move_paths[mpi],
|
||||
self.move_data.move_paths[initialized_child]
|
||||
);
|
||||
|
||||
let live_local_ty = self.mir.local_decls[live_local].ty;
|
||||
self.add_drop_live_constraint(live_local_ty, location);
|
||||
}
|
||||
}
|
||||
|
||||
if location.statement_index == terminator_index {
|
||||
debug!(
|
||||
"add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
|
||||
location
|
||||
);
|
||||
self.flow_inits.reconstruct_terminator_effect(location);
|
||||
} else {
|
||||
debug!(
|
||||
"add_liveness_constraints: reconstruct_statement_effect from {:#?}",
|
||||
location
|
||||
);
|
||||
self.flow_inits.reconstruct_statement_effect(location);
|
||||
}
|
||||
self.flow_inits.apply_local_effect(location);
|
||||
}
|
||||
}
|
||||
|
||||
/// Some variable with type `live_ty` is "regular live" at
|
||||
/// `location` -- i.e., it may be used later. This means that all
|
||||
/// regions appearing in the type `live_ty` must be live at
|
||||
|
|
@ -230,75 +130,6 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
/// Some variable with type `live_ty` is "drop live" at `location`
|
||||
/// -- i.e., it may be dropped later. This means that *some* of
|
||||
/// the regions in its type must be live at `location`. The
|
||||
/// precise set will depend on the dropck constraints, and in
|
||||
/// particular this takes `#[may_dangle]` into account.
|
||||
fn add_drop_live_constraint(&mut self, dropped_ty: Ty<'tcx>, location: Location) {
|
||||
debug!(
|
||||
"add_drop_live_constraint(dropped_ty={:?}, location={:?})",
|
||||
dropped_ty,
|
||||
location
|
||||
);
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let mut types = vec![(dropped_ty, 0)];
|
||||
let mut known = FxHashSet();
|
||||
while let Some((ty, depth)) = types.pop() {
|
||||
let span = DUMMY_SP; // FIXME
|
||||
let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) {
|
||||
Ok(result) => result,
|
||||
Err(ErrorReported) => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let ty::DtorckConstraint {
|
||||
outlives,
|
||||
dtorck_types,
|
||||
} = result;
|
||||
|
||||
// All things in the `outlives` array may be touched by
|
||||
// the destructor and must be live at this point.
|
||||
for outlive in outlives {
|
||||
self.add_regular_live_constraint(outlive, location);
|
||||
}
|
||||
|
||||
// However, there may also be some types that
|
||||
// `dtorck_constraint_for_ty` could not resolve (e.g.,
|
||||
// associated types and parameters). We need to normalize
|
||||
// associated types here and possibly recursively process.
|
||||
for ty in dtorck_types {
|
||||
let cause = ObligationCause::dummy();
|
||||
// We know that our original `dropped_ty` is well-formed,
|
||||
// so region obligations resulting from this normalization
|
||||
// should always hold.
|
||||
//
|
||||
// Therefore we ignore them instead of trying to match
|
||||
// them up with a location.
|
||||
let fulfillcx = traits::FulfillmentContext::new_ignoring_regions();
|
||||
match traits::fully_normalize_with_fulfillcx(
|
||||
self.infcx, fulfillcx, cause, self.param_env, &ty
|
||||
) {
|
||||
Ok(ty) => match ty.sty {
|
||||
ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
|
||||
self.add_regular_live_constraint(ty, location);
|
||||
}
|
||||
|
||||
_ => if known.insert(ty) {
|
||||
types.push((ty, depth + 1));
|
||||
},
|
||||
},
|
||||
|
||||
Err(errors) => {
|
||||
self.infcx.report_fulfillment_errors(&errors, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_reborrow_constraint(
|
||||
&mut self,
|
||||
location: Location,
|
||||
|
|
|
|||
|
|
@ -9,16 +9,16 @@
|
|||
// except according to those terms.
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir::{ClosureRegionRequirements, Mir};
|
||||
use rustc::mir::{ClosureRegionRequirements, ClosureOutlivesSubject, Mir};
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::ty::{self, RegionKind, RegionVid};
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt::Debug;
|
||||
use std::io;
|
||||
use transform::MirSource;
|
||||
use transform::type_check;
|
||||
use util::liveness::{self, LivenessMode, LivenessResult, LocalSet};
|
||||
use borrow_check::FlowAtLocation;
|
||||
use util::liveness::{LivenessResults, LocalSet};
|
||||
use dataflow::FlowAtLocation;
|
||||
use dataflow::MaybeInitializedLvals;
|
||||
use dataflow::move_paths::MoveData;
|
||||
|
||||
|
|
@ -27,14 +27,15 @@ use util::pretty::{self, ALIGN};
|
|||
use self::mir_util::PassWhere;
|
||||
|
||||
mod constraint_generation;
|
||||
pub(crate) mod region_infer;
|
||||
mod renumber;
|
||||
mod subtype_constraint_generation;
|
||||
pub(crate) mod type_check;
|
||||
mod universal_regions;
|
||||
|
||||
use self::region_infer::RegionInferenceContext;
|
||||
use self::universal_regions::UniversalRegions;
|
||||
|
||||
pub(crate) mod region_infer;
|
||||
use self::region_infer::RegionInferenceContext;
|
||||
|
||||
mod renumber;
|
||||
|
||||
/// Rewrites the regions in the MIR to use NLL variables, also
|
||||
/// scraping out the set of universal regions (e.g., region parameters)
|
||||
|
|
@ -52,7 +53,7 @@ pub(in borrow_check) fn replace_regions_in_mir<'cx, 'gcx, 'tcx>(
|
|||
let universal_regions = UniversalRegions::new(infcx, def_id, param_env);
|
||||
|
||||
// Replace all remaining regions with fresh inference variables.
|
||||
renumber::renumber_mir(infcx, &universal_regions, mir);
|
||||
renumber::renumber_mir(infcx, mir);
|
||||
|
||||
let source = MirSource::item(def_id);
|
||||
mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, mir, |_, _| Ok(()));
|
||||
|
|
@ -73,11 +74,24 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
|||
move_data: &MoveData<'tcx>,
|
||||
) -> (
|
||||
RegionInferenceContext<'tcx>,
|
||||
Option<ClosureRegionRequirements>,
|
||||
Option<ClosureRegionRequirements<'gcx>>,
|
||||
) {
|
||||
// Run the MIR type-checker.
|
||||
let mir_node_id = infcx.tcx.hir.as_local_node_id(def_id).unwrap();
|
||||
let constraint_sets = &type_check::type_check(infcx, mir_node_id, param_env, mir);
|
||||
let liveness = &LivenessResults::compute(mir);
|
||||
let fr_fn_body = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
|
||||
let constraint_sets = &type_check::type_check(
|
||||
infcx,
|
||||
mir_node_id,
|
||||
param_env,
|
||||
mir,
|
||||
fr_fn_body,
|
||||
universal_regions.input_tys,
|
||||
universal_regions.output_ty,
|
||||
&liveness,
|
||||
flow_inits,
|
||||
move_data,
|
||||
);
|
||||
|
||||
// Create the region inference context, taking ownership of the region inference
|
||||
// data that was contained in `infcx`.
|
||||
|
|
@ -85,35 +99,9 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
|||
let mut regioncx = RegionInferenceContext::new(var_origins, universal_regions, mir);
|
||||
subtype_constraint_generation::generate(&mut regioncx, mir, constraint_sets);
|
||||
|
||||
// Compute what is live where.
|
||||
let liveness = &LivenessResults {
|
||||
regular: liveness::liveness_of_locals(
|
||||
&mir,
|
||||
LivenessMode {
|
||||
include_regular_use: true,
|
||||
include_drops: false,
|
||||
},
|
||||
),
|
||||
|
||||
drop: liveness::liveness_of_locals(
|
||||
&mir,
|
||||
LivenessMode {
|
||||
include_regular_use: false,
|
||||
include_drops: true,
|
||||
},
|
||||
),
|
||||
};
|
||||
|
||||
// Generate non-subtyping constraints.
|
||||
constraint_generation::generate_constraints(
|
||||
infcx,
|
||||
&mut regioncx,
|
||||
&mir,
|
||||
param_env,
|
||||
liveness,
|
||||
flow_inits,
|
||||
move_data,
|
||||
);
|
||||
constraint_generation::generate_constraints(infcx, &mut regioncx, &mir);
|
||||
|
||||
// Solve the region constraints.
|
||||
let closure_region_requirements = regioncx.solve(infcx, &mir, def_id);
|
||||
|
|
@ -136,11 +124,6 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
|||
(regioncx, closure_region_requirements)
|
||||
}
|
||||
|
||||
struct LivenessResults {
|
||||
regular: LivenessResult,
|
||||
drop: LivenessResult,
|
||||
}
|
||||
|
||||
fn dump_mir_results<'a, 'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
liveness: &LivenessResults,
|
||||
|
|
@ -283,9 +266,13 @@ fn for_each_region_constraint(
|
|||
with_msg: &mut FnMut(&str) -> io::Result<()>,
|
||||
) -> io::Result<()> {
|
||||
for req in &closure_region_requirements.outlives_requirements {
|
||||
let subject: &Debug = match &req.subject {
|
||||
ClosureOutlivesSubject::Region(subject) => subject,
|
||||
ClosureOutlivesSubject::Ty(ty) => ty,
|
||||
};
|
||||
with_msg(&format!(
|
||||
"where {:?}: {:?}",
|
||||
req.free_region,
|
||||
subject,
|
||||
req.outlived_free_region,
|
||||
))?;
|
||||
}
|
||||
|
|
|
|||
234
src/librustc_mir/borrow_check/nll/region_infer/dfs.rs
Normal file
234
src/librustc_mir/borrow_check/nll/region_infer/dfs.rs
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Module defining the `dfs` method on `RegionInferenceContext`, along with
|
||||
//! its associated helper traits.
|
||||
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
use borrow_check::nll::region_infer::RegionInferenceContext;
|
||||
use borrow_check::nll::region_infer::values::{RegionElementIndex, RegionValueElements,
|
||||
RegionValues};
|
||||
use rustc::mir::{Location, Mir};
|
||||
use rustc::ty::RegionVid;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Function used to satisfy or test a `R1: R2 @ P`
|
||||
/// constraint. The core idea is that it performs a DFS starting
|
||||
/// from `P`. The precise actions *during* that DFS depend on the
|
||||
/// `op` supplied, so see (e.g.) `CopyFromSourceToTarget` for more
|
||||
/// details.
|
||||
///
|
||||
/// Returns:
|
||||
///
|
||||
/// - `Ok(true)` if the walk was completed and something changed
|
||||
/// along the way;
|
||||
/// - `Ok(false)` if the walk was completed with no changes;
|
||||
/// - `Err(early)` if the walk was existed early by `op`. `earlyelem` is the
|
||||
/// value that `op` returned.
|
||||
pub(super) fn dfs<C>(&self, mir: &Mir<'tcx>, mut op: C) -> Result<bool, C::Early>
|
||||
where
|
||||
C: DfsOp,
|
||||
{
|
||||
let mut changed = false;
|
||||
|
||||
let mut stack = vec![];
|
||||
let mut visited = FxHashSet();
|
||||
|
||||
stack.push(op.start_point());
|
||||
while let Some(p) = stack.pop() {
|
||||
let point_index = self.elements.index(p);
|
||||
|
||||
if !op.source_region_contains(point_index) {
|
||||
debug!(" not in from-region");
|
||||
continue;
|
||||
}
|
||||
|
||||
if !visited.insert(p) {
|
||||
debug!(" already visited");
|
||||
continue;
|
||||
}
|
||||
|
||||
let new = op.add_to_target_region(point_index)?;
|
||||
changed |= new;
|
||||
|
||||
let block_data = &mir[p.block];
|
||||
|
||||
let start_stack_len = stack.len();
|
||||
|
||||
if p.statement_index < block_data.statements.len() {
|
||||
stack.push(Location {
|
||||
statement_index: p.statement_index + 1,
|
||||
..p
|
||||
});
|
||||
} else {
|
||||
stack.extend(block_data.terminator().successors().iter().map(
|
||||
|&basic_block| {
|
||||
Location {
|
||||
statement_index: 0,
|
||||
block: basic_block,
|
||||
}
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
if stack.len() == start_stack_len {
|
||||
// If we reach the END point in the graph, then copy
|
||||
// over any skolemized end points in the `from_region`
|
||||
// and make sure they are included in the `to_region`.
|
||||
changed |= op.add_universal_regions_outlived_by_source_to_target()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(changed)
|
||||
}
|
||||
}
|
||||
|
||||
/// Customizes the operation of the `dfs` function. This function is
|
||||
/// used during inference to satisfy a `R1: R2 @ P` constraint.
|
||||
pub(super) trait DfsOp {
|
||||
/// If this op stops the walk early, what type does it propagate?
|
||||
type Early;
|
||||
|
||||
/// Returns the point from which to start the DFS.
|
||||
fn start_point(&self) -> Location;
|
||||
|
||||
/// Returns true if the source region contains the given point.
|
||||
fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool;
|
||||
|
||||
/// Adds the given point to the target region, returning true if
|
||||
/// something has changed. Returns `Err` if we should abort the
|
||||
/// walk early.
|
||||
fn add_to_target_region(
|
||||
&mut self,
|
||||
point_index: RegionElementIndex,
|
||||
) -> Result<bool, Self::Early>;
|
||||
|
||||
/// Adds all universal regions in the source region to the target region, returning
|
||||
/// true if something has changed.
|
||||
fn add_universal_regions_outlived_by_source_to_target(&mut self) -> Result<bool, Self::Early>;
|
||||
}
|
||||
|
||||
/// Used during inference to enforce a `R1: R2 @ P` constraint. For
|
||||
/// each point Q we reach along the DFS, we check if Q is in R2 (the
|
||||
/// "source region"). If not, we stop the walk. Otherwise, we add Q to
|
||||
/// R1 (the "target region") and continue to Q's successors. If we
|
||||
/// reach the end of the graph, then we add any universal regions from
|
||||
/// R2 into R1.
|
||||
pub(super) struct CopyFromSourceToTarget<'v> {
|
||||
pub source_region: RegionVid,
|
||||
pub target_region: RegionVid,
|
||||
pub inferred_values: &'v mut RegionValues,
|
||||
pub constraint_point: Location,
|
||||
}
|
||||
|
||||
impl<'v> DfsOp for CopyFromSourceToTarget<'v> {
|
||||
/// We never stop the walk early.
|
||||
type Early = !;
|
||||
|
||||
fn start_point(&self) -> Location {
|
||||
self.constraint_point
|
||||
}
|
||||
|
||||
fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool {
|
||||
self.inferred_values
|
||||
.contains(self.source_region, point_index)
|
||||
}
|
||||
|
||||
fn add_to_target_region(&mut self, point_index: RegionElementIndex) -> Result<bool, !> {
|
||||
Ok(self.inferred_values.add(self.target_region, point_index))
|
||||
}
|
||||
|
||||
fn add_universal_regions_outlived_by_source_to_target(&mut self) -> Result<bool, !> {
|
||||
Ok(
|
||||
self.inferred_values
|
||||
.add_universal_regions_outlived_by(self.source_region, self.target_region),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Used after inference to *test* a `R1: R2 @ P` constraint. For
|
||||
/// each point Q we reach along the DFS, we check if Q in R2 is also
|
||||
/// contained in R1. If not, we abort the walk early with an `Err`
|
||||
/// condition. Similarly, if we reach the end of the graph and find
|
||||
/// that R1 contains some universal region that R2 does not contain,
|
||||
/// we abort the walk early.
|
||||
pub(super) struct TestTargetOutlivesSource<'v, 'tcx: 'v> {
|
||||
pub source_region: RegionVid,
|
||||
pub target_region: RegionVid,
|
||||
pub elements: &'v RegionValueElements,
|
||||
pub universal_regions: &'v UniversalRegions<'tcx>,
|
||||
pub inferred_values: &'v RegionValues,
|
||||
pub constraint_point: Location,
|
||||
}
|
||||
|
||||
impl<'v, 'tcx> DfsOp for TestTargetOutlivesSource<'v, 'tcx> {
|
||||
/// The element that was not found within R2.
|
||||
type Early = RegionElementIndex;
|
||||
|
||||
fn start_point(&self) -> Location {
|
||||
self.constraint_point
|
||||
}
|
||||
|
||||
fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool {
|
||||
self.inferred_values
|
||||
.contains(self.source_region, point_index)
|
||||
}
|
||||
|
||||
fn add_to_target_region(
|
||||
&mut self,
|
||||
point_index: RegionElementIndex,
|
||||
) -> Result<bool, RegionElementIndex> {
|
||||
if !self.inferred_values
|
||||
.contains(self.target_region, point_index)
|
||||
{
|
||||
return Err(point_index);
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn add_universal_regions_outlived_by_source_to_target(
|
||||
&mut self,
|
||||
) -> Result<bool, RegionElementIndex> {
|
||||
// For all `ur_in_source` in `source_region`.
|
||||
for ur_in_source in self.inferred_values
|
||||
.universal_regions_outlived_by(self.source_region)
|
||||
{
|
||||
// Check that `target_region` outlives `ur_in_source`.
|
||||
|
||||
// If `ur_in_source` is a member of `target_region`, OK.
|
||||
//
|
||||
// (This is implied by the loop below, actually, just an
|
||||
// irresistible micro-opt. Mm. Premature optimization. So
|
||||
// tasty.)
|
||||
if self.inferred_values
|
||||
.contains(self.target_region, ur_in_source)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there is some other element X such that `target_region: X` and
|
||||
// `X: ur_in_source`, OK.
|
||||
if self.inferred_values
|
||||
.universal_regions_outlived_by(self.target_region)
|
||||
.any(|ur_in_target| {
|
||||
self.universal_regions.outlives(ur_in_target, ur_in_source)
|
||||
}) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, not known to be true.
|
||||
return Err(self.elements.index(ur_in_source));
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
|
@ -12,18 +12,23 @@ use super::universal_regions::UniversalRegions;
|
|||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::infer::NLLRegionVariableOrigin;
|
||||
use rustc::infer::RegionObligation;
|
||||
use rustc::infer::RegionVariableOrigin;
|
||||
use rustc::infer::SubregionOrigin;
|
||||
use rustc::infer::region_constraints::VarOrigins;
|
||||
use rustc::mir::{ClosureOutlivesRequirement, ClosureRegionRequirements, Location, Mir};
|
||||
use rustc::ty::{self, RegionVid};
|
||||
use rustc::infer::region_constraints::{GenericKind, VarOrigins};
|
||||
use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
|
||||
Location, Mir};
|
||||
use rustc::traits::ObligationCause;
|
||||
use rustc::ty::{self, RegionVid, Ty, TypeFoldable};
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
|
||||
mod annotation;
|
||||
mod dfs;
|
||||
use self::dfs::{CopyFromSourceToTarget, TestTargetOutlivesSource};
|
||||
mod dump_mir;
|
||||
mod graphviz;
|
||||
mod values;
|
||||
|
|
@ -52,6 +57,9 @@ pub struct RegionInferenceContext<'tcx> {
|
|||
/// The constraints we have accumulated and used during solving.
|
||||
constraints: Vec<Constraint>,
|
||||
|
||||
/// Type constraints that we check after solving.
|
||||
type_tests: Vec<TypeTest<'tcx>>,
|
||||
|
||||
/// Information about the universally quantified regions in scope
|
||||
/// on this function and their (known) relations to one another.
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
|
|
@ -94,6 +102,92 @@ pub struct Constraint {
|
|||
span: Span,
|
||||
}
|
||||
|
||||
/// A "type test" corresponds to an outlives constraint between a type
|
||||
/// and a lifetime, like `T: 'x` or `<T as Foo>::Bar: 'x`. They are
|
||||
/// translated from the `Verify` region constraints in the ordinary
|
||||
/// inference context.
|
||||
///
|
||||
/// These sorts of constraints are handled differently than ordinary
|
||||
/// constraints, at least at present. During type checking, the
|
||||
/// `InferCtxt::process_registered_region_obligations` method will
|
||||
/// attempt to convert a type test like `T: 'x` into an ordinary
|
||||
/// outlives constraint when possible (for example, `&'a T: 'b` will
|
||||
/// be converted into `'a: 'b` and registered as a `Constraint`).
|
||||
///
|
||||
/// In some cases, however, there are outlives relationships that are
|
||||
/// not converted into a region constraint, but rather into one of
|
||||
/// these "type tests". The distinction is that a type test does not
|
||||
/// influence the inference result, but instead just examines the
|
||||
/// values that we ultimately inferred for each region variable and
|
||||
/// checks that they meet certain extra criteria. If not, an error
|
||||
/// can be issued.
|
||||
///
|
||||
/// One reason for this is that these type tests typically boil down
|
||||
/// to a check like `'a: 'x` where `'a` is a universally quantified
|
||||
/// region -- and therefore not one whose value is really meant to be
|
||||
/// *inferred*, precisely (this is not always the case: one can have a
|
||||
/// type test like `<Foo as Trait<'?0>>::Bar: 'x`, where `'?0` is an
|
||||
/// inference variable). Another reason is that these type tests can
|
||||
/// involve *disjunction* -- that is, they can be satisfied in more
|
||||
/// than one way.
|
||||
///
|
||||
/// For more information about this translation, see
|
||||
/// `InferCtxt::process_registered_region_obligations` and
|
||||
/// `InferCtxt::type_must_outlive` in `rustc::infer::outlives`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TypeTest<'tcx> {
|
||||
/// The type `T` that must outlive the region.
|
||||
pub generic_kind: GenericKind<'tcx>,
|
||||
|
||||
/// The region `'x` that the type must outlive.
|
||||
pub lower_bound: RegionVid,
|
||||
|
||||
/// The point where the outlives relation must hold.
|
||||
pub point: Location,
|
||||
|
||||
/// Where did this constraint arise?
|
||||
pub span: Span,
|
||||
|
||||
/// A test which, if met by the region `'x`, proves that this type
|
||||
/// constraint is satisfied.
|
||||
pub test: RegionTest,
|
||||
}
|
||||
|
||||
/// A "test" that can be applied to some "subject region" `'x`. These are used to
|
||||
/// describe type constraints. Tests do not presently affect the
|
||||
/// region values that get inferred for each variable; they only
|
||||
/// examine the results *after* inference. This means they can
|
||||
/// conveniently include disjuction ("a or b must be true").
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum RegionTest {
|
||||
/// The subject region `'x` must by outlived by *some* region in
|
||||
/// the given set of regions.
|
||||
///
|
||||
/// This test comes from e.g. a where clause like `T: 'a + 'b`,
|
||||
/// which implies that we know that `T: 'a` and that `T:
|
||||
/// 'b`. Therefore, if we are trying to prove that `T: 'x`, we can
|
||||
/// do so by showing that `'a: 'x` *or* `'b: 'x`.
|
||||
IsOutlivedByAnyRegionIn(Vec<RegionVid>),
|
||||
|
||||
/// The subject region `'x` must by outlived by *all* regions in
|
||||
/// the given set of regions.
|
||||
///
|
||||
/// This test comes from e.g. a projection type like `T = <u32 as
|
||||
/// Trait<'a, 'b>>::Foo`, which must outlive `'a` or `'b`, and
|
||||
/// maybe both. Therefore we can prove that `T: 'x` if we know
|
||||
/// that `'a: 'x` *and* `'b: 'x`.
|
||||
IsOutlivedByAllRegionsIn(Vec<RegionVid>),
|
||||
|
||||
/// Any of the given tests are true.
|
||||
///
|
||||
/// This arises from projections, for which there are multiple
|
||||
/// ways to prove an outlives relationship.
|
||||
Any(Vec<RegionTest>),
|
||||
|
||||
/// All of the given tests are true.
|
||||
All(Vec<RegionTest>),
|
||||
}
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Creates a new region inference context with a total of
|
||||
/// `num_region_variables` valid inference variables; the first N
|
||||
|
|
@ -121,6 +215,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
liveness_constraints: RegionValues::new(elements, num_region_variables),
|
||||
inferred_values: None,
|
||||
constraints: Vec::new(),
|
||||
type_tests: Vec::new(),
|
||||
universal_regions,
|
||||
};
|
||||
|
||||
|
|
@ -242,32 +337,414 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
/// Perform region inference.
|
||||
pub(super) fn solve(
|
||||
/// Add a "type test" that must be satisfied.
|
||||
pub(super) fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
|
||||
self.type_tests.push(type_test);
|
||||
}
|
||||
|
||||
/// Perform region inference and report errors if we see any
|
||||
/// unsatisfiable constraints. If this is a closure, returns the
|
||||
/// region requirements to propagate to our creator, if any.
|
||||
pub(super) fn solve<'gcx>(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
) -> Option<ClosureRegionRequirements> {
|
||||
) -> Option<ClosureRegionRequirements<'gcx>> {
|
||||
assert!(self.inferred_values.is_none(), "values already inferred");
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
// Find the minimal regions that can solve the constraints. This is infallible.
|
||||
self.propagate_constraints(mir);
|
||||
|
||||
// Now, see whether any of the constraints were too strong. In
|
||||
// particular, we want to check for a case where a universally
|
||||
// quantified region exceeded its bounds. Consider:
|
||||
//
|
||||
// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
|
||||
//
|
||||
// In this case, returning `x` requires `&'a u32 <: &'b u32`
|
||||
// and hence we establish (transitively) a constraint that
|
||||
// `'a: 'b`. The `propagate_constraints` code above will
|
||||
// therefore add `end('a)` into the region for `'b` -- but we
|
||||
// have no evidence that `'a` outlives `'b`, so we want to report
|
||||
// an error.
|
||||
// If this is a closure, we can propagate unsatisfied
|
||||
// `outlives_requirements` to our creator, so create a vector
|
||||
// to store those. Otherwise, we'll pass in `None` to the
|
||||
// functions below, which will trigger them to report errors
|
||||
// eagerly.
|
||||
let mut outlives_requirements = if infcx.tcx.is_closure(mir_def_id) {
|
||||
Some(vec![])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
self.check_type_tests(infcx, mir, outlives_requirements.as_mut());
|
||||
|
||||
self.check_universal_regions(infcx, outlives_requirements.as_mut());
|
||||
|
||||
let outlives_requirements = outlives_requirements.unwrap_or(vec![]);
|
||||
|
||||
if outlives_requirements.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let num_external_vids = self.universal_regions.num_global_and_external_regions();
|
||||
Some(ClosureRegionRequirements {
|
||||
num_external_vids,
|
||||
outlives_requirements,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Propagate the region constraints: this will grow the values
|
||||
/// for each region variable until all the constraints are
|
||||
/// satisfied. Note that some values may grow **too** large to be
|
||||
/// feasible, but we check this later.
|
||||
fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
|
||||
let mut changed = true;
|
||||
|
||||
debug!("propagate_constraints()");
|
||||
debug!("propagate_constraints: constraints={:#?}", {
|
||||
let mut constraints: Vec<_> = self.constraints.iter().collect();
|
||||
constraints.sort();
|
||||
constraints
|
||||
});
|
||||
|
||||
// The initial values for each region are derived from the liveness
|
||||
// constraints we have accumulated.
|
||||
let mut inferred_values = self.liveness_constraints.clone();
|
||||
|
||||
while changed {
|
||||
changed = false;
|
||||
debug!("propagate_constraints: --------------------");
|
||||
for constraint in &self.constraints {
|
||||
debug!("propagate_constraints: constraint={:?}", constraint);
|
||||
|
||||
// Grow the value as needed to accommodate the
|
||||
// outlives constraint.
|
||||
let Ok(made_changes) = self.dfs(
|
||||
mir,
|
||||
CopyFromSourceToTarget {
|
||||
source_region: constraint.sub,
|
||||
target_region: constraint.sup,
|
||||
inferred_values: &mut inferred_values,
|
||||
constraint_point: constraint.point,
|
||||
},
|
||||
);
|
||||
|
||||
if made_changes {
|
||||
debug!("propagate_constraints: sub={:?}", constraint.sub);
|
||||
debug!("propagate_constraints: sup={:?}", constraint.sup);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
debug!("\n");
|
||||
}
|
||||
|
||||
self.inferred_values = Some(inferred_values);
|
||||
}
|
||||
|
||||
/// Once regions have been propagated, this method is used to see
|
||||
/// whether the "type tests" produced by typeck were satisfied;
|
||||
/// type tests encode type-outlives relationships like `T:
|
||||
/// 'a`. See `TypeTest` for more details.
|
||||
fn check_type_tests<'gcx>(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
for type_test in &self.type_tests {
|
||||
debug!("check_type_test: {:?}", type_test);
|
||||
|
||||
if self.eval_region_test(mir, type_test.point, type_test.lower_bound, &type_test.test) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
|
||||
if self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Oh the humanity. Obviously we will do better than this error eventually.
|
||||
tcx.sess.span_err(
|
||||
type_test.span,
|
||||
&format!(
|
||||
"`{}` does not outlive `{:?}`",
|
||||
type_test.generic_kind,
|
||||
type_test.lower_bound,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn try_promote_type_test<'gcx>(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
type_test: &TypeTest<'tcx>,
|
||||
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'gcx>>,
|
||||
) -> bool {
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
let TypeTest {
|
||||
generic_kind,
|
||||
lower_bound,
|
||||
point: _,
|
||||
span,
|
||||
test: _,
|
||||
} = type_test;
|
||||
|
||||
let generic_ty = generic_kind.to_ty(tcx);
|
||||
let subject = match self.try_promote_type_test_subject(infcx, generic_ty) {
|
||||
Some(s) => s,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// Find some bounding subject-region R+ that is a super-region
|
||||
// of the existing subject-region R. This should be a non-local, universal
|
||||
// region, which ensures it can be encoded in a `ClosureOutlivesRequirement`.
|
||||
let lower_bound_plus = self.non_local_universal_upper_bound(*lower_bound);
|
||||
assert!(self.universal_regions.is_universal_region(lower_bound_plus));
|
||||
assert!(!self.universal_regions
|
||||
.is_local_free_region(lower_bound_plus));
|
||||
|
||||
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
|
||||
subject,
|
||||
outlived_free_region: lower_bound_plus,
|
||||
blame_span: *span,
|
||||
});
|
||||
true
|
||||
}
|
||||
|
||||
/// When we promote a type test `T: 'r`, we have to convert the
|
||||
/// type `T` into something we can store in a query result (so
|
||||
/// something allocated for `'gcx`). This is problematic if `ty`
|
||||
/// contains regions. During the course of NLL region checking, we
|
||||
/// will have replaced all of those regions with fresh inference
|
||||
/// variables. To create a test subject, we want to replace those
|
||||
/// inference variables with some region from the closure
|
||||
/// signature -- this is not always possible, so this is a
|
||||
/// fallible process. Presuming we do find a suitable region, we
|
||||
/// will represent it with a `ReClosureBound`, which is a
|
||||
/// `RegionKind` variant that can be allocated in the gcx.
|
||||
fn try_promote_type_test_subject<'gcx>(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<ClosureOutlivesSubject<'gcx>> {
|
||||
let tcx = infcx.tcx;
|
||||
let gcx = tcx.global_tcx();
|
||||
let inferred_values = self.inferred_values
|
||||
.as_ref()
|
||||
.expect("region values not yet inferred");
|
||||
|
||||
debug!("try_promote_type_test_subject(ty = {:?})", ty);
|
||||
|
||||
let ty = tcx.fold_regions(&ty, &mut false, |r, _depth| {
|
||||
let region_vid = self.to_region_vid(r);
|
||||
|
||||
// The challenge if this. We have some region variable `r`
|
||||
// whose value is a set of CFG points and universal
|
||||
// regions. We want to find if that set is *equivalent* to
|
||||
// any of the named regions found in the closure.
|
||||
//
|
||||
// To do so, we compute the
|
||||
// `non_local_universal_upper_bound`. This will be a
|
||||
// non-local, universal region that is greater than `r`.
|
||||
// However, it might not be *contained* within `r`, so
|
||||
// then we further check whether this bound is contained
|
||||
// in `r`. If so, we can say that `r` is equivalent to the
|
||||
// bound.
|
||||
//
|
||||
// Let's work through a few examples. For these, imagine
|
||||
// that we have 3 non-local regions (I'll denote them as
|
||||
// `'static`, `'a`, and `'b`, though of course in the code
|
||||
// they would be represented with indices) where:
|
||||
//
|
||||
// - `'static: 'a`
|
||||
// - `'static: 'b`
|
||||
//
|
||||
// First, let's assume that `r` is some existential
|
||||
// variable with an inferred value `{'a, 'static}` (plus
|
||||
// some CFG nodes). In this case, the non-local upper
|
||||
// bound is `'static`, since that outlives `'a`. `'static`
|
||||
// is also a member of `r` and hence we consider `r`
|
||||
// equivalent to `'static` (and replace it with
|
||||
// `'static`).
|
||||
//
|
||||
// Now let's consider the inferred value `{'a, 'b}`. This
|
||||
// means `r` is effectively `'a | 'b`. I'm not sure if
|
||||
// this can come about, actually, but assuming it did, we
|
||||
// would get a non-local upper bound of `'static`. Since
|
||||
// `'static` is not contained in `r`, we would fail to
|
||||
// find an equivalent.
|
||||
let upper_bound = self.non_local_universal_upper_bound(region_vid);
|
||||
if inferred_values.contains(region_vid, upper_bound) {
|
||||
tcx.mk_region(ty::ReClosureBound(upper_bound))
|
||||
} else {
|
||||
// In the case of a failure, use a `ReVar`
|
||||
// result. This will cause the `lift` later on to
|
||||
// fail.
|
||||
r
|
||||
}
|
||||
});
|
||||
debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
|
||||
|
||||
// `lift` will only fail if we failed to promote some region.
|
||||
let ty = gcx.lift(&ty)?;
|
||||
|
||||
Some(ClosureOutlivesSubject::Ty(ty))
|
||||
}
|
||||
|
||||
/// Given some universal or existential region `r`, finds a
|
||||
/// non-local, universal region `r+` that outlives `r` at entry to (and
|
||||
/// exit from) the closure. In the worst case, this will be
|
||||
/// `'static`.
|
||||
///
|
||||
/// This is used for two purposes. First, if we are propagated
|
||||
/// some requirement `T: r`, we can use this method to enlarge `r`
|
||||
/// to something we can encode for our creator (which only knows
|
||||
/// about non-local, universal regions). It is also used when
|
||||
/// encoding `T` as part of `try_promote_type_test_subject` (see
|
||||
/// that fn for details).
|
||||
///
|
||||
/// Since `r` is (potentially) an existential region, it has some
|
||||
/// value which may include (a) any number of points in the CFG
|
||||
/// and (b) any number of `end('x)` elements of universally
|
||||
/// quantified regions. To convert this into a single universal
|
||||
/// region we do as follows:
|
||||
///
|
||||
/// - Ignore the CFG points in `'r`. All universally quantified regions
|
||||
/// include the CFG anyhow.
|
||||
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
|
||||
/// a result `'y`.
|
||||
/// - Finally, we take the non-local upper bound of `'y`.
|
||||
/// - This uses `UniversalRegions::non_local_upper_bound`, which
|
||||
/// is similar to this method but only works on universal
|
||||
/// regions).
|
||||
fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
|
||||
let inferred_values = self.inferred_values.as_ref().unwrap();
|
||||
|
||||
debug!(
|
||||
"non_local_universal_upper_bound(r={:?}={})",
|
||||
r,
|
||||
inferred_values.region_value_str(r)
|
||||
);
|
||||
|
||||
// Find the smallest universal region that contains all other
|
||||
// universal regions within `region`.
|
||||
let mut lub = self.universal_regions.fr_fn_body;
|
||||
for ur in inferred_values.universal_regions_outlived_by(r) {
|
||||
lub = self.universal_regions.postdom_upper_bound(lub, ur);
|
||||
}
|
||||
|
||||
debug!("non_local_universal_upper_bound: lub={:?}", lub);
|
||||
|
||||
// Grow further to get smallest universal region known to
|
||||
// creator.
|
||||
let non_local_lub = self.universal_regions.non_local_upper_bound(lub);
|
||||
|
||||
debug!(
|
||||
"non_local_universal_upper_bound: non_local_lub={:?}",
|
||||
non_local_lub
|
||||
);
|
||||
|
||||
non_local_lub
|
||||
}
|
||||
|
||||
/// Test if `test` is true when applied to `lower_bound` at
|
||||
/// `point`, and returns true or false.
|
||||
fn eval_region_test(
|
||||
&self,
|
||||
mir: &Mir<'tcx>,
|
||||
point: Location,
|
||||
lower_bound: RegionVid,
|
||||
test: &RegionTest,
|
||||
) -> bool {
|
||||
debug!(
|
||||
"eval_region_test(point={:?}, lower_bound={:?}, test={:?})",
|
||||
point,
|
||||
lower_bound,
|
||||
test
|
||||
);
|
||||
|
||||
match test {
|
||||
RegionTest::IsOutlivedByAllRegionsIn(regions) => regions
|
||||
.iter()
|
||||
.all(|&r| self.eval_outlives(mir, r, lower_bound, point)),
|
||||
|
||||
RegionTest::IsOutlivedByAnyRegionIn(regions) => regions
|
||||
.iter()
|
||||
.any(|&r| self.eval_outlives(mir, r, lower_bound, point)),
|
||||
|
||||
RegionTest::Any(tests) => tests
|
||||
.iter()
|
||||
.any(|test| self.eval_region_test(mir, point, lower_bound, test)),
|
||||
|
||||
RegionTest::All(tests) => tests
|
||||
.iter()
|
||||
.all(|test| self.eval_region_test(mir, point, lower_bound, test)),
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate whether `sup_region: sub_region @ point`.
|
||||
fn eval_outlives(
|
||||
&self,
|
||||
mir: &Mir<'tcx>,
|
||||
sup_region: RegionVid,
|
||||
sub_region: RegionVid,
|
||||
point: Location,
|
||||
) -> bool {
|
||||
debug!(
|
||||
"eval_outlives({:?}: {:?} @ {:?})",
|
||||
sup_region,
|
||||
sub_region,
|
||||
point
|
||||
);
|
||||
|
||||
// Roughly speaking, do a DFS of all region elements reachable
|
||||
// from `point` contained in `sub_region`. If any of those are
|
||||
// *not* present in `sup_region`, the DFS will abort early and
|
||||
// yield an `Err` result.
|
||||
match self.dfs(
|
||||
mir,
|
||||
TestTargetOutlivesSource {
|
||||
source_region: sub_region,
|
||||
target_region: sup_region,
|
||||
constraint_point: point,
|
||||
elements: &self.elements,
|
||||
universal_regions: &self.universal_regions,
|
||||
inferred_values: self.inferred_values.as_ref().unwrap(),
|
||||
},
|
||||
) {
|
||||
Ok(_) => {
|
||||
debug!("eval_outlives: true");
|
||||
true
|
||||
}
|
||||
|
||||
Err(elem) => {
|
||||
debug!(
|
||||
"eval_outlives: false because `{:?}` is not present in `{:?}`",
|
||||
self.elements.to_element(elem),
|
||||
sup_region
|
||||
);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Once regions have been propagated, this method is used to see
|
||||
/// whether any of the constraints were too strong. In particular,
|
||||
/// we want to check for a case where a universally quantified
|
||||
/// region exceeded its bounds. Consider:
|
||||
///
|
||||
/// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
|
||||
///
|
||||
/// In this case, returning `x` requires `&'a u32 <: &'b u32`
|
||||
/// and hence we establish (transitively) a constraint that
|
||||
/// `'a: 'b`. The `propagate_constraints` code above will
|
||||
/// therefore add `end('a)` into the region for `'b` -- but we
|
||||
/// have no evidence that `'b` outlives `'a`, so we want to report
|
||||
/// an error.
|
||||
///
|
||||
/// If `propagated_outlives_requirements` is `Some`, then we will
|
||||
/// push unsatisfied obligations into there. Otherwise, we'll
|
||||
/// report them as errors.
|
||||
fn check_universal_regions<'gcx>(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
|
||||
) {
|
||||
// The universal regions are always found in a prefix of the
|
||||
// full list.
|
||||
let universal_definitions = self.definitions
|
||||
|
|
@ -277,32 +754,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// Go through each of the universal regions `fr` and check that
|
||||
// they did not grow too large, accumulating any requirements
|
||||
// for our caller into the `outlives_requirements` vector.
|
||||
let mut outlives_requirements = vec![];
|
||||
for (fr, _) in universal_definitions {
|
||||
self.check_universal_region(infcx, fr, &mut outlives_requirements);
|
||||
self.check_universal_region(infcx, fr, &mut propagated_outlives_requirements);
|
||||
}
|
||||
|
||||
// If this is not a closure, then there is no caller to which we can
|
||||
// "pass the buck". So if there are any outlives-requirements that were
|
||||
// not satisfied, we just have to report a hard error here.
|
||||
if !tcx.is_closure(mir_def_id) {
|
||||
for outlives_requirement in outlives_requirements {
|
||||
self.report_error(
|
||||
infcx,
|
||||
outlives_requirement.free_region,
|
||||
outlives_requirement.outlived_free_region,
|
||||
outlives_requirement.blame_span,
|
||||
);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
let num_external_vids = self.universal_regions.num_global_and_external_regions();
|
||||
|
||||
Some(ClosureRegionRequirements {
|
||||
num_external_vids,
|
||||
outlives_requirements,
|
||||
})
|
||||
}
|
||||
|
||||
/// Check the final value for the free region `fr` to see if it
|
||||
|
|
@ -313,11 +767,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
///
|
||||
/// Things that are to be propagated are accumulated into the
|
||||
/// `outlives_requirements` vector.
|
||||
fn check_universal_region(
|
||||
fn check_universal_region<'gcx>(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
longer_fr: RegionVid,
|
||||
outlives_requirements: &mut Vec<ClosureOutlivesRequirement>,
|
||||
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
|
||||
) {
|
||||
let inferred_values = self.inferred_values.as_ref().unwrap();
|
||||
|
||||
|
|
@ -339,33 +793,39 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
let blame_span = self.blame_span(longer_fr, shorter_fr);
|
||||
|
||||
// Shrink `fr` until we find a non-local region (if we do).
|
||||
// We'll call that `fr-` -- it's ever so slightly smaller than `fr`.
|
||||
if let Some(fr_minus) = self.universal_regions.non_local_lower_bound(longer_fr) {
|
||||
debug!("check_universal_region: fr_minus={:?}", fr_minus);
|
||||
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
|
||||
// Shrink `fr` until we find a non-local region (if we do).
|
||||
// We'll call that `fr-` -- it's ever so slightly smaller than `fr`.
|
||||
if let Some(fr_minus) = self.universal_regions.non_local_lower_bound(longer_fr) {
|
||||
debug!("check_universal_region: fr_minus={:?}", fr_minus);
|
||||
|
||||
// Grow `shorter_fr` until we find a non-local
|
||||
// regon. (We always will.) We'll call that
|
||||
// `shorter_fr+` -- it's ever so slightly larger than
|
||||
// `fr`.
|
||||
let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr);
|
||||
debug!(
|
||||
"check_universal_region: shorter_fr_plus={:?}",
|
||||
shorter_fr_plus
|
||||
);
|
||||
// Grow `shorter_fr` until we find a non-local
|
||||
// regon. (We always will.) We'll call that
|
||||
// `shorter_fr+` -- it's ever so slightly larger than
|
||||
// `fr`.
|
||||
let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr);
|
||||
debug!(
|
||||
"check_universal_region: shorter_fr_plus={:?}",
|
||||
shorter_fr_plus
|
||||
);
|
||||
|
||||
// Push the constraint `fr-: shorter_fr+`
|
||||
outlives_requirements.push(ClosureOutlivesRequirement {
|
||||
free_region: fr_minus,
|
||||
outlived_free_region: shorter_fr_plus,
|
||||
blame_span: blame_span,
|
||||
});
|
||||
return;
|
||||
// Push the constraint `fr-: shorter_fr+`
|
||||
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
|
||||
subject: ClosureOutlivesSubject::Region(fr_minus),
|
||||
outlived_free_region: shorter_fr_plus,
|
||||
blame_span: blame_span,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we could not shrink `fr` to something smaller that
|
||||
// the external users care about, then we can't pass the
|
||||
// buck; just report an error.
|
||||
// If we are not in a context where we can propagate
|
||||
// errors, or we could not shrink `fr` to something
|
||||
// smaller, then just report an error.
|
||||
//
|
||||
// Note: in this case, we use the unapproximated regions
|
||||
// to report the error. This gives better error messages
|
||||
// in some cases.
|
||||
self.report_error(infcx, longer_fr, shorter_fr, blame_span);
|
||||
}
|
||||
}
|
||||
|
|
@ -395,117 +855,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
/// Propagate the region constraints: this will grow the values
|
||||
/// for each region variable until all the constraints are
|
||||
/// satisfied. Note that some values may grow **too** large to be
|
||||
/// feasible, but we check this later.
|
||||
fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
|
||||
let mut changed = true;
|
||||
|
||||
debug!("propagate_constraints()");
|
||||
debug!("propagate_constraints: constraints={:#?}", {
|
||||
let mut constraints: Vec<_> = self.constraints.iter().collect();
|
||||
constraints.sort();
|
||||
constraints
|
||||
});
|
||||
|
||||
// The initial values for each region are derived from the liveness
|
||||
// constraints we have accumulated.
|
||||
let mut inferred_values = self.liveness_constraints.clone();
|
||||
|
||||
while changed {
|
||||
changed = false;
|
||||
debug!("propagate_constraints: --------------------");
|
||||
for constraint in &self.constraints {
|
||||
debug!("propagate_constraints: constraint={:?}", constraint);
|
||||
|
||||
// Grow the value as needed to accommodate the
|
||||
// outlives constraint.
|
||||
|
||||
if self.copy(
|
||||
&mut inferred_values,
|
||||
mir,
|
||||
constraint.sub,
|
||||
constraint.sup,
|
||||
constraint.point,
|
||||
) {
|
||||
debug!("propagate_constraints: sub={:?}", constraint.sub);
|
||||
debug!("propagate_constraints: sup={:?}", constraint.sup);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
debug!("\n");
|
||||
}
|
||||
|
||||
self.inferred_values = Some(inferred_values);
|
||||
}
|
||||
|
||||
fn copy(
|
||||
&self,
|
||||
inferred_values: &mut RegionValues,
|
||||
mir: &Mir<'tcx>,
|
||||
from_region: RegionVid,
|
||||
to_region: RegionVid,
|
||||
constraint_point: Location,
|
||||
) -> bool {
|
||||
let mut changed = false;
|
||||
|
||||
let mut stack = vec![];
|
||||
let mut visited = FxHashSet();
|
||||
|
||||
stack.push(constraint_point);
|
||||
while let Some(p) = stack.pop() {
|
||||
let point_index = self.elements.index(p);
|
||||
|
||||
if !inferred_values.contains(from_region, point_index) {
|
||||
debug!(" not in from-region");
|
||||
continue;
|
||||
}
|
||||
|
||||
if !visited.insert(p) {
|
||||
debug!(" already visited");
|
||||
continue;
|
||||
}
|
||||
|
||||
let new = inferred_values.add(to_region, point_index);
|
||||
changed |= new;
|
||||
|
||||
let block_data = &mir[p.block];
|
||||
let successor_points = if p.statement_index < block_data.statements.len() {
|
||||
vec![
|
||||
Location {
|
||||
statement_index: p.statement_index + 1,
|
||||
..p
|
||||
},
|
||||
]
|
||||
} else {
|
||||
block_data
|
||||
.terminator()
|
||||
.successors()
|
||||
.iter()
|
||||
.map(|&basic_block| {
|
||||
Location {
|
||||
statement_index: 0,
|
||||
block: basic_block,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
if successor_points.is_empty() {
|
||||
// If we reach the END point in the graph, then copy
|
||||
// over any skolemized end points in the `from_region`
|
||||
// and make sure they are included in the `to_region`.
|
||||
changed |=
|
||||
inferred_values.add_universal_regions_outlived_by(from_region, to_region);
|
||||
} else {
|
||||
stack.extend(successor_points);
|
||||
}
|
||||
}
|
||||
|
||||
changed
|
||||
}
|
||||
|
||||
/// Tries to finds a good span to blame for the fact that `fr1`
|
||||
/// contains `fr2`.
|
||||
fn blame_span(&self, fr1: RegionVid, fr2: RegionVid) -> Span {
|
||||
|
|
@ -520,35 +869,50 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// be obvious to the user -- not to mention the naive notion
|
||||
// of dependencies, which doesn't account for the locations of
|
||||
// contraints at all. But it will do for now.
|
||||
for constraint in &self.constraints {
|
||||
if constraint.sub == fr2 && influenced_fr1[constraint.sup] {
|
||||
return constraint.span;
|
||||
}
|
||||
}
|
||||
let relevant_constraint = self.constraints
|
||||
.iter()
|
||||
.filter_map(|constraint| {
|
||||
if constraint.sub != fr2 {
|
||||
None
|
||||
} else {
|
||||
influenced_fr1[constraint.sup]
|
||||
.map(|distance| (distance, constraint.span))
|
||||
}
|
||||
})
|
||||
.min() // constraining fr1 with fewer hops *ought* to be more obvious
|
||||
.map(|(_dist, span)| span);
|
||||
|
||||
bug!(
|
||||
"could not find any constraint to blame for {:?}: {:?}",
|
||||
fr1,
|
||||
fr2
|
||||
);
|
||||
relevant_constraint.unwrap_or_else(|| {
|
||||
bug!(
|
||||
"could not find any constraint to blame for {:?}: {:?}",
|
||||
fr1,
|
||||
fr2
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
/// Finds all regions whose values `'a` may depend on in some way.
|
||||
/// Basically if there exists a constraint `'a: 'b @ P`, then `'b`
|
||||
/// and `dependencies('b)` will be in the final set.
|
||||
/// For each region, returns either `None` (does not influence
|
||||
/// `'a`) or `Some(d)` which indicates that it influences `'a`
|
||||
/// with distinct `d` (minimum number of edges that must be
|
||||
/// traversed).
|
||||
///
|
||||
/// Used during error reporting, extremely naive and inefficient.
|
||||
fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, bool> {
|
||||
let mut result_set = IndexVec::from_elem(false, &self.definitions);
|
||||
fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> {
|
||||
let mut result_set = IndexVec::from_elem(None, &self.definitions);
|
||||
let mut changed = true;
|
||||
result_set[r0] = true;
|
||||
result_set[r0] = Some(0); // distance 0 from `r0`
|
||||
|
||||
while changed {
|
||||
changed = false;
|
||||
for constraint in &self.constraints {
|
||||
if result_set[constraint.sup] {
|
||||
if !result_set[constraint.sub] {
|
||||
result_set[constraint.sub] = true;
|
||||
if let Some(n) = result_set[constraint.sup] {
|
||||
let m = n + 1;
|
||||
if result_set[constraint.sub]
|
||||
.map(|distance| m < distance)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
result_set[constraint.sub] = Some(m);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -585,17 +949,27 @@ impl fmt::Debug for Constraint {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ClosureRegionRequirementsExt {
|
||||
fn apply_requirements<'tcx>(
|
||||
pub trait ClosureRegionRequirementsExt<'gcx, 'tcx> {
|
||||
fn apply_requirements(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
body_id: ast::NodeId,
|
||||
location: Location,
|
||||
closure_def_id: DefId,
|
||||
closure_substs: ty::ClosureSubsts<'tcx>,
|
||||
);
|
||||
|
||||
fn subst_closure_mapping<T>(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
closure_mapping: &IndexVec<RegionVid, ty::Region<'tcx>>,
|
||||
value: &T,
|
||||
) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>;
|
||||
}
|
||||
|
||||
impl ClosureRegionRequirementsExt for ClosureRegionRequirements {
|
||||
impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequirements<'gcx> {
|
||||
/// Given an instance T of the closure type, this method
|
||||
/// instantiates the "extra" requirements that we computed for the
|
||||
/// closure into the inference context. This has the effect of
|
||||
|
|
@ -608,9 +982,10 @@ impl ClosureRegionRequirementsExt for ClosureRegionRequirements {
|
|||
/// a vector. Then we can just index into that vector to extract
|
||||
/// out the corresponding region from T and apply the
|
||||
/// requirements.
|
||||
fn apply_requirements<'tcx>(
|
||||
fn apply_requirements(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
body_id: ast::NodeId,
|
||||
location: Location,
|
||||
closure_def_id: DefId,
|
||||
closure_substs: ty::ClosureSubsts<'tcx>,
|
||||
|
|
@ -632,22 +1007,71 @@ impl ClosureRegionRequirementsExt for ClosureRegionRequirements {
|
|||
// into a vector. These are the regions that we will be
|
||||
// relating to one another.
|
||||
let closure_mapping =
|
||||
UniversalRegions::closure_mapping(infcx, user_closure_ty, self.num_external_vids);
|
||||
&UniversalRegions::closure_mapping(infcx, user_closure_ty, self.num_external_vids);
|
||||
debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
|
||||
|
||||
// Create the predicates.
|
||||
for outlives_requirement in &self.outlives_requirements {
|
||||
let region = closure_mapping[outlives_requirement.free_region];
|
||||
let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
|
||||
debug!(
|
||||
"apply_requirements: region={:?} outlived_region={:?} outlives_requirements={:?}",
|
||||
region,
|
||||
outlived_region,
|
||||
outlives_requirement
|
||||
);
|
||||
|
||||
// FIXME, this origin is not entirely suitable.
|
||||
let origin = SubregionOrigin::CallRcvr(outlives_requirement.blame_span);
|
||||
infcx.sub_regions(origin, outlived_region, region);
|
||||
|
||||
match outlives_requirement.subject {
|
||||
ClosureOutlivesSubject::Region(region) => {
|
||||
let region = closure_mapping[region];
|
||||
debug!(
|
||||
"apply_requirements: region={:?} \
|
||||
outlived_region={:?} \
|
||||
outlives_requirement={:?}",
|
||||
region,
|
||||
outlived_region,
|
||||
outlives_requirement,
|
||||
);
|
||||
infcx.sub_regions(origin, outlived_region, region);
|
||||
}
|
||||
|
||||
ClosureOutlivesSubject::Ty(ty) => {
|
||||
let ty = self.subst_closure_mapping(infcx, closure_mapping, &ty);
|
||||
debug!(
|
||||
"apply_requirements: ty={:?} \
|
||||
outlived_region={:?} \
|
||||
outlives_requirement={:?}",
|
||||
ty,
|
||||
outlived_region,
|
||||
outlives_requirement,
|
||||
);
|
||||
infcx.register_region_obligation(
|
||||
body_id,
|
||||
RegionObligation {
|
||||
sup_type: ty,
|
||||
sub_region: outlived_region,
|
||||
cause: ObligationCause::misc(outlives_requirement.blame_span, body_id),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn subst_closure_mapping<T>(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
closure_mapping: &IndexVec<RegionVid, ty::Region<'tcx>>,
|
||||
value: &T,
|
||||
) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
infcx.tcx.fold_regions(value, &mut false, |r, _depth| {
|
||||
if let ty::ReClosureBound(vid) = r {
|
||||
closure_mapping[*vid]
|
||||
} else {
|
||||
bug!(
|
||||
"subst_closure_mapping: encountered non-closure bound free region {:?}",
|
||||
r
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -215,8 +215,11 @@ impl RegionValues {
|
|||
// FIXME. We could optimize this by improving
|
||||
// `BitMatrix::merge` so it does not always merge an entire
|
||||
// row.
|
||||
debug!("add_universal_regions_outlived_by(from_region={:?}, to_region={:?})",
|
||||
from_region, to_region);
|
||||
debug!(
|
||||
"add_universal_regions_outlived_by(from_region={:?}, to_region={:?})",
|
||||
from_region,
|
||||
to_region
|
||||
);
|
||||
let mut changed = false;
|
||||
for elem in self.elements.all_universal_region_indices() {
|
||||
if self.contains(from_region, elem) {
|
||||
|
|
@ -269,24 +272,70 @@ impl RegionValues {
|
|||
let mut result = String::new();
|
||||
result.push_str("{");
|
||||
|
||||
for (index, element) in self.elements_contained_in(r).enumerate() {
|
||||
if index > 0 {
|
||||
result.push_str(", ");
|
||||
}
|
||||
// Set to Some(l1, l2) when we have observed all the locations
|
||||
// from l1..=l2 (inclusive) but not yet printed them. This
|
||||
// gets extended if we then see l3 where l3 is the successor
|
||||
// to l2.
|
||||
let mut open_location: Option<(Location, Location)> = None;
|
||||
|
||||
let mut sep = "";
|
||||
let mut push_sep = |s: &mut String| {
|
||||
s.push_str(sep);
|
||||
sep = ", ";
|
||||
};
|
||||
|
||||
for element in self.elements_contained_in(r) {
|
||||
match element {
|
||||
RegionElement::Location(l) => {
|
||||
result.push_str(&format!("{:?}", l));
|
||||
if let Some((location1, location2)) = open_location {
|
||||
if location2.block == l.block
|
||||
&& location2.statement_index == l.statement_index - 1
|
||||
{
|
||||
open_location = Some((location1, l));
|
||||
continue;
|
||||
}
|
||||
|
||||
push_sep(&mut result);
|
||||
Self::push_location_range(&mut result, location1, location2);
|
||||
}
|
||||
|
||||
open_location = Some((l, l));
|
||||
}
|
||||
|
||||
RegionElement::UniversalRegion(fr) => {
|
||||
if let Some((location1, location2)) = open_location {
|
||||
push_sep(&mut result);
|
||||
Self::push_location_range(&mut result, location1, location2);
|
||||
open_location = None;
|
||||
}
|
||||
|
||||
push_sep(&mut result);
|
||||
result.push_str(&format!("{:?}", fr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((location1, location2)) = open_location {
|
||||
push_sep(&mut result);
|
||||
Self::push_location_range(&mut result, location1, location2);
|
||||
}
|
||||
|
||||
result.push_str("}");
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn push_location_range(str: &mut String, location1: Location, location2: Location) {
|
||||
if location1 == location2 {
|
||||
str.push_str(&format!("{:?}", location1));
|
||||
} else {
|
||||
assert_eq!(location1.block, location2.block);
|
||||
str.push_str(&format!(
|
||||
"{:?}[{}..={}]",
|
||||
location1.block,
|
||||
location1.statement_index,
|
||||
location2.statement_index
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,50 +8,24 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, ClosureSubsts, Ty, TypeFoldable};
|
||||
use rustc::mir::{BasicBlock, Local, Location, Mir, Statement, StatementKind};
|
||||
use rustc::mir::RETURN_PLACE;
|
||||
use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
|
||||
use rustc::mir::visit::{MutVisitor, TyContext};
|
||||
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||
|
||||
use super::ToRegionVid;
|
||||
use super::universal_regions::UniversalRegions;
|
||||
|
||||
/// Replaces all free regions appearing in the MIR with fresh
|
||||
/// inference variables, returning the number of variables created.
|
||||
pub fn renumber_mir<'a, 'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
mir: &mut Mir<'tcx>,
|
||||
) {
|
||||
pub fn renumber_mir<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &mut Mir<'tcx>) {
|
||||
debug!("renumber_mir()");
|
||||
debug!("renumber_mir: mir.arg_count={:?}", mir.arg_count);
|
||||
|
||||
// Update the return type and types of the arguments based on the
|
||||
// `universal_regions` computation.
|
||||
debug!("renumber_mir: output_ty={:?}", universal_regions.output_ty);
|
||||
mir.local_decls[RETURN_PLACE].ty = universal_regions.output_ty;
|
||||
for (&input_ty, local) in universal_regions
|
||||
.input_tys
|
||||
.iter()
|
||||
.zip((1..).map(Local::new))
|
||||
{
|
||||
debug!("renumber_mir: input_ty={:?} local={:?}", input_ty, local);
|
||||
mir.local_decls[local].ty = input_ty;
|
||||
}
|
||||
|
||||
let mut visitor = NLLVisitor {
|
||||
infcx,
|
||||
arg_count: mir.arg_count,
|
||||
};
|
||||
let mut visitor = NLLVisitor { infcx };
|
||||
visitor.visit_mir(mir);
|
||||
}
|
||||
|
||||
struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
arg_count: usize,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
|
||||
|
|
@ -71,45 +45,13 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
|
|||
self.infcx.next_nll_region_var(origin)
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks that all the regions appearing in `value` have already
|
||||
/// been renumbered. `FreeRegions` code should have done this.
|
||||
fn assert_free_regions_are_renumbered<T>(&self, value: &T)
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
debug!("assert_free_regions_are_renumbered(value={:?})", value);
|
||||
|
||||
self.infcx.tcx.for_each_free_region(value, |region| {
|
||||
region.to_region_vid(); // will panic if `region` is not renumbered
|
||||
});
|
||||
}
|
||||
|
||||
fn is_argument_or_return_slot(&self, local: Local) -> bool {
|
||||
// The first argument is return slot, next N are arguments.
|
||||
local.index() <= self.arg_count
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
|
||||
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
|
||||
let is_arg = match ty_context {
|
||||
TyContext::LocalDecl { local, .. } => self.is_argument_or_return_slot(local),
|
||||
TyContext::ReturnTy(..) => true,
|
||||
TyContext::Location(..) => false,
|
||||
};
|
||||
debug!(
|
||||
"visit_ty(ty={:?}, is_arg={:?}, ty_context={:?})",
|
||||
ty,
|
||||
is_arg,
|
||||
ty_context
|
||||
);
|
||||
debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context);
|
||||
|
||||
if is_arg {
|
||||
self.assert_free_regions_are_renumbered(ty);
|
||||
} else {
|
||||
*ty = self.renumber_regions(ty_context, ty);
|
||||
}
|
||||
*ty = self.renumber_regions(ty_context, ty);
|
||||
|
||||
debug!("visit_ty: ty={:?}", ty);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,14 @@
|
|||
use rustc::mir::Mir;
|
||||
use rustc::infer::region_constraints::Constraint;
|
||||
use rustc::infer::region_constraints::RegionConstraintData;
|
||||
use rustc::infer::region_constraints::{Verify, VerifyBound};
|
||||
use rustc::ty;
|
||||
use transform::type_check::MirTypeckRegionConstraints;
|
||||
use transform::type_check::OutlivesSet;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use super::region_infer::RegionInferenceContext;
|
||||
use super::region_infer::{TypeTest, RegionInferenceContext, RegionTest};
|
||||
use super::type_check::Locations;
|
||||
use super::type_check::MirTypeckRegionConstraints;
|
||||
use super::type_check::OutlivesSet;
|
||||
|
||||
/// When the MIR type-checker executes, it validates all the types in
|
||||
/// the MIR, and in the process generates a set of constraints that
|
||||
|
|
@ -27,10 +30,7 @@ pub(super) fn generate<'tcx>(
|
|||
mir: &Mir<'tcx>,
|
||||
constraints: &MirTypeckRegionConstraints<'tcx>,
|
||||
) {
|
||||
SubtypeConstraintGenerator {
|
||||
regioncx,
|
||||
mir,
|
||||
}.generate(constraints);
|
||||
SubtypeConstraintGenerator { regioncx, mir }.generate(constraints);
|
||||
}
|
||||
|
||||
struct SubtypeConstraintGenerator<'cx, 'tcx: 'cx> {
|
||||
|
|
@ -65,6 +65,8 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
|
|||
givens,
|
||||
} = data;
|
||||
|
||||
let span = self.mir.source_info(locations.from_location).span;
|
||||
|
||||
for constraint in constraints.keys() {
|
||||
debug!("generate: constraint: {:?}", constraint);
|
||||
let (a_vid, b_vid) = match constraint {
|
||||
|
|
@ -81,12 +83,15 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
|
|||
// reverse direction, because `regioncx` talks about
|
||||
// "outlives" (`>=`) whereas the region constraints
|
||||
// talk about `<=`.
|
||||
let span = self.mir.source_info(locations.from_location).span;
|
||||
self.regioncx
|
||||
.add_outlives(span, b_vid, a_vid, locations.at_location);
|
||||
}
|
||||
|
||||
assert!(verifys.is_empty(), "verifys not yet implemented");
|
||||
for verify in verifys {
|
||||
let type_test = self.verify_to_type_test(verify, span, locations);
|
||||
self.regioncx.add_type_test(type_test);
|
||||
}
|
||||
|
||||
assert!(
|
||||
givens.is_empty(),
|
||||
"MIR type-checker does not use givens (thank goodness)"
|
||||
|
|
@ -94,6 +99,55 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn verify_to_type_test(
|
||||
&self,
|
||||
verify: &Verify<'tcx>,
|
||||
span: Span,
|
||||
locations: &Locations,
|
||||
) -> TypeTest<'tcx> {
|
||||
let generic_kind = verify.kind;
|
||||
|
||||
let lower_bound = self.to_region_vid(verify.region);
|
||||
|
||||
let point = locations.at_location;
|
||||
|
||||
let test = self.verify_bound_to_region_test(&verify.bound);
|
||||
|
||||
TypeTest {
|
||||
generic_kind,
|
||||
lower_bound,
|
||||
point,
|
||||
span,
|
||||
test,
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_bound_to_region_test(&self, verify_bound: &VerifyBound<'tcx>) -> RegionTest {
|
||||
match verify_bound {
|
||||
VerifyBound::AnyRegion(regions) => RegionTest::IsOutlivedByAnyRegionIn(
|
||||
regions.iter().map(|r| self.to_region_vid(r)).collect(),
|
||||
),
|
||||
|
||||
VerifyBound::AllRegions(regions) => RegionTest::IsOutlivedByAllRegionsIn(
|
||||
regions.iter().map(|r| self.to_region_vid(r)).collect(),
|
||||
),
|
||||
|
||||
VerifyBound::AnyBound(bounds) => RegionTest::Any(
|
||||
bounds
|
||||
.iter()
|
||||
.map(|b| self.verify_bound_to_region_test(b))
|
||||
.collect(),
|
||||
),
|
||||
|
||||
VerifyBound::AllBounds(bounds) => RegionTest::All(
|
||||
bounds
|
||||
.iter()
|
||||
.map(|b| self.verify_bound_to_region_test(b))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_region_vid(&self, r: ty::Region<'tcx>) -> ty::RegionVid {
|
||||
// Every region that we see in the constraints came from the
|
||||
// MIR or from the parameter environment. If the former, it
|
||||
|
|
|
|||
220
src/librustc_mir/borrow_check/nll/type_check/liveness.rs
Normal file
220
src/librustc_mir/borrow_check/nll/type_check/liveness.rs
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use dataflow::{FlowAtLocation, FlowsAtLocation};
|
||||
use dataflow::MaybeInitializedLvals;
|
||||
use dataflow::move_paths::{HasMoveData, MoveData};
|
||||
use rustc::mir::{BasicBlock, Location, Mir};
|
||||
use rustc::mir::Local;
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::util::common::ErrorReported;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
use util::liveness::LivenessResults;
|
||||
|
||||
use super::TypeChecker;
|
||||
|
||||
/// Combines liveness analysis with initialization analysis to
|
||||
/// determine which variables are live at which points, both due to
|
||||
/// ordinary uses and drops. Returns a set of (ty, location) pairs
|
||||
/// that indicate which types must be live at which point in the CFG.
|
||||
/// This vector is consumed by `constraint_generation`.
|
||||
///
|
||||
/// NB. This computation requires normalization; therefore, it must be
|
||||
/// performed before
|
||||
pub(super) fn generate<'gcx, 'tcx>(
|
||||
cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
liveness: &LivenessResults,
|
||||
flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'_, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
) {
|
||||
let tcx = cx.tcx();
|
||||
let mut generator = TypeLivenessGenerator {
|
||||
cx,
|
||||
tcx,
|
||||
mir,
|
||||
liveness,
|
||||
flow_inits,
|
||||
move_data,
|
||||
};
|
||||
|
||||
for bb in mir.basic_blocks().indices() {
|
||||
generator.add_liveness_constraints(bb);
|
||||
}
|
||||
}
|
||||
|
||||
struct TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx>
|
||||
where
|
||||
'typeck: 'gen,
|
||||
'flow: 'gen,
|
||||
'tcx: 'typeck + 'flow,
|
||||
'gcx: 'tcx,
|
||||
{
|
||||
cx: &'gen mut TypeChecker<'typeck, 'gcx, 'tcx>,
|
||||
tcx: TyCtxt<'typeck, 'gcx, 'tcx>,
|
||||
mir: &'gen Mir<'tcx>,
|
||||
liveness: &'gen LivenessResults,
|
||||
flow_inits: &'gen mut FlowAtLocation<MaybeInitializedLvals<'flow, 'gcx, 'tcx>>,
|
||||
move_data: &'gen MoveData<'tcx>,
|
||||
}
|
||||
|
||||
impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> {
|
||||
/// Liveness constraints:
|
||||
///
|
||||
/// > If a variable V is live at point P, then all regions R in the type of V
|
||||
/// > must include the point P.
|
||||
fn add_liveness_constraints(&mut self, bb: BasicBlock) {
|
||||
debug!("add_liveness_constraints(bb={:?})", bb);
|
||||
|
||||
self.liveness
|
||||
.regular
|
||||
.simulate_block(self.mir, bb, |location, live_locals| {
|
||||
for live_local in live_locals.iter() {
|
||||
let live_local_ty = self.mir.local_decls[live_local].ty;
|
||||
self.push_type_live_constraint(live_local_ty, location);
|
||||
}
|
||||
});
|
||||
|
||||
let mut all_live_locals: Vec<(Location, Vec<Local>)> = vec![];
|
||||
self.liveness
|
||||
.drop
|
||||
.simulate_block(self.mir, bb, |location, live_locals| {
|
||||
all_live_locals.push((location, live_locals.iter().collect()));
|
||||
});
|
||||
debug!(
|
||||
"add_liveness_constraints: all_live_locals={:#?}",
|
||||
all_live_locals
|
||||
);
|
||||
|
||||
let terminator_index = self.mir.basic_blocks()[bb].statements.len();
|
||||
self.flow_inits.reset_to_entry_of(bb);
|
||||
while let Some((location, live_locals)) = all_live_locals.pop() {
|
||||
for live_local in live_locals {
|
||||
debug!(
|
||||
"add_liveness_constraints: location={:?} live_local={:?}",
|
||||
location,
|
||||
live_local
|
||||
);
|
||||
|
||||
self.flow_inits.each_state_bit(|mpi_init| {
|
||||
debug!(
|
||||
"add_liveness_constraints: location={:?} initialized={:?}",
|
||||
location,
|
||||
&self.flow_inits.operator().move_data().move_paths[mpi_init]
|
||||
);
|
||||
});
|
||||
|
||||
let mpi = self.move_data.rev_lookup.find_local(live_local);
|
||||
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
|
||||
debug!(
|
||||
"add_liveness_constraints: mpi={:?} has initialized child {:?}",
|
||||
self.move_data.move_paths[mpi],
|
||||
self.move_data.move_paths[initialized_child]
|
||||
);
|
||||
|
||||
let live_local_ty = self.mir.local_decls[live_local].ty;
|
||||
self.add_drop_live_constraint(live_local_ty, location);
|
||||
}
|
||||
}
|
||||
|
||||
if location.statement_index == terminator_index {
|
||||
debug!(
|
||||
"add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
|
||||
location
|
||||
);
|
||||
self.flow_inits.reconstruct_terminator_effect(location);
|
||||
} else {
|
||||
debug!(
|
||||
"add_liveness_constraints: reconstruct_statement_effect from {:#?}",
|
||||
location
|
||||
);
|
||||
self.flow_inits.reconstruct_statement_effect(location);
|
||||
}
|
||||
self.flow_inits.apply_local_effect(location);
|
||||
}
|
||||
}
|
||||
|
||||
/// Some variable with type `live_ty` is "regular live" at
|
||||
/// `location` -- i.e., it may be used later. This means that all
|
||||
/// regions appearing in the type `live_ty` must be live at
|
||||
/// `location`.
|
||||
fn push_type_live_constraint<T>(&mut self, value: T, location: Location)
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
debug!(
|
||||
"push_type_live_constraint(live_ty={:?}, location={:?})",
|
||||
value,
|
||||
location
|
||||
);
|
||||
|
||||
self.tcx.for_each_free_region(&value, |live_region| {
|
||||
self.cx
|
||||
.constraints
|
||||
.liveness_set
|
||||
.push((live_region, location));
|
||||
});
|
||||
}
|
||||
|
||||
/// Some variable with type `live_ty` is "drop live" at `location`
|
||||
/// -- i.e., it may be dropped later. This means that *some* of
|
||||
/// the regions in its type must be live at `location`. The
|
||||
/// precise set will depend on the dropck constraints, and in
|
||||
/// particular this takes `#[may_dangle]` into account.
|
||||
fn add_drop_live_constraint(&mut self, dropped_ty: Ty<'tcx>, location: Location) {
|
||||
debug!(
|
||||
"add_drop_live_constraint(dropped_ty={:?}, location={:?})",
|
||||
dropped_ty,
|
||||
location
|
||||
);
|
||||
|
||||
let tcx = self.cx.infcx.tcx;
|
||||
let mut types = vec![(dropped_ty, 0)];
|
||||
let mut known = FxHashSet();
|
||||
while let Some((ty, depth)) = types.pop() {
|
||||
let span = DUMMY_SP; // FIXME
|
||||
let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) {
|
||||
Ok(result) => result,
|
||||
Err(ErrorReported) => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let ty::DtorckConstraint {
|
||||
outlives,
|
||||
dtorck_types,
|
||||
} = result;
|
||||
|
||||
// All things in the `outlives` array may be touched by
|
||||
// the destructor and must be live at this point.
|
||||
for outlive in outlives {
|
||||
self.push_type_live_constraint(outlive, location);
|
||||
}
|
||||
|
||||
// However, there may also be some types that
|
||||
// `dtorck_constraint_for_ty` could not resolve (e.g.,
|
||||
// associated types and parameters). We need to normalize
|
||||
// associated types here and possibly recursively process.
|
||||
for ty in dtorck_types {
|
||||
let ty = self.cx.normalize(&ty, location);
|
||||
match ty.sty {
|
||||
ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
|
||||
self.push_type_live_constraint(ty, location);
|
||||
}
|
||||
|
||||
_ => if known.insert(ty) {
|
||||
types.push((ty, depth + 1));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,9 @@
|
|||
#![allow(unreachable_code)]
|
||||
|
||||
use borrow_check::nll::region_infer::ClosureRegionRequirementsExt;
|
||||
use dataflow::FlowAtLocation;
|
||||
use dataflow::MaybeInitializedLvals;
|
||||
use dataflow::move_paths::MoveData;
|
||||
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
|
||||
use rustc::infer::region_constraints::RegionConstraintData;
|
||||
use rustc::traits::{self, FulfillmentContext};
|
||||
|
|
@ -26,24 +29,80 @@ use std::fmt;
|
|||
use syntax::ast;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use transform::{MirPass, MirSource};
|
||||
use util::liveness::LivenessResults;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
mod liveness;
|
||||
|
||||
/// Type checks the given `mir` in the context of the inference
|
||||
/// context `infcx`. Returns any region constraints that have yet to
|
||||
/// be proven.
|
||||
/// be proven. This result is includes liveness constraints that
|
||||
/// ensure that regions appearing in the types of all local variables
|
||||
/// are live at all points where that local variable may later be
|
||||
/// used.
|
||||
///
|
||||
/// This phase of type-check ought to be infallible -- this is because
|
||||
/// the original, HIR-based type-check succeeded. So if any errors
|
||||
/// occur here, we will get a `bug!` reported.
|
||||
pub fn type_check<'a, 'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `infcx` -- inference context to use
|
||||
/// - `body_id` -- body-id of the MIR being checked
|
||||
/// - `param_env` -- parameter environment to use for trait solving
|
||||
/// - `mir` -- MIR to type-check
|
||||
/// - `implicit_region_bound` -- a region which all generic parameters are assumed
|
||||
/// to outlive; should represent the fn body
|
||||
/// - `input_tys` -- fully liberated, but **not** normalized, expected types of the arguments;
|
||||
/// the types of the input parameters found in the MIR itself will be equated with these
|
||||
/// - `output_ty` -- fully liberaetd, but **not** normalized, expected return type;
|
||||
/// the type for the RETURN_PLACE will be equated with this
|
||||
/// - `liveness` -- results of a liveness computation on the MIR; used to create liveness
|
||||
/// constraints for the regions in the types of variables
|
||||
/// - `flow_inits` -- results of a maybe-init dataflow analysis
|
||||
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
|
||||
pub(crate) fn type_check<'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
body_id: ast::NodeId,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
input_tys: &[Ty<'tcx>],
|
||||
output_ty: Ty<'tcx>,
|
||||
liveness: &LivenessResults,
|
||||
flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'_, 'gcx, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
) -> MirTypeckRegionConstraints<'tcx> {
|
||||
let mut checker = TypeChecker::new(infcx, body_id, param_env);
|
||||
type_check_internal(
|
||||
infcx,
|
||||
body_id,
|
||||
param_env,
|
||||
mir,
|
||||
Some(implicit_region_bound),
|
||||
&mut |cx| {
|
||||
liveness::generate(cx, mir, liveness, flow_inits, move_data);
|
||||
|
||||
// Equate the input and output tys given by the user with
|
||||
// the ones found in the MIR.
|
||||
cx.equate_input_or_output(output_ty, mir.local_decls[RETURN_PLACE].ty);
|
||||
for (&input_ty, local) in input_tys.iter().zip((1..).map(Local::new)) {
|
||||
cx.equate_input_or_output(input_ty, mir.local_decls[local].ty);
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn type_check_internal<'gcx, 'tcx>(
|
||||
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
|
||||
body_id: ast::NodeId,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
extra: &mut FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>),
|
||||
) -> MirTypeckRegionConstraints<'tcx> {
|
||||
let mut checker = TypeChecker::new(infcx, body_id, param_env, implicit_region_bound);
|
||||
let errors_reported = {
|
||||
let mut verifier = TypeVerifier::new(&mut checker, mir);
|
||||
verifier.visit_mir(mir);
|
||||
|
|
@ -55,9 +114,12 @@ pub fn type_check<'a, 'gcx, 'tcx>(
|
|||
checker.typeck_mir(mir);
|
||||
}
|
||||
|
||||
extra(&mut checker);
|
||||
|
||||
checker.constraints
|
||||
}
|
||||
|
||||
|
||||
fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
|
||||
// We sometimes see MIR failures (notably predicate failures) due to
|
||||
// the fact that we check rvalue sized predicates here. So use `delay_span_bug`
|
||||
|
|
@ -503,11 +565,12 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
/// constraints needed for it to be valid and well-typed. Along the
|
||||
/// way, it accrues region constraints -- these can later be used by
|
||||
/// NLL region checking.
|
||||
pub struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
last_span: Span,
|
||||
body_id: ast::NodeId,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
|
||||
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
}
|
||||
|
|
@ -561,12 +624,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
body_id: ast::NodeId,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
) -> Self {
|
||||
TypeChecker {
|
||||
infcx,
|
||||
last_span: DUMMY_SP,
|
||||
body_id,
|
||||
param_env,
|
||||
implicit_region_bound,
|
||||
reported_errors: FxHashSet(),
|
||||
constraints: MirTypeckRegionConstraints::default(),
|
||||
}
|
||||
|
|
@ -591,8 +656,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
span_mirbug!(self, "", "errors selecting obligation: {:?}", e);
|
||||
}
|
||||
|
||||
self.infcx
|
||||
.process_registered_region_obligations(&[], None, self.param_env, self.body_id);
|
||||
self.infcx.process_registered_region_obligations(
|
||||
&[],
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
self.body_id,
|
||||
);
|
||||
|
||||
let data = self.infcx.take_and_reset_region_constraints();
|
||||
if !data.is_empty() {
|
||||
|
|
@ -625,6 +694,25 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
fn equate_input_or_output(&mut self, unnormalized_a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
let start_position = Location {
|
||||
block: START_BLOCK,
|
||||
statement_index: 0,
|
||||
};
|
||||
let a = self.normalize(&unnormalized_a, start_position);
|
||||
if let Err(terr) = self.eq_types(a, b, start_position.at_self()) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
start_position,
|
||||
"bad input or output {:?} normalized to {:?} should equal {:?} but got error {:?}",
|
||||
unnormalized_a,
|
||||
a,
|
||||
b,
|
||||
terr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
|
@ -1368,6 +1456,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
if let Some(closure_region_requirements) = tcx.mir_borrowck(*def_id) {
|
||||
closure_region_requirements.apply_requirements(
|
||||
self.infcx,
|
||||
self.body_id,
|
||||
location,
|
||||
*def_id,
|
||||
*substs,
|
||||
|
|
@ -1474,7 +1563,7 @@ impl MirPass for TypeckMir {
|
|||
}
|
||||
let param_env = tcx.param_env(def_id);
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let _region_constraint_sets = type_check(&infcx, id, param_env, mir);
|
||||
let _ = type_check_internal(&infcx, id, param_env, mir, None, &mut |_| ());
|
||||
|
||||
// For verification purposes, we just ignore the resulting
|
||||
// region constraint sets. Not our problem. =)
|
||||
|
|
@ -45,6 +45,11 @@ pub struct UniversalRegions<'tcx> {
|
|||
/// The vid assigned to `'static`
|
||||
pub fr_static: RegionVid,
|
||||
|
||||
/// A special region vid created to represent the current MIR fn
|
||||
/// body. It will outlive the entire CFG but it will not outlive
|
||||
/// any other universal regions.
|
||||
pub fr_fn_body: RegionVid,
|
||||
|
||||
/// We create region variables such that they are ordered by their
|
||||
/// `RegionClassification`. The first block are globals, then
|
||||
/// externals, then locals. So things from:
|
||||
|
|
@ -64,12 +69,16 @@ pub struct UniversalRegions<'tcx> {
|
|||
/// closure type, but for a top-level function it's the `TyFnDef`.
|
||||
pub defining_ty: Ty<'tcx>,
|
||||
|
||||
/// The return type of this function, with all regions replaced
|
||||
/// by their universal `RegionVid` equivalents.
|
||||
/// The return type of this function, with all regions replaced by
|
||||
/// their universal `RegionVid` equivalents. This type is **NOT
|
||||
/// NORMALIZED** (i.e., it contains unnormalized associated type
|
||||
/// projections).
|
||||
pub output_ty: Ty<'tcx>,
|
||||
|
||||
/// The fully liberated input types of this function, with all
|
||||
/// regions replaced by their universal `RegionVid` equivalents.
|
||||
/// This type is **NOT NORMALIZED** (i.e., it contains
|
||||
/// unnormalized associated type projections).
|
||||
pub input_tys: &'tcx [Ty<'tcx>],
|
||||
|
||||
/// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to
|
||||
|
|
@ -242,17 +251,7 @@ impl<'tcx> UniversalRegions<'tcx> {
|
|||
(FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::new)
|
||||
}
|
||||
|
||||
/// True if `r` is classied as a global region.
|
||||
pub fn is_global_free_region(&self, r: RegionVid) -> bool {
|
||||
self.region_classification(r) == Some(RegionClassification::Global)
|
||||
}
|
||||
|
||||
/// True if `r` is classied as an external region.
|
||||
pub fn is_extern_free_region(&self, r: RegionVid) -> bool {
|
||||
self.region_classification(r) == Some(RegionClassification::External)
|
||||
}
|
||||
|
||||
/// True if `r` is classied as an local region.
|
||||
/// True if `r` is classified as an local region.
|
||||
pub fn is_local_free_region(&self, r: RegionVid) -> bool {
|
||||
self.region_classification(r) == Some(RegionClassification::Local)
|
||||
}
|
||||
|
|
@ -262,6 +261,20 @@ impl<'tcx> UniversalRegions<'tcx> {
|
|||
self.num_universals
|
||||
}
|
||||
|
||||
/// Given two universal regions, returns the postdominating
|
||||
/// upper-bound (effectively the least upper bound).
|
||||
///
|
||||
/// (See `TransitiveRelation::postdom_upper_bound` for details on
|
||||
/// the postdominating upper bound in general.)
|
||||
pub fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid {
|
||||
assert!(self.is_universal_region(fr1));
|
||||
assert!(self.is_universal_region(fr2));
|
||||
*self.relations
|
||||
.inverse_outlives
|
||||
.postdom_upper_bound(&fr1, &fr2)
|
||||
.unwrap_or(&self.fr_static)
|
||||
}
|
||||
|
||||
/// Finds an "upper bound" for `fr` that is not local. In other
|
||||
/// words, returns the smallest (*) known region `fr1` that (a)
|
||||
/// outlives `fr` and (b) is not local. This cannot fail, because
|
||||
|
|
@ -305,6 +318,10 @@ impl<'tcx> UniversalRegions<'tcx> {
|
|||
relation: &TransitiveRelation<RegionVid>,
|
||||
fr0: RegionVid,
|
||||
) -> Option<RegionVid> {
|
||||
// This method assumes that `fr0` is one of the universally
|
||||
// quantified region variables.
|
||||
assert!(self.is_universal_region(fr0));
|
||||
|
||||
let mut external_parents = vec![];
|
||||
let mut queue = vec![&fr0];
|
||||
|
||||
|
|
@ -408,6 +425,7 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
|||
let first_local_index = self.infcx.num_region_vars();
|
||||
let inputs_and_output = self.infcx
|
||||
.replace_bound_regions_with_nll_infer_vars(FR, &bound_inputs_and_output);
|
||||
let fr_fn_body = self.infcx.next_nll_region_var(FR).to_region_vid();
|
||||
let num_universals = self.infcx.num_region_vars();
|
||||
|
||||
// Insert the facts we know from the predicates. Why? Why not.
|
||||
|
|
@ -419,12 +437,19 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
|||
self.add_implied_bounds(&indices, ty);
|
||||
}
|
||||
|
||||
// Finally, outlives is reflexive, and static outlives every
|
||||
// other free region.
|
||||
// Finally:
|
||||
// - outlives is reflexive, so `'r: 'r` for every region `'r`
|
||||
// - `'static: 'r` for every region `'r`
|
||||
// - `'r: 'fn_body` for every (other) universally quantified
|
||||
// region `'r`, all of which are provided by our caller
|
||||
for fr in (FIRST_GLOBAL_INDEX..num_universals).map(RegionVid::new) {
|
||||
debug!("build: relating free region {:?} to itself and to 'static", fr);
|
||||
debug!(
|
||||
"build: relating free region {:?} to itself and to 'static",
|
||||
fr
|
||||
);
|
||||
self.relations.relate_universal_regions(fr, fr);
|
||||
self.relations.relate_universal_regions(fr_static, fr);
|
||||
self.relations.relate_universal_regions(fr, fr_fn_body);
|
||||
}
|
||||
|
||||
let (output_ty, input_tys) = inputs_and_output.split_last().unwrap();
|
||||
|
|
@ -432,19 +457,26 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
|||
// we should not have created any more variables
|
||||
assert_eq!(self.infcx.num_region_vars(), num_universals);
|
||||
|
||||
debug!("build: global regions = {}..{}",
|
||||
FIRST_GLOBAL_INDEX,
|
||||
first_extern_index);
|
||||
debug!("build: extern regions = {}..{}",
|
||||
first_extern_index,
|
||||
first_local_index);
|
||||
debug!("build: local regions = {}..{}",
|
||||
first_local_index,
|
||||
num_universals);
|
||||
debug!(
|
||||
"build: global regions = {}..{}",
|
||||
FIRST_GLOBAL_INDEX,
|
||||
first_extern_index
|
||||
);
|
||||
debug!(
|
||||
"build: extern regions = {}..{}",
|
||||
first_extern_index,
|
||||
first_local_index
|
||||
);
|
||||
debug!(
|
||||
"build: local regions = {}..{}",
|
||||
first_local_index,
|
||||
num_universals
|
||||
);
|
||||
|
||||
UniversalRegions {
|
||||
indices,
|
||||
fr_static,
|
||||
fr_fn_body,
|
||||
first_extern_index,
|
||||
first_local_index,
|
||||
num_universals,
|
||||
|
|
|
|||
|
|
@ -25,26 +25,43 @@ use std::iter;
|
|||
/// There's probably a way to auto-impl this, but I think
|
||||
/// it is cleaner to have manual visitor impls.
|
||||
pub trait FlowsAtLocation {
|
||||
// reset the state bitvector to represent the entry to block `bb`.
|
||||
/// Reset the state bitvector to represent the entry to block `bb`.
|
||||
fn reset_to_entry_of(&mut self, bb: BasicBlock);
|
||||
|
||||
// build gen + kill sets for statement at `loc`.
|
||||
/// Build gen + kill sets for statement at `loc`.
|
||||
///
|
||||
/// Note that invoking this method alone does not change the
|
||||
/// `curr_state` -- you must invoke `apply_local_effect`
|
||||
/// afterwards.
|
||||
fn reconstruct_statement_effect(&mut self, loc: Location);
|
||||
|
||||
// build gen + kill sets for terminator for `loc`.
|
||||
/// Build gen + kill sets for terminator for `loc`.
|
||||
///
|
||||
/// Note that invoking this method alone does not change the
|
||||
/// `curr_state` -- you must invoke `apply_local_effect`
|
||||
/// afterwards.
|
||||
fn reconstruct_terminator_effect(&mut self, loc: Location);
|
||||
|
||||
// apply current gen + kill sets to `flow_state`.
|
||||
//
|
||||
// (`bb` and `stmt_idx` parameters can be ignored if desired by
|
||||
// client. For the terminator, the `stmt_idx` will be the number
|
||||
// of statements in the block.)
|
||||
/// Apply current gen + kill sets to `flow_state`.
|
||||
///
|
||||
/// (`loc` parameters can be ignored if desired by
|
||||
/// client. For the terminator, the `stmt_idx` will be the number
|
||||
/// of statements in the block.)
|
||||
fn apply_local_effect(&mut self, loc: Location);
|
||||
}
|
||||
|
||||
/// Represents the state of dataflow at a particular
|
||||
/// CFG location, both before and after it is
|
||||
/// executed.
|
||||
///
|
||||
/// Data flow results are typically computed only as basic block
|
||||
/// boundaries. A `FlowInProgress` allows you to reconstruct the
|
||||
/// effects at any point in the control-flow graph by starting with
|
||||
/// the state at the start of the basic block (`reset_to_entry_of`)
|
||||
/// and then replaying the effects of statements and terminators
|
||||
/// (e.g. via `reconstruct_statement_effect` and
|
||||
/// `reconstruct_terminator_effect`; don't forget to call
|
||||
/// `apply_local_effect`).
|
||||
pub struct FlowAtLocation<BD>
|
||||
where
|
||||
BD: BitDenotation,
|
||||
|
|
@ -59,6 +76,7 @@ impl<BD> FlowAtLocation<BD>
|
|||
where
|
||||
BD: BitDenotation,
|
||||
{
|
||||
/// Iterate over each bit set in the current state.
|
||||
pub fn each_state_bit<F>(&self, f: F)
|
||||
where
|
||||
F: FnMut(BD::Idx),
|
||||
|
|
@ -67,6 +85,9 @@ where
|
|||
.each_bit(self.base_results.operator().bits_per_block(), f)
|
||||
}
|
||||
|
||||
/// Iterate over each `gen` bit in the current effect (invoke
|
||||
/// `reconstruct_statement_effect` or
|
||||
/// `reconstruct_terminator_effect` first).
|
||||
pub fn each_gen_bit<F>(&self, f: F)
|
||||
where
|
||||
F: FnMut(BD::Idx),
|
||||
|
|
@ -88,6 +109,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Access the underlying operator.
|
||||
pub fn operator(&self) -> &BD {
|
||||
self.base_results.operator()
|
||||
}
|
||||
|
|
@ -96,11 +118,15 @@ where
|
|||
self.curr_state.contains(x)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the elements present in the current state.
|
||||
pub fn elems_incoming(&self) -> iter::Peekable<indexed_set::Elems<BD::Idx>> {
|
||||
let univ = self.base_results.sets().bits_per_block();
|
||||
self.curr_state.elems(univ).peekable()
|
||||
}
|
||||
|
||||
/// Creates a clone of the current state and applies the local
|
||||
/// effects to the clone (leaving the state of self intact).
|
||||
/// Invokes `f` with an iterator over the resulting state.
|
||||
pub fn with_elems_outgoing<F>(&self, f: F)
|
||||
where
|
||||
F: FnOnce(indexed_set::Elems<BD::Idx>),
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use borrow_check::nll::type_check;
|
||||
use build;
|
||||
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use rustc::mir::{Mir, Promoted};
|
||||
|
|
@ -30,7 +31,6 @@ pub mod simplify_branches;
|
|||
pub mod simplify;
|
||||
pub mod erase_regions;
|
||||
pub mod no_landing_pads;
|
||||
pub mod type_check;
|
||||
pub mod rustc_peek;
|
||||
pub mod elaborate_drops;
|
||||
pub mod add_call_guards;
|
||||
|
|
|
|||
|
|
@ -80,6 +80,39 @@ pub struct LivenessMode {
|
|||
pub include_drops: bool,
|
||||
}
|
||||
|
||||
/// A combination of liveness results, used in NLL.
|
||||
pub struct LivenessResults {
|
||||
/// Liveness results where a regular use makes a variable X live,
|
||||
/// but not a drop.
|
||||
pub regular: LivenessResult,
|
||||
|
||||
/// Liveness results where a drop makes a variable X live,
|
||||
/// but not a regular use.
|
||||
pub drop: LivenessResult,
|
||||
}
|
||||
|
||||
impl LivenessResults {
|
||||
pub fn compute<'tcx>(mir: &Mir<'tcx>) -> LivenessResults {
|
||||
LivenessResults {
|
||||
regular: liveness_of_locals(
|
||||
&mir,
|
||||
LivenessMode {
|
||||
include_regular_use: true,
|
||||
include_drops: false,
|
||||
},
|
||||
),
|
||||
|
||||
drop: liveness_of_locals(
|
||||
&mir,
|
||||
LivenessMode {
|
||||
include_regular_use: false,
|
||||
include_drops: true,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute which local variables are live within the given function
|
||||
/// `mir`. The liveness mode `mode` determines what sorts of uses are
|
||||
/// considered to make a variable live (e.g., do drops count?).
|
||||
|
|
|
|||
|
|
@ -465,6 +465,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
ty::ReFree(..) |
|
||||
ty::ReClosureBound(..) |
|
||||
ty::ReScope(..) |
|
||||
ty::ReVar(..) |
|
||||
ty::ReSkolemized(..) |
|
||||
|
|
|
|||
|
|
@ -1055,6 +1055,7 @@ impl Clean<Option<Lifetime>> for ty::RegionKind {
|
|||
ty::ReVar(..) |
|
||||
ty::ReSkolemized(..) |
|
||||
ty::ReEmpty |
|
||||
ty::ReClosureBound(_) |
|
||||
ty::ReErased => None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
fn bar<'a, 'b>() -> fn(&'a u32, &'b u32) -> &'a u32 {
|
||||
let g: fn(_, _) -> _ = |_x, y| y;
|
||||
//~^ ERROR free region `'b` does not outlive free region `'a`
|
||||
g
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR free region `'b` does not outlive free region `'a`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ fn bar<'a>(x: &'a u32) -> &'static u32 {
|
|||
// as part of checking the `ReifyFnPointer`.
|
||||
let f: fn(_) -> _ = foo;
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR free region `'_#1r` does not outlive free region `'static`
|
||||
f(x)
|
||||
//~^ ERROR free region `'_#1r` does not outlive free region `'static`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ fn bar<'a>(input: &'a u32, f: fn(&'a u32) -> &'a u32) -> &'static u32 {
|
|||
// in `g`. These are related via the `UnsafeFnPointer` cast.
|
||||
let g: unsafe fn(_) -> _ = f;
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR free region `'_#1r` does not outlive free region `'static`
|
||||
unsafe { g(input) }
|
||||
//~^ ERROR free region `'_#1r` does not outlive free region `'static`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -27,17 +27,23 @@ fn main() {
|
|||
// END RUST SOURCE
|
||||
// START rustc.use_x.nll.0.mir
|
||||
// | Free Region Mapping
|
||||
// | '_#0r | Global | ['_#2r, '_#1r, '_#0r, '_#3r]
|
||||
// | '_#1r | External | ['_#1r]
|
||||
// | '_#2r | External | ['_#2r, '_#1r]
|
||||
// | '_#3r | Local | ['_#3r]
|
||||
// | '_#0r | Global | ['_#2r, '_#1r, '_#0r, '_#4r, '_#3r]
|
||||
// | '_#1r | External | ['_#1r, '_#4r]
|
||||
// | '_#2r | External | ['_#2r, '_#1r, '_#4r]
|
||||
// | '_#3r | Local | ['_#4r, '_#3r]
|
||||
// | '_#4r | Local | ['_#4r]
|
||||
// |
|
||||
// | Inferred Region Values
|
||||
// | '_#0r | {'_#0r, bb0[0], bb0[1]}
|
||||
// | '_#1r | {'_#1r, bb0[0], bb0[1]}
|
||||
// | '_#2r | {'_#2r, bb0[0], bb0[1]}
|
||||
// | '_#3r | {'_#3r, bb0[0], bb0[1]}
|
||||
// | '_#0r | {'_#0r, bb0[0..=1]}
|
||||
// | '_#1r | {'_#1r, bb0[0..=1]}
|
||||
// | '_#2r | {'_#2r, bb0[0..=1]}
|
||||
// | '_#3r | {'_#3r, bb0[0..=1]}
|
||||
// | '_#4r | {'_#4r, bb0[0..=1]}
|
||||
// | '_#5r | {'_#1r, bb0[0..=1]}
|
||||
// | '_#6r | {'_#2r, bb0[0..=1]}
|
||||
// | '_#7r | {'_#1r, bb0[0..=1]}
|
||||
// | '_#8r | {'_#3r, bb0[0..=1]}
|
||||
// |
|
||||
// ...
|
||||
// fn use_x(_1: &'_#1r mut i32, _2: &'_#2r u32, _3: &'_#1r u32, _4: &'_#3r u32) -> bool {
|
||||
// fn use_x(_1: &'_#5r mut i32, _2: &'_#6r u32, _3: &'_#7r u32, _4: &'_#8r u32) -> bool {
|
||||
// END rustc.use_x.nll.0.mir
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@ fn main() {
|
|||
|
||||
// END RUST SOURCE
|
||||
// START rustc.main.nll.0.mir
|
||||
// | '_#6r | {bb0[6], bb0[7], bb0[8], bb0[9], bb0[10], bb0[11], bb0[12], bb0[13], bb0[14]}
|
||||
// | '_#7r | {bb0[6..=14]}
|
||||
// ...
|
||||
// | '_#8r | {bb0[11], bb0[12], bb0[13], bb0[14]}
|
||||
// | '_#9r | {bb0[11..=14]}
|
||||
// ...
|
||||
// let _2: &'_#6r mut i32;
|
||||
// let _2: &'_#7r mut i32;
|
||||
// ...
|
||||
// let _4: &'_#8r mut i32;
|
||||
// let _4: &'_#9r mut i32;
|
||||
// END rustc.main.nll.0.mir
|
||||
|
|
|
|||
|
|
@ -31,15 +31,15 @@ fn main() {
|
|||
|
||||
// END RUST SOURCE
|
||||
// START rustc.main.nll.0.mir
|
||||
// | '_#1r | {bb2[0], bb2[1], bb3[0], bb3[1]}
|
||||
// | '_#2r | {bb2[1], bb3[0], bb3[1]}
|
||||
// | '_#2r | {bb2[0..=1], bb3[0..=1]}
|
||||
// | '_#3r | {bb2[1], bb3[0..=1]}
|
||||
// ...
|
||||
// let _2: &'_#2r usize;
|
||||
// let _2: &'_#3r usize;
|
||||
// END rustc.main.nll.0.mir
|
||||
// START rustc.main.nll.0.mir
|
||||
// bb2: {
|
||||
// | Live variables on entry to bb2[0]: [_1, _3]
|
||||
// _2 = &'_#1r _1[_3];
|
||||
// _2 = &'_#2r _1[_3];
|
||||
// | Live variables on entry to bb2[1]: [_2]
|
||||
// switchInt(const true) -> [0u8: bb4, otherwise: bb3];
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -44,5 +44,7 @@ unsafe impl<#[may_dangle] T> Drop for Wrap<T> {
|
|||
|
||||
// END RUST SOURCE
|
||||
// START rustc.main.nll.0.mir
|
||||
// | '_#5r | {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1]}
|
||||
// | '_#6r | {bb2[3..=5], bb3[0..=1]}
|
||||
// ...
|
||||
// let _2: Wrap<&'_#6r usize>;
|
||||
// END rustc.main.nll.0.mir
|
||||
|
|
|
|||
|
|
@ -46,5 +46,7 @@ impl<T> Drop for Wrap<T> {
|
|||
|
||||
// END RUST SOURCE
|
||||
// START rustc.main.nll.0.mir
|
||||
// | '_#5r | {bb2[3], bb2[4], bb2[5], bb3[0], bb3[1], bb3[2], bb4[0], bb5[0], bb5[1], bb5[2], bb6[0], bb7[0], bb7[1], bb8[0]}
|
||||
// | '_#6r | {bb2[3..=5], bb3[0..=2], bb4[0], bb5[0..=2], bb6[0], bb7[0..=1], bb8[0]}
|
||||
// ...
|
||||
// let _2: Wrap<&'_#6r usize>;
|
||||
// END rustc.main.nll.0.mir
|
||||
|
|
|
|||
|
|
@ -36,14 +36,14 @@ fn main() {
|
|||
|
||||
// END RUST SOURCE
|
||||
// START rustc.main.nll.0.mir
|
||||
// | '_#1r | {bb2[0], bb2[1], bb3[0], bb3[1]}
|
||||
// | '_#2r | {bb2[0..=1], bb3[0..=1]}
|
||||
// ...
|
||||
// | '_#3r | {bb8[1], bb8[2], bb8[3], bb8[4]}
|
||||
// | '_#4r | {bb2[1], bb3[0], bb3[1], bb8[2], bb8[3], bb8[4]}
|
||||
// | '_#4r | {bb8[1..=4]}
|
||||
// | '_#5r | {bb2[1], bb3[0..=1], bb8[2..=4]}
|
||||
// ...
|
||||
// let mut _2: &'_#4r usize;
|
||||
// let mut _2: &'_#5r usize;
|
||||
// ...
|
||||
// _2 = &'_#1r _1[_3];
|
||||
// _2 = &'_#2r _1[_3];
|
||||
// ...
|
||||
// _2 = &'_#3r (*_10);
|
||||
// _2 = &'_#4r (*_10);
|
||||
// END rustc.main.nll.0.mir
|
||||
|
|
|
|||
|
|
@ -32,16 +32,16 @@ fn main() {
|
|||
|
||||
// END RUST SOURCE
|
||||
// START rustc.main.nll.0.mir
|
||||
// | '_#1r | {bb2[0], bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]}
|
||||
// | '_#2r | {bb2[1], bb2[2], bb2[3], bb2[4], bb2[5], bb2[6], bb3[0], bb3[1]}
|
||||
// | '_#3r | {bb2[5], bb2[6], bb3[0], bb3[1]}
|
||||
// | '_#2r | {bb2[0..=6], bb3[0..=1]}
|
||||
// | '_#3r | {bb2[1..=6], bb3[0..=1]}
|
||||
// | '_#4r | {bb2[5..=6], bb3[0..=1]}
|
||||
// END rustc.main.nll.0.mir
|
||||
// START rustc.main.nll.0.mir
|
||||
// let _2: &'_#2r usize;
|
||||
// let _2: &'_#3r usize;
|
||||
// ...
|
||||
// let _6: &'_#3r usize;
|
||||
// let _6: &'_#4r usize;
|
||||
// ...
|
||||
// _2 = &'_#1r _1[_3];
|
||||
// _2 = &'_#2r _1[_3];
|
||||
// ...
|
||||
// _7 = _2;
|
||||
// ...
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ error[E0597]: `y` does not live long enough
|
|||
37 | }
|
||||
| - borrowed value only lives until here
|
||||
|
|
||||
= note: borrowed value must be valid for lifetime '_#4r...
|
||||
= note: borrowed value must be valid for lifetime '_#5r...
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ error: free region `'_#4r` does not outlive free region `'_#3r`
|
|||
36 | let mut closure = expect_sig(|p, y| *p = y);
|
||||
| ^^^^^^
|
||||
|
||||
note: External requirements
|
||||
note: No external requirements
|
||||
--> $DIR/escape-argument-callee.rs:36:38
|
||||
|
|
||||
36 | let mut closure = expect_sig(|p, y| *p = y);
|
||||
|
|
@ -20,7 +20,6 @@ note: External requirements
|
|||
i16,
|
||||
for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0)) i32))
|
||||
]
|
||||
= note: number of external vids: 1
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/escape-argument-callee.rs:30:1
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
note: External requirements
|
||||
note: No external requirements
|
||||
--> $DIR/escape-argument.rs:36:38
|
||||
|
|
||||
36 | let mut closure = expect_sig(|p, y| *p = y);
|
||||
|
|
@ -8,7 +8,6 @@ note: External requirements
|
|||
i16,
|
||||
for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) i32))
|
||||
]
|
||||
= note: number of external vids: 1
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/escape-argument.rs:30:1
|
||||
|
|
@ -33,7 +32,7 @@ error[E0597]: `y` does not live long enough
|
|||
39 | }
|
||||
| - borrowed value only lives until here
|
||||
|
|
||||
= note: borrowed value must be valid for lifetime '_#5r...
|
||||
= note: borrowed value must be valid for lifetime '_#6r...
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ error[E0597]: `y` does not live long enough
|
|||
36 | }
|
||||
| - borrowed value only lives until here
|
||||
|
|
||||
= note: borrowed value must be valid for lifetime '_#3r...
|
||||
= note: borrowed value must be valid for lifetime '_#4r...
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ error[E0597]: `y` does not live long enough
|
|||
36 | }
|
||||
| - borrowed value only lives until here
|
||||
|
|
||||
= note: borrowed value must be valid for lifetime '_#3r...
|
||||
= note: borrowed value must be valid for lifetime '_#4r...
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ fn supply<'a, 'b, 'c>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>, cell_c: Cell
|
|||
// Only works if 'x: 'y:
|
||||
let p = x.get();
|
||||
//~^ WARN not reporting region error due to -Znll
|
||||
//~| ERROR free region `'_#5r` does not outlive free region `'_#6r`
|
||||
demand_y(x, y, p)
|
||||
//~^ ERROR free region `'_#5r` does not outlive free region `'_#6r`
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,20 +5,20 @@ warning: not reporting region error due to -Znll
|
|||
| ^^^^^^^
|
||||
|
||||
error: free region `'_#5r` does not outlive free region `'_#6r`
|
||||
--> $DIR/propagate-approximated-fail-no-postdom.rs:57:25
|
||||
--> $DIR/propagate-approximated-fail-no-postdom.rs:55:17
|
||||
|
|
||||
57 | demand_y(x, y, p)
|
||||
| ^
|
||||
55 | let p = x.get();
|
||||
| ^
|
||||
|
||||
note: External requirements
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-approximated-fail-no-postdom.rs:53:9
|
||||
|
|
||||
53 | / |_outlives1, _outlives2, _outlives3, x, y| {
|
||||
54 | | // Only works if 'x: 'y:
|
||||
55 | | let p = x.get();
|
||||
56 | | //~^ WARN not reporting region error due to -Znll
|
||||
57 | | demand_y(x, y, p)
|
||||
58 | | //~^ ERROR free region `'_#5r` does not outlive free region `'_#6r`
|
||||
57 | | //~| ERROR free region `'_#5r` does not outlive free region `'_#6r`
|
||||
58 | | demand_y(x, y, p)
|
||||
59 | | },
|
||||
| |_________^
|
||||
|
|
||||
|
|
@ -26,7 +26,6 @@ note: External requirements
|
|||
i16,
|
||||
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>))
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-approximated-fail-no-postdom.rs:48:1
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@ note: External requirements
|
|||
= note: where '_#1r: '_#2r
|
||||
|
||||
error: free region `'_#1r` does not outlive free region `'_#2r`
|
||||
--> $DIR/propagate-approximated-ref.rs:53:38
|
||||
--> $DIR/propagate-approximated-ref.rs:53:29
|
||||
|
|
||||
53 | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-approximated-ref.rs:52:1
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ error: free region `'_#2r` does not outlive free region `'_#1r`
|
|||
33 | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
|
||||
| ^^^^^^
|
||||
|
||||
note: External requirements
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:15
|
||||
|
|
||||
31 | foo(cell, |cell_a, cell_x| {
|
||||
|
|
@ -25,7 +25,6 @@ note: External requirements
|
|||
i32,
|
||||
for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>))
|
||||
]
|
||||
= note: number of external vids: 2
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:28:1
|
||||
|
|
@ -80,7 +79,7 @@ error[E0597]: `a` does not live long enough
|
|||
49 | }
|
||||
| - borrowed value only lives until here
|
||||
|
|
||||
= note: borrowed value must be valid for lifetime '_#1r...
|
||||
= note: borrowed value must be valid for lifetime '_#2r...
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/propagate-approximated-to-empty.rs:41:9
|
||||
|
|
||||
41 | demand_y(x, y, x.get())
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: free region `'_#6r` does not outlive free region `'_#4r`
|
||||
--> $DIR/propagate-approximated-to-empty.rs:41:18
|
||||
|
|
||||
41 | demand_y(x, y, x.get())
|
||||
| ^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-approximated-to-empty.rs:39:47
|
||||
|
|
||||
39 | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
|
||||
| _______________________________________________^
|
||||
40 | | // Only works if 'x: 'y:
|
||||
41 | | demand_y(x, y, x.get())
|
||||
42 | | //~^ WARN not reporting region error due to -Znll
|
||||
43 | | //~| ERROR free region `'_#6r` does not outlive free region `'_#4r`
|
||||
44 | | });
|
||||
| |_____^
|
||||
|
|
||||
= note: defining type: DefId(0/1:18 ~ propagate_approximated_to_empty[317d]::supply[0]::{{closure}}[0]) with closure substs [
|
||||
i16,
|
||||
for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>))
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-approximated-to-empty.rs:38:1
|
||||
|
|
||||
38 | / fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
|
||||
39 | | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
|
||||
40 | | // Only works if 'x: 'y:
|
||||
41 | | demand_y(x, y, x.get())
|
||||
... |
|
||||
44 | | });
|
||||
45 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:6 ~ propagate_approximated_to_empty[317d]::supply[0]) with substs []
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
@ -24,10 +24,10 @@ note: External requirements
|
|||
= note: where '_#1r: '_#2r
|
||||
|
||||
error: free region `'_#1r` does not outlive free region `'_#2r`
|
||||
--> $DIR/propagate-approximated-val.rs:46:37
|
||||
--> $DIR/propagate-approximated-val.rs:46:29
|
||||
|
|
||||
46 | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
|
||||
| ^^^^^^
|
||||
| ^^^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-approximated-val.rs:45:1
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ warning: not reporting region error due to -Znll
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: free region `'_#6r` does not outlive free region `'_#4r`
|
||||
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:21
|
||||
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:18
|
||||
|
|
||||
47 | demand_y(x, y, x.get())
|
||||
| ^
|
||||
| ^
|
||||
|
||||
note: External requirements
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:45:47
|
||||
|
|
||||
45 | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
|
||||
|
|
@ -26,7 +26,6 @@ note: External requirements
|
|||
i16,
|
||||
for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>))
|
||||
]
|
||||
= note: number of external vids: 2
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:44:1
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ warning: not reporting region error due to -Znll
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: free region `'_#5r` does not outlive free region `'_#7r`
|
||||
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:21
|
||||
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:18
|
||||
|
|
||||
51 | demand_y(x, y, x.get())
|
||||
| ^
|
||||
| ^
|
||||
|
||||
note: External requirements
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:49:47
|
||||
|
|
||||
49 | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
|
||||
|
|
@ -26,7 +26,6 @@ note: External requirements
|
|||
i16,
|
||||
for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
|
||||
]
|
||||
= note: number of external vids: 3
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:48:1
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that regions which appear only in the closure's generics (in
|
||||
// this case, `'a`) are properly mapped to the creator's generics. In
|
||||
// this case, the closure constrains its type parameter `T` to outlive
|
||||
// the same `'a` for which it implements `Trait`, which can only be the `'a`
|
||||
// from the function definition.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Trait<'a> {}
|
||||
|
||||
fn establish_relationships<T, F>(value: T, closure: F)
|
||||
where
|
||||
F: FnOnce(T),
|
||||
{
|
||||
closure(value)
|
||||
}
|
||||
|
||||
fn require<'a, T>(t: T)
|
||||
where
|
||||
T: Trait<'a> + 'a,
|
||||
{
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn supply<'a, T>(value: T)
|
||||
where
|
||||
T: Trait<'a>,
|
||||
{
|
||||
establish_relationships(value, |value| {
|
||||
//~^ ERROR `T` does not outlive
|
||||
|
||||
// This function call requires that
|
||||
//
|
||||
// (a) T: Trait<'a>
|
||||
//
|
||||
// and
|
||||
//
|
||||
// (b) T: 'a
|
||||
//
|
||||
// The latter does not hold.
|
||||
|
||||
require(value);
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
});
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/propagate-from-trait-match.rs:55:9
|
||||
|
|
||||
55 | require(value);
|
||||
| ^^^^^^^
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/propagate-from-trait-match.rs:42:36
|
||||
|
|
||||
42 | establish_relationships(value, |value| {
|
||||
| ____________________________________^
|
||||
43 | | //~^ ERROR `T` does not outlive
|
||||
44 | |
|
||||
45 | | // This function call requires that
|
||||
... |
|
||||
56 | | //~^ WARNING not reporting region error due to -Znll
|
||||
57 | | });
|
||||
| |_____^
|
||||
|
|
||||
= note: defining type: DefId(0/1:16 ~ propagate_from_trait_match[317d]::supply[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((T,))
|
||||
]
|
||||
= note: number of external vids: 2
|
||||
= note: where T: '_#1r
|
||||
|
||||
error: `T` does not outlive `'_#3r`
|
||||
--> $DIR/propagate-from-trait-match.rs:42:36
|
||||
|
|
||||
42 | establish_relationships(value, |value| {
|
||||
| ____________________________________^
|
||||
43 | | //~^ ERROR `T` does not outlive
|
||||
44 | |
|
||||
45 | | // This function call requires that
|
||||
... |
|
||||
56 | | //~^ WARNING not reporting region error due to -Znll
|
||||
57 | | });
|
||||
| |_____^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/propagate-from-trait-match.rs:38:1
|
||||
|
|
||||
38 | / fn supply<'a, T>(value: T)
|
||||
39 | | where
|
||||
40 | | T: Trait<'a>,
|
||||
41 | | {
|
||||
... |
|
||||
57 | | });
|
||||
58 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:6 ~ propagate_from_trait_match[317d]::supply[0]) with substs [
|
||||
'_#1r,
|
||||
T
|
||||
]
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ error: free region `'_#3r` does not outlive free region `'_#2r`
|
|||
21 | expect_sig(|a, b| b); // ought to return `a`
|
||||
| ^
|
||||
|
||||
note: External requirements
|
||||
note: No external requirements
|
||||
--> $DIR/return-wrong-bound-region.rs:21:16
|
||||
|
|
||||
21 | expect_sig(|a, b| b); // ought to return `a`
|
||||
|
|
@ -20,7 +20,6 @@ note: External requirements
|
|||
i16,
|
||||
for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) i32, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) i32)) -> &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) i32
|
||||
]
|
||||
= note: number of external vids: 1
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/return-wrong-bound-region.rs:20:1
|
||||
|
|
|
|||
29
src/test/ui/nll/projection-return.rs
Normal file
29
src/test/ui/nll/projection-return.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir
|
||||
// must-compile-successfully
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
trait Foo {
|
||||
type Bar;
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
type Bar = u32;
|
||||
}
|
||||
|
||||
fn foo() -> <() as Foo>::Bar {
|
||||
22
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
||||
68
src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs
Normal file
68
src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
|
||||
// Tests closures that propagate an outlives relationship to their
|
||||
// creator where the subject is a projection with no regions (`<T as
|
||||
// Iterator>::Item`, to be exact).
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(dyn_trait)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
trait Anything { }
|
||||
|
||||
impl<T> Anything for T { }
|
||||
|
||||
fn with_signature<'a, T, F>(x: Box<T>, op: F) -> Box<dyn Anything + 'a>
|
||||
where F: FnOnce(Box<T>) -> Box<dyn Anything + 'a>
|
||||
{
|
||||
op(x)
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn no_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
|
||||
where
|
||||
T: Iterator,
|
||||
{
|
||||
with_signature(x, |mut y| Box::new(y.next()))
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn correct_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
|
||||
where
|
||||
T: 'a + Iterator,
|
||||
{
|
||||
with_signature(x, |mut y| Box::new(y.next()))
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
|
||||
where
|
||||
T: 'b + Iterator,
|
||||
{
|
||||
with_signature(x, |mut y| Box::new(y.next()))
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
|
||||
where
|
||||
T: 'b + Iterator,
|
||||
'b: 'a,
|
||||
{
|
||||
with_signature(x, |mut y| Box::new(y.next()))
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
157
src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
Normal file
157
src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-no-regions-closure.rs:36:31
|
||||
|
|
||||
36 | with_signature(x, |mut y| Box::new(y.next()))
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-no-regions-closure.rs:54:31
|
||||
|
|
||||
54 | with_signature(x, |mut y| Box::new(y.next()))
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-no-regions-closure.rs:36:23
|
||||
|
|
||||
36 | with_signature(x, |mut y| Box::new(y.next()))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:15 ~ projection_no_regions_closure[317d]::no_region[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#2r>
|
||||
]
|
||||
= note: number of external vids: 3
|
||||
= note: where <T as std::iter::Iterator>::Item: '_#2r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-no-regions-closure.rs:46:23
|
||||
|
|
||||
46 | with_signature(x, |mut y| Box::new(y.next()))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:18 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#2r>
|
||||
]
|
||||
= note: number of external vids: 3
|
||||
= note: where <T as std::iter::Iterator>::Item: '_#2r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-no-regions-closure.rs:54:23
|
||||
|
|
||||
54 | with_signature(x, |mut y| Box::new(y.next()))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:22 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#3r>
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
= note: where <T as std::iter::Iterator>::Item: '_#3r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-no-regions-closure.rs:65:23
|
||||
|
|
||||
65 | with_signature(x, |mut y| Box::new(y.next()))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:26 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<Anything + '_#3r>
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
= note: where <T as std::iter::Iterator>::Item: '_#3r
|
||||
|
||||
error: `<T as std::iter::Iterator>::Item` does not outlive `'_#4r`
|
||||
--> $DIR/projection-no-regions-closure.rs:36:23
|
||||
|
|
||||
36 | with_signature(x, |mut y| Box::new(y.next()))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-no-regions-closure.rs:32:1
|
||||
|
|
||||
32 | / fn no_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
|
||||
33 | | where
|
||||
34 | | T: Iterator,
|
||||
35 | | {
|
||||
... |
|
||||
38 | | //~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
|
||||
39 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:6 ~ projection_no_regions_closure[317d]::no_region[0]) with substs [
|
||||
'_#1r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-no-regions-closure.rs:42:1
|
||||
|
|
||||
42 | / fn correct_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
|
||||
43 | | where
|
||||
44 | | T: 'a + Iterator,
|
||||
45 | | {
|
||||
46 | | with_signature(x, |mut y| Box::new(y.next()))
|
||||
47 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:7 ~ projection_no_regions_closure[317d]::correct_region[0]) with substs [
|
||||
'_#1r,
|
||||
T
|
||||
]
|
||||
|
||||
error: `<T as std::iter::Iterator>::Item` does not outlive `'_#6r`
|
||||
--> $DIR/projection-no-regions-closure.rs:54:23
|
||||
|
|
||||
54 | with_signature(x, |mut y| Box::new(y.next()))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-no-regions-closure.rs:50:1
|
||||
|
|
||||
50 | / fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
|
||||
51 | | where
|
||||
52 | | T: 'b + Iterator,
|
||||
53 | | {
|
||||
... |
|
||||
56 | | //~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
|
||||
57 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:8 ~ projection_no_regions_closure[317d]::wrong_region[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-no-regions-closure.rs:60:1
|
||||
|
|
||||
60 | / fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
|
||||
61 | | where
|
||||
62 | | T: 'b + Iterator,
|
||||
63 | | 'b: 'a,
|
||||
64 | | {
|
||||
65 | | with_signature(x, |mut y| Box::new(y.next()))
|
||||
66 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:9 ~ projection_no_regions_closure[317d]::outlives_region[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
53
src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs
Normal file
53
src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(dyn_trait)]
|
||||
|
||||
trait Anything { }
|
||||
|
||||
impl<T> Anything for T { }
|
||||
|
||||
fn no_region<'a, T>(mut x: T) -> Box<dyn Anything + 'a>
|
||||
where
|
||||
T: Iterator,
|
||||
{
|
||||
Box::new(x.next())
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
|
||||
}
|
||||
|
||||
fn correct_region<'a, T>(mut x: T) -> Box<dyn Anything + 'a>
|
||||
where
|
||||
T: 'a + Iterator,
|
||||
{
|
||||
Box::new(x.next())
|
||||
}
|
||||
|
||||
fn wrong_region<'a, 'b, T>(mut x: T) -> Box<dyn Anything + 'a>
|
||||
where
|
||||
T: 'b + Iterator,
|
||||
{
|
||||
Box::new(x.next())
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `<T as std::iter::Iterator>::Item` does not outlive
|
||||
}
|
||||
|
||||
fn outlives_region<'a, 'b, T>(mut x: T) -> Box<dyn Anything + 'a>
|
||||
where
|
||||
T: 'b + Iterator,
|
||||
'b: 'a,
|
||||
{
|
||||
Box::new(x.next())
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
26
src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr
Normal file
26
src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-no-regions-fn.rs:24:5
|
||||
|
|
||||
24 | Box::new(x.next())
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-no-regions-fn.rs:40:5
|
||||
|
|
||||
40 | Box::new(x.next())
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `<T as std::iter::Iterator>::Item` does not outlive `'_#4r`
|
||||
--> $DIR/projection-no-regions-fn.rs:24:5
|
||||
|
|
||||
24 | Box::new(x.next())
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `<T as std::iter::Iterator>::Item` does not outlive `'_#5r`
|
||||
--> $DIR/projection-no-regions-fn.rs:40:5
|
||||
|
|
||||
40 | Box::new(x.next())
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
106
src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
Normal file
106
src/test/ui/nll/ty-outlives/projection-one-region-closure.rs
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test cases where we constrain `<T as Anything<'b>>::AssocType` to
|
||||
// outlive `'a` and there are no bounds in the trait definition of
|
||||
// `Anything`. This means that the constraint can only be satisfied in two
|
||||
// ways:
|
||||
//
|
||||
// - by ensuring that `T: 'a` and `'b: 'a`, or
|
||||
// - by something in the where clauses.
|
||||
//
|
||||
// As of this writing, the where clause option does not work because
|
||||
// of limitations in our region inferencing system (this is true both
|
||||
// with and without NLL). See `projection_outlives`.
|
||||
//
|
||||
// Ensuring that both `T: 'a` and `'b: 'a` holds does work (`elements_outlive`).
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(dyn_trait)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
trait Anything<'a> {
|
||||
type AssocType;
|
||||
}
|
||||
|
||||
fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
|
||||
where
|
||||
F: FnOnce(Cell<&'a ()>, T),
|
||||
{
|
||||
op(cell, t)
|
||||
}
|
||||
|
||||
fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
T::AssocType: 'a,
|
||||
{
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `T` does not outlive
|
||||
//~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
'a: 'a,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `T` does not outlive
|
||||
//~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
T::AssocType: 'a,
|
||||
{
|
||||
// This error is unfortunate. This code ought to type-check: we
|
||||
// are projecting `<T as Anything<'b>>::AssocType`, and we know
|
||||
// that this outlives `'a` because of the where-clause. However,
|
||||
// the way the region checker works, we don't register this
|
||||
// outlives obligation, and hence we get an error: this is because
|
||||
// what we see is a projection like `<T as
|
||||
// Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
|
||||
// equal `'b` or not, so we ignore the where-clause. Obviously we
|
||||
// can do better here with a more involved verification step.
|
||||
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `T` does not outlive
|
||||
//~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
T: 'a,
|
||||
'b: 'a,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
194
src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
Normal file
194
src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-one-region-closure.rs:56:39
|
||||
|
|
||||
56 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-one-region-closure.rs:68:39
|
||||
|
|
||||
68 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-one-region-closure.rs:90:39
|
||||
|
|
||||
90 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-closure.rs:56:29
|
||||
|
|
||||
56 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:19 ~ projection_one_region_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 3
|
||||
= note: where T: '_#2r
|
||||
= note: where '_#1r: '_#2r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-closure.rs:68:29
|
||||
|
|
||||
68 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:23 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
= note: where T: '_#3r
|
||||
= note: where '_#2r: '_#3r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-closure.rs:90:29
|
||||
|
|
||||
90 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:27 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
= note: where T: '_#3r
|
||||
= note: where '_#2r: '_#3r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-closure.rs:103:29
|
||||
|
|
||||
103 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:31 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
= note: where T: '_#3r
|
||||
= note: where '_#2r: '_#3r
|
||||
|
||||
error: `T` does not outlive `'_#5r`
|
||||
--> $DIR/projection-one-region-closure.rs:56:29
|
||||
|
|
||||
56 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
|
||||
--> $DIR/projection-one-region-closure.rs:56:20
|
||||
|
|
||||
56 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-closure.rs:52:1
|
||||
|
|
||||
52 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
53 | | where
|
||||
54 | | T: Anything<'b>,
|
||||
55 | | {
|
||||
... |
|
||||
59 | | //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
|
||||
60 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]) with substs [
|
||||
'_#1r,
|
||||
T
|
||||
]
|
||||
|
||||
error: `T` does not outlive `'_#6r`
|
||||
--> $DIR/projection-one-region-closure.rs:68:29
|
||||
|
|
||||
68 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||
--> $DIR/projection-one-region-closure.rs:68:20
|
||||
|
|
||||
68 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-closure.rs:63:1
|
||||
|
|
||||
63 | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
64 | | where
|
||||
65 | | T: Anything<'b>,
|
||||
66 | | 'a: 'a,
|
||||
... |
|
||||
71 | | //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||
72 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:9 ~ projection_one_region_closure[317d]::no_relationships_early[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
error: `T` does not outlive `'_#6r`
|
||||
--> $DIR/projection-one-region-closure.rs:90:29
|
||||
|
|
||||
90 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||
--> $DIR/projection-one-region-closure.rs:90:20
|
||||
|
|
||||
90 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-closure.rs:75:1
|
||||
|
|
||||
75 | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
76 | | where
|
||||
77 | | T: Anything<'b>,
|
||||
78 | | T::AssocType: 'a,
|
||||
... |
|
||||
93 | | //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||
94 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:10 ~ projection_one_region_closure[317d]::projection_outlives[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-closure.rs:97:1
|
||||
|
|
||||
97 | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
98 | | where
|
||||
99 | | T: Anything<'b>,
|
||||
100 | | T: 'a,
|
||||
... |
|
||||
103 | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
104 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:11 ~ projection_one_region_closure[317d]::elements_outlive[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test cases where we constrain `<T as Anything<'b>>::AssocType` to
|
||||
// outlive `'a` and there is a unique bound in the trait definition of
|
||||
// `Anything` -- i.e., we know that `AssocType` outlives `'b`. In this
|
||||
// case, the best way to satisfy the trait bound is to show that `'b:
|
||||
// 'a`, which can be done in various ways.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(dyn_trait)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
trait Anything<'a> {
|
||||
type AssocType: 'a;
|
||||
}
|
||||
|
||||
fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
|
||||
where
|
||||
F: FnOnce(Cell<&'a ()>, T),
|
||||
{
|
||||
op(cell, t)
|
||||
}
|
||||
|
||||
fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
T::AssocType: 'a,
|
||||
{
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
'a: 'a,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
T::AssocType: 'a,
|
||||
{
|
||||
// This error is unfortunate. This code ought to type-check: we
|
||||
// are projecting `<T as Anything<'b>>::AssocType`, and we know
|
||||
// that this outlives `'a` because of the where-clause. However,
|
||||
// the way the region checker works, we don't register this
|
||||
// outlives obligation, and hence we get an error: this is because
|
||||
// what we see is a projection like `<T as
|
||||
// Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
|
||||
// equal `'b` or not, so we ignore the where-clause. Obviously we
|
||||
// can do better here with a more involved verification step.
|
||||
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
'b: 'a,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'a>,
|
||||
{
|
||||
// Note that in this case the closure still propagates an external
|
||||
// requirement between two variables in its signature, but the
|
||||
// creator maps both those two region variables to `'a` on its
|
||||
// side.
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:48:39
|
||||
|
|
||||
48 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:59:39
|
||||
|
|
||||
59 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:80:39
|
||||
|
|
||||
80 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:48:29
|
||||
|
|
||||
48 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:19 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 3
|
||||
= note: where '_#1r: '_#2r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:59:29
|
||||
|
|
||||
59 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
= note: where '_#2r: '_#3r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:80:29
|
||||
|
|
||||
80 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
= note: where '_#2r: '_#3r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:91:29
|
||||
|
|
||||
91 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
= note: where '_#2r: '_#3r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:103:29
|
||||
|
|
||||
103 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 3
|
||||
= note: where '_#1r: '_#2r
|
||||
|
||||
error: free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:48:20
|
||||
|
|
||||
48 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:44:1
|
||||
|
|
||||
44 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
45 | | where
|
||||
46 | | T: Anything<'b>,
|
||||
47 | | {
|
||||
... |
|
||||
50 | | //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
|
||||
51 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [
|
||||
'_#1r,
|
||||
T
|
||||
]
|
||||
|
||||
error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:59:20
|
||||
|
|
||||
59 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:54:1
|
||||
|
|
||||
54 | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
55 | | where
|
||||
56 | | T: Anything<'b>,
|
||||
57 | | 'a: 'a,
|
||||
... |
|
||||
61 | | //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||
62 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:80:20
|
||||
|
|
||||
80 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:65:1
|
||||
|
|
||||
65 | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
66 | | where
|
||||
67 | | T: Anything<'b>,
|
||||
68 | | T::AssocType: 'a,
|
||||
... |
|
||||
82 | | //~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
|
||||
83 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:86:1
|
||||
|
|
||||
86 | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
87 | | where
|
||||
88 | | T: Anything<'b>,
|
||||
89 | | 'b: 'a,
|
||||
90 | | {
|
||||
91 | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
92 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-closure.rs:95:1
|
||||
|
|
||||
95 | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
|
||||
96 | | where
|
||||
97 | | T: Anything<'a>,
|
||||
98 | | {
|
||||
... |
|
||||
103 | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
104 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]) with substs [
|
||||
'_#1r,
|
||||
T
|
||||
]
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test cases where we constrain `<T as Anything<'b>>::AssocType` to
|
||||
// outlive `'static`. In this case, we don't get any errors, and in fact
|
||||
// we don't even propagate constraints from the closures to the callers.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
// must-compile-successfully
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(dyn_trait)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
trait Anything<'a> {
|
||||
type AssocType: 'static;
|
||||
}
|
||||
|
||||
fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
|
||||
where
|
||||
F: FnOnce(Cell<&'a ()>, T),
|
||||
{
|
||||
op(cell, t)
|
||||
}
|
||||
|
||||
fn require<'a, 'b, T>(_cell: Cell<&'a ()>, _t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
T::AssocType: 'a,
|
||||
{
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
'a: 'a,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
T::AssocType: 'a,
|
||||
{
|
||||
// This error is unfortunate. This code ought to type-check: we
|
||||
// are projecting `<T as Anything<'b>>::AssocType`, and we know
|
||||
// that this outlives `'a` because of the where-clause. However,
|
||||
// the way the region checker works, we don't register this
|
||||
// outlives obligation, and hence we get an error: this is because
|
||||
// what we see is a projection like `<T as
|
||||
// Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
|
||||
// equal `'b` or not, so we ignore the where-clause. Obviously we
|
||||
// can do better here with a more involved verification step.
|
||||
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b>,
|
||||
'b: 'a,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'a>,
|
||||
{
|
||||
// Note that in this case the closure still propagates an external
|
||||
// requirement between two variables in its signature, but the
|
||||
// creator maps both those two region variables to `'a` on its
|
||||
// side.
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-static-closure.rs:47:29
|
||||
|
|
||||
47 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:19 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-static-closure.rs:56:29
|
||||
|
|
||||
56 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-static-closure.rs:75:29
|
||||
|
|
||||
75 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-static-closure.rs:84:29
|
||||
|
|
||||
84 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-static-closure.rs:96:29
|
||||
|
|
||||
96 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-static-closure.rs:43:1
|
||||
|
|
||||
43 | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
44 | | where
|
||||
45 | | T: Anything<'b>,
|
||||
46 | | {
|
||||
47 | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
48 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [
|
||||
'_#1r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-static-closure.rs:51:1
|
||||
|
|
||||
51 | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
52 | | where
|
||||
53 | | T: Anything<'b>,
|
||||
54 | | 'a: 'a,
|
||||
55 | | {
|
||||
56 | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
57 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-static-closure.rs:60:1
|
||||
|
|
||||
60 | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
61 | | where
|
||||
62 | | T: Anything<'b>,
|
||||
63 | | T::AssocType: 'a,
|
||||
... |
|
||||
75 | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
76 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-static-closure.rs:79:1
|
||||
|
|
||||
79 | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
80 | | where
|
||||
81 | | T: Anything<'b>,
|
||||
82 | | 'b: 'a,
|
||||
83 | | {
|
||||
84 | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
85 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-one-region-trait-bound-static-closure.rs:88:1
|
||||
|
|
||||
88 | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
|
||||
89 | | where
|
||||
90 | | T: Anything<'a>,
|
||||
91 | | {
|
||||
... |
|
||||
96 | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
97 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]) with substs [
|
||||
'_#1r,
|
||||
T
|
||||
]
|
||||
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test cases where we constrain `<T as Anything<'a, 'b>>::AssocType`
|
||||
// to outlive `'a` and there are two bounds in the trait definition of
|
||||
// `Anything` -- i.e., we know that `AssocType` outlives `'a` and
|
||||
// `'b`. In this case, it's not clear what is the best way to satisfy
|
||||
// the trait bound, and hence we propagate it to the caller as a type
|
||||
// test.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(dyn_trait)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
trait Anything<'a, 'b> {
|
||||
type AssocType: 'a + 'b;
|
||||
}
|
||||
|
||||
fn with_signature<'a, T, F>(cell: Cell<&'a ()>, t: T, op: F)
|
||||
where
|
||||
F: FnOnce(Cell<&'a ()>, T),
|
||||
{
|
||||
op(cell, t)
|
||||
}
|
||||
|
||||
fn require<'a, 'b, 'c, T>(_cell: Cell<&'a ()>, _t: T)
|
||||
where
|
||||
T: Anything<'b, 'c>,
|
||||
T::AssocType: 'a,
|
||||
{
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b, 'c>,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `<T as Anything<'_#5r, '_#6r>>::AssocType` does not outlive `'_#7r`
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b, 'c>,
|
||||
'a: 'a,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `<T as Anything<'_#6r, '_#7r>>::AssocType` does not outlive `'_#8r`
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b, 'c>,
|
||||
T::AssocType: 'a,
|
||||
{
|
||||
// This error is unfortunate. This code ought to type-check: we
|
||||
// are projecting `<T as Anything<'b>>::AssocType`, and we know
|
||||
// that this outlives `'a` because of the where-clause. However,
|
||||
// the way the region checker works, we don't register this
|
||||
// outlives obligation, and hence we get an error: this is because
|
||||
// what we see is a projection like `<T as
|
||||
// Anything<'?0>>::AssocType`, and we don't yet know if `?0` will
|
||||
// equal `'b` or not, so we ignore the where-clause. Obviously we
|
||||
// can do better here with a more involved verification step.
|
||||
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `<T as Anything<'_#6r, '_#7r>>::AssocType` does not outlive `'_#8r`
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b, 'c>,
|
||||
'b: 'a,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b, 'c>,
|
||||
'c: 'a,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b, 'b>,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'b, 'b>,
|
||||
'b: 'a,
|
||||
{
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
|
||||
where
|
||||
T: Anything<'a, 'a>,
|
||||
{
|
||||
// Note that in this case the closure still propagates an external
|
||||
// requirement between two variables in its signature, but the
|
||||
// creator maps both those two region variables to `'a` on its
|
||||
// side.
|
||||
with_signature(cell, t, |cell, t| require(cell, t));
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,326 @@
|
|||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:49:39
|
||||
|
|
||||
49 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:60:39
|
||||
|
|
||||
60 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:81:39
|
||||
|
|
||||
81 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:109:39
|
||||
|
|
||||
109 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:49:29
|
||||
|
|
||||
49 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:22 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
= note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#2r)>>::AssocType: '_#3r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:60:29
|
||||
|
|
||||
60 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:27 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
'_#3r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 5
|
||||
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:81:29
|
||||
|
|
||||
81 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:32 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
'_#3r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 5
|
||||
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:92:29
|
||||
|
|
||||
92 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:37 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
'_#3r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 5
|
||||
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:101:29
|
||||
|
|
||||
101 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:42 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
'_#3r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 5
|
||||
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:109:29
|
||||
|
|
||||
109 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:46 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 3
|
||||
= note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:120:29
|
||||
|
|
||||
120 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:50 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#2r)>>::AssocType: '_#3r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:132:29
|
||||
|
|
||||
132 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:53 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 3
|
||||
= note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
|
||||
|
||||
error: `<T as Anything<'_#5r, '_#6r>>::AssocType` does not outlive `'_#7r`
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:49:29
|
||||
|
|
||||
49 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:45:1
|
||||
|
|
||||
45 | / fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||
46 | | where
|
||||
47 | | T: Anything<'b, 'c>,
|
||||
48 | | {
|
||||
... |
|
||||
51 | | //~| ERROR `<T as Anything<'_#5r, '_#6r>>::AssocType` does not outlive `'_#7r`
|
||||
52 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
error: `<T as Anything<'_#6r, '_#7r>>::AssocType` does not outlive `'_#8r`
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:60:29
|
||||
|
|
||||
60 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:55:1
|
||||
|
|
||||
55 | / fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||
56 | | where
|
||||
57 | | T: Anything<'b, 'c>,
|
||||
58 | | 'a: 'a,
|
||||
... |
|
||||
62 | | //~| ERROR `<T as Anything<'_#6r, '_#7r>>::AssocType` does not outlive `'_#8r`
|
||||
63 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:9 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
'_#3r,
|
||||
T
|
||||
]
|
||||
|
||||
error: `<T as Anything<'_#6r, '_#7r>>::AssocType` does not outlive `'_#8r`
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:81:29
|
||||
|
|
||||
81 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:66:1
|
||||
|
|
||||
66 | / fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||
67 | | where
|
||||
68 | | T: Anything<'b, 'c>,
|
||||
69 | | T::AssocType: 'a,
|
||||
... |
|
||||
83 | | //~| ERROR `<T as Anything<'_#6r, '_#7r>>::AssocType` does not outlive `'_#8r`
|
||||
84 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:10 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
'_#3r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:87:1
|
||||
|
|
||||
87 | / fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||
88 | | where
|
||||
89 | | T: Anything<'b, 'c>,
|
||||
90 | | 'b: 'a,
|
||||
91 | | {
|
||||
92 | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
93 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:11 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
'_#3r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:96:1
|
||||
|
|
||||
96 | / fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
|
||||
97 | | where
|
||||
98 | | T: Anything<'b, 'c>,
|
||||
99 | | 'c: 'a,
|
||||
100 | | {
|
||||
101 | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
102 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:12 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
'_#3r,
|
||||
T
|
||||
]
|
||||
|
||||
error: free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:109:20
|
||||
|
|
||||
109 | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
| ^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:105:1
|
||||
|
|
||||
105 | / fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
106 | | where
|
||||
107 | | T: Anything<'b, 'b>,
|
||||
108 | | {
|
||||
... |
|
||||
111 | | //~| ERROR free region `ReEarlyBound(0, 'b)` does not outlive free region `'_#2r`
|
||||
112 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]) with substs [
|
||||
'_#1r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:115:1
|
||||
|
|
||||
115 | / fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
|
||||
116 | | where
|
||||
117 | | T: Anything<'b, 'b>,
|
||||
118 | | 'b: 'a,
|
||||
119 | | {
|
||||
120 | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
121 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:14 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/projection-two-region-trait-bound-closure.rs:124:1
|
||||
|
|
||||
124 | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
|
||||
125 | | where
|
||||
126 | | T: Anything<'a, 'a>,
|
||||
127 | | {
|
||||
... |
|
||||
132 | | with_signature(cell, t, |cell, t| require(cell, t));
|
||||
133 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:15 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]) with substs [
|
||||
'_#1r,
|
||||
T
|
||||
]
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(dyn_trait)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn with_signature<'a, T, F>(x: Box<T>, op: F) -> Box<dyn Debug + 'a>
|
||||
where F: FnOnce(Box<T>) -> Box<dyn Debug + 'a>
|
||||
{
|
||||
op(x)
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
// Here, the closure winds up being required to prove that `T:
|
||||
// 'a`. In principle, it could know that, except that it is
|
||||
// type-checked in a fully generic way, and hence it winds up with
|
||||
// a propagated requirement that `T: '_#2`, where `'_#2` appears
|
||||
// in the return type. The caller makes the mapping from `'_#2` to
|
||||
// `'a` (and subsequently reports an error).
|
||||
|
||||
with_signature(x, |y| y)
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `T` does not outlive
|
||||
}
|
||||
|
||||
fn correct_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
|
||||
where
|
||||
T: 'a + Debug,
|
||||
{
|
||||
x
|
||||
}
|
||||
|
||||
fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
|
||||
where
|
||||
T: 'b + Debug,
|
||||
{
|
||||
x
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `T` does not outlive
|
||||
}
|
||||
|
||||
fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
|
||||
where
|
||||
T: 'b + Debug,
|
||||
'b: 'a,
|
||||
{
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/ty-param-closure-outlives-from-return-type.rs:37:27
|
||||
|
|
||||
37 | with_signature(x, |y| y)
|
||||
| ^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/ty-param-closure-outlives-from-return-type.rs:53:5
|
||||
|
|
||||
53 | x
|
||||
| ^
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/ty-param-closure-outlives-from-return-type.rs:37:23
|
||||
|
|
||||
37 | with_signature(x, |y| y)
|
||||
| ^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:14 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<std::fmt::Debug + '_#2r>
|
||||
]
|
||||
= note: number of external vids: 3
|
||||
= note: where T: '_#2r
|
||||
|
||||
error: `T` does not outlive `'_#4r`
|
||||
--> $DIR/ty-param-closure-outlives-from-return-type.rs:37:23
|
||||
|
|
||||
37 | with_signature(x, |y| y)
|
||||
| ^^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/ty-param-closure-outlives-from-return-type.rs:26:1
|
||||
|
|
||||
26 | / fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a>
|
||||
27 | | where
|
||||
28 | | T: Debug,
|
||||
29 | | {
|
||||
... |
|
||||
39 | | //~| ERROR `T` does not outlive
|
||||
40 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:5 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]) with substs [
|
||||
'_#1r,
|
||||
T
|
||||
]
|
||||
|
||||
error: `T` does not outlive `'_#4r`
|
||||
--> $DIR/ty-param-closure-outlives-from-return-type.rs:53:5
|
||||
|
|
||||
53 | x
|
||||
| ^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that we can propagate `T: 'a` obligations to our caller. See
|
||||
// `correct_region` for an explanation of how this test is setup; it's
|
||||
// somewhat intricate.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(dyn_trait)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
fn with_signature<'a, T, F>(a: Cell<&'a ()>, b: T, op: F)
|
||||
where
|
||||
F: FnOnce(Cell<&'a ()>, T),
|
||||
{
|
||||
op(a, b)
|
||||
}
|
||||
|
||||
fn require<'a, T>(_a: &Cell<&'a ()>, _b: &T)
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn no_region<'a, T>(a: Cell<&'a ()>, b: T) {
|
||||
with_signature(a, b, |x, y| {
|
||||
//~^ ERROR `T` does not outlive
|
||||
//
|
||||
// See `correct_region`, which explains the point of this
|
||||
// test. The only difference is that, in the case of this
|
||||
// function, there is no where clause *anywhere*, and hence we
|
||||
// get an error (but reported by the closure creator).
|
||||
require(&x, &y)
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
})
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn correct_region<'a, T>(a: Cell<&'a ()>, b: T)
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
with_signature(a, b, |x, y| {
|
||||
// Key point of this test:
|
||||
//
|
||||
// The *closure* is being type-checked with all of its free
|
||||
// regions "universalized". In particular, it does not know
|
||||
// that `x` has the type `Cell<&'a ()>`, but rather treats it
|
||||
// as if the type of `x` is `Cell<&'A ()>`, where `'A` is some
|
||||
// fresh, independent region distinct from the `'a` which
|
||||
// appears in the environment. The call to `require` here
|
||||
// forces us then to prove that `T: 'A`, but the closure
|
||||
// cannot do it on its own. It has to surface this requirement
|
||||
// to its creator (which knows that `'a == 'A`).
|
||||
require(&x, &y)
|
||||
})
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
|
||||
where
|
||||
T: 'b,
|
||||
{
|
||||
with_signature(a, b, |x, y| {
|
||||
//~^ ERROR `T` does not outlive
|
||||
// See `correct_region`
|
||||
require(&x, &y)
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
})
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn outlives_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
|
||||
where
|
||||
T: 'b,
|
||||
'b: 'a,
|
||||
{
|
||||
with_signature(a, b, |x, y| {
|
||||
// See `correct_region`
|
||||
require(&x, &y)
|
||||
})
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:45:9
|
||||
|
|
||||
45 | require(&x, &y)
|
||||
| ^^^^^^^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:79:9
|
||||
|
|
||||
79 | require(&x, &y)
|
||||
| ^^^^^^^
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26
|
||||
|
|
||||
38 | with_signature(a, b, |x, y| {
|
||||
| __________________________^
|
||||
39 | | //~^ ERROR `T` does not outlive
|
||||
40 | | //
|
||||
41 | | // See `correct_region`, which explains the point of this
|
||||
... |
|
||||
46 | | //~^ WARNING not reporting region error due to -Znll
|
||||
47 | | })
|
||||
| |_____^
|
||||
|
|
||||
= note: defining type: DefId(0/1:16 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]::{{closure}}[0]) with closure substs [
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 2
|
||||
= note: where T: '_#1r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:55:26
|
||||
|
|
||||
55 | with_signature(a, b, |x, y| {
|
||||
| __________________________^
|
||||
56 | | // Key point of this test:
|
||||
57 | | //
|
||||
58 | | // The *closure* is being type-checked with all of its free
|
||||
... |
|
||||
67 | | require(&x, &y)
|
||||
68 | | })
|
||||
| |_____^
|
||||
|
|
||||
= note: defining type: DefId(0/1:19 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 3
|
||||
= note: where T: '_#2r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26
|
||||
|
|
||||
76 | with_signature(a, b, |x, y| {
|
||||
| __________________________^
|
||||
77 | | //~^ ERROR `T` does not outlive
|
||||
78 | | // See `correct_region`
|
||||
79 | | require(&x, &y)
|
||||
80 | | //~^ WARNING not reporting region error due to -Znll
|
||||
81 | | })
|
||||
| |_____^
|
||||
|
|
||||
= note: defining type: DefId(0/1:23 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 3
|
||||
= note: where T: '_#2r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:90:26
|
||||
|
|
||||
90 | with_signature(a, b, |x, y| {
|
||||
| __________________________^
|
||||
91 | | // See `correct_region`
|
||||
92 | | require(&x, &y)
|
||||
93 | | })
|
||||
| |_____^
|
||||
|
|
||||
= note: defining type: DefId(0/1:27 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T,
|
||||
i32,
|
||||
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T))
|
||||
]
|
||||
= note: number of external vids: 4
|
||||
= note: where T: '_#3r
|
||||
|
||||
error: `T` does not outlive `'_#3r`
|
||||
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26
|
||||
|
|
||||
38 | with_signature(a, b, |x, y| {
|
||||
| __________________________^
|
||||
39 | | //~^ ERROR `T` does not outlive
|
||||
40 | | //
|
||||
41 | | // See `correct_region`, which explains the point of this
|
||||
... |
|
||||
46 | | //~^ WARNING not reporting region error due to -Znll
|
||||
47 | | })
|
||||
| |_____^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:1
|
||||
|
|
||||
37 | / fn no_region<'a, T>(a: Cell<&'a ()>, b: T) {
|
||||
38 | | with_signature(a, b, |x, y| {
|
||||
39 | | //~^ ERROR `T` does not outlive
|
||||
40 | | //
|
||||
... |
|
||||
47 | | })
|
||||
48 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]) with substs [
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:51:1
|
||||
|
|
||||
51 | / fn correct_region<'a, T>(a: Cell<&'a ()>, b: T)
|
||||
52 | | where
|
||||
53 | | T: 'a,
|
||||
54 | | {
|
||||
... |
|
||||
68 | | })
|
||||
69 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:7 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]) with substs [
|
||||
'_#1r,
|
||||
T
|
||||
]
|
||||
|
||||
error: `T` does not outlive `'_#5r`
|
||||
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26
|
||||
|
|
||||
76 | with_signature(a, b, |x, y| {
|
||||
| __________________________^
|
||||
77 | | //~^ ERROR `T` does not outlive
|
||||
78 | | // See `correct_region`
|
||||
79 | | require(&x, &y)
|
||||
80 | | //~^ WARNING not reporting region error due to -Znll
|
||||
81 | | })
|
||||
| |_____^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:72:1
|
||||
|
|
||||
72 | / fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
|
||||
73 | | where
|
||||
74 | | T: 'b,
|
||||
75 | | {
|
||||
... |
|
||||
81 | | })
|
||||
82 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]) with substs [
|
||||
'_#1r,
|
||||
T
|
||||
]
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:85:1
|
||||
|
|
||||
85 | / fn outlives_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
|
||||
86 | | where
|
||||
87 | | T: 'b,
|
||||
88 | | 'b: 'a,
|
||||
... |
|
||||
93 | | })
|
||||
94 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:9 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]) with substs [
|
||||
'_#1r,
|
||||
'_#2r,
|
||||
T
|
||||
]
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
41
src/test/ui/nll/ty-outlives/ty-param-fn-body.rs
Normal file
41
src/test/ui/nll/ty-outlives/ty-param-fn-body.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir
|
||||
|
||||
// Test that we assume that universal types like `T` outlive the
|
||||
// function body.
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(dyn_trait)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
// No errors here, because `'a` is local to the body.
|
||||
fn region_within_body<T>(t: T) {
|
||||
let some_int = 22;
|
||||
let cell = Cell::new(&some_int);
|
||||
outlives(cell, t)
|
||||
}
|
||||
|
||||
// Error here, because T: 'a is not satisfied.
|
||||
fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) {
|
||||
outlives(cell, t)
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `T` does not outlive
|
||||
}
|
||||
|
||||
fn outlives<'a, T>(x: Cell<&'a usize>, y: T)
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
14
src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr
Normal file
14
src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/ty-param-fn-body.rs:30:5
|
||||
|
|
||||
30 | outlives(cell, t)
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `T` does not outlive `'_#4r`
|
||||
--> $DIR/ty-param-fn-body.rs:30:5
|
||||
|
|
||||
30 | outlives(cell, t)
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
51
src/test/ui/nll/ty-outlives/ty-param-fn.rs
Normal file
51
src/test/ui/nll/ty-outlives/ty-param-fn.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(dyn_trait)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn no_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
x
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `T` does not outlive
|
||||
}
|
||||
|
||||
fn correct_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
|
||||
where
|
||||
T: 'a + Debug,
|
||||
{
|
||||
x
|
||||
}
|
||||
|
||||
fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
|
||||
where
|
||||
T: 'b + Debug,
|
||||
{
|
||||
x
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `T` does not outlive
|
||||
}
|
||||
|
||||
fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
|
||||
where
|
||||
T: 'b + Debug,
|
||||
'b: 'a,
|
||||
{
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
26
src/test/ui/nll/ty-outlives/ty-param-fn.stderr
Normal file
26
src/test/ui/nll/ty-outlives/ty-param-fn.stderr
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/ty-param-fn.rs:22:5
|
||||
|
|
||||
22 | x
|
||||
| ^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/ty-param-fn.rs:38:5
|
||||
|
|
||||
38 | x
|
||||
| ^
|
||||
|
||||
error: `T` does not outlive `'_#3r`
|
||||
--> $DIR/ty-param-fn.rs:22:5
|
||||
|
|
||||
22 | x
|
||||
| ^
|
||||
|
||||
error: `T` does not outlive `'_#4r`
|
||||
--> $DIR/ty-param-fn.rs:38:5
|
||||
|
|
||||
38 | x
|
||||
| ^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue