-Subproject commit 36d65d00164d1750f6fa7f8b0f52dabc3fea500b
+Subproject commit f475da63a18d50217459a601cbef69a4bcac5e71
-Subproject commit 748a5e6742db4a21c4c630a58087f818828e8a0a
+Subproject commit 13e3745ca399118df05e8261e12e3ada6e616b48
-Subproject commit 134f419ee62714590b04712fe6072253bc2a7822
+Subproject commit 0f63519ea10c028f48b2dbf7d0a2454203b68b0b
-Subproject commit eebda16e4b45f2eed4310cf7b9872cc752278163
+Subproject commit d2a64395a5210a61d3512a3a5c615f5c47699443
Enum(DefId),
Variant(DefId),
Trait(DefId),
+ Existential(DefId),
TyAlias(DefId),
TyForeign(DefId),
TraitAlias(DefId),
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
Def::AssociatedConst(id) | Def::Macro(id, ..) |
+ Def::Existential(id) |
Def::GlobalAsm(id) | Def::TyForeign(id) => {
id
}
Def::VariantCtor(.., CtorKind::Const) => "unit variant",
Def::VariantCtor(.., CtorKind::Fictive) => "struct variant",
Def::Enum(..) => "enum",
+ Def::Existential(..) => "existential type",
Def::TyAlias(..) => "type alias",
Def::TraitAlias(..) => "trait alias",
Def::AssociatedTy(..) => "associated type",
visitor.visit_ty(typ);
visitor.visit_generics(type_parameters)
}
+ ItemExistential(ExistTy {ref generics, ref bounds, impl_trait_fn}) => {
+ visitor.visit_id(item.id);
+ walk_generics(visitor, generics);
+ walk_list!(visitor, visit_ty_param_bound, bounds);
+ if let Some(impl_trait_fn) = impl_trait_fn {
+ visitor.visit_def_mention(Def::Fn(impl_trait_fn))
+ }
+ }
ItemEnum(ref enum_definition, ref type_parameters) => {
visitor.visit_generics(type_parameters);
// visit_enum_def() takes care of visiting the Item's NodeId
}
visitor.visit_lifetime(lifetime);
}
- TyImplTraitExistential(ref existty, ref lifetimes) => {
- let ExistTy { ref generics, ref bounds } = *existty;
- walk_generics(visitor, generics);
- walk_list!(visitor, visit_ty_param_bound, bounds);
+ TyImplTraitExistential(item_id, def_id, ref lifetimes) => {
+ visitor.visit_def_mention(Def::Existential(def_id));
+ visitor.visit_nested_item(item_id);
walk_list!(visitor, visit_lifetime, lifetimes);
}
TyTypeof(ref expression) => {
/// Treat `impl Trait` as shorthand for a new universal existential parameter.
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
/// equivalent to a fresh existential parameter like `abstract type T; fn foo() -> T`.
- Existential,
+ ///
+ /// We store a DefId here so we can look up necessary information later
+ Existential(DefId),
/// `impl Trait` is not accepted in this position.
Disallowed,
Optional,
}
+#[derive(Debug)]
struct LoweredNodeId {
node_id: NodeId,
hir_id: hir::HirId,
}
}
- fn with_hir_id_owner<F>(&mut self, owner: NodeId, f: F)
+ fn with_hir_id_owner<F, T>(&mut self, owner: NodeId, f: F) -> T
where
- F: FnOnce(&mut Self),
+ F: FnOnce(&mut Self) -> T,
{
let counter = self.item_local_id_counters
.insert(owner, HIR_ID_COUNTER_LOCKED)
.unwrap();
let def_index = self.resolver.definitions().opt_def_index(owner).unwrap();
self.current_hir_id_owner.push((def_index, counter));
- f(self);
+ let ret = f(self);
let (new_def_index, new_counter) = self.current_hir_id_owner.pop().unwrap();
debug_assert!(def_index == new_def_index);
.insert(owner, new_counter)
.unwrap();
debug_assert!(prev == HIR_ID_COUNTER_LOCKED);
+ ret
}
/// This method allocates a new HirId for the given NodeId and stores it in
fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> LoweredNodeId {
self.lower_node_id_generic(ast_node_id, |this| {
- let local_id_counter = this.item_local_id_counters.get_mut(&owner).unwrap();
+ let local_id_counter = this
+ .item_local_id_counters
+ .get_mut(&owner)
+ .expect("called lower_node_id_with_owner before allocate_hir_id_counter");
let local_id = *local_id_counter;
// We want to be sure not to modify the counter in the map while it
debug_assert!(local_id != HIR_ID_COUNTER_LOCKED);
*local_id_counter += 1;
- let def_index = this.resolver.definitions().opt_def_index(owner).unwrap();
+ let def_index = this
+ .resolver
+ .definitions()
+ .opt_def_index(owner)
+ .expect("You forgot to call `create_def_with_parent` or are lowering node ids \
+ that do not belong to the current owner");
hir::HirId {
owner: def_index,
TyKind::ImplTrait(ref bounds) => {
let span = t.span;
match itctx {
- ImplTraitContext::Existential => {
- let def_index = self.resolver.definitions().opt_def_index(t.id).unwrap();
- let hir_bounds = self.lower_bounds(bounds, itctx);
- let (lifetimes, lifetime_defs) =
- self.lifetimes_from_impl_trait_bounds(def_index, &hir_bounds);
+ ImplTraitContext::Existential(fn_def_id) => {
+
+ // We need to manually repeat the code of `next_id` because the lowering
+ // needs to happen while the owner_id is pointing to the item itself,
+ // because items are their own owners
+ let exist_ty_node_id = self.sess.next_node_id();
+
+ // Make sure we know that some funky desugaring has been going on here.
+ // This is a first: there is code in other places like for loop
+ // desugaring that explicitly states that we don't want to track that.
+ // Not tracking it makes lints in rustc and clippy very fragile as
+ // frequently opened issues show.
+ let exist_ty_span = self.allow_internal_unstable(
+ CompilerDesugaringKind::ExistentialReturnType,
+ t.span,
+ );
- hir::TyImplTraitExistential(
- hir::ExistTy {
+ // Pull a new definition from the ether
+ let exist_ty_def_index = self
+ .resolver
+ .definitions()
+ .create_def_with_parent(
+ fn_def_id.index,
+ exist_ty_node_id,
+ DefPathData::ExistentialImplTrait,
+ DefIndexAddressSpace::High,
+ Mark::root(),
+ exist_ty_span,
+ );
+
+ // the `t` is just for printing debug messages
+ self.allocate_hir_id_counter(exist_ty_node_id, t);
+
+ let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, |lctx| {
+ lctx.lower_bounds(bounds, itctx)
+ });
+
+ let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
+ exist_ty_node_id,
+ exist_ty_def_index,
+ &hir_bounds,
+ );
+
+ self.with_hir_id_owner(exist_ty_node_id, |lctx| {
+ let exist_ty_item_kind = hir::ItemExistential(hir::ExistTy {
generics: hir::Generics {
params: lifetime_defs,
where_clause: hir::WhereClause {
- id: self.next_id().node_id,
+ id: lctx.next_id().node_id,
predicates: Vec::new().into(),
},
span,
},
bounds: hir_bounds,
- },
- lifetimes,
- )
+ impl_trait_fn: Some(fn_def_id),
+ });
+ let exist_ty_id = lctx.lower_node_id(exist_ty_node_id);
+ // Generate an `existential type Foo: Trait;` declaration
+ trace!("creating existential type with id {:#?}", exist_ty_id);
+ // Set the name to `impl Bound1 + Bound2`
+ let exist_ty_name = Symbol::intern(&pprust::ty_to_string(t));
+
+ trace!("exist ty def index: {:#?}", exist_ty_def_index);
+ let exist_ty_item = hir::Item {
+ id: exist_ty_id.node_id,
+ hir_id: exist_ty_id.hir_id,
+ name: exist_ty_name,
+ attrs: Default::default(),
+ node: exist_ty_item_kind,
+ vis: hir::Visibility::Inherited,
+ span: exist_ty_span,
+ };
+
+ // Insert the item into the global list. This usually happens
+ // automatically for all AST items. But this existential type item
+ // does not actually exist in the AST.
+ lctx.items.insert(exist_ty_id.node_id, exist_ty_item);
+
+ // `impl Trait` now just becomes `Foo<'a, 'b, ..>`
+ hir::TyImplTraitExistential(
+ hir::ItemId {
+ id: exist_ty_id.node_id
+ },
+ DefId::local(exist_ty_def_index),
+ lifetimes,
+ )
+ })
}
ImplTraitContext::Universal(def_id) => {
let def_node_id = self.next_id().node_id;
let def_index = self.resolver.definitions().create_def_with_parent(
def_id.index,
def_node_id,
- DefPathData::ImplTrait,
+ DefPathData::UniversalImplTrait,
DefIndexAddressSpace::High,
Mark::root(),
span,
fn lifetimes_from_impl_trait_bounds(
&mut self,
+ exist_ty_id: NodeId,
parent_index: DefIndex,
bounds: &hir::TyParamBounds,
) -> (HirVec<hir::Lifetime>, HirVec<hir::GenericParam>) {
struct ImplTraitLifetimeCollector<'r, 'a: 'r> {
context: &'r mut LoweringContext<'a>,
parent: DefIndex,
+ exist_ty_id: NodeId,
collect_elided_lifetimes: bool,
currently_bound_lifetimes: Vec<hir::LifetimeName>,
already_defined_lifetimes: HashSet<hir::LifetimeName>,
name,
});
- let def_node_id = self.context.next_id().node_id;
+ // We need to manually create the ids here, because the
+ // definitions will go into the explicit `existential type`
+ // declaration and thus need to have their owner set to that item
+ let def_node_id = self.context.sess.next_node_id();
+ let _ = self.context.lower_node_id_with_owner(def_node_id, self.exist_ty_id);
self.context.resolver.definitions().create_def_with_parent(
self.parent,
def_node_id,
let def_lifetime = hir::Lifetime {
id: def_node_id,
span: lifetime.span,
- name: name,
+ name,
};
self.output_lifetime_params
.push(hir::GenericParam::Lifetime(hir::LifetimeDef {
let mut lifetime_collector = ImplTraitLifetimeCollector {
context: self,
parent: parent_index,
+ exist_ty_id,
collect_elided_lifetimes: true,
currently_bound_lifetimes: Vec::new(),
already_defined_lifetimes: HashSet::new(),
.collect(),
output: match decl.output {
FunctionRetTy::Ty(ref ty) => match fn_def_id {
- Some(_) if impl_trait_return_allow => {
- hir::Return(self.lower_ty(ty, ImplTraitContext::Existential))
+ Some(def_id) if impl_trait_return_allow => {
+ hir::Return(self.lower_ty(ty, ImplTraitContext::Existential(def_id)))
}
_ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
},
debug!("visit_item: {:?}", i);
// Pick the def data. This need not be unique, but the more
- // information we encapsulate into
+ // information we encapsulate into, the better
let def_data = match i.node {
ItemKind::Impl(..) => DefPathData::Impl,
ItemKind::Trait(..) => DefPathData::Trait(i.ident.name.as_interned_str()),
fn visit_ty(&mut self, ty: &'a Ty) {
match ty.node {
TyKind::Mac(..) => return self.visit_macro_invoc(ty.id),
- TyKind::ImplTrait(..) => {
- self.create_def(ty.id, DefPathData::ImplTrait, REGULAR_SPACE, ty.span);
- }
_ => {}
}
visit::walk_ty(self, ty);
} = self.disambiguated_data;
::std::mem::discriminant(data).hash(&mut hasher);
- match *data {
- DefPathData::TypeNs(name) |
- DefPathData::Trait(name) |
- DefPathData::AssocTypeInTrait(name) |
- DefPathData::AssocTypeInImpl(name) |
- DefPathData::ValueNs(name) |
- DefPathData::Module(name) |
- DefPathData::MacroDef(name) |
- DefPathData::TypeParam(name) |
- DefPathData::LifetimeDef(name) |
- DefPathData::EnumVariant(name) |
- DefPathData::Field(name) |
- DefPathData::GlobalMetaData(name) => {
- name.hash(&mut hasher);
- }
-
- DefPathData::Impl |
- DefPathData::CrateRoot |
- DefPathData::Misc |
- DefPathData::ClosureExpr |
- DefPathData::StructCtor |
- DefPathData::AnonConst |
- DefPathData::ImplTrait => {}
- };
+ if let Some(name) = data.get_opt_name() {
+ name.hash(&mut hasher);
+ }
disambiguator.hash(&mut hasher);
StructCtor,
/// A constant expression (see {ast,hir}::AnonConst).
AnonConst,
- /// An `impl Trait` type node.
- ImplTrait,
+ /// An `impl Trait` type node in argument position.
+ UniversalImplTrait,
+ /// An `impl Trait` type node in return position.
+ ExistentialImplTrait,
/// GlobalMetaData identifies a piece of crate metadata that is global to
/// a whole crate (as opposed to just one item). GlobalMetaData components
ClosureExpr |
StructCtor |
AnonConst |
- ImplTrait => None
+ ExistentialImplTrait |
+ UniversalImplTrait => None
}
}
ClosureExpr => "{{closure}}",
StructCtor => "{{constructor}}",
AnonConst => "{{constant}}",
- ImplTrait => "{{impl-Trait}}",
+ ExistentialImplTrait => "{{exist-impl-Trait}}",
+ UniversalImplTrait => "{{univ-impl-Trait}}",
};
Symbol::intern(s).as_interned_str()
.keys()
.map(|local_id| local_id.as_usize())
.max()
- .unwrap();
+ .expect("owning item has no entry");
if max != self.hir_ids_seen.len() - 1 {
// Collect the missing ItemLocalIds
local_id: ItemLocalId(local_id as u32),
};
+ trace!("missing hir id {:#?}", hir_id);
+
// We are already in ICE mode here, so doing a linear search
// should be fine.
let (node_id, _) = self.hir_map
.iter()
.enumerate()
.find(|&(_, &entry)| hir_id == entry)
- .unwrap();
+ .expect("no node_to_hir_id entry");
let node_id = NodeId::new(node_id);
missing_items.push(format!("[local_id: {}, node:{}]",
local_id,
}
fn visit_id(&mut self, node_id: NodeId) {
- let owner = self.owner_def_index.unwrap();
+ let owner = self.owner_def_index.expect("no owner_def_index");
let stable_id = self.hir_map.definitions().node_to_hir_id[node_id];
if stable_id == hir::DUMMY_HIR_ID {
ItemFn(..) => Some(Def::Fn(def_id())),
ItemMod(..) => Some(Def::Mod(def_id())),
ItemGlobalAsm(..) => Some(Def::GlobalAsm(def_id())),
+ ItemExistential(..) => Some(Def::Existential(def_id())),
ItemTy(..) => Some(Def::TyAlias(def_id())),
ItemEnum(..) => Some(Def::Enum(def_id())),
ItemStruct(..) => Some(Def::Struct(def_id())),
/// Retrieve the NodeId for `id`'s parent item, or `id` itself if no
/// parent item is in this map. The "parent item" is the closest parent node
- /// in the AST which is recorded by the map and is an item, either an item
+ /// in the HIR which is recorded by the map and is an item, either an item
/// in a module, trait, or impl.
pub fn get_parent(&self, id: NodeId) -> NodeId {
match self.walk_parent_nodes(id, |node| match *node {
ItemForeignMod(..) => "foreign mod",
ItemGlobalAsm(..) => "global asm",
ItemTy(..) => "ty",
+ ItemExistential(..) => "existential",
ItemEnum(..) => "enum",
ItemStruct(..) => "struct",
ItemUnion(..) => "union",
pub struct ExistTy {
pub generics: Generics,
pub bounds: TyParamBounds,
+ pub impl_trait_fn: Option<DefId>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
/// An existentially quantified (there exists a type satisfying) `impl
/// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime.
///
- /// The `ExistTy` structure emulates an
- /// `abstract type Foo<'a, 'b>: MyTrait<'a, 'b>;`.
+ /// The `Item` is the generated
+ /// `existential type Foo<'a, 'b>: MyTrait<'a, 'b>;`.
///
/// The `HirVec<Lifetime>` is the list of lifetimes applied as parameters
/// to the `abstract type`, e.g. the `'c` and `'d` in `-> Foo<'c, 'd>`.
/// This list is only a list of lifetimes and not type parameters
/// because all in-scope type parameters are captured by `impl Trait`,
/// so they are resolved directly through the parent `Generics`.
- TyImplTraitExistential(ExistTy, HirVec<Lifetime>),
+ TyImplTraitExistential(ItemId, DefId, HirVec<Lifetime>),
/// Unused for now
TyTypeof(AnonConst),
/// TyInfer means the type should be inferred instead of it having been
ItemGlobalAsm(P<GlobalAsm>),
/// A type alias, e.g. `type Foo = Bar<u8>`
ItemTy(P<Ty>, Generics),
+ /// A type alias, e.g. `type Foo = Bar<u8>`
+ ItemExistential(ExistTy),
/// An enum definition, e.g. `enum Foo<A, B> {C<A>, D<B>}`
ItemEnum(EnumDef, Generics),
/// A struct definition, e.g. `struct Foo<A> {x: A}`
ItemForeignMod(..) => "foreign module",
ItemGlobalAsm(..) => "global asm",
ItemTy(..) => "type alias",
+ ItemExistential(..) => "existential type",
ItemEnum(..) => "enum",
ItemStruct(..) => "struct",
ItemUnion(..) => "union",
fn post(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> {
Ok(())
}
+ fn try_fetch_item(&self, _: ast::NodeId) -> Option<&hir::Item> {
+ None
+ }
}
pub struct NoAnn;
pub const NO_ANN: &'static dyn PpAnn = &NoAnn;
impl PpAnn for hir::Crate {
+ fn try_fetch_item(&self, item: ast::NodeId) -> Option<&hir::Item> {
+ Some(self.item(item))
+ }
fn nested(&self, state: &mut State, nested: Nested) -> io::Result<()> {
match nested {
Nested::Item(id) => state.print_item(self.item(id.id)),
self.print_lifetime(lifetime)?;
}
}
- hir::TyImplTraitExistential(ref existty, ref _lifetimes) => {
- self.print_bounds("impl", &existty.bounds[..])?;
+ hir::TyImplTraitExistential(hir_id, _def_id, ref _lifetimes) => {
+ match self.ann.try_fetch_item(hir_id.id).map(|it| &it.node) {
+ None => self.word_space("impl {{Trait}}")?,
+ Some(&hir::ItemExistential(ref exist_ty)) => {
+ self.print_bounds("impl", &exist_ty.bounds)?;
+ },
+ other => bug!("impl Trait pointed to {:#?}", other),
+ }
}
hir::TyArray(ref ty, ref length) => {
self.s.word("[")?;
self.s.word(";")?;
self.end()?; // end the outer ibox
}
+ hir::ItemExistential(ref exist) => {
+ self.ibox(indent_unit)?;
+ self.ibox(0)?;
+ self.word_nbsp(&visibility_qualified(&item.vis, "existential type"))?;
+ self.print_name(item.name)?;
+ self.print_generic_params(&exist.generics.params)?;
+ self.end()?; // end the inner ibox
+
+ self.print_where_clause(&exist.generics.where_clause)?;
+ self.s.space()?;
+ self.word_space(":")?;
+ let mut real_bounds = Vec::with_capacity(exist.bounds.len());
+ for b in exist.bounds.iter() {
+ if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
+ self.s.space()?;
+ self.word_space("for ?")?;
+ self.print_trait_ref(&ptr.trait_ref)?;
+ } else {
+ real_bounds.push(b.clone());
+ }
+ }
+ self.print_bounds(":", &real_bounds[..])?;
+ self.s.word(";")?;
+ self.end()?; // end the outer ibox
+ }
hir::ItemEnum(ref enum_definition, ref params) => {
self.print_enum_def(enum_definition, params, item.name, item.span, &item.vis)?;
}
impl_stable_hash_for!(struct hir::ExistTy {
generics,
+ impl_trait_fn,
bounds
});
TyTup(ts),
TyPath(qpath),
TyTraitObject(trait_refs, lifetime),
- TyImplTraitExistential(existty, lifetimes),
+ TyImplTraitExistential(existty, def_id, lifetimes),
TyTypeof(body_id),
TyErr,
TyInfer
ItemForeignMod(foreign_mod),
ItemGlobalAsm(global_asm),
ItemTy(ty, generics),
+ ItemExistential(exist),
ItemEnum(enum_def, generics),
ItemStruct(variant_data, generics),
ItemUnion(variant_data, generics),
Struct(def_id),
Union(def_id),
Enum(def_id),
+ Existential(def_id),
Variant(def_id),
Trait(def_id),
TyAlias(def_id),
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
DotFill,
QuestionMark,
+ ExistentialReturnType,
Catch
});
// except according to those terms.
use hir::def_id::DefId;
+use hir;
use infer::{self, InferCtxt, InferOk, TypeVariableOrigin};
use infer::outlives::free_region_map::FreeRegionRelations;
use rustc_data_structures::fx::FxHashMap;
// }
// ```
if let Some(anon_node_id) = tcx.hir.as_local_node_id(def_id) {
- let anon_parent_node_id = tcx.hir.get_parent(anon_node_id);
- let anon_parent_def_id = tcx.hir.local_def_id(anon_parent_node_id);
+ let anon_parent_def_id = match tcx.hir.expect_item(anon_node_id).node {
+ hir::ItemExistential(hir::ExistTy {
+ impl_trait_fn: Some(parent),
+ ..
+ }) => parent,
+ _ => {
+ let anon_parent_node_id = tcx.hir.get_parent(anon_node_id);
+ tcx.hir.local_def_id(anon_parent_node_id)
+ },
+ };
if self.parent_def_id == anon_parent_def_id {
return self.fold_anon_ty(ty, def_id, substs);
}
tcx: self.tcx,
bound_region: *br,
found_type: None,
- current_index: ty::DebruijnIndex::INNERMOST,
+ current_index: ty::INNERMOST,
};
nested_visitor.visit_ty(arg);
nested_visitor.found_type
{
for (a_br, a_r) in a_map {
if *a_r == r {
- return infcx.tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::INNERMOST,
- *a_br));
+ return infcx.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, *a_br));
}
}
span_bug!(
// trait checking, and all of the skolemized regions
// appear inside predicates, which always have
// binders, so this assert is satisfied.
- assert!(current_depth > ty::DebruijnIndex::INNERMOST);
+ assert!(current_depth > ty::INNERMOST);
// since leak-check passed, this skolemized region
// should only have incoming edges from variables
/// would wind up with a fresh stream of region variables that
/// have been equated but appear distinct.
unification_table: ut::UnificationTable<ut::InPlace<ty::RegionVid>>,
+
+ /// a flag set to true when we perform any unifications; this is used
+ /// to micro-optimize `take_and_reset_data`
+ any_unifications: bool,
}
pub type VarInfos = IndexVec<RegionVid, RegionVariableInfo>;
pub struct RegionSnapshot {
length: usize,
region_snapshot: ut::Snapshot<ut::InPlace<ty::RegionVid>>,
+ any_unifications: bool,
}
/// When working with skolemized regions, we often wish to find all of
bound_count: 0,
undo_log: Vec::new(),
unification_table: ut::UnificationTable::new(),
+ any_unifications: false,
}
}
bound_count: _,
undo_log: _,
unification_table,
+ any_unifications,
} = self;
// Clear the tables of (lubs, glbs), so that we will create
// un-unified" state. Note that when we unify `a` and `b`, we
// also insert `a <= b` and a `b <= a` edges, so the
// `RegionConstraintData` contains the relationship here.
- unification_table.reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid });
+ if *any_unifications {
+ unification_table.reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid });
+ *any_unifications = false;
+ }
mem::replace(data, RegionConstraintData::default())
}
RegionSnapshot {
length,
region_snapshot: self.unification_table.snapshot(),
+ any_unifications: self.any_unifications,
}
}
let c = self.undo_log.pop().unwrap();
assert!(c == OpenSnapshot);
self.unification_table.rollback_to(snapshot.region_snapshot);
+ self.any_unifications = snapshot.any_unifications;
}
fn rollback_undo_entry(&mut self, undo_entry: UndoLogEntry<'tcx>) {
if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) {
self.unification_table.union(sub, sup);
+ self.any_unifications = true;
}
}
}
// inherently and their children are already in the
// worklist, as determined by the privacy pass
hir::ItemExternCrate(_) | hir::ItemUse(..) |
+ hir::ItemExistential(..) |
hir::ItemTy(..) | hir::ItemStatic(..) |
hir::ItemMod(..) | hir::ItemForeignMod(..) |
hir::ItemImpl(..) | hir::ItemTrait(..) | hir::ItemTraitAlias(..) |
}
fn late(hir_map: &Map, def: &hir::LifetimeDef) -> (hir::LifetimeName, Region) {
- let depth = ty::DebruijnIndex::INNERMOST;
+ let depth = ty::INNERMOST;
let def_id = hir_map.local_def_id(def.lifetime.id);
let origin = LifetimeDefOrigin::from_is_in_band(def.in_band);
debug!(
fn late_anon(index: &Cell<u32>) -> Region {
let i = index.get();
index.set(i + 1);
- let depth = ty::DebruijnIndex::INNERMOST;
+ let depth = ty::INNERMOST;
Region::LateBoundAnon(depth, i)
}
};
self.with(scope, |_, this| intravisit::walk_item(this, item));
}
+ hir::ItemExistential(hir::ExistTy { impl_trait_fn: Some(_), .. }) => {
+ // currently existential type declarations are just generated from impl Trait
+ // items. doing anything on this node is irrelevant, as we currently don't need
+ // it.
+ }
hir::ItemTy(_, ref generics)
+ | hir::ItemExistential(hir::ExistTy { impl_trait_fn: None, ref generics, .. })
| hir::ItemEnum(_, ref generics)
| hir::ItemStruct(_, ref generics)
| hir::ItemUnion(_, ref generics)
};
self.with(scope, |_, this| this.visit_ty(&mt.ty));
}
- hir::TyImplTraitExistential(ref exist_ty, ref lifetimes) => {
+ hir::TyImplTraitExistential(item_id, _, ref lifetimes) => {
// Resolve the lifetimes that are applied to the existential type.
// These are resolved in the current scope.
// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
// `abstract type MyAnonTy<'b>: MyTrait<'b>;`
// ^ ^ this gets resolved in the scope of
// the exist_ty generics
- let hir::ExistTy {
- ref generics,
- ref bounds,
- } = *exist_ty;
+ let (generics, bounds) = match self.tcx.hir.expect_item(item_id.id).node {
+ hir::ItemExistential(hir::ExistTy{ ref generics, ref bounds, .. }) => (
+ generics,
+ bounds,
+ ),
+ ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i),
+ };
// We want to start our early-bound indices at the end of the parent scope,
// not including any parent `impl Trait`s.
.map(|(i, input)| {
let mut gather = GatherLifetimes {
map: self.map,
- outer_index: ty::DebruijnIndex::INNERMOST,
+ outer_index: ty::INNERMOST,
have_bound_regions: false,
lifetimes: FxHashSet(),
};
let generic_ty = self.tcx().type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx(), substs);
self.anon_depth += 1;
+ if concrete_ty == ty {
+ println!("generic_ty: {:#?}", generic_ty);
+ println!("substs {:#?}", substs);
+ }
+ assert_ne!(concrete_ty, ty, "infinite recursion");
let folded_ty = self.fold_ty(concrete_ty);
self.anon_depth -= 1;
folded_ty
/// its where clauses and parameter types. These are then
/// read-again by borrowck.
pub free_region_map: FreeRegionMap<'tcx>,
+
+ /// All the existential types that are restricted to concrete types
+ /// by this function
+ pub concrete_existential_types: FxHashMap<DefId, Ty<'tcx>>,
}
impl<'tcx> TypeckTables<'tcx> {
used_trait_imports: Lrc::new(DefIdSet()),
tainted_by_errors: false,
free_region_map: FreeRegionMap::new(),
+ concrete_existential_types: FxHashMap(),
}
}
ref used_trait_imports,
tainted_by_errors,
ref free_region_map,
+ ref concrete_existential_types,
} = *self;
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
used_trait_imports.hash_stable(hcx, hasher);
tainted_by_errors.hash_stable(hcx, hasher);
free_region_map.hash_stable(hcx, hasher);
+ concrete_existential_types.hash_stable(hcx, hasher);
})
}
}
fn new() -> FlagComputation {
FlagComputation {
flags: TypeFlags::empty(),
- outer_exclusive_binder: ty::DebruijnIndex::INNERMOST,
+ outer_exclusive_binder: ty::INNERMOST,
}
}
// a region binder, so subtract one from the region depth
// within when adding the depth to `self`.
let outer_exclusive_binder = computation.outer_exclusive_binder;
- if outer_exclusive_binder > ty::DebruijnIndex::INNERMOST {
+ if outer_exclusive_binder > ty::INNERMOST {
self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
} else {
// otherwise, this binder captures nothing
/// True if `self` has any late-bound regions that are either
/// bound by `binder` or bound by some binder outside of `binder`.
- /// If `binder` is `ty::DebruijnIndex::INNERMOST`, this indicates whether
+ /// If `binder` is `ty::INNERMOST`, this indicates whether
/// there are any late-bound regions that appear free.
fn has_regions_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
self.visit_with(&mut HasEscapingRegionsVisitor { outer_index: binder })
}
fn has_escaping_regions(&self) -> bool {
- self.has_regions_bound_at_or_above(ty::DebruijnIndex::INNERMOST)
+ self.has_regions_bound_at_or_above(ty::INNERMOST)
}
fn has_type_flags(&self, flags: TypeFlags) -> bool {
T: TypeFoldable<'tcx>,
{
value.visit_with(&mut RegionVisitor {
- outer_index: ty::DebruijnIndex::INNERMOST,
+ outer_index: ty::INNERMOST,
callback
});
/// ^ ^ ^ ^
/// | | | | here, would be shifted in 1
/// | | | here, would be shifted in 2
- /// | | here, would be INNTERMOST shifted in by 1
+ /// | | here, would be INNERMOST shifted in by 1
/// | here, initially, binder would be INNERMOST
/// ```
///
RegionFolder {
tcx,
skipped_regions,
- current_index: ty::DebruijnIndex::INNERMOST,
+ current_index: ty::INNERMOST,
fold_region_fn,
}
}
let mut counter = 0;
Binder::bind(self.replace_late_bound_regions(sig, |_| {
counter += 1;
- self.mk_region(ty::ReLateBound(ty::DebruijnIndex::INNERMOST, ty::BrAnon(counter)))
+ self.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(counter)))
}).0)
}
}
{
RegionReplacer {
tcx,
- current_index: ty::DebruijnIndex::INNERMOST,
+ current_index: ty::INNERMOST,
fld_r,
map: BTreeMap::default()
}
// that region should always use the INNERMOST
// debruijn index. Then we adjust it to the
// correct depth.
- assert_eq!(debruijn1, ty::DebruijnIndex::INNERMOST);
+ assert_eq!(debruijn1, ty::INNERMOST);
self.tcx.mk_region(ty::ReLateBound(debruijn, br))
} else {
region
impl LateBoundRegionsCollector {
fn new(just_constrained: bool) -> Self {
LateBoundRegionsCollector {
- current_index: ty::DebruijnIndex::INNERMOST,
+ current_index: ty::INNERMOST,
regions: FxHashSet(),
just_constrained,
}
data @ DefPathData::AnonConst |
data @ DefPathData::MacroDef(..) |
data @ DefPathData::ClosureExpr |
- data @ DefPathData::ImplTrait |
+ data @ DefPathData::ExistentialImplTrait |
+ data @ DefPathData::UniversalImplTrait |
data @ DefPathData::GlobalMetaData(..) => {
let parent_def_id = self.parent_def_id(def_id).unwrap();
self.push_item_path(buffer, parent_def_id);
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{self, Lrc, ParallelIterator, par_iter};
use std::slice;
use std::vec::IntoIter;
use std::mem;
use hir;
-pub use self::sty::{Binder, CanonicalVar, DebruijnIndex};
+pub use self::sty::{Binder, CanonicalVar, DebruijnIndex, INNERMOST};
pub use self::sty::{FnSig, GenSig, PolyFnSig, PolyGenSig};
pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
pub use self::sty::{ClosureSubsts, GeneratorSubsts, UpvarSubsts, TypeAndMut};
.map(move |&body_id| self.hir.body_owner_def_id(body_id))
}
+ pub fn par_body_owners<F: Fn(DefId) + sync::Sync + sync::Send>(self, f: F) {
+ par_iter(&self.hir.krate().body_ids).for_each(|&body_id| {
+ f(self.hir.body_owner_def_id(body_id))
+ });
+ }
+
pub fn expr_span(self, id: NodeId) -> Span {
match self.hir.find(id) {
Some(hir_map::NodeExpr(e)) => {
fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ParamEnv<'tcx> {
+
+ // The param_env of an existential type is its parent's param_env
+ if let Some(Def::Existential(_)) = tcx.describe_def(def_id) {
+ let parent = tcx.parent_def_id(def_id).expect("impl trait item w/o a parent");
+ return param_env(tcx, parent);
+ }
// Compute the bounds on Self and the type parameters.
let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx);
/// is the outer fn.
///
/// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, Copy, PartialOrd, Ord)]
-pub struct DebruijnIndex {
- /// We maintain the invariant that this is never 0. So 1 indicates
- /// the innermost binder.
- index: u32,
-}
+newtype_index!(DebruijnIndex
+ {
+ DEBUG_FORMAT = "DebruijnIndex({})",
+ const INNERMOST = 0,
+ });
pub type Region<'tcx> = &'tcx RegionKind;
}
impl DebruijnIndex {
- pub const INNERMOST: DebruijnIndex = DebruijnIndex { index: 0 };
-
/// Returns the resulting index when this value is moved into
/// `amount` number of new binders. So e.g. if you had
///
/// you would need to shift the index for `'a` into 1 new binder.
#[must_use]
pub const fn shifted_in(self, amount: u32) -> DebruijnIndex {
- DebruijnIndex { index: self.index + amount }
+ DebruijnIndex(self.0 + amount)
}
/// Update this index in place by shifting it "in" through
/// `amount` number of new binders.
#[must_use]
pub const fn shifted_out(self, amount: u32) -> DebruijnIndex {
- DebruijnIndex { index: self.index - amount }
+ DebruijnIndex(self.0 - amount)
}
/// Update in place by shifting out from `amount` binders.
/// bound by one of the binders we are shifting out of, that is an
/// error (and should fail an assertion failure).
pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self {
- self.shifted_out(to_binder.index - Self::INNERMOST.index)
+ self.shifted_out((to_binder.0 - INNERMOST.0) as u32)
}
}
-impl_stable_hash_for!(struct DebruijnIndex {
- index
-});
+impl_stable_hash_for!(tuple_struct DebruijnIndex { index });
/// Region utilities
impl RegionKind {
-> Option<ty::Binder<Ty<'tcx>>>
{
let closure_ty = self.mk_closure(closure_def_id, closure_substs);
- let env_region = ty::ReLateBound(ty::DebruijnIndex::INNERMOST, ty::BrEnv);
+ let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self);
let closure_kind = closure_kind_ty.to_opt_closure_kind()?;
let env_ty = match closure_kind {
DefPathData::Field(_) |
DefPathData::StructCtor |
DefPathData::AnonConst |
- DefPathData::ImplTrait |
+ DefPathData::ExistentialImplTrait |
+ DefPathData::UniversalImplTrait |
DefPathData::GlobalMetaData(_) => {
// if we're making a symbol for something, there ought
// to be a value or type-def or something in there
ty::BrNamed(tcx.hir.local_def_id(CRATE_NODE_ID), name)
}
};
- tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::INNERMOST, br))
+ tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br))
}).0;
start_or_continue(f, "", "> ")?;
pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>;
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
- for body_owner_def_id in tcx.body_owners() {
+ tcx.par_body_owners(|body_owner_def_id| {
tcx.borrowck(body_owner_def_id);
- }
+ });
}
pub fn provide(providers: &mut Providers) {
#![feature(from_ref)]
#![feature(quote)]
+#![recursion_limit="256"]
+
#[macro_use] extern crate log;
extern crate syntax;
extern crate syntax_pos;
let tcx = cx.tcx;
let sig = substs.poly_sig(def_id, cx.tcx);
- let env_region = ty::ReLateBound(ty::DebruijnIndex::INNERMOST, ty::BrEnv);
+ let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
sig.map_bound(|sig| {
IndexVec { raw: Vec::new(), _marker: PhantomData }
}
+ #[inline]
+ pub fn from_raw(raw: Vec<T>) -> Self {
+ IndexVec { raw, _marker: PhantomData }
+ }
+
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
IndexVec { raw: Vec::with_capacity(capacity), _marker: PhantomData }
//!
//! `MTLock` is a mutex which disappears if cfg!(parallel_queries) is false.
//!
+//! `MTRef` is a immutable refernce if cfg!(parallel_queries), and an mutable reference otherwise.
+//!
//! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send + Sync
//! depending on the value of cfg!(parallel_queries).
}
}
+ pub type MTRef<'a, T> = &'a mut T;
+
#[derive(Debug)]
pub struct MTLock<T>(T);
}
#[inline(always)]
- pub fn borrow(&self) -> &T {
- &self.0
- }
-
- #[inline(always)]
- pub fn borrow_mut(&self) -> &T {
- &self.0
+ pub fn lock_mut(&mut self) -> &mut T {
+ &mut self.0
}
}
pub use std::sync::Arc as Lrc;
pub use std::sync::Weak as Weak;
- pub use self::Lock as MTLock;
+ pub type MTRef<'a, T> = &'a T;
+
+ #[derive(Debug)]
+ pub struct MTLock<T>(Lock<T>);
+
+ impl<T> MTLock<T> {
+ #[inline(always)]
+ pub fn new(inner: T) -> Self {
+ MTLock(Lock::new(inner))
+ }
+
+ #[inline(always)]
+ pub fn into_inner(self) -> T {
+ self.0.into_inner()
+ }
+
+ #[inline(always)]
+ pub fn get_mut(&mut self) -> &mut T {
+ self.0.get_mut()
+ }
+
+ #[inline(always)]
+ pub fn lock(&self) -> LockGuard<T> {
+ self.0.lock()
+ }
+
+ #[inline(always)]
+ pub fn lock_mut(&self) -> LockGuard<T> {
+ self.lock()
+ }
+ }
use parking_lot::Mutex as InnerLock;
use parking_lot::RwLock as InnerRwLock;
time(sess, "borrow checking", || borrowck::check_crate(tcx));
- time(sess, "MIR borrow checking", || {
- for def_id in tcx.body_owners() {
- tcx.mir_borrowck(def_id);
- }
- });
+ time(sess,
+ "MIR borrow checking",
+ || tcx.par_body_owners(|def_id| { tcx.mir_borrowck(def_id); }));
time(sess, "dumping chalk-like clauses", || {
rustc_traits::lowering::dump_program_clauses(tcx);
});
}
-const D1: ty::DebruijnIndex = ty::DebruijnIndex::INNERMOST;
+const D1: ty::DebruijnIndex = ty::INNERMOST;
const D2: ty::DebruijnIndex = D1.shifted_in(1);
impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
hir::ItemFn(..) |
hir::ItemForeignMod(..) |
hir::ItemGlobalAsm(..) |
+ hir::ItemExistential(..) |
hir::ItemTy(..) => None,
hir::ItemEnum(..) |
#![feature(fs_read_write)]
#![feature(specialization)]
+#![recursion_limit="256"]
+
extern crate graphviz;
#[macro_use] extern crate rustc;
extern crate rustc_data_structures;
use rustc::ty::TyCtxt;
use rustc::util::common::time;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::join;
use rustc_serialize::Encodable as RustcEncodable;
use rustc_serialize::opaque::Encoder;
use std::io::{self, Cursor};
return;
}
- time(sess, "persist query result cache", || {
- save_in(sess,
- query_cache_path(sess),
- |e| encode_query_cache(tcx, e));
- });
+ let query_cache_path = query_cache_path(sess);
+ let dep_graph_path = dep_graph_path(sess);
- if tcx.sess.opts.debugging_opts.incremental_queries {
+ join(move || {
+ if tcx.sess.opts.debugging_opts.incremental_queries {
+ time(sess, "persist query result cache", || {
+ save_in(sess,
+ query_cache_path,
+ |e| encode_query_cache(tcx, e));
+ });
+ }
+ }, || {
time(sess, "persist dep-graph", || {
save_in(sess,
- dep_graph_path(sess),
+ dep_graph_path,
|e| {
time(sess, "encode dep-graph", || {
encode_dep_graph(tcx, e)
})
});
});
- }
+ });
dirty_clean::check_dirty_clean_annotations(tcx);
})
EntryKind::ForeignFn(_) => Def::Fn(did),
EntryKind::Method(_) => Def::Method(did),
EntryKind::Type => Def::TyAlias(did),
+ EntryKind::Existential => Def::Existential(did),
EntryKind::AssociatedType(_) => Def::AssociatedTy(did),
EntryKind::Mod(_) => Def::Mod(did),
EntryKind::Variant(_) => Def::Variant(did),
hir::ItemForeignMod(_) => EntryKind::ForeignMod,
hir::ItemGlobalAsm(..) => EntryKind::GlobalAsm,
hir::ItemTy(..) => EntryKind::Type,
+ hir::ItemExistential(..) => EntryKind::Existential,
hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)),
hir::ItemStruct(ref struct_def, _) => {
let variant = tcx.adt_def(def_id).non_enum_variant();
hir::ItemConst(..) |
hir::ItemFn(..) |
hir::ItemTy(..) |
+ hir::ItemExistential(..) |
hir::ItemEnum(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemImpl(..) |
+ hir::ItemExistential(..) |
hir::ItemTrait(..) => Some(self.encode_generics(def_id)),
_ => None,
},
hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemImpl(..) |
+ hir::ItemExistential(..) |
hir::ItemTrait(..) => Some(self.encode_predicates(def_id)),
_ => None,
},
}
}
- fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> {
- debug!("IsolatedEncoder::encode_info_for_anon_ty({:?})", def_id);
- let tcx = self.tcx;
- Entry {
- kind: EntryKind::Type,
- visibility: self.lazy(&ty::Visibility::Public),
- span: self.lazy(&tcx.def_span(def_id)),
- attributes: LazySeq::empty(),
- children: LazySeq::empty(),
- stability: None,
- deprecation: None,
-
- ty: Some(self.encode_item_type(def_id)),
- inherent_impls: LazySeq::empty(),
- variances: LazySeq::empty(),
- generics: Some(self.encode_generics(def_id)),
- predicates: Some(self.encode_predicates(def_id)),
-
- mir: None,
- }
- }
-
fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> {
debug!("IsolatedEncoder::encode_info_for_closure({:?})", def_id);
let tcx = self.tcx;
fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
match ty.node {
- hir::TyImplTraitExistential(..) => {
- let def_id = self.tcx.hir.local_def_id(ty.id);
- self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id);
- }
hir::TyArray(_, ref length) => {
let def_id = self.tcx.hir.local_def_id(length.id);
self.record(def_id, IsolatedEncoder::encode_info_for_anon_const, def_id);
hir::ItemExternCrate(..) |
hir::ItemUse(..) |
hir::ItemTy(..) |
+ hir::ItemExistential(..) |
hir::ItemTraitAlias(..) => {
// no sub-item recording needed in these cases
}
ForeignType,
GlobalAsm,
Type,
+ Existential,
Enum(ReprOptions),
Field,
Variant(Lazy<VariantData<'tcx>>),
EntryKind::GlobalAsm |
EntryKind::ForeignType |
EntryKind::Field |
+ EntryKind::Existential |
EntryKind::Type => {
// Nothing else to hash here.
}
use borrow_check::borrow_set::BorrowSet;
use borrow_check::location::LocationTable;
use borrow_check::nll::facts::AllFacts;
+use borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
+use borrow_check::nll::ToRegionVid;
use rustc::hir;
use rustc::infer::InferCtxt;
use rustc::mir::visit::TyContext;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::Substs;
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts};
-
-use super::region_infer::{Cause, RegionInferenceContext};
-use super::ToRegionVid;
+use std::iter;
pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
location_table: &LocationTable,
mir: &Mir<'tcx>,
borrow_set: &BorrowSet<'tcx>,
+ liveness_set_from_typeck: &[(ty::Region<'tcx>, Location, Cause)],
) {
let mut cg = ConstraintGeneration {
borrow_set,
mir,
};
+ cg.add_region_liveness_constraints_from_type_check(liveness_set_from_typeck);
+
for (bb, data) in mir.basic_blocks().iter_enumerated() {
cg.visit_basic_block_data(bb, data);
}
self.add_reborrow_constraint(location, region, borrowed_place);
}
- _ => { }
+ _ => {}
}
self.super_rvalue(rvalue, location);
}
impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
+ /// The MIR type checker generates region liveness constraints
+ /// that we also have to respect.
+ fn add_region_liveness_constraints_from_type_check(
+ &mut self,
+ liveness_set: &[(ty::Region<'tcx>, Location, Cause)],
+ ) {
+ debug!(
+ "add_region_liveness_constraints_from_type_check(liveness_set={} items)",
+ liveness_set.len(),
+ );
+
+ let ConstraintGeneration {
+ regioncx,
+ location_table,
+ all_facts,
+ ..
+ } = self;
+
+ for (region, location, cause) in liveness_set {
+ debug!("generate: {:#?} is live at {:#?}", region, location);
+ let region_vid = regioncx.to_region_vid(region);
+ regioncx.add_live_point(region_vid, *location, &cause);
+ }
+
+ if let Some(all_facts) = all_facts {
+ all_facts
+ .region_live_at
+ .extend(liveness_set.into_iter().flat_map(|(region, location, _)| {
+ let r = regioncx.to_region_vid(region);
+ let p1 = location_table.start_index(*location);
+ let p2 = location_table.mid_index(*location);
+ iter::once((r, p1)).chain(iter::once((r, p2)))
+ }));
+ }
+ }
+
/// 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
use borrow_check::borrow_set::BorrowSet;
use borrow_check::location::{LocationIndex, LocationTable};
use borrow_check::nll::facts::AllFactsExt;
+use borrow_check::nll::type_check::MirTypeckRegionConstraints;
use dataflow::indexes::BorrowIndex;
use dataflow::move_paths::MoveData;
use dataflow::FlowAtLocation;
mod invalidation;
crate mod region_infer;
mod renumber;
-mod subtype_constraint_generation;
crate mod type_check;
mod universal_regions;
Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
Option<ClosureRegionRequirements<'gcx>>,
) {
+ let mut all_facts = if infcx.tcx.sess.opts.debugging_opts.nll_facts
+ || infcx.tcx.sess.opts.debugging_opts.polonius
+ {
+ Some(AllFacts::default())
+ } else {
+ None
+ };
+
// Run the MIR type-checker.
let liveness = &LivenessResults::compute(mir);
- let constraint_sets = &type_check::type_check(
+ let constraint_sets = type_check::type_check(
infcx,
param_env,
mir,
def_id,
&universal_regions,
+ location_table,
&liveness,
+ &mut all_facts,
flow_inits,
move_data,
);
- let mut all_facts = if infcx.tcx.sess.opts.debugging_opts.nll_facts
- || infcx.tcx.sess.opts.debugging_opts.polonius
- {
- Some(AllFacts::default())
- } else {
- None
- };
-
if let Some(all_facts) = &mut all_facts {
all_facts
.universal_region
.extend(universal_regions.universal_regions());
}
- // Create the region inference context, taking ownership of the region inference
- // data that was contained in `infcx`.
+ // Create the region inference context, taking ownership of the
+ // region inference data that was contained in `infcx`, and the
+ // base constraints generated by the type-check.
let var_origins = infcx.take_region_var_origins();
- let mut regioncx = RegionInferenceContext::new(var_origins, universal_regions, mir);
-
- // Generate various constraints.
- subtype_constraint_generation::generate(
- &mut regioncx,
- &mut all_facts,
- location_table,
+ let MirTypeckRegionConstraints {
+ liveness_set,
+ outlives_constraints,
+ type_tests,
+ } = constraint_sets;
+ let mut regioncx = RegionInferenceContext::new(
+ var_origins,
+ universal_regions,
mir,
- constraint_sets,
+ outlives_constraints,
+ type_tests,
);
+
+ // Generate various additional constraints.
constraint_generation::generate_constraints(
infcx,
&mut regioncx,
location_table,
&mir,
borrow_set,
+ &liveness_set,
);
invalidation::generate_invalidates(
infcx,
//! context internal state.
use std::io::{self, Write};
-use super::{Constraint, RegionInferenceContext};
+use super::{OutlivesConstraint, RegionInferenceContext};
// Room for "'_#NNNNr" before things get misaligned.
// Easy enough to fix if this ever doesn't seem like
let mut constraints: Vec<_> = self.constraints.iter().collect();
constraints.sort();
for constraint in &constraints {
- let Constraint {
+ let OutlivesConstraint {
sup,
sub,
point,
impl<'this, 'tcx> dot::Labeller<'this> for RegionInferenceContext<'tcx> {
type Node = RegionVid;
- type Edge = Constraint;
+ type Edge = OutlivesConstraint;
fn graph_id(&'this self) -> dot::Id<'this> {
dot::Id::new(format!("RegionInferenceContext")).unwrap()
fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> {
dot::LabelText::LabelStr(format!("{:?}", n).into_cow())
}
- fn edge_label(&'this self, e: &Constraint) -> dot::LabelText<'this> {
+ fn edge_label(&'this self, e: &OutlivesConstraint) -> dot::LabelText<'this> {
dot::LabelText::LabelStr(format!("{:?}", e.point).into_cow())
}
}
impl<'this, 'tcx> dot::GraphWalk<'this> for RegionInferenceContext<'tcx> {
type Node = RegionVid;
- type Edge = Constraint;
+ type Edge = OutlivesConstraint;
fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> {
let vids: Vec<RegionVid> = self.definitions.indices().collect();
vids.into_cow()
}
- fn edges(&'this self) -> dot::Edges<'this, Constraint> {
+ fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint> {
(&self.constraints.raw[..]).into_cow()
}
// Render `a: b` as `a <- b`, indicating the flow
// of data during inference.
- fn source(&'this self, edge: &Constraint) -> RegionVid {
+ fn source(&'this self, edge: &OutlivesConstraint) -> RegionVid {
edge.sub
}
- fn target(&'this self, edge: &Constraint) -> RegionVid {
+ fn target(&'this self, edge: &OutlivesConstraint) -> RegionVid {
edge.sup
}
}
dependency_map: Option<IndexVec<RegionVid, Option<ConstraintIndex>>>,
/// The constraints we have accumulated and used during solving.
- constraints: IndexVec<ConstraintIndex, Constraint>,
+ constraints: IndexVec<ConstraintIndex, OutlivesConstraint>,
/// Type constraints that we check after solving.
type_tests: Vec<TypeTest<'tcx>>,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct Constraint {
+pub struct OutlivesConstraint {
// NB. The ordering here is not significant for correctness, but
// it is for convenience. Before we dump the constraints in the
// debugging logs, we sort them, and we'd like the "super region"
// to be first, etc. (In particular, span should remain last.)
/// The region SUP must outlive SUB...
- sup: RegionVid,
+ pub sup: RegionVid,
/// Region that must be outlived.
- sub: RegionVid,
+ pub sub: RegionVid,
/// At this location.
- point: Location,
+ pub point: Location,
/// Later on, we thread the constraints onto a linked list
/// grouped by their `sub` field. So if you had:
/// 0 | `'a: 'b` | Some(2)
/// 1 | `'b: 'c` | None
/// 2 | `'c: 'b` | None
- next: Option<ConstraintIndex>,
+ pub next: Option<ConstraintIndex>,
/// Where did this constraint arise?
- span: Span,
+ pub span: Span,
}
newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" });
/// `num_region_variables` valid inference variables; the first N
/// of those will be constant regions representing the free
/// regions defined in `universal_regions`.
+ ///
+ /// The `outlives_constraints` and `type_tests` are an initial set
+ /// of constraints produced by the MIR type check.
pub(crate) fn new(
var_infos: VarInfos,
universal_regions: UniversalRegions<'tcx>,
mir: &Mir<'tcx>,
+ outlives_constraints: Vec<OutlivesConstraint>,
+ type_tests: Vec<TypeTest<'tcx>>,
) -> Self {
+ // The `next` field should not yet have been initialized:
+ debug_assert!(outlives_constraints.iter().all(|c| c.next.is_none()));
+
let num_region_variables = var_infos.len();
let num_universal_regions = universal_regions.len();
liveness_constraints: RegionValues::new(elements, num_region_variables),
inferred_values: None,
dependency_map: None,
- constraints: IndexVec::new(),
- type_tests: Vec::new(),
+ constraints: IndexVec::from_raw(outlives_constraints),
+ type_tests,
universal_regions,
};
where
R: ToRegionVid,
{
- let inferred_values = self.inferred_values
+ let inferred_values = self
+ .inferred_values
.as_ref()
.expect("region values not yet inferred");
inferred_values.contains(r.to_region_vid(), p)
/// Returns access to the value of `r` for debugging purposes.
crate fn region_value_str(&self, r: RegionVid) -> String {
- let inferred_values = self.inferred_values
+ let inferred_values = self
+ .inferred_values
.as_ref()
.expect("region values not yet inferred");
) {
debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point);
assert!(self.inferred_values.is_none(), "values already inferred");
- self.constraints.push(Constraint {
+ self.constraints.push(OutlivesConstraint {
span,
sup,
sub,
});
}
- /// 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.
self.inferred_values = Some(inferred_values);
}
- #[inline(never)] // ensure dfs is identifiable in profiles
fn compute_region_values(&self, _mir: &Mir<'tcx>) -> RegionValues {
debug!("compute_region_values()");
debug!("compute_region_values: constraints={:#?}", {
/// indices of constraints that need to be re-evaluated when X changes.
/// These are constraints like Y: X @ P -- so if X changed, we may
/// need to grow Y.
- #[inline(never)] // ensure dfs is identifiable in profiles
fn build_dependency_map(&mut self) -> IndexVec<RegionVid, Option<ConstraintIndex>> {
let mut map = IndexVec::from_elem(None, &self.definitions);
if self.universal_regions.is_universal_region(r) {
return self.definitions[r].external_name;
} else {
- let inferred_values = self.inferred_values
+ let inferred_values = self
+ .inferred_values
.as_ref()
.expect("region values not yet inferred");
let upper_bound = self.universal_upper_bound(r);
// 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));
+ assert!(
+ !self
+ .universal_regions
+ .is_local_free_region(lower_bound_plus)
+ );
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
subject,
) -> Option<ClosureOutlivesSubject<'gcx>> {
let tcx = infcx.tcx;
let gcx = tcx.global_tcx();
- let inferred_values = self.inferred_values
+ let inferred_values = self
+ .inferred_values
.as_ref()
.expect("region values not yet inferred");
sup_region, sub_region, point
);
- let inferred_values = self.inferred_values
+ let inferred_values = self
+ .inferred_values
.as_ref()
.expect("values for regions not yet inferred");
) {
// The universal regions are always found in a prefix of the
// full list.
- let universal_definitions = self.definitions
+ let universal_definitions = self
+ .definitions
.iter_enumerated()
.take_while(|(_, fr_definition)| fr_definition.is_universal);
}
}
-impl fmt::Debug for Constraint {
+impl fmt::Debug for OutlivesConstraint {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
formatter,
+++ /dev/null
-// 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 borrow_check::location::LocationTable;
-use borrow_check::nll::facts::AllFacts;
-use rustc::infer::region_constraints::Constraint;
-use rustc::infer::region_constraints::RegionConstraintData;
-use rustc::infer::region_constraints::{Verify, VerifyBound};
-use rustc::mir::{Location, Mir};
-use rustc::ty;
-use std::iter;
-use syntax::codemap::Span;
-
-use super::region_infer::{RegionInferenceContext, RegionTest, TypeTest};
-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
-/// must hold regarding the regions in the MIR, along with locations
-/// *where* they must hold. This code takes those constriants and adds
-/// them into the NLL `RegionInferenceContext`.
-pub(super) fn generate<'tcx>(
- regioncx: &mut RegionInferenceContext<'tcx>,
- all_facts: &mut Option<AllFacts>,
- location_table: &LocationTable,
- mir: &Mir<'tcx>,
- constraints: &MirTypeckRegionConstraints<'tcx>,
-) {
- SubtypeConstraintGenerator {
- regioncx,
- location_table,
- mir,
- }.generate(constraints, all_facts);
-}
-
-struct SubtypeConstraintGenerator<'cx, 'tcx: 'cx> {
- regioncx: &'cx mut RegionInferenceContext<'tcx>,
- location_table: &'cx LocationTable,
- mir: &'cx Mir<'tcx>,
-}
-
-impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
- fn generate(
- &mut self,
- constraints: &MirTypeckRegionConstraints<'tcx>,
- all_facts: &mut Option<AllFacts>,
- ) {
- let MirTypeckRegionConstraints {
- liveness_set,
- outlives_sets,
- } = constraints;
-
- debug!(
- "generate(liveness_set={} items, outlives_sets={} items)",
- liveness_set.len(),
- outlives_sets.len()
- );
-
- for (region, location, cause) in liveness_set {
- debug!("generate: {:#?} is live at {:#?}", region, location);
- let region_vid = self.to_region_vid(region);
- self.regioncx.add_live_point(region_vid, *location, &cause);
- }
-
- if let Some(all_facts) = all_facts {
- all_facts
- .region_live_at
- .extend(liveness_set.into_iter().flat_map(|(region, location, _)| {
- let r = self.to_region_vid(region);
- let p1 = self.location_table.start_index(*location);
- let p2 = self.location_table.mid_index(*location);
- iter::once((r, p1)).chain(iter::once((r, p2)))
- }));
- }
-
- for OutlivesSet { locations, data } in outlives_sets {
- debug!("generate: constraints at: {:#?}", locations);
- let RegionConstraintData {
- constraints,
- verifys,
- givens,
- } = data;
-
- let span = self.mir
- .source_info(locations.from_location().unwrap_or(Location::START))
- .span;
-
- let at_location = locations.at_location().unwrap_or(Location::START);
-
- for constraint in constraints.keys() {
- debug!("generate: constraint: {:?}", constraint);
- let (a_vid, b_vid) = match constraint {
- Constraint::VarSubVar(a_vid, b_vid) => (*a_vid, *b_vid),
- Constraint::RegSubVar(a_r, b_vid) => (self.to_region_vid(a_r), *b_vid),
- Constraint::VarSubReg(a_vid, b_r) => (*a_vid, self.to_region_vid(b_r)),
- Constraint::RegSubReg(a_r, b_r) => {
- (self.to_region_vid(a_r), self.to_region_vid(b_r))
- }
- };
-
- // We have the constraint that `a_vid <= b_vid`. Add
- // `b_vid: a_vid` to our region checker. Note that we
- // reverse direction, because `regioncx` talks about
- // "outlives" (`>=`) whereas the region constraints
- // talk about `<=`.
- self.regioncx.add_outlives(span, b_vid, a_vid, at_location);
-
- // In the new analysis, all outlives relations etc
- // "take effect" at the mid point of the statement
- // that requires them, so ignore the `at_location`.
- if let Some(all_facts) = all_facts {
- if let Some(from_location) = locations.from_location() {
- all_facts.outlives.push((
- b_vid,
- a_vid,
- self.location_table.mid_index(from_location),
- ));
- } else {
- for location in self.location_table.all_points() {
- all_facts.outlives.push((b_vid, a_vid, location));
- }
- }
- }
- }
-
- 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)"
- );
- }
- }
-
- 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().unwrap_or(Location::START);
-
- 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 {
- self.regioncx.to_region_vid(r)
- }
-}
--- /dev/null
+// 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 borrow_check::location::LocationTable;
+use borrow_check::nll::facts::AllFacts;
+use borrow_check::nll::region_infer::{OutlivesConstraint, RegionTest, TypeTest};
+use borrow_check::nll::type_check::Locations;
+use borrow_check::nll::universal_regions::UniversalRegions;
+use rustc::infer::region_constraints::Constraint;
+use rustc::infer::region_constraints::RegionConstraintData;
+use rustc::infer::region_constraints::{Verify, VerifyBound};
+use rustc::mir::{Location, Mir};
+use rustc::ty;
+use syntax::codemap::Span;
+
+crate struct ConstraintConversion<'a, 'tcx: 'a> {
+ mir: &'a Mir<'tcx>,
+ universal_regions: &'a UniversalRegions<'tcx>,
+ location_table: &'a LocationTable,
+ outlives_constraints: &'a mut Vec<OutlivesConstraint>,
+ type_tests: &'a mut Vec<TypeTest<'tcx>>,
+ all_facts: &'a mut Option<AllFacts>,
+
+}
+
+impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
+ crate fn new(
+ mir: &'a Mir<'tcx>,
+ universal_regions: &'a UniversalRegions<'tcx>,
+ location_table: &'a LocationTable,
+ outlives_constraints: &'a mut Vec<OutlivesConstraint>,
+ type_tests: &'a mut Vec<TypeTest<'tcx>>,
+ all_facts: &'a mut Option<AllFacts>,
+ ) -> Self {
+ Self {
+ mir,
+ universal_regions,
+ location_table,
+ outlives_constraints,
+ type_tests,
+ all_facts,
+ }
+ }
+
+ crate fn convert(
+ &mut self,
+ locations: Locations,
+ data: &RegionConstraintData<'tcx>,
+ ) {
+ debug!("generate: constraints at: {:#?}", locations);
+ let RegionConstraintData {
+ constraints,
+ verifys,
+ givens,
+ } = data;
+
+ let span = self
+ .mir
+ .source_info(locations.from_location().unwrap_or(Location::START))
+ .span;
+
+ let at_location = locations.at_location().unwrap_or(Location::START);
+
+ for constraint in constraints.keys() {
+ debug!("generate: constraint: {:?}", constraint);
+ let (a_vid, b_vid) = match constraint {
+ Constraint::VarSubVar(a_vid, b_vid) => (*a_vid, *b_vid),
+ Constraint::RegSubVar(a_r, b_vid) => (self.to_region_vid(a_r), *b_vid),
+ Constraint::VarSubReg(a_vid, b_r) => (*a_vid, self.to_region_vid(b_r)),
+ Constraint::RegSubReg(a_r, b_r) => {
+ (self.to_region_vid(a_r), self.to_region_vid(b_r))
+ }
+ };
+
+ // We have the constraint that `a_vid <= b_vid`. Add
+ // `b_vid: a_vid` to our region checker. Note that we
+ // reverse direction, because `regioncx` talks about
+ // "outlives" (`>=`) whereas the region constraints
+ // talk about `<=`.
+ self.add_outlives(span, b_vid, a_vid, at_location);
+
+ // In the new analysis, all outlives relations etc
+ // "take effect" at the mid point of the statement
+ // that requires them, so ignore the `at_location`.
+ if let Some(all_facts) = &mut self.all_facts {
+ if let Some(from_location) = locations.from_location() {
+ all_facts.outlives.push((
+ b_vid,
+ a_vid,
+ self.location_table.mid_index(from_location),
+ ));
+ } else {
+ for location in self.location_table.all_points() {
+ all_facts.outlives.push((b_vid, a_vid, location));
+ }
+ }
+ }
+ }
+
+ for verify in verifys {
+ let type_test = self.verify_to_type_test(verify, span, locations);
+ self.add_type_test(type_test);
+ }
+
+ assert!(
+ givens.is_empty(),
+ "MIR type-checker does not use givens (thank goodness)"
+ );
+ }
+
+ 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().unwrap_or(Location::START);
+
+ 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 {
+ self.universal_regions.to_region_vid(r)
+ }
+
+ fn add_outlives(
+ &mut self,
+ span: Span,
+ sup: ty::RegionVid,
+ sub: ty::RegionVid,
+ point: Location,
+ ) {
+ self.outlives_constraints.push(OutlivesConstraint {
+ span,
+ sub,
+ sup,
+ point,
+ next: None,
+ });
+ }
+
+ fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
+ self.type_tests.push(type_test);
+ }
+}
use borrow_check::nll::universal_regions::UniversalRegions;
use rustc::hir::def_id::DefId;
use rustc::infer::InferOk;
-use rustc::ty::Ty;
-use rustc::ty::subst::Subst;
-use rustc::mir::*;
use rustc::mir::visit::TyContext;
-use rustc::traits::PredicateObligations;
+use rustc::mir::*;
+use rustc::traits::{ObligationCause, PredicateObligations};
+use rustc::ty::subst::Subst;
+use rustc::ty::Ty;
use rustc_data_structures::indexed_vec::Idx;
}
assert!(
- mir.yield_ty.is_some() && universal_regions.yield_ty.is_some() ||
- mir.yield_ty.is_none() && universal_regions.yield_ty.is_none()
+ mir.yield_ty.is_some() && universal_regions.yield_ty.is_some()
+ || mir.yield_ty.is_none() && universal_regions.yield_ty.is_none()
);
if let Some(mir_yield_ty) = mir.yield_ty {
let ur_yield_ty = universal_regions.yield_ty.unwrap();
output_ty
);
let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
- let anon_type_map = self.fully_perform_op(Locations::All, |cx| {
- let mut obligations = ObligationAccumulator::default();
-
- let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types(
- mir_def_id,
- cx.body_id,
- cx.param_env,
- &output_ty,
- ));
- debug!(
- "equate_inputs_and_outputs: instantiated output_ty={:?}",
- output_ty
- );
- debug!(
- "equate_inputs_and_outputs: anon_type_map={:#?}",
- anon_type_map
- );
-
- debug!(
- "equate_inputs_and_outputs: mir_output_ty={:?}",
- mir_output_ty
- );
- obligations.add(infcx
- .at(&cx.misc(cx.last_span), cx.param_env)
- .eq(output_ty, mir_output_ty)?);
-
- for (&anon_def_id, anon_decl) in &anon_type_map {
- let anon_defn_ty = tcx.type_of(anon_def_id);
- let anon_defn_ty = anon_defn_ty.subst(tcx, anon_decl.substs);
- let anon_defn_ty = renumber::renumber_regions(
- cx.infcx,
- TyContext::Location(Location::START),
- &anon_defn_ty,
- );
- debug!(
- "equate_inputs_and_outputs: concrete_ty={:?}",
- anon_decl.concrete_ty
- );
- debug!("equate_inputs_and_outputs: anon_defn_ty={:?}", anon_defn_ty);
- obligations.add(infcx
- .at(&cx.misc(cx.last_span), cx.param_env)
- .eq(anon_decl.concrete_ty, anon_defn_ty)?);
- }
-
- debug!("equate_inputs_and_outputs: equated");
-
- Ok(InferOk {
- value: Some(anon_type_map),
- obligations: obligations.into_vec(),
- })
- }).unwrap_or_else(|terr| {
+ let anon_type_map =
+ self.fully_perform_op(
+ Locations::All,
+ || format!("input_output"),
+ |cx| {
+ let mut obligations = ObligationAccumulator::default();
+
+ let dummy_body_id = ObligationCause::dummy().body_id;
+ let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types(
+ mir_def_id,
+ dummy_body_id,
+ cx.param_env,
+ &output_ty,
+ ));
+ debug!(
+ "equate_inputs_and_outputs: instantiated output_ty={:?}",
+ output_ty
+ );
+ debug!(
+ "equate_inputs_and_outputs: anon_type_map={:#?}",
+ anon_type_map
+ );
+
+ debug!(
+ "equate_inputs_and_outputs: mir_output_ty={:?}",
+ mir_output_ty
+ );
+ obligations.add(
+ infcx
+ .at(&ObligationCause::dummy(), cx.param_env)
+ .eq(output_ty, mir_output_ty)?,
+ );
+
+ for (&anon_def_id, anon_decl) in &anon_type_map {
+ let anon_defn_ty = tcx.type_of(anon_def_id);
+ let anon_defn_ty = anon_defn_ty.subst(tcx, anon_decl.substs);
+ let anon_defn_ty = renumber::renumber_regions(
+ cx.infcx,
+ TyContext::Location(Location::START),
+ &anon_defn_ty,
+ );
+ debug!(
+ "equate_inputs_and_outputs: concrete_ty={:?}",
+ anon_decl.concrete_ty
+ );
+ debug!("equate_inputs_and_outputs: anon_defn_ty={:?}", anon_defn_ty);
+ obligations.add(
+ infcx
+ .at(&ObligationCause::dummy(), cx.param_env)
+ .eq(anon_decl.concrete_ty, anon_defn_ty)?,
+ );
+ }
+
+ debug!("equate_inputs_and_outputs: equated");
+
+ Ok(InferOk {
+ value: Some(anon_type_map),
+ obligations: obligations.into_vec(),
+ })
+ },
+ ).unwrap_or_else(|terr| {
span_mirbug!(
self,
Location::START,
// prove that `T: Iterator` where `T` is the type we
// instantiated it with).
if let Some(anon_type_map) = anon_type_map {
- self.fully_perform_op(Locations::All, |_cx| {
- infcx.constrain_anon_types(&anon_type_map, universal_regions);
- Ok(InferOk {
- value: (),
- obligations: vec![],
- })
- }).unwrap();
+ self.fully_perform_op(
+ Locations::All,
+ || format!("anon_type_map"),
+ |_cx| {
+ infcx.constrain_anon_types(&anon_type_map, universal_regions);
+ Ok(InferOk {
+ value: (),
+ obligations: vec![],
+ })
+ },
+ ).unwrap();
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use dataflow::{FlowAtLocation, FlowsAtLocation};
use borrow_check::nll::region_infer::Cause;
-use dataflow::MaybeInitializedPlaces;
+use borrow_check::nll::type_check::AtLocation;
use dataflow::move_paths::{HasMoveData, MoveData};
-use rustc::mir::{BasicBlock, Location, Mir};
+use dataflow::MaybeInitializedPlaces;
+use dataflow::{FlowAtLocation, FlowsAtLocation};
+use rustc::infer::region_constraints::RegionConstraintData;
use rustc::mir::Local;
-use rustc::ty::{Ty, TyCtxt, TypeFoldable};
-use rustc::infer::InferOk;
-use borrow_check::nll::type_check::AtLocation;
+use rustc::mir::{BasicBlock, Location, Mir};
+use rustc::traits::ObligationCause;
+use rustc::ty::subst::Kind;
+use rustc::ty::{Ty, TypeFoldable};
+use rustc_data_structures::fx::FxHashMap;
+use std::rc::Rc;
use util::liveness::LivenessResults;
use super::TypeChecker;
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
) {
- let tcx = cx.tcx();
let mut generator = TypeLivenessGenerator {
cx,
- tcx,
mir,
liveness,
flow_inits,
move_data,
+ drop_data: FxHashMap(),
};
for bb in mir.basic_blocks().indices() {
'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<MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
move_data: &'gen MoveData<'tcx>,
+ drop_data: FxHashMap<Ty<'tcx>, DropData<'tcx>>,
+}
+
+struct DropData<'tcx> {
+ dropped_kinds: Vec<Kind<'tcx>>,
+ region_constraint_data: Option<Rc<RegionConstraintData<'tcx>>>,
}
impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> {
for live_local in live_locals.iter() {
let live_local_ty = self.mir.local_decls[live_local].ty;
let cause = Cause::LiveVar(live_local, location);
- self.push_type_live_constraint(live_local_ty, location, cause);
+ Self::push_type_live_constraint(&mut self.cx, live_local_ty, location, cause);
}
});
/// `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, cause: Cause)
- where
+ fn push_type_live_constraint<T>(
+ cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
+ value: T,
+ location: Location,
+ cause: Cause,
+ ) where
T: TypeFoldable<'tcx>,
{
debug!(
value, location
);
- self.tcx.for_each_free_region(&value, |live_region| {
- self.cx
+ cx.tcx().for_each_free_region(&value, |live_region| {
+ cx
.constraints
.liveness_set
.push((live_region, location, cause.clone()));
dropped_local, dropped_ty, location
);
- // If we end visiting the same type twice (usually due to a cycle involving
- // associated types), we need to ensure that its region types match up with the type
- // we added to the 'known' map the first time around. For this reason, we need
- // our infcx to hold onto its calculated region constraints after each call
- // to dtorck_constraint_for_ty. Otherwise, normalizing the corresponding associated
- // type will end up instantiating the type with a new set of inference variables
- // Since this new type will never be in 'known', we end up looping forever.
- //
- // For this reason, we avoid calling TypeChecker.normalize, instead doing all normalization
- // ourselves in one large 'fully_perform_op' callback.
- let kind_constraints = self.cx
- .fully_perform_op(location.at_self(), |cx| {
- let span = cx.last_span;
-
- let mut final_obligations = Vec::new();
- let mut kind_constraints = Vec::new();
-
- let InferOk {
- value: kinds,
- obligations,
- } = cx.infcx
- .at(&cx.misc(span), cx.param_env)
- .dropck_outlives(dropped_ty);
- for kind in kinds {
- // All things in the `outlives` array may be touched by
- // the destructor and must be live at this point.
- let cause = Cause::DropVar(dropped_local, location);
- kind_constraints.push((kind, location, cause));
- }
+ let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
+ let cx = &mut self.cx;
+ move || Self::compute_drop_data(cx, dropped_ty)
+ });
- final_obligations.extend(obligations);
+ if let Some(data) = &drop_data.region_constraint_data {
+ self.cx
+ .push_region_constraints(location.at_self(), data.clone());
+ }
- Ok(InferOk {
- value: kind_constraints,
- obligations: final_obligations,
- })
- })
- .unwrap();
+ // All things in the `outlives` array may be touched by
+ // the destructor and must be live at this point.
+ let cause = Cause::DropVar(dropped_local, location);
+ for &kind in &drop_data.dropped_kinds {
+ Self::push_type_live_constraint(&mut self.cx, kind, location, cause);
+ }
+ }
- for (kind, location, cause) in kind_constraints {
- self.push_type_live_constraint(kind, location, cause);
+ fn compute_drop_data(
+ cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
+ dropped_ty: Ty<'tcx>,
+ ) -> DropData<'tcx> {
+ debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
+
+ let (dropped_kinds, region_constraint_data) =
+ cx.fully_perform_op_and_get_region_constraint_data(
+ || format!("compute_drop_data(dropped_ty={:?})", dropped_ty),
+ |cx| {
+ Ok(cx
+ .infcx
+ .at(&ObligationCause::dummy(), cx.param_env)
+ .dropck_outlives(dropped_ty))
+ },
+ ).unwrap();
+
+ DropData {
+ dropped_kinds,
+ region_constraint_data,
}
}
}
//! This pass type-checks the MIR to ensure it is not broken.
#![allow(unreachable_code)]
+use borrow_check::location::LocationTable;
+use borrow_check::nll::facts::AllFacts;
use borrow_check::nll::region_infer::Cause;
-use borrow_check::nll::region_infer::ClosureRegionRequirementsExt;
+use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, OutlivesConstraint, TypeTest};
use borrow_check::nll::universal_regions::UniversalRegions;
use dataflow::move_paths::MoveData;
use dataflow::FlowAtLocation;
use rustc::hir::def_id::DefId;
use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
+use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
use rustc::mir::tcx::PlaceTy;
use rustc::mir::visit::{PlaceContext, Visitor};
-use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
use rustc::mir::*;
use rustc::traits::query::NoSolution;
-use rustc::traits::{self, Normalized, TraitEngine};
+use rustc::traits::{self, ObligationCause, Normalized, TraitEngine};
use rustc::ty::error::TypeError;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
use std::fmt;
-use syntax::ast;
+use std::rc::Rc;
use syntax_pos::{Span, DUMMY_SP};
use transform::{MirPass, MirSource};
use util::liveness::LivenessResults;
$context.last_span,
&format!(
"broken MIR in {:?} ({:?}): {}",
- $context.body_id,
+ $context.mir_def_id,
$elem,
format_args!($($message)*),
),
})
}
+mod constraint_conversion;
mod input_output;
mod liveness;
mir: &Mir<'tcx>,
mir_def_id: DefId,
universal_regions: &UniversalRegions<'tcx>,
+ location_table: &LocationTable,
liveness: &LivenessResults,
+ all_facts: &mut Option<AllFacts>,
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
) -> MirTypeckRegionConstraints<'tcx> {
- let body_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap();
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
type_check_internal(
infcx,
- body_id,
+ mir_def_id,
param_env,
mir,
&universal_regions.region_bound_pairs,
Some(implicit_region_bound),
+ Some(BorrowCheckContext {
+ universal_regions,
+ location_table,
+ all_facts,
+ }),
&mut |cx| {
liveness::generate(cx, mir, liveness, flow_inits, move_data);
fn type_check_internal<'gcx, 'tcx>(
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
- body_id: ast::NodeId,
+ mir_def_id: DefId,
param_env: ty::ParamEnv<'gcx>,
mir: &Mir<'tcx>,
region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
implicit_region_bound: Option<ty::Region<'tcx>>,
+ borrowck_context: Option<BorrowCheckContext<'_, 'tcx>>,
extra: &mut dyn FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>),
) -> MirTypeckRegionConstraints<'tcx> {
let mut checker = TypeChecker::new(
infcx,
- body_id,
+ mir_def_id,
param_env,
region_bound_pairs,
implicit_region_bound,
+ borrowck_context,
+ mir,
);
let errors_reported = {
let mut verifier = TypeVerifier::new(&mut checker, mir);
cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>,
mir: &'a Mir<'tcx>,
last_span: Span,
- body_id: ast::NodeId,
+ mir_def_id: DefId,
errors_reported: bool,
}
fn new(cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
TypeVerifier {
mir,
- body_id: cx.body_id,
+ mir_def_id: cx.mir_def_id,
cx,
last_span: mir.span,
errors_reported: false,
debug!("sanitize_constant: expected_ty={:?}", expected_ty);
- if let Err(terr) = self.cx
+ if let Err(terr) = self
+ .cx
.eq_types(expected_ty, constant.ty, location.at_self())
{
span_mirbug!(
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'gcx>,
last_span: Span,
- body_id: ast::NodeId,
+ mir_def_id: DefId,
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
implicit_region_bound: Option<ty::Region<'tcx>>,
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
constraints: MirTypeckRegionConstraints<'tcx>,
+ borrowck_context: Option<BorrowCheckContext<'a, 'tcx>>,
+ mir: &'a Mir<'tcx>,
+}
+
+struct BorrowCheckContext<'a, 'tcx: 'a> {
+ universal_regions: &'a UniversalRegions<'tcx>,
+ location_table: &'a LocationTable,
+ all_facts: &'a mut Option<AllFacts>,
}
/// A collection of region constraints that must be satisfied for the
/// program to be considered well-typed.
#[derive(Default)]
-pub(crate) struct MirTypeckRegionConstraints<'tcx> {
+crate struct MirTypeckRegionConstraints<'tcx> {
/// In general, the type-checker is not responsible for enforcing
/// liveness constraints; this job falls to the region inferencer,
/// which performs a liveness analysis. However, in some limited
/// not otherwise appear in the MIR -- in particular, the
/// late-bound regions that it instantiates at call-sites -- and
/// hence it must report on their liveness constraints.
- pub liveness_set: Vec<(ty::Region<'tcx>, Location, Cause)>,
-
- /// During the course of type-checking, we will accumulate region
- /// constraints due to performing subtyping operations or solving
- /// traits. These are accumulated into this vector for later use.
- pub outlives_sets: Vec<OutlivesSet<'tcx>>,
-}
+ crate liveness_set: Vec<(ty::Region<'tcx>, Location, Cause)>,
-/// Outlives relationships between regions and types created at a
-/// particular point within the control-flow graph.
-pub struct OutlivesSet<'tcx> {
- /// The locations associated with these constraints.
- pub locations: Locations,
+ crate outlives_constraints: Vec<OutlivesConstraint>,
- /// Constraints generated. In terms of the NLL RFC, when you have
- /// a constraint `R1: R2 @ P`, the data in there specifies things
- /// like `R1: R2`.
- pub data: RegionConstraintData<'tcx>,
+ crate type_tests: Vec<TypeTest<'tcx>>,
}
/// The `Locations` type summarizes *where* region constraints are
/// NLL RFC, when you have a constraint `R1: R2 @ P`, this field
/// is the `P` value.
at_location: Location,
- }
+ },
}
impl Locations {
impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
fn new(
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
- body_id: ast::NodeId,
+ mir_def_id: DefId,
param_env: ty::ParamEnv<'gcx>,
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
implicit_region_bound: Option<ty::Region<'tcx>>,
+ borrowck_context: Option<BorrowCheckContext<'a, 'tcx>>,
+ mir: &'a Mir<'tcx>,
) -> Self {
TypeChecker {
infcx,
last_span: DUMMY_SP,
- body_id,
+ mir_def_id,
param_env,
region_bound_pairs,
implicit_region_bound,
+ borrowck_context,
+ mir,
reported_errors: FxHashSet(),
constraints: MirTypeckRegionConstraints::default(),
}
}
- fn misc(&self, span: Span) -> traits::ObligationCause<'tcx> {
- traits::ObligationCause::misc(span, self.body_id)
+ /// Given some operation `op` that manipulates types, proves
+ /// predicates, or otherwise uses the inference context, executes
+ /// `op` and then executes all the further obligations that `op`
+ /// returns. This will yield a set of outlives constraints amongst
+ /// regions which are extracted and stored as having occured at
+ /// `locations`.
+ ///
+ /// **Any `rustc::infer` operations that might generate region
+ /// constraints should occur within this method so that those
+ /// constraints can be properly localized!**
+ fn fully_perform_op<R>(
+ &mut self,
+ locations: Locations,
+ describe_op: impl Fn() -> String,
+ op: impl FnOnce(&mut Self) -> InferResult<'tcx, R>,
+ ) -> Result<R, TypeError<'tcx>> {
+ let (r, opt_data) = self.fully_perform_op_and_get_region_constraint_data(
+ || format!("{} at {:?}", describe_op(), locations),
+ op,
+ )?;
+
+ if let Some(data) = opt_data {
+ self.push_region_constraints(locations, data);
+ }
+
+ Ok(r)
}
- fn fully_perform_op<OP, R>(
+ fn push_region_constraints(
&mut self,
locations: Locations,
- op: OP,
- ) -> Result<R, TypeError<'tcx>>
- where
- OP: FnOnce(&mut Self) -> InferResult<'tcx, R>,
- {
+ data: Rc<RegionConstraintData<'tcx>>,
+ ) {
+ debug!(
+ "push_region_constraints: constraints generated at {:?} are {:#?}",
+ locations, data
+ );
+
+ if let Some(borrowck_context) = &mut self.borrowck_context {
+ constraint_conversion::ConstraintConversion::new(
+ self.mir,
+ borrowck_context.universal_regions,
+ borrowck_context.location_table,
+ &mut self.constraints.outlives_constraints,
+ &mut self.constraints.type_tests,
+ &mut borrowck_context.all_facts,
+ ).convert(locations, &data);
+ }
+ }
+
+ /// Helper for `fully_perform_op`, but also used on its own
+ /// sometimes to enable better caching: executes `op` fully (along
+ /// with resulting obligations) and returns the full set of region
+ /// obligations. If the same `op` were to be performed at some
+ /// other location, then the same set of region obligations would
+ /// be generated there, so this can be useful for caching.
+ fn fully_perform_op_and_get_region_constraint_data<R>(
+ &mut self,
+ describe_op: impl Fn() -> String,
+ op: impl FnOnce(&mut Self) -> InferResult<'tcx, R>,
+ ) -> Result<(R, Option<Rc<RegionConstraintData<'tcx>>>), TypeError<'tcx>> {
+ if cfg!(debug_assertions) {
+ info!(
+ "fully_perform_op_and_get_region_constraint_data({})",
+ describe_op(),
+ );
+ }
+
let mut fulfill_cx = TraitEngine::new(self.infcx.tcx);
+ let dummy_body_id = ObligationCause::dummy().body_id;
let InferOk { value, obligations } = self.infcx.commit_if_ok(|_| op(self))?;
+ debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
fulfill_cx.register_predicate_obligations(self.infcx, obligations);
if let Err(e) = fulfill_cx.select_all_or_error(self.infcx) {
span_mirbug!(self, "", "errors selecting obligation: {:?}", e);
self.region_bound_pairs,
self.implicit_region_bound,
self.param_env,
- self.body_id,
+ dummy_body_id,
);
let data = self.infcx.take_and_reset_region_constraints();
- if !data.is_empty() {
- debug!(
- "fully_perform_op: constraints generated at {:?} are {:#?}",
- locations, data
- );
- self.constraints
- .outlives_sets
- .push(OutlivesSet { locations, data });
+ if data.is_empty() {
+ Ok((value, None))
+ } else {
+ Ok((value, Some(Rc::new(data))))
}
-
- Ok(value)
}
fn sub_types(
sup: Ty<'tcx>,
locations: Locations,
) -> UnitResult<'tcx> {
- self.fully_perform_op(locations, |this| {
- this.infcx
- .at(&this.misc(this.last_span), this.param_env)
- .sup(sup, sub)
- })
+ // Micro-optimization.
+ if sub == sup {
+ return Ok(());
+ }
+
+ self.fully_perform_op(
+ locations,
+ || format!("sub_types({:?} <: {:?})", sub, sup),
+ |this| {
+ this.infcx
+ .at(&ObligationCause::dummy(), this.param_env)
+ .sup(sup, sub)
+ },
+ )
}
fn eq_types(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, locations: Locations) -> UnitResult<'tcx> {
- self.fully_perform_op(locations, |this| {
- this.infcx
- .at(&this.misc(this.last_span), this.param_env)
- .eq(b, a)
- })
+ // Micro-optimization.
+ if a == b {
+ return Ok(());
+ }
+
+ self.fully_perform_op(
+ locations,
+ || format!("eq_types({:?} = {:?})", a, b),
+ |this| {
+ this.infcx
+ .at(&ObligationCause::dummy(), this.param_env)
+ .eq(b, a)
+ },
+ )
}
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
}
StatementKind::UserAssertTy(ref c_ty, ref local) => {
let local_ty = mir.local_decls()[*local].ty;
- let (ty, _) = self.infcx
+ let (ty, _) = self
+ .infcx
.instantiate_canonical_with_fresh_inference_vars(stmt.source_info.span, c_ty);
debug!(
"check_stmt: user_assert_ty ty={:?} local_ty={:?}",
}
};
let operand_ty = operand.ty(mir, tcx);
- if let Err(terr) =
- self.sub_types(operand_ty, field_ty, location.at_self())
- {
+ if let Err(terr) = self.sub_types(operand_ty, field_ty, location.at_self()) {
span_mirbug!(
self,
rvalue,
if let Some(closure_region_requirements) =
tcx.mir_borrowck(*def_id).closure_requirements
{
+ let dummy_body_id = ObligationCause::dummy().body_id;
closure_region_requirements.apply_requirements(
self.infcx,
- self.body_id,
+ dummy_body_id,
location,
*def_id,
*substs,
fn prove_predicates<T>(&mut self, predicates: T, location: Location)
where
- T: IntoIterator<Item = ty::Predicate<'tcx>>,
- T::IntoIter: Clone,
+ T: IntoIterator<Item = ty::Predicate<'tcx>> + Clone,
{
- let predicates = predicates.into_iter();
+ let cause = ObligationCause::dummy();
+ let obligations: Vec<_> = predicates
+ .into_iter()
+ .map(|p| traits::Obligation::new(cause.clone(), self.param_env, p))
+ .collect();
+
+ // Micro-optimization
+ if obligations.is_empty() {
+ return;
+ }
+
+ // This intermediate vector is mildly unfortunate, in that we
+ // sometimes create it even when logging is disabled, but only
+ // if debug-info is enabled, and I doubt it is actually
+ // expensive. -nmatsakis
+ let predicates_vec: Vec<_> = if cfg!(debug_assertions) {
+ obligations.iter().map(|o| o.predicate).collect()
+ } else {
+ Vec::new()
+ };
debug!(
"prove_predicates(predicates={:?}, location={:?})",
- predicates.clone().collect::<Vec<_>>(),
- location,
+ predicates_vec, location,
);
- self.fully_perform_op(location.at_self(), |this| {
- let cause = this.misc(this.last_span);
- let obligations = predicates
- .into_iter()
- .map(|p| traits::Obligation::new(cause.clone(), this.param_env, p))
- .collect();
- Ok(InferOk {
- value: (),
- obligations,
- })
- }).unwrap()
+
+ self.fully_perform_op(
+ location.at_self(),
+ || format!("prove_predicates({:?})", predicates_vec),
+ |_this| {
+ Ok(InferOk {
+ value: (),
+ obligations,
+ })
+ },
+ ).unwrap()
}
fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
where
T: fmt::Debug + TypeFoldable<'tcx>,
{
+ // Micro-optimization: avoid work when we don't have to
+ if !value.has_projections() {
+ return value.clone();
+ }
+
debug!("normalize(value={:?}, location={:?})", value, location);
- self.fully_perform_op(location.to_locations(), |this| {
- let Normalized { value, obligations } = this.infcx
- .at(&this.misc(this.last_span), this.param_env)
- .normalize(value)
- .unwrap_or_else(|NoSolution| {
- span_bug!(
- this.last_span,
- "normalization of `{:?}` failed at {:?}",
- value,
- location,
- );
- });
- Ok(InferOk { value, obligations })
- }).unwrap()
+ self.fully_perform_op(
+ location.to_locations(),
+ || format!("normalize(value={:?})", value),
+ |this| {
+ let Normalized { value, obligations } = this
+ .infcx
+ .at(&ObligationCause::dummy(), this.param_env)
+ .normalize(value)
+ .unwrap_or_else(|NoSolution| {
+ span_bug!(
+ this.last_span,
+ "normalization of `{:?}` failed at {:?}",
+ value,
+ location,
+ );
+ });
+ Ok(InferOk { value, obligations })
+ },
+ ).unwrap()
}
}
impl MirPass for TypeckMir {
fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
let def_id = src.def_id;
- let id = tcx.hir.as_local_node_id(def_id).unwrap();
debug!("run_pass: {:?}", def_id);
// When NLL is enabled, the borrow checker runs the typeck
}
let param_env = tcx.param_env(def_id);
tcx.infer_ctxt().enter(|infcx| {
- let _ = type_check_internal(&infcx, id, param_env, mir, &[], None, &mut |_| ());
+ let _ = type_check_internal(
+ &infcx,
+ def_id,
+ param_env,
+ mir,
+ &[],
+ None,
+ None,
+ &mut |_| (),
+ );
// For verification purposes, we just ignore the resulting
// region constraint sets. Not our problem. =)
#![feature(specialization)]
#![feature(try_trait)]
+#![recursion_limit="256"]
+
extern crate arena;
+
#[macro_use]
extern crate bitflags;
#[macro_use] extern crate log;
use monomorphize::{self, Instance};
use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
+use rustc::util::common::time;
use monomorphize::item::{MonoItemExt, DefPathBasedNames, InstantiationMode};
use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::sync::{MTRef, MTLock, ParallelIterator, par_iter};
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub enum MonoItemCollectionMode {
mode: MonoItemCollectionMode)
-> (FxHashSet<MonoItem<'tcx>>,
InliningMap<'tcx>) {
- let roots = collect_roots(tcx, mode);
+ let roots = time(tcx.sess, "collecting roots", || {
+ collect_roots(tcx, mode)
+ });
debug!("Building mono item graph, beginning at roots");
- let mut visited = FxHashSet();
- let mut recursion_depths = DefIdMap();
- let mut inlining_map = InliningMap::new();
-
- for root in roots {
- collect_items_rec(tcx,
- root,
- &mut visited,
- &mut recursion_depths,
- &mut inlining_map);
+
+ let mut visited = MTLock::new(FxHashSet());
+ let mut inlining_map = MTLock::new(InliningMap::new());
+
+ {
+ let visited: MTRef<'_, _> = &mut visited;
+ let inlining_map: MTRef<'_, _> = &mut inlining_map;
+
+ time(tcx.sess, "collecting mono items", || {
+ par_iter(roots).for_each(|root| {
+ let mut recursion_depths = DefIdMap();
+ collect_items_rec(tcx,
+ root,
+ visited,
+ &mut recursion_depths,
+ inlining_map);
+ });
+ });
}
- (visited, inlining_map)
+ (visited.into_inner(), inlining_map.into_inner())
}
// Find all non-generic items by walking the HIR. These items serve as roots to
// Collect all monomorphized items reachable from `starting_point`
fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
starting_point: MonoItem<'tcx>,
- visited: &mut FxHashSet<MonoItem<'tcx>>,
+ visited: MTRef<'_, MTLock<FxHashSet<MonoItem<'tcx>>>>,
recursion_depths: &mut DefIdMap<usize>,
- inlining_map: &mut InliningMap<'tcx>) {
- if !visited.insert(starting_point.clone()) {
+ inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>) {
+ if !visited.lock_mut().insert(starting_point.clone()) {
// We've been here already, no need to search again.
return;
}
fn record_accesses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
caller: MonoItem<'tcx>,
callees: &[MonoItem<'tcx>],
- inlining_map: &mut InliningMap<'tcx>) {
+ inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>) {
let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| {
mono_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy
};
(*mono_item, is_inlining_candidate(mono_item))
});
- inlining_map.record_accesses(caller, accesses);
+ inlining_map.lock_mut().record_accesses(caller, accesses);
}
fn check_recursion_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
hir::ItemTy(..) |
hir::ItemTrait(..) |
hir::ItemTraitAlias(..) |
+ hir::ItemExistential(..) |
hir::ItemMod(..) => {
// Nothing to do, just keep recursing...
}
hir::ItemGlobalAsm(..) | hir::ItemFn(..) | hir::ItemMod(..) |
hir::ItemStatic(..) | hir::ItemStruct(..) |
hir::ItemTrait(..) | hir::ItemTraitAlias(..) |
+ hir::ItemExistential(..) |
hir::ItemTy(..) | hir::ItemUnion(..) | hir::ItemUse(..) => {
if item.vis == hir::Public { self.prev_level } else { None }
}
}
}
}
+ hir::ItemExistential(..) |
hir::ItemUse(..) | hir::ItemStatic(..) | hir::ItemConst(..) |
hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemMod(..) | hir::ItemTraitAlias(..) |
hir::ItemFn(..) | hir::ItemExternCrate(..) => {}
hir::ItemUse(..) => {}
// The interface is empty
hir::ItemGlobalAsm(..) => {}
+ // Checked by visit_ty
+ hir::ItemExistential(..) => {}
// Visit everything
hir::ItemConst(..) | hir::ItemStatic(..) |
hir::ItemFn(..) | hir::ItemTy(..) => {
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
- if let hir::TyImplTraitExistential(..) = ty.node {
- if self.get(ty.id).is_some() {
- // Reach the (potentially private) type and the API being exposed.
- self.reach(ty.id).ty().predicates();
+ if let hir::TyImplTraitExistential(item_id, _, _) = ty.node {
+ if self.get(item_id.id).is_some() {
+ // Reach the (potentially private) type and the API being exposed
+ self.reach(item_id.id).ty().predicates();
}
}
fn ty(&mut self) -> &mut Self {
let ty = self.ev.tcx.type_of(self.item_def_id);
+ self.walk_ty(ty)
+ }
+
+ fn walk_ty(&mut self, ty: Ty<'tcx>) -> &mut Self {
ty.visit_with(self);
if let ty::TyFnDef(def_id, _) = ty.sty {
if def_id == self.item_def_id {
hir::ItemUse(..) => {}
// No subitems
hir::ItemGlobalAsm(..) => {}
+ // Checked in visit_ty
+ hir::ItemExistential(..) => {}
// Subitems of these items have inherited publicity
hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
hir::ItemTy(..) => {
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
- if let hir::TyImplTraitExistential(..) = ty.node {
+ if let hir::TyImplTraitExistential(ref exist_item, _, _) = ty.node {
// Check the traits being exposed, as they're separate,
// e.g. `impl Iterator<Item=T>` has two predicates,
// `X: Iterator` and `<X as Iterator>::Item == T`,
// where `X` is the `impl Iterator<Item=T>` itself,
// stored in `predicates_of`, not in the `Ty` itself.
- self.check(ty.id, self.inner_visibility).predicates();
+
+ self.check(exist_item.id, self.inner_visibility).predicates();
}
intravisit::walk_ty(self, ty);
Def::AssociatedTy(..) | Def::PrimTy(..) | Def::Fn(..) | Def::Const(..) |
Def::Static(..) | Def::StructCtor(..) | Def::VariantCtor(..) | Def::Method(..) |
Def::AssociatedConst(..) | Def::Local(..) | Def::Upvar(..) | Def::Label(..) |
+ Def::Existential(..) |
Def::Macro(..) | Def::GlobalAsm(..) | Def::Err =>
bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy or \
Def::TyParam")
HirDef::TraitAlias(def_id) |
HirDef::AssociatedTy(def_id) |
HirDef::Trait(def_id) |
+ HirDef::Existential(def_id) |
HirDef::TyParam(def_id) => {
let span = self.span_from_span(sub_span);
Some(Ref {
hir::TyTraitObject(ref bounds, ref lifetime) => {
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
}
- hir::TyImplTraitExistential(_, ref lifetimes) => {
- let def_id = tcx.hir.local_def_id(ast_ty.id);
+ hir::TyImplTraitExistential(_, def_id, ref lifetimes) => {
self.impl_trait_ty_to_ty(def_id, lifetimes)
}
hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
result_ty
}
- pub fn impl_trait_ty_to_ty(&self, def_id: DefId, lifetimes: &[hir::Lifetime]) -> Ty<'tcx> {
+ pub fn impl_trait_ty_to_ty(
+ &self,
+ def_id: DefId,
+ lifetimes: &[hir::Lifetime],
+ ) -> Ty<'tcx> {
debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes);
let tcx = self.tcx();
+
let generics = tcx.generics_of(def_id);
debug!("impl_trait_ty_to_ty: generics={:?}", generics);
});
debug!("impl_trait_ty_to_ty: final substs = {:?}", substs);
- tcx.mk_anon(def_id, substs)
+ let ty = tcx.mk_anon(def_id, substs);
+ debug!("impl_trait_ty_to_ty: {}", ty);
+ ty
}
pub fn ty_of_arg(&self,
// Create a `PolyFnSig`. Note the oddity that late bound
// regions appearing free in `expected_sig` are now bound up
// in this binder we are creating.
- assert!(!expected_sig.sig.has_regions_bound_above(ty::DebruijnIndex::INNERMOST));
+ assert!(!expected_sig.sig.has_regions_bound_above(ty::INNERMOST));
let bound_sig = ty::Binder::bind(self.tcx.mk_fn_sig(
expected_sig.sig.inputs().iter().cloned(),
expected_sig.sig.output(),
"pref_align_of" | "min_align_of" => (1, Vec::new(), tcx.types.usize),
"size_of_val" | "min_align_of_val" => {
(1, vec![
- tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::INNERMOST,
+ tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST,
ty::BrAnon(0))),
param(0))
], tcx.types.usize)
"unlikely" => (0, vec![tcx.types.bool], tcx.types.bool),
"discriminant_value" => (1, vec![
- tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::INNERMOST,
+ tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST,
ty::BrAnon(0))),
param(0))], tcx.types.u64),
{
debug_assert!(crate_num == LOCAL_CRATE);
Ok(tcx.sess.track_errors(|| {
- for body_owner_def_id in tcx.body_owners() {
+ tcx.par_body_owners(|body_owner_def_id| {
ty::query::queries::typeck_tables_of::ensure(tcx, body_owner_def_id);
- }
+ });
})?)
}
debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env);
// Create the function context. This is either derived from scratch or,
- // in the case of function expressions, based on the outer context.
+ // in the case of closures, based on the outer context.
let mut fcx = FnCtxt::new(inherited, param_env, body.value.id);
*fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
wbcx.visit_fru_field_types();
- wbcx.visit_anon_types();
+ wbcx.visit_anon_types(body.value.span);
wbcx.visit_cast_types();
wbcx.visit_free_region_map();
wbcx.visit_user_provided_tys();
}
}
- fn visit_anon_types(&mut self) {
- let gcx = self.tcx().global_tcx();
+ fn visit_anon_types(&mut self, span: Span) {
for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() {
- let node_id = gcx.hir.as_local_node_id(def_id).unwrap();
+ let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
let instantiated_ty = self.resolve(&anon_defn.concrete_ty, &node_id);
let definition_ty = self.fcx.infer_anon_definition_from_instantiation(
def_id,
anon_defn,
instantiated_ty,
);
- let hir_id = self.tcx().hir.node_to_hir_id(node_id);
- self.tables.node_types_mut().insert(hir_id, definition_ty);
+ let old = self.tables.concrete_existential_types.insert(def_id, definition_ty);
+ if let Some(old) = old {
+ if old != definition_ty {
+ span_bug!(
+ span,
+ "visit_anon_types tried to write \
+ different types for the same existential type: {:?}, {:?}, {:?}",
+ def_id,
+ definition_ty,
+ old,
+ );
+ }
+ }
}
}
intravisit::walk_expr(self, expr);
}
- fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
- if let hir::TyImplTraitExistential(..) = ty.node {
- let def_id = self.tcx.hir.local_def_id(ty.id);
- self.tcx.generics_of(def_id);
- self.tcx.predicates_of(def_id);
- }
- intravisit::walk_ty(self, ty);
- }
-
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
convert_trait_item(self.tcx, trait_item.id);
intravisit::walk_trait_item(self, trait_item);
convert_variant_ctor(tcx, struct_def.id());
}
},
+ hir::ItemExistential(..) |
hir::ItemTy(..) | hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => {
tcx.generics_of(def_id);
tcx.type_of(def_id);
-> Option<Span> {
let mut visitor = LateBoundRegionsDetector {
tcx,
- outer_index: ty::DebruijnIndex::INNERMOST,
+ outer_index: ty::INNERMOST,
has_late_bound_regions: None,
};
for lifetime in generics.lifetimes() {
NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
Some(tcx.closure_base_def_id(def_id))
}
- NodeTy(&hir::Ty { node: hir::TyImplTraitExistential(..), .. }) => {
- let mut parent_id = node_id;
- loop {
- match tcx.hir.get(parent_id) {
- NodeItem(_) | NodeImplItem(_) | NodeTraitItem(_) => break,
- _ => {
- parent_id = tcx.hir.get_parent_node(parent_id);
- }
- }
+ NodeItem(item) => {
+ match item.node {
+ ItemExistential(hir::ExistTy { impl_trait_fn, .. }) => impl_trait_fn,
+ _ => None,
}
- Some(tcx.hir.local_def_id(parent_id))
- }
+ },
_ => None
};
ItemTy(_, ref generics) |
ItemEnum(_, ref generics) |
ItemStruct(_, ref generics) |
+ ItemExistential(hir::ExistTy { ref generics, .. }) |
ItemUnion(_, ref generics) => {
allow_defaults = true;
generics
}
}
- NodeTy(&hir::Ty { node: hir::TyImplTraitExistential(ref exist_ty, _), .. }) => {
- &exist_ty.generics
+ NodeTy(&hir::Ty { node: hir::TyImplTraitExistential(..), .. }) => {
+ bug!("impl Trait is desugared to existential type items");
}
_ => &no_generics,
let substs = Substs::identity_for_item(tcx, def_id);
tcx.mk_adt(def, substs)
}
+ // this is only reachable once we have named existential types
+ ItemExistential(hir::ExistTy { impl_trait_fn: None, .. }) => unimplemented!(),
+ // existential types desugared from impl Trait
+ ItemExistential(hir::ExistTy { impl_trait_fn: Some(owner), .. }) => {
+ tcx.typeck_tables_of(owner).concrete_existential_types[&def_id]
+ },
ItemTrait(..) | ItemTraitAlias(..) |
ItemMod(..) |
ItemForeignMod(..) |
icx.to_ty(ty)
}
- NodeTy(&hir::Ty { node: TyImplTraitExistential(..), .. }) => {
- let owner = tcx.hir.get_parent_did(node_id);
- let hir_id = tcx.hir.node_to_hir_id(node_id);
- tcx.typeck_tables_of(owner).node_id_to_type(hir_id)
- }
-
x => {
bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
}
}, items));
generics
}
+ ItemExistential(ref exist_ty) => {
+ let substs = Substs::identity_for_item(tcx, def_id);
+ let anon_ty = tcx.mk_anon(def_id, substs);
+
+ // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
+ let bounds = compute_bounds(&icx,
+ anon_ty,
+ &exist_ty.bounds,
+ SizedByDefault::Yes,
+ tcx.def_span(def_id));
+
+ let predicates = bounds.predicates(tcx, anon_ty);
+
+ return ty::GenericPredicates {
+ parent: None,
+ predicates: predicates
+ };
+ }
_ => &no_generics,
}
}
}
- NodeTy(&Ty { node: TyImplTraitExistential(ref exist_ty, _), span, .. }) => {
- let substs = Substs::identity_for_item(tcx, def_id);
- let anon_ty = tcx.mk_anon(def_id, substs);
-
- debug!("explicit_predicates_of: anon_ty={:?}", anon_ty);
-
- // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
- let bounds = compute_bounds(&icx,
- anon_ty,
- &exist_ty.bounds,
- SizedByDefault::Yes,
- span);
-
- debug!("explicit_predicates_of: bounds={:?}", bounds);
-
- let predicates = bounds.predicates(tcx, anon_ty);
-
- debug!("explicit_predicates_of: predicates={:?}", predicates);
-
- return ty::GenericPredicates {
- parent: None,
- predicates: predicates
- };
- }
-
_ => &no_generics,
};
#![feature(slice_sort_by_cached_key)]
#![feature(never_type)]
+#![recursion_limit="256"]
+
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate syntax_pos;
}
}
TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
- TyImplTraitExistential(ref exist_ty, ref _lts) => ImplTrait(exist_ty.bounds.clean(cx)),
+ TyImplTraitExistential(hir_id, _, _) => {
+ match cx.tcx.hir.expect_item(hir_id.id).node {
+ hir::ItemExistential(ref exist_ty) => {
+ ImplTrait(exist_ty.bounds.clean(cx))
+ },
+ ref other => panic!("impl Trait pointed to {:#?}", other),
+ }
+ },
TyInfer | TyErr => Infer,
TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
}
om.impls.push(i);
}
},
+ hir::ItemExistential(_) => {
+ // FIXME(oli-obk): actually generate docs for real existential items
+ }
}
}
/// # Examples
///
/// ```
-/// #![feature(path_ancestors)]
-///
/// use std::path::Path;
///
/// let path = Path::new("/foo/bar");
/// [`ancestors`]: struct.Path.html#method.ancestors
/// [`Path`]: struct.Path.html
#[derive(Copy, Clone, Debug)]
-#[unstable(feature = "path_ancestors", issue = "48581")]
+#[stable(feature = "path_ancestors", since = "1.28.0")]
pub struct Ancestors<'a> {
next: Option<&'a Path>,
}
-#[unstable(feature = "path_ancestors", issue = "48581")]
+#[stable(feature = "path_ancestors", since = "1.28.0")]
impl<'a> Iterator for Ancestors<'a> {
type Item = &'a Path;
}
}
-#[unstable(feature = "path_ancestors", issue = "48581")]
+#[stable(feature = "path_ancestors", since = "1.28.0")]
impl<'a> FusedIterator for Ancestors<'a> {}
////////////////////////////////////////////////////////////////////////////////
/// # Examples
///
/// ```
- /// #![feature(path_ancestors)]
- ///
/// use std::path::Path;
///
/// let mut ancestors = Path::new("/foo/bar").ancestors();
///
/// [`None`]: ../../std/option/enum.Option.html#variant.None
/// [`parent`]: struct.Path.html#method.parent
- #[unstable(feature = "path_ancestors", issue = "48581")]
+ #[stable(feature = "path_ancestors", since = "1.28.0")]
pub fn ancestors(&self) -> Ancestors {
Ancestors {
next: Some(&self),
}
pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
- attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&d.as_str()))
+ if let Some(s) = attr::first_attr_value_str_by_name(attrs, "path") {
+ let s = s.as_str();
+
+ // On windows, the base path might have the form
+ // `\\?\foo\bar` in which case it does not tolerate
+ // mixed `/` and `\` separators, so canonicalize
+ // `/` to `\`.
+ #[cfg(windows)]
+ let s = s.replace("/", "\\");
+ Some(dir_path.join(s))
+ } else {
+ None
+ }
}
/// Returns either a path to a module, or .
Annotatable::Stmt(_) |
Annotatable::Expr(_) => {
ecx.span_err(span, "proc-macro derives may only be \
- applied to struct/enum items");
+ applied to a struct, enum, or union");
return Vec::new()
}
};
match item.node {
ItemKind::Struct(..) |
- ItemKind::Enum(..) => {},
+ ItemKind::Enum(..) |
+ ItemKind::Union(..) => {},
_ => {
ecx.span_err(span, "proc-macro derives may only be \
- applied to struct/enum items");
+ applied to a struct, enum, or union");
return Vec::new()
}
}
DotFill,
QuestionMark,
Catch,
+ /// Desugaring of an `impl Trait` in return type position
+ /// to an `existential type Foo: Trait;` + replacing the
+ /// `impl Trait` with `Foo`.
+ ExistentialReturnType,
}
impl CompilerDesugaringKind {
DotFill => "...",
QuestionMark => "?",
Catch => "do catch",
+ ExistentialReturnType => "existental type",
};
Symbol::intern(s)
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
pub fn change_return_impl_trait() -> impl Copy {
0u32
--- /dev/null
+// Copyright 2012-2014 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.
+
+// Testing that a libsyntax can parse modules with canonicalized base path
+// ignore-cross-compile
+
+#![feature(rustc_private)]
+
+extern crate syntax;
+
+use std::path::Path;
+use syntax::codemap::FilePathMapping;
+use syntax::parse::{self, ParseSess};
+
+#[path = "mod_dir_simple/test.rs"]
+mod gravy;
+
+pub fn main() {
+ syntax::with_globals(|| parse());
+
+ assert_eq!(gravy::foo(), 10);
+}
+
+fn parse() {
+ let parse_session = ParseSess::new(FilePathMapping::empty());
+
+ let path = Path::new(file!());
+ let path = path.canonicalize().unwrap();
+ let mut parser = parse::new_parser_from_file(&parse_session, &path);
+ let _ = parser.parse_crate_mod();
+}
--- /dev/null
+// Copyright 2012 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.
+
+pub fn foo() -> isize { 10 }
--- /dev/null
+// Copyright 2018 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(UnionTest)]
+pub fn derive(input: TokenStream) -> TokenStream {
+ let input = input.to_string();
+ assert!(input.contains("#[repr(C)]"));
+ assert!(input.contains("union Test {"));
+ assert!(input.contains("a: u8,"));
+ assert!(input.contains("}"));
+ "".parse().unwrap()
+}
--- /dev/null
+// Copyright 2018 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.
+
+// aux-build:derive-union.rs
+// ignore-stage1
+
+#[macro_use]
+extern crate derive_union;
+
+#[repr(C)]
+#[derive(UnionTest)]
+union Test {
+ a: u8,
+}
+
+fn main() {
+ let t = Test { a: 0 };
+}
some_internal_fn() + 1
}
}
+
+pub fn return_internal_fn() -> impl Fn() -> u32 {
+ some_internal_fn
+}
--- /dev/null
+// Copyright 2018 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.
+
+pub trait FakeGenerator {
+ type Yield;
+ type Return;
+}
+
+pub trait FakeFuture {
+ type Output;
+}
+
+pub fn future_from_generator<
+ T: FakeGenerator<Yield = ()>
+>(x: T) -> impl FakeFuture<Output = T::Return> {
+ GenFuture(x)
+}
+
+struct GenFuture<T: FakeGenerator<Yield = ()>>(T);
+
+impl<T: FakeGenerator<Yield = ()>> FakeFuture for GenFuture<T> {
+ type Output = T::Return;
+}
+
+fn main() {}
#![feature(fn_traits,
step_trait,
unboxed_closures,
- copy_closures,
- clone_closures
)]
//! Derived from: <https://raw.githubusercontent.com/quickfur/dcal/master/dcal.d>.
--- /dev/null
+// Copyright 2018 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.
+
+fn main() {}
+
+fn foo() -> impl std::fmt::Debug { "cake" }
--- /dev/null
+// Copyright 2018 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.
+
+fn foo<T>(t: T) -> impl Into<[T; { const FOO: usize = 1; FOO }]> {
+ [t]
+}
+
+fn bar() -> impl Into<[u8; { const FOO: usize = 1; FOO }]> {
+ [99]
+}
+
+fn main() {
+ println!("{:?}", foo(42).into());
+ println!("{:?}", bar().into());
+}
--- /dev/null
+// 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.
+
+// aux-build:xcrate.rs
+
+extern crate xcrate;
+
+fn main() {
+ xcrate::return_internal_fn()();
+}
use std::cell::Cell;
use std::rc::Rc;
-// Fast path, main can see the concrete type returned.
-fn before() -> impl Fn(i32) {
- let p = Rc::new(Cell::new(0));
- move |x| p.set(x)
-}
-
fn send<T: Send>(_: T) {}
fn main() {
- send(before());
- //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
-
- send(after());
- //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
-}
-
-// Deferred path, main has to wait until typeck finishes,
-// to check if the return type of after is Send.
-fn after() -> impl Fn(i32) {
- let p = Rc::new(Cell::new(0));
- move |x| p.set(x)
}
// Cycles should work as the deferred obligations are
// return type, which can't depend on the obligation.
fn cycle1() -> impl Clone {
//~^ ERROR cycle detected
+ //~| ERROR cycle detected
send(cycle2().clone());
+ //~^ ERROR Send` is not satisfied
Rc::new(Cell::new(5))
}
-error[E0277]: the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>`
- --> $DIR/auto-trait-leak.rs:25:5
+error[E0391]: cycle detected when processing `cycle1::{{exist-impl-Trait}}`
+ --> $DIR/auto-trait-leak.rs:24:16
|
-LL | send(before());
- | ^^^^ `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
+LL | fn cycle1() -> impl Clone {
+ | ^^^^^^^^^^
|
- = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
- = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:19:5: 19:22 p:std::rc::Rc<std::cell::Cell<i32>>]`
- = note: required because it appears within the type `impl std::ops::Fn<(i32,)>`
-note: required by `send`
- --> $DIR/auto-trait-leak.rs:22:1
+note: ...which requires processing `cycle1`...
+ --> $DIR/auto-trait-leak.rs:24:1
|
-LL | fn send<T: Send>(_: T) {}
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>`
- --> $DIR/auto-trait-leak.rs:28:5
- |
-LL | send(after());
- | ^^^^ `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
+LL | fn cycle1() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
+note: ...which requires processing `cycle2::{{exist-impl-Trait}}`...
+ --> $DIR/auto-trait-leak.rs:33:16
|
- = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
- = note: required because it appears within the type `[closure@$DIR/auto-trait-leak.rs:36:5: 36:22 p:std::rc::Rc<std::cell::Cell<i32>>]`
- = note: required because it appears within the type `impl std::ops::Fn<(i32,)>`
-note: required by `send`
- --> $DIR/auto-trait-leak.rs:22:1
+LL | fn cycle2() -> impl Clone {
+ | ^^^^^^^^^^
+note: ...which requires processing `cycle2`...
+ --> $DIR/auto-trait-leak.rs:33:1
|
-LL | fn send<T: Send>(_: T) {}
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | fn cycle2() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
+ = note: ...which again requires processing `cycle1::{{exist-impl-Trait}}`, completing the cycle
-error[E0391]: cycle detected when processing `cycle1`
- --> $DIR/auto-trait-leak.rs:42:1
+error[E0391]: cycle detected when processing `cycle1::{{exist-impl-Trait}}`
+ --> $DIR/auto-trait-leak.rs:24:16
|
LL | fn cycle1() -> impl Clone {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^
|
+note: ...which requires processing `cycle1`...
+ --> $DIR/auto-trait-leak.rs:24:1
+ |
+LL | fn cycle1() -> impl Clone {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
-note: ...which requires processing `cycle2::{{impl-Trait}}`...
- --> $DIR/auto-trait-leak.rs:49:16
+note: ...which requires processing `cycle2::{{exist-impl-Trait}}`...
+ --> $DIR/auto-trait-leak.rs:33:16
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^
note: ...which requires processing `cycle2`...
- --> $DIR/auto-trait-leak.rs:49:1
+ --> $DIR/auto-trait-leak.rs:33:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
-note: ...which requires processing `cycle1::{{impl-Trait}}`...
- --> $DIR/auto-trait-leak.rs:42:16
+ = note: ...which again requires processing `cycle1::{{exist-impl-Trait}}`, completing the cycle
+
+error[E0277]: the trait bound `std::rc::Rc<std::string::String>: std::marker::Send` is not satisfied in `impl std::clone::Clone`
+ --> $DIR/auto-trait-leak.rs:27:5
|
-LL | fn cycle1() -> impl Clone {
- | ^^^^^^^^^^
- = note: ...which again requires processing `cycle1`, completing the cycle
-note: cycle used when type-checking all item bodies
+LL | send(cycle2().clone());
+ | ^^^^ `std::rc::Rc<std::string::String>` cannot be sent between threads safely
+ |
+ = help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>`
+ = note: required because it appears within the type `impl std::clone::Clone`
+note: required by `send`
+ --> $DIR/auto-trait-leak.rs:16:1
+ |
+LL | fn send<T: Send>(_: T) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
--- /dev/null
+// 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.
+
+// ignore-tidy-linelength
+
+use std::cell::Cell;
+use std::rc::Rc;
+
+// Fast path, main can see the concrete type returned.
+fn before() -> impl Fn(i32) {
+ let p = Rc::new(Cell::new(0));
+ move |x| p.set(x)
+}
+
+fn send<T: Send>(_: T) {}
+
+fn main() {
+ send(before());
+ //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
+
+ send(after());
+ //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
+}
+
+// Deferred path, main has to wait until typeck finishes,
+// to check if the return type of after is Send.
+fn after() -> impl Fn(i32) {
+ let p = Rc::new(Cell::new(0));
+ move |x| p.set(x)
+}
+
--- /dev/null
+error[E0277]: the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>`
+ --> $DIR/auto-trait-leak2.rs:25:5
+ |
+LL | send(before());
+ | ^^^^ `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
+ |
+ = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
+ = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:19:5: 19:22 p:std::rc::Rc<std::cell::Cell<i32>>]`
+ = note: required because it appears within the type `impl std::ops::Fn<(i32,)>`
+note: required by `send`
+ --> $DIR/auto-trait-leak2.rs:22:1
+ |
+LL | fn send<T: Send>(_: T) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>`
+ --> $DIR/auto-trait-leak2.rs:28:5
+ |
+LL | send(after());
+ | ^^^^ `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
+ |
+ = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
+ = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:36:5: 36:22 p:std::rc::Rc<std::cell::Cell<i32>>]`
+ = note: required because it appears within the type `impl std::ops::Fn<(i32,)>`
+note: required by `send`
+ --> $DIR/auto-trait-leak2.rs:22:1
+ |
+LL | fn send<T: Send>(_: T) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
}
fn main() {
- let _: u32 = hide(0_u32);
- //~^ ERROR mismatched types
- //~| expected type `u32`
- //~| found type `impl Foo`
- //~| expected u32, found anonymized type
-
- let _: i32 = Leak::leak(hide(0_i32));
- //~^ ERROR mismatched types
- //~| expected type `i32`
- //~| found type `<impl Foo as Leak>::T`
- //~| expected i32, found associated type
-
- let mut x = (hide(0_u32), hide(0_i32));
- x = (x.1,
- //~^ ERROR mismatched types
- //~| expected u32, found i32
- x.0);
- //~^ ERROR mismatched types
- //~| expected i32, found u32
}
|
= help: the trait `std::ops::Add<impl Foo>` is not implemented for `u32`
-error[E0308]: mismatched types
- --> $DIR/equality.rs:53:18
- |
-LL | let _: u32 = hide(0_u32);
- | ^^^^^^^^^^^ expected u32, found anonymized type
- |
- = note: expected type `u32`
- found type `impl Foo`
-
-error[E0308]: mismatched types
- --> $DIR/equality.rs:59:18
- |
-LL | let _: i32 = Leak::leak(hide(0_i32));
- | ^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found associated type
- |
- = note: expected type `i32`
- found type `<impl Foo as Leak>::T`
-
-error[E0308]: mismatched types
- --> $DIR/equality.rs:66:10
- |
-LL | x = (x.1,
- | ^^^ expected u32, found i32
- |
- = note: expected type `impl Foo` (u32)
- found type `impl Foo` (i32)
-
-error[E0308]: mismatched types
- --> $DIR/equality.rs:69:10
- |
-LL | x.0);
- | ^^^ expected i32, found u32
- |
- = note: expected type `impl Foo` (i32)
- found type `impl Foo` (u32)
-
-error: aborting due to 6 previous errors
+error: aborting due to 2 previous errors
Some errors occurred: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+// 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.
+
+#![feature(specialization)]
+
+trait Foo: Copy + ToString {}
+
+impl<T: Copy + ToString> Foo for T {}
+
+fn hide<T: Foo>(x: T) -> impl Foo {
+ x
+}
+
+trait Leak: Sized {
+ type T;
+ fn leak(self) -> Self::T;
+}
+impl<T> Leak for T {
+ default type T = ();
+ default fn leak(self) -> Self::T { panic!() }
+}
+impl Leak for i32 {
+ type T = i32;
+ fn leak(self) -> i32 { self }
+}
+
+fn main() {
+ let _: u32 = hide(0_u32);
+ //~^ ERROR mismatched types
+ //~| expected type `u32`
+ //~| found type `impl Foo`
+ //~| expected u32, found anonymized type
+
+ let _: i32 = Leak::leak(hide(0_i32));
+ //~^ ERROR mismatched types
+ //~| expected type `i32`
+ //~| found type `<impl Foo as Leak>::T`
+ //~| expected i32, found associated type
+
+ let mut x = (hide(0_u32), hide(0_i32));
+ x = (x.1,
+ //~^ ERROR mismatched types
+ //~| expected u32, found i32
+ x.0);
+ //~^ ERROR mismatched types
+ //~| expected i32, found u32
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/equality2.rs:35:18
+ |
+LL | let _: u32 = hide(0_u32);
+ | ^^^^^^^^^^^ expected u32, found anonymized type
+ |
+ = note: expected type `u32`
+ found type `impl Foo`
+
+error[E0308]: mismatched types
+ --> $DIR/equality2.rs:41:18
+ |
+LL | let _: i32 = Leak::leak(hide(0_i32));
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found associated type
+ |
+ = note: expected type `i32`
+ found type `<impl Foo as Leak>::T`
+
+error[E0308]: mismatched types
+ --> $DIR/equality2.rs:48:10
+ |
+LL | x = (x.1,
+ | ^^^ expected u32, found i32
+ |
+ = note: expected type `impl Foo` (u32)
+ found type `impl Foo` (i32)
+
+error[E0308]: mismatched types
+ --> $DIR/equality2.rs:51:10
+ |
+LL | x.0);
+ | ^^^ expected i32, found u32
+ |
+ = note: expected type `impl Foo` (i32)
+ found type `impl Foo` (u32)
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
|
= note: defining type: DefId(0/1:9 ~ escape_argument_callee[317d]::test[0]::{{closure}}[0]) with closure substs [
i16,
- for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't0)) i32))
+ for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) i32))
]
note: No external requirements
|
= note: defining type: DefId(0/1:9 ~ escape_argument[317d]::test[0]::{{closure}}[0]) with closure substs [
i16,
- for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) i32))
+ for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32))
]
note: No external requirements
|
= note: defining type: DefId(0/1:20 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]::{{closure}}[0]) with closure substs [
i16,
- for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>))
+ for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>))
]
note: No external requirements
|
= note: defining type: DefId(0/1:18 ~ propagate_approximated_ref[317d]::supply[0]::{{closure}}[0]) with closure substs [
i16,
- for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
+ for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
]
= note: number of external vids: 3
= note: where '_#1r: '_#2r
|
= note: defining type: DefId(0/1:12 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]::{{closure}}[0]) with closure substs [
i32,
- for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>))
+ for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>))
]
note: No external requirements
|
= note: defining type: DefId(0/1:13 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]::{{closure}}[0]) with closure substs [
i32,
- for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>))
+ for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>))
]
= note: number of external vids: 2
= note: where '_#1r: '_#0r
|
= note: defining type: DefId(0/1:18 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [
i16,
- for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't1)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't2)) u32>))
+ for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) u32>))
]
= note: number of external vids: 2
= note: where '_#1r: '_#0r
error: free region `ReFree(DefId(0/0:6 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]), BrNamed(crate0:DefIndex(1:16), 'a))` does not outlive free region `ReStatic`
- --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:47
+ --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:5
|
-LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
- | _______________________________________________^
+LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
LL | | //~^ ERROR does not outlive free region
LL | |
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
LL | | });
- | |_____^
+ | |______^
note: No external requirements
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:44:1
|
= note: defining type: DefId(0/1:18 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [
i16,
- for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
+ for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
]
= note: number of external vids: 3
= note: where '_#1r: '_#0r
error: free region `ReFree(DefId(0/0:6 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]), BrNamed(crate0:DefIndex(1:16), 'a))` does not outlive free region `ReStatic`
- --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:47
+ --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:5
|
-LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
- | _______________________________________________^
+LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
LL | | //~^ ERROR does not outlive free region
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
LL | | //~^ WARNING not reporting region error due to nll
LL | | });
- | |_____^
+ | |______^
note: No external requirements
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:47:1
|
= note: defining type: DefId(0/1:18 ~ propagate_approximated_val[317d]::test[0]::{{closure}}[0]) with closure substs [
i16,
- for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>))
+ for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>))
]
= note: number of external vids: 3
= note: where '_#1r: '_#2r
|
= note: defining type: DefId(0/1:16 ~ propagate_despite_same_free_region[317d]::supply[0]::{{closure}}[0]) with closure substs [
i16,
- for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>))
+ for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>))
]
= note: number of external vids: 3
= note: where '_#1r: '_#2r
|
= note: defining type: DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [
i16,
- for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>))
+ for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>))
]
note: No external requirements
|
= note: defining type: DefId(0/1:18 ~ propagate_fail_to_approximate_longer_wrong_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [
i16,
- for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
+ for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
]
note: No external requirements
|
= note: defining type: DefId(0/1:9 ~ return_wrong_bound_region[317d]::test[0]::{{closure}}[0]) with closure substs [
i16,
- for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) i32, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) i32)) -> &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) i32
+ for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) i32
]
note: No external requirements
= note: defining type: DefId(0/1:14 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]::{{closure}}[0]) with closure substs [
T,
i16,
- for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) T))
+ for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) T))
]
= note: number of external vids: 2
= note: where T: '_#1r
= note: defining type: DefId(0/1:17 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [
T,
i16,
- for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex { index: 0 }, BrNamed(crate0:DefIndex(0:0), 's)) T))
+ for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) T))
]
= note: number of external vids: 2
= note: where T: '_#1r