From 32ad4ae4cde68fed1b132be79bc9068b020d270b Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 13 Nov 2012 19:08:01 -0800 Subject: [PATCH] librustc: Require the #[derivable] attribute, remove the significance of "impl Foo : Bar;", and allow only a subset of methods in a trait to be derived. r=brson --- src/librustc/front/config.rs | 4 +- src/librustc/metadata/encoder.rs | 26 ++--- src/librustc/middle/resolve.rs | 78 ++++++------- src/librustc/middle/trans/base.rs | 18 ++- src/librustc/middle/trans/deriving.rs | 50 ++++---- src/librustc/middle/trans/meth.rs | 3 +- src/librustc/middle/trans/reachable.rs | 14 +-- src/librustc/middle/typeck/check.rs | 8 +- src/librustc/middle/typeck/coherence.rs | 108 +++++++++++++----- src/librustc/middle/typeck/collect.rs | 42 ++----- src/librustc/middle/typeck/deriving.rs | 61 +++++----- src/librustdoc/attr_pass.rs | 15 +-- src/librustdoc/extract.rs | 23 ++-- src/librustdoc/tystr_pass.rs | 29 ++--- src/libsyntax/ast.rs | 2 +- src/libsyntax/ast_map.rs | 8 +- src/libsyntax/ext/auto_serialize.rs | 2 +- src/libsyntax/fold.rs | 6 +- src/libsyntax/parse/parser.rs | 10 +- src/libsyntax/print/pprust.rs | 19 ++- src/libsyntax/visit.rs | 8 +- .../compile-fail/enum-deriving-incomplete.rs | 1 + .../compile-fail/missing-derivable-attr.rs | 17 +++ src/test/run-pass/deriving-generic-bounded.rs | 1 + src/test/run-pass/deriving-one-method.rs | 25 ++++ src/test/run-pass/deriving-override.rs | 26 +++++ src/test/run-pass/deriving-returning-nil.rs | 1 + src/test/run-pass/deriving-simple.rs | 1 + src/test/run-pass/enum-deriving-simple.rs | 1 + 29 files changed, 335 insertions(+), 272 deletions(-) create mode 100644 src/test/compile-fail/missing-derivable-attr.rs create mode 100644 src/test/run-pass/deriving-one-method.rs create mode 100644 src/test/run-pass/deriving-override.rs diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs index e988f5ed542..da3247de3b1 100644 --- a/src/librustc/front/config.rs +++ b/src/librustc/front/config.rs @@ -83,9 +83,9 @@ fn fold_foreign_mod(cx: ctxt, nm: ast::foreign_mod, fn fold_item_underscore(cx: ctxt, item: ast::item_, fld: fold::ast_fold) -> ast::item_ { let item = match item { - ast::item_impl(a, b, c, Some(methods)) => { + ast::item_impl(a, b, c, methods) => { let methods = methods.filter(|m| method_in_cfg(cx, *m) ); - ast::item_impl(a, b, c, Some(methods)) + ast::item_impl(a, b, c, methods) } ast::item_trait(a, b, ref methods) => { let methods = methods.filter(|m| trait_method_in_cfg(cx, m) ); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 07fc637a049..98c6688f03c 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -715,7 +715,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer, encode_index(ebml_w, bkts, write_int); ebml_w.end_tag(); } - item_impl(tps, opt_trait, ty, methods_opt) => { + item_impl(tps, opt_trait, ty, methods) => { add_to_index(); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(item.id)); @@ -732,13 +732,11 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer, } _ => {} } - for methods_opt.each |methods| { - for methods.each |m| { - ebml_w.start_tag(tag_item_impl_method); - let method_def_id = local_def(m.id); - ebml_w.writer.write(str::to_bytes(def_to_str(method_def_id))); - ebml_w.end_tag(); - } + for methods.each |m| { + ebml_w.start_tag(tag_item_impl_method); + let method_def_id = local_def(m.id); + ebml_w.writer.write(str::to_bytes(def_to_str(method_def_id))); + ebml_w.end_tag(); } do opt_trait.iter() |associated_trait| { encode_trait_ref(ebml_w, ecx, *associated_trait); @@ -748,13 +746,11 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer, let impl_path = vec::append_one(path, ast_map::path_name(item.ident)); - for methods_opt.each |methods| { - for methods.each |m| { - index.push({val: m.id, pos: ebml_w.writer.tell()}); - encode_info_for_method(ecx, ebml_w, impl_path, - should_inline(m.attrs), item.id, *m, - vec::append(tps, m.tps)); - } + for methods.each |m| { + index.push({val: m.id, pos: ebml_w.writer.tell()}); + encode_info_for_method(ecx, ebml_w, impl_path, + should_inline(m.attrs), item.id, *m, + vec::append(tps, m.tps)); } } item_trait(tps, traits, ms) => { diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 6b5f1c33e6f..4d435bea7a2 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1223,7 +1223,7 @@ impl Resolver { visit_item(item, new_parent, visitor); } - item_impl(_, trait_ref_opt, ty, methods_opt) => { + item_impl(_, trait_ref_opt, ty, methods) => { // If this implements an anonymous trait and it has static // methods, then add all the static methods within to a new // module, if the type was defined within this module. @@ -1234,12 +1234,10 @@ impl Resolver { // Bail out early if there are no static methods. let mut has_static_methods = false; - for methods_opt.each |methods| { - for methods.each |method| { - match method.self_ty.node { - sty_static => has_static_methods = true, - _ => {} - } + for methods.each |method| { + match method.self_ty.node { + sty_static => has_static_methods = true, + _ => {} } } @@ -1266,26 +1264,24 @@ impl Resolver { name_bindings.get_module()); // For each static method... - for methods_opt.each |methods| { - for methods.each |method| { - match method.self_ty.node { - sty_static => { - // Add the static method to the - // module. - let ident = method.ident; - let (method_name_bindings, _) = - self.add_child( - ident, - new_parent, - ForbidDuplicateValues, - method.span); - let def = def_fn(local_def(method.id), - method.purity); - method_name_bindings.define_value( - Public, def, method.span); - } - _ => {} + for methods.each |method| { + match method.self_ty.node { + sty_static => { + // Add the static method to the + // module. + let ident = method.ident; + let (method_name_bindings, _) = + self.add_child( + ident, + new_parent, + ForbidDuplicateValues, + method.span); + let def = def_fn(local_def(method.id), + method.purity); + method_name_bindings.define_value( + Public, def, method.span); } + _ => {} } } } @@ -3553,14 +3549,16 @@ impl Resolver { } } - item_impl(type_parameters, implemented_traits, self_type, - methods_opt) => { + item_impl(type_parameters, + implemented_traits, + self_type, + methods) => { self.resolve_implementation(item.id, item.span, type_parameters, implemented_traits, self_type, - methods_opt, + methods, visitor); } @@ -3988,7 +3986,7 @@ impl Resolver { type_parameters: ~[ty_param], opt_trait_reference: Option<@trait_ref>, self_type: @Ty, - opt_methods: Option<~[@method]>, + methods: ~[@method], visitor: ResolveVisitor) { // If applicable, create a rib for the type parameters. let outer_type_parameter_count = type_parameters.len(); @@ -4027,16 +4025,15 @@ impl Resolver { // Resolve the self type. self.resolve_type(self_type, visitor); - for opt_methods.each |methods| { - for methods.each |method| { - // We also need a new scope for the method-specific - // type parameters. - self.resolve_method(MethodRibKind( - id, - Provided(method.id)), - *method, - outer_type_parameter_count, - visitor); + for methods.each |method| { + // We also need a new scope for the method-specific + // type parameters. + self.resolve_method(MethodRibKind( + id, + Provided(method.id)), + *method, + outer_type_parameter_count, + visitor); /* let borrowed_type_parameters = &method.tps; self.resolve_function(MethodRibKind( @@ -4053,7 +4050,6 @@ impl Resolver { NoCaptureClause, visitor); */ - } } // Restore the original trait references. diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index ddc027f618e..c14bc6772b4 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1854,17 +1854,13 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) { } } } - ast::item_impl(tps, _, _, ms_opt) => { - match ms_opt { - None => { - deriving::trans_deriving_impl(ccx, *path, item.ident, tps, - item.id); - } - Some(ms) => { - meth::trans_impl(ccx, *path, item.ident, ms, tps, None, - item.id); - } - } + ast::item_impl(tps, _, _, ms) => { + // This call will do nothing if there are no derivable methods. + deriving::trans_deriving_impl(ccx, *path, item.ident, tps, + item.id); + + meth::trans_impl(ccx, *path, item.ident, ms, tps, None, + item.id); } ast::item_mod(m) => { trans_mod(ccx, m); diff --git a/src/librustc/middle/trans/deriving.rs b/src/librustc/middle/trans/deriving.rs index 93f65b5ad0e..7fe4a0b0e46 100644 --- a/src/librustc/middle/trans/deriving.rs +++ b/src/librustc/middle/trans/deriving.rs @@ -53,37 +53,43 @@ impl DerivingKind { } } -/// The main "translation" pass for automatically-derived impls. Generates -/// code for monomorphic methods only. Other methods will be generated when -/// they are invoked with specific type parameters; see +/// The main "translation" pass for the automatically-derived methods in +/// an impl. Generates code for monomorphic methods only. Other methods will +/// be generated when they are invoked with specific type parameters; see /// `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`. -pub fn trans_deriving_impl(ccx: @crate_ctxt, _path: path, _name: ident, - tps: ~[ty_param], id: node_id) { +pub fn trans_deriving_impl(ccx: @crate_ctxt, + _path: path, + _name: ident, + tps: ~[ty_param], + id: node_id) { let _icx = ccx.insn_ctxt("deriving::trans_deriving_impl"); if tps.len() > 0 { return; } let impl_def_id = local_def(id); let self_ty = ty::lookup_item_type(ccx.tcx, impl_def_id); - let method_dids = ccx.tcx.automatically_derived_methods_for_impl.get( - impl_def_id); - for method_dids.each |method_did| { - let kind = DerivingKind::of_item(ccx, *method_did); - let llfn = get_item_val(ccx, method_did.node); - match ty::get(self_ty.ty).sty { - ty::ty_class(*) => { - trans_deriving_struct_method(ccx, llfn, impl_def_id, - self_ty.ty, kind); - } - ty::ty_enum(*) => { - trans_deriving_enum_method(ccx, llfn, impl_def_id, - self_ty.ty, kind); - } - _ => { - ccx.tcx.sess.bug(~"translation of non-struct deriving \ - method"); + match ccx.tcx.automatically_derived_methods_for_impl.find(impl_def_id) { + Some(copy method_dids) => { + for method_dids.each |method_did| { + let kind = DerivingKind::of_item(ccx, *method_did); + let llfn = get_item_val(ccx, method_did.node); + match ty::get(self_ty.ty).sty { + ty::ty_class(*) => { + trans_deriving_struct_method(ccx, llfn, impl_def_id, + self_ty.ty, kind); + } + ty::ty_enum(*) => { + trans_deriving_enum_method(ccx, llfn, impl_def_id, + self_ty.ty, kind); + } + _ => { + ccx.tcx.sess.bug(~"translation of non-struct \ + deriving method"); + } + } } } + None => {} // Nothing to do. } } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index ea85453a445..c64c8554718 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -306,8 +306,7 @@ fn method_with_name(ccx: @crate_ctxt, impl_id: ast::def_id, name: ast::ident) -> ast::def_id { if impl_id.crate == ast::local_crate { match ccx.tcx.items.get(impl_id.node) { - ast_map::node_item(@{node: ast::item_impl(_, _, _, Some(ms)), _}, - _) => { + ast_map::node_item(@{node: ast::item_impl(_, _, _, ms), _}, _) => { method_from_methods(ms, name) } ast_map::node_item(@{node: diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs index 87cb4716cd2..a99ef96b254 100644 --- a/src/librustc/middle/trans/reachable.rs +++ b/src/librustc/middle/trans/reachable.rs @@ -90,14 +90,12 @@ fn traverse_public_item(cx: ctx, item: @item) { traverse_inline_body(cx, blk); } } - item_impl(tps, _, _, ms_opt) => { - for ms_opt.each |ms| { - for vec::each(*ms) |m| { - if tps.len() > 0u || m.tps.len() > 0u || - attr::find_inline_attr(m.attrs) != attr::ia_none { - cx.rmap.insert(m.id, ()); - traverse_inline_body(cx, m.body); - } + item_impl(tps, _, _, ms) => { + for vec::each(ms) |m| { + if tps.len() > 0u || m.tps.len() > 0u || + attr::find_inline_attr(m.attrs) != attr::ia_none { + cx.rmap.insert(m.id, ()); + traverse_inline_body(cx, m.body); } } } diff --git a/src/librustc/middle/typeck/check.rs b/src/librustc/middle/typeck/check.rs index 3d56ad3595d..938f6c34ea0 100644 --- a/src/librustc/middle/typeck/check.rs +++ b/src/librustc/middle/typeck/check.rs @@ -498,15 +498,13 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) { ast::item_fn(decl, _, _, body) => { check_bare_fn(ccx, decl, body, it.id, None); } - ast::item_impl(_, _, ty, ms_opt) => { + ast::item_impl(_, _, ty, ms) => { let rp = ccx.tcx.region_paramd_items.find(it.id); debug!("item_impl %s with id %d rp %?", ccx.tcx.sess.str_of(it.ident), it.id, rp); let self_ty = ccx.to_ty(rscope::type_rscope(rp), ty); - for ms_opt.each |ms| { - for ms.each |m| { - check_method(ccx, *m, self_ty, local_def(it.id)); - } + for ms.each |m| { + check_method(ccx, *m, self_ty, local_def(it.id)); } } ast::item_trait(_, _, trait_methods) => { diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 7a863b0cc39..9fc7814422f 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -25,6 +25,7 @@ use syntax::ast::{item_trait, item_ty, local_crate, method, node_id}; use syntax::ast::{trait_ref}; use syntax::ast_map::node_item; use syntax::ast_util::{def_id_of_def, dummy_sp}; +use syntax::attr; use syntax::codemap::span; use syntax::visit::{default_simple_visitor, default_visitor}; use syntax::visit::{mk_simple_visitor, mk_vt, visit_crate, visit_item}; @@ -613,14 +614,67 @@ impl CoherenceChecker { return trait_id; } + /// Returns true if the method has been marked with the #[derivable] + /// attribute and false otherwise. + fn method_is_derivable(method_def_id: ast::def_id) -> bool { + if method_def_id.crate == local_crate { + match self.crate_context.tcx.items.find(method_def_id.node) { + Some(ast_map::node_trait_method(trait_method, _, _)) => { + match *trait_method { + ast::required(ty_method) => { + attr::attrs_contains_name(ty_method.attrs, + ~"derivable") + } + ast::provided(method) => { + attr::attrs_contains_name(method.attrs, + ~"derivable") + } + } + } + _ => { + self.crate_context.tcx.sess.bug(~"method_is_derivable(): \ + def ID passed in \ + wasn't a trait method") + } + } + } else { + false // XXX: Unimplemented. + } + } + fn add_automatically_derived_methods_from_trait( all_methods: &mut ~[@MethodInfo], trait_did: def_id, self_ty: ty::t, - impl_did: def_id) { + impl_did: def_id, + trait_ref_span: span) { let tcx = self.crate_context.tcx; + + // Make a set of all the method names that this implementation and + // trait provided so that we don't try to automatically derive + // implementations for them. + let mut provided_names = send_map::linear::LinearMap(); + for uint::range(0, all_methods.len()) |i| { + provided_names.insert(all_methods[i].ident, ()); + } + for ty::provided_trait_methods(tcx, trait_did).each |ident| { + provided_names.insert(*ident, ()); + } + let new_method_dids = dvec::DVec(); for (*ty::trait_methods(tcx, trait_did)).each |method| { + // Check to see whether we need to derive this method. We need to + // derive a method only if and only if neither the trait nor the + // implementation we're considering provided a body. + if provided_names.contains_key(&method.ident) { loop; } + + if !self.method_is_derivable(method.def_id) { + tcx.sess.span_err(trait_ref_span, + fmt!("missing method `%s`", + tcx.sess.str_of(method.ident))); + loop; + } + // Generate a def ID for each node. let new_def_id = local_def(tcx.sess.next_node_id()); let method_info = @{ @@ -656,8 +710,10 @@ impl CoherenceChecker { } let new_method_dids = @dvec::unwrap(move new_method_dids); - tcx.automatically_derived_methods_for_impl.insert(impl_did, - new_method_dids); + if new_method_dids.len() > 0 { + tcx.automatically_derived_methods_for_impl.insert( + impl_did, new_method_dids); + } } // Converts an implementation in the AST to an Impl structure. @@ -674,36 +730,28 @@ impl CoherenceChecker { } match item.node { - item_impl(_, trait_refs, _, ast_methods_opt) => { + item_impl(_, trait_refs, _, ast_methods) => { let mut methods = ~[]; - - match ast_methods_opt { - Some(ast_methods) => { - for ast_methods.each |ast_method| { - methods.push(method_to_MethodInfo(*ast_method)); - } - } - None => { - // This is a "deriving" impl. For each trait, - // collect all the "required" methods and add - // them to the Impl structure. - let tcx = self.crate_context.tcx; - let self_ty = ty::lookup_item_type( - tcx, local_def(item.id)); - for trait_refs.each |trait_ref| { - let trait_did = - self.trait_ref_to_trait_def_id( - *trait_ref); - self.add_automatically_derived_methods_from_trait( - &mut methods, - trait_did, - self_ty.ty, - local_def(item.id)); - } - } + for ast_methods.each |ast_method| { + methods.push(method_to_MethodInfo(*ast_method)); } - // For each trait that the impl implements, see what + // Now search for methods that need to be automatically + // derived. + let tcx = self.crate_context.tcx; + let self_ty = ty::lookup_item_type(tcx, local_def(item.id)); + for trait_refs.each |trait_ref| { + let trait_did = + self.trait_ref_to_trait_def_id(*trait_ref); + self.add_automatically_derived_methods_from_trait( + &mut methods, + trait_did, + self_ty.ty, + local_def(item.id), + trait_ref.path.span); + } + + // For each trait that the impl implements, see which // methods are provided. For each of those methods, // if a method of that name is not inherent to the // impl, use the provided definition in the trait. diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index ebc26d4b4df..4faf34b3078 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -451,24 +451,10 @@ fn check_methods_against_trait(ccx: @crate_ctxt, } None => { // If we couldn't find an implementation for trait_m in - // the impl, then see if there was a default - // implementation in the trait itself. If not, raise a - // "missing method" error. - - let provided_methods = ty::provided_trait_methods(tcx, did); - match vec::find(provided_methods, |provided_method| - *provided_method == trait_m.ident) { - Some(_) => { - // If there's a provided method with the name we - // want, then we're fine; nothing else to do. - } - None => { - tcx.sess.span_err( - a_trait_ty.path.span, - fmt!("missing method `%s`", - tcx.sess.str_of(trait_m.ident))); - } - } + // the impl, then either this method has a default + // implementation or we're using the trait-provided + // version. Either way, we handle this later, during the + // coherence phase. } } // match } // |trait_m| @@ -532,7 +518,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) { get_enum_variant_types(ccx, tpt.ty, enum_definition.variants, ty_params, rp); } - ast::item_impl(tps, trait_ref, selfty, ms_opt) => { + ast::item_impl(tps, trait_ref, selfty, ms) => { let i_bounds = ty_param_bounds(ccx, tps); let selfty = ccx.to_ty(type_rscope(rp), selfty); write_ty_to_tcx(tcx, it.id, selfty); @@ -541,21 +527,9 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) { region_param: rp, ty: selfty}); - match ms_opt { - Some(ref ms) => { - let cms = convert_methods(ccx, *ms, rp, i_bounds); - for trait_ref.each |t| { - check_methods_against_trait(ccx, tps, rp, selfty, *t, - cms); - } - } - None => { - // We still need to instantiate the trait ref here so that - // metadata encoding will find the type. - for trait_ref.each |trait_ref| { - let _ = instantiate_trait_ref(ccx, *trait_ref, rp); - } - } + let cms = convert_methods(ccx, ms, rp, i_bounds); + for trait_ref.each |t| { + check_methods_against_trait(ccx, tps, rp, selfty, *t, cms); } } ast::item_trait(tps, supertraits, trait_methods) => { diff --git a/src/librustc/middle/typeck/deriving.rs b/src/librustc/middle/typeck/deriving.rs index 7fa44491a87..197a06a1d97 100644 --- a/src/librustc/middle/typeck/deriving.rs +++ b/src/librustc/middle/typeck/deriving.rs @@ -251,33 +251,40 @@ impl DerivingChecker { visit_crate(*crate, (), mk_simple_visitor(@{ visit_item: |item| { match item.node { - item_impl(_, Some(trait_ref), _, None) => { - // XXX: This does not handle generic impls. - let superty = ty::lookup_item_type( - tcx, local_def(item.id)).ty; - match ty::get(superty).sty { - ty_enum(def_id, ref substs) => { - self.check_deriving_for_enum( - def_id, - substs, - trait_ref, - item.id, - item.span); - } - ty_class(def_id, ref substs) => { - self.check_deriving_for_struct( - def_id, - substs, - trait_ref, - item.id, - item.span); - } - _ => { - tcx.sess.span_err(item.span, - ~"only enums and structs \ - may have implementations \ - automatically derived \ - for them"); + item_impl(_, Some(trait_ref), _, _) => { + // Determine whether there were any automatically- + // derived methods in this implementation. + let impl_did = local_def(item.id); + if tcx.automatically_derived_methods_for_impl. + contains_key(impl_did) { + // XXX: This does not handle generic impls. + let superty = ty::lookup_item_type( + tcx, local_def(item.id)).ty; + match ty::get(superty).sty { + ty_enum(def_id, ref substs) => { + self.check_deriving_for_enum( + def_id, + substs, + trait_ref, + item.id, + item.span); + } + ty_class(def_id, ref substs) => { + self.check_deriving_for_struct( + def_id, + substs, + trait_ref, + item.id, + item.span); + } + _ => { + tcx.sess.span_err(item.span, + ~"only enums and \ + structs may have \ + implementations \ + automatically \ + derived for them"); + } } } } diff --git a/src/librustdoc/attr_pass.rs b/src/librustdoc/attr_pass.rs index 92ab33e3614..da90dccc228 100644 --- a/src/librustdoc/attr_pass.rs +++ b/src/librustdoc/attr_pass.rs @@ -221,17 +221,12 @@ fn merge_method_attrs( }) } ast_map::node_item(@{ - node: ast::item_impl(_, _, _, methods_opt), _ + node: ast::item_impl(_, _, _, methods), _ }, _) => { - match methods_opt { - None => ~[], - Some(methods) => { - vec::map(methods, |method| { - (to_str(method.ident), - attr_parser::parse_desc(method.attrs)) - }) - } - } + vec::map(methods, |method| { + (to_str(method.ident), + attr_parser::parse_desc(method.attrs)) + }) } _ => fail ~"unexpected item" } diff --git a/src/librustdoc/extract.rs b/src/librustdoc/extract.rs index 8ac74f4663c..7b34a327bee 100644 --- a/src/librustdoc/extract.rs +++ b/src/librustdoc/extract.rs @@ -258,25 +258,20 @@ fn should_extract_trait_methods() { fn impldoc_from_impl( itemdoc: doc::ItemDoc, - methods_opt: Option<~[@ast::method]> + methods: ~[@ast::method] ) -> doc::ImplDoc { { item: itemdoc, trait_types: ~[], self_ty: None, - methods: match methods_opt { - None => ~[], - Some(methods) => { - do vec::map(methods) |method| { - { - name: to_str(method.ident), - brief: None, - desc: None, - sections: ~[], - sig: None, - implementation: doc::Provided, - } - } + methods: do vec::map(methods) |method| { + { + name: to_str(method.ident), + brief: None, + desc: None, + sections: ~[], + sig: None, + implementation: doc::Provided, } } } diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs index fb47e58f769..08ad3ea3ecf 100644 --- a/src/librustdoc/tystr_pass.rs +++ b/src/librustdoc/tystr_pass.rs @@ -207,25 +207,20 @@ fn get_method_sig( } } ast_map::node_item(@{ - node: ast::item_impl(_, _, _, methods_opt), _ + node: ast::item_impl(_, _, _, methods), _ }, _) => { - match methods_opt { - None => fail ~"no methods in this impl", - Some(methods) => { - match vec::find(methods, |method| { - to_str(method.ident) == method_name - }) { - Some(method) => { - Some(pprust::fun_to_str( - method.decl, - method.ident, - method.tps, - extract::interner() - )) - } - None => fail ~"method not found" - } + match vec::find(methods, |method| { + to_str(method.ident) == method_name + }) { + Some(method) => { + Some(pprust::fun_to_str( + method.decl, + method.ident, + method.tps, + extract::interner() + )) } + None => fail ~"method not found" } } _ => fail ~"get_method_sig: item ID not bound to trait or impl" diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index dd90dfee683..148600d8d21 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1517,7 +1517,7 @@ enum item_ { item_impl(~[ty_param], Option<@trait_ref>, /* (optional) trait this impl implements */ @Ty, /* self */ - Option<~[@method]>), + ~[@method]), item_mac(mac), } diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index c2e255cad14..0d7b1f1e5c4 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -203,12 +203,10 @@ fn map_item(i: @item, cx: ctx, v: vt) { let item_path = @/* FIXME (#2543) */ copy cx.path; cx.map.insert(i.id, node_item(i, item_path)); match i.node { - item_impl(_, _, _, ms_opt) => { + item_impl(_, _, _, ms) => { let impl_did = ast_util::local_def(i.id); - for ms_opt.each |ms| { - for ms.each |m| { - map_method(impl_did, extend(cx, i.ident), *m, cx); - } + for ms.each |m| { + map_method(impl_did, extend(cx, i.ident), *m, cx); } } item_enum(enum_definition, _) => { diff --git a/src/libsyntax/ext/auto_serialize.rs b/src/libsyntax/ext/auto_serialize.rs index 39e94291d8b..f9fece0b5cb 100644 --- a/src/libsyntax/ext/auto_serialize.rs +++ b/src/libsyntax/ext/auto_serialize.rs @@ -398,7 +398,7 @@ fn mk_impl( ident: ast::token::special_idents::clownshoes_extensions, attrs: ~[], id: cx.next_id(), - node: ast::item_impl(trait_tps, opt_trait, ty, Some(~[f(ty)])), + node: ast::item_impl(trait_tps, opt_trait, ty, ~[f(ty)]), vis: ast::public, span: span, } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 8609124126c..4d51ecded01 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -249,13 +249,11 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ { let struct_def = fold_struct_def(struct_def, fld); item_class(struct_def, /* FIXME (#2543) */ copy typms) } - item_impl(tps, ifce, ty, ref methods_opt) => { + item_impl(tps, ifce, ty, ref methods) => { item_impl(fold_ty_params(tps, fld), ifce.map(|p| fold_trait_ref(*p, fld)), fld.fold_ty(ty), - option::map(methods_opt, - |methods| vec::map( - *methods, |x| fld.fold_method(*x)))) + vec::map(*methods, |x| fld.fold_method(*x))) } item_trait(tps, traits, methods) => { let methods = do methods.map |method| { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c5f3b1b5306..49c3d38ce55 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2687,19 +2687,15 @@ impl Parser { None }; - let meths_opt; - if self.eat(token::SEMI) { - meths_opt = None; - } else { - let mut meths = ~[]; + let mut meths = ~[]; + if !self.eat(token::SEMI) { self.expect(token::LBRACE); while !self.eat(token::RBRACE) { meths.push(self.parse_method()); } - meths_opt = Some(move meths); } - (ident, item_impl(tps, opt_trait, ty, meths_opt), None) + (ident, item_impl(tps, opt_trait, ty, meths), None) } // Instantiates ident with references to as arguments. diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 09cc9ad0232..267f0e7d5f2 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -520,7 +520,7 @@ fn print_item(s: ps, &&item: @ast::item) { print_struct(s, struct_def, tps, item.ident, item.span); } - ast::item_impl(tps, opt_trait, ty, methods_opt) => { + ast::item_impl(tps, opt_trait, ty, methods) => { head(s, visibility_qualified(item.vis, ~"impl")); if tps.is_not_empty() { print_type_params(s, tps); @@ -537,17 +537,14 @@ fn print_item(s: ps, &&item: @ast::item) { }; space(s.s); - match methods_opt { - None => { - word(s.s, ~";"); - } - Some(methods) => { - bopen(s); - for methods.each |meth| { - print_method(s, *meth); - } - bclose(s, item.span); + if methods.len() == 0 { + word(s.s, ~";"); + } else { + bopen(s); + for methods.each |meth| { + print_method(s, *meth); } + bclose(s, item.span); } } ast::item_trait(tps, traits, methods) => { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 42b869b6c34..3bc8c7b9420 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -142,16 +142,14 @@ fn visit_item(i: @item, e: E, v: vt) { v.visit_ty_params(tps, e, v); visit_enum_def(enum_definition, tps, e, v); } - item_impl(tps, traits, ty, methods_opt) => { + item_impl(tps, traits, ty, methods) => { v.visit_ty_params(tps, e, v); for traits.each |p| { visit_path(p.path, e, v); } v.visit_ty(ty, e, v); - for methods_opt.each |methods| { - for methods.each |m| { - visit_method_helper(*m, e, v) - } + for methods.each |m| { + visit_method_helper(*m, e, v) } } item_class(struct_def, tps) => { diff --git a/src/test/compile-fail/enum-deriving-incomplete.rs b/src/test/compile-fail/enum-deriving-incomplete.rs index 1eba177e964..eb103a48df9 100644 --- a/src/test/compile-fail/enum-deriving-incomplete.rs +++ b/src/test/compile-fail/enum-deriving-incomplete.rs @@ -1,4 +1,5 @@ trait MyEq { + #[derivable] pure fn eq(other: &self) -> bool; } diff --git a/src/test/compile-fail/missing-derivable-attr.rs b/src/test/compile-fail/missing-derivable-attr.rs new file mode 100644 index 00000000000..140c915c57d --- /dev/null +++ b/src/test/compile-fail/missing-derivable-attr.rs @@ -0,0 +1,17 @@ +trait MyEq { + pure fn eq(other: &self) -> bool; +} + +struct A { + x: int +} + +impl int : MyEq { + pure fn eq(other: &int) -> bool { self == *other } +} + +impl A : MyEq; //~ ERROR missing method + +fn main() { +} + diff --git a/src/test/run-pass/deriving-generic-bounded.rs b/src/test/run-pass/deriving-generic-bounded.rs index 94ecb476584..a45b7df3a2a 100644 --- a/src/test/run-pass/deriving-generic-bounded.rs +++ b/src/test/run-pass/deriving-generic-bounded.rs @@ -1,4 +1,5 @@ trait MyEq { + #[derivable] pure fn eq(other: &self) -> bool; } diff --git a/src/test/run-pass/deriving-one-method.rs b/src/test/run-pass/deriving-one-method.rs new file mode 100644 index 00000000000..20fe5a35cd3 --- /dev/null +++ b/src/test/run-pass/deriving-one-method.rs @@ -0,0 +1,25 @@ +trait MyEq { + #[derivable] + pure fn eq(other: &self) -> bool; + pure fn ne(other: &self) -> bool; +} + +struct A { + x: int +} + +impl int : MyEq { + pure fn eq(other: &int) -> bool { self == *other } + pure fn ne(other: &int) -> bool { self != *other } +} + +impl A : MyEq { + pure fn ne(other: &A) -> bool { !self.eq(other) } +} + +fn main() { + let a = A { x: 1 }; + assert a.eq(&a); + assert !a.ne(&a); +} + diff --git a/src/test/run-pass/deriving-override.rs b/src/test/run-pass/deriving-override.rs new file mode 100644 index 00000000000..5b030e4db18 --- /dev/null +++ b/src/test/run-pass/deriving-override.rs @@ -0,0 +1,26 @@ +trait MyEq { + #[derivable] + pure fn eq(other: &self) -> bool; + #[derivable] + pure fn ne(other: &self) -> bool; +} + +struct A { + x: int +} + +impl int : MyEq { + pure fn eq(other: &int) -> bool { self == *other } + pure fn ne(other: &int) -> bool { self != *other } +} + +impl A : MyEq { + pure fn ne(other: &A) -> bool { !self.eq(other) } +} + +fn main() { + let a = A { x: 1 }; + assert a.eq(&a); + assert !a.ne(&a); +} + diff --git a/src/test/run-pass/deriving-returning-nil.rs b/src/test/run-pass/deriving-returning-nil.rs index ed399b998ce..385bb9a3b95 100644 --- a/src/test/run-pass/deriving-returning-nil.rs +++ b/src/test/run-pass/deriving-returning-nil.rs @@ -1,4 +1,5 @@ trait Show { + #[derivable] fn show(); } diff --git a/src/test/run-pass/deriving-simple.rs b/src/test/run-pass/deriving-simple.rs index 04167893507..60c51a73ddb 100644 --- a/src/test/run-pass/deriving-simple.rs +++ b/src/test/run-pass/deriving-simple.rs @@ -1,4 +1,5 @@ trait MyEq { + #[derivable] pure fn eq(other: &self) -> bool; } diff --git a/src/test/run-pass/enum-deriving-simple.rs b/src/test/run-pass/enum-deriving-simple.rs index 1a49bcd312c..b075f1b1c6a 100644 --- a/src/test/run-pass/enum-deriving-simple.rs +++ b/src/test/run-pass/enum-deriving-simple.rs @@ -1,4 +1,5 @@ trait MyEq { + #[derivable] pure fn eq(other: &self) -> bool; }