mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-19 18:34:08 +00:00
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:
parent
3e14ada4f6
commit
32ad4ae4cd
@ -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) );
|
||||
|
@ -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) => {
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) => {
|
||||
|
@ -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.
|
||||
|
@ -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) => {
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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),
|
||||
}
|
||||
|
||||
|
@ -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, _) => {
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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| {
|
||||
|
@ -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.
|
||||
|
@ -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) => {
|
||||
|
@ -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) => {
|
||||
|
@ -1,4 +1,5 @@
|
||||
trait MyEq {
|
||||
#[derivable]
|
||||
pure fn eq(other: &self) -> bool;
|
||||
}
|
||||
|
||||
|
17
src/test/compile-fail/missing-derivable-attr.rs
Normal file
17
src/test/compile-fail/missing-derivable-attr.rs
Normal 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() {
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
trait MyEq {
|
||||
#[derivable]
|
||||
pure fn eq(other: &self) -> bool;
|
||||
}
|
||||
|
||||
|
25
src/test/run-pass/deriving-one-method.rs
Normal file
25
src/test/run-pass/deriving-one-method.rs
Normal 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);
|
||||
}
|
||||
|
26
src/test/run-pass/deriving-override.rs
Normal file
26
src/test/run-pass/deriving-override.rs
Normal 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);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
trait Show {
|
||||
#[derivable]
|
||||
fn show();
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
trait MyEq {
|
||||
#[derivable]
|
||||
pure fn eq(other: &self) -> bool;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
trait MyEq {
|
||||
#[derivable]
|
||||
pure fn eq(other: &self) -> bool;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user