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())),
pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
match self.get(id) {
NodeItem(&Item { node: ItemTrait(..), .. }) => id,
+ NodeItem(&Item {
+ node: ItemExistential(ExistTy {
+ impl_trait_fn: Some(did),
+ ..
+ }), ..
+ }) => self.def_index_to_node_id(did.index),
NodeTyParam(_) => self.get_parent_node(id),
_ => {
bug!("ty_param_owner: {} not a type parameter",
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);
}
// 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(..) |
};
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.
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);
})
}
}
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);
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
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.
}
hir::ItemEnum(_, ref generics) |
hir::ItemStruct(_, ref generics) |
+ hir::ItemExistential(hir::ExistTy { ref generics, .. }) |
hir::ItemUnion(_, ref generics) => {
if generics.params.is_empty() {
if self.mode == MonoItemCollectionMode::Eager {
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,
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);
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: parent_did, .. }) => parent_did,
+ _ => 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);
+
+ debug!("explicit_predicates_of: predicates={:?}", predicates);
+
+ 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,
};
}
}
TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
- TyImplTraitExistential(ref exist_ty, ref _lts) => ImplTrait(exist_ty.bounds.clean(cx)),
+ TyImplTraitExistential(ref exist_ty, _, _) => ImplTrait(exist_ty.bounds.clean(cx)),
TyInfer | TyErr => Infer,
TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
}
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
some_internal_fn() + 1
}
}
+
+pub fn return_internal_fn() -> impl Fn() -> u32 {
+ some_internal_fn
+}
#![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 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`.