Skip to content

propagate outlives between types and regions #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Dec 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
019e703
remove unnecessary intermediate vector from `copy`
nikomatsakis Dec 3, 2017
297b2ce
rename `copy` to `dfs` and make it customizable
nikomatsakis Dec 3, 2017
173ced7
only propagate ClosureRegionRequirements if non-trivial
nikomatsakis Dec 3, 2017
228358d
translate `Verify`s into `TypeTest`s and check them
nikomatsakis Dec 3, 2017
d1b8aeb
dfs.rs: rustfmt
nikomatsakis Dec 5, 2017
39dd556
move `type_check` out of transform and into `type_check` module
nikomatsakis Dec 3, 2017
87beb7a
move `LivenessResults` from `nll` into `liveness` analysis
nikomatsakis Dec 3, 2017
ff7f2b0
move `flow_in_progress` into `dataflow` and document it
nikomatsakis Dec 3, 2017
8270bd1
move some parts of liveness to happen during type checking
nikomatsakis Dec 3, 2017
dfdd869
mild refactors of the control flow (no functional changes)
nikomatsakis Dec 4, 2017
4c02fa2
rework region flags: 'static can be erased too
nikomatsakis Dec 4, 2017
32ebbea
thread through an implicit region body of the fn body
nikomatsakis Dec 4, 2017
eb8d137
permit `ClosureOutlivesRequirement` to constrain regions or types
nikomatsakis Dec 4, 2017
89b99d3
propagate type tests from closure to closure creators
nikomatsakis Dec 4, 2017
613990e
add a new RegionKind variant: ReClosureBound
nikomatsakis Dec 5, 2017
8a06880
handle projections with regions
nikomatsakis Dec 5, 2017
ac7c826
impose inputs/ouputs on MIR after the fact
nikomatsakis Dec 6, 2017
cf75bad
add a test regarding relating closure and fn generics
nikomatsakis Dec 6, 2017
637880f
compiletest: account for `ui` reference files when deciding to skip
nikomatsakis Dec 6, 2017
d408a06
make `blame_span` deterministic
nikomatsakis Dec 6, 2017
5c50d6c
more concise debug output when dumping the value of a region
nikomatsakis Dec 6, 2017
25808b1
simplify `AnonTypeDecl` in the impl trait code
nikomatsakis Dec 6, 2017
afa2e58
region_infer/values.rs: rustfmt
nikomatsakis Dec 6, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions src/librustc/ich/impls_mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,14 +573,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);
}
}
}
}
3 changes: 3 additions & 0 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..) => {
Expand Down
8 changes: 8 additions & 0 deletions src/librustc/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/librustc/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
7 changes: 7 additions & 0 deletions src/librustc/infer/freshen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
);
}
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/librustc/infer/lexical_region_resolve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
42 changes: 34 additions & 8 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1824,8 +1824,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)]
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
Expand All @@ -1835,15 +1844,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)]
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)]
pub struct ClosureOutlivesRequirement<'tcx> {
// This region or type ...
pub subject: ClosureOutlivesSubject<'tcx>,

// .. must outlive this one.
pub outlived_free_region: ty::RegionVid,
Expand All @@ -1852,6 +1861,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)]
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
*/
Expand Down
15 changes: 10 additions & 5 deletions src/librustc/ty/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
/// "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_RE_EARLY_BOUND |
TypeFlags::HAS_RE_INFER |
TypeFlags::HAS_FREE_REGIONS)
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 |
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/maps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
10 changes: 10 additions & 0 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,8 +412,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;

Expand Down
26 changes: 23 additions & 3 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {}
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,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(..) |
Expand Down
8 changes: 8 additions & 0 deletions src/librustc/util/ppaux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/librustc_borrowck/borrowck/gather_loans/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..) |
Expand Down
Loading