Skip to content
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

nll part 5 #46733

Merged
merged 25 commits into from
Dec 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
86334c7
remove unnecessary intermediate vector from `copy`
nikomatsakis Dec 3, 2017
a0f0392
rename `copy` to `dfs` and make it customizable
nikomatsakis Dec 3, 2017
cd564d2
only propagate ClosureRegionRequirements if non-trivial
nikomatsakis Dec 3, 2017
6193c5c
translate `Verify`s into `TypeTest`s and check them
nikomatsakis Dec 3, 2017
fad3d1d
dfs.rs: rustfmt
nikomatsakis Dec 5, 2017
1c57468
move `type_check` out of `transform` and into the `nll` module
nikomatsakis Dec 3, 2017
ebd086b
move `LivenessResults` from `nll` into `liveness` analysis
nikomatsakis Dec 3, 2017
4a940b3
move `flow_in_progress` into `dataflow` and document it
nikomatsakis Dec 3, 2017
47c1921
move some parts of liveness to happen during type checking
nikomatsakis Dec 3, 2017
02e6525
mild refactors of the control flow (no functional changes)
nikomatsakis Dec 4, 2017
154cd94
rework region flags: 'static can be erased too
nikomatsakis Dec 4, 2017
c7cfa23
thread through an implicit region body of the fn body
nikomatsakis Dec 4, 2017
5804637
permit `ClosureOutlivesRequirement` to constrain regions or types
nikomatsakis Dec 4, 2017
85e1d47
propagate type tests from closure to closure creators
nikomatsakis Dec 4, 2017
3a5842a
add a new RegionKind variant: ReClosureBound
nikomatsakis Dec 5, 2017
3fcb13a
handle projections with regions
nikomatsakis Dec 5, 2017
e9824c5
impose inputs/ouputs on MIR after the fact
nikomatsakis Dec 6, 2017
a118afe
add a test regarding relating closure and fn generics
nikomatsakis Dec 6, 2017
0d6bd42
make `blame_span` deterministic
nikomatsakis Dec 6, 2017
0f8ef0c
more concise debug output when dumping the value of a region
nikomatsakis Dec 6, 2017
4f43c5b
stop dumping DefPath into "failed type test" errors
nikomatsakis Dec 15, 2017
03bfb0f
tweak comment on `TypeTest` to be more accurate
nikomatsakis Dec 19, 2017
3c56c36
fix comment on `check_type_tests`
nikomatsakis Dec 19, 2017
3d826e5
remove dead `is_foo_free_region` helpers
nikomatsakis Dec 19, 2017
1816ede
be specific about what kind of normalization we mean
nikomatsakis Dec 19, 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 @@ -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);
}
}
}
}
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 @@ -1831,8 +1831,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
Expand All @@ -1842,15 +1851,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,
Expand All @@ -1859,6 +1868,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
*/
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 @@ -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;

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 @@ -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(..) |
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
1 change: 1 addition & 0 deletions src/librustc_mir/borrow_check/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
},
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_mir/borrow_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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));

Expand All @@ -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);
Expand Down
Loading