Skip to content

Commit

Permalink
Auto merge of #52024 - oli-obk:existential_parse, r=nikomatsakis
Browse files Browse the repository at this point in the history
Implement existential types

(not for associated types yet)

r? @nikomatsakis

cc @Centril @varkor @alexreg
  • Loading branch information
bors committed Jul 19, 2018
2 parents 11864c4 + 9017f79 commit c7cba3d
Show file tree
Hide file tree
Showing 216 changed files with 2,028 additions and 146 deletions.
7 changes: 6 additions & 1 deletion src/librustc/hir/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,15 @@ pub enum Def {
Enum(DefId),
Variant(DefId),
Trait(DefId),
/// `existential type Foo: Bar;`
Existential(DefId),
/// `type Foo = Bar;`
TyAlias(DefId),
TyForeign(DefId),
TraitAlias(DefId),
AssociatedTy(DefId),
/// `existential type Foo: Bar;`
AssociatedExistential(DefId),
PrimTy(hir::PrimTy),
TyParam(DefId),
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
Expand Down Expand Up @@ -245,7 +249,7 @@ impl Def {
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
Def::AssociatedConst(id) | Def::Macro(id, ..) |
Def::Existential(id) |
Def::Existential(id) | Def::AssociatedExistential(id) |
Def::GlobalAsm(id) | Def::TyForeign(id) => {
id
}
Expand Down Expand Up @@ -276,6 +280,7 @@ impl Def {
Def::TyAlias(..) => "type alias",
Def::TraitAlias(..) => "trait alias",
Def::AssociatedTy(..) => "associated type",
Def::AssociatedExistential(..) => "associated existential type",
Def::Struct(..) => "struct",
Def::StructCtor(.., CtorKind::Fn) => "tuple struct",
Def::StructCtor(.., CtorKind::Const) => "unit struct",
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_ty(ty);
}
ImplItemKind::Existential(ref bounds) => {
visitor.visit_id(impl_item.id);
walk_list!(visitor, visit_param_bound, bounds);
}
}
}

Expand Down
15 changes: 14 additions & 1 deletion src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ impl<'a> LoweringContext<'a> {
| ItemKind::Union(_, ref generics)
| ItemKind::Enum(_, ref generics)
| ItemKind::Ty(_, ref generics)
| ItemKind::Existential(_, ref generics)
| ItemKind::Trait(_, _, ref generics, ..) => {
let def_id = self.lctx.resolver.definitions().local_def_id(item.id);
let count = generics
Expand Down Expand Up @@ -2632,6 +2633,11 @@ impl<'a> LoweringContext<'a> {
self.lower_ty(t, 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(
hir::EnumDef {
variants: enum_definition
Expand Down Expand Up @@ -3037,6 +3043,12 @@ impl<'a> LoweringContext<'a> {
self.lower_generics(&i.generics, 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"),
};

Expand Down Expand Up @@ -3065,6 +3077,7 @@ impl<'a> LoweringContext<'a> {
kind: match i.node {
ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
ImplItemKind::Existential(..) => hir::AssociatedItemKind::Existential,
ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
has_self: sig.decl.has_self(),
},
Expand Down Expand Up @@ -4335,7 +4348,7 @@ impl<'a> LoweringContext<'a> {
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 {
Defaultness::Default => hir::Defaultness::Default {
has_value: has_value,
Expand Down
5 changes: 4 additions & 1 deletion src/librustc/hir/map/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
ItemKind::Impl(..) => DefPathData::Impl,
ItemKind::Trait(..) => DefPathData::Trait(i.ident.as_interned_str()),
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) |
ItemKind::TraitAlias(..) |
ItemKind::TraitAlias(..) | ItemKind::Existential(..) |
ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
DefPathData::TypeNs(i.ident.as_interned_str()),
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
Expand Down Expand Up @@ -250,6 +250,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
DefPathData::ValueNs(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),
};

Expand Down
4 changes: 4 additions & 0 deletions src/librustc/hir/map/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,8 @@ pub enum DefPathData {
AssocTypeInTrait(InternedString),
/// An associated type **value** (i.e., in an impl)
AssocTypeInImpl(InternedString),
/// An existential associated type **value** (i.e., in an impl)
AssocExistentialInImpl(InternedString),
/// Something in the type NS
TypeNs(InternedString),
/// Something in the value NS
Expand Down Expand Up @@ -605,6 +607,7 @@ impl DefPathData {
Trait(name) |
AssocTypeInTrait(name) |
AssocTypeInImpl(name) |
AssocExistentialInImpl(name) |
ValueNs(name) |
Module(name) |
MacroDef(name) |
Expand All @@ -631,6 +634,7 @@ impl DefPathData {
Trait(name) |
AssocTypeInTrait(name) |
AssocTypeInImpl(name) |
AssocExistentialInImpl(name) |
ValueNs(name) |
Module(name) |
MacroDef(name) |
Expand Down
6 changes: 5 additions & 1 deletion src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ impl<'hir> Map<'hir> {
ImplItemKind::Const(..) => Some(Def::AssociatedConst(def_id)),
ImplItemKind::Method(..) => Some(Def::Method(def_id)),
ImplItemKind::Type(..) => Some(Def::AssociatedTy(def_id)),
ImplItemKind::Existential(..) => Some(Def::AssociatedExistential(def_id)),
}
}
NodeVariant(variant) => {
Expand Down Expand Up @@ -1323,7 +1324,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
ItemKind::ForeignMod(..) => "foreign mod",
ItemKind::GlobalAsm(..) => "global asm",
ItemKind::Ty(..) => "ty",
ItemKind::Existential(..) => "existential",
ItemKind::Existential(..) => "existential type",
ItemKind::Enum(..) => "enum",
ItemKind::Struct(..) => "struct",
ItemKind::Union(..) => "union",
Expand All @@ -1347,6 +1348,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
ImplItemKind::Type(_) => {
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)) => {
Expand Down
6 changes: 5 additions & 1 deletion src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1620,6 +1620,8 @@ pub enum ImplItemKind {
Method(MethodSig, BodyId),
/// An associated type
Type(P<Ty>),
/// An associated existential type
Existential(GenericBounds),
}

// Bind a type to an associated type: `A=Foo`.
Expand Down Expand Up @@ -2080,7 +2082,7 @@ pub enum ItemKind {
GlobalAsm(P<GlobalAsm>),
/// A type alias, e.g. `type Foo = Bar<u8>`
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),
/// An enum definition, e.g. `enum Foo<A, B> {C<A>, D<B>}`
Enum(EnumDef, Generics),
Expand Down Expand Up @@ -2138,6 +2140,7 @@ impl ItemKind {
Some(match *self {
ItemKind::Fn(_, _, ref generics, _) |
ItemKind::Ty(_, ref generics) |
ItemKind::Existential(ExistTy { ref generics, impl_trait_fn: None, .. }) |
ItemKind::Enum(_, ref generics) |
ItemKind::Struct(_, ref generics) |
ItemKind::Union(_, ref generics) |
Expand Down Expand Up @@ -2184,6 +2187,7 @@ pub enum AssociatedItemKind {
Const,
Method { has_self: bool },
Type,
Existential,
}

#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
Expand Down
12 changes: 6 additions & 6 deletions src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,9 +627,7 @@ impl<'a> State<'a> {
self.end()?
}
hir::ItemKind::Ty(ref ty, ref generics) => {
self.ibox(indent_unit)?;
self.ibox(0)?;
self.word_nbsp(&visibility_qualified(&item.vis, "type"))?;
self.head(&visibility_qualified(&item.vis, "type"))?;
self.print_name(item.name)?;
self.print_generic_params(&generics.params)?;
self.end()?; // end the inner ibox
Expand All @@ -642,9 +640,7 @@ impl<'a> State<'a> {
self.end()?; // end the outer ibox
}
hir::ItemKind::Existential(ref exist) => {
self.ibox(indent_unit)?;
self.ibox(0)?;
self.word_nbsp(&visibility_qualified(&item.vis, "existential type"))?;
self.head(&visibility_qualified(&item.vis, "existential type"))?;
self.print_name(item.name)?;
self.print_generic_params(&exist.generics.params)?;
self.end()?; // end the inner ibox
Expand Down Expand Up @@ -994,6 +990,10 @@ impl<'a> State<'a> {
hir::ImplItemKind::Type(ref 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))
}
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::ImplItem {
impl_stable_hash_for!(enum hir::ImplItemKind {
Const(t, body),
Method(sig, body),
Existential(bounds),
Type(t)
});

Expand Down Expand Up @@ -890,6 +891,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::AssociatedItemKind {
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
hir::AssociatedItemKind::Const |
hir::AssociatedItemKind::Existential |
hir::AssociatedItemKind::Type => {
// No fields to hash.
}
Expand Down Expand Up @@ -997,6 +999,7 @@ impl_stable_hash_for!(enum hir::def::Def {
TyAlias(def_id),
TraitAlias(def_id),
AssociatedTy(def_id),
AssociatedExistential(def_id),
PrimTy(prim_ty),
TyParam(def_id),
SelfTy(trait_def_id, impl_def_id),
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,7 @@ impl_stable_hash_for!(struct ty::AssociatedItem {
impl_stable_hash_for!(enum ty::AssociatedKind {
Const,
Method,
Existential,
Type
});

Expand Down
81 changes: 73 additions & 8 deletions src/librustc/infer/anon_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
let tcx = self.infcx.tcx;
value.fold_with(&mut BottomUpFolder {
tcx,
reg_op: |reg| reg,
fldop: |ty| {
if let ty::TyAnon(def_id, substs) = ty.sty {
// Check that this is `impl Trait` type is
Expand Down Expand Up @@ -690,26 +691,35 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
// }
// ```
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 in_definition_scope = match tcx.hir.expect_item(anon_node_id).node {
// impl trait
hir::ItemKind::Existential(hir::ExistTy {
impl_trait_fn: Some(parent),
..
}) => parent,
}) => parent == self.parent_def_id,
// named existential types
hir::ItemKind::Existential(hir::ExistTy {
impl_trait_fn: None,
..
}) => may_define_existential_type(
tcx,
self.parent_def_id,
anon_node_id,
),
_ => {
let anon_parent_node_id = tcx.hir.get_parent(anon_node_id);
tcx.hir.local_def_id(anon_parent_node_id)
self.parent_def_id == tcx.hir.local_def_id(anon_parent_node_id)
},
};
if self.parent_def_id == anon_parent_def_id {
if in_definition_scope {
return self.fold_anon_ty(ty, def_id, substs);
}

debug!(
"instantiate_anon_types_in_map: \
encountered anon with wrong parent \
def_id={:?} \
anon_parent_def_id={:?}",
def_id, anon_parent_def_id
encountered anon outside it's definition scope \
def_id={:?}",
def_id,
);
}
}
Expand Down Expand Up @@ -742,6 +752,10 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
let ty_var = infcx.next_ty_var(TypeVariableOrigin::TypeInference(span));

let predicates_of = tcx.predicates_of(def_id);
debug!(
"instantiate_anon_types: predicates: {:#?}",
predicates_of,
);
let bounds = predicates_of.instantiate(tcx, substs);
debug!("instantiate_anon_types: bounds={:?}", bounds);

Expand All @@ -751,6 +765,18 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
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(
def_id,
AnonTypeDecl {
Expand Down Expand Up @@ -778,3 +804,42 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
ty_var
}
}

/// Whether `anon_node_id` is a sibling or a child of a sibling of `def_id`
///
/// ```rust
/// pub mod foo {
/// pub mod bar {
/// pub existential type Baz;
///
/// fn f1() -> Baz { .. }
/// }
///
/// fn f2() -> bar::Baz { .. }
/// }
/// ```
///
/// Here, `def_id` will be the `DefId` of the existential type `Baz`.
/// `anon_node_id` is the `NodeId` of the reference to Baz -- so either the return type of f1 or f2.
/// We will return true if the reference is within the same module as the existential type
/// So true for f1, false for f2.
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
}
4 changes: 3 additions & 1 deletion src/librustc/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str {
match item.node {
hir::ImplItemKind::Method(..) => "method body",
hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) => "associated item",
hir::ImplItemKind::Const(..) |
hir::ImplItemKind::Existential(..) |
hir::ImplItemKind::Type(..) => "associated item",
}
}

Expand Down
Loading

0 comments on commit c7cba3d

Please sign in to comment.