提交 862703e0 编写于 作者: B bors

Auto merge of #51414 - oli-obk:impl_trait_type_def, r=pnkfelix

Add existential type definitions

Note: this does not allow creating named existential types, it just desugars `impl Trait` to a less (but still very) hacky version of actual `existential type` items.

r? @nikomatsakis
......@@ -37,6 +37,7 @@ pub enum Def {
Enum(DefId),
Variant(DefId),
Trait(DefId),
Existential(DefId),
TyAlias(DefId),
TyForeign(DefId),
TraitAlias(DefId),
......@@ -234,6 +235,7 @@ pub fn def_id(&self) -> 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
}
......@@ -260,6 +262,7 @@ pub fn kind_name(&self) -> &'static str {
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",
......
......@@ -502,6 +502,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
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
......@@ -596,10 +604,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
}
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) => {
......
......@@ -182,7 +182,9 @@ enum ImplTraitContext {
/// 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,
......@@ -238,6 +240,7 @@ enum ParamMode {
Optional,
}
#[derive(Debug)]
struct LoweredNodeId {
node_id: NodeId,
hir_id: hir::HirId,
......@@ -488,16 +491,16 @@ fn lower_node_id_generic<F>(&mut self, ast_node_id: NodeId, alloc_hir_id: F) ->
}
}
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);
......@@ -507,6 +510,7 @@ fn with_hir_id_owner<F>(&mut self, owner: NodeId, f: F)
.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
......@@ -530,7 +534,10 @@ fn lower_node_id(&mut self, ast_node_id: NodeId) -> LoweredNodeId {
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
......@@ -539,7 +546,12 @@ fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> Lo
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,
......@@ -1120,26 +1132,93 @@ fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> P<hir::Ty> {
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;
......@@ -1148,7 +1227,7 @@ fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> P<hir::Ty> {
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,
......@@ -1203,6 +1282,7 @@ fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> P<hir::Ty> {
fn lifetimes_from_impl_trait_bounds(
&mut self,
exist_ty_id: NodeId,
parent_index: DefIndex,
bounds: &hir::TyParamBounds,
) -> (HirVec<hir::Lifetime>, HirVec<hir::GenericParam>) {
......@@ -1212,6 +1292,7 @@ fn lifetimes_from_impl_trait_bounds(
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>,
......@@ -1306,7 +1387,11 @@ fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
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,
......@@ -1318,7 +1403,7 @@ fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
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 {
......@@ -1334,6 +1419,7 @@ fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
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(),
......@@ -1772,8 +1858,8 @@ fn lower_fn_decl(
.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)),
},
......
......@@ -88,7 +88,7 @@ fn visit_item(&mut self, i: &'a Item) {
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()),
......@@ -256,9 +256,6 @@ fn visit_expr(&mut self, expr: &'a Expr) {
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);
......
......@@ -210,30 +210,9 @@ fn compute_stable_hash(&self, parent_hash: DefPathHash) -> DefPathHash {
} = 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);
......@@ -390,8 +369,10 @@ pub enum DefPathData {
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
......@@ -655,7 +636,8 @@ pub fn get_opt_name(&self) -> Option<InternedString> {
ClosureExpr |
StructCtor |
AnonConst |
ImplTrait => None
ExistentialImplTrait |
UniversalImplTrait => None
}
}
......@@ -685,7 +667,8 @@ pub fn as_interned_str(&self) -> InternedString {
ClosureExpr => "{{closure}}",
StructCtor => "{{constructor}}",
AnonConst => "{{constant}}",
ImplTrait => "{{impl-Trait}}",
ExistentialImplTrait => "{{exist-impl-Trait}}",
UniversalImplTrait => "{{univ-impl-Trait}}",
};
Symbol::intern(s).as_interned_str()
......
......@@ -96,7 +96,7 @@ fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self,
.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
......@@ -113,6 +113,8 @@ fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self,
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
......@@ -121,7 +123,7 @@ fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self,
.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,
......@@ -146,7 +148,7 @@ fn nested_visit_map<'this>(&'this mut self)
}
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 {
......
......@@ -398,6 +398,7 @@ pub fn describe_def(&self, node_id: NodeId) -> Option<Def> {
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())),
......@@ -767,7 +768,7 @@ pub fn get_return_block(&self, id: NodeId) -> Option<NodeId> {
/// 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 {
......@@ -1250,6 +1251,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
ItemForeignMod(..) => "foreign mod",
ItemGlobalAsm(..) => "global asm",
ItemTy(..) => "ty",
ItemExistential(..) => "existential",
ItemEnum(..) => "enum",
ItemStruct(..) => "struct",
ItemUnion(..) => "union",
......
......@@ -1693,6 +1693,7 @@ pub struct BareFnTy {
pub struct ExistTy {
pub generics: Generics,
pub bounds: TyParamBounds,
pub impl_trait_fn: Option<DefId>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
......@@ -1723,15 +1724,15 @@ pub enum Ty_ {
/// 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
......@@ -2091,6 +2092,8 @@ pub enum Item_ {
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}`
......@@ -2124,6 +2127,7 @@ pub fn descriptive_variant(&self) -> &str {
ItemForeignMod(..) => "foreign module",
ItemGlobalAsm(..) => "global asm",
ItemTy(..) => "type alias",
ItemExistential(..) => "existential type",
ItemEnum(..) => "enum",
ItemStruct(..) => "struct",
ItemUnion(..) => "union",
......
......@@ -58,6 +58,9 @@ fn pre(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> {
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;
......@@ -65,6 +68,9 @@ impl PpAnn for 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)),
......@@ -413,8 +419,14 @@ pub fn print_type(&mut self, ty: &hir::Ty) -> io::Result<()> {
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("[")?;
......@@ -636,6 +648,31 @@ pub fn print_item(&mut self, item: &hir::Item) -> io::Result<()> {
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)?;
}
......
......@@ -310,6 +310,7 @@ fn hash_stable<W: StableHasherResult>(&self,
impl_stable_hash_for!(struct hir::ExistTy {
generics,
impl_trait_fn,
bounds
});
......@@ -323,7 +324,7 @@ fn hash_stable<W: StableHasherResult>(&self,
TyTup(ts),
TyPath(qpath),
TyTraitObject(trait_refs, lifetime),
TyImplTraitExistential(existty, lifetimes),
TyImplTraitExistential(existty, def_id, lifetimes),
TyTypeof(body_id),
TyErr,
TyInfer
......@@ -889,6 +890,7 @@ fn hash_stable<W: StableHasherResult>(&self,
ItemForeignMod(foreign_mod),
ItemGlobalAsm(global_asm),
ItemTy(ty, generics),
ItemExistential(exist),
ItemEnum(enum_def, generics),
ItemStruct(variant_data, generics),
ItemUnion(variant_data, generics),
......@@ -1046,6 +1048,7 @@ fn hash_stable<W: StableHasherResult>(&self,
Struct(def_id),
Union(def_id),
Enum(def_id),
Existential(def_id),
Variant(def_id),
Trait(def_id),
TyAlias(def_id),
......
......@@ -411,6 +411,7 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>(
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
DotFill,
QuestionMark,
ExistentialReturnType,
Catch
});
......
......@@ -9,6 +9,7 @@
// 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;
......@@ -689,8 +690,16 @@ fn instantiate_anon_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) ->
// }
// ```
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);
}
......
......@@ -267,6 +267,7 @@ fn propagate_node(&mut self, node: &hir_map::Node<'tcx>,
// 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(..) |
......
......@@ -499,7 +499,13 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
};
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)
......@@ -613,7 +619,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
};
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
......@@ -655,10 +661,13 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
// `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.
......
......@@ -123,6 +123,11 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
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
......
......@@ -427,6 +427,10 @@ pub struct TypeckTables<'tcx> {
/// 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> {
......@@ -449,6 +453,7 @@ pub fn empty(local_id_root: Option<DefId>) -> TypeckTables<'tcx> {
used_trait_imports: Lrc::new(DefIdSet()),
tainted_by_errors: false,
free_region_map: FreeRegionMap::new(),
concrete_existential_types: FxHashMap(),
}
}
......@@ -746,6 +751,7 @@ fn hash_stable<W: StableHasherResult>(&self,
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| {
......@@ -786,6 +792,7 @@ fn hash_stable<W: StableHasherResult>(&self,
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);
})
}
}
......
......@@ -221,7 +221,8 @@ pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId)
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);
......
......@@ -2857,6 +2857,12 @@ fn trait_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option
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);
......
......@@ -291,7 +291,8 @@ fn parameterized<F: fmt::Write>(&mut self,
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
......
......@@ -256,6 +256,7 @@ fn search(this: &Env, it: &hir::Item, idx: usize, names: &[String]) -> Option<as
hir::ItemFn(..) |
hir::ItemForeignMod(..) |
hir::ItemGlobalAsm(..) |
hir::ItemExistential(..) |
hir::ItemTy(..) => None,
hir::ItemEnum(..) |
......
......@@ -419,6 +419,7 @@ fn to_def(&self, did: DefId) -> Option<Def> {
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),
......
......@@ -1060,6 +1060,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
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();
......@@ -1187,6 +1188,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
hir::ItemConst(..) |
hir::ItemFn(..) |
hir::ItemTy(..) |
hir::ItemExistential(..) |
hir::ItemEnum(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) |
......@@ -1210,6 +1212,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemImpl(..) |
hir::ItemExistential(..) |
hir::ItemTrait(..) => Some(self.encode_generics(def_id)),
_ => None,
},
......@@ -1222,6 +1225,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemImpl(..) |
hir::ItemExistential(..) |
hir::ItemTrait(..) => Some(self.encode_predicates(def_id)),
_ => None,
},
......@@ -1301,28 +1305,6 @@ fn encode_info_for_ty_param(&mut self,
}
}
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;
......@@ -1672,10 +1654,6 @@ fn encode_info_for_generics(&mut self, generics: &hir::Generics) {
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);
......@@ -1710,6 +1688,7 @@ fn encode_addl_info_for_item(&mut self, item: &hir::Item) {
hir::ItemExternCrate(..) |
hir::ItemUse(..) |
hir::ItemTy(..) |
hir::ItemExistential(..) |
hir::ItemTraitAlias(..) => {
// no sub-item recording needed in these cases
}
......
......@@ -304,6 +304,7 @@ pub enum EntryKind<'tcx> {
ForeignType,
GlobalAsm,
Type,
Existential,
Enum(ReprOptions),
Field,
Variant(Lazy<VariantData<'tcx>>),
......@@ -336,6 +337,7 @@ fn hash_stable<W: StableHasherResult>(&self,
EntryKind::GlobalAsm |
EntryKind::ForeignType |
EntryKind::Field |
EntryKind::Existential |
EntryKind::Type => {
// Nothing else to hash here.
}
......
......@@ -944,6 +944,7 @@ fn visit_item(&mut self, item: &'v hir::Item) {
hir::ItemTy(..) |
hir::ItemTrait(..) |
hir::ItemTraitAlias(..) |
hir::ItemExistential(..) |
hir::ItemMod(..) => {
// Nothing to do, just keep recursing...
}
......
......@@ -160,6 +160,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
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 }
}
......@@ -212,6 +213,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
}
}
}
hir::ItemExistential(..) |
hir::ItemUse(..) | hir::ItemStatic(..) | hir::ItemConst(..) |
hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemMod(..) | hir::ItemTraitAlias(..) |
hir::ItemFn(..) | hir::ItemExternCrate(..) => {}
......@@ -227,6 +229,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
hir::ItemUse(..) => {}
// The interface is empty
hir::ItemGlobalAsm(..) => {}
// Checked by visit_ty
hir::ItemExistential(..) => {}
// Visit everything
hir::ItemConst(..) | hir::ItemStatic(..) |
hir::ItemFn(..) | hir::ItemTy(..) => {
......@@ -388,10 +392,10 @@ fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
}
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();
}
}
......@@ -436,6 +440,10 @@ fn predicates(&mut self) -> &mut Self {
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 {
......@@ -1546,6 +1554,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
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(..) => {
......@@ -1644,13 +1654,14 @@ fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) {
}
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);
......
......@@ -205,6 +205,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
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")
......
......@@ -749,6 +749,7 @@ fn fn_type(path: &ast::Path) -> bool {
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 {
......
......@@ -1118,8 +1118,7 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
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)) => {
......@@ -1171,9 +1170,14 @@ pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
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);
......@@ -1198,7 +1202,9 @@ pub fn impl_trait_ty_to_ty(&self, def_id: DefId, lifetimes: &[hir::Lifetime]) ->
});
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,
......
......@@ -1013,7 +1013,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
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);
......
......@@ -43,7 +43,7 @@ pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) -> &'gcx ty::Type
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();
......@@ -385,18 +385,28 @@ fn visit_user_provided_tys(&mut self) {
}
}
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,
);
}
}
}
}
......
......@@ -131,15 +131,6 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
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);
......@@ -420,6 +411,7 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) {
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);
......@@ -803,18 +795,12 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
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
};
......@@ -835,6 +821,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ItemTy(_, ref generics) |
ItemEnum(_, ref generics) |
ItemStruct(_, ref generics) |
ItemExistential(hir::ExistTy { ref generics, .. }) |
ItemUnion(_, ref generics) => {
allow_defaults = true;
generics
......@@ -875,8 +862,8 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
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,
......@@ -1056,6 +1043,12 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
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(..) |
......@@ -1130,12 +1123,6 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
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);
}
......@@ -1353,6 +1340,24 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}, 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,
}
......@@ -1366,31 +1371,6 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
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,
};
......
......@@ -2939,7 +2939,14 @@ fn clean(&self, cx: &DocContext) -> Type {
}
}
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),
}
......
......@@ -564,6 +564,9 @@ pub fn visit_item(&mut self, item: &hir::Item,
om.impls.push(i);
}
},
hir::ItemExistential(_) => {
// FIXME(oli-obk): actually generate docs for real existential items
}
}
}
......
......@@ -489,6 +489,10 @@ pub enum CompilerDesugaringKind {
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 {
......@@ -498,6 +502,7 @@ pub fn as_symbol(&self) -> Symbol {
DotFill => "...",
QuestionMark => "?",
Catch => "do catch",
ExistentialReturnType => "existental type",
};
Symbol::intern(s)
}
......
......@@ -284,7 +284,7 @@ pub fn change_return_impl_trait() -> impl Clone {
}
#[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
......
......@@ -23,3 +23,7 @@ pub fn return_closure_accessing_internal_fn() -> impl Fn() -> u32 {
some_internal_fn() + 1
}
}
pub fn return_internal_fn() -> impl Fn() -> u32 {
some_internal_fn
}
// 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() {}
......@@ -14,8 +14,6 @@
#![feature(fn_traits,
step_trait,
unboxed_closures,
copy_closures,
clone_closures
)]
//! Derived from: <https://raw.githubusercontent.com/quickfur/dcal/master/dcal.d>.
......
// 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" }
// 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());
}
// 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()();
}
......@@ -13,27 +13,9 @@
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
......@@ -41,7 +23,9 @@ fn after() -> impl Fn(i32) {
// 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
......
// 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)
}
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`.
......@@ -50,23 +50,4 @@ 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
}
......@@ -15,43 +15,7 @@ LL | n + sum_to(n - 1)
|
= 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`.
// 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
}
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`.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册