Rollup merge of #35728 - petrochenkov:empderive, r=manishearth

Fix #[derive] for empty tuple structs/variants

This was missing from https://github.com/rust-lang/rust/pull/35138
This commit is contained in:
Jeffrey Seyfried 2016-08-28 10:34:44 +00:00
commit 413ecdee30
7 changed files with 79 additions and 51 deletions

View File

@ -171,9 +171,11 @@ pub trait AstBuilder {
span: Span, span: Span,
ident: ast::Ident, ident: ast::Ident,
bm: ast::BindingMode) -> P<ast::Pat>; bm: ast::BindingMode) -> P<ast::Pat>;
fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec<P<ast::Pat>> ) -> P<ast::Pat>; fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat>;
fn pat_struct(&self, span: Span, fn pat_tuple_struct(&self, span: Span, path: ast::Path,
path: ast::Path, field_pats: Vec<Spanned<ast::FieldPat>> ) -> P<ast::Pat>; subpats: Vec<P<ast::Pat>>) -> P<ast::Pat>;
fn pat_struct(&self, span: Span, path: ast::Path,
field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat>;
fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat>; fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat>;
fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat>; fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat>;
@ -802,10 +804,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
let binding_expr = self.expr_ident(sp, binding_variable); let binding_expr = self.expr_ident(sp, binding_variable);
// Ok(__try_var) pattern // Ok(__try_var) pattern
let ok_pat = self.pat_enum(sp, ok_path, vec!(binding_pat.clone())); let ok_pat = self.pat_tuple_struct(sp, ok_path, vec![binding_pat.clone()]);
// Err(__try_var) (pattern and expression resp.) // Err(__try_var) (pattern and expression resp.)
let err_pat = self.pat_enum(sp, err_path.clone(), vec!(binding_pat)); let err_pat = self.pat_tuple_struct(sp, err_path.clone(), vec![binding_pat]);
let err_inner_expr = self.expr_call(sp, self.expr_path(err_path), let err_inner_expr = self.expr_call(sp, self.expr_path(err_path),
vec!(binding_expr.clone())); vec!(binding_expr.clone()));
// return Err(__try_var) // return Err(__try_var)
@ -842,18 +844,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
let pat = PatKind::Ident(bm, Spanned{span: span, node: ident}, None); let pat = PatKind::Ident(bm, Spanned{span: span, node: ident}, None);
self.pat(span, pat) self.pat(span, pat)
} }
fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> { fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat> {
let pat = if subpats.is_empty() { self.pat(span, PatKind::Path(None, path))
PatKind::Path(None, path)
} else {
PatKind::TupleStruct(path, subpats, None)
};
self.pat(span, pat)
} }
fn pat_struct(&self, span: Span, fn pat_tuple_struct(&self, span: Span, path: ast::Path,
path: ast::Path, field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> { subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
let pat = PatKind::Struct(path, field_pats, false); self.pat(span, PatKind::TupleStruct(path, subpats, None))
self.pat(span, pat) }
fn pat_struct(&self, span: Span, path: ast::Path,
field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> {
self.pat(span, PatKind::Struct(path, field_pats, false))
} }
fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> { fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
self.pat(span, PatKind::Tuple(pats, None)) self.pat(span, PatKind::Tuple(pats, None))
@ -862,25 +862,25 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> { fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
let some = self.std_path(&["option", "Option", "Some"]); let some = self.std_path(&["option", "Option", "Some"]);
let path = self.path_global(span, some); let path = self.path_global(span, some);
self.pat_enum(span, path, vec!(pat)) self.pat_tuple_struct(span, path, vec![pat])
} }
fn pat_none(&self, span: Span) -> P<ast::Pat> { fn pat_none(&self, span: Span) -> P<ast::Pat> {
let some = self.std_path(&["option", "Option", "None"]); let some = self.std_path(&["option", "Option", "None"]);
let path = self.path_global(span, some); let path = self.path_global(span, some);
self.pat_enum(span, path, vec!()) self.pat_path(span, path)
} }
fn pat_ok(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> { fn pat_ok(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
let some = self.std_path(&["result", "Result", "Ok"]); let some = self.std_path(&["result", "Result", "Ok"]);
let path = self.path_global(span, some); let path = self.path_global(span, some);
self.pat_enum(span, path, vec!(pat)) self.pat_tuple_struct(span, path, vec![pat])
} }
fn pat_err(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> { fn pat_err(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
let some = self.std_path(&["result", "Result", "Err"]); let some = self.std_path(&["result", "Result", "Err"]);
let path = self.path_global(span, some); let path = self.path_global(span, some);
self.pat_enum(span, path, vec!(pat)) self.pat_tuple_struct(span, path, vec![pat])
} }
fn arm(&self, _span: Span, pats: Vec<P<ast::Pat>>, expr: P<ast::Expr>) -> ast::Arm { fn arm(&self, _span: Span, pats: Vec<P<ast::Pat>>, expr: P<ast::Expr>) -> ast::Arm {

View File

@ -104,7 +104,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
}; };
let eq_arm = cx.arm(span, let eq_arm = cx.arm(span,
vec![cx.pat_enum(span, equals_path.clone(), vec![])], vec![cx.pat_path(span, equals_path.clone())],
old); old);
let neq_arm = cx.arm(span, let neq_arm = cx.arm(span,
vec![cx.pat_ident(span, test_id)], vec![cx.pat_ident(span, test_id)],

View File

@ -165,7 +165,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<
}; };
let eq_arm = cx.arm(span, let eq_arm = cx.arm(span,
vec![cx.pat_some(span, cx.pat_enum(span, ordering.clone(), vec![]))], vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))],
old); old);
let neq_arm = cx.arm(span, let neq_arm = cx.arm(span,
vec![cx.pat_ident(span, test_id)], vec![cx.pat_ident(span, test_id)],

View File

@ -110,7 +110,7 @@ fn decodable_substructure(cx: &mut ExtCtxt,
return match *substr.fields { return match *substr.fields {
StaticStruct(_, ref summary) => { StaticStruct(_, ref summary) => {
let nfields = match *summary { let nfields = match *summary {
Unnamed(ref fields) => fields.len(), Unnamed(ref fields, _) => fields.len(),
Named(ref fields) => fields.len(), Named(ref fields) => fields.len(),
}; };
let read_struct_field = cx.ident_of("read_struct_field"); let read_struct_field = cx.ident_of("read_struct_field");
@ -193,9 +193,9 @@ fn decode_static_fields<F>(cx: &mut ExtCtxt,
where F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P<Expr> where F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P<Expr>
{ {
match *fields { match *fields {
Unnamed(ref fields) => { Unnamed(ref fields, is_tuple) => {
let path_expr = cx.expr_path(outer_pat_path); let path_expr = cx.expr_path(outer_pat_path);
if fields.is_empty() { if !is_tuple {
path_expr path_expr
} else { } else {
let fields = fields.iter() let fields = fields.iter()

View File

@ -57,8 +57,8 @@ fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructur
return match *substr.fields { return match *substr.fields {
StaticStruct(_, ref summary) => { StaticStruct(_, ref summary) => {
match *summary { match *summary {
Unnamed(ref fields) => { Unnamed(ref fields, is_tuple) => {
if fields.is_empty() { if !is_tuple {
cx.expr_ident(trait_span, substr.type_ident) cx.expr_ident(trait_span, substr.type_ident)
} else { } else {
let exprs = fields.iter().map(|sp| default_call(*sp)).collect(); let exprs = fields.iter().map(|sp| default_call(*sp)).collect();

View File

@ -294,8 +294,8 @@ pub struct FieldInfo<'a> {
/// Fields for a static method /// Fields for a static method
pub enum StaticFields { pub enum StaticFields {
/// Tuple structs/enum variants like this. /// Tuple and unit structs/enum variants like this.
Unnamed(Vec<Span>), Unnamed(Vec<Span>, bool /*is tuple*/),
/// Normal structs/struct variants. /// Normal structs/struct variants.
Named(Vec<(Ident, Span)>), Named(Vec<(Ident, Span)>),
} }
@ -1472,7 +1472,7 @@ impl<'a> TraitDef<'a> {
(_, false) => Named(named_idents), (_, false) => Named(named_idents),
// empty structs // empty structs
_ if struct_def.is_struct() => Named(named_idents), _ if struct_def.is_struct() => Named(named_idents),
_ => Unnamed(just_spans), _ => Unnamed(just_spans, struct_def.is_tuple()),
} }
} }
@ -1512,26 +1512,32 @@ impl<'a> TraitDef<'a> {
} }
let subpats = self.create_subpatterns(cx, paths, mutbl); let subpats = self.create_subpatterns(cx, paths, mutbl);
let pattern = if struct_def.is_struct() { let pattern = match *struct_def {
let field_pats = subpats.into_iter() VariantData::Struct(..) => {
.zip(&ident_exprs) let field_pats = subpats.into_iter()
.map(|(pat, &(sp, ident, _, _))| { .zip(&ident_exprs)
if ident.is_none() { .map(|(pat, &(sp, ident, _, _))| {
cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); if ident.is_none() {
} cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
codemap::Spanned { }
span: pat.span, codemap::Spanned {
node: ast::FieldPat { span: pat.span,
ident: ident.unwrap(), node: ast::FieldPat {
pat: pat, ident: ident.unwrap(),
is_shorthand: false, pat: pat,
}, is_shorthand: false,
} },
}) }
.collect(); })
cx.pat_struct(self.span, struct_path, field_pats) .collect();
} else { cx.pat_struct(self.span, struct_path, field_pats)
cx.pat_enum(self.span, struct_path, subpats) }
VariantData::Tuple(..) => {
cx.pat_tuple_struct(self.span, struct_path, subpats)
}
VariantData::Unit(..) => {
cx.pat_path(self.span, struct_path)
}
}; };
(pattern, ident_exprs) (pattern, ident_exprs)

View File

@ -8,8 +8,9 @@
// 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.
// `#[derive(Trait)]` works for empty structs/variants with braces // `#[derive(Trait)]` works for empty structs/variants with braces or parens.
#![feature(relaxed_adts)]
#![feature(rustc_private)] #![feature(rustc_private)]
extern crate serialize as rustc_serialize; extern crate serialize as rustc_serialize;
@ -18,11 +19,16 @@ extern crate serialize as rustc_serialize;
Default, Debug, RustcEncodable, RustcDecodable)] Default, Debug, RustcEncodable, RustcDecodable)]
struct S {} struct S {}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
Default, Debug, RustcEncodable, RustcDecodable)]
struct Z();
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
Debug, RustcEncodable, RustcDecodable)] Debug, RustcEncodable, RustcDecodable)]
enum E { enum E {
V {}, V {},
U, U,
W(),
} }
fn main() { fn main() {
@ -34,6 +40,14 @@ fn main() {
assert!(!(s < s1)); assert!(!(s < s1));
assert_eq!(format!("{:?}", s), "S"); assert_eq!(format!("{:?}", s), "S");
let z = Z();
let z1 = z;
let z2 = z.clone();
assert_eq!(z, z1);
assert_eq!(z, z2);
assert!(!(z < z1));
assert_eq!(format!("{:?}", z), "Z");
let e = E::V {}; let e = E::V {};
let e1 = e; let e1 = e;
let e2 = e.clone(); let e2 = e.clone();
@ -41,4 +55,12 @@ fn main() {
assert_eq!(e, e2); assert_eq!(e, e2);
assert!(!(e < e1)); assert!(!(e < e1));
assert_eq!(format!("{:?}", e), "V"); assert_eq!(format!("{:?}", e), "V");
let e = E::W();
let e1 = e;
let e2 = e.clone();
assert_eq!(e, e1);
assert_eq!(e, e2);
assert!(!(e < e1));
assert_eq!(format!("{:?}", e), "W");
} }