Skip to content

Commit a594a99

Browse files
committed
auto merge of #10355 : huonw/rust/deriving-field-spans, r=alexcrichton
This rearranges the deriving code so that #[deriving] a trait on a field that doesn't implement that trait will point to the field in question, e.g. struct NotEq; // doesn't implement Eq #[deriving(Eq)] struct Foo { ok: int, also_ok: ~str, bad: NotEq // error points here. } Unfortunately, this means the error is disconnected from the `deriving` itself but there's no current way to pass that information through to rustc except via the spans, at the moment. Fixes #7724.
2 parents 9d8dc00 + 812ea9e commit a594a99

13 files changed

+410
-312
lines changed

src/libsyntax/ext/deriving/clone.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -94,21 +94,21 @@ fn cs_clone(
9494
}
9595

9696
match *all_fields {
97-
[(None, _, _), .. _] => {
97+
[FieldInfo { name: None, _ }, .. _] => {
9898
// enum-like
99-
let subcalls = all_fields.map(|&(_, self_f, _)| subcall(self_f));
99+
let subcalls = all_fields.map(|field| subcall(field.self_));
100100
cx.expr_call_ident(span, ctor_ident, subcalls)
101101
},
102102
_ => {
103103
// struct-like
104-
let fields = do all_fields.map |&(o_id, self_f, _)| {
105-
let ident = match o_id {
104+
let fields = do all_fields.map |field| {
105+
let ident = match field.name {
106106
Some(i) => i,
107107
None => cx.span_bug(span,
108108
format!("unnamed field in normal struct in `deriving({})`",
109109
name))
110110
};
111-
cx.field_imm(span, ident, subcall(self_f))
111+
cx.field_imm(span, ident, subcall(field.self_))
112112
};
113113

114114
if fields.is_empty() {

src/libsyntax/ext/deriving/decodable.rs

+35-46
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ The compiler code necessary for #[deriving(Decodable)]. See
1313
encodable.rs for more.
1414
*/
1515

16-
use std::vec;
17-
18-
use ast::{MetaItem, item, Expr, MutMutable};
16+
use ast::{MetaItem, item, Expr, MutMutable, Ident};
1917
use codemap::Span;
2018
use ext::base::ExtCtxt;
2119
use ext::build::AstBuilder;
@@ -66,37 +64,18 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
6664
return match *substr.fields {
6765
StaticStruct(_, ref summary) => {
6866
let nfields = match *summary {
69-
Left(n) => n, Right(ref fields) => fields.len()
67+
Unnamed(ref fields) => fields.len(),
68+
Named(ref fields) => fields.len()
7069
};
7170
let read_struct_field = cx.ident_of("read_struct_field");
7271

73-
let getarg = |name: @str, field: uint| {
72+
let result = do decode_static_fields(cx, span, substr.type_ident,
73+
summary) |span, name, field| {
7474
cx.expr_method_call(span, blkdecoder, read_struct_field,
7575
~[cx.expr_str(span, name),
7676
cx.expr_uint(span, field),
7777
lambdadecode])
7878
};
79-
80-
let result = match *summary {
81-
Left(n) => {
82-
if n == 0 {
83-
cx.expr_ident(span, substr.type_ident)
84-
} else {
85-
let mut fields = vec::with_capacity(n);
86-
for i in range(0, n) {
87-
fields.push(getarg(format!("_field{}", i).to_managed(), i));
88-
}
89-
cx.expr_call_ident(span, substr.type_ident, fields)
90-
}
91-
}
92-
Right(ref fields) => {
93-
let fields = do fields.iter().enumerate().map |(i, f)| {
94-
cx.field_imm(span, *f, getarg(cx.str_of(*f), i))
95-
}.collect();
96-
cx.expr_struct_ident(span, substr.type_ident, fields)
97-
}
98-
};
99-
10079
cx.expr_method_call(span, decoder, cx.ident_of("read_struct"),
10180
~[cx.expr_str(span, cx.str_of(substr.type_ident)),
10281
cx.expr_uint(span, nfields),
@@ -113,31 +92,13 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
11392
let (name, parts) = match *f { (i, ref p) => (i, p) };
11493
variants.push(cx.expr_str(span, cx.str_of(name)));
11594

116-
let getarg = |field: uint| {
95+
let decoded = do decode_static_fields(cx, span, name,
96+
parts) |span, _, field| {
11797
cx.expr_method_call(span, blkdecoder, rvariant_arg,
11898
~[cx.expr_uint(span, field),
11999
lambdadecode])
120100
};
121101

122-
let decoded = match *parts {
123-
Left(n) => {
124-
if n == 0 {
125-
cx.expr_ident(span, name)
126-
} else {
127-
let mut fields = vec::with_capacity(n);
128-
for i in range(0u, n) {
129-
fields.push(getarg(i));
130-
}
131-
cx.expr_call_ident(span, name, fields)
132-
}
133-
}
134-
Right(ref fields) => {
135-
let fields = do fields.iter().enumerate().map |(i, f)| {
136-
cx.field_imm(span, *f, getarg(i))
137-
}.collect();
138-
cx.expr_struct_ident(span, name, fields)
139-
}
140-
};
141102
arms.push(cx.arm(span,
142103
~[cx.pat_lit(span, cx.expr_uint(span, i))],
143104
decoded));
@@ -158,3 +119,31 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
158119
_ => cx.bug("expected StaticEnum or StaticStruct in deriving(Decodable)")
159120
};
160121
}
122+
123+
/// Create a decoder for a single enum variant/struct:
124+
/// - `outer_pat_ident` is the name of this enum variant/struct
125+
/// - `getarg` should retrieve the `uint`-th field with name `@str`.
126+
fn decode_static_fields(cx: @ExtCtxt, outer_span: Span, outer_pat_ident: Ident,
127+
fields: &StaticFields,
128+
getarg: &fn(Span, @str, uint) -> @Expr) -> @Expr {
129+
match *fields {
130+
Unnamed(ref fields) => {
131+
if fields.is_empty() {
132+
cx.expr_ident(outer_span, outer_pat_ident)
133+
} else {
134+
let fields = do fields.iter().enumerate().map |(i, &span)| {
135+
getarg(span, format!("_field{}", i).to_managed(), i)
136+
}.collect();
137+
138+
cx.expr_call_ident(outer_span, outer_pat_ident, fields)
139+
}
140+
}
141+
Named(ref fields) => {
142+
// use the field's span to get nicer error messages.
143+
let fields = do fields.iter().enumerate().map |(i, &(name, span))| {
144+
cx.field_imm(span, name, getarg(span, cx.str_of(name), i))
145+
}.collect();
146+
cx.expr_struct_ident(outer_span, outer_pat_ident, fields)
147+
}
148+
}
149+
}

src/libsyntax/ext/deriving/default.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ use ext::base::ExtCtxt;
1414
use ext::build::AstBuilder;
1515
use ext::deriving::generic::*;
1616

17-
use std::vec;
18-
1917
pub fn expand_deriving_default(cx: @ExtCtxt,
2018
span: Span,
2119
mitem: @MetaItem,
@@ -47,22 +45,22 @@ fn default_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Exp
4745
cx.ident_of("Default"),
4846
cx.ident_of("default")
4947
];
50-
let default_call = cx.expr_call_global(span, default_ident.clone(), ~[]);
48+
let default_call = |span| cx.expr_call_global(span, default_ident.clone(), ~[]);
5149

5250
return match *substr.fields {
5351
StaticStruct(_, ref summary) => {
5452
match *summary {
55-
Left(count) => {
56-
if count == 0 {
53+
Unnamed(ref fields) => {
54+
if fields.is_empty() {
5755
cx.expr_ident(span, substr.type_ident)
5856
} else {
59-
let exprs = vec::from_elem(count, default_call);
57+
let exprs = fields.map(|sp| default_call(*sp));
6058
cx.expr_call_ident(span, substr.type_ident, exprs)
6159
}
6260
}
63-
Right(ref fields) => {
64-
let default_fields = do fields.map |ident| {
65-
cx.field_imm(span, *ident, default_call)
61+
Named(ref fields) => {
62+
let default_fields = do fields.map |&(ident, span)| {
63+
cx.field_imm(span, ident, default_call(span))
6664
};
6765
cx.expr_struct_ident(span, substr.type_ident, default_fields)
6866
}

src/libsyntax/ext/deriving/encodable.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,11 @@ fn encodable_substructure(cx: @ExtCtxt, span: Span,
123123
let emit_struct_field = cx.ident_of("emit_struct_field");
124124
let mut stmts = ~[];
125125
for (i, f) in fields.iter().enumerate() {
126-
let (name, val) = match *f {
127-
(Some(id), e, _) => (cx.str_of(id), e),
128-
(None, e, _) => (format!("_field{}", i).to_managed(), e)
126+
let name = match f.name {
127+
Some(id) => cx.str_of(id),
128+
None => format!("_field{}", i).to_managed()
129129
};
130-
let enc = cx.expr_method_call(span, val, encode, ~[blkencoder]);
130+
let enc = cx.expr_method_call(span, f.self_, encode, ~[blkencoder]);
131131
let lambda = cx.lambda_expr_1(span, enc, blkarg);
132132
let call = cx.expr_method_call(span, blkencoder,
133133
emit_struct_field,
@@ -154,8 +154,7 @@ fn encodable_substructure(cx: @ExtCtxt, span: Span,
154154
let emit_variant_arg = cx.ident_of("emit_enum_variant_arg");
155155
let mut stmts = ~[];
156156
for (i, f) in fields.iter().enumerate() {
157-
let val = match *f { (_, e, _) => e };
158-
let enc = cx.expr_method_call(span, val, encode, ~[blkencoder]);
157+
let enc = cx.expr_method_call(span, f.self_, encode, ~[blkencoder]);
159158
let lambda = cx.lambda_expr_1(span, enc, blkarg);
160159
let call = cx.expr_method_call(span, blkencoder,
161160
emit_variant_arg,

0 commit comments

Comments
 (0)