Skip to content

Commit

Permalink
Auto merge of #48482 - davidtwco:issue-47184, r=nikomatsakis
Browse files Browse the repository at this point in the history
NLL should identify and respect the lifetime annotations that the user wrote

Part of #47184.

r? @nikomatsakis
  • Loading branch information
bors committed Mar 24, 2018
2 parents 4be5d36 + 4161ae7 commit ab0ef14
Show file tree
Hide file tree
Showing 36 changed files with 358 additions and 33 deletions.
4 changes: 4 additions & 0 deletions src/librustc/ich/impls_mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,10 @@ for mir::StatementKind<'gcx> {
op.hash_stable(hcx, hasher);
places.hash_stable(hcx, hasher);
}
mir::StatementKind::UserAssertTy(ref c_ty, ref local) => {
c_ty.hash_stable(hcx, hasher);
local.hash_stable(hcx, hasher);
}
mir::StatementKind::Nop => {}
mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
asm.hash_stable(hcx, hasher);
Expand Down
29 changes: 21 additions & 8 deletions src/librustc/infer/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

use infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TypeVariableOrigin};
use rustc_data_structures::indexed_vec::Idx;
use serialize::UseSpecializedDecodable;
use std::fmt::Debug;
use std::ops::Index;
use syntax::codemap::Span;
Expand All @@ -49,14 +50,16 @@ use rustc_data_structures::fx::FxHashMap;
/// A "canonicalized" type `V` is one where all free inference
/// variables have been rewriten to "canonical vars". These are
/// numbered starting from 0 in order of first appearance.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct Canonical<'gcx, V> {
pub variables: CanonicalVarInfos<'gcx>,
pub value: V,
}

pub type CanonicalVarInfos<'gcx> = &'gcx Slice<CanonicalVarInfo>;

impl<'gcx> UseSpecializedDecodable for CanonicalVarInfos<'gcx> { }

/// A set of values corresponding to the canonical variables from some
/// `Canonical`. You can give these values to
/// `canonical_value.substitute` to substitute them into the canonical
Expand All @@ -69,7 +72,7 @@ pub type CanonicalVarInfos<'gcx> = &'gcx Slice<CanonicalVarInfo>;
/// You can also use `infcx.fresh_inference_vars_for_canonical_vars`
/// to get back a `CanonicalVarValues` containing fresh inference
/// variables.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct CanonicalVarValues<'tcx> {
pub var_values: IndexVec<CanonicalVar, Kind<'tcx>>,
}
Expand All @@ -78,15 +81,15 @@ pub struct CanonicalVarValues<'tcx> {
/// canonical value. This is sufficient information for code to create
/// a copy of the canonical value in some other inference context,
/// with fresh inference variables replacing the canonical values.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub struct CanonicalVarInfo {
pub kind: CanonicalVarKind,
}

/// Describes the "kind" of the canonical variable. This is a "kind"
/// in the type-theory sense of the term -- i.e., a "meta" type system
/// that analyzes type-like values.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub enum CanonicalVarKind {
/// Some kind of type inference variable.
Ty(CanonicalTyVarKind),
Expand All @@ -100,7 +103,7 @@ pub enum CanonicalVarKind {
/// 22.) can only be instantiated with integral/float types (e.g.,
/// usize or f32). In order to faithfully reproduce a type, we need to
/// know what set of types a given type variable can be unified with.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
pub enum CanonicalTyVarKind {
/// General type variable `?T` that can be unified with arbitrary types.
General,
Expand Down Expand Up @@ -855,11 +858,14 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'g
}

CloneTypeFoldableAndLiftImpls! {
::infer::canonical::Certainty,
::infer::canonical::CanonicalVarInfo,
::infer::canonical::CanonicalVarKind,
}

CloneTypeFoldableImpls! {
for <'tcx> {
::infer::canonical::Certainty,
::infer::canonical::CanonicalVarInfo,
::infer::canonical::CanonicalVarInfos<'tcx>,
::infer::canonical::CanonicalVarKind,
}
}

Expand All @@ -870,6 +876,13 @@ BraceStructTypeFoldableImpl! {
} where C: TypeFoldable<'tcx>
}

BraceStructLiftImpl! {
impl<'a, 'tcx, T> Lift<'tcx> for Canonical<'a, T> {
type Lifted = Canonical<'tcx, T::Lifted>;
variables, value
} where T: Lift<'tcx>
}

impl<'tcx> CanonicalVarValues<'tcx> {
fn iter<'a>(&'a self) -> impl Iterator<Item = Kind<'tcx>> + 'a {
self.var_values.iter().cloned()
Expand Down
22 changes: 21 additions & 1 deletion src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use hir::def_id::DefId;
use mir::visit::MirVisitable;
use mir::interpret::{Value, PrimVal};
use ty::subst::{Subst, Substs};
use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior};
use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use ty::TypeAndMut;
use util::ppaux;
Expand Down Expand Up @@ -1253,6 +1253,23 @@ pub enum StatementKind<'tcx> {
/// (The starting point(s) arise implicitly from borrows.)
EndRegion(region::Scope),

/// Encodes a user's type assertion. These need to be preserved intact so that NLL can respect
/// them. For example:
///
/// let (a, b): (T, U) = y;
///
/// Here we would insert a `UserAssertTy<(T, U)>(y)` instruction to check that the type of `y`
/// is the right thing.
///
/// `CanonicalTy` is used to capture "inference variables" from the user's types. For example:
///
/// let x: Vec<_> = ...;
/// let y: &u32 = ...;
///
/// would result in `Vec<?0>` and `&'?0 u32` respectively (where `?0` is a canonicalized
/// variable).
UserAssertTy(CanonicalTy<'tcx>, Local),

/// No-op. Useful for deleting instructions without affecting statement indices.
Nop,
}
Expand Down Expand Up @@ -1324,6 +1341,8 @@ impl<'tcx> Debug for Statement<'tcx> {
InlineAsm { ref asm, ref outputs, ref inputs } => {
write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs)
},
UserAssertTy(ref c_ty, ref local) => write!(fmt, "UserAssertTy({:?}, {:?})",
c_ty, local),
Nop => write!(fmt, "nop"),
}
}
Expand Down Expand Up @@ -2184,6 +2203,7 @@ EnumTypeFoldableImpl! {
(StatementKind::InlineAsm) { asm, outputs, inputs },
(StatementKind::Validate)(a, b),
(StatementKind::EndRegion)(a),
(StatementKind::UserAssertTy)(a, b),
(StatementKind::Nop),
}
}
Expand Down
20 changes: 19 additions & 1 deletion src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

use hir::def_id::DefId;
use ty::subst::Substs;
use ty::{ClosureSubsts, Region, Ty, GeneratorInterior};
use ty::{CanonicalTy, ClosureSubsts, Region, Ty, GeneratorInterior};
use mir::*;
use syntax_pos::Span;

Expand Down Expand Up @@ -144,6 +144,13 @@ macro_rules! make_mir_visitor {
self.super_operand(operand, location);
}

fn visit_user_assert_ty(&mut self,
c_ty: & $($mutability)* CanonicalTy<'tcx>,
local: & $($mutability)* Local,
location: Location) {
self.super_user_assert_ty(c_ty, local, location);
}

fn visit_place(&mut self,
place: & $($mutability)* Place<'tcx>,
context: PlaceContext<'tcx>,
Expand Down Expand Up @@ -376,6 +383,10 @@ macro_rules! make_mir_visitor {
self.visit_operand(input, location);
}
}
StatementKind::UserAssertTy(ref $($mutability)* c_ty,
ref $($mutability)* local) => {
self.visit_user_assert_ty(c_ty, local, location);
}
StatementKind::Nop => {}
}
}
Expand Down Expand Up @@ -619,6 +630,13 @@ macro_rules! make_mir_visitor {
}
}

fn super_user_assert_ty(&mut self,
_c_ty: & $($mutability)* CanonicalTy<'tcx>,
local: & $($mutability)* Local,
location: Location) {
self.visit_local(local, PlaceContext::Validate, location);
}

fn super_place(&mut self,
place: & $($mutability)* Place<'tcx>,
context: PlaceContext<'tcx>,
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1251,6 +1251,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"choose which RELRO level to use"),
nll: bool = (false, parse_bool, [UNTRACKED],
"run the non-lexical lifetimes MIR pass"),
disable_nll_user_type_assert: bool = (false, parse_bool, [UNTRACKED],
"disable user provided type assertion in NLL"),
trans_time_graph: bool = (false, parse_bool, [UNTRACKED],
"generate a graphical HTML report of time spent in trans and LLVM"),
thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
Expand Down
23 changes: 23 additions & 0 deletions src/librustc/ty/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// persisting to incr. comp. caches.

use hir::def_id::{DefId, CrateNum};
use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
use rustc_data_structures::fx::FxHashMap;
use rustc_serialize::{Decodable, Decoder, Encoder, Encodable, opaque};
use std::hash::Hash;
Expand Down Expand Up @@ -239,6 +240,19 @@ pub fn decode_existential_predicate_slice<'a, 'tcx, D>(decoder: &mut D)
.mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?)
}

#[inline]
pub fn decode_canonical_var_infos<'a, 'tcx, D>(decoder: &mut D)
-> Result<CanonicalVarInfos<'tcx>, D::Error>
where D: TyDecoder<'a, 'tcx>,
'tcx: 'a,
{
let len = decoder.read_usize()?;
let interned: Result<Vec<CanonicalVarInfo>, _> = (0..len).map(|_| Decodable::decode(decoder))
.collect();
Ok(decoder.tcx()
.intern_canonical_var_infos(interned?.as_slice()))
}

#[inline]
pub fn decode_const<'a, 'tcx, D>(decoder: &mut D)
-> Result<&'tcx ty::Const<'tcx>, D::Error>
Expand All @@ -262,6 +276,7 @@ macro_rules! implement_ty_decoder {
($DecoderName:ident <$($typaram:tt),*>) => {
mod __ty_decoder_impl {
use super::$DecoderName;
use $crate::infer::canonical::CanonicalVarInfos;
use $crate::ty;
use $crate::ty::codec::*;
use $crate::ty::subst::Substs;
Expand Down Expand Up @@ -364,6 +379,14 @@ macro_rules! implement_ty_decoder {
}
}

impl<$($typaram),*> SpecializedDecoder<CanonicalVarInfos<'tcx>>
for $DecoderName<$($typaram),*> {
fn specialized_decode(&mut self)
-> Result<CanonicalVarInfos<'tcx>, Self::Error> {
decode_canonical_var_infos(self)
}
}

impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::Const<'tcx>>
for $DecoderName<$($typaram),*> {
fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
Expand Down
40 changes: 40 additions & 0 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ use ty::layout::{LayoutDetails, TargetDataLayout};
use ty::maps;
use ty::steal::Steal;
use ty::BindingMode;
use ty::CanonicalTy;
use util::nodemap::{NodeMap, DefIdSet, ItemLocalMap};
use util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::accumulate_vec::AccumulateVec;
Expand Down Expand Up @@ -344,6 +345,10 @@ pub struct TypeckTables<'tcx> {
/// method calls, including those of overloaded operators.
type_dependent_defs: ItemLocalMap<Def>,

/// Stores the canonicalized types provided by the user. See also `UserAssertTy` statement in
/// MIR.
user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,

/// Stores the types for various nodes in the AST. Note that this table
/// is not guaranteed to be populated until after typeck. See
/// typeck::check::fn_ctxt for details.
Expand Down Expand Up @@ -420,6 +425,7 @@ impl<'tcx> TypeckTables<'tcx> {
TypeckTables {
local_id_root,
type_dependent_defs: ItemLocalMap(),
user_provided_tys: ItemLocalMap(),
node_types: ItemLocalMap(),
node_substs: ItemLocalMap(),
adjustments: ItemLocalMap(),
Expand Down Expand Up @@ -461,6 +467,20 @@ impl<'tcx> TypeckTables<'tcx> {
}
}

pub fn user_provided_tys(&self) -> LocalTableInContext<CanonicalTy<'tcx>> {
LocalTableInContext {
local_id_root: self.local_id_root,
data: &self.user_provided_tys
}
}

pub fn user_provided_tys_mut(&mut self) -> LocalTableInContextMut<CanonicalTy<'tcx>> {
LocalTableInContextMut {
local_id_root: self.local_id_root,
data: &mut self.user_provided_tys
}
}

pub fn node_types(&self) -> LocalTableInContext<Ty<'tcx>> {
LocalTableInContext {
local_id_root: self.local_id_root,
Expand Down Expand Up @@ -685,6 +705,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
let ty::TypeckTables {
local_id_root,
ref type_dependent_defs,
ref user_provided_tys,
ref node_types,
ref node_substs,
ref adjustments,
Expand All @@ -704,6 +725,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {

hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
type_dependent_defs.hash_stable(hcx, hasher);
user_provided_tys.hash_stable(hcx, hasher);
node_types.hash_stable(hcx, hasher);
node_substs.hash_stable(hcx, hasher);
adjustments.hash_stable(hcx, hasher);
Expand Down Expand Up @@ -1637,6 +1659,24 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice<Predicate<'a>> {
}
}

impl<'a, 'tcx> Lift<'tcx> for &'a Slice<CanonicalVarInfo> {
type Lifted = &'tcx Slice<CanonicalVarInfo>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
if self.len() == 0 {
return Some(Slice::empty());
}
if tcx.interners.arena.in_arena(*self as *const _) {
return Some(unsafe { mem::transmute(*self) });
}
// Also try in the global tcx if we're not that.
if !tcx.is_global() {
self.lift_to_tcx(tcx.global_tcx())
} else {
None
}
}
}

pub mod tls {
use super::{CtxtInterners, GlobalCtxt, TyCtxt};

Expand Down
12 changes: 12 additions & 0 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use hir::map::DefPathData;
use hir::svh::Svh;
use ich::Fingerprint;
use ich::StableHashingContext;
use infer::canonical::{Canonical, Canonicalize};
use middle::const_val::ConstVal;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::privacy::AccessLevels;
Expand Down Expand Up @@ -554,6 +555,17 @@ pub type Ty<'tcx> = &'tcx TyS<'tcx>;
impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {}
impl<'tcx> serialize::UseSpecializedDecodable for Ty<'tcx> {}

pub type CanonicalTy<'gcx> = Canonical<'gcx, Ty<'gcx>>;

impl <'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for Ty<'tcx> {
type Canonicalized = CanonicalTy<'gcx>;

fn intern(_gcx: TyCtxt<'_, 'gcx, 'gcx>,
value: Canonical<'gcx, Self::Lifted>) -> Self::Canonicalized {
value
}
}

/// A wrapper for slices with the additional invariant
/// that the slice is interned and no other slice with
/// the same contents can exist in the same context.
Expand Down
8 changes: 5 additions & 3 deletions src/librustc_mir/borrow_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,11 +392,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
// ignored when consuming results (update to
// flow_state already handled).
}
StatementKind::Nop | StatementKind::Validate(..) | StatementKind::StorageLive(..) => {
// `Nop`, `Validate`, and `StorageLive` are irrelevant
StatementKind::Nop |
StatementKind::UserAssertTy(..) |
StatementKind::Validate(..) |
StatementKind::StorageLive(..) => {
// `Nop`, `UserAssertTy`, `Validate`, and `StorageLive` are irrelevant
// to borrow check.
}

StatementKind::StorageDead(local) => {
self.access_place(
ContextKind::StorageDead.new(location),
Expand Down
Loading

0 comments on commit ab0ef14

Please sign in to comment.