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:
commit
413ecdee30
@ -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 {
|
||||||
|
@ -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)],
|
||||||
|
@ -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)],
|
||||||
|
@ -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()
|
||||||
|
@ -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();
|
||||||
|
@ -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)
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user