Skip to content

Commit b0280ac

Browse files
committed
auto merge of #11834 : huonw/rust/deriving-spans, r=alexcrichton
I'd forgotten to update them when I changed this a while ago; it now displays error messages linked to the struct/variant field, rather than the `#[deriving(Trait)]` line, for all traits. This also adds a very large number of autogenerated tests. I can easily remove/tone down that commit if necessary.
2 parents 4b2fdfa + d9a204b commit b0280ac

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1051
-165
lines changed
+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#!/usr/bin/env python
2+
# xfail-license
3+
# Copyright 2013 The Rust Project Developers. See the COPYRIGHT
4+
# file at the top-level directory of this distribution and at
5+
# http://rust-lang.org/COPYRIGHT.
6+
#
7+
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
8+
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
9+
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
10+
# option. This file may not be copied, modified, or distributed
11+
# except according to those terms.
12+
13+
"""
14+
This script creates a pile of compile-fail tests check that all the
15+
derivings have spans that point to the fields, rather than the
16+
#[deriving(...)] line.
17+
18+
sample usage: src/etc/generate-deriving-span-tests.py
19+
"""
20+
21+
import sys, os, datetime, stat
22+
23+
TEST_DIR = os.path.abspath(
24+
os.path.join(os.path.dirname(__file__), '../test/compile-fail'))
25+
26+
YEAR = datetime.datetime.now().year
27+
28+
TEMPLATE = """// Copyright {year} The Rust Project Developers. See the COPYRIGHT
29+
// file at the top-level directory of this distribution and at
30+
// http://rust-lang.org/COPYRIGHT.
31+
//
32+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
33+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
34+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
35+
// option. This file may not be copied, modified, or distributed
36+
// except according to those terms.
37+
38+
// This file was auto-generated using 'src/etc/generate-keyword-span-tests.py'
39+
40+
#[feature(struct_variant)];
41+
extern mod extra;
42+
43+
{error_deriving}
44+
struct Error;
45+
{code}
46+
fn main() {{}}
47+
"""
48+
49+
ENUM_STRING = """
50+
#[deriving({traits})]
51+
enum Enum {{
52+
A(
53+
Error {errors}
54+
)
55+
}}
56+
"""
57+
ENUM_STRUCT_VARIANT_STRING = """
58+
#[deriving({traits})]
59+
enum Enum {{
60+
A {{
61+
x: Error {errors}
62+
}}
63+
}}
64+
"""
65+
STRUCT_STRING = """
66+
#[deriving({traits})]
67+
struct Struct {{
68+
x: Error {errors}
69+
}}
70+
"""
71+
STRUCT_TUPLE_STRING = """
72+
#[deriving({traits})]
73+
struct Struct(
74+
Error {errors}
75+
);
76+
"""
77+
78+
ENUM_TUPLE, ENUM_STRUCT, STRUCT_FIELDS, STRUCT_TUPLE = range(4)
79+
80+
def create_test_case(type, trait, super_traits, number_of_errors):
81+
string = [ENUM_STRING, ENUM_STRUCT_VARIANT_STRING, STRUCT_STRING, STRUCT_TUPLE_STRING][type]
82+
all_traits = ','.join([trait] + super_traits)
83+
super_traits = ','.join(super_traits)
84+
error_deriving = '#[deriving(%s)]' % super_traits if super_traits else ''
85+
86+
errors = '\n'.join('//~%s ERROR' % ('^' * n) for n in range(error_count))
87+
code = string.format(traits = all_traits, errors = errors)
88+
return TEMPLATE.format(year = YEAR, error_deriving=error_deriving, code = code)
89+
90+
def write_file(name, string):
91+
test_file = os.path.join(TEST_DIR, 'deriving-span-%s.rs' % name)
92+
93+
# set write permission if file exists, so it can be changed
94+
if os.path.exists(test_file):
95+
os.chmod(test_file, stat.S_IWUSR)
96+
97+
with open(test_file, 'wt') as f:
98+
f.write(string)
99+
100+
# mark file read-only
101+
os.chmod(test_file, stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH)
102+
103+
104+
105+
ENUM = 1
106+
STRUCT = 2
107+
ALL = STRUCT | ENUM
108+
109+
traits = {
110+
'Zero': (STRUCT, [], 1),
111+
'Default': (STRUCT, [], 1),
112+
'FromPrimitive': (0, [], 0), # only works for C-like enums
113+
114+
'Decodable': (0, [], 0), # FIXME: quoting gives horrible spans
115+
'Encodable': (0, [], 0), # FIXME: quoting gives horrible spans
116+
}
117+
118+
for (trait, supers, errs) in [('Rand', [], 1),
119+
('Clone', [], 1), ('DeepClone', ['Clone'], 1),
120+
('Eq', [], 2), ('Ord', [], 8),
121+
('TotalEq', [], 2), ('TotalOrd', ['TotalEq'], 2)]:
122+
traits[trait] = (ALL, supers, errs)
123+
124+
for (trait, (types, super_traits, error_count)) in traits.items():
125+
mk = lambda ty: create_test_case(ty, trait, super_traits, error_count)
126+
if types & ENUM:
127+
write_file(trait + '-enum', mk(ENUM_TUPLE))
128+
write_file(trait + '-enum-struct-variant', mk(ENUM_STRUCT))
129+
if types & STRUCT:
130+
write_file(trait + '-struct', mk(STRUCT_FIELDS))
131+
write_file(trait + '-tuple-struct', mk(STRUCT_TUPLE))

src/libsyntax/ext/deriving/clone.rs

+16-16
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,13 @@ pub fn expand_deriving_deep_clone(cx: &ExtCtxt,
7474

7575
fn cs_clone(
7676
name: &str,
77-
cx: &ExtCtxt, span: Span,
77+
cx: &ExtCtxt, trait_span: Span,
7878
substr: &Substructure) -> @Expr {
7979
let clone_ident = substr.method_ident;
8080
let ctor_ident;
8181
let all_fields;
82-
let subcall = |field|
83-
cx.expr_method_call(span, field, clone_ident, ~[]);
82+
let subcall = |field: &FieldInfo|
83+
cx.expr_method_call(field.span, field.self_, clone_ident, ~[]);
8484

8585
match *substr.fields {
8686
Struct(ref af) => {
@@ -91,37 +91,37 @@ fn cs_clone(
9191
ctor_ident = variant.node.name;
9292
all_fields = af;
9393
},
94-
EnumNonMatching(..) => cx.span_bug(span,
95-
format!("Non-matching enum variants in `deriving({})`",
96-
name)),
97-
StaticEnum(..) | StaticStruct(..) => cx.span_bug(span,
98-
format!("Static method in `deriving({})`",
99-
name))
94+
EnumNonMatching(..) => cx.span_bug(trait_span,
95+
format!("Non-matching enum variants in `deriving({})`",
96+
name)),
97+
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span,
98+
format!("Static method in `deriving({})`",
99+
name))
100100
}
101101

102102
match *all_fields {
103103
[FieldInfo { name: None, .. }, ..] => {
104104
// enum-like
105-
let subcalls = all_fields.map(|field| subcall(field.self_));
106-
cx.expr_call_ident(span, ctor_ident, subcalls)
105+
let subcalls = all_fields.map(subcall);
106+
cx.expr_call_ident(trait_span, ctor_ident, subcalls)
107107
},
108108
_ => {
109109
// struct-like
110110
let fields = all_fields.map(|field| {
111111
let ident = match field.name {
112112
Some(i) => i,
113-
None => cx.span_bug(span,
113+
None => cx.span_bug(trait_span,
114114
format!("unnamed field in normal struct in `deriving({})`",
115-
name))
115+
name))
116116
};
117-
cx.field_imm(span, ident, subcall(field.self_))
117+
cx.field_imm(field.span, ident, subcall(field))
118118
});
119119

120120
if fields.is_empty() {
121121
// no fields, so construct like `None`
122-
cx.expr_ident(span, ctor_ident)
122+
cx.expr_ident(trait_span, ctor_ident)
123123
} else {
124-
cx.expr_struct_ident(span, ctor_ident, fields)
124+
cx.expr_struct_ident(trait_span, ctor_ident, fields)
125125
}
126126
}
127127
}

src/libsyntax/ext/deriving/decodable.rs

+26-27
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub fn expand_deriving_decodable(cx: &ExtCtxt,
5151
trait_def.expand(mitem, in_items)
5252
}
5353

54-
fn decodable_substructure(cx: &ExtCtxt, span: Span,
54+
fn decodable_substructure(cx: &ExtCtxt, trait_span: Span,
5555
substr: &Substructure) -> @Expr {
5656
let decoder = substr.nonself_args[0];
5757
let recurse = ~[cx.ident_of("extra"),
@@ -60,9 +60,9 @@ fn decodable_substructure(cx: &ExtCtxt, span: Span,
6060
cx.ident_of("decode")];
6161
// throw an underscore in front to suppress unused variable warnings
6262
let blkarg = cx.ident_of("_d");
63-
let blkdecoder = cx.expr_ident(span, blkarg);
64-
let calldecode = cx.expr_call_global(span, recurse, ~[blkdecoder]);
65-
let lambdadecode = cx.lambda_expr_1(span, calldecode, blkarg);
63+
let blkdecoder = cx.expr_ident(trait_span, blkarg);
64+
let calldecode = cx.expr_call_global(trait_span, recurse, ~[blkdecoder]);
65+
let lambdadecode = cx.lambda_expr_1(trait_span, calldecode, blkarg);
6666

6767
return match *substr.fields {
6868
StaticStruct(_, ref summary) => {
@@ -73,7 +73,7 @@ fn decodable_substructure(cx: &ExtCtxt, span: Span,
7373
let read_struct_field = cx.ident_of("read_struct_field");
7474

7575
let result = decode_static_fields(cx,
76-
span,
76+
trait_span,
7777
substr.type_ident,
7878
summary,
7979
|span, name, field| {
@@ -82,10 +82,10 @@ fn decodable_substructure(cx: &ExtCtxt, span: Span,
8282
cx.expr_uint(span, field),
8383
lambdadecode])
8484
});
85-
cx.expr_method_call(span, decoder, cx.ident_of("read_struct"),
86-
~[cx.expr_str(span, cx.str_of(substr.type_ident)),
87-
cx.expr_uint(span, nfields),
88-
cx.lambda_expr_1(span, result, blkarg)])
85+
cx.expr_method_call(trait_span, decoder, cx.ident_of("read_struct"),
86+
~[cx.expr_str(trait_span, cx.str_of(substr.type_ident)),
87+
cx.expr_uint(trait_span, nfields),
88+
cx.lambda_expr_1(trait_span, result, blkarg)])
8989
}
9090
StaticEnum(_, ref fields) => {
9191
let variant = cx.ident_of("i");
@@ -94,12 +94,11 @@ fn decodable_substructure(cx: &ExtCtxt, span: Span,
9494
let mut variants = ~[];
9595
let rvariant_arg = cx.ident_of("read_enum_variant_arg");
9696

97-
for (i, f) in fields.iter().enumerate() {
98-
let (name, parts) = match *f { (i, ref p) => (i, p) };
99-
variants.push(cx.expr_str(span, cx.str_of(name)));
97+
for (i, &(name, v_span, ref parts)) in fields.iter().enumerate() {
98+
variants.push(cx.expr_str(v_span, cx.str_of(name)));
10099

101100
let decoded = decode_static_fields(cx,
102-
span,
101+
v_span,
103102
name,
104103
parts,
105104
|span, _, field| {
@@ -108,22 +107,22 @@ fn decodable_substructure(cx: &ExtCtxt, span: Span,
108107
lambdadecode])
109108
});
110109

111-
arms.push(cx.arm(span,
112-
~[cx.pat_lit(span, cx.expr_uint(span, i))],
110+
arms.push(cx.arm(v_span,
111+
~[cx.pat_lit(v_span, cx.expr_uint(v_span, i))],
113112
decoded));
114113
}
115114

116-
arms.push(cx.arm_unreachable(span));
115+
arms.push(cx.arm_unreachable(trait_span));
117116

118-
let result = cx.expr_match(span, cx.expr_ident(span, variant), arms);
119-
let lambda = cx.lambda_expr(span, ~[blkarg, variant], result);
120-
let variant_vec = cx.expr_vec(span, variants);
121-
let result = cx.expr_method_call(span, blkdecoder,
117+
let result = cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms);
118+
let lambda = cx.lambda_expr(trait_span, ~[blkarg, variant], result);
119+
let variant_vec = cx.expr_vec(trait_span, variants);
120+
let result = cx.expr_method_call(trait_span, blkdecoder,
122121
cx.ident_of("read_enum_variant"),
123122
~[variant_vec, lambda]);
124-
cx.expr_method_call(span, decoder, cx.ident_of("read_enum"),
125-
~[cx.expr_str(span, cx.str_of(substr.type_ident)),
126-
cx.lambda_expr_1(span, result, blkarg)])
123+
cx.expr_method_call(trait_span, decoder, cx.ident_of("read_enum"),
124+
~[cx.expr_str(trait_span, cx.str_of(substr.type_ident)),
125+
cx.lambda_expr_1(trait_span, result, blkarg)])
127126
}
128127
_ => cx.bug("expected StaticEnum or StaticStruct in deriving(Decodable)")
129128
};
@@ -133,29 +132,29 @@ fn decodable_substructure(cx: &ExtCtxt, span: Span,
133132
/// - `outer_pat_ident` is the name of this enum variant/struct
134133
/// - `getarg` should retrieve the `uint`-th field with name `@str`.
135134
fn decode_static_fields(cx: &ExtCtxt,
136-
outer_span: Span,
135+
trait_span: Span,
137136
outer_pat_ident: Ident,
138137
fields: &StaticFields,
139138
getarg: |Span, @str, uint| -> @Expr)
140139
-> @Expr {
141140
match *fields {
142141
Unnamed(ref fields) => {
143142
if fields.is_empty() {
144-
cx.expr_ident(outer_span, outer_pat_ident)
143+
cx.expr_ident(trait_span, outer_pat_ident)
145144
} else {
146145
let fields = fields.iter().enumerate().map(|(i, &span)| {
147146
getarg(span, format!("_field{}", i).to_managed(), i)
148147
}).collect();
149148

150-
cx.expr_call_ident(outer_span, outer_pat_ident, fields)
149+
cx.expr_call_ident(trait_span, outer_pat_ident, fields)
151150
}
152151
}
153152
Named(ref fields) => {
154153
// use the field's span to get nicer error messages.
155154
let fields = fields.iter().enumerate().map(|(i, &(name, span))| {
156155
cx.field_imm(span, name, getarg(span, cx.str_of(name), i))
157156
}).collect();
158-
cx.expr_struct_ident(outer_span, outer_pat_ident, fields)
157+
cx.expr_struct_ident(trait_span, outer_pat_ident, fields)
159158
}
160159
}
161160
}

src/libsyntax/ext/deriving/default.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub fn expand_deriving_default(cx: &ExtCtxt,
4141
trait_def.expand(mitem, in_items)
4242
}
4343

44-
fn default_substructure(cx: &ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
44+
fn default_substructure(cx: &ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
4545
let default_ident = ~[
4646
cx.ident_of("std"),
4747
cx.ident_of("default"),
@@ -55,25 +55,25 @@ fn default_substructure(cx: &ExtCtxt, span: Span, substr: &Substructure) -> @Exp
5555
match *summary {
5656
Unnamed(ref fields) => {
5757
if fields.is_empty() {
58-
cx.expr_ident(span, substr.type_ident)
58+
cx.expr_ident(trait_span, substr.type_ident)
5959
} else {
6060
let exprs = fields.map(|sp| default_call(*sp));
61-
cx.expr_call_ident(span, substr.type_ident, exprs)
61+
cx.expr_call_ident(trait_span, substr.type_ident, exprs)
6262
}
6363
}
6464
Named(ref fields) => {
6565
let default_fields = fields.map(|&(ident, span)| {
6666
cx.field_imm(span, ident, default_call(span))
6767
});
68-
cx.expr_struct_ident(span, substr.type_ident, default_fields)
68+
cx.expr_struct_ident(trait_span, substr.type_ident, default_fields)
6969
}
7070
}
7171
}
7272
StaticEnum(..) => {
73-
cx.span_err(span, "`Default` cannot be derived for enums, only structs");
73+
cx.span_err(trait_span, "`Default` cannot be derived for enums, only structs");
7474
// let compilation continue
75-
cx.expr_uint(span, 0)
75+
cx.expr_uint(trait_span, 0)
7676
}
77-
_ => cx.bug("Non-static method in `deriving(Default)`")
77+
_ => cx.span_bug(trait_span, "Non-static method in `deriving(Default)`")
7878
};
7979
}

0 commit comments

Comments
 (0)