Skip to content

Commit

Permalink
Auto merge of #56225 - alexreg:type_alias_enum_variants, r=petrochenkov
Browse files Browse the repository at this point in the history
Implement RFC 2338, "Type alias enum variants"

This PR implements [RFC 2338](rust-lang/rfcs#2338), allowing one to write code like the following.

```rust
#![feature(type_alias_enum_variants)]

enum Foo {
    Bar(i32),
    Baz { i: i32 },
}

type Alias = Foo;

fn main() {
    let t = Alias::Bar(0);
    let t = Alias::Baz { i: 0 };
    match t {
        Alias::Bar(_i) => {}
        Alias::Baz { i: _i } => {}
    }
}
```

Since `Self` can be considered a type alias in this context, it also enables using `Self::Variant` as both a constructor and pattern.

Fixes issues #56199 and #56611.

N.B., after discussing the syntax for type arguments on enum variants with @petrochenkov and @eddyb (there are also a few comments on the [tracking issue](#49683)), the consensus seems to be treat the syntax as follows, which ought to be backwards-compatible.

```rust
Option::<u8>::None; // OK
Option::None::<u8>; // OK, but lint in near future (hard error next edition?)
Alias::<u8>::None; // OK
Alias::None::<u8>; // Error
```

I do not know if this will need an FCP, but let's start one if so.
  • Loading branch information
bors committed Dec 29, 2018
2 parents 0071157 + a4fa7ef commit 5918318
Show file tree
Hide file tree
Showing 111 changed files with 1,605 additions and 758 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# `type_alias_enum_variants`

The tracking issue for this feature is: [#49683]

[#49683]: https://github.com/rust-lang/rust/issues/49683

------------------------

The `type_alias_enum_variants` feature enables the use of variants on type
aliases that refer to enums, as both a constructor and a pattern. That is,
it allows for the syntax `EnumAlias::Variant`, which behaves exactly the same
as `Enum::Variant` (assuming that `EnumAlias` is an alias for some enum type
`Enum`).

Note that since `Self` exists as a type alias, this feature also enables the
use of the syntax `Self::Variant` within an impl block for an enum type.

```rust
#![feature(type_alias_enum_variants)]

enum Foo {
Bar(i32),
Baz { i: i32 },
}

type Alias = Foo;

fn main() {
let t = Alias::Bar(0);
let t = Alias::Baz { i: 0 };
match t {
Alias::Bar(_i) => {}
Alias::Baz { i: _i } => {}
}
}
```
24 changes: 15 additions & 9 deletions src/libproc_macro/bridge/rpc.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Serialization for client<->server communication.
//! Serialization for client-server communication.

use std::any::Any;
use std::char;
Expand Down Expand Up @@ -71,15 +71,18 @@ macro_rules! rpc_encode_decode {
(enum $name:ident $(<$($T:ident),+>)* { $($variant:ident $(($field:ident))*),* $(,)* }) => {
impl<S, $($($T: Encode<S>),+)*> Encode<S> for $name $(<$($T),+>)* {
fn encode(self, w: &mut Writer, s: &mut S) {
// HACK(eddyb) `Tag` enum duplicated between the
// HACK(eddyb): `Tag` enum duplicated between the
// two impls as there's no other place to stash it.
#[repr(u8)] enum Tag { $($variant),* }
#[allow(non_upper_case_globals)]
impl Tag { $(const $variant: u8 = Tag::$variant as u8;)* }
mod tag {
#[repr(u8)] enum Tag { $($variant),* }

$(pub const $variant: u8 = Tag::$variant as u8;)*
}

match self {
$($name::$variant $(($field))* => {
<Tag>::$variant.encode(w, s);
tag::$variant.encode(w, s);
$($field.encode(w, s);)*
})*
}
Expand All @@ -90,14 +93,17 @@ macro_rules! rpc_encode_decode {
for $name $(<$($T),+>)*
{
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
// HACK(eddyb) `Tag` enum duplicated between the
// HACK(eddyb): `Tag` enum duplicated between the
// two impls as there's no other place to stash it.
#[repr(u8)] enum Tag { $($variant),* }
#[allow(non_upper_case_globals)]
impl Tag { $(const $variant: u8 = Tag::$variant as u8;)* }
mod tag {
#[repr(u8)] enum Tag { $($variant),* }

$(pub const $variant: u8 = Tag::$variant as u8;)*
}

match u8::decode(r, s) {
$(<Tag>::$variant => {
$(tag::$variant => {
$(let $field = DecodeMut::decode(r, s);)*
$name::$variant $(($field))*
})*
Expand Down
13 changes: 7 additions & 6 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef)

pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
visitor.visit_vis(&item.vis);
visitor.visit_name(item.span, item.name);
visitor.visit_ident(item.ident);
match item.node {
ItemKind::ExternCrate(orig_name) => {
visitor.visit_id(item.id);
Expand All @@ -472,7 +472,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
visitor.visit_nested_body(body);
}
ItemKind::Fn(ref declaration, header, ref generics, body_id) => {
visitor.visit_fn(FnKind::ItemFn(item.name,
visitor.visit_fn(FnKind::ItemFn(item.ident.name,
generics,
header,
&item.vis,
Expand Down Expand Up @@ -528,7 +528,8 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
ItemKind::Union(ref struct_definition, ref generics) => {
visitor.visit_generics(generics);
visitor.visit_id(item.id);
visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span);
visitor.visit_variant_data(struct_definition, item.ident.name, generics, item.id,
item.span);
}
ItemKind::Trait(.., ref generics, ref bounds, ref trait_item_refs) => {
visitor.visit_id(item.id);
Expand Down Expand Up @@ -569,9 +570,9 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
variant: &'v Variant,
generics: &'v Generics,
parent_item_id: NodeId) {
visitor.visit_name(variant.span, variant.node.name);
visitor.visit_ident(variant.node.ident);
visitor.visit_variant_data(&variant.node.data,
variant.node.name,
variant.node.ident.name,
generics,
parent_item_id,
variant.span);
Expand Down Expand Up @@ -720,7 +721,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem) {
visitor.visit_id(foreign_item.id);
visitor.visit_vis(&foreign_item.vis);
visitor.visit_name(foreign_item.span, foreign_item.name);
visitor.visit_ident(foreign_item.ident);

match foreign_item.node {
ForeignItemKind::Fn(ref function_declaration, ref param_names, ref generics) => {
Expand Down
54 changes: 27 additions & 27 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1360,7 +1360,7 @@ impl<'a> LoweringContext<'a> {
let exist_ty_item = hir::Item {
id: exist_ty_id.node_id,
hir_id: exist_ty_id.hir_id,
name: keywords::Invalid.name(),
ident: keywords::Invalid.ident(),
attrs: Default::default(),
node: exist_ty_item_kind,
vis: respan(span.shrink_to_lo(), hir::VisibilityKind::Inherited),
Expand Down Expand Up @@ -1563,7 +1563,7 @@ impl<'a> LoweringContext<'a> {
fn lower_variant(&mut self, v: &Variant) -> hir::Variant {
Spanned {
node: hir::VariantKind {
name: v.node.ident.name,
ident: v.node.ident,
attrs: self.lower_attrs(&v.node.attrs),
data: self.lower_variant_data(&v.node.data),
disr_expr: v.node.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
Expand Down Expand Up @@ -2737,7 +2737,7 @@ impl<'a> LoweringContext<'a> {
fn lower_item_kind(
&mut self,
id: NodeId,
name: &mut Name,
ident: &mut Ident,
attrs: &hir::HirVec<Attribute>,
vis: &mut hir::Visibility,
i: &ItemKind,
Expand All @@ -2751,7 +2751,7 @@ impl<'a> LoweringContext<'a> {
span: use_tree.span,
};

self.lower_use_tree(use_tree, &prefix, id, vis, name, attrs)
self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs)
}
ItemKind::Static(ref t, m, ref e) => {
let value = self.lower_body(None, |this| this.lower_expr(e));
Expand Down Expand Up @@ -2943,7 +2943,7 @@ impl<'a> LoweringContext<'a> {
prefix: &Path,
id: NodeId,
vis: &mut hir::Visibility,
name: &mut Name,
ident: &mut Ident,
attrs: &hir::HirVec<Attribute>,
) -> hir::ItemKind {
debug!("lower_use_tree(tree={:?})", tree);
Expand All @@ -2959,28 +2959,28 @@ impl<'a> LoweringContext<'a> {

match tree.kind {
UseTreeKind::Simple(rename, id1, id2) => {
*name = tree.ident().name;
*ident = tree.ident();

// First apply the prefix to the path
// First, apply the prefix to the path.
let mut path = Path {
segments,
span: path.span,
};

// Correctly resolve `self` imports
// Correctly resolve `self` imports.
if path.segments.len() > 1
&& path.segments.last().unwrap().ident.name == keywords::SelfLower.name()
{
let _ = path.segments.pop();
if rename.is_none() {
*name = path.segments.last().unwrap().ident.name;
*ident = path.segments.last().unwrap().ident;
}
}

let parent_def_index = self.current_hir_id_owner.last().unwrap().0;
let mut defs = self.expect_full_def_from_use(id);
// we want to return *something* from this function, so hang onto the first item
// for later
// We want to return *something* from this function, so hold onto the first item
// for later.
let ret_def = defs.next().unwrap_or(Def::Err);

// Here, we are looping over namespaces, if they exist for the definition
Expand All @@ -2990,7 +2990,7 @@ impl<'a> LoweringContext<'a> {
// two imports.
for (def, &new_node_id) in defs.zip([id1, id2].iter()) {
let vis = vis.clone();
let name = name.clone();
let ident = ident.clone();
let mut path = path.clone();
for seg in &mut path.segments {
seg.id = self.sess.next_node_id();
Expand Down Expand Up @@ -3031,7 +3031,7 @@ impl<'a> LoweringContext<'a> {
hir::Item {
id: new_id.node_id,
hir_id: new_id.hir_id,
name: name,
ident,
attrs: attrs.clone(),
node: item,
vis,
Expand All @@ -3057,8 +3057,8 @@ impl<'a> LoweringContext<'a> {
hir::ItemKind::Use(path, hir::UseKind::Glob)
}
UseTreeKind::Nested(ref trees) => {
// Nested imports are desugared into simple
// imports. So if we start with
// Nested imports are desugared into simple imports.
// So, if we start with
//
// ```
// pub(x) use foo::{a, b};
Expand All @@ -3079,14 +3079,14 @@ impl<'a> LoweringContext<'a> {
// `self.items`. However, the structure of this
// function also requires us to return one item, and
// for that we return the `{}` import (called the
// "`ListStem`").
// `ListStem`).

let prefix = Path {
segments,
span: prefix.span.to(path.span),
};

// Add all the nested PathListItems to the HIR.
// Add all the nested `PathListItem`s to the HIR.
for &(ref use_tree, id) in trees {
self.allocate_hir_id_counter(id, &use_tree);

Expand All @@ -3096,10 +3096,10 @@ impl<'a> LoweringContext<'a> {
} = self.lower_node_id(id);

let mut vis = vis.clone();
let mut name = name.clone();
let mut ident = ident.clone();
let mut prefix = prefix.clone();

// Give the segments new ids since they are being cloned.
// Give the segments new node-ids since they are being cloned.
for seg in &mut prefix.segments {
seg.id = self.sess.next_node_id();
}
Expand All @@ -3114,7 +3114,7 @@ impl<'a> LoweringContext<'a> {
&prefix,
new_id,
&mut vis,
&mut name,
&mut ident,
attrs);

let vis_kind = match vis.node {
Expand All @@ -3138,7 +3138,7 @@ impl<'a> LoweringContext<'a> {
hir::Item {
id: new_id,
hir_id: new_hir_id,
name,
ident,
attrs: attrs.clone(),
node: item,
vis,
Expand All @@ -3165,7 +3165,7 @@ impl<'a> LoweringContext<'a> {
*vis = respan(prefix.span.shrink_to_lo(), hir::VisibilityKind::Inherited);
}
hir::VisibilityKind::Restricted { .. } => {
// do nothing here, as described in the comment on the match
// Do nothing here, as described in the comment on the match.
}
}

Expand Down Expand Up @@ -3413,15 +3413,15 @@ impl<'a> LoweringContext<'a> {
}

pub fn lower_item(&mut self, i: &Item) -> Option<hir::Item> {
let mut name = i.ident.name;
let mut ident = i.ident;
let mut vis = self.lower_visibility(&i.vis, None);
let attrs = self.lower_attrs(&i.attrs);
if let ItemKind::MacroDef(ref def) = i.node {
if !def.legacy || attr::contains_name(&i.attrs, "macro_export") ||
attr::contains_name(&i.attrs, "rustc_doc_only_macro") {
let body = self.lower_token_stream(def.stream());
self.exported_macros.push(hir::MacroDef {
name,
name: ident.name,
vis,
attrs,
id: i.id,
Expand All @@ -3433,14 +3433,14 @@ impl<'a> LoweringContext<'a> {
return None;
}

let node = self.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node);
let node = self.lower_item_kind(i.id, &mut ident, &attrs, &mut vis, &i.node);

let LoweredNodeId { node_id, hir_id } = self.lower_node_id(i.id);

Some(hir::Item {
id: node_id,
hir_id,
name,
ident,
attrs,
node,
vis,
Expand All @@ -3453,7 +3453,7 @@ impl<'a> LoweringContext<'a> {
let def_id = self.resolver.definitions().local_def_id(node_id);
hir::ForeignItem {
id: node_id,
name: i.ident.name,
ident: i.ident,
attrs: self.lower_attrs(&i.attrs),
node: match i.node {
ForeignItemKind::Fn(ref fdec, ref generics) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/hir/map/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ impl<'a> FnLikeNode<'a> {
ast::ItemKind::Fn(ref decl, header, ref generics, block) =>
item_fn(ItemFnParts {
id: i.id,
name: i.name,
name: i.ident.name,
decl: &decl,
body: block,
vis: &i.vis,
Expand Down
Loading

0 comments on commit 5918318

Please sign in to comment.