Skip to content

Fix #[derive] for empty tuple structs/variants #35728

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 30, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 20 additions & 20 deletions src/libsyntax/ext/build.rs
Original file line number Diff line number Diff line change
@@ -171,9 +171,11 @@ pub trait AstBuilder {
span: Span,
ident: ast::Ident,
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_struct(&self, span: Span,
path: ast::Path, field_pats: Vec<Spanned<ast::FieldPat>> ) -> P<ast::Pat>;
fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat>;
fn pat_tuple_struct(&self, span: Span, path: ast::Path,
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_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);

// 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.)
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),
vec!(binding_expr.clone()));
// 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);
self.pat(span, pat)
}
fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
let pat = if subpats.is_empty() {
PatKind::Path(None, path)
} else {
PatKind::TupleStruct(path, subpats, None)
};
self.pat(span, pat)
fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat> {
self.pat(span, PatKind::Path(None, path))
}
fn pat_struct(&self, span: Span,
path: ast::Path, field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> {
let pat = PatKind::Struct(path, field_pats, false);
self.pat(span, pat)
fn pat_tuple_struct(&self, span: Span, path: ast::Path,
subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
self.pat(span, PatKind::TupleStruct(path, subpats, None))
}
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> {
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> {
let some = self.std_path(&["option", "Option", "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> {
let some = self.std_path(&["option", "Option", "None"]);
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> {
let some = self.std_path(&["result", "Result", "Ok"]);
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> {
let some = self.std_path(&["result", "Result", "Err"]);
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 {
2 changes: 1 addition & 1 deletion src/libsyntax_ext/deriving/cmp/ord.rs
Original file line number Diff line number Diff line change
@@ -104,7 +104,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
};

let eq_arm = cx.arm(span,
vec![cx.pat_enum(span, equals_path.clone(), vec![])],
vec![cx.pat_path(span, equals_path.clone())],
old);
let neq_arm = cx.arm(span,
vec![cx.pat_ident(span, test_id)],
2 changes: 1 addition & 1 deletion src/libsyntax_ext/deriving/cmp/partial_ord.rs
Original file line number Diff line number Diff line change
@@ -165,7 +165,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<
};

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);
let neq_arm = cx.arm(span,
vec![cx.pat_ident(span, test_id)],
6 changes: 3 additions & 3 deletions src/libsyntax_ext/deriving/decodable.rs
Original file line number Diff line number Diff line change
@@ -110,7 +110,7 @@ fn decodable_substructure(cx: &mut ExtCtxt,
return match *substr.fields {
StaticStruct(_, ref summary) => {
let nfields = match *summary {
Unnamed(ref fields) => fields.len(),
Unnamed(ref fields, _) => fields.len(),
Named(ref fields) => fields.len(),
};
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>
{
match *fields {
Unnamed(ref fields) => {
Unnamed(ref fields, is_tuple) => {
let path_expr = cx.expr_path(outer_pat_path);
if fields.is_empty() {
if !is_tuple {
path_expr
} else {
let fields = fields.iter()
4 changes: 2 additions & 2 deletions src/libsyntax_ext/deriving/default.rs
Original file line number Diff line number Diff line change
@@ -57,8 +57,8 @@ fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructur
return match *substr.fields {
StaticStruct(_, ref summary) => {
match *summary {
Unnamed(ref fields) => {
if fields.is_empty() {
Unnamed(ref fields, is_tuple) => {
if !is_tuple {
cx.expr_ident(trait_span, substr.type_ident)
} else {
let exprs = fields.iter().map(|sp| default_call(*sp)).collect();
52 changes: 29 additions & 23 deletions src/libsyntax_ext/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
@@ -294,8 +294,8 @@ pub struct FieldInfo<'a> {

/// Fields for a static method
pub enum StaticFields {
/// Tuple structs/enum variants like this.
Unnamed(Vec<Span>),
/// Tuple and unit structs/enum variants like this.
Unnamed(Vec<Span>, bool /*is tuple*/),
/// Normal structs/struct variants.
Named(Vec<(Ident, Span)>),
}
@@ -1470,7 +1470,7 @@ impl<'a> TraitDef<'a> {
(_, false) => Named(named_idents),
// empty structs
_ if struct_def.is_struct() => Named(named_idents),
_ => Unnamed(just_spans),
_ => Unnamed(just_spans, struct_def.is_tuple()),
}
}

@@ -1510,26 +1510,32 @@ impl<'a> TraitDef<'a> {
}

let subpats = self.create_subpatterns(cx, paths, mutbl);
let pattern = if struct_def.is_struct() {
let field_pats = subpats.into_iter()
.zip(&ident_exprs)
.map(|(pat, &(sp, ident, _, _))| {
if ident.is_none() {
cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
}
codemap::Spanned {
span: pat.span,
node: ast::FieldPat {
ident: ident.unwrap(),
pat: pat,
is_shorthand: false,
},
}
})
.collect();
cx.pat_struct(self.span, struct_path, field_pats)
} else {
cx.pat_enum(self.span, struct_path, subpats)
let pattern = match *struct_def {
VariantData::Struct(..) => {
let field_pats = subpats.into_iter()
.zip(&ident_exprs)
.map(|(pat, &(sp, ident, _, _))| {
if ident.is_none() {
cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
}
codemap::Spanned {
span: pat.span,
node: ast::FieldPat {
ident: ident.unwrap(),
pat: pat,
is_shorthand: false,
},
}
})
.collect();
cx.pat_struct(self.span, struct_path, field_pats)
}
VariantData::Tuple(..) => {
cx.pat_tuple_struct(self.span, struct_path, subpats)
}
VariantData::Unit(..) => {
cx.pat_path(self.span, struct_path)
}
};

(pattern, ident_exprs)
24 changes: 23 additions & 1 deletion src/test/run-pass-fulldeps/empty-struct-braces-derive.rs
Original file line number Diff line number Diff line change
@@ -8,8 +8,9 @@
// option. This file may not be copied, modified, or distributed
// 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)]

extern crate serialize as rustc_serialize;
@@ -18,11 +19,16 @@ extern crate serialize as rustc_serialize;
Default, Debug, RustcEncodable, RustcDecodable)]
struct S {}

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
Default, Debug, RustcEncodable, RustcDecodable)]
struct Z();

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash,
Debug, RustcEncodable, RustcDecodable)]
enum E {
V {},
U,
W(),
}

fn main() {
@@ -34,11 +40,27 @@ fn main() {
assert!(!(s < s1));
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 e1 = e;
let e2 = e.clone();
assert_eq!(e, e1);
assert_eq!(e, e2);
assert!(!(e < e1));
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");
}