Skip to content
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

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

Merged
merged 2 commits into from
Aug 30, 2016
Merged
Show file tree
Hide file tree
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
Expand Up @@ -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>;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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))
Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax_ext/deriving/cmp/ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)],
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax_ext/deriving/cmp/partial_ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)],
Expand Down
6 changes: 3 additions & 3 deletions src/libsyntax_ext/deriving/decodable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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()
Expand Down
4 changes: 2 additions & 2 deletions src/libsyntax_ext/deriving/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
52 changes: 29 additions & 23 deletions src/libsyntax_ext/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)>),
}
Expand Down Expand Up @@ -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()),
}
}

Expand Down Expand Up @@ -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)
Expand Down
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
Expand Up @@ -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;
Expand All @@ -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() {
Expand All @@ -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");
}