提交 a594a999 编写于 作者: B bors

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.
......@@ -94,21 +94,21 @@ fn cs_clone(
}
match *all_fields {
[(None, _, _), .. _] => {
[FieldInfo { name: None, _ }, .. _] => {
// enum-like
let subcalls = all_fields.map(|&(_, self_f, _)| subcall(self_f));
let subcalls = all_fields.map(|field| subcall(field.self_));
cx.expr_call_ident(span, ctor_ident, subcalls)
},
_ => {
// struct-like
let fields = do all_fields.map |&(o_id, self_f, _)| {
let ident = match o_id {
let fields = do all_fields.map |field| {
let ident = match field.name {
Some(i) => i,
None => cx.span_bug(span,
format!("unnamed field in normal struct in `deriving({})`",
name))
};
cx.field_imm(span, ident, subcall(self_f))
cx.field_imm(span, ident, subcall(field.self_))
};
if fields.is_empty() {
......
......@@ -13,9 +13,7 @@
encodable.rs for more.
*/
use std::vec;
use ast::{MetaItem, item, Expr, MutMutable};
use ast::{MetaItem, item, Expr, MutMutable, Ident};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
......@@ -66,37 +64,18 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
return match *substr.fields {
StaticStruct(_, ref summary) => {
let nfields = match *summary {
Left(n) => n, Right(ref fields) => fields.len()
Unnamed(ref fields) => fields.len(),
Named(ref fields) => fields.len()
};
let read_struct_field = cx.ident_of("read_struct_field");
let getarg = |name: @str, field: uint| {
let result = do decode_static_fields(cx, span, substr.type_ident,
summary) |span, name, field| {
cx.expr_method_call(span, blkdecoder, read_struct_field,
~[cx.expr_str(span, name),
cx.expr_uint(span, field),
lambdadecode])
};
let result = match *summary {
Left(n) => {
if n == 0 {
cx.expr_ident(span, substr.type_ident)
} else {
let mut fields = vec::with_capacity(n);
for i in range(0, n) {
fields.push(getarg(format!("_field{}", i).to_managed(), i));
}
cx.expr_call_ident(span, substr.type_ident, fields)
}
}
Right(ref fields) => {
let fields = do fields.iter().enumerate().map |(i, f)| {
cx.field_imm(span, *f, getarg(cx.str_of(*f), i))
}.collect();
cx.expr_struct_ident(span, substr.type_ident, fields)
}
};
cx.expr_method_call(span, decoder, cx.ident_of("read_struct"),
~[cx.expr_str(span, cx.str_of(substr.type_ident)),
cx.expr_uint(span, nfields),
......@@ -113,31 +92,13 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
let (name, parts) = match *f { (i, ref p) => (i, p) };
variants.push(cx.expr_str(span, cx.str_of(name)));
let getarg = |field: uint| {
let decoded = do decode_static_fields(cx, span, name,
parts) |span, _, field| {
cx.expr_method_call(span, blkdecoder, rvariant_arg,
~[cx.expr_uint(span, field),
lambdadecode])
};
let decoded = match *parts {
Left(n) => {
if n == 0 {
cx.expr_ident(span, name)
} else {
let mut fields = vec::with_capacity(n);
for i in range(0u, n) {
fields.push(getarg(i));
}
cx.expr_call_ident(span, name, fields)
}
}
Right(ref fields) => {
let fields = do fields.iter().enumerate().map |(i, f)| {
cx.field_imm(span, *f, getarg(i))
}.collect();
cx.expr_struct_ident(span, name, fields)
}
};
arms.push(cx.arm(span,
~[cx.pat_lit(span, cx.expr_uint(span, i))],
decoded));
......@@ -158,3 +119,31 @@ fn decodable_substructure(cx: @ExtCtxt, span: Span,
_ => cx.bug("expected StaticEnum or StaticStruct in deriving(Decodable)")
};
}
/// Create a decoder for a single enum variant/struct:
/// - `outer_pat_ident` is the name of this enum variant/struct
/// - `getarg` should retrieve the `uint`-th field with name `@str`.
fn decode_static_fields(cx: @ExtCtxt, outer_span: Span, outer_pat_ident: Ident,
fields: &StaticFields,
getarg: &fn(Span, @str, uint) -> @Expr) -> @Expr {
match *fields {
Unnamed(ref fields) => {
if fields.is_empty() {
cx.expr_ident(outer_span, outer_pat_ident)
} else {
let fields = do fields.iter().enumerate().map |(i, &span)| {
getarg(span, format!("_field{}", i).to_managed(), i)
}.collect();
cx.expr_call_ident(outer_span, outer_pat_ident, fields)
}
}
Named(ref fields) => {
// use the field's span to get nicer error messages.
let fields = do fields.iter().enumerate().map |(i, &(name, span))| {
cx.field_imm(span, name, getarg(span, cx.str_of(name), i))
}.collect();
cx.expr_struct_ident(outer_span, outer_pat_ident, fields)
}
}
}
......@@ -14,8 +14,6 @@
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use std::vec;
pub fn expand_deriving_default(cx: @ExtCtxt,
span: Span,
mitem: @MetaItem,
......@@ -47,22 +45,22 @@ fn default_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Exp
cx.ident_of("Default"),
cx.ident_of("default")
];
let default_call = cx.expr_call_global(span, default_ident.clone(), ~[]);
let default_call = |span| cx.expr_call_global(span, default_ident.clone(), ~[]);
return match *substr.fields {
StaticStruct(_, ref summary) => {
match *summary {
Left(count) => {
if count == 0 {
Unnamed(ref fields) => {
if fields.is_empty() {
cx.expr_ident(span, substr.type_ident)
} else {
let exprs = vec::from_elem(count, default_call);
let exprs = fields.map(|sp| default_call(*sp));
cx.expr_call_ident(span, substr.type_ident, exprs)
}
}
Right(ref fields) => {
let default_fields = do fields.map |ident| {
cx.field_imm(span, *ident, default_call)
Named(ref fields) => {
let default_fields = do fields.map |&(ident, span)| {
cx.field_imm(span, ident, default_call(span))
};
cx.expr_struct_ident(span, substr.type_ident, default_fields)
}
......
......@@ -123,11 +123,11 @@ fn encodable_substructure(cx: @ExtCtxt, span: Span,
let emit_struct_field = cx.ident_of("emit_struct_field");
let mut stmts = ~[];
for (i, f) in fields.iter().enumerate() {
let (name, val) = match *f {
(Some(id), e, _) => (cx.str_of(id), e),
(None, e, _) => (format!("_field{}", i).to_managed(), e)
let name = match f.name {
Some(id) => cx.str_of(id),
None => format!("_field{}", i).to_managed()
};
let enc = cx.expr_method_call(span, val, encode, ~[blkencoder]);
let enc = cx.expr_method_call(span, f.self_, encode, ~[blkencoder]);
let lambda = cx.lambda_expr_1(span, enc, blkarg);
let call = cx.expr_method_call(span, blkencoder,
emit_struct_field,
......@@ -154,8 +154,7 @@ fn encodable_substructure(cx: @ExtCtxt, span: Span,
let emit_variant_arg = cx.ident_of("emit_enum_variant_arg");
let mut stmts = ~[];
for (i, f) in fields.iter().enumerate() {
let val = match *f { (_, e, _) => e };
let enc = cx.expr_method_call(span, val, encode, ~[blkencoder]);
let enc = cx.expr_method_call(span, f.self_, encode, ~[blkencoder]);
let lambda = cx.lambda_expr_1(span, enc, blkarg);
let call = cx.expr_method_call(span, blkencoder,
emit_variant_arg,
......
......@@ -81,8 +81,8 @@ fn iter_bytes_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @
_ => cx.span_bug(span, "Impossible substructure in `deriving(IterBytes)`")
}
for &(_, field, _) in fields.iter() {
exprs.push(call_iterbytes(field));
for &FieldInfo { self_, _ } in fields.iter() {
exprs.push(call_iterbytes(self_));
}
if exprs.len() == 0 {
......
......@@ -15,8 +15,6 @@
use ext::build::{AstBuilder};
use ext::deriving::generic::*;
use std::vec;
pub fn expand_deriving_rand(cx: @ExtCtxt,
span: Span,
mitem: @MetaItem,
......@@ -59,7 +57,7 @@ fn rand_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
cx.ident_of("Rand"),
cx.ident_of("rand")
];
let rand_call = || {
let rand_call = |span| {
cx.expr_call_global(span,
rand_ident.clone(),
~[ rng[0] ])
......@@ -112,7 +110,7 @@ fn rand_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
(ident, ref summary) => {
cx.arm(span,
~[ pat ],
rand_thing(cx, span, ident, summary, || rand_call()))
rand_thing(cx, span, ident, summary, |sp| rand_call(sp)))
}
}
}.collect::<~[ast::Arm]>();
......@@ -130,20 +128,20 @@ fn rand_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
fn rand_thing(cx: @ExtCtxt, span: Span,
ctor_ident: Ident,
summary: &Either<uint, ~[Ident]>,
rand_call: &fn() -> @Expr) -> @Expr {
summary: &StaticFields,
rand_call: &fn(Span) -> @Expr) -> @Expr {
match *summary {
Left(count) => {
if count == 0 {
Unnamed(ref fields) => {
if fields.is_empty() {
cx.expr_ident(span, ctor_ident)
} else {
let exprs = vec::from_fn(count, |_| rand_call());
let exprs = fields.map(|span| rand_call(*span));
cx.expr_call_ident(span, ctor_ident, exprs)
}
}
Right(ref fields) => {
let rand_fields = do fields.map |ident| {
cx.field_imm(span, *ident, rand_call())
Named(ref fields) => {
let rand_fields = do fields.map |&(ident, span)| {
cx.field_imm(span, ident, rand_call(span))
};
cx.expr_struct_ident(span, ctor_ident, rand_fields)
}
......
......@@ -49,7 +49,7 @@ fn to_str_substructure(cx: @ExtCtxt, span: Span,
let to_str = cx.ident_of("to_str");
let doit = |start: &str, end: @str, name: ast::Ident,
fields: &[(Option<ast::Ident>, @Expr, ~[@Expr])]| {
fields: &[FieldInfo]| {
if fields.len() == 0 {
cx.expr_str_uniq(span, cx.str_of(name))
} else {
......@@ -65,7 +65,7 @@ fn to_str_substructure(cx: @ExtCtxt, span: Span,
stmts.push(cx.stmt_expr(call));
};
for (i, &(name, e, _)) in fields.iter().enumerate() {
for (i, &FieldInfo {name, span, self_, _}) in fields.iter().enumerate() {
if i > 0 {
push(cx.expr_str(span, @", "));
}
......@@ -76,7 +76,7 @@ fn to_str_substructure(cx: @ExtCtxt, span: Span,
push(cx.expr_str(span, name.to_managed()));
}
}
push(cx.expr_method_call(span, e, to_str, ~[]));
push(cx.expr_method_call(span, self_, to_str, ~[]));
}
push(cx.expr_str(span, end));
......@@ -86,7 +86,7 @@ fn to_str_substructure(cx: @ExtCtxt, span: Span,
return match *substr.fields {
Struct(ref fields) => {
if fields.len() == 0 || fields[0].n0_ref().is_none() {
if fields.len() == 0 || fields[0].name.is_none() {
doit("(", @")", substr.type_ident, *fields)
} else {
doit("{", @"}", substr.type_ident, *fields)
......
......@@ -14,8 +14,6 @@
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use std::vec;
pub fn expand_deriving_zero(cx: @ExtCtxt,
span: Span,
mitem: @MetaItem,
......@@ -62,22 +60,22 @@ fn zero_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
cx.ident_of("Zero"),
cx.ident_of("zero")
];
let zero_call = cx.expr_call_global(span, zero_ident.clone(), ~[]);
let zero_call = |span| cx.expr_call_global(span, zero_ident.clone(), ~[]);
return match *substr.fields {
StaticStruct(_, ref summary) => {
match *summary {
Left(count) => {
if count == 0 {
Unnamed(ref fields) => {
if fields.is_empty() {
cx.expr_ident(span, substr.type_ident)
} else {
let exprs = vec::from_elem(count, zero_call);
let exprs = fields.map(|sp| zero_call(*sp));
cx.expr_call_ident(span, substr.type_ident, exprs)
}
}
Right(ref fields) => {
let zero_fields = do fields.map |ident| {
cx.field_imm(span, *ident, zero_call)
Named(ref fields) => {
let zero_fields = do fields.map |&(ident, span)| {
cx.field_imm(span, ident, zero_call(span))
};
cx.expr_struct_ident(span, substr.type_ident, zero_fields)
}
......
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[feature(struct_variant)];
struct NotEq;
#[deriving(Eq)]
enum Foo {
Bar {
x: NotEq //~ ERROR mismatched types
//~^ ERROR failed to find an implementation of trait std::cmp::Eq for NotEq
}
}
pub fn main() {}
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[feature(struct_variant)];
struct NotEq;
#[deriving(Eq)]
enum Foo {
Bar(NotEq), //~ ERROR mismatched types
//~^ ERROR failed to find an implementation of trait std::cmp::Eq for NotEq
Baz { x: NotEq }
}
pub fn main() {}
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
struct NotEq;
#[deriving(Eq)]
struct Foo {
x: NotEq //~ ERROR mismatched types
//~^ ERROR failed to find an implementation of trait std::cmp::Eq for NotEq
}
pub fn main() {}
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
struct NotEq;
#[deriving(Eq)]
struct Foo (
NotEq //~ ERROR mismatched types
//~^ ERROR failed to find an implementation of trait std::cmp::Eq for NotEq
);
pub fn main() {}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册