diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 6dd911e8ef321..c460ec89e4e9e 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -96,6 +96,7 @@ pub enum lint { unnecessary_allocation, missing_doc, + unreachable_code, } pub fn level_to_str(lv: level) -> &'static str { @@ -273,6 +274,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[ desc: "detects missing documentation for public members", default: allow }), + + ("unreachable_code", + LintSpec { + lint: unreachable_code, + desc: "detects unreachable code", + default: warn + }), ]; /* diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 61da263e8439a..f8481d4cf904d 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -81,6 +81,7 @@ use core::prelude::*; use middle::const_eval; use middle::pat_util::pat_id_map; use middle::pat_util; +use middle::lint::unreachable_code; use middle::ty::{FnSig, VariantInfo_}; use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty}; use middle::ty::{substs, param_ty}; @@ -2937,7 +2938,8 @@ pub fn check_block_with_expected(fcx: @mut FnCtxt, let mut any_err = false; for blk.node.stmts.each |s| { check_stmt(fcx, *s); - let s_ty = fcx.node_ty(ast_util::stmt_id(*s)); + let s_id = ast_util::stmt_id(*s); + let s_ty = fcx.node_ty(s_id); if last_was_bot && !warned && match s.node { ast::stmt_decl(@codemap::spanned { node: ast::decl_local(_), _}, _) | @@ -2946,7 +2948,8 @@ pub fn check_block_with_expected(fcx: @mut FnCtxt, } _ => false } { - fcx.ccx.tcx.sess.span_warn(s.span, "unreachable statement"); + fcx.ccx.tcx.sess.add_lint(unreachable_code, s_id, s.span, + ~"unreachable statement"); warned = true; } if ty::type_is_bot(s_ty) { diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index 72f92bc1522e9..4826af20c69a1 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -72,11 +72,12 @@ pub fn linear_map_with_capacity( fn linear_map_with_capacity_and_keys( k0: u64, k1: u64, initial_capacity: uint) -> HashMap { + let cap = uint::max(INITIAL_CAPACITY, initial_capacity); HashMap { k0: k0, k1: k1, - resize_at: resize_at(initial_capacity), + resize_at: resize_at(cap), size: 0, - buckets: vec::from_fn(initial_capacity, |_| None) + buckets: vec::from_fn(cap, |_| None) } } @@ -480,7 +481,8 @@ pub impl HashMap { } fn consume(&mut self, f: &fn(K, V)) { - let buckets = replace(&mut self.buckets, ~[]); + let buckets = replace(&mut self.buckets, + vec::from_fn(INITIAL_CAPACITY, |_| None)); self.size = 0; do vec::consume(buckets) |_, bucket| { @@ -664,6 +666,12 @@ mod test_map { use super::*; use uint; + #[test] + fn test_create_capacity_zero() { + let mut m = HashMap::with_capacity(0); + assert!(m.insert(1, 1)); + } + #[test] fn test_insert() { let mut m = HashMap::new(); @@ -771,6 +779,14 @@ mod test_map { assert_eq!(m2.get(&2), &3); } + #[test] + fn test_consume_still_usable() { + let mut m = HashMap::new(); + assert!(m.insert(1, 2)); + do m.consume |_, _| {} + assert!(m.insert(1, 2)); + } + #[test] fn test_iterate() { let mut m = linear_map_with_capacity(4); diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 4ae4533956e95..1991b2456d97d 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -14,410 +14,150 @@ encodable.rs for more. */ use core::prelude::*; +use core::vec; +use core::uint; -use ast::*; -use ast; -use ast_util; -use codemap::{span, spanned}; +use ast::{meta_item, item, expr, m_mutbl}; +use codemap::span; use ext::base::ExtCtxt; use ext::build::AstBuilder; -use ext::deriving::*; -use opt_vec; - -use core::uint; - -pub fn expand_deriving_decodable( - cx: @ExtCtxt, - span: span, - _mitem: @meta_item, - in_items: ~[@item] -) -> ~[@item] { - expand_deriving( - cx, - span, - in_items, - expand_deriving_decodable_struct_def, - expand_deriving_decodable_enum_def - ) -} - -fn create_derived_decodable_impl( - cx: @ExtCtxt, - span: span, - type_ident: ident, - generics: &Generics, - method: @method -) -> @item { - let decoder_ty_param = cx.typaram( - cx.ident_of("__D"), - @opt_vec::with( - cx.typarambound( - cx.path_global( - span, - ~[ - cx.ident_of("extra"), - cx.ident_of("serialize"), - cx.ident_of("Decoder"), - ])))); - - // All the type parameters need to bound to the trait. - let generic_ty_params = opt_vec::with(decoder_ty_param); - - let methods = [method]; - let trait_path = cx.path_all( - span, - true, - ~[ - cx.ident_of("extra"), - cx.ident_of("serialize"), - cx.ident_of("Decodable") - ], - None, - ~[ - cx.ty_ident(span, cx.ident_of("__D")) +use ext::deriving::generic::*; + +pub fn expand_deriving_decodable(cx: @ExtCtxt, + span: span, + mitem: @meta_item, + in_items: ~[@item]) -> ~[@item] { + let trait_def = TraitDef { + path: Path::new_(~["extra", "serialize", "Decodable"], None, + ~[~Literal(Path::new_local("__D"))], true), + additional_bounds: ~[], + generics: LifetimeBounds { + lifetimes: ~[], + bounds: ~[("__D", ~[Path::new(~["extra", "serialize", "Decoder"])])], + }, + methods: ~[ + MethodDef { + name: "decode", + generics: LifetimeBounds::empty(), + explicit_self: None, + args: ~[Ptr(~Literal(Path::new_local("__D")), + Borrowed(None, m_mutbl))], + ret_ty: Self, + const_nonmatching: true, + combine_substructure: decodable_substructure, + }, ] - ); - create_derived_impl( - cx, - span, - type_ident, - generics, - methods, - trait_path, - Generics { ty_params: generic_ty_params, lifetimes: opt_vec::Empty }, - opt_vec::Empty - ) -} - -// Creates a method from the given set of statements conforming to the -// signature of the `decodable` method. -fn create_decode_method( - cx: @ExtCtxt, - span: span, - type_ident: ast::ident, - generics: &Generics, - expr: @ast::expr -) -> @method { - // Create the `e` parameter. - let d_arg_type = cx.ty_rptr( - span, - cx.ty_ident(span, cx.ident_of("__D")), - None, - ast::m_mutbl - ); - let d_ident = cx.ident_of("__d"); - let d_arg = cx.arg(span, d_ident, d_arg_type); - - // Create the type of the return value. - let output_type = create_self_type_with_params( - cx, - span, - type_ident, - generics - ); - - // Create the function declaration. - let inputs = ~[d_arg]; - let fn_decl = cx.fn_decl(inputs, output_type); - - // Create the body block. - let body_block = cx.blk_expr(expr); + }; - // Create the method. - let explicit_self = spanned { node: sty_static, span: span }; - let method_ident = cx.ident_of("decode"); - @ast::method { - ident: method_ident, - attrs: ~[], - generics: ast_util::empty_generics(), - explicit_self: explicit_self, - purity: impure_fn, - decl: fn_decl, - body: body_block, - id: cx.next_id(), - span: span, - self_id: cx.next_id(), - vis: public - } + expand_deriving_generic(cx, span, mitem, in_items, + &trait_def) } -fn call_substructure_decode_method( - cx: @ExtCtxt, - span: span -) -> @ast::expr { - // Call the substructure method. - cx.expr_call( - span, - cx.expr_path( - cx.path_global( - span, - ~[ - cx.ident_of("extra"), +fn decodable_substructure(cx: @ExtCtxt, span: span, + substr: &Substructure) -> @expr { + let decoder = substr.nonself_args[0]; + let recurse = ~[cx.ident_of("extra"), cx.ident_of("serialize"), cx.ident_of("Decodable"), - cx.ident_of("decode"), - ] - ) - ), - ~[ - cx.expr_ident(span, cx.ident_of("__d")) - ] - ) -} - -fn expand_deriving_decodable_struct_def( - cx: @ExtCtxt, - span: span, - struct_def: &struct_def, - type_ident: ident, - generics: &Generics -) -> @item { - // Create the method. - let method = expand_deriving_decodable_struct_method( - cx, - span, - struct_def, - type_ident, - generics - ); - - // Create the implementation. - create_derived_decodable_impl( - cx, - span, - type_ident, - generics, - method - ) -} - -fn expand_deriving_decodable_enum_def( - cx: @ExtCtxt, - span: span, - enum_definition: &enum_def, - type_ident: ident, - generics: &Generics -) -> @item { - // Create the method. - let method = expand_deriving_decodable_enum_method( - cx, - span, - enum_definition, - type_ident, - generics - ); - - // Create the implementation. - create_derived_decodable_impl( - cx, - span, - type_ident, - generics, - method - ) -} - -fn create_read_struct_field( - cx: @ExtCtxt, - span: span, - idx: uint, - ident: ident -) -> ast::field { - // Call the substructure method. - let decode_expr = call_substructure_decode_method(cx, span); - - let d_id = cx.ident_of("__d"); - - let call_expr = cx.expr_method_call( - span, - cx.expr_ident(span, d_id), - cx.ident_of("read_struct_field"), - ~[ - cx.expr_str(span, cx.str_of(ident)), - cx.expr_uint(span, idx), - cx.lambda_expr_1(span, decode_expr, d_id) - ] - ); - - cx.field_imm(span, ident, call_expr) -} - -fn create_read_struct_arg( - cx: @ExtCtxt, - span: span, - idx: uint, - ident: ident -) -> ast::field { - // Call the substructure method. - let decode_expr = call_substructure_decode_method(cx, span); - - let call_expr = cx.expr_method_call( - span, - cx.expr_ident(span, cx.ident_of("__d")), - cx.ident_of("read_struct_arg"), - ~[ - cx.expr_uint(span, idx), - cx.lambda_expr_0(span, decode_expr), - ] - ); - - cx.field_imm(span, ident, call_expr) -} - -fn expand_deriving_decodable_struct_method( - cx: @ExtCtxt, - span: span, - struct_def: &struct_def, - type_ident: ident, - generics: &Generics -) -> @method { - // Create the body of the method. - let mut i = 0; - let mut fields = ~[]; - for struct_def.fields.each |struct_field| { - match struct_field.node.kind { - named_field(ident, _) => { - fields.push(create_read_struct_field(cx, span, i, ident)); - } - unnamed_field => { - cx.span_unimpl( - span, - "unnamed fields with `deriving(Decodable)`" - ); - } - } - i += 1; - } - - let d_id = cx.ident_of("__d"); - - let read_struct_expr = cx.expr_method_call( - span, - cx.expr_ident(span, d_id), - cx.ident_of("read_struct"), - ~[ - cx.expr_str(span, cx.str_of(type_ident)), - cx.expr_uint(span, fields.len()), - cx.lambda_expr_1( - span, - cx.expr_struct_ident(span, type_ident, fields), - d_id) - ] - ); - - // Create the method itself. - create_decode_method(cx, span, type_ident, generics, read_struct_expr) -} - -fn create_read_variant_arg( - cx: @ExtCtxt, - span: span, - idx: uint, - variant: &ast::variant -) -> ast::arm { - // Create the matching pattern. - let pat = cx.pat_lit(span, cx.expr_uint(span, idx)); - - // Feed each argument in this variant to the decode function - // as well. - let variant_arg_len = variant_arg_count(cx, span, variant); - - let expr = if variant_arg_len == 0 { - cx.expr_ident(span, variant.node.name) - } else { - // Feed the discriminant to the decode function. - let mut args = ~[]; - - for uint::range(0, variant_arg_len) |j| { - // Call the substructure method. - let expr = call_substructure_decode_method(cx, span); - - let d_id = cx.ident_of("__d"); - - let call_expr = cx.expr_method_call( - span, - cx.expr_ident(span, d_id), - cx.ident_of("read_enum_variant_arg"), - ~[ - cx.expr_uint(span, j), - cx.lambda_expr_1(span, expr, d_id), - ] - ); - - args.push(call_expr); + cx.ident_of("decode")]; + // throw an underscore in front to suppress unused variable warnings + let blkarg = cx.ident_of("_d"); + let blkdecoder = cx.expr_ident(span, blkarg); + let calldecode = cx.expr_call_global(span, recurse, ~[blkdecoder]); + let lambdadecode = cx.lambda_expr_1(span, calldecode, blkarg); + + return match *substr.fields { + StaticStruct(_, ref summary) => { + let nfields = match *summary { + Left(n) => n, Right(ref fields) => fields.len() + }; + let read_struct_field = cx.ident_of("read_struct_field"); + + let getarg = |name: ~str, field: uint| { + 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 uint::range(0, n) |i| { + fields.push(getarg(fmt!("_field%u", i), i)); + } + cx.expr_call_ident(span, substr.type_ident, fields) + } + } + Right(ref fields) => { + let fields = do fields.mapi |i, f| { + cx.field_imm(span, *f, getarg(cx.str_of(*f), i)) + }; + 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), + cx.lambda_expr_1(span, result, blkarg)]) } + StaticEnum(_, ref fields) => { + let variant = cx.ident_of("i"); + + let mut arms = ~[]; + let mut variants = ~[]; + let rvariant_arg = cx.ident_of("read_enum_variant_arg"); + + for fields.eachi |i, f| { + let (name, parts) = match *f { (i, ref p) => (i, p) }; + variants.push(cx.expr_str(span, cx.str_of(name))); + + let getarg = |field: uint| { + 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 uint::range(0, n) |i| { + fields.push(getarg(i)); + } + cx.expr_call_ident(span, name, fields) + } + } + Right(ref fields) => { + let fields = do fields.mapi |i, f| { + cx.field_imm(span, *f, getarg(i)) + }; + cx.expr_struct_ident(span, name, fields) + } + }; + arms.push(cx.arm(span, + ~[cx.pat_lit(span, cx.expr_uint(span, i))], + decoded)); + } - cx.expr_call_ident(span, variant.node.name, args) - }; - - // Create the arm. - cx.arm(span, ~[pat], expr) -} - -fn create_read_enum_variant( - cx: @ExtCtxt, - span: span, - enum_definition: &enum_def -) -> @expr { - // Create a vector that contains all the variant names. - let expr_arm_names = cx.expr_vec( - span, - do enum_definition.variants.map |variant| { - cx.expr_str( - span, - cx.str_of(variant.node.name) - ) + arms.push(cx.arm_unreachable(span)); + + let result = cx.expr_match(span, cx.expr_ident(span, variant), arms); + let lambda = cx.lambda_expr(span, ~[blkarg, variant], result); + let variant_vec = cx.expr_vec(span, variants); + let result = cx.expr_method_call(span, blkdecoder, + cx.ident_of("read_enum_variant"), + ~[variant_vec, lambda]); + cx.expr_method_call(span, decoder, cx.ident_of("read_enum"), + ~[cx.expr_str(span, cx.str_of(substr.type_ident)), + cx.lambda_expr_1(span, result, blkarg)]) } - ); - - // Create the arms of the match in the method body. - let mut arms = do enum_definition.variants.mapi |i, variant| { - create_read_variant_arg(cx, span, i, variant) + _ => cx.bug("expected StaticEnum or StaticStruct in deriving(Decodable)") }; - - // Add the impossible case arm. - arms.push(cx.arm_unreachable(span)); - - // Create the read_enum_variant expression. - cx.expr_method_call( - span, - cx.expr_ident(span, cx.ident_of("__d")), - cx.ident_of("read_enum_variant"), - ~[ - expr_arm_names, - cx.lambda_expr(span, - ~[cx.ident_of("__d"), cx.ident_of("__i")], - cx.expr_match(span, cx.expr_ident(span, cx.ident_of("__i")), arms)) - ] - ) -} - -fn expand_deriving_decodable_enum_method( - cx: @ExtCtxt, - span: span, - enum_definition: &enum_def, - type_ident: ast::ident, - generics: &Generics -) -> @method { - let read_enum_variant_expr = create_read_enum_variant( - cx, - span, - enum_definition - ); - - let d_id = cx.ident_of("__d"); - - // Create the read_enum expression - let read_enum_expr = cx.expr_method_call( - span, - cx.expr_ident(span, d_id), - cx.ident_of("read_enum"), - ~[ - cx.expr_str(span, cx.str_of(type_ident)), - cx.lambda_expr_1(span, read_enum_variant_expr, d_id) - ] - ); - - // Create the method. - create_decode_method(cx, span, type_ident, generics, read_enum_expr) } diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index 6ca7d0b7b28c8..b9c4bf7bf26af 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -77,578 +77,113 @@ would yield functions like: use core::prelude::*; -use ast; -use ast::*; +use ast::{meta_item, item, expr, m_imm, m_mutbl}; +use codemap::span; use ext::base::ExtCtxt; use ext::build::AstBuilder; -use ext::deriving::*; -use codemap::{span, spanned}; -use ast_util; -use opt_vec; - -pub fn expand_deriving_encodable( - cx: @ExtCtxt, - span: span, - _mitem: @meta_item, - in_items: ~[@item] -) -> ~[@item] { - expand_deriving( - cx, - span, - in_items, - expand_deriving_encodable_struct_def, - expand_deriving_encodable_enum_def - ) -} - -fn create_derived_encodable_impl( - cx: @ExtCtxt, - span: span, - type_ident: ident, - generics: &Generics, - method: @method -) -> @item { - let encoder_ty_param = cx.typaram( - cx.ident_of("__E"), - @opt_vec::with( - cx.typarambound( - cx.path_global( - span, - ~[ - cx.ident_of("extra"), - cx.ident_of("serialize"), - cx.ident_of("Encoder"), - ])))); - - // All the type parameters need to bound to the trait. - let generic_ty_params = opt_vec::with(encoder_ty_param); - - let methods = [method]; - let trait_path = cx.path_all( - span, - true, - ~[ - cx.ident_of("extra"), - cx.ident_of("serialize"), - cx.ident_of("Encodable") - ], - None, - ~[ - cx.ty_ident(span, cx.ident_of("__E")) +use ext::deriving::generic::*; + +pub fn expand_deriving_encodable(cx: @ExtCtxt, + span: span, + mitem: @meta_item, + in_items: ~[@item]) -> ~[@item] { + let trait_def = TraitDef { + path: Path::new_(~["extra", "serialize", "Encodable"], None, + ~[~Literal(Path::new_local("__E"))], true), + additional_bounds: ~[], + generics: LifetimeBounds { + lifetimes: ~[], + bounds: ~[("__E", ~[Path::new(~["extra", "serialize", "Encoder"])])], + }, + methods: ~[ + MethodDef { + name: "encode", + generics: LifetimeBounds::empty(), + explicit_self: Some(Some(Borrowed(None, m_imm))), + args: ~[Ptr(~Literal(Path::new_local("__E")), + Borrowed(None, m_mutbl))], + ret_ty: nil_ty(), + const_nonmatching: true, + combine_substructure: encodable_substructure, + }, ] - ); - create_derived_impl( - cx, - span, - type_ident, - generics, - methods, - trait_path, - Generics { ty_params: generic_ty_params, lifetimes: opt_vec::Empty }, - opt_vec::Empty - ) -} - -// Creates a method from the given set of statements conforming to the -// signature of the `encodable` method. -fn create_encode_method( - cx: @ExtCtxt, - span: span, - statements: ~[@stmt] -) -> @method { - // Create the `e` parameter. - let e_arg_type = cx.ty_rptr( - span, - cx.ty_ident(span, cx.ident_of("__E")), - None, - ast::m_mutbl - ); - let e_arg = cx.arg(span, cx.ident_of("__e"), e_arg_type); - - // Create the type of the return value. - let output_type = cx.ty_nil(); - - // Create the function declaration. - let inputs = ~[e_arg]; - let fn_decl = cx.fn_decl(inputs, output_type); - - // Create the body block. - let body_block = cx.blk(span, statements, None); - - // Create the method. - let explicit_self = spanned { node: sty_region(None, m_imm), span: span }; - let method_ident = cx.ident_of("encode"); - @ast::method { - ident: method_ident, - attrs: ~[], - generics: ast_util::empty_generics(), - explicit_self: explicit_self, - purity: impure_fn, - decl: fn_decl, - body: body_block, - id: cx.next_id(), - span: span, - self_id: cx.next_id(), - vis: public - } -} - -fn call_substructure_encode_method( - cx: @ExtCtxt, - span: span, - self_field: @expr -) -> @ast::expr { - // Gather up the parameters we want to chain along. - let e_ident = cx.ident_of("__e"); - let e_expr = cx.expr_ident(span, e_ident); - - // Call the substructure method. - let encode_ident = cx.ident_of("encode"); - cx.expr_method_call( - span, - self_field, - encode_ident, - ~[e_expr] - ) -} - -fn expand_deriving_encodable_struct_def( - cx: @ExtCtxt, - span: span, - struct_def: &struct_def, - type_ident: ident, - generics: &Generics -) -> @item { - // Create the method. - let method = expand_deriving_encodable_struct_method( - cx, - span, - type_ident, - struct_def - ); - - // Create the implementation. - create_derived_encodable_impl( - cx, - span, - type_ident, - generics, - method - ) -} - -fn expand_deriving_encodable_enum_def( - cx: @ExtCtxt, - span: span, - enum_definition: &enum_def, - type_ident: ident, - generics: &Generics -) -> @item { - // Create the method. - let method = expand_deriving_encodable_enum_method( - cx, - span, - type_ident, - enum_definition - ); + }; - // Create the implementation. - create_derived_encodable_impl( - cx, - span, - type_ident, - generics, - method - ) + expand_deriving_generic(cx, span, mitem, in_items, + &trait_def) } -fn expand_deriving_encodable_struct_method( - cx: @ExtCtxt, - span: span, - type_ident: ident, - struct_def: &struct_def -) -> @method { - // Create the body of the method. - let mut idx = 0; - let mut statements = ~[]; - for struct_def.fields.each |struct_field| { - match struct_field.node.kind { - named_field(ident, _) => { - // Create the accessor for this field. - let self_field = cx.expr_field_access(span, - cx.expr_self(span), - ident); - - // Call the substructure method. - let encode_expr = call_substructure_encode_method( - cx, - span, - self_field - ); - - let e_ident = cx.ident_of("__e"); - - let call_expr = cx.expr_method_call( - span, - cx.expr_ident(span, e_ident), - cx.ident_of("emit_struct_field"), - ~[ - cx.expr_str(span, cx.str_of(ident)), - cx.expr_uint(span, idx), - cx.lambda_expr_1(span, encode_expr, e_ident) - ] - ); - - statements.push(cx.stmt_expr(call_expr)); +fn encodable_substructure(cx: @ExtCtxt, span: span, + substr: &Substructure) -> @expr { + let encoder = substr.nonself_args[0]; + // throw an underscore in front to suppress unused variable warnings + let blkarg = cx.ident_of("_e"); + let blkencoder = cx.expr_ident(span, blkarg); + let encode = cx.ident_of("encode"); + + return match *substr.fields { + Struct(ref fields) => { + let emit_struct_field = cx.ident_of("emit_struct_field"); + let mut stmts = ~[]; + for fields.eachi |i, f| { + let (name, val) = match *f { + (Some(id), e, _) => (cx.str_of(id), e), + (None, e, _) => (fmt!("_field%u", i), e) + }; + let enc = cx.expr_method_call(span, val, encode, ~[blkencoder]); + let lambda = cx.lambda_expr_1(span, enc, blkarg); + let call = cx.expr_method_call(span, blkencoder, + emit_struct_field, + ~[cx.expr_str(span, name), + cx.expr_uint(span, i), + lambda]); + stmts.push(cx.stmt_expr(call)); } - unnamed_field => { - cx.span_unimpl( - span, - "unnamed fields with `deriving(Encodable)`" - ); - } - } - idx += 1; - } - let e_id = cx.ident_of("__e"); - let emit_struct_stmt = cx.expr_method_call( - span, - cx.expr_ident(span, e_id), - cx.ident_of("emit_struct"), - ~[ - cx.expr_str(span, cx.str_of(type_ident)), - cx.expr_uint(span, statements.len()), - cx.lambda_stmts_1(span, statements, e_id), - ] - ); - - let statements = ~[cx.stmt_expr(emit_struct_stmt)]; - - // Create the method itself. - return create_encode_method(cx, span, statements); -} - -fn expand_deriving_encodable_enum_method( - cx: @ExtCtxt, - span: span, - type_ident: ast::ident, - enum_definition: &enum_def -) -> @method { - // Create the arms of the match in the method body. - let arms = do enum_definition.variants.mapi |i, variant| { - // Create the matching pattern. - let (pat, fields) = create_enum_variant_pattern(cx, span, variant, "__self", ast::m_imm); - - // Feed the discriminant to the encode function. - let mut stmts = ~[]; - - // Feed each argument in this variant to the encode function - // as well. - let variant_arg_len = variant_arg_count(cx, span, variant); - for fields.eachi |j, &(_, field)| { - // Call the substructure method. - let expr = call_substructure_encode_method(cx, span, field); - - let e_ident = cx.ident_of("__e"); - let call_expr = cx.expr_method_call( - span, - cx.expr_ident(span, e_ident), - cx.ident_of("emit_enum_variant_arg"), - ~[ - cx.expr_uint(span, j), - cx.lambda_expr_1(span, expr, e_ident), - ] - ); - - stmts.push(cx.stmt_expr(call_expr)); - } - - // Create the pattern body. - let e_id = cx.ident_of("__e"); - - let call_expr = cx.expr_method_call( - span, - cx.expr_ident(span, e_id), - cx.ident_of("emit_enum_variant"), - ~[ - cx.expr_str(span, cx.str_of(variant.node.name)), - cx.expr_uint(span, i), - cx.expr_uint(span, variant_arg_len), - cx.lambda_stmts_1(span, stmts, e_id) - ] - ); - - //let match_body_block = cx.blk_expr(call_expr); + let blk = cx.lambda_stmts_1(span, stmts, blkarg); + cx.expr_method_call(span, encoder, cx.ident_of("emit_struct"), + ~[cx.expr_str(span, cx.str_of(substr.type_ident)), + cx.expr_uint(span, fields.len()), + blk]) + } + + EnumMatching(idx, variant, ref fields) => { + // We're not generating an AST that the borrow checker is expecting, + // so we need to generate a unique local variable to take the + // mutable loan out on, otherwise we get conflicts which don't + // actually exist. + let me = cx.stmt_let(span, false, blkarg, encoder); + let encoder = cx.expr_ident(span, blkarg); + let emit_variant_arg = cx.ident_of("emit_enum_variant_arg"); + let mut stmts = ~[]; + for fields.eachi |i, f| { + let val = match *f { (_, e, _) => e }; + let enc = cx.expr_method_call(span, val, encode, ~[blkencoder]); + let lambda = cx.lambda_expr_1(span, enc, blkarg); + let call = cx.expr_method_call(span, blkencoder, + emit_variant_arg, + ~[cx.expr_uint(span, i), + lambda]); + stmts.push(cx.stmt_expr(call)); + } - // Create the arm. - cx.arm(span, ~[pat], call_expr) //match_body_block) + let blk = cx.lambda_stmts_1(span, stmts, blkarg); + let name = cx.expr_str(span, cx.str_of(variant.node.name)); + let call = cx.expr_method_call(span, blkencoder, + cx.ident_of("emit_enum_variant"), + ~[name, + cx.expr_uint(span, idx), + cx.expr_uint(span, fields.len()), + blk]); + let blk = cx.lambda_expr_1(span, call, blkarg); + let ret = cx.expr_method_call(span, encoder, + cx.ident_of("emit_enum"), + ~[cx.expr_str(span, + cx.str_of(substr.type_ident)), + blk]); + cx.expr_blk(cx.blk(span, ~[me], Some(ret))) + } + + _ => cx.bug("expected Struct or EnumMatching in deriving(Encodable)") }; - - let e_ident = cx.ident_of("__e"); - - // Create the method body. - let lambda_expr = cx.lambda_expr_1( - span, - expand_enum_or_struct_match(cx, span, arms), - e_ident); - - let call_expr = cx.expr_method_call( - span, - cx.expr_ident(span, e_ident), - cx.ident_of("emit_enum"), - ~[ - cx.expr_str(span, cx.str_of(type_ident)), - lambda_expr, - ] - ); - - let stmt = cx.stmt_expr(call_expr); - - // Create the method. - create_encode_method(cx, span, ~[stmt]) -} - -#[cfg(test)] -mod test { - extern mod extra; - use core::option::{None, Some}; - use extra::serialize::Encodable; - use extra::serialize::Encoder; - - // just adding the ones I want to test, for now: - #[deriving(Eq)] - pub enum call { - CallToEmitEnum(~str), - CallToEmitEnumVariant(~str, uint, uint), - CallToEmitEnumVariantArg(uint), - CallToEmitUint(uint), - CallToEmitNil, - CallToEmitStruct(~str,uint), - CallToEmitField(~str,uint), - CallToEmitOption, - CallToEmitOptionNone, - CallToEmitOptionSome, - // all of the ones I was too lazy to handle: - CallToOther - } - // using `@mut` rather than changing the - // type of self in every method of every encoder everywhere. - pub struct TestEncoder {call_log : @mut ~[call]} - - pub impl TestEncoder { - // these self's should be &mut self's, as well.... - fn add_to_log (&self, c : call) { - self.call_log.push(copy c); - } - fn add_unknown_to_log (&self) { - self.add_to_log (CallToOther) - } - } - - impl Encoder for TestEncoder { - fn emit_nil(&mut self) { self.add_to_log(CallToEmitNil) } - - fn emit_uint(&mut self, v: uint) { - self.add_to_log(CallToEmitUint(v)); - } - fn emit_u64(&mut self, _v: u64) { self.add_unknown_to_log(); } - fn emit_u32(&mut self, _v: u32) { self.add_unknown_to_log(); } - fn emit_u16(&mut self, _v: u16) { self.add_unknown_to_log(); } - fn emit_u8(&mut self, _v: u8) { self.add_unknown_to_log(); } - - fn emit_int(&mut self, _v: int) { self.add_unknown_to_log(); } - fn emit_i64(&mut self, _v: i64) { self.add_unknown_to_log(); } - fn emit_i32(&mut self, _v: i32) { self.add_unknown_to_log(); } - fn emit_i16(&mut self, _v: i16) { self.add_unknown_to_log(); } - fn emit_i8(&mut self, _v: i8) { self.add_unknown_to_log(); } - - fn emit_bool(&mut self, _v: bool) { self.add_unknown_to_log(); } - - fn emit_f64(&mut self, _v: f64) { self.add_unknown_to_log(); } - fn emit_f32(&mut self, _v: f32) { self.add_unknown_to_log(); } - fn emit_float(&mut self, _v: float) { self.add_unknown_to_log(); } - - fn emit_char(&mut self, _v: char) { self.add_unknown_to_log(); } - fn emit_str(&mut self, _v: &str) { self.add_unknown_to_log(); } - - fn emit_enum(&mut self, name: &str, f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitEnum(name.to_str())); - f(self); - } - - fn emit_enum_variant(&mut self, - name: &str, - id: uint, - cnt: uint, - f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitEnumVariant(name.to_str(), id, cnt)); - f(self); - } - - fn emit_enum_variant_arg(&mut self, - idx: uint, - f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitEnumVariantArg(idx)); - f(self); - } - - fn emit_enum_struct_variant(&mut self, - name: &str, - id: uint, - cnt: uint, - f: &fn(&mut TestEncoder)) { - self.emit_enum_variant(name, id, cnt, f) - } - - fn emit_enum_struct_variant_field(&mut self, - _name: &str, - idx: uint, - f: &fn(&mut TestEncoder)) { - self.emit_enum_variant_arg(idx, f) - } - - fn emit_struct(&mut self, - name: &str, - len: uint, - f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitStruct (name.to_str(),len)); - f(self); - } - fn emit_struct_field(&mut self, - name: &str, - idx: uint, - f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitField (name.to_str(),idx)); - f(self); - } - - fn emit_tuple(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - fn emit_tuple_arg(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - - fn emit_tuple_struct(&mut self, - _name: &str, - _len: uint, - f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - - fn emit_tuple_struct_arg(&mut self, - _idx: uint, - f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - - fn emit_option(&mut self, f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitOption); - f(self); - } - fn emit_option_none(&mut self) { - self.add_to_log(CallToEmitOptionNone); - } - fn emit_option_some(&mut self, f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitOptionSome); - f(self); - } - - fn emit_seq(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - fn emit_seq_elt(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - - fn emit_map(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - fn emit_map_elt_key(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - } - - - fn to_call_log>(val: E) -> ~[call] { - let mut te = TestEncoder { - call_log: @mut ~[] - }; - val.encode(&mut te); - copy *te.call_log - } - - #[deriving(Encodable)] - enum Written { - Book(uint,uint), - Magazine(~str) - } - - #[test] - fn test_encode_enum() { - assert_eq!( - to_call_log(Book(34,44)), - ~[ - CallToEmitEnum(~"Written"), - CallToEmitEnumVariant(~"Book",0,2), - CallToEmitEnumVariantArg(0), - CallToEmitUint(34), - CallToEmitEnumVariantArg(1), - CallToEmitUint(44), - ] - ); - } - - pub struct BPos(uint); - - #[deriving(Encodable)] - pub struct HasPos { pos : BPos } - - #[test] - fn test_encode_newtype() { - assert_eq!( - to_call_log(HasPos { pos:BPos(48) }), - ~[ - CallToEmitStruct(~"HasPos",1), - CallToEmitField(~"pos",0), - CallToEmitUint(48), - ] - ); - } - - #[test] - fn test_encode_option() { - let mut v = None; - - assert_eq!( - to_call_log(v), - ~[ - CallToEmitOption, - CallToEmitOptionNone, - ] - ); - - v = Some(54u); - assert_eq!( - to_call_log(v), - ~[ - CallToEmitOption, - CallToEmitOptionSome, - CallToEmitUint(54) - ] - ); - } } diff --git a/src/test/compile-fail/dead-code-ret.rs b/src/test/compile-fail/dead-code-ret.rs index 5fa796db88444..91b89a67ee348 100644 --- a/src/test/compile-fail/dead-code-ret.rs +++ b/src/test/compile-fail/dead-code-ret.rs @@ -9,13 +9,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -fn f(caller: &str) { - debug!(caller); - let x: uint = 0u32; // induce type error //~ ERROR mismatched types -} +#[deny(unreachable_code)]; fn main() { - return f("main"); - debug!("Paul is dead"); //~ WARNING unreachable + return; + debug!("Paul is dead"); //~ ERROR: unreachable } diff --git a/src/test/compile-fail/issue-2150.rs b/src/test/compile-fail/issue-2150.rs index 9f2f9a855ed52..0b35104841e64 100644 --- a/src/test/compile-fail/issue-2150.rs +++ b/src/test/compile-fail/issue-2150.rs @@ -8,11 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[deny(unreachable_code)]; +#[allow(unused_variable)]; + fn fail_len(v: ~[int]) -> uint { - let mut i = fail!(); + let mut i = 3; + fail!(); for v.each |x| { i += 1u; } - //~^ WARNING unreachable statement - //~^^ ERROR the type of this value must be known + //~^ ERROR: unreachable statement return i; } fn main() {} diff --git a/src/test/compile-fail/issue-897-2.rs b/src/test/compile-fail/issue-897-2.rs index 253563c12195c..eb60e34df8f14 100644 --- a/src/test/compile-fail/issue-897-2.rs +++ b/src/test/compile-fail/issue-897-2.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[deny(unreachable_code)]; + fn g() -> ! { fail!(); } fn f() -> ! { - return 42i; //~ ERROR expected `!` but found `int` - g(); //~ WARNING unreachable statement + return g(); + g(); //~ ERROR: unreachable statement } fn main() { } diff --git a/src/test/compile-fail/issue-897.rs b/src/test/compile-fail/issue-897.rs index 503574fce8773..103156175a3fd 100644 --- a/src/test/compile-fail/issue-897.rs +++ b/src/test/compile-fail/issue-897.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[deny(unreachable_code)]; + fn f() -> ! { - return 42i; //~ ERROR expected `!` but found `int` - fail!(); //~ WARNING unreachable statement + return fail!(); + fail!(); //~ ERROR: unreachable statement } fn main() { } diff --git a/src/test/compile-fail/liveness-break-uninit-2.rs b/src/test/compile-fail/liveness-break-uninit-2.rs index c87439db6173a..2ed02e2cdd7db 100644 --- a/src/test/compile-fail/liveness-break-uninit-2.rs +++ b/src/test/compile-fail/liveness-break-uninit-2.rs @@ -13,7 +13,7 @@ fn foo() -> int { while 1 != 2 { break; - x = 0; //~ WARNING unreachable statement + x = 0; } debug!(x); //~ ERROR use of possibly uninitialized variable: `x` diff --git a/src/test/compile-fail/liveness-break-uninit.rs b/src/test/compile-fail/liveness-break-uninit.rs index 07075e4ef6398..2dcbad2804c16 100644 --- a/src/test/compile-fail/liveness-break-uninit.rs +++ b/src/test/compile-fail/liveness-break-uninit.rs @@ -13,7 +13,7 @@ fn foo() -> int { loop { break; - x = 0; //~ WARNING unreachable statement + x = 0; } debug!(x); //~ ERROR use of possibly uninitialized variable: `x` diff --git a/src/test/compile-fail/unreachable-code.rs b/src/test/compile-fail/unreachable-code.rs index f1fbc5b009e0a..a9365eeda1c55 100644 --- a/src/test/compile-fail/unreachable-code.rs +++ b/src/test/compile-fail/unreachable-code.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:unreachable statement +#[deny(unreachable_code)]; +#[allow(unused_variable)]; + fn main() { loop{} - // red herring to make sure compilation fails - error!(42 == 'c'); + + let a = 3; //~ ERROR: unreachable statement } diff --git a/src/test/run-pass/deriving-encodable-decodable.rs b/src/test/run-pass/deriving-encodable-decodable.rs new file mode 100644 index 0000000000000..fa672581238fe --- /dev/null +++ b/src/test/run-pass/deriving-encodable-decodable.rs @@ -0,0 +1,77 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This actually tests a lot more than just encodable/decodable, but it gets the +// job done at least + +// xfail-fast + +extern mod extra; + +use std::io; +use std::rand::{random, Rand}; +use extra::serialize::*; +use extra::ebml; +use extra::ebml::writer::Encoder; +use extra::ebml::reader::Decoder; + +#[deriving(Encodable, Decodable, Eq, Rand)] +struct A; +#[deriving(Encodable, Decodable, Eq, Rand)] +struct B(int); +#[deriving(Encodable, Decodable, Eq, Rand)] +struct C(int, int, uint); + +#[deriving(Encodable, Decodable, Eq, Rand)] +struct D { + a: int, + b: uint, +} + +#[deriving(Encodable, Decodable, Eq, Rand)] +enum E { + E1, + E2(uint), + E3(D), + E4{ x: uint }, +} + +#[deriving(Encodable, Decodable, Eq, Rand)] +enum F { F1 } + +#[deriving(Encodable, Decodable, Eq, Rand)] +struct G { + t: T +} + +fn roundtrip + Decodable>() { + let obj: T = random(); + let bytes = do io::with_bytes_writer |w| { + let mut e = Encoder(w); + obj.encode(&mut e); + }; + let doc = ebml::reader::Doc(@bytes); + let mut dec = Decoder(doc); + let obj2 = Decodable::decode(&mut dec); + assert!(obj == obj2); +} + +pub fn main() { + roundtrip::(); + roundtrip::(); + roundtrip::(); + roundtrip::(); + + for 20.times { + roundtrip::(); + roundtrip::(); + roundtrip::>(); + } +}