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

This commit is contained in:
Patrick Walton 2012-11-13 19:08:01 -08:00
parent 3e14ada4f6
commit 32ad4ae4cd
29 changed files with 335 additions and 272 deletions

View File

@ -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) );

View File

@ -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) => {

View File

@ -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.

View File

@ -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);

View File

@ -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.
}
}

View File

@ -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:

View File

@ -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);
}
}
}

View File

@ -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) => {

View File

@ -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.

View File

@ -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) => {

View File

@ -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");
}
}
}
}

View File

@ -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"
}

View File

@ -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,
}
}
}

View File

@ -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"

View File

@ -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),
}

View File

@ -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, _) => {

View File

@ -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,
}

View File

@ -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| {

View File

@ -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 <i> with references to <typarams> as arguments.

View File

@ -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) => {

View File

@ -142,16 +142,14 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
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) => {

View File

@ -1,4 +1,5 @@
trait MyEq {
#[derivable]
pure fn eq(other: &self) -> bool;
}

View File

@ -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() {
}

View File

@ -1,4 +1,5 @@
trait MyEq {
#[derivable]
pure fn eq(other: &self) -> bool;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -1,4 +1,5 @@
trait Show {
#[derivable]
fn show();
}

View File

@ -1,4 +1,5 @@
trait MyEq {
#[derivable]
pure fn eq(other: &self) -> bool;
}

View File

@ -1,4 +1,5 @@
trait MyEq {
#[derivable]
pure fn eq(other: &self) -> bool;
}