Implement existential types
This commit is contained in:
parent
1c84d81873
commit
53d2ebb0ad
182 changed files with 1389 additions and 121 deletions
|
@ -37,11 +37,15 @@ pub enum Def {
|
||||||
Enum(DefId),
|
Enum(DefId),
|
||||||
Variant(DefId),
|
Variant(DefId),
|
||||||
Trait(DefId),
|
Trait(DefId),
|
||||||
|
/// `existential type Foo: Bar;`
|
||||||
Existential(DefId),
|
Existential(DefId),
|
||||||
|
/// `type Foo = Bar;`
|
||||||
TyAlias(DefId),
|
TyAlias(DefId),
|
||||||
TyForeign(DefId),
|
TyForeign(DefId),
|
||||||
TraitAlias(DefId),
|
TraitAlias(DefId),
|
||||||
AssociatedTy(DefId),
|
AssociatedTy(DefId),
|
||||||
|
/// `existential type Foo: Bar;`
|
||||||
|
AssociatedExistential(DefId),
|
||||||
PrimTy(hir::PrimTy),
|
PrimTy(hir::PrimTy),
|
||||||
TyParam(DefId),
|
TyParam(DefId),
|
||||||
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
|
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
|
||||||
|
@ -245,7 +249,7 @@ impl Def {
|
||||||
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
|
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::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
|
||||||
Def::AssociatedConst(id) | Def::Macro(id, ..) |
|
Def::AssociatedConst(id) | Def::Macro(id, ..) |
|
||||||
Def::Existential(id) |
|
Def::Existential(id) | Def::AssociatedExistential(id) |
|
||||||
Def::GlobalAsm(id) | Def::TyForeign(id) => {
|
Def::GlobalAsm(id) | Def::TyForeign(id) => {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
@ -276,6 +280,7 @@ impl Def {
|
||||||
Def::TyAlias(..) => "type alias",
|
Def::TyAlias(..) => "type alias",
|
||||||
Def::TraitAlias(..) => "trait alias",
|
Def::TraitAlias(..) => "trait alias",
|
||||||
Def::AssociatedTy(..) => "associated type",
|
Def::AssociatedTy(..) => "associated type",
|
||||||
|
Def::AssociatedExistential(..) => "associated existential type",
|
||||||
Def::Struct(..) => "struct",
|
Def::Struct(..) => "struct",
|
||||||
Def::StructCtor(.., CtorKind::Fn) => "tuple struct",
|
Def::StructCtor(.., CtorKind::Fn) => "tuple struct",
|
||||||
Def::StructCtor(.., CtorKind::Const) => "unit struct",
|
Def::StructCtor(.., CtorKind::Const) => "unit struct",
|
||||||
|
|
|
@ -907,6 +907,10 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
|
||||||
visitor.visit_id(impl_item.id);
|
visitor.visit_id(impl_item.id);
|
||||||
visitor.visit_ty(ty);
|
visitor.visit_ty(ty);
|
||||||
}
|
}
|
||||||
|
ImplItemKind::Existential(ref bounds) => {
|
||||||
|
visitor.visit_id(impl_item.id);
|
||||||
|
walk_list!(visitor, visit_param_bound, bounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -323,6 +323,7 @@ impl<'a> LoweringContext<'a> {
|
||||||
| ItemKind::Union(_, ref generics)
|
| ItemKind::Union(_, ref generics)
|
||||||
| ItemKind::Enum(_, ref generics)
|
| ItemKind::Enum(_, ref generics)
|
||||||
| ItemKind::Ty(_, ref generics)
|
| ItemKind::Ty(_, ref generics)
|
||||||
|
| ItemKind::Existential(_, ref generics)
|
||||||
| ItemKind::Trait(_, _, ref generics, ..) => {
|
| ItemKind::Trait(_, _, ref generics, ..) => {
|
||||||
let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
|
let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
|
||||||
let count = generics
|
let count = generics
|
||||||
|
@ -2632,6 +2633,11 @@ impl<'a> LoweringContext<'a> {
|
||||||
self.lower_ty(t, ImplTraitContext::Disallowed),
|
self.lower_ty(t, ImplTraitContext::Disallowed),
|
||||||
self.lower_generics(generics, ImplTraitContext::Disallowed),
|
self.lower_generics(generics, ImplTraitContext::Disallowed),
|
||||||
),
|
),
|
||||||
|
ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(hir::ExistTy {
|
||||||
|
generics: self.lower_generics(generics, ImplTraitContext::Disallowed),
|
||||||
|
bounds: self.lower_param_bounds(b, ImplTraitContext::Disallowed),
|
||||||
|
impl_trait_fn: None,
|
||||||
|
}),
|
||||||
ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
|
ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
|
||||||
hir::EnumDef {
|
hir::EnumDef {
|
||||||
variants: enum_definition
|
variants: enum_definition
|
||||||
|
@ -3037,6 +3043,12 @@ impl<'a> LoweringContext<'a> {
|
||||||
self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
|
self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
|
||||||
hir::ImplItemKind::Type(self.lower_ty(ty, ImplTraitContext::Disallowed)),
|
hir::ImplItemKind::Type(self.lower_ty(ty, ImplTraitContext::Disallowed)),
|
||||||
),
|
),
|
||||||
|
ImplItemKind::Existential(ref bounds) => (
|
||||||
|
self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
|
||||||
|
hir::ImplItemKind::Existential(
|
||||||
|
self.lower_param_bounds(bounds, ImplTraitContext::Disallowed),
|
||||||
|
),
|
||||||
|
),
|
||||||
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
|
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3065,6 +3077,7 @@ impl<'a> LoweringContext<'a> {
|
||||||
kind: match i.node {
|
kind: match i.node {
|
||||||
ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
|
ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
|
||||||
ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
|
ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
|
||||||
|
ImplItemKind::Existential(..) => hir::AssociatedItemKind::Existential,
|
||||||
ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
|
ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
|
||||||
has_self: sig.decl.has_self(),
|
has_self: sig.decl.has_self(),
|
||||||
},
|
},
|
||||||
|
@ -4331,7 +4344,7 @@ impl<'a> LoweringContext<'a> {
|
||||||
respan(v.span, node)
|
respan(v.span, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_defaultness(&mut self, d: Defaultness, has_value: bool) -> hir::Defaultness {
|
fn lower_defaultness(&self, d: Defaultness, has_value: bool) -> hir::Defaultness {
|
||||||
match d {
|
match d {
|
||||||
Defaultness::Default => hir::Defaultness::Default {
|
Defaultness::Default => hir::Defaultness::Default {
|
||||||
has_value: has_value,
|
has_value: has_value,
|
||||||
|
|
|
@ -116,7 +116,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
||||||
ItemKind::Impl(..) => DefPathData::Impl,
|
ItemKind::Impl(..) => DefPathData::Impl,
|
||||||
ItemKind::Trait(..) => DefPathData::Trait(i.ident.as_interned_str()),
|
ItemKind::Trait(..) => DefPathData::Trait(i.ident.as_interned_str()),
|
||||||
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) |
|
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) |
|
||||||
ItemKind::TraitAlias(..) |
|
ItemKind::TraitAlias(..) | ItemKind::Existential(..) |
|
||||||
ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
|
ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
|
||||||
DefPathData::TypeNs(i.ident.as_interned_str()),
|
DefPathData::TypeNs(i.ident.as_interned_str()),
|
||||||
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
|
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
|
||||||
|
@ -250,6 +250,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
||||||
ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
|
ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
|
||||||
DefPathData::ValueNs(ii.ident.as_interned_str()),
|
DefPathData::ValueNs(ii.ident.as_interned_str()),
|
||||||
ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.as_interned_str()),
|
ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.as_interned_str()),
|
||||||
|
ImplItemKind::Existential(..) => {
|
||||||
|
DefPathData::AssocExistentialInImpl(ii.ident.as_interned_str())
|
||||||
|
},
|
||||||
ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id),
|
ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -330,6 +330,8 @@ pub enum DefPathData {
|
||||||
AssocTypeInTrait(InternedString),
|
AssocTypeInTrait(InternedString),
|
||||||
/// An associated type **value** (i.e., in an impl)
|
/// An associated type **value** (i.e., in an impl)
|
||||||
AssocTypeInImpl(InternedString),
|
AssocTypeInImpl(InternedString),
|
||||||
|
/// An existential associated type **value** (i.e., in an impl)
|
||||||
|
AssocExistentialInImpl(InternedString),
|
||||||
/// Something in the type NS
|
/// Something in the type NS
|
||||||
TypeNs(InternedString),
|
TypeNs(InternedString),
|
||||||
/// Something in the value NS
|
/// Something in the value NS
|
||||||
|
@ -605,6 +607,7 @@ impl DefPathData {
|
||||||
Trait(name) |
|
Trait(name) |
|
||||||
AssocTypeInTrait(name) |
|
AssocTypeInTrait(name) |
|
||||||
AssocTypeInImpl(name) |
|
AssocTypeInImpl(name) |
|
||||||
|
AssocExistentialInImpl(name) |
|
||||||
ValueNs(name) |
|
ValueNs(name) |
|
||||||
Module(name) |
|
Module(name) |
|
||||||
MacroDef(name) |
|
MacroDef(name) |
|
||||||
|
@ -631,6 +634,7 @@ impl DefPathData {
|
||||||
Trait(name) |
|
Trait(name) |
|
||||||
AssocTypeInTrait(name) |
|
AssocTypeInTrait(name) |
|
||||||
AssocTypeInImpl(name) |
|
AssocTypeInImpl(name) |
|
||||||
|
AssocExistentialInImpl(name) |
|
||||||
ValueNs(name) |
|
ValueNs(name) |
|
||||||
Module(name) |
|
Module(name) |
|
||||||
MacroDef(name) |
|
MacroDef(name) |
|
||||||
|
|
|
@ -470,6 +470,7 @@ impl<'hir> Map<'hir> {
|
||||||
ImplItemKind::Const(..) => Some(Def::AssociatedConst(def_id)),
|
ImplItemKind::Const(..) => Some(Def::AssociatedConst(def_id)),
|
||||||
ImplItemKind::Method(..) => Some(Def::Method(def_id)),
|
ImplItemKind::Method(..) => Some(Def::Method(def_id)),
|
||||||
ImplItemKind::Type(..) => Some(Def::AssociatedTy(def_id)),
|
ImplItemKind::Type(..) => Some(Def::AssociatedTy(def_id)),
|
||||||
|
ImplItemKind::Existential(..) => Some(Def::AssociatedExistential(def_id)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeVariant(variant) => {
|
NodeVariant(variant) => {
|
||||||
|
@ -1323,7 +1324,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
|
||||||
ItemKind::ForeignMod(..) => "foreign mod",
|
ItemKind::ForeignMod(..) => "foreign mod",
|
||||||
ItemKind::GlobalAsm(..) => "global asm",
|
ItemKind::GlobalAsm(..) => "global asm",
|
||||||
ItemKind::Ty(..) => "ty",
|
ItemKind::Ty(..) => "ty",
|
||||||
ItemKind::Existential(..) => "existential",
|
ItemKind::Existential(..) => "existential type",
|
||||||
ItemKind::Enum(..) => "enum",
|
ItemKind::Enum(..) => "enum",
|
||||||
ItemKind::Struct(..) => "struct",
|
ItemKind::Struct(..) => "struct",
|
||||||
ItemKind::Union(..) => "union",
|
ItemKind::Union(..) => "union",
|
||||||
|
@ -1347,6 +1348,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
|
||||||
ImplItemKind::Type(_) => {
|
ImplItemKind::Type(_) => {
|
||||||
format!("assoc type {} in {}{}", ii.ident, path_str(), id_str)
|
format!("assoc type {} in {}{}", ii.ident, path_str(), id_str)
|
||||||
}
|
}
|
||||||
|
ImplItemKind::Existential(_) => {
|
||||||
|
format!("assoc existential type {} in {}{}", ii.ident, path_str(), id_str)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(NodeTraitItem(ti)) => {
|
Some(NodeTraitItem(ti)) => {
|
||||||
|
|
|
@ -1620,6 +1620,8 @@ pub enum ImplItemKind {
|
||||||
Method(MethodSig, BodyId),
|
Method(MethodSig, BodyId),
|
||||||
/// An associated type
|
/// An associated type
|
||||||
Type(P<Ty>),
|
Type(P<Ty>),
|
||||||
|
/// An associated existential type
|
||||||
|
Existential(GenericBounds),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind a type to an associated type: `A=Foo`.
|
// Bind a type to an associated type: `A=Foo`.
|
||||||
|
@ -2080,7 +2082,7 @@ pub enum ItemKind {
|
||||||
GlobalAsm(P<GlobalAsm>),
|
GlobalAsm(P<GlobalAsm>),
|
||||||
/// A type alias, e.g. `type Foo = Bar<u8>`
|
/// A type alias, e.g. `type Foo = Bar<u8>`
|
||||||
Ty(P<Ty>, Generics),
|
Ty(P<Ty>, Generics),
|
||||||
/// A type alias, e.g. `type Foo = Bar<u8>`
|
/// An existential type definition, e.g. `existential type Foo: Bar;`
|
||||||
Existential(ExistTy),
|
Existential(ExistTy),
|
||||||
/// An enum definition, e.g. `enum Foo<A, B> {C<A>, D<B>}`
|
/// An enum definition, e.g. `enum Foo<A, B> {C<A>, D<B>}`
|
||||||
Enum(EnumDef, Generics),
|
Enum(EnumDef, Generics),
|
||||||
|
@ -2138,6 +2140,7 @@ impl ItemKind {
|
||||||
Some(match *self {
|
Some(match *self {
|
||||||
ItemKind::Fn(_, _, ref generics, _) |
|
ItemKind::Fn(_, _, ref generics, _) |
|
||||||
ItemKind::Ty(_, ref generics) |
|
ItemKind::Ty(_, ref generics) |
|
||||||
|
ItemKind::Existential(ExistTy { ref generics, impl_trait_fn: None, .. }) |
|
||||||
ItemKind::Enum(_, ref generics) |
|
ItemKind::Enum(_, ref generics) |
|
||||||
ItemKind::Struct(_, ref generics) |
|
ItemKind::Struct(_, ref generics) |
|
||||||
ItemKind::Union(_, ref generics) |
|
ItemKind::Union(_, ref generics) |
|
||||||
|
@ -2184,6 +2187,7 @@ pub enum AssociatedItemKind {
|
||||||
Const,
|
Const,
|
||||||
Method { has_self: bool },
|
Method { has_self: bool },
|
||||||
Type,
|
Type,
|
||||||
|
Existential,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||||
|
|
|
@ -627,9 +627,7 @@ impl<'a> State<'a> {
|
||||||
self.end()?
|
self.end()?
|
||||||
}
|
}
|
||||||
hir::ItemKind::Ty(ref ty, ref generics) => {
|
hir::ItemKind::Ty(ref ty, ref generics) => {
|
||||||
self.ibox(indent_unit)?;
|
self.head(&visibility_qualified(&item.vis, "type"))?;
|
||||||
self.ibox(0)?;
|
|
||||||
self.word_nbsp(&visibility_qualified(&item.vis, "type"))?;
|
|
||||||
self.print_name(item.name)?;
|
self.print_name(item.name)?;
|
||||||
self.print_generic_params(&generics.params)?;
|
self.print_generic_params(&generics.params)?;
|
||||||
self.end()?; // end the inner ibox
|
self.end()?; // end the inner ibox
|
||||||
|
@ -642,9 +640,7 @@ impl<'a> State<'a> {
|
||||||
self.end()?; // end the outer ibox
|
self.end()?; // end the outer ibox
|
||||||
}
|
}
|
||||||
hir::ItemKind::Existential(ref exist) => {
|
hir::ItemKind::Existential(ref exist) => {
|
||||||
self.ibox(indent_unit)?;
|
self.head(&visibility_qualified(&item.vis, "existential type"))?;
|
||||||
self.ibox(0)?;
|
|
||||||
self.word_nbsp(&visibility_qualified(&item.vis, "existential type"))?;
|
|
||||||
self.print_name(item.name)?;
|
self.print_name(item.name)?;
|
||||||
self.print_generic_params(&exist.generics.params)?;
|
self.print_generic_params(&exist.generics.params)?;
|
||||||
self.end()?; // end the inner ibox
|
self.end()?; // end the inner ibox
|
||||||
|
@ -994,6 +990,10 @@ impl<'a> State<'a> {
|
||||||
hir::ImplItemKind::Type(ref ty) => {
|
hir::ImplItemKind::Type(ref ty) => {
|
||||||
self.print_associated_type(ii.ident, None, Some(ty))?;
|
self.print_associated_type(ii.ident, None, Some(ty))?;
|
||||||
}
|
}
|
||||||
|
hir::ImplItemKind::Existential(ref bounds) => {
|
||||||
|
self.word_space("existential")?;
|
||||||
|
self.print_associated_type(ii.ident, Some(bounds), None)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.ann.post(self, NodeSubItem(ii.id))
|
self.ann.post(self, NodeSubItem(ii.id))
|
||||||
}
|
}
|
||||||
|
|
|
@ -701,6 +701,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::ImplItem {
|
||||||
impl_stable_hash_for!(enum hir::ImplItemKind {
|
impl_stable_hash_for!(enum hir::ImplItemKind {
|
||||||
Const(t, body),
|
Const(t, body),
|
||||||
Method(sig, body),
|
Method(sig, body),
|
||||||
|
Existential(bounds),
|
||||||
Type(t)
|
Type(t)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -890,6 +891,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::AssociatedItemKind {
|
||||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||||
match *self {
|
match *self {
|
||||||
hir::AssociatedItemKind::Const |
|
hir::AssociatedItemKind::Const |
|
||||||
|
hir::AssociatedItemKind::Existential |
|
||||||
hir::AssociatedItemKind::Type => {
|
hir::AssociatedItemKind::Type => {
|
||||||
// No fields to hash.
|
// No fields to hash.
|
||||||
}
|
}
|
||||||
|
@ -997,6 +999,7 @@ impl_stable_hash_for!(enum hir::def::Def {
|
||||||
TyAlias(def_id),
|
TyAlias(def_id),
|
||||||
TraitAlias(def_id),
|
TraitAlias(def_id),
|
||||||
AssociatedTy(def_id),
|
AssociatedTy(def_id),
|
||||||
|
AssociatedExistential(def_id),
|
||||||
PrimTy(prim_ty),
|
PrimTy(prim_ty),
|
||||||
TyParam(def_id),
|
TyParam(def_id),
|
||||||
SelfTy(trait_def_id, impl_def_id),
|
SelfTy(trait_def_id, impl_def_id),
|
||||||
|
|
|
@ -1055,6 +1055,7 @@ impl_stable_hash_for!(struct ty::AssociatedItem {
|
||||||
impl_stable_hash_for!(enum ty::AssociatedKind {
|
impl_stable_hash_for!(enum ty::AssociatedKind {
|
||||||
Const,
|
Const,
|
||||||
Method,
|
Method,
|
||||||
|
Existential,
|
||||||
Type
|
Type
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -691,10 +691,22 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
||||||
// ```
|
// ```
|
||||||
if let Some(anon_node_id) = tcx.hir.as_local_node_id(def_id) {
|
if let Some(anon_node_id) = tcx.hir.as_local_node_id(def_id) {
|
||||||
let anon_parent_def_id = match tcx.hir.expect_item(anon_node_id).node {
|
let anon_parent_def_id = match tcx.hir.expect_item(anon_node_id).node {
|
||||||
|
// impl trait
|
||||||
hir::ItemKind::Existential(hir::ExistTy {
|
hir::ItemKind::Existential(hir::ExistTy {
|
||||||
impl_trait_fn: Some(parent),
|
impl_trait_fn: Some(parent),
|
||||||
..
|
..
|
||||||
}) => parent,
|
}) => parent,
|
||||||
|
// named existential types
|
||||||
|
hir::ItemKind::Existential(hir::ExistTy {
|
||||||
|
impl_trait_fn: None,
|
||||||
|
..
|
||||||
|
}) if may_define_existential_type(
|
||||||
|
tcx,
|
||||||
|
self.parent_def_id,
|
||||||
|
anon_node_id,
|
||||||
|
) => {
|
||||||
|
return self.fold_anon_ty(ty, def_id, substs);
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let anon_parent_node_id = tcx.hir.get_parent(anon_node_id);
|
let anon_parent_node_id = tcx.hir.get_parent(anon_node_id);
|
||||||
tcx.hir.local_def_id(anon_parent_node_id)
|
tcx.hir.local_def_id(anon_parent_node_id)
|
||||||
|
@ -742,6 +754,10 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
||||||
let ty_var = infcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
|
let ty_var = infcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
|
||||||
|
|
||||||
let predicates_of = tcx.predicates_of(def_id);
|
let predicates_of = tcx.predicates_of(def_id);
|
||||||
|
debug!(
|
||||||
|
"instantiate_anon_types: predicates: {:#?}",
|
||||||
|
predicates_of,
|
||||||
|
);
|
||||||
let bounds = predicates_of.instantiate(tcx, substs);
|
let bounds = predicates_of.instantiate(tcx, substs);
|
||||||
debug!("instantiate_anon_types: bounds={:?}", bounds);
|
debug!("instantiate_anon_types: bounds={:?}", bounds);
|
||||||
|
|
||||||
|
@ -751,6 +767,18 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
||||||
required_region_bounds
|
required_region_bounds
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// make sure that we are in fact defining the *entire* type
|
||||||
|
// e.g. `existential type Foo<T: Bound>: Bar;` needs to be
|
||||||
|
// defined by a function like `fn foo<T: Bound>() -> Foo<T>`.
|
||||||
|
debug!(
|
||||||
|
"instantiate_anon_types: param_env: {:#?}",
|
||||||
|
self.param_env,
|
||||||
|
);
|
||||||
|
debug!(
|
||||||
|
"instantiate_anon_types: generics: {:#?}",
|
||||||
|
tcx.generics_of(def_id),
|
||||||
|
);
|
||||||
|
|
||||||
self.anon_types.insert(
|
self.anon_types.insert(
|
||||||
def_id,
|
def_id,
|
||||||
AnonTypeDecl {
|
AnonTypeDecl {
|
||||||
|
@ -778,3 +806,25 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
||||||
ty_var
|
ty_var
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether `anon_node_id` is a sibling or a child of a sibling of `def_id`
|
||||||
|
pub fn may_define_existential_type(
|
||||||
|
tcx: TyCtxt,
|
||||||
|
def_id: DefId,
|
||||||
|
anon_node_id: ast::NodeId,
|
||||||
|
) -> bool {
|
||||||
|
let mut node_id = tcx
|
||||||
|
.hir
|
||||||
|
.as_local_node_id(def_id)
|
||||||
|
.unwrap();
|
||||||
|
// named existential types can be defined by any siblings or
|
||||||
|
// children of siblings
|
||||||
|
let mod_id = tcx.hir.get_parent(anon_node_id);
|
||||||
|
// so we walk up the node tree until we hit the root or the parent
|
||||||
|
// of the anon type
|
||||||
|
while node_id != mod_id && node_id != ast::CRATE_NODE_ID {
|
||||||
|
node_id = tcx.hir.get_parent(node_id);
|
||||||
|
}
|
||||||
|
// syntactically we are allowed to define the concrete type
|
||||||
|
node_id == mod_id
|
||||||
|
}
|
||||||
|
|
|
@ -279,7 +279,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str {
|
fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str {
|
||||||
match item.node {
|
match item.node {
|
||||||
hir::ImplItemKind::Method(..) => "method body",
|
hir::ImplItemKind::Method(..) => "method body",
|
||||||
hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) => "associated item",
|
hir::ImplItemKind::Const(..) |
|
||||||
|
hir::ImplItemKind::Existential(..) |
|
||||||
|
hir::ImplItemKind::Type(..) => "associated item",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -622,6 +622,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
self.visit_nested_body(body_id)
|
self.visit_nested_body(body_id)
|
||||||
}
|
}
|
||||||
|
hir::ImplItemKind::Existential(..) |
|
||||||
hir::ImplItemKind::Type(..) => {}
|
hir::ImplItemKind::Type(..) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,6 +210,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hir::ImplItemKind::Existential(..) |
|
||||||
hir::ImplItemKind::Type(_) => false,
|
hir::ImplItemKind::Type(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,6 +320,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
|
||||||
self.visit_nested_body(body)
|
self.visit_nested_body(body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hir::ImplItemKind::Existential(..) |
|
||||||
hir::ImplItemKind::Type(_) => {}
|
hir::ImplItemKind::Type(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -627,6 +627,30 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
|
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
|
||||||
if let Def::Existential(exist_ty_did) = path.def {
|
if let Def::Existential(exist_ty_did) = path.def {
|
||||||
|
let id = self.tcx.hir.as_local_node_id(exist_ty_did).unwrap();
|
||||||
|
|
||||||
|
// Resolve the lifetimes in the bounds to the lifetime defs in the generics.
|
||||||
|
// `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 (generics, bounds) = match self.tcx.hir.expect_item(id).node {
|
||||||
|
// named existential types don't need these hacks
|
||||||
|
hir::ItemKind::Existential(hir::ExistTy{ impl_trait_fn: None, .. }) => {
|
||||||
|
intravisit::walk_ty(self, ty);
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
hir::ItemKind::Existential(hir::ExistTy{
|
||||||
|
ref generics,
|
||||||
|
ref bounds,
|
||||||
|
..
|
||||||
|
}) => (
|
||||||
|
generics,
|
||||||
|
bounds,
|
||||||
|
),
|
||||||
|
ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i),
|
||||||
|
};
|
||||||
|
|
||||||
assert!(exist_ty_did.is_local());
|
assert!(exist_ty_did.is_local());
|
||||||
// Resolve the lifetimes that are applied to the existential type.
|
// Resolve the lifetimes that are applied to the existential type.
|
||||||
// These are resolved in the current scope.
|
// These are resolved in the current scope.
|
||||||
|
@ -667,23 +691,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = self.tcx.hir.as_local_node_id(exist_ty_did).unwrap();
|
|
||||||
|
|
||||||
// Resolve the lifetimes in the bounds to the lifetime defs in the generics.
|
|
||||||
// `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 (generics, bounds) = match self.tcx.hir.expect_item(id).node {
|
|
||||||
hir::ItemKind::Existential(
|
|
||||||
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,
|
// We want to start our early-bound indices at the end of the parent scope,
|
||||||
// not including any parent `impl Trait`s.
|
// not including any parent `impl Trait`s.
|
||||||
let mut index = self.next_early_index_for_abstract_type();
|
let mut index = self.next_early_index_for_abstract_type();
|
||||||
|
@ -847,6 +854,35 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
this.visit_ty(ty);
|
this.visit_ty(ty);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Existential(ref bounds) => {
|
||||||
|
let generics = &impl_item.generics;
|
||||||
|
let mut index = self.next_early_index();
|
||||||
|
let mut next_early_index = index;
|
||||||
|
debug!("visit_ty: index = {}", index);
|
||||||
|
let lifetimes = generics.params.iter().filter_map(|param| match param.kind {
|
||||||
|
GenericParamKind::Lifetime { .. } => {
|
||||||
|
Some(Region::early(&self.tcx.hir, &mut index, param))
|
||||||
|
}
|
||||||
|
GenericParamKind::Type { .. } => {
|
||||||
|
next_early_index += 1;
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
let scope = Scope::Binder {
|
||||||
|
lifetimes,
|
||||||
|
next_early_index,
|
||||||
|
s: self.scope,
|
||||||
|
track_lifetime_uses: true,
|
||||||
|
abstract_type_parent: true,
|
||||||
|
};
|
||||||
|
self.with(scope, |_old_scope, this| {
|
||||||
|
this.visit_generics(generics);
|
||||||
|
for bound in bounds {
|
||||||
|
this.visit_param_bound(bound);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
Const(_, _) => {
|
Const(_, _) => {
|
||||||
// Only methods and types support generics.
|
// Only methods and types support generics.
|
||||||
assert!(impl_item.generics.params.is_empty());
|
assert!(impl_item.generics.params.is_empty());
|
||||||
|
@ -1213,6 +1249,7 @@ fn compute_object_lifetime_defaults(
|
||||||
hir::ItemKind::Struct(_, ref generics)
|
hir::ItemKind::Struct(_, ref generics)
|
||||||
| hir::ItemKind::Union(_, ref generics)
|
| hir::ItemKind::Union(_, ref generics)
|
||||||
| hir::ItemKind::Enum(_, ref generics)
|
| hir::ItemKind::Enum(_, ref generics)
|
||||||
|
| hir::ItemKind::Existential(hir::ExistTy { ref generics, impl_trait_fn: None, .. })
|
||||||
| hir::ItemKind::Ty(_, ref generics)
|
| hir::ItemKind::Ty(_, ref generics)
|
||||||
| hir::ItemKind::Trait(_, _, ref generics, ..) => {
|
| hir::ItemKind::Trait(_, _, ref generics, ..) => {
|
||||||
let result = object_lifetime_defaults_for_item(tcx, generics);
|
let result = object_lifetime_defaults_for_item(tcx, generics);
|
||||||
|
|
|
@ -212,6 +212,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
data @ DefPathData::Trait(..) |
|
data @ DefPathData::Trait(..) |
|
||||||
data @ DefPathData::AssocTypeInTrait(..) |
|
data @ DefPathData::AssocTypeInTrait(..) |
|
||||||
data @ DefPathData::AssocTypeInImpl(..) |
|
data @ DefPathData::AssocTypeInImpl(..) |
|
||||||
|
data @ DefPathData::AssocExistentialInImpl(..) |
|
||||||
data @ DefPathData::ValueNs(..) |
|
data @ DefPathData::ValueNs(..) |
|
||||||
data @ DefPathData::Module(..) |
|
data @ DefPathData::Module(..) |
|
||||||
data @ DefPathData::TypeParam(..) |
|
data @ DefPathData::TypeParam(..) |
|
||||||
|
|
|
@ -192,6 +192,7 @@ pub struct AssociatedItem {
|
||||||
pub enum AssociatedKind {
|
pub enum AssociatedKind {
|
||||||
Const,
|
Const,
|
||||||
Method,
|
Method,
|
||||||
|
Existential,
|
||||||
Type
|
Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,6 +202,7 @@ impl AssociatedItem {
|
||||||
AssociatedKind::Const => Def::AssociatedConst(self.def_id),
|
AssociatedKind::Const => Def::AssociatedConst(self.def_id),
|
||||||
AssociatedKind::Method => Def::Method(self.def_id),
|
AssociatedKind::Method => Def::Method(self.def_id),
|
||||||
AssociatedKind::Type => Def::AssociatedTy(self.def_id),
|
AssociatedKind::Type => Def::AssociatedTy(self.def_id),
|
||||||
|
AssociatedKind::Existential => Def::AssociatedExistential(self.def_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +210,8 @@ impl AssociatedItem {
|
||||||
/// for !
|
/// for !
|
||||||
pub fn relevant_for_never<'tcx>(&self) -> bool {
|
pub fn relevant_for_never<'tcx>(&self) -> bool {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
AssociatedKind::Const => true,
|
AssociatedKind::Existential |
|
||||||
|
AssociatedKind::Const |
|
||||||
AssociatedKind::Type => true,
|
AssociatedKind::Type => true,
|
||||||
// FIXME(canndrew): Be more thorough here, check if any argument is uninhabited.
|
// FIXME(canndrew): Be more thorough here, check if any argument is uninhabited.
|
||||||
AssociatedKind::Method => !self.method_has_self_argument,
|
AssociatedKind::Method => !self.method_has_self_argument,
|
||||||
|
@ -225,6 +228,7 @@ impl AssociatedItem {
|
||||||
format!("{}", tcx.fn_sig(self.def_id).skip_binder())
|
format!("{}", tcx.fn_sig(self.def_id).skip_binder())
|
||||||
}
|
}
|
||||||
ty::AssociatedKind::Type => format!("type {};", self.ident),
|
ty::AssociatedKind::Type => format!("type {};", self.ident),
|
||||||
|
ty::AssociatedKind::Existential => format!("existential type {};", self.ident),
|
||||||
ty::AssociatedKind::Const => {
|
ty::AssociatedKind::Const => {
|
||||||
format!("const {}: {:?};", self.ident, tcx.type_of(self.def_id))
|
format!("const {}: {:?};", self.ident, tcx.type_of(self.def_id))
|
||||||
}
|
}
|
||||||
|
@ -2491,6 +2495,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
(ty::AssociatedKind::Method, has_self)
|
(ty::AssociatedKind::Method, has_self)
|
||||||
}
|
}
|
||||||
hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
|
hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
|
||||||
|
hir::AssociatedItemKind::Existential => bug!("only impls can have existentials"),
|
||||||
};
|
};
|
||||||
|
|
||||||
AssociatedItem {
|
AssociatedItem {
|
||||||
|
@ -2516,6 +2521,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
(ty::AssociatedKind::Method, has_self)
|
(ty::AssociatedKind::Method, has_self)
|
||||||
}
|
}
|
||||||
hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
|
hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
|
||||||
|
hir::AssociatedItemKind::Existential => (ty::AssociatedKind::Existential, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
AssociatedItem {
|
AssociatedItem {
|
||||||
|
@ -2857,9 +2863,16 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
|
||||||
// The param_env of an existential type is its parent's param_env
|
// The param_env of an existential type is its parent's param_env
|
||||||
if let Some(Def::Existential(_)) = tcx.describe_def(def_id) {
|
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");
|
if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
|
||||||
|
if let hir::map::NodeItem(item) = tcx.hir.get(node_id) {
|
||||||
|
if let hir::ItemKind::Existential(ref exist_ty) = item.node {
|
||||||
|
if let Some(parent) = exist_ty.impl_trait_fn {
|
||||||
return param_env(tcx, parent);
|
return param_env(tcx, parent);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Compute the bounds on Self and the type parameters.
|
// Compute the bounds on Self and the type parameters.
|
||||||
|
|
||||||
let InstantiatedPredicates { predicates } =
|
let InstantiatedPredicates { predicates } =
|
||||||
|
|
|
@ -158,8 +158,10 @@ pub enum TypeVariants<'tcx> {
|
||||||
TyProjection(ProjectionTy<'tcx>),
|
TyProjection(ProjectionTy<'tcx>),
|
||||||
|
|
||||||
/// Anonymized (`impl Trait`) type found in a return type.
|
/// Anonymized (`impl Trait`) type found in a return type.
|
||||||
/// The DefId comes from the `impl Trait` ast::Ty node, and the
|
/// The DefId comes either from
|
||||||
/// substitutions are for the generics of the function in question.
|
/// * the `impl Trait` ast::Ty node,
|
||||||
|
/// * or the `existential type` declaration
|
||||||
|
/// The substitutions are for the generics of the function in question.
|
||||||
/// After typeck, the concrete type can be found in the `types` map.
|
/// After typeck, the concrete type can be found in the `types` map.
|
||||||
TyAnon(DefId, &'tcx Substs<'tcx>),
|
TyAnon(DefId, &'tcx Substs<'tcx>),
|
||||||
|
|
||||||
|
|
|
@ -271,6 +271,7 @@ impl PrintContext {
|
||||||
match key.disambiguated_data.data {
|
match key.disambiguated_data.data {
|
||||||
DefPathData::AssocTypeInTrait(_) |
|
DefPathData::AssocTypeInTrait(_) |
|
||||||
DefPathData::AssocTypeInImpl(_) |
|
DefPathData::AssocTypeInImpl(_) |
|
||||||
|
DefPathData::AssocExistentialInImpl(_) |
|
||||||
DefPathData::Trait(_) |
|
DefPathData::Trait(_) |
|
||||||
DefPathData::TypeNs(_) => {
|
DefPathData::TypeNs(_) => {
|
||||||
break;
|
break;
|
||||||
|
@ -1081,6 +1082,20 @@ define_print! {
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::tls::with(|tcx| {
|
ty::tls::with(|tcx| {
|
||||||
|
let def_key = tcx.def_key(def_id);
|
||||||
|
if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
|
||||||
|
write!(f, "{}", name)?;
|
||||||
|
let mut substs = substs.iter();
|
||||||
|
if let Some(first) = substs.next() {
|
||||||
|
write!(f, "::<")?;
|
||||||
|
write!(f, "{}", first)?;
|
||||||
|
for subst in substs {
|
||||||
|
write!(f, ", {}", subst)?;
|
||||||
|
}
|
||||||
|
write!(f, ">")?;
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
|
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
|
||||||
// by looking up the projections associated with the def_id.
|
// by looking up the projections associated with the def_id.
|
||||||
let predicates_of = tcx.predicates_of(def_id);
|
let predicates_of = tcx.predicates_of(def_id);
|
||||||
|
|
|
@ -417,6 +417,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
|
||||||
ImplItemKind::Method(..) => ("NodeImplItem", LABELS_FN_IN_IMPL),
|
ImplItemKind::Method(..) => ("NodeImplItem", LABELS_FN_IN_IMPL),
|
||||||
ImplItemKind::Const(..) => ("NodeImplConst", LABELS_CONST_IN_IMPL),
|
ImplItemKind::Const(..) => ("NodeImplConst", LABELS_CONST_IN_IMPL),
|
||||||
ImplItemKind::Type(..) => ("NodeImplType", LABELS_CONST_IN_IMPL),
|
ImplItemKind::Type(..) => ("NodeImplType", LABELS_CONST_IN_IMPL),
|
||||||
|
ImplItemKind::Existential(..) => ("NodeImplType", LABELS_CONST_IN_IMPL),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => self.tcx.sess.span_fatal(
|
_ => self.tcx.sess.span_fatal(
|
||||||
|
|
|
@ -461,6 +461,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
|
||||||
hir::ImplItemKind::Const(..) => "an associated constant",
|
hir::ImplItemKind::Const(..) => "an associated constant",
|
||||||
hir::ImplItemKind::Method(..) => "a method",
|
hir::ImplItemKind::Method(..) => "a method",
|
||||||
hir::ImplItemKind::Type(_) => "an associated type",
|
hir::ImplItemKind::Type(_) => "an associated type",
|
||||||
|
hir::ImplItemKind::Existential(_) => "an associated existential type",
|
||||||
};
|
};
|
||||||
self.check_missing_docs_attrs(cx,
|
self.check_missing_docs_attrs(cx,
|
||||||
Some(impl_item.id),
|
Some(impl_item.id),
|
||||||
|
|
|
@ -421,6 +421,7 @@ impl<'tcx> EntryKind<'tcx> {
|
||||||
EntryKind::Type => Def::TyAlias(did),
|
EntryKind::Type => Def::TyAlias(did),
|
||||||
EntryKind::Existential => Def::Existential(did),
|
EntryKind::Existential => Def::Existential(did),
|
||||||
EntryKind::AssociatedType(_) => Def::AssociatedTy(did),
|
EntryKind::AssociatedType(_) => Def::AssociatedTy(did),
|
||||||
|
EntryKind::AssociatedExistential(_) => Def::AssociatedExistential(did),
|
||||||
EntryKind::Mod(_) => Def::Mod(did),
|
EntryKind::Mod(_) => Def::Mod(did),
|
||||||
EntryKind::Variant(_) => Def::Variant(did),
|
EntryKind::Variant(_) => Def::Variant(did),
|
||||||
EntryKind::Trait(_) => Def::Trait(did),
|
EntryKind::Trait(_) => Def::Trait(did),
|
||||||
|
|
|
@ -840,6 +840,8 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
ty::AssociatedKind::Type => EntryKind::AssociatedType(container),
|
ty::AssociatedKind::Type => EntryKind::AssociatedType(container),
|
||||||
|
ty::AssociatedKind::Existential =>
|
||||||
|
span_bug!(ast_item.span, "existential type in trait"),
|
||||||
};
|
};
|
||||||
|
|
||||||
Entry {
|
Entry {
|
||||||
|
@ -863,6 +865,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ty::AssociatedKind::Existential => unreachable!(),
|
||||||
},
|
},
|
||||||
inherent_impls: LazySeq::empty(),
|
inherent_impls: LazySeq::empty(),
|
||||||
variances: if trait_item.kind == ty::AssociatedKind::Method {
|
variances: if trait_item.kind == ty::AssociatedKind::Method {
|
||||||
|
@ -933,6 +936,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
||||||
has_self: impl_item.method_has_self_argument,
|
has_self: impl_item.method_has_self_argument,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
ty::AssociatedKind::Existential => EntryKind::AssociatedExistential(container),
|
||||||
ty::AssociatedKind::Type => EntryKind::AssociatedType(container)
|
ty::AssociatedKind::Type => EntryKind::AssociatedType(container)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -948,6 +952,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
|
||||||
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
|
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
|
||||||
needs_inline || is_const_fn || always_encode_mir
|
needs_inline || is_const_fn || always_encode_mir
|
||||||
},
|
},
|
||||||
|
hir::ImplItemKind::Existential(..) |
|
||||||
hir::ImplItemKind::Type(..) => false,
|
hir::ImplItemKind::Type(..) => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -321,6 +321,7 @@ pub enum EntryKind<'tcx> {
|
||||||
Impl(Lazy<ImplData<'tcx>>),
|
Impl(Lazy<ImplData<'tcx>>),
|
||||||
Method(Lazy<MethodData<'tcx>>),
|
Method(Lazy<MethodData<'tcx>>),
|
||||||
AssociatedType(AssociatedContainer),
|
AssociatedType(AssociatedContainer),
|
||||||
|
AssociatedExistential(AssociatedContainer),
|
||||||
AssociatedConst(AssociatedContainer, ConstQualif, Lazy<RenderedConst>),
|
AssociatedConst(AssociatedContainer, ConstQualif, Lazy<RenderedConst>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,6 +383,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for EntryKind<'gcx> {
|
||||||
EntryKind::Method(ref method_data) => {
|
EntryKind::Method(ref method_data) => {
|
||||||
method_data.hash_stable(hcx, hasher);
|
method_data.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
|
EntryKind::AssociatedExistential(associated_container) |
|
||||||
EntryKind::AssociatedType(associated_container) => {
|
EntryKind::AssociatedType(associated_container) => {
|
||||||
associated_container.hash_stable(hcx, hasher);
|
associated_container.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,7 +237,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
|
||||||
hir::ItemKind::Use(..) => {}
|
hir::ItemKind::Use(..) => {}
|
||||||
// The interface is empty
|
// The interface is empty
|
||||||
hir::ItemKind::GlobalAsm(..) => {}
|
hir::ItemKind::GlobalAsm(..) => {}
|
||||||
hir::ItemKind::Existential(..) => {
|
hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(_), .. }) => {
|
||||||
if item_level.is_some() {
|
if item_level.is_some() {
|
||||||
// Reach the (potentially private) type and the API being exposed
|
// Reach the (potentially private) type and the API being exposed
|
||||||
self.reach(item.id).ty().predicates();
|
self.reach(item.id).ty().predicates();
|
||||||
|
@ -245,6 +245,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
// Visit everything
|
// Visit everything
|
||||||
hir::ItemKind::Const(..) | hir::ItemKind::Static(..) |
|
hir::ItemKind::Const(..) | hir::ItemKind::Static(..) |
|
||||||
|
hir::ItemKind::Existential(..) |
|
||||||
hir::ItemKind::Fn(..) | hir::ItemKind::Ty(..) => {
|
hir::ItemKind::Fn(..) | hir::ItemKind::Ty(..) => {
|
||||||
if item_level.is_some() {
|
if item_level.is_some() {
|
||||||
self.reach(item.id).generics().predicates().ty();
|
self.reach(item.id).generics().predicates().ty();
|
||||||
|
@ -1165,6 +1166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
|
||||||
hir::ImplItemKind::Method(..) => {
|
hir::ImplItemKind::Method(..) => {
|
||||||
self.access_levels.is_reachable(impl_item.id)
|
self.access_levels.is_reachable(impl_item.id)
|
||||||
}
|
}
|
||||||
|
hir::ImplItemKind::Existential(..) |
|
||||||
hir::ImplItemKind::Type(_) => false,
|
hir::ImplItemKind::Type(_) => false,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1566,7 +1568,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
|
||||||
hir::ItemKind::Use(..) => {}
|
hir::ItemKind::Use(..) => {}
|
||||||
// No subitems
|
// No subitems
|
||||||
hir::ItemKind::GlobalAsm(..) => {}
|
hir::ItemKind::GlobalAsm(..) => {}
|
||||||
hir::ItemKind::Existential(..) => {
|
hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(_), .. }) => {
|
||||||
// Check the traits being exposed, as they're separate,
|
// Check the traits being exposed, as they're separate,
|
||||||
// e.g. `impl Iterator<Item=T>` has two predicates,
|
// e.g. `impl Iterator<Item=T>` has two predicates,
|
||||||
// `X: Iterator` and `<X as Iterator>::Item == T`,
|
// `X: Iterator` and `<X as Iterator>::Item == T`,
|
||||||
|
@ -1577,6 +1579,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
|
||||||
}
|
}
|
||||||
// Subitems of these items have inherited publicity
|
// Subitems of these items have inherited publicity
|
||||||
hir::ItemKind::Const(..) | hir::ItemKind::Static(..) | hir::ItemKind::Fn(..) |
|
hir::ItemKind::Const(..) | hir::ItemKind::Static(..) | hir::ItemKind::Fn(..) |
|
||||||
|
hir::ItemKind::Existential(..) |
|
||||||
hir::ItemKind::Ty(..) => {
|
hir::ItemKind::Ty(..) => {
|
||||||
self.check(item.id, item_visibility).generics().predicates().ty();
|
self.check(item.id, item_visibility).generics().predicates().ty();
|
||||||
|
|
||||||
|
|
|
@ -361,6 +361,11 @@ impl<'a> Resolver<'a> {
|
||||||
self.define(parent, ident, TypeNS, (def, vis, sp, expansion));
|
self.define(parent, ident, TypeNS, (def, vis, sp, expansion));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ItemKind::Existential(_, _) => {
|
||||||
|
let def = Def::Existential(self.definitions.local_def_id(item.id));
|
||||||
|
self.define(parent, ident, TypeNS, (def, vis, sp, expansion));
|
||||||
|
}
|
||||||
|
|
||||||
ItemKind::Enum(ref enum_definition, _) => {
|
ItemKind::Enum(ref enum_definition, _) => {
|
||||||
let def = Def::Enum(self.definitions.local_def_id(item.id));
|
let def = Def::Enum(self.definitions.local_def_id(item.id));
|
||||||
let module_kind = ModuleKind::Def(def, ident.name);
|
let module_kind = ModuleKind::Def(def, ident.name);
|
||||||
|
|
|
@ -207,7 +207,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
|
||||||
Def::AssociatedTy(..) | Def::PrimTy(..) | Def::Fn(..) | Def::Const(..) |
|
Def::AssociatedTy(..) | Def::PrimTy(..) | Def::Fn(..) | Def::Const(..) |
|
||||||
Def::Static(..) | Def::StructCtor(..) | Def::VariantCtor(..) | Def::Method(..) |
|
Def::Static(..) | Def::StructCtor(..) | Def::VariantCtor(..) | Def::Method(..) |
|
||||||
Def::AssociatedConst(..) | Def::Local(..) | Def::Upvar(..) | Def::Label(..) |
|
Def::AssociatedConst(..) | Def::Local(..) | Def::Upvar(..) | Def::Label(..) |
|
||||||
Def::Existential(..) |
|
Def::Existential(..) | Def::AssociatedExistential(..) |
|
||||||
Def::Macro(..) | Def::GlobalAsm(..) | Def::Err =>
|
Def::Macro(..) | Def::GlobalAsm(..) | Def::Err =>
|
||||||
bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy or \
|
bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy or \
|
||||||
Def::TyParam")
|
Def::TyParam")
|
||||||
|
@ -535,6 +535,7 @@ impl<'a> PathSource<'a> {
|
||||||
Def::Struct(..) | Def::Union(..) | Def::Enum(..) |
|
Def::Struct(..) | Def::Union(..) | Def::Enum(..) |
|
||||||
Def::Trait(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
|
Def::Trait(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
|
||||||
Def::PrimTy(..) | Def::TyParam(..) | Def::SelfTy(..) |
|
Def::PrimTy(..) | Def::TyParam(..) | Def::SelfTy(..) |
|
||||||
|
Def::Existential(..) |
|
||||||
Def::TyForeign(..) => true,
|
Def::TyForeign(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
@ -2148,6 +2149,7 @@ impl<'a> Resolver<'a> {
|
||||||
match item.node {
|
match item.node {
|
||||||
ItemKind::Enum(_, ref generics) |
|
ItemKind::Enum(_, ref generics) |
|
||||||
ItemKind::Ty(_, ref generics) |
|
ItemKind::Ty(_, ref generics) |
|
||||||
|
ItemKind::Existential(_, ref generics) |
|
||||||
ItemKind::Struct(_, ref generics) |
|
ItemKind::Struct(_, ref generics) |
|
||||||
ItemKind::Union(_, ref generics) |
|
ItemKind::Union(_, ref generics) |
|
||||||
ItemKind::Fn(_, _, ref generics, _) => {
|
ItemKind::Fn(_, _, ref generics, _) => {
|
||||||
|
@ -2486,6 +2488,18 @@ impl<'a> Resolver<'a> {
|
||||||
|
|
||||||
this.visit_ty(ty);
|
this.visit_ty(ty);
|
||||||
}
|
}
|
||||||
|
ImplItemKind::Existential(ref bounds) => {
|
||||||
|
// If this is a trait impl, ensure the type
|
||||||
|
// exists in trait
|
||||||
|
this.check_trait_item(impl_item.ident,
|
||||||
|
TypeNS,
|
||||||
|
impl_item.span,
|
||||||
|
|n, s| TypeNotMemberOfTrait(n, s));
|
||||||
|
|
||||||
|
for bound in bounds {
|
||||||
|
this.visit_param_bound(bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
ImplItemKind::Macro(_) =>
|
ImplItemKind::Macro(_) =>
|
||||||
panic!("unexpanded macro in resolve!"),
|
panic!("unexpanded macro in resolve!"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1238,6 +1238,16 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
||||||
// trait.
|
// trait.
|
||||||
self.visit_ty(ty)
|
self.visit_ty(ty)
|
||||||
}
|
}
|
||||||
|
ast::ImplItemKind::Existential(ref bounds) => {
|
||||||
|
// FIXME uses of the assoc type should ideally point to this
|
||||||
|
// 'def' and the name here should be a ref to the def in the
|
||||||
|
// trait.
|
||||||
|
for bound in bounds.iter() {
|
||||||
|
if let ast::GenericBound::Trait(ref trait_ref, _) = *bound {
|
||||||
|
self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
ast::ImplItemKind::Macro(_) => {}
|
ast::ImplItemKind::Macro(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1477,6 +1487,36 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
||||||
self.visit_ty(&ty);
|
self.visit_ty(&ty);
|
||||||
self.process_generic_params(ty_params, item.span, &qualname, item.id);
|
self.process_generic_params(ty_params, item.span, &qualname, item.id);
|
||||||
}
|
}
|
||||||
|
Existential(ref _bounds, ref ty_params) => {
|
||||||
|
let qualname = format!("::{}", self.tcx.node_path_str(item.id));
|
||||||
|
// FIXME do something with _bounds
|
||||||
|
let value = String::new();
|
||||||
|
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
|
||||||
|
if !self.span.filter_generated(sub_span, item.span) {
|
||||||
|
let span = self.span_from_span(sub_span.expect("No span found for typedef"));
|
||||||
|
let id = ::id_from_node_id(item.id, &self.save_ctxt);
|
||||||
|
|
||||||
|
self.dumper.dump_def(
|
||||||
|
&access_from!(self.save_ctxt, item),
|
||||||
|
Def {
|
||||||
|
kind: DefKind::Type,
|
||||||
|
id,
|
||||||
|
span,
|
||||||
|
name: item.ident.to_string(),
|
||||||
|
qualname: qualname.clone(),
|
||||||
|
value,
|
||||||
|
parent: None,
|
||||||
|
children: vec![],
|
||||||
|
decl_id: None,
|
||||||
|
docs: self.save_ctxt.docs_for_attrs(&item.attrs),
|
||||||
|
sig: sig::item_signature(item, &self.save_ctxt),
|
||||||
|
attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.process_generic_params(ty_params, item.span, &qualname, item.id);
|
||||||
|
}
|
||||||
Mac(_) => (),
|
Mac(_) => (),
|
||||||
_ => visit::walk_item(self, item),
|
_ => visit::walk_item(self, item),
|
||||||
}
|
}
|
||||||
|
|
|
@ -749,6 +749,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
||||||
HirDef::TyAlias(def_id) |
|
HirDef::TyAlias(def_id) |
|
||||||
HirDef::TyForeign(def_id) |
|
HirDef::TyForeign(def_id) |
|
||||||
HirDef::TraitAlias(def_id) |
|
HirDef::TraitAlias(def_id) |
|
||||||
|
HirDef::AssociatedExistential(def_id) |
|
||||||
HirDef::AssociatedTy(def_id) |
|
HirDef::AssociatedTy(def_id) |
|
||||||
HirDef::Trait(def_id) |
|
HirDef::Trait(def_id) |
|
||||||
HirDef::Existential(def_id) |
|
HirDef::Existential(def_id) |
|
||||||
|
|
|
@ -444,6 +444,18 @@ impl Sig for ast::Item {
|
||||||
refs: vec![],
|
refs: vec![],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ast::ItemKind::Existential(ref bounds, ref generics) => {
|
||||||
|
let text = "existential type ".to_owned();
|
||||||
|
let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
|
||||||
|
|
||||||
|
if !bounds.is_empty() {
|
||||||
|
sig.text.push_str(": ");
|
||||||
|
sig.text.push_str(&pprust::bounds_to_string(bounds));
|
||||||
|
}
|
||||||
|
sig.text.push(';');
|
||||||
|
|
||||||
|
Ok(sig)
|
||||||
|
}
|
||||||
ast::ItemKind::Ty(ref ty, ref generics) => {
|
ast::ItemKind::Ty(ref ty, ref generics) => {
|
||||||
let text = "type ".to_owned();
|
let text = "type ".to_owned();
|
||||||
let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
|
let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
|
||||||
|
|
|
@ -1035,6 +1035,26 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
|
||||||
|
|
||||||
let span = path.span;
|
let span = path.span;
|
||||||
match path.def {
|
match path.def {
|
||||||
|
Def::Existential(did) => {
|
||||||
|
// check for desugared impl trait
|
||||||
|
if let Some(node_id) = tcx.hir.as_local_node_id(did) {
|
||||||
|
if let hir::map::NodeItem(item) = tcx.hir.get(node_id) {
|
||||||
|
if let hir::ItemKind::Existential(ref exist_ty) = item.node {
|
||||||
|
if exist_ty.impl_trait_fn.is_some() {
|
||||||
|
let lifetimes = &path.segments[0].args.as_ref().unwrap().args;
|
||||||
|
return self.impl_trait_ty_to_ty(did, lifetimes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let item_segment = path.segments.split_last().unwrap();
|
||||||
|
self.prohibit_generics(item_segment.1);
|
||||||
|
let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
|
||||||
|
self.normalize_ty(
|
||||||
|
span,
|
||||||
|
tcx.mk_anon(did, substs),
|
||||||
|
)
|
||||||
|
}
|
||||||
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) |
|
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) |
|
||||||
Def::Union(did) | Def::TyForeign(did) => {
|
Def::Union(did) | Def::TyForeign(did) => {
|
||||||
assert_eq!(opt_self_ty, None);
|
assert_eq!(opt_self_ty, None);
|
||||||
|
@ -1095,11 +1115,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
|
||||||
hir::TyStr => tcx.mk_str()
|
hir::TyStr => tcx.mk_str()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Def::Existential(exist_ty_did) => {
|
|
||||||
assert!(exist_ty_did.is_local());
|
|
||||||
let lifetimes = &path.segments[0].args.as_ref().unwrap().args;
|
|
||||||
self.impl_trait_ty_to_ty(exist_ty_did, lifetimes)
|
|
||||||
}
|
|
||||||
Def::Err => {
|
Def::Err => {
|
||||||
self.set_tainted_by_errors();
|
self.set_tainted_by_errors();
|
||||||
return self.tcx().types.err;
|
return self.tcx().types.err;
|
||||||
|
|
|
@ -1332,6 +1332,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
Mode::MethodCall => item.method_has_self_argument,
|
Mode::MethodCall => item.method_has_self_argument,
|
||||||
Mode::Path => match item.kind {
|
Mode::Path => match item.kind {
|
||||||
|
ty::AssociatedKind::Existential |
|
||||||
ty::AssociatedKind::Type => false,
|
ty::AssociatedKind::Type => false,
|
||||||
ty::AssociatedKind::Method | ty::AssociatedKind::Const => true
|
ty::AssociatedKind::Method | ty::AssociatedKind::Const => true
|
||||||
},
|
},
|
||||||
|
|
|
@ -1410,6 +1410,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
let kind = match impl_item.node {
|
let kind = match impl_item.node {
|
||||||
hir::ImplItemKind::Const(..) => ty::AssociatedKind::Const,
|
hir::ImplItemKind::Const(..) => ty::AssociatedKind::Const,
|
||||||
hir::ImplItemKind::Method(..) => ty::AssociatedKind::Method,
|
hir::ImplItemKind::Method(..) => ty::AssociatedKind::Method,
|
||||||
|
hir::ImplItemKind::Existential(..) => ty::AssociatedKind::Existential,
|
||||||
hir::ImplItemKind::Type(_) => ty::AssociatedKind::Type
|
hir::ImplItemKind::Type(_) => ty::AssociatedKind::Type
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1503,6 +1504,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
err.emit()
|
err.emit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hir::ImplItemKind::Existential(..) |
|
||||||
hir::ImplItemKind::Type(_) => {
|
hir::ImplItemKind::Type(_) => {
|
||||||
if ty_trait_item.kind == ty::AssociatedKind::Type {
|
if ty_trait_item.kind == ty::AssociatedKind::Type {
|
||||||
if ty_trait_item.defaultness.has_value() {
|
if ty_trait_item.defaultness.has_value() {
|
||||||
|
|
|
@ -13,11 +13,12 @@ use constrained_type_params::{identify_constrained_type_params, Parameter};
|
||||||
|
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use rustc::traits::{self, ObligationCauseCode};
|
use rustc::traits::{self, ObligationCauseCode};
|
||||||
use rustc::ty::{self, Lift, Ty, TyCtxt, GenericParamDefKind};
|
use rustc::ty::{self, Lift, Ty, TyCtxt, GenericParamDefKind, TypeFoldable};
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::{Subst, Substs};
|
||||||
use rustc::ty::util::ExplicitSelf;
|
use rustc::ty::util::ExplicitSelf;
|
||||||
use rustc::util::nodemap::{FxHashSet, FxHashMap};
|
use rustc::util::nodemap::{FxHashSet, FxHashMap};
|
||||||
use rustc::middle::lang_items;
|
use rustc::middle::lang_items;
|
||||||
|
use rustc::infer::anon_types::may_define_existential_type;
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::feature_gate::{self, GateIssue};
|
use syntax::feature_gate::{self, GateIssue};
|
||||||
|
@ -209,6 +210,10 @@ fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
fcx.register_wf_obligation(ty, span, code.clone());
|
fcx.register_wf_obligation(ty, span, code.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ty::AssociatedKind::Existential => {
|
||||||
|
// FIXME(oli-obk) implement existential types in trait impls
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implied_bounds
|
implied_bounds
|
||||||
|
@ -282,7 +287,7 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check_where_clauses(tcx, fcx, item.span, def_id);
|
check_where_clauses(tcx, fcx, item.span, def_id, None);
|
||||||
|
|
||||||
vec![] // no implied bounds in a struct def'n
|
vec![] // no implied bounds in a struct def'n
|
||||||
});
|
});
|
||||||
|
@ -291,7 +296,7 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) {
|
fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) {
|
||||||
let trait_def_id = tcx.hir.local_def_id(item.id);
|
let trait_def_id = tcx.hir.local_def_id(item.id);
|
||||||
for_item(tcx, item).with_fcx(|fcx, _| {
|
for_item(tcx, item).with_fcx(|fcx, _| {
|
||||||
check_where_clauses(tcx, fcx, item.span, trait_def_id);
|
check_where_clauses(tcx, fcx, item.span, trait_def_id, None);
|
||||||
vec![]
|
vec![]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -357,7 +362,7 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check_where_clauses(tcx, fcx, item.span, item_def_id);
|
check_where_clauses(tcx, fcx, item.span, item_def_id, None);
|
||||||
|
|
||||||
fcx.impl_implied_bounds(item_def_id, item.span)
|
fcx.impl_implied_bounds(item_def_id, item.span)
|
||||||
});
|
});
|
||||||
|
@ -369,6 +374,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
|
||||||
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
|
return_ty: Option<Ty<'tcx>>,
|
||||||
) {
|
) {
|
||||||
use ty::subst::Subst;
|
use ty::subst::Subst;
|
||||||
use rustc::ty::TypeFoldable;
|
use rustc::ty::TypeFoldable;
|
||||||
|
@ -482,7 +488,12 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
|
||||||
traits::Obligation::new(cause, fcx.param_env, pred)
|
traits::Obligation::new(cause, fcx.param_env, pred)
|
||||||
});
|
});
|
||||||
|
|
||||||
let predicates = predicates.instantiate_identity(fcx.tcx);
|
let mut predicates = predicates.instantiate_identity(fcx.tcx);
|
||||||
|
|
||||||
|
if let Some(return_ty) = return_ty {
|
||||||
|
predicates.predicates.extend(check_existential_types(tcx, fcx, def_id, span, return_ty));
|
||||||
|
}
|
||||||
|
|
||||||
let predicates = fcx.normalize_associated_types_in(span, &predicates);
|
let predicates = fcx.normalize_associated_types_in(span, &predicates);
|
||||||
|
|
||||||
debug!("check_where_clauses: predicates={:?}", predicates.predicates);
|
debug!("check_where_clauses: predicates={:?}", predicates.predicates);
|
||||||
|
@ -521,7 +532,79 @@ fn check_fn_or_method<'a, 'fcx, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
|
||||||
// FIXME(#25759) return types should not be implied bounds
|
// FIXME(#25759) return types should not be implied bounds
|
||||||
implied_bounds.push(sig.output());
|
implied_bounds.push(sig.output());
|
||||||
|
|
||||||
check_where_clauses(tcx, fcx, span, def_id);
|
check_where_clauses(tcx, fcx, span, def_id, Some(sig.output()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
|
||||||
|
tcx: TyCtxt<'a, 'gcx, 'gcx>,
|
||||||
|
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
||||||
|
fn_def_id: DefId,
|
||||||
|
span: Span,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> Vec<ty::Predicate<'tcx>> {
|
||||||
|
trace!("check_existential_types: {:?}, {:?}", ty, ty.sty);
|
||||||
|
let mut substituted_predicates = Vec::new();
|
||||||
|
ty.fold_with(&mut ty::fold::BottomUpFolder {
|
||||||
|
tcx: fcx.tcx,
|
||||||
|
fldop: |ty| {
|
||||||
|
if let ty::TyAnon(def_id, substs) = ty.sty {
|
||||||
|
trace!("check_existential_types: anon_ty, {:?}, {:?}", def_id, substs);
|
||||||
|
let anon_node_id = tcx.hir.as_local_node_id(def_id).unwrap();
|
||||||
|
if may_define_existential_type(tcx, fn_def_id, anon_node_id) {
|
||||||
|
let generics = tcx.generics_of(def_id);
|
||||||
|
trace!("check_existential_types may define. Generics: {:#?}", generics);
|
||||||
|
for (subst, param) in substs.iter().zip(&generics.params) {
|
||||||
|
if let ty::subst::UnpackedKind::Type(ty) = subst.unpack() {
|
||||||
|
match ty.sty {
|
||||||
|
ty::TyParam(..) => {},
|
||||||
|
// prevent `fn foo() -> Foo<u32>` from being defining
|
||||||
|
_ => {
|
||||||
|
tcx
|
||||||
|
.sess
|
||||||
|
.struct_span_err(
|
||||||
|
span,
|
||||||
|
"non-defining existential type use in defining scope",
|
||||||
|
)
|
||||||
|
.span_note(
|
||||||
|
tcx.def_span(param.def_id),
|
||||||
|
&format!(
|
||||||
|
"used non-generic type {} for generic parameter",
|
||||||
|
ty,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
return tcx.types.err;
|
||||||
|
},
|
||||||
|
} // match ty
|
||||||
|
} // if let Type = subst
|
||||||
|
} // for (subst, param)
|
||||||
|
} // if may_define_existential_type
|
||||||
|
|
||||||
|
// now register the bounds on the parameters of the existential type
|
||||||
|
// so the parameters given by the function need to fulfil them
|
||||||
|
// ```rust
|
||||||
|
// existential type Foo<T: Bar>: 'static;
|
||||||
|
// fn foo<U>() -> Foo<U> { .. *}
|
||||||
|
// ```
|
||||||
|
// becomes
|
||||||
|
// ```rust
|
||||||
|
// existential type Foo<T: Bar>: 'static;
|
||||||
|
// fn foo<U: Bar>() -> Foo<U> { .. *}
|
||||||
|
// ```
|
||||||
|
let predicates = tcx.predicates_of(def_id);
|
||||||
|
trace!("check_existential_types may define. adding predicates: {:#?}", predicates);
|
||||||
|
for &pred in predicates.predicates.iter() {
|
||||||
|
let substituted_pred = pred.subst(fcx.tcx, substs);
|
||||||
|
// Avoid duplication of predicates that contain no parameters, for example.
|
||||||
|
if !predicates.predicates.contains(&substituted_pred) {
|
||||||
|
substituted_predicates.push(substituted_pred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // if let TyAnon
|
||||||
|
ty
|
||||||
|
},
|
||||||
|
});
|
||||||
|
substituted_predicates
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
||||||
|
|
|
@ -17,9 +17,10 @@ use rustc::hir;
|
||||||
use rustc::hir::def_id::{DefId, DefIndex};
|
use rustc::hir::def_id::{DefId, DefIndex};
|
||||||
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
|
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||||
use rustc::infer::InferCtxt;
|
use rustc::infer::InferCtxt;
|
||||||
|
use rustc::ty::subst::UnpackedKind;
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::ty::adjustment::{Adjust, Adjustment};
|
use rustc::ty::adjustment::{Adjust, Adjustment};
|
||||||
use rustc::ty::fold::{TypeFoldable, TypeFolder};
|
use rustc::ty::fold::{TypeFoldable, TypeFolder, BottomUpFolder};
|
||||||
use rustc::util::nodemap::DefIdSet;
|
use rustc::util::nodemap::DefIdSet;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
@ -388,11 +389,65 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
|
||||||
for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() {
|
for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() {
|
||||||
let node_id = self.tcx().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 instantiated_ty = self.resolve(&anon_defn.concrete_ty, &node_id);
|
||||||
let definition_ty = self.fcx.infer_anon_definition_from_instantiation(
|
let mut definition_ty = self.fcx.infer_anon_definition_from_instantiation(
|
||||||
def_id,
|
def_id,
|
||||||
anon_defn,
|
anon_defn,
|
||||||
instantiated_ty,
|
instantiated_ty,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let generics = self.tcx().generics_of(def_id);
|
||||||
|
|
||||||
|
// named existential type, not an impl trait
|
||||||
|
if generics.parent.is_none() {
|
||||||
|
// prevent
|
||||||
|
// * `fn foo<T>() -> Foo<T>`
|
||||||
|
// * `fn foo<T: Bound + Other>() -> Foo<T>`
|
||||||
|
// from being defining
|
||||||
|
|
||||||
|
// Also replace all generic params with the ones from the existential type
|
||||||
|
// definition so
|
||||||
|
// ```rust
|
||||||
|
// existential type Foo<T>: 'static;
|
||||||
|
// fn foo<U>() -> Foo<U> { .. }
|
||||||
|
// ```
|
||||||
|
// figures out the concrete type with `U`, but the stored type is with `T`
|
||||||
|
definition_ty = definition_ty.fold_with(&mut BottomUpFolder {
|
||||||
|
tcx: self.tcx().global_tcx(),
|
||||||
|
fldop: |ty| {
|
||||||
|
// find a type parameter
|
||||||
|
if let ty::TyParam(..) = ty.sty {
|
||||||
|
// look it up in the substitution list
|
||||||
|
assert_eq!(anon_defn.substs.len(), generics.params.len());
|
||||||
|
for (subst, param) in anon_defn.substs.iter().zip(&generics.params) {
|
||||||
|
if let UnpackedKind::Type(subst) = subst.unpack() {
|
||||||
|
if subst == ty {
|
||||||
|
// found it in the substitution list, replace with the
|
||||||
|
// parameter from the existential type
|
||||||
|
return self
|
||||||
|
.tcx()
|
||||||
|
.global_tcx()
|
||||||
|
.mk_ty_param(param.index, param.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.tcx()
|
||||||
|
.sess
|
||||||
|
.struct_span_err(
|
||||||
|
span,
|
||||||
|
&format!(
|
||||||
|
"type parameter `{}` is part of concrete type but not used \
|
||||||
|
in parameter list for existential type",
|
||||||
|
ty,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
return self.tcx().types.err;
|
||||||
|
}
|
||||||
|
ty
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let old = self.tables.concrete_existential_types.insert(def_id, definition_ty);
|
let old = self.tables.concrete_existential_types.insert(def_id, definition_ty);
|
||||||
if let Some(old) = old {
|
if let Some(old) = old {
|
||||||
if old != definition_ty {
|
if old != definition_ty {
|
||||||
|
|
|
@ -269,6 +269,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
ItemKind::Fn(.., ref generics, _) |
|
ItemKind::Fn(.., ref generics, _) |
|
||||||
ItemKind::Impl(_, _, _, ref generics, ..) |
|
ItemKind::Impl(_, _, _, ref generics, ..) |
|
||||||
ItemKind::Ty(_, ref generics) |
|
ItemKind::Ty(_, ref generics) |
|
||||||
|
ItemKind::Existential(ExistTy { ref generics, impl_trait_fn: None, ..}) |
|
||||||
ItemKind::Enum(_, ref generics) |
|
ItemKind::Enum(_, ref generics) |
|
||||||
ItemKind::Struct(_, ref generics) |
|
ItemKind::Struct(_, ref generics) |
|
||||||
ItemKind::Union(_, ref generics) => generics,
|
ItemKind::Union(_, ref generics) => generics,
|
||||||
|
@ -419,7 +420,11 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) {
|
||||||
convert_variant_ctor(tcx, struct_def.id());
|
convert_variant_ctor(tcx, struct_def.id());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hir::ItemKind::Existential(..) => {}
|
|
||||||
|
// Desugared from `impl Trait` -> visited by the function's return type
|
||||||
|
hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(_), .. }) => {}
|
||||||
|
|
||||||
|
hir::ItemKind::Existential(..) |
|
||||||
hir::ItemKind::Ty(..) |
|
hir::ItemKind::Ty(..) |
|
||||||
hir::ItemKind::Static(..) |
|
hir::ItemKind::Static(..) |
|
||||||
hir::ItemKind::Const(..) |
|
hir::ItemKind::Const(..) |
|
||||||
|
@ -1002,6 +1007,13 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report_assoc_ty_on_inherent_impl<'a, 'tcx>(
|
||||||
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
span: Span,
|
||||||
|
) {
|
||||||
|
span_err!(tcx.sess, span, E0202, "associated types are not allowed in inherent impls");
|
||||||
|
}
|
||||||
|
|
||||||
fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
def_id: DefId)
|
def_id: DefId)
|
||||||
-> Ty<'tcx> {
|
-> Ty<'tcx> {
|
||||||
|
@ -1034,10 +1046,16 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
tcx.mk_fn_def(def_id, substs)
|
tcx.mk_fn_def(def_id, substs)
|
||||||
}
|
}
|
||||||
ImplItemKind::Const(ref ty, _) => icx.to_ty(ty),
|
ImplItemKind::Const(ref ty, _) => icx.to_ty(ty),
|
||||||
|
ImplItemKind::Existential(ref _bounds) => {
|
||||||
|
if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() {
|
||||||
|
report_assoc_ty_on_inherent_impl(tcx, item.span);
|
||||||
|
}
|
||||||
|
// FIXME(oli-obk) implement existential types in trait impls
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
ImplItemKind::Type(ref ty) => {
|
ImplItemKind::Type(ref ty) => {
|
||||||
if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() {
|
if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() {
|
||||||
span_err!(tcx.sess, item.span, E0202,
|
report_assoc_ty_on_inherent_impl(tcx, item.span);
|
||||||
"associated types are not allowed in inherent impls");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
icx.to_ty(ty)
|
icx.to_ty(ty)
|
||||||
|
@ -1062,8 +1080,9 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
let substs = Substs::identity_for_item(tcx, def_id);
|
let substs = Substs::identity_for_item(tcx, def_id);
|
||||||
tcx.mk_adt(def, substs)
|
tcx.mk_adt(def, substs)
|
||||||
}
|
}
|
||||||
// this is only reachable once we have named existential types
|
ItemKind::Existential(hir::ExistTy { impl_trait_fn: None, .. }) => {
|
||||||
ItemKind::Existential(hir::ExistTy { impl_trait_fn: None, .. }) => unimplemented!(),
|
find_existential_constraints(tcx, def_id)
|
||||||
|
},
|
||||||
// existential types desugared from impl Trait
|
// existential types desugared from impl Trait
|
||||||
ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(owner), .. }) => {
|
ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(owner), .. }) => {
|
||||||
tcx.typeck_tables_of(owner).concrete_existential_types[&def_id]
|
tcx.typeck_tables_of(owner).concrete_existential_types[&def_id]
|
||||||
|
@ -1153,6 +1172,95 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_existential_constraints<'a, 'tcx>(
|
||||||
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
def_id: DefId,
|
||||||
|
) -> ty::Ty<'tcx> {
|
||||||
|
use rustc::hir::map::*;
|
||||||
|
use rustc::hir::*;
|
||||||
|
|
||||||
|
struct ConstraintLocator<'a, 'tcx: 'a> {
|
||||||
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
def_id: DefId,
|
||||||
|
found: Option<(Span, ty::Ty<'tcx>)>,
|
||||||
|
}
|
||||||
|
impl<'a, 'tcx> ConstraintLocator<'a, 'tcx> {
|
||||||
|
fn check(&mut self, node_id: ast::NodeId) {
|
||||||
|
let def_id = self.tcx.hir.local_def_id(node_id);
|
||||||
|
// don't try to check items that cannot possibly constrain the type
|
||||||
|
if !self.tcx.has_typeck_tables(def_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let ty = self
|
||||||
|
.tcx
|
||||||
|
.typeck_tables_of(def_id)
|
||||||
|
.concrete_existential_types
|
||||||
|
.get(&self.def_id)
|
||||||
|
.cloned();
|
||||||
|
if let Some(ty) = ty {
|
||||||
|
// FIXME(oli-obk): trace the actual span from inference to improve errors
|
||||||
|
let span = self.tcx.def_span(def_id);
|
||||||
|
if let Some((prev_span, prev_ty)) = self.found {
|
||||||
|
if ty != prev_ty {
|
||||||
|
// found different concrete types for the existential type
|
||||||
|
let mut err = self.tcx.sess.struct_span_err(
|
||||||
|
span,
|
||||||
|
"defining existential type use differs from previous",
|
||||||
|
);
|
||||||
|
err.span_note(prev_span, "previous use here");
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.found = Some((span, ty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, 'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'a, 'tcx> {
|
||||||
|
fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
|
||||||
|
intravisit::NestedVisitorMap::All(&self.tcx.hir)
|
||||||
|
}
|
||||||
|
fn visit_item(&mut self, it: &'tcx Item) {
|
||||||
|
// the existential type itself or its children are not within its reveal scope
|
||||||
|
if self.tcx.hir.local_def_id(it.id) != self.def_id {
|
||||||
|
self.check(it.id);
|
||||||
|
intravisit::walk_item(self, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_impl_item(&mut self, it: &'tcx ImplItem) {
|
||||||
|
// the existential type itself or its children are not within its reveal scope
|
||||||
|
if self.tcx.hir.local_def_id(it.id) != self.def_id {
|
||||||
|
self.check(it.id);
|
||||||
|
intravisit::walk_impl_item(self, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_trait_item(&mut self, it: &'tcx TraitItem) {
|
||||||
|
self.check(it.id);
|
||||||
|
intravisit::walk_trait_item(self, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut locator = ConstraintLocator { def_id, tcx, found: None };
|
||||||
|
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
|
||||||
|
let parent = tcx.hir.get_parent(node_id);
|
||||||
|
if parent == ast::CRATE_NODE_ID {
|
||||||
|
intravisit::walk_crate(&mut locator, tcx.hir.krate());
|
||||||
|
} else {
|
||||||
|
match tcx.hir.get(parent) {
|
||||||
|
NodeItem(ref it) => intravisit::walk_item(&mut locator, it),
|
||||||
|
NodeImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it),
|
||||||
|
other => bug!("{:?} is not a valid parent of an existential type item", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match locator.found {
|
||||||
|
Some((_, ty)) => ty,
|
||||||
|
None => {
|
||||||
|
let span = tcx.def_span(def_id);
|
||||||
|
tcx.sess.span_err(span, "could not find defining uses");
|
||||||
|
tcx.types.err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
def_id: DefId)
|
def_id: DefId)
|
||||||
-> ty::PolyFnSig<'tcx> {
|
-> ty::PolyFnSig<'tcx> {
|
||||||
|
@ -1366,6 +1474,9 @@ fn explicit_predicates_of<'a, 'tcx>(
|
||||||
|
|
||||||
let icx = ItemCtxt::new(tcx, def_id);
|
let icx = ItemCtxt::new(tcx, def_id);
|
||||||
let no_generics = hir::Generics::empty();
|
let no_generics = hir::Generics::empty();
|
||||||
|
|
||||||
|
let mut predicates = vec![];
|
||||||
|
|
||||||
let ast_generics = match node {
|
let ast_generics = match node {
|
||||||
NodeTraitItem(item) => {
|
NodeTraitItem(item) => {
|
||||||
&item.generics
|
&item.generics
|
||||||
|
@ -1391,23 +1502,28 @@ fn explicit_predicates_of<'a, 'tcx>(
|
||||||
is_trait = Some((ty::TraitRef::identity(tcx, def_id), items));
|
is_trait = Some((ty::TraitRef::identity(tcx, def_id), items));
|
||||||
generics
|
generics
|
||||||
}
|
}
|
||||||
ItemKind::Existential(ref exist_ty) => {
|
ItemKind::Existential(ExistTy { ref bounds, impl_trait_fn, ref generics }) => {
|
||||||
let substs = Substs::identity_for_item(tcx, def_id);
|
let substs = Substs::identity_for_item(tcx, def_id);
|
||||||
let anon_ty = tcx.mk_anon(def_id, substs);
|
let anon_ty = tcx.mk_anon(def_id, substs);
|
||||||
|
|
||||||
// Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
|
// Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
|
||||||
let bounds = compute_bounds(&icx,
|
let bounds = compute_bounds(&icx,
|
||||||
anon_ty,
|
anon_ty,
|
||||||
&exist_ty.bounds,
|
bounds,
|
||||||
SizedByDefault::Yes,
|
SizedByDefault::Yes,
|
||||||
tcx.def_span(def_id));
|
tcx.def_span(def_id));
|
||||||
|
|
||||||
let predicates = bounds.predicates(tcx, anon_ty);
|
if impl_trait_fn.is_some() {
|
||||||
|
// impl Trait
|
||||||
return ty::GenericPredicates {
|
return ty::GenericPredicates {
|
||||||
parent: None,
|
parent: None,
|
||||||
predicates: predicates
|
predicates: bounds.predicates(tcx, anon_ty),
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
// named existential types
|
||||||
|
predicates.extend(bounds.predicates(tcx, anon_ty));
|
||||||
|
generics
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => &no_generics,
|
_ => &no_generics,
|
||||||
|
@ -1429,8 +1545,6 @@ fn explicit_predicates_of<'a, 'tcx>(
|
||||||
let parent_count = generics.parent_count as u32;
|
let parent_count = generics.parent_count as u32;
|
||||||
let has_own_self = generics.has_self && parent_count == 0;
|
let has_own_self = generics.has_self && parent_count == 0;
|
||||||
|
|
||||||
let mut predicates = vec![];
|
|
||||||
|
|
||||||
// Below we'll consider the bounds on the type parameters (including `Self`)
|
// Below we'll consider the bounds on the type parameters (including `Self`)
|
||||||
// and the explicit where-clauses, but to get the full set of predicates
|
// and the explicit where-clauses, but to get the full set of predicates
|
||||||
// on a trait we need to add in the supertrait bounds and bounds found on
|
// on a trait we need to add in the supertrait bounds and bounds found on
|
||||||
|
|
|
@ -21,6 +21,7 @@ pub enum Namespace {
|
||||||
impl From<ty::AssociatedKind> for Namespace {
|
impl From<ty::AssociatedKind> for Namespace {
|
||||||
fn from(a_kind: ty::AssociatedKind) -> Self {
|
fn from(a_kind: ty::AssociatedKind) -> Self {
|
||||||
match a_kind {
|
match a_kind {
|
||||||
|
ty::AssociatedKind::Existential |
|
||||||
ty::AssociatedKind::Type => Namespace::Type,
|
ty::AssociatedKind::Type => Namespace::Type,
|
||||||
ty::AssociatedKind::Const |
|
ty::AssociatedKind::Const |
|
||||||
ty::AssociatedKind::Method => Namespace::Value,
|
ty::AssociatedKind::Method => Namespace::Value,
|
||||||
|
@ -31,6 +32,7 @@ impl From<ty::AssociatedKind> for Namespace {
|
||||||
impl<'a> From <&'a hir::ImplItemKind> for Namespace {
|
impl<'a> From <&'a hir::ImplItemKind> for Namespace {
|
||||||
fn from(impl_kind: &'a hir::ImplItemKind) -> Self {
|
fn from(impl_kind: &'a hir::ImplItemKind) -> Self {
|
||||||
match *impl_kind {
|
match *impl_kind {
|
||||||
|
hir::ImplItemKind::Existential(..) |
|
||||||
hir::ImplItemKind::Type(..) => Namespace::Type,
|
hir::ImplItemKind::Type(..) => Namespace::Type,
|
||||||
hir::ImplItemKind::Const(..) |
|
hir::ImplItemKind::Const(..) |
|
||||||
hir::ImplItemKind::Method(..) => Namespace::Value,
|
hir::ImplItemKind::Method(..) => Namespace::Value,
|
||||||
|
|
|
@ -512,6 +512,7 @@ pub enum ItemEnum {
|
||||||
FunctionItem(Function),
|
FunctionItem(Function),
|
||||||
ModuleItem(Module),
|
ModuleItem(Module),
|
||||||
TypedefItem(Typedef, bool /* is associated type */),
|
TypedefItem(Typedef, bool /* is associated type */),
|
||||||
|
ExistentialItem(Existential, bool /* is associated type */),
|
||||||
StaticItem(Static),
|
StaticItem(Static),
|
||||||
ConstantItem(Constant),
|
ConstantItem(Constant),
|
||||||
TraitItem(Trait),
|
TraitItem(Trait),
|
||||||
|
@ -545,6 +546,7 @@ impl ItemEnum {
|
||||||
ItemEnum::EnumItem(ref e) => &e.generics,
|
ItemEnum::EnumItem(ref e) => &e.generics,
|
||||||
ItemEnum::FunctionItem(ref f) => &f.generics,
|
ItemEnum::FunctionItem(ref f) => &f.generics,
|
||||||
ItemEnum::TypedefItem(ref t, _) => &t.generics,
|
ItemEnum::TypedefItem(ref t, _) => &t.generics,
|
||||||
|
ItemEnum::ExistentialItem(ref t, _) => &t.generics,
|
||||||
ItemEnum::TraitItem(ref t) => &t.generics,
|
ItemEnum::TraitItem(ref t) => &t.generics,
|
||||||
ItemEnum::ImplItem(ref i) => &i.generics,
|
ItemEnum::ImplItem(ref i) => &i.generics,
|
||||||
ItemEnum::TyMethodItem(ref i) => &i.generics,
|
ItemEnum::TyMethodItem(ref i) => &i.generics,
|
||||||
|
@ -596,6 +598,7 @@ impl Clean<Item> for doctree::Module {
|
||||||
items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx)));
|
items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx)));
|
||||||
items.extend(self.mods.iter().map(|x| x.clean(cx)));
|
items.extend(self.mods.iter().map(|x| x.clean(cx)));
|
||||||
items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
|
items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
|
||||||
|
items.extend(self.existentials.iter().map(|x| x.clean(cx)));
|
||||||
items.extend(self.statics.iter().map(|x| x.clean(cx)));
|
items.extend(self.statics.iter().map(|x| x.clean(cx)));
|
||||||
items.extend(self.constants.iter().map(|x| x.clean(cx)));
|
items.extend(self.constants.iter().map(|x| x.clean(cx)));
|
||||||
items.extend(self.traits.iter().map(|x| x.clean(cx)));
|
items.extend(self.traits.iter().map(|x| x.clean(cx)));
|
||||||
|
@ -2411,6 +2414,10 @@ impl Clean<Item> for hir::ImplItem {
|
||||||
type_: ty.clean(cx),
|
type_: ty.clean(cx),
|
||||||
generics: Generics::default(),
|
generics: Generics::default(),
|
||||||
}, true),
|
}, true),
|
||||||
|
hir::ImplItemKind::Existential(ref bounds) => ExistentialItem(Existential {
|
||||||
|
bounds: bounds.clean(cx),
|
||||||
|
generics: Generics::default(),
|
||||||
|
}, true),
|
||||||
};
|
};
|
||||||
Item {
|
Item {
|
||||||
name: Some(self.ident.name.clean(cx)),
|
name: Some(self.ident.name.clean(cx)),
|
||||||
|
@ -2554,6 +2561,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
|
||||||
}, true)
|
}, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ty::AssociatedKind::Existential => unimplemented!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let visibility = match self.container {
|
let visibility = match self.container {
|
||||||
|
@ -3696,6 +3704,30 @@ impl Clean<Item> for doctree::Typedef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||||
|
pub struct Existential {
|
||||||
|
pub bounds: Vec<GenericBound>,
|
||||||
|
pub generics: Generics,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clean<Item> for doctree::Existential {
|
||||||
|
fn clean(&self, cx: &DocContext) -> Item {
|
||||||
|
Item {
|
||||||
|
name: Some(self.name.clean(cx)),
|
||||||
|
attrs: self.attrs.clean(cx),
|
||||||
|
source: self.whence.clean(cx),
|
||||||
|
def_id: cx.tcx.hir.local_def_id(self.id.clone()),
|
||||||
|
visibility: self.vis.clean(cx),
|
||||||
|
stability: self.stab.clean(cx),
|
||||||
|
deprecation: self.depr.clean(cx),
|
||||||
|
inner: ExistentialItem(Existential {
|
||||||
|
bounds: self.exist_ty.bounds.clean(cx),
|
||||||
|
generics: self.exist_ty.generics.clean(cx),
|
||||||
|
}, false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct BareFunctionDecl {
|
pub struct BareFunctionDecl {
|
||||||
pub unsafety: hir::Unsafety,
|
pub unsafety: hir::Unsafety,
|
||||||
|
|
|
@ -37,6 +37,7 @@ pub struct Module {
|
||||||
pub mods: Vec<Module>,
|
pub mods: Vec<Module>,
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
pub typedefs: Vec<Typedef>,
|
pub typedefs: Vec<Typedef>,
|
||||||
|
pub existentials: Vec<Existential>,
|
||||||
pub statics: Vec<Static>,
|
pub statics: Vec<Static>,
|
||||||
pub constants: Vec<Constant>,
|
pub constants: Vec<Constant>,
|
||||||
pub traits: Vec<Trait>,
|
pub traits: Vec<Trait>,
|
||||||
|
@ -68,6 +69,7 @@ impl Module {
|
||||||
fns : Vec::new(),
|
fns : Vec::new(),
|
||||||
mods : Vec::new(),
|
mods : Vec::new(),
|
||||||
typedefs : Vec::new(),
|
typedefs : Vec::new(),
|
||||||
|
existentials: Vec::new(),
|
||||||
statics : Vec::new(),
|
statics : Vec::new(),
|
||||||
constants : Vec::new(),
|
constants : Vec::new(),
|
||||||
traits : Vec::new(),
|
traits : Vec::new(),
|
||||||
|
@ -167,6 +169,17 @@ pub struct Typedef {
|
||||||
pub depr: Option<attr::Deprecation>,
|
pub depr: Option<attr::Deprecation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Existential {
|
||||||
|
pub exist_ty: hir::ExistTy,
|
||||||
|
pub name: Name,
|
||||||
|
pub id: ast::NodeId,
|
||||||
|
pub attrs: hir::HirVec<ast::Attribute>,
|
||||||
|
pub whence: Span,
|
||||||
|
pub vis: hir::Visibility,
|
||||||
|
pub stab: Option<attr::Stability>,
|
||||||
|
pub depr: Option<attr::Deprecation>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Static {
|
pub struct Static {
|
||||||
pub type_: P<hir::Ty>,
|
pub type_: P<hir::Ty>,
|
||||||
|
|
|
@ -43,6 +43,7 @@ pub enum ItemType {
|
||||||
Union = 19,
|
Union = 19,
|
||||||
ForeignType = 20,
|
ForeignType = 20,
|
||||||
Keyword = 21,
|
Keyword = 21,
|
||||||
|
Existential = 22,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,6 +71,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
|
||||||
clean::EnumItem(..) => ItemType::Enum,
|
clean::EnumItem(..) => ItemType::Enum,
|
||||||
clean::FunctionItem(..) => ItemType::Function,
|
clean::FunctionItem(..) => ItemType::Function,
|
||||||
clean::TypedefItem(..) => ItemType::Typedef,
|
clean::TypedefItem(..) => ItemType::Typedef,
|
||||||
|
clean::ExistentialItem(..) => ItemType::Existential,
|
||||||
clean::StaticItem(..) => ItemType::Static,
|
clean::StaticItem(..) => ItemType::Static,
|
||||||
clean::ConstantItem(..) => ItemType::Constant,
|
clean::ConstantItem(..) => ItemType::Constant,
|
||||||
clean::TraitItem(..) => ItemType::Trait,
|
clean::TraitItem(..) => ItemType::Trait,
|
||||||
|
@ -135,6 +137,7 @@ impl ItemType {
|
||||||
ItemType::AssociatedConst => "associatedconstant",
|
ItemType::AssociatedConst => "associatedconstant",
|
||||||
ItemType::ForeignType => "foreigntype",
|
ItemType::ForeignType => "foreigntype",
|
||||||
ItemType::Keyword => "keyword",
|
ItemType::Keyword => "keyword",
|
||||||
|
ItemType::Existential => "existential",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +151,7 @@ impl ItemType {
|
||||||
ItemType::Trait |
|
ItemType::Trait |
|
||||||
ItemType::Primitive |
|
ItemType::Primitive |
|
||||||
ItemType::AssociatedType |
|
ItemType::AssociatedType |
|
||||||
|
ItemType::Existential |
|
||||||
ItemType::ForeignType => NameSpace::Type,
|
ItemType::ForeignType => NameSpace::Type,
|
||||||
|
|
||||||
ItemType::ExternCrate |
|
ItemType::ExternCrate |
|
||||||
|
|
|
@ -1570,6 +1570,7 @@ struct AllTypes {
|
||||||
macros: HashSet<ItemEntry>,
|
macros: HashSet<ItemEntry>,
|
||||||
functions: HashSet<ItemEntry>,
|
functions: HashSet<ItemEntry>,
|
||||||
typedefs: HashSet<ItemEntry>,
|
typedefs: HashSet<ItemEntry>,
|
||||||
|
existentials: HashSet<ItemEntry>,
|
||||||
statics: HashSet<ItemEntry>,
|
statics: HashSet<ItemEntry>,
|
||||||
constants: HashSet<ItemEntry>,
|
constants: HashSet<ItemEntry>,
|
||||||
keywords: HashSet<ItemEntry>,
|
keywords: HashSet<ItemEntry>,
|
||||||
|
@ -1586,6 +1587,7 @@ impl AllTypes {
|
||||||
macros: HashSet::with_capacity(100),
|
macros: HashSet::with_capacity(100),
|
||||||
functions: HashSet::with_capacity(100),
|
functions: HashSet::with_capacity(100),
|
||||||
typedefs: HashSet::with_capacity(100),
|
typedefs: HashSet::with_capacity(100),
|
||||||
|
existentials: HashSet::with_capacity(100),
|
||||||
statics: HashSet::with_capacity(100),
|
statics: HashSet::with_capacity(100),
|
||||||
constants: HashSet::with_capacity(100),
|
constants: HashSet::with_capacity(100),
|
||||||
keywords: HashSet::with_capacity(100),
|
keywords: HashSet::with_capacity(100),
|
||||||
|
@ -1607,6 +1609,7 @@ impl AllTypes {
|
||||||
ItemType::Macro => self.macros.insert(ItemEntry::new(new_url, name)),
|
ItemType::Macro => self.macros.insert(ItemEntry::new(new_url, name)),
|
||||||
ItemType::Function => self.functions.insert(ItemEntry::new(new_url, name)),
|
ItemType::Function => self.functions.insert(ItemEntry::new(new_url, name)),
|
||||||
ItemType::Typedef => self.typedefs.insert(ItemEntry::new(new_url, name)),
|
ItemType::Typedef => self.typedefs.insert(ItemEntry::new(new_url, name)),
|
||||||
|
ItemType::Existential => self.existentials.insert(ItemEntry::new(new_url, name)),
|
||||||
ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)),
|
ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)),
|
||||||
ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
|
ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
|
||||||
_ => true,
|
_ => true,
|
||||||
|
@ -1650,6 +1653,7 @@ impl fmt::Display for AllTypes {
|
||||||
print_entries(f, &self.macros, "Macros", "macros")?;
|
print_entries(f, &self.macros, "Macros", "macros")?;
|
||||||
print_entries(f, &self.functions, "Functions", "functions")?;
|
print_entries(f, &self.functions, "Functions", "functions")?;
|
||||||
print_entries(f, &self.typedefs, "Typedefs", "typedefs")?;
|
print_entries(f, &self.typedefs, "Typedefs", "typedefs")?;
|
||||||
|
print_entries(f, &self.existentials, "Existentials", "existentials")?;
|
||||||
print_entries(f, &self.statics, "Statics", "statics")?;
|
print_entries(f, &self.statics, "Statics", "statics")?;
|
||||||
print_entries(f, &self.constants, "Constants", "constants")
|
print_entries(f, &self.constants, "Constants", "constants")
|
||||||
}
|
}
|
||||||
|
@ -4400,6 +4404,7 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
|
||||||
ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
|
ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
|
||||||
ItemType::ForeignType => ("foreign-types", "Foreign Types"),
|
ItemType::ForeignType => ("foreign-types", "Foreign Types"),
|
||||||
ItemType::Keyword => ("keywords", "Keywords"),
|
ItemType::Keyword => ("keywords", "Keywords"),
|
||||||
|
ItemType::Existential => ("existentials", "Existentials"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
// These items can all get re-exported
|
// These items can all get re-exported
|
||||||
|
clean::ExistentialItem(..) |
|
||||||
clean::TypedefItem(..) | clean::StaticItem(..) |
|
clean::TypedefItem(..) | clean::StaticItem(..) |
|
||||||
clean::StructItem(..) | clean::EnumItem(..) |
|
clean::StructItem(..) | clean::EnumItem(..) |
|
||||||
clean::TraitItem(..) | clean::FunctionItem(..) |
|
clean::TraitItem(..) | clean::FunctionItem(..) |
|
||||||
|
|
|
@ -439,6 +439,19 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
|
||||||
};
|
};
|
||||||
om.typedefs.push(t);
|
om.typedefs.push(t);
|
||||||
},
|
},
|
||||||
|
hir::ItemKind::Existential(ref exist_ty) => {
|
||||||
|
let t = Existential {
|
||||||
|
exist_ty: exist_ty.clone(),
|
||||||
|
name,
|
||||||
|
id: item.id,
|
||||||
|
attrs: item.attrs.clone(),
|
||||||
|
whence: item.span,
|
||||||
|
vis: item.vis.clone(),
|
||||||
|
stab: self.stability(item.id),
|
||||||
|
depr: self.deprecation(item.id),
|
||||||
|
};
|
||||||
|
om.existentials.push(t);
|
||||||
|
},
|
||||||
hir::ItemKind::Static(ref ty, ref mut_, ref exp) => {
|
hir::ItemKind::Static(ref ty, ref mut_, ref exp) => {
|
||||||
let s = Static {
|
let s = Static {
|
||||||
type_: ty.clone(),
|
type_: ty.clone(),
|
||||||
|
@ -523,9 +536,6 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
|
||||||
om.impls.push(i);
|
om.impls.push(i);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hir::ItemKind::Existential(_) => {
|
|
||||||
// FIXME(oli-obk): actually generate docs for real existential items
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1394,6 +1394,7 @@ pub enum ImplItemKind {
|
||||||
Const(P<Ty>, P<Expr>),
|
Const(P<Ty>, P<Expr>),
|
||||||
Method(MethodSig, P<Block>),
|
Method(MethodSig, P<Block>),
|
||||||
Type(P<Ty>),
|
Type(P<Ty>),
|
||||||
|
Existential(GenericBounds),
|
||||||
Macro(Mac),
|
Macro(Mac),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2132,6 +2133,10 @@ pub enum ItemKind {
|
||||||
///
|
///
|
||||||
/// E.g. `type Foo = Bar<u8>;`
|
/// E.g. `type Foo = Bar<u8>;`
|
||||||
Ty(P<Ty>, Generics),
|
Ty(P<Ty>, Generics),
|
||||||
|
/// An existential type declaration (`existential type`).
|
||||||
|
///
|
||||||
|
/// E.g. `existential type Foo: Bar + Boo;`
|
||||||
|
Existential(GenericBounds, Generics),
|
||||||
/// An enum definition (`enum` or `pub enum`).
|
/// An enum definition (`enum` or `pub enum`).
|
||||||
///
|
///
|
||||||
/// E.g. `enum Foo<A, B> { C<A>, D<B> }`
|
/// E.g. `enum Foo<A, B> { C<A>, D<B> }`
|
||||||
|
@ -2183,6 +2188,7 @@ impl ItemKind {
|
||||||
ItemKind::ForeignMod(..) => "foreign module",
|
ItemKind::ForeignMod(..) => "foreign module",
|
||||||
ItemKind::GlobalAsm(..) => "global asm",
|
ItemKind::GlobalAsm(..) => "global asm",
|
||||||
ItemKind::Ty(..) => "type alias",
|
ItemKind::Ty(..) => "type alias",
|
||||||
|
ItemKind::Existential(..) => "existential type",
|
||||||
ItemKind::Enum(..) => "enum",
|
ItemKind::Enum(..) => "enum",
|
||||||
ItemKind::Struct(..) => "struct",
|
ItemKind::Struct(..) => "struct",
|
||||||
ItemKind::Union(..) => "union",
|
ItemKind::Union(..) => "union",
|
||||||
|
|
|
@ -419,6 +419,9 @@ declare_features! (
|
||||||
// Allows macro invocations in `extern {}` blocks
|
// Allows macro invocations in `extern {}` blocks
|
||||||
(active, macros_in_extern, "1.27.0", Some(49476), None),
|
(active, macros_in_extern, "1.27.0", Some(49476), None),
|
||||||
|
|
||||||
|
// `existential type`
|
||||||
|
(active, existential_type, "1.28.0", Some(34511), None),
|
||||||
|
|
||||||
// unstable #[target_feature] directives
|
// unstable #[target_feature] directives
|
||||||
(active, arm_target_feature, "1.27.0", Some(44839), None),
|
(active, arm_target_feature, "1.27.0", Some(44839), None),
|
||||||
(active, aarch64_target_feature, "1.27.0", Some(44839), None),
|
(active, aarch64_target_feature, "1.27.0", Some(44839), None),
|
||||||
|
@ -1643,6 +1646,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
gate_feature_post!(&self, decl_macro, i.span, msg);
|
gate_feature_post!(&self, decl_macro, i.span, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast::ItemKind::Existential(..) => {
|
||||||
|
gate_feature_post!(
|
||||||
|
&self,
|
||||||
|
existential_type,
|
||||||
|
i.span,
|
||||||
|
"existential types are unstable"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1842,6 +1854,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
|
gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast::ImplItemKind::Existential(..) => {
|
||||||
|
gate_feature_post!(
|
||||||
|
&self,
|
||||||
|
existential_type,
|
||||||
|
ii.span,
|
||||||
|
"existential types are unstable"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ast::ImplItemKind::Type(_) if !ii.generics.params.is_empty() => {
|
ast::ImplItemKind::Type(_) if !ii.generics.params.is_empty() => {
|
||||||
gate_feature_post!(&self, generic_associated_types, ii.span,
|
gate_feature_post!(&self, generic_associated_types, ii.span,
|
||||||
"generic associated types are unstable");
|
"generic associated types are unstable");
|
||||||
|
|
|
@ -912,6 +912,10 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
|
||||||
ItemKind::Ty(t, generics) => {
|
ItemKind::Ty(t, generics) => {
|
||||||
ItemKind::Ty(folder.fold_ty(t), folder.fold_generics(generics))
|
ItemKind::Ty(folder.fold_ty(t), folder.fold_generics(generics))
|
||||||
}
|
}
|
||||||
|
ItemKind::Existential(bounds, generics) => ItemKind::Existential(
|
||||||
|
folder.fold_bounds(bounds),
|
||||||
|
folder.fold_generics(generics),
|
||||||
|
),
|
||||||
ItemKind::Enum(enum_definition, generics) => {
|
ItemKind::Enum(enum_definition, generics) => {
|
||||||
let generics = folder.fold_generics(generics);
|
let generics = folder.fold_generics(generics);
|
||||||
let variants = enum_definition.variants.move_map(|x| folder.fold_variant(x));
|
let variants = enum_definition.variants.move_map(|x| folder.fold_variant(x));
|
||||||
|
@ -1002,6 +1006,9 @@ pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T)
|
||||||
folder.fold_block(body))
|
folder.fold_block(body))
|
||||||
}
|
}
|
||||||
ast::ImplItemKind::Type(ty) => ast::ImplItemKind::Type(folder.fold_ty(ty)),
|
ast::ImplItemKind::Type(ty) => ast::ImplItemKind::Type(folder.fold_ty(ty)),
|
||||||
|
ast::ImplItemKind::Existential(bounds) => {
|
||||||
|
ast::ImplItemKind::Existential(folder.fold_bounds(bounds))
|
||||||
|
},
|
||||||
ast::ImplItemKind::Macro(mac) => ast::ImplItemKind::Macro(folder.fold_mac(mac))
|
ast::ImplItemKind::Macro(mac) => ast::ImplItemKind::Macro(folder.fold_mac(mac))
|
||||||
},
|
},
|
||||||
span: folder.new_span(i.span),
|
span: folder.new_span(i.span),
|
||||||
|
|
|
@ -63,6 +63,15 @@ use std::mem;
|
||||||
use std::path::{self, Path, PathBuf};
|
use std::path::{self, Path, PathBuf};
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// Whether the type alias or associated type is a concrete type or an existential type
|
||||||
|
pub enum AliasKind {
|
||||||
|
/// Just a new name for the same type
|
||||||
|
Weak(P<Ty>),
|
||||||
|
/// Only trait impls of the type will be usable, not the actual type itself
|
||||||
|
Existential(GenericBounds),
|
||||||
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
struct Restrictions: u8 {
|
struct Restrictions: u8 {
|
||||||
const STMT_EXPR = 1 << 0;
|
const STMT_EXPR = 1 << 0;
|
||||||
|
@ -5502,16 +5511,13 @@ impl<'a> Parser<'a> {
|
||||||
let lo = self.span;
|
let lo = self.span;
|
||||||
let vis = self.parse_visibility(false)?;
|
let vis = self.parse_visibility(false)?;
|
||||||
let defaultness = self.parse_defaultness();
|
let defaultness = self.parse_defaultness();
|
||||||
let (name, node, generics) = if self.eat_keyword(keywords::Type) {
|
let (name, node, generics) = if let Some(type_) = self.eat_type() {
|
||||||
// This parses the grammar:
|
let (name, alias, generics) = type_?;
|
||||||
// ImplItemAssocTy = Ident ["<"...">"] ["where" ...] "=" Ty ";"
|
let kind = match alias {
|
||||||
let name = self.parse_ident()?;
|
AliasKind::Weak(typ) => ast::ImplItemKind::Type(typ),
|
||||||
let mut generics = self.parse_generics()?;
|
AliasKind::Existential(bounds) => ast::ImplItemKind::Existential(bounds),
|
||||||
generics.where_clause = self.parse_where_clause()?;
|
};
|
||||||
self.expect(&token::Eq)?;
|
(name, kind, generics)
|
||||||
let typ = self.parse_ty()?;
|
|
||||||
self.expect(&token::Semi)?;
|
|
||||||
(name, ast::ImplItemKind::Type(typ), generics)
|
|
||||||
} else if self.is_const_item() {
|
} else if self.is_const_item() {
|
||||||
// This parses the grammar:
|
// This parses the grammar:
|
||||||
// ImplItemConst = "const" Ident ":" Ty "=" Expr ";"
|
// ImplItemConst = "const" Ident ":" Ty "=" Expr ";"
|
||||||
|
@ -6563,14 +6569,43 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse type Foo = Bar;
|
/// Parse type Foo = Bar;
|
||||||
fn parse_item_type(&mut self) -> PResult<'a, ItemInfo> {
|
/// or
|
||||||
|
/// existential type Foo: Bar;
|
||||||
|
/// or
|
||||||
|
/// return None without modifying the parser state
|
||||||
|
fn eat_type(&mut self) -> Option<PResult<'a, (Ident, AliasKind, ast::Generics)>> {
|
||||||
|
// This parses the grammar:
|
||||||
|
// Ident ["<"...">"] ["where" ...] ("=" | ":") Ty ";"
|
||||||
|
if self.check_keyword(keywords::Type) ||
|
||||||
|
self.check_keyword(keywords::Existential) &&
|
||||||
|
self.look_ahead(1, |t| t.is_keyword(keywords::Type)) {
|
||||||
|
let existential = self.eat_keyword(keywords::Existential);
|
||||||
|
assert!(self.eat_keyword(keywords::Type));
|
||||||
|
Some(self.parse_existential_or_alias(existential))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse type alias or existential type
|
||||||
|
fn parse_existential_or_alias(
|
||||||
|
&mut self,
|
||||||
|
existential: bool,
|
||||||
|
) -> PResult<'a, (Ident, AliasKind, ast::Generics)> {
|
||||||
let ident = self.parse_ident()?;
|
let ident = self.parse_ident()?;
|
||||||
let mut tps = self.parse_generics()?;
|
let mut tps = self.parse_generics()?;
|
||||||
tps.where_clause = self.parse_where_clause()?;
|
tps.where_clause = self.parse_where_clause()?;
|
||||||
|
let alias = if existential {
|
||||||
|
self.expect(&token::Colon)?;
|
||||||
|
let bounds = self.parse_generic_bounds()?;
|
||||||
|
AliasKind::Existential(bounds)
|
||||||
|
} else {
|
||||||
self.expect(&token::Eq)?;
|
self.expect(&token::Eq)?;
|
||||||
let ty = self.parse_ty()?;
|
let ty = self.parse_ty()?;
|
||||||
|
AliasKind::Weak(ty)
|
||||||
|
};
|
||||||
self.expect(&token::Semi)?;
|
self.expect(&token::Semi)?;
|
||||||
Ok((ident, ItemKind::Ty(ty, tps), None))
|
Ok((ident, alias, tps))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the part of an "enum" decl following the '{'
|
/// Parse the part of an "enum" decl following the '{'
|
||||||
|
@ -6926,15 +6961,19 @@ impl<'a> Parser<'a> {
|
||||||
maybe_append(attrs, extra_attrs));
|
maybe_append(attrs, extra_attrs));
|
||||||
return Ok(Some(item));
|
return Ok(Some(item));
|
||||||
}
|
}
|
||||||
if self.eat_keyword(keywords::Type) {
|
if let Some(type_) = self.eat_type() {
|
||||||
|
let (ident, alias, generics) = type_?;
|
||||||
// TYPE ITEM
|
// TYPE ITEM
|
||||||
let (ident, item_, extra_attrs) = self.parse_item_type()?;
|
let item_ = match alias {
|
||||||
|
AliasKind::Weak(ty) => ItemKind::Ty(ty, generics),
|
||||||
|
AliasKind::Existential(bounds) => ItemKind::Existential(bounds, generics),
|
||||||
|
};
|
||||||
let prev_span = self.prev_span;
|
let prev_span = self.prev_span;
|
||||||
let item = self.mk_item(lo.to(prev_span),
|
let item = self.mk_item(lo.to(prev_span),
|
||||||
ident,
|
ident,
|
||||||
item_,
|
item_,
|
||||||
visibility,
|
visibility,
|
||||||
maybe_append(attrs, extra_attrs));
|
attrs);
|
||||||
return Ok(Some(item));
|
return Ok(Some(item));
|
||||||
}
|
}
|
||||||
if self.eat_keyword(keywords::Enum) {
|
if self.eat_keyword(keywords::Enum) {
|
||||||
|
|
|
@ -1280,9 +1280,7 @@ impl<'a> State<'a> {
|
||||||
self.end()?;
|
self.end()?;
|
||||||
}
|
}
|
||||||
ast::ItemKind::Ty(ref ty, ref generics) => {
|
ast::ItemKind::Ty(ref ty, ref generics) => {
|
||||||
self.ibox(INDENT_UNIT)?;
|
self.head(&visibility_qualified(&item.vis, "type"))?;
|
||||||
self.ibox(0)?;
|
|
||||||
self.word_nbsp(&visibility_qualified(&item.vis, "type"))?;
|
|
||||||
self.print_ident(item.ident)?;
|
self.print_ident(item.ident)?;
|
||||||
self.print_generic_params(&generics.params)?;
|
self.print_generic_params(&generics.params)?;
|
||||||
self.end()?; // end the inner ibox
|
self.end()?; // end the inner ibox
|
||||||
|
@ -1294,6 +1292,18 @@ impl<'a> State<'a> {
|
||||||
self.s.word(";")?;
|
self.s.word(";")?;
|
||||||
self.end()?; // end the outer ibox
|
self.end()?; // end the outer ibox
|
||||||
}
|
}
|
||||||
|
ast::ItemKind::Existential(ref bounds, ref generics) => {
|
||||||
|
self.head(&visibility_qualified(&item.vis, "existential type"))?;
|
||||||
|
self.print_ident(item.ident)?;
|
||||||
|
self.print_generic_params(&generics.params)?;
|
||||||
|
self.end()?; // end the inner ibox
|
||||||
|
|
||||||
|
self.print_where_clause(&generics.where_clause)?;
|
||||||
|
self.s.space()?;
|
||||||
|
self.print_type_bounds(":", bounds)?;
|
||||||
|
self.s.word(";")?;
|
||||||
|
self.end()?; // end the outer ibox
|
||||||
|
}
|
||||||
ast::ItemKind::Enum(ref enum_definition, ref params) => {
|
ast::ItemKind::Enum(ref enum_definition, ref params) => {
|
||||||
self.print_enum_def(
|
self.print_enum_def(
|
||||||
enum_definition,
|
enum_definition,
|
||||||
|
@ -1501,8 +1511,8 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_defaultness(&mut self, defatulness: ast::Defaultness) -> io::Result<()> {
|
pub fn print_defaultness(&mut self, defaultness: ast::Defaultness) -> io::Result<()> {
|
||||||
if let ast::Defaultness::Default = defatulness {
|
if let ast::Defaultness::Default = defaultness {
|
||||||
try!(self.word_nbsp("default"));
|
try!(self.word_nbsp("default"));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1650,6 +1660,10 @@ impl<'a> State<'a> {
|
||||||
ast::ImplItemKind::Type(ref ty) => {
|
ast::ImplItemKind::Type(ref ty) => {
|
||||||
self.print_associated_type(ii.ident, None, Some(ty))?;
|
self.print_associated_type(ii.ident, None, Some(ty))?;
|
||||||
}
|
}
|
||||||
|
ast::ImplItemKind::Existential(ref bounds) => {
|
||||||
|
self.word_space("existential")?;
|
||||||
|
self.print_associated_type(ii.ident, Some(bounds), None)?;
|
||||||
|
}
|
||||||
ast::ImplItemKind::Macro(ref mac) => {
|
ast::ImplItemKind::Macro(ref mac) => {
|
||||||
self.print_mac(mac)?;
|
self.print_mac(mac)?;
|
||||||
match mac.node.delim {
|
match mac.node.delim {
|
||||||
|
|
|
@ -252,6 +252,10 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
|
||||||
visitor.visit_ty(typ);
|
visitor.visit_ty(typ);
|
||||||
visitor.visit_generics(type_parameters)
|
visitor.visit_generics(type_parameters)
|
||||||
}
|
}
|
||||||
|
ItemKind::Existential(ref bounds, ref type_parameters) => {
|
||||||
|
walk_list!(visitor, visit_param_bound, bounds);
|
||||||
|
visitor.visit_generics(type_parameters)
|
||||||
|
}
|
||||||
ItemKind::Enum(ref enum_definition, ref type_parameters) => {
|
ItemKind::Enum(ref enum_definition, ref type_parameters) => {
|
||||||
visitor.visit_generics(type_parameters);
|
visitor.visit_generics(type_parameters);
|
||||||
visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span)
|
visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span)
|
||||||
|
@ -600,6 +604,9 @@ pub fn walk_impl_item<'a, V: Visitor<'a>>(visitor: &mut V, impl_item: &'a ImplIt
|
||||||
ImplItemKind::Type(ref ty) => {
|
ImplItemKind::Type(ref ty) => {
|
||||||
visitor.visit_ty(ty);
|
visitor.visit_ty(ty);
|
||||||
}
|
}
|
||||||
|
ImplItemKind::Existential(ref bounds) => {
|
||||||
|
walk_list!(visitor, visit_param_bound, bounds);
|
||||||
|
}
|
||||||
ImplItemKind::Macro(ref mac) => {
|
ImplItemKind::Macro(ref mac) => {
|
||||||
visitor.visit_mac(mac);
|
visitor.visit_mac(mac);
|
||||||
}
|
}
|
||||||
|
|
|
@ -426,6 +426,7 @@ declare_keywords! {
|
||||||
(56, Default, "default")
|
(56, Default, "default")
|
||||||
(57, Dyn, "dyn")
|
(57, Dyn, "dyn")
|
||||||
(58, Union, "union")
|
(58, Union, "union")
|
||||||
|
(59, Existential, "existential")
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol {
|
impl Symbol {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
// compile-flags: -Z parse-only
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
struct Foo;
|
struct Foo;
|
||||||
|
|
||||||
|
@ -16,6 +17,6 @@ impl Foo {
|
||||||
fn foo() {}
|
fn foo() {}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or
|
} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, or
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -9,11 +9,12 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
// compile-flags: -Z parse-only
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
struct Foo;
|
struct Foo;
|
||||||
|
|
||||||
impl Foo {
|
impl Foo {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or
|
} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, or
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -9,10 +9,11 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
// compile-flags: -Z parse-only
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
impl S {
|
impl S {
|
||||||
static fn f() {}
|
static fn f() {}
|
||||||
}
|
}
|
||||||
//~^^ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`,
|
//~^^ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`,
|
||||||
|
|
113
src/test/run-pass/existential_type.rs
Normal file
113
src/test/run-pass/existential_type.rs
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#![feature(existential_type)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(foo().to_string(), "foo");
|
||||||
|
assert_eq!(bar1().to_string(), "bar1");
|
||||||
|
assert_eq!(bar2().to_string(), "bar2");
|
||||||
|
let mut x = bar1();
|
||||||
|
x = bar2();
|
||||||
|
assert_eq!(boo::boo().to_string(), "boo");
|
||||||
|
assert_eq!(my_iter(42u8).collect::<Vec<u8>>(), vec![42u8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// single definition
|
||||||
|
existential type Foo: std::fmt::Display;
|
||||||
|
|
||||||
|
fn foo() -> Foo {
|
||||||
|
"foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
// two definitions
|
||||||
|
existential type Bar: std::fmt::Display;
|
||||||
|
|
||||||
|
fn bar1() -> Bar {
|
||||||
|
"bar1"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar2() -> Bar {
|
||||||
|
"bar2"
|
||||||
|
}
|
||||||
|
|
||||||
|
// definition in submodule
|
||||||
|
existential type Boo: std::fmt::Display;
|
||||||
|
|
||||||
|
mod boo {
|
||||||
|
pub fn boo() -> super::Boo {
|
||||||
|
"boo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
existential type MyIter<T>: Iterator<Item = T>;
|
||||||
|
|
||||||
|
fn my_iter<T>(t: T) -> MyIter<T> {
|
||||||
|
std::iter::once(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn my_iter2<T>(t: T) -> MyIter<T> {
|
||||||
|
std::iter::once(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// param names should not have an effect!
|
||||||
|
fn my_iter3<U>(u: U) -> MyIter<U> {
|
||||||
|
std::iter::once(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
// param position should not have an effect!
|
||||||
|
fn my_iter4<U, V>(_: U, v: V) -> MyIter<V> {
|
||||||
|
std::iter::once(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// param names should not have an effect!
|
||||||
|
existential type MyOtherIter<T>: Iterator<Item = T>;
|
||||||
|
|
||||||
|
fn my_other_iter<U>(u: U) -> MyOtherIter<U> {
|
||||||
|
std::iter::once(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Trait {}
|
||||||
|
existential type GenericBound<T: Trait>: 'static;
|
||||||
|
|
||||||
|
fn generic_bound<T: Trait>(_: T) -> GenericBound<T> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
mod pass_through {
|
||||||
|
pub existential type Passthrough<T>: 'static;
|
||||||
|
|
||||||
|
fn define_passthrough<T: 'static>(t: T) -> Passthrough<T> {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_passthrough(x: pass_through::Passthrough<u32>) -> pass_through::Passthrough<u32> {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
existential type PartiallyDefined<T>: 'static;
|
||||||
|
|
||||||
|
// doesn't declare all PartiallyDefined for all possible `T`, but since it's the only
|
||||||
|
// function producing the value, noone can ever get a value that is problematic
|
||||||
|
fn partially_defined<T: std::fmt::Debug>(_: T) -> PartiallyDefined<T> {
|
||||||
|
4u32
|
||||||
|
}
|
||||||
|
|
||||||
|
existential type PartiallyDefined2<T>: 'static;
|
||||||
|
|
||||||
|
fn partially_defined2<T: std::fmt::Debug>(_: T) -> PartiallyDefined2<T> {
|
||||||
|
4u32
|
||||||
|
}
|
||||||
|
|
||||||
|
// fully defines PartiallyDefine2
|
||||||
|
fn partially_defined22<T>(_: T) -> PartiallyDefined2<T> {
|
||||||
|
4u32
|
||||||
|
}
|
111
src/test/ui/existential_type.nll.stderr
Normal file
111
src/test/ui/existential_type.nll.stderr
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
error: defining existential type use differs from previous
|
||||||
|
--> $DIR/existential_type.rs:23:1
|
||||||
|
|
|
||||||
|
LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
|
||||||
|
LL | | 42i32
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
note: previous use here
|
||||||
|
--> $DIR/existential_type.rs:19:1
|
||||||
|
|
|
||||||
|
LL | / fn foo() -> Foo {
|
||||||
|
LL | | ""
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/existential_type.rs:36:5
|
||||||
|
|
|
||||||
|
LL | fn bomp() -> boo::Boo {
|
||||||
|
| -------- expected `Boo` because of return type
|
||||||
|
LL | "" //~ ERROR mismatched types
|
||||||
|
| ^^ expected anonymized type, found reference
|
||||||
|
|
|
||||||
|
= note: expected type `Boo`
|
||||||
|
found type `&'static str`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/existential_type.rs:50:23
|
||||||
|
|
|
||||||
|
LL | let _: &str = bomp(); //~ ERROR mismatched types
|
||||||
|
| ^^^^^^ expected &str, found anonymized type
|
||||||
|
|
|
||||||
|
= note: expected type `&str`
|
||||||
|
found type `Boo`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/existential_type.rs:54:9
|
||||||
|
|
|
||||||
|
LL | fn bomp() -> boo::Boo {
|
||||||
|
| -------- expected `Boo` because of return type
|
||||||
|
LL | "" //~ ERROR mismatched types
|
||||||
|
| ^^ expected anonymized type, found reference
|
||||||
|
|
|
||||||
|
= note: expected type `Boo`
|
||||||
|
found type `&'static str`
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `T: Trait` is not satisfied
|
||||||
|
--> $DIR/existential_type.rs:61:1
|
||||||
|
|
|
||||||
|
LL | existential type Underconstrained<T: Trait>: 'static; //~ ERROR the trait bound `T: Trait`
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
|
||||||
|
|
|
||||||
|
= help: consider adding a `where T: Trait` bound
|
||||||
|
= note: the return type of a function must have a statically known size
|
||||||
|
|
||||||
|
warning: not reporting region error due to nll
|
||||||
|
--> $DIR/existential_type.rs:78:1
|
||||||
|
|
|
||||||
|
LL | existential type WrongGeneric<T>: 'static;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/existential_type.rs:93:27
|
||||||
|
|
|
||||||
|
LL | let _: &'static str = x; //~ mismatched types
|
||||||
|
| ^ expected reference, found anonymized type
|
||||||
|
|
|
||||||
|
= note: expected type `&'static str`
|
||||||
|
found type `NoReveal`
|
||||||
|
|
||||||
|
error[E0605]: non-primitive cast: `NoReveal` as `&'static str`
|
||||||
|
--> $DIR/existential_type.rs:94:13
|
||||||
|
|
|
||||||
|
LL | let _ = x as &'static str; //~ non-primitive cast
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
|
||||||
|
|
||||||
|
error: could not find defining uses
|
||||||
|
--> $DIR/existential_type.rs:28:1
|
||||||
|
|
|
||||||
|
LL | existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: could not find defining uses
|
||||||
|
--> $DIR/existential_type.rs:32:5
|
||||||
|
|
|
||||||
|
LL | pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: defining existential type use differs from previous
|
||||||
|
--> $DIR/existential_type.rs:74:1
|
||||||
|
|
|
||||||
|
LL | / fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR defining existential type use differs from previous
|
||||||
|
LL | | Some(t).into_iter()
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
note: previous use here
|
||||||
|
--> $DIR/existential_type.rs:70:1
|
||||||
|
|
|
||||||
|
LL | / fn my_iter<T>(t: T) -> MyIter<T> {
|
||||||
|
LL | | std::iter::once(t)
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
|
error: aborting due to 10 previous errors
|
||||||
|
|
||||||
|
Some errors occurred: E0277, E0308, E0605.
|
||||||
|
For more information about an error, try `rustc --explain E0277`.
|
95
src/test/ui/existential_type.rs
Normal file
95
src/test/ui/existential_type.rs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
|
||||||
|
#![feature(existential_type)]
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
// two definitions with different types
|
||||||
|
existential type Foo: std::fmt::Debug;
|
||||||
|
|
||||||
|
fn foo() -> Foo {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
|
||||||
|
42i32
|
||||||
|
}
|
||||||
|
|
||||||
|
// declared but never defined
|
||||||
|
existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses
|
||||||
|
|
||||||
|
mod boo {
|
||||||
|
// declared in module but not defined inside of it
|
||||||
|
pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bomp() -> boo::Boo {
|
||||||
|
"" //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
mod boo2 {
|
||||||
|
mod boo {
|
||||||
|
pub existential type Boo: ::std::fmt::Debug;
|
||||||
|
fn bomp() -> Boo {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't actually know the type here
|
||||||
|
|
||||||
|
fn bomp2() {
|
||||||
|
let _: &str = bomp(); //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bomp() -> boo::Boo {
|
||||||
|
"" //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generics
|
||||||
|
|
||||||
|
trait Trait {}
|
||||||
|
existential type Underconstrained<T: Trait>: 'static; //~ ERROR the trait bound `T: Trait`
|
||||||
|
|
||||||
|
// no `Trait` bound
|
||||||
|
fn underconstrain<T>(_: T) -> Underconstrained<T> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
existential type MyIter<T>: Iterator<Item = T>;
|
||||||
|
|
||||||
|
fn my_iter<T>(t: T) -> MyIter<T> {
|
||||||
|
std::iter::once(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR defining existential type use differs from previous
|
||||||
|
Some(t).into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
existential type WrongGeneric<T>: 'static;
|
||||||
|
//~^ ERROR the parameter type `T` may not live long enough
|
||||||
|
|
||||||
|
fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't reveal the concrete type
|
||||||
|
existential type NoReveal: std::fmt::Debug;
|
||||||
|
|
||||||
|
fn define_no_reveal() -> NoReveal {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
fn no_reveal(x: NoReveal) {
|
||||||
|
let _: &'static str = x; //~ mismatched types
|
||||||
|
let _ = x as &'static str; //~ non-primitive cast
|
||||||
|
}
|
120
src/test/ui/existential_type.stderr
Normal file
120
src/test/ui/existential_type.stderr
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
error: defining existential type use differs from previous
|
||||||
|
--> $DIR/existential_type.rs:23:1
|
||||||
|
|
|
||||||
|
LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
|
||||||
|
LL | | 42i32
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
note: previous use here
|
||||||
|
--> $DIR/existential_type.rs:19:1
|
||||||
|
|
|
||||||
|
LL | / fn foo() -> Foo {
|
||||||
|
LL | | ""
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/existential_type.rs:36:5
|
||||||
|
|
|
||||||
|
LL | fn bomp() -> boo::Boo {
|
||||||
|
| -------- expected `Boo` because of return type
|
||||||
|
LL | "" //~ ERROR mismatched types
|
||||||
|
| ^^ expected anonymized type, found reference
|
||||||
|
|
|
||||||
|
= note: expected type `Boo`
|
||||||
|
found type `&'static str`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/existential_type.rs:50:23
|
||||||
|
|
|
||||||
|
LL | let _: &str = bomp(); //~ ERROR mismatched types
|
||||||
|
| ^^^^^^ expected &str, found anonymized type
|
||||||
|
|
|
||||||
|
= note: expected type `&str`
|
||||||
|
found type `Boo`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/existential_type.rs:54:9
|
||||||
|
|
|
||||||
|
LL | fn bomp() -> boo::Boo {
|
||||||
|
| -------- expected `Boo` because of return type
|
||||||
|
LL | "" //~ ERROR mismatched types
|
||||||
|
| ^^ expected anonymized type, found reference
|
||||||
|
|
|
||||||
|
= note: expected type `Boo`
|
||||||
|
found type `&'static str`
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `T: Trait` is not satisfied
|
||||||
|
--> $DIR/existential_type.rs:61:1
|
||||||
|
|
|
||||||
|
LL | existential type Underconstrained<T: Trait>: 'static; //~ ERROR the trait bound `T: Trait`
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
|
||||||
|
|
|
||||||
|
= help: consider adding a `where T: Trait` bound
|
||||||
|
= note: the return type of a function must have a statically known size
|
||||||
|
|
||||||
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
|
--> $DIR/existential_type.rs:78:1
|
||||||
|
|
|
||||||
|
LL | existential type WrongGeneric<T>: 'static;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
|
||||||
|
| - help: consider adding an explicit lifetime bound `T: 'static`...
|
||||||
|
|
|
||||||
|
note: ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
--> $DIR/existential_type.rs:78:1
|
||||||
|
|
|
||||||
|
LL | existential type WrongGeneric<T>: 'static;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/existential_type.rs:93:27
|
||||||
|
|
|
||||||
|
LL | let _: &'static str = x; //~ mismatched types
|
||||||
|
| ^ expected reference, found anonymized type
|
||||||
|
|
|
||||||
|
= note: expected type `&'static str`
|
||||||
|
found type `NoReveal`
|
||||||
|
|
||||||
|
error[E0605]: non-primitive cast: `NoReveal` as `&'static str`
|
||||||
|
--> $DIR/existential_type.rs:94:13
|
||||||
|
|
|
||||||
|
LL | let _ = x as &'static str; //~ non-primitive cast
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
|
||||||
|
|
||||||
|
error: could not find defining uses
|
||||||
|
--> $DIR/existential_type.rs:28:1
|
||||||
|
|
|
||||||
|
LL | existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: could not find defining uses
|
||||||
|
--> $DIR/existential_type.rs:32:5
|
||||||
|
|
|
||||||
|
LL | pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: defining existential type use differs from previous
|
||||||
|
--> $DIR/existential_type.rs:74:1
|
||||||
|
|
|
||||||
|
LL | / fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR defining existential type use differs from previous
|
||||||
|
LL | | Some(t).into_iter()
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
note: previous use here
|
||||||
|
--> $DIR/existential_type.rs:70:1
|
||||||
|
|
|
||||||
|
LL | / fn my_iter<T>(t: T) -> MyIter<T> {
|
||||||
|
LL | | std::iter::once(t)
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
|
error: aborting due to 11 previous errors
|
||||||
|
|
||||||
|
Some errors occurred: E0277, E0308, E0310, E0605.
|
||||||
|
For more information about an error, try `rustc --explain E0277`.
|
30
src/test/ui/existential_type2.rs
Normal file
30
src/test/ui/existential_type2.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
|
||||||
|
#![feature(existential_type)]
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
existential type Underconstrained<T: std::fmt::Debug>: 'static;
|
||||||
|
//~^ ERROR `U` doesn't implement `std::fmt::Debug`
|
||||||
|
|
||||||
|
// not a defining use, because it doesn't define *all* possible generics
|
||||||
|
fn underconstrained<U>(_: U) -> Underconstrained<U> {
|
||||||
|
5u32
|
||||||
|
}
|
||||||
|
|
||||||
|
existential type Underconstrained2<T: std::fmt::Debug>: 'static;
|
||||||
|
//~^ ERROR `V` doesn't implement `std::fmt::Debug`
|
||||||
|
|
||||||
|
// not a defining use, because it doesn't define *all* possible generics
|
||||||
|
fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
|
||||||
|
5u32
|
||||||
|
}
|
23
src/test/ui/existential_type2.stderr
Normal file
23
src/test/ui/existential_type2.stderr
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
error[E0277]: `U` doesn't implement `std::fmt::Debug`
|
||||||
|
--> $DIR/existential_type2.rs:16:1
|
||||||
|
|
|
||||||
|
LL | existential type Underconstrained<T: std::fmt::Debug>: 'static;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
|
||||||
|
|
|
||||||
|
= help: the trait `std::fmt::Debug` is not implemented for `U`
|
||||||
|
= help: consider adding a `where U: std::fmt::Debug` bound
|
||||||
|
= note: the return type of a function must have a statically known size
|
||||||
|
|
||||||
|
error[E0277]: `V` doesn't implement `std::fmt::Debug`
|
||||||
|
--> $DIR/existential_type2.rs:24:1
|
||||||
|
|
|
||||||
|
LL | existential type Underconstrained2<T: std::fmt::Debug>: 'static;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
|
||||||
|
|
|
||||||
|
= help: the trait `std::fmt::Debug` is not implemented for `V`
|
||||||
|
= help: consider adding a `where V: std::fmt::Debug` bound
|
||||||
|
= note: the return type of a function must have a statically known size
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
21
src/test/ui/existential_type3.rs
Normal file
21
src/test/ui/existential_type3.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
|
||||||
|
#![feature(existential_type)]
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
existential type WrongGeneric<T: 'static>: 'static;
|
||||||
|
|
||||||
|
fn wrong_generic<U: 'static, V: 'static>(_: U, v: V) -> WrongGeneric<U> {
|
||||||
|
//~^ ERROR type parameter `V` is part of concrete type but not used in parameter list
|
||||||
|
v
|
||||||
|
}
|
12
src/test/ui/existential_type3.stderr
Normal file
12
src/test/ui/existential_type3.stderr
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
error: type parameter `V` is part of concrete type but not used in parameter list for existential type
|
||||||
|
--> $DIR/existential_type3.rs:18:73
|
||||||
|
|
|
||||||
|
LL | fn wrong_generic<U: 'static, V: 'static>(_: U, v: V) -> WrongGeneric<U> {
|
||||||
|
| _________________________________________________________________________^
|
||||||
|
LL | | //~^ ERROR type parameter `V` is part of concrete type but not used in parameter list
|
||||||
|
LL | | v
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
|
@ -8,15 +8,14 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// run-rustfix
|
|
||||||
|
|
||||||
// Point at the captured immutable outer variable
|
#![feature(existential_type)]
|
||||||
|
|
||||||
fn foo(mut f: Box<FnMut()>) {
|
fn main() {}
|
||||||
f();
|
|
||||||
}
|
existential type Cmp<T>: 'static;
|
||||||
|
|
||||||
fn main() {
|
// not a defining use, because it doesn't define *all* possible generics
|
||||||
let y = true;
|
fn cmp() -> Cmp<u32> { //~ ERROR non-defining existential type use in defining scope
|
||||||
foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable
|
5u32
|
||||||
}
|
}
|
16
src/test/ui/existential_type4.stderr
Normal file
16
src/test/ui/existential_type4.stderr
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
error: non-defining existential type use in defining scope
|
||||||
|
--> $DIR/existential_type4.rs:19:1
|
||||||
|
|
|
||||||
|
LL | / fn cmp() -> Cmp<u32> { //~ ERROR non-defining existential type use in defining scope
|
||||||
|
LL | | 5u32
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
note: used non-generic type u32 for generic parameter
|
||||||
|
--> $DIR/existential_type4.rs:16:22
|
||||||
|
|
|
||||||
|
LL | existential type Cmp<T>: 'static;
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
25
src/test/ui/feature-gate-existential-type.rs
Normal file
25
src/test/ui/feature-gate-existential-type.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
// Check that existential types must be ungated to use the `existential` keyword
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
existential type Foo: std::fmt::Debug; //~ ERROR existential types are unstable
|
||||||
|
|
||||||
|
trait Bar {
|
||||||
|
type Baa: std::fmt::Debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bar for () {
|
||||||
|
existential type Baa: std::fmt::Debug; //~ ERROR existential types are unstable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
19
src/test/ui/feature-gate-existential-type.stderr
Normal file
19
src/test/ui/feature-gate-existential-type.stderr
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
error[E0658]: existential types are unstable (see issue #34511)
|
||||||
|
--> $DIR/feature-gate-existential-type.rs:15:1
|
||||||
|
|
|
||||||
|
LL | existential type Foo: std::fmt::Debug; //~ ERROR existential types are unstable
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(existential_type)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: existential types are unstable (see issue #34511)
|
||||||
|
--> $DIR/feature-gate-existential-type.rs:22:5
|
||||||
|
|
|
||||||
|
LL | existential type Baa: std::fmt::Debug; //~ ERROR existential types are unstable
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(existential_type)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue