rustc: Implement typechecking for simple monomorphic derivable traits on monomorphic types. r=brson
This commit is contained in:
parent
575950d12c
commit
3bf0a9b094
23 changed files with 422 additions and 123 deletions
|
@ -1508,7 +1508,7 @@ enum item_ {
|
|||
item_impl(~[ty_param],
|
||||
Option<@trait_ref>, /* (optional) trait this impl implements */
|
||||
@Ty, /* self */
|
||||
~[@method]),
|
||||
Option<~[@method]>),
|
||||
item_mac(mac),
|
||||
}
|
||||
|
||||
|
|
|
@ -202,11 +202,13 @@ 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) => {
|
||||
item_impl(_, _, _, ms_opt) => {
|
||||
let impl_did = ast_util::local_def(i.id);
|
||||
for ms.each |m| {
|
||||
map_method(impl_did, extend(cx, i.ident), *m,
|
||||
cx);
|
||||
for ms_opt.each |ms| {
|
||||
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, ~[f(ty)]),
|
||||
node: ast::item_impl(trait_tps, opt_trait, ty, Some(~[f(ty)])),
|
||||
vis: ast::public,
|
||||
span: span,
|
||||
}
|
||||
|
|
|
@ -248,11 +248,13 @@ 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, methods) => {
|
||||
item_impl(tps, ifce, ty, ref methods_opt) => {
|
||||
item_impl(fold_ty_params(tps, fld),
|
||||
ifce.map(|p| fold_trait_ref(*p, fld)),
|
||||
fld.fold_ty(ty),
|
||||
vec::map(methods, |x| fld.fold_method(*x)))
|
||||
option::map(methods_opt,
|
||||
|methods| vec::map(
|
||||
*methods, |x| fld.fold_method(*x))))
|
||||
}
|
||||
item_trait(tps, traits, methods) => {
|
||||
item_trait(fold_ty_params(tps, fld),
|
||||
|
|
|
@ -2603,13 +2603,20 @@ impl Parser {
|
|||
None
|
||||
};
|
||||
|
||||
let mut meths = ~[];
|
||||
self.expect(token::LBRACE);
|
||||
while !self.eat(token::RBRACE) {
|
||||
let vis = self.parse_visibility();
|
||||
meths.push(self.parse_method(vis));
|
||||
let meths_opt;
|
||||
if self.eat(token::SEMI) {
|
||||
meths_opt = None;
|
||||
} else {
|
||||
let mut meths = ~[];
|
||||
self.expect(token::LBRACE);
|
||||
while !self.eat(token::RBRACE) {
|
||||
let vis = self.parse_visibility();
|
||||
meths.push(self.parse_method(vis));
|
||||
}
|
||||
meths_opt = Some(move meths);
|
||||
}
|
||||
(ident, item_impl(tps, opt_trait, ty, meths), None)
|
||||
|
||||
(ident, item_impl(tps, opt_trait, ty, meths_opt), None)
|
||||
}
|
||||
|
||||
// Instantiates ident <i> with references to <typarams> as arguments.
|
||||
|
|
|
@ -522,7 +522,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) => {
|
||||
ast::item_impl(tps, opt_trait, ty, methods_opt) => {
|
||||
head(s, visibility_qualified(item.vis, ~"impl"));
|
||||
if tps.is_not_empty() {
|
||||
print_type_params(s, tps);
|
||||
|
@ -539,11 +539,18 @@ fn print_item(s: ps, &&item: @ast::item) {
|
|||
};
|
||||
space(s.s);
|
||||
|
||||
bopen(s);
|
||||
for methods.each |meth| {
|
||||
print_method(s, *meth);
|
||||
match methods_opt {
|
||||
None => {
|
||||
word(s.s, ~";");
|
||||
}
|
||||
Some(methods) => {
|
||||
bopen(s);
|
||||
for methods.each |meth| {
|
||||
print_method(s, *meth);
|
||||
}
|
||||
bclose(s, item.span);
|
||||
}
|
||||
}
|
||||
bclose(s, item.span);
|
||||
}
|
||||
ast::item_trait(tps, traits, methods) => {
|
||||
head(s, visibility_qualified(item.vis, ~"trait"));
|
||||
|
|
|
@ -142,14 +142,16 @@ 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) => {
|
||||
item_impl(tps, traits, ty, methods_opt) => {
|
||||
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.each |m| {
|
||||
visit_method_helper(*m, e, v)
|
||||
for methods_opt.each |methods| {
|
||||
for methods.each |m| {
|
||||
visit_method_helper(*m, e, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
item_class(struct_def, tps) => {
|
||||
|
|
|
@ -712,7 +712,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) => {
|
||||
item_impl(tps, opt_trait, ty, methods_opt) => {
|
||||
add_to_index();
|
||||
ebml_w.start_tag(tag_items_data_item);
|
||||
encode_def_id(ebml_w, local_def(item.id));
|
||||
|
@ -729,10 +729,13 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
for methods.each |m| {
|
||||
ebml_w.start_tag(tag_item_impl_method);
|
||||
ebml_w.writer.write(str::to_bytes(def_to_str(local_def(m.id))));
|
||||
ebml_w.end_tag();
|
||||
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();
|
||||
}
|
||||
}
|
||||
do opt_trait.iter() |associated_trait| {
|
||||
encode_trait_ref(ebml_w, ecx, *associated_trait)
|
||||
|
@ -742,11 +745,13 @@ 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.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_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));
|
||||
}
|
||||
}
|
||||
}
|
||||
item_trait(tps, traits, ms) => {
|
||||
|
|
|
@ -1192,7 +1192,7 @@ impl Resolver {
|
|||
visit_item(item, new_parent, visitor);
|
||||
}
|
||||
|
||||
item_impl(_, trait_ref_opt, ty, methods) => {
|
||||
item_impl(_, trait_ref_opt, ty, methods_opt) => {
|
||||
// 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.
|
||||
|
@ -1203,10 +1203,12 @@ impl Resolver {
|
|||
|
||||
// Bail out early if there are no static methods.
|
||||
let mut has_static_methods = false;
|
||||
for methods.each |method| {
|
||||
match method.self_ty.node {
|
||||
sty_static => has_static_methods = true,
|
||||
_ => {}
|
||||
for methods_opt.each |methods| {
|
||||
for methods.each |method| {
|
||||
match method.self_ty.node {
|
||||
sty_static => has_static_methods = true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1233,22 +1235,26 @@ impl Resolver {
|
|||
name_bindings.get_module());
|
||||
|
||||
// For each static method...
|
||||
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_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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3446,12 +3452,14 @@ impl Resolver {
|
|||
}
|
||||
|
||||
item_impl(type_parameters, implemented_traits, self_type,
|
||||
methods) => {
|
||||
|
||||
self.resolve_implementation(item.id, item.span,
|
||||
methods_opt) => {
|
||||
self.resolve_implementation(item.id,
|
||||
item.span,
|
||||
type_parameters,
|
||||
implemented_traits,
|
||||
self_type, methods, visitor);
|
||||
self_type,
|
||||
methods_opt,
|
||||
visitor);
|
||||
}
|
||||
|
||||
item_trait(type_parameters, traits, methods) => {
|
||||
|
@ -3876,7 +3884,7 @@ impl Resolver {
|
|||
type_parameters: ~[ty_param],
|
||||
opt_trait_reference: Option<@trait_ref>,
|
||||
self_type: @Ty,
|
||||
methods: ~[@method],
|
||||
opt_methods: Option<~[@method]>,
|
||||
visitor: ResolveVisitor) {
|
||||
// If applicable, create a rib for the type parameters.
|
||||
let outer_type_parameter_count = type_parameters.len();
|
||||
|
@ -3915,27 +3923,33 @@ impl Resolver {
|
|||
// Resolve the self type.
|
||||
self.resolve_type(self_type, 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);
|
||||
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);
|
||||
/*
|
||||
let borrowed_type_parameters = &method.tps;
|
||||
self.resolve_function(MethodRibKind(id, Provided(method.id)),
|
||||
Some(@method.decl),
|
||||
HasTypeParameters
|
||||
(borrowed_type_parameters,
|
||||
method.id,
|
||||
outer_type_parameter_count,
|
||||
NormalRibKind),
|
||||
method.body,
|
||||
HasSelfBinding(method.self_id),
|
||||
NoCaptureClause,
|
||||
visitor);
|
||||
let borrowed_type_parameters = &method.tps;
|
||||
self.resolve_function(MethodRibKind(
|
||||
id,
|
||||
Provided(method.id)),
|
||||
Some(@method.decl),
|
||||
HasTypeParameters
|
||||
(borrowed_type_parameters,
|
||||
method.id,
|
||||
outer_type_parameter_count,
|
||||
NormalRibKind),
|
||||
method.body,
|
||||
HasSelfBinding(method.self_id),
|
||||
NoCaptureClause,
|
||||
visitor);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the original trait references.
|
||||
|
|
|
@ -1798,8 +1798,17 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
|
|||
}
|
||||
}
|
||||
}
|
||||
ast::item_impl(tps, _, _, ms) => {
|
||||
meth::trans_impl(ccx, *path, item.ident, ms, tps, None, item.id);
|
||||
ast::item_impl(tps, _, _, ms_opt) => {
|
||||
match ms_opt {
|
||||
None => {
|
||||
deriving::trans_deriving_impl(ccx, *path, item.ident, tps,
|
||||
None, item.id);
|
||||
}
|
||||
Some(ms) => {
|
||||
meth::trans_impl(ccx, *path, item.ident, ms, tps, None,
|
||||
item.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::item_mod(m) => {
|
||||
trans_mod(ccx, m);
|
||||
|
|
21
src/rustc/middle/trans/deriving.rs
Normal file
21
src/rustc/middle/trans/deriving.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Translation of automatically-derived trait implementations. This handles
|
||||
// enums and structs only; other types cannot be automatically derived.
|
||||
|
||||
use middle::trans::base::get_insn_ctxt;
|
||||
use middle::trans::common::crate_ctxt;
|
||||
use syntax::ast::{ident, node_id, ty_param};
|
||||
use syntax::ast_map::path;
|
||||
|
||||
/// 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
|
||||
/// `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], _self_ty: Option<ty::t>,
|
||||
_id: node_id) {
|
||||
let _icx = ccx.insn_ctxt("deriving::trans_deriving_impl");
|
||||
if tps.len() > 0 { return; }
|
||||
|
||||
// XXX: Unimplemented.
|
||||
}
|
||||
|
|
@ -306,7 +306,8 @@ 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(_, _, _, ms), _}, _) => {
|
||||
ast_map::node_item(@{node: ast::item_impl(_, _, _, Some(ms)), _},
|
||||
_) => {
|
||||
method_from_methods(ms, name)
|
||||
}
|
||||
ast_map::node_item(@{node:
|
||||
|
|
|
@ -90,12 +90,14 @@ fn traverse_public_item(cx: ctx, item: @item) {
|
|||
traverse_inline_body(cx, blk);
|
||||
}
|
||||
}
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -374,7 +374,9 @@ type ctxt =
|
|||
lang_items: middle::lang_items::LanguageItems,
|
||||
legacy_boxed_traits: HashMap<node_id, ()>,
|
||||
provided_method_sources: HashMap<ast::def_id, ProvidedMethodSource>,
|
||||
supertraits: HashMap<ast::def_id, @~[InstantiatedTraitRef]>};
|
||||
supertraits: HashMap<ast::def_id, @~[InstantiatedTraitRef]>,
|
||||
deriving_struct_methods: HashMap<ast::def_id,
|
||||
@~[typeck::method_origin]>};
|
||||
|
||||
enum tbox_flag {
|
||||
has_params = 1,
|
||||
|
@ -901,7 +903,8 @@ fn mk_ctxt(s: session::Session,
|
|||
lang_items: move lang_items,
|
||||
legacy_boxed_traits: HashMap(),
|
||||
provided_method_sources: HashMap(),
|
||||
supertraits: HashMap()}
|
||||
supertraits: HashMap(),
|
||||
deriving_struct_methods: HashMap()}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -334,6 +334,7 @@ fn check_crate(tcx: ty::ctxt,
|
|||
tcx: tcx});
|
||||
collect::collect_item_types(ccx, crate);
|
||||
coherence::check_coherence(ccx, crate);
|
||||
deriving::check_deriving(ccx, crate);
|
||||
|
||||
check::check_item_types(ccx, crate);
|
||||
check_for_main_fn(ccx);
|
||||
|
|
|
@ -489,13 +489,15 @@ 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) => {
|
||||
ast::item_impl(_, _, ty, ms_opt) => {
|
||||
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.each |m| {
|
||||
check_method(ccx, *m, self_ty, local_def(it.id));
|
||||
for ms_opt.each |ms| {
|
||||
for ms.each |m| {
|
||||
check_method(ccx, *m, self_ty, local_def(it.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::item_trait(_, _, trait_methods) => {
|
||||
|
|
|
@ -591,6 +591,32 @@ impl CoherenceChecker {
|
|||
return trait_id;
|
||||
}
|
||||
|
||||
fn add_automatically_derived_methods_from_trait(
|
||||
all_methods: &mut ~[@MethodInfo], trait_did: def_id, self_ty: ty::t) {
|
||||
let tcx = self.crate_context.tcx;
|
||||
for (*ty::trait_methods(tcx, trait_did)).each |method| {
|
||||
// Generate a def ID for each node.
|
||||
let new_def_id = local_def(tcx.sess.next_node_id());
|
||||
all_methods.push(@{
|
||||
did: new_def_id,
|
||||
n_tps: method.tps.len(),
|
||||
ident: method.ident,
|
||||
self_type: method.self_ty
|
||||
});
|
||||
|
||||
// Additionally, generate the type for the derived method and add
|
||||
// it to the type cache.
|
||||
//
|
||||
// XXX: Handle generics correctly.
|
||||
let substs = { self_r: None, self_ty: Some(self_ty), tps: ~[] };
|
||||
tcx.tcache.insert(new_def_id, {
|
||||
bounds: @~[],
|
||||
region_param: None,
|
||||
ty: ty::subst(tcx, &substs, ty::mk_fn(tcx, method.fty))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Converts an implementation in the AST to an Impl structure.
|
||||
fn create_impl_from_item(item: @item) -> @Impl {
|
||||
fn add_provided_methods(all_methods: &mut ~[@MethodInfo],
|
||||
|
@ -605,11 +631,29 @@ impl CoherenceChecker {
|
|||
}
|
||||
|
||||
match item.node {
|
||||
item_impl(_, trait_refs, _, ast_methods) => {
|
||||
item_impl(_, trait_refs, _, ast_methods_opt) => {
|
||||
let mut methods = ~[];
|
||||
|
||||
for ast_methods.each |ast_method| {
|
||||
methods.push(method_to_MethodInfo(*ast_method));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For each trait that the impl implements, see what
|
||||
|
@ -617,7 +661,6 @@ impl CoherenceChecker {
|
|||
// if a method of that name is not inherent to the
|
||||
// impl, use the provided definition in the trait.
|
||||
for trait_refs.each |trait_ref| {
|
||||
|
||||
let trait_did =
|
||||
self.trait_ref_to_trait_def_id(*trait_ref);
|
||||
|
||||
|
|
|
@ -463,7 +463,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) => {
|
||||
ast::item_impl(tps, trait_ref, selfty, ms_opt) => {
|
||||
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);
|
||||
|
@ -472,9 +472,11 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
|
|||
region_param: rp,
|
||||
ty: selfty});
|
||||
|
||||
let cms = convert_methods(ccx, ms, rp, i_bounds);
|
||||
for trait_ref.each |t| {
|
||||
check_methods_against_trait(ccx, tps, rp, selfty, *t, cms);
|
||||
for ms_opt.each |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);
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::item_trait(tps, supertraits, trait_methods) => {
|
||||
|
|
158
src/rustc/middle/typeck/deriving.rs
Normal file
158
src/rustc/middle/typeck/deriving.rs
Normal file
|
@ -0,0 +1,158 @@
|
|||
// Deriving phase
|
||||
//
|
||||
// The purpose of the deriving phase of typechecking is to ensure that, for
|
||||
// each automatically derived implementation of an automatically-derivable
|
||||
// trait (for example, Eq), all the subcomponents of the type in question
|
||||
// also implement the trait. This phase runs after coherence.
|
||||
|
||||
use syntax::ast::crate;
|
||||
use syntax::ast::{def_id, ident};
|
||||
use syntax::ast::item_impl;
|
||||
use syntax::ast::node_id;
|
||||
use syntax::ast::self_ty_;
|
||||
use syntax::ast::trait_ref;
|
||||
use syntax::ast_util::def_id_of_def;
|
||||
use syntax::codemap::span;
|
||||
use syntax::print::pprust;
|
||||
use syntax::visit::{default_simple_visitor, mk_simple_visitor, visit_crate};
|
||||
use middle::resolve::{Impl, MethodInfo};
|
||||
use middle::ty;
|
||||
use middle::ty::{substs, ty_class, ty_enum, ty_param_bounds_and_ty};
|
||||
use /*middle::typeck::*/check::method;
|
||||
use /*middle::typeck::*/infer::infer_ctxt;
|
||||
|
||||
struct DerivingChecker {
|
||||
crate_context: @crate_ctxt,
|
||||
inference_context: infer_ctxt
|
||||
}
|
||||
|
||||
fn DerivingChecker_new(crate_context: @crate_ctxt) -> DerivingChecker {
|
||||
DerivingChecker {
|
||||
crate_context: crate_context,
|
||||
inference_context: infer::new_infer_ctxt(crate_context.tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl DerivingChecker {
|
||||
/// Matches one substructure type against an implementation.
|
||||
fn match_impl_method(impl_info: @Impl,
|
||||
substructure_type: ty::t,
|
||||
method_info: @MethodInfo) -> bool {
|
||||
// XXX: Generics and regions are not handled properly.
|
||||
let tcx = self.crate_context.tcx;
|
||||
let impl_self_ty = ty::lookup_item_type(tcx, impl_info.did).ty;
|
||||
let transformed_type = method::transform_self_type_for_method(
|
||||
tcx, None, impl_self_ty, method_info.self_type);
|
||||
return infer::can_mk_subty(self.inference_context,
|
||||
substructure_type,
|
||||
transformed_type).is_ok();
|
||||
}
|
||||
|
||||
fn check_deriving_for_substructure_type(substructure_type: ty::t,
|
||||
trait_ref: @trait_ref,
|
||||
impl_span: span) ->
|
||||
Option<def_id> {
|
||||
let tcx = self.crate_context.tcx;
|
||||
let sess = tcx.sess;
|
||||
let coherence_info = self.crate_context.coherence_info;
|
||||
let trait_id = def_id_of_def(tcx.def_map.get(trait_ref.ref_id));
|
||||
match coherence_info.extension_methods.find(trait_id) {
|
||||
None => {
|
||||
sess.span_bug(impl_span, ~"no extension method info found \
|
||||
for this trait");
|
||||
}
|
||||
Some(impls) => {
|
||||
// Try to unify each of these impls with the substructure
|
||||
// type.
|
||||
for impls.each |impl_info| {
|
||||
for impl_info.methods.each |method_info| {
|
||||
if self.match_impl_method(*impl_info,
|
||||
substructure_type,
|
||||
*method_info) {
|
||||
return Some(method_info.did);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
fn check_deriving_for_struct(struct_def_id: def_id,
|
||||
struct_substs: &substs,
|
||||
trait_ref: @trait_ref,
|
||||
impl_id: node_id,
|
||||
impl_span: span) {
|
||||
let tcx = self.crate_context.tcx;
|
||||
let field_info = dvec::DVec();
|
||||
for ty::lookup_class_fields(tcx, struct_def_id).each |field| {
|
||||
let field_type = ty::lookup_field_type(
|
||||
tcx, struct_def_id, field.id, struct_substs);
|
||||
match self.check_deriving_for_substructure_type(field_type,
|
||||
trait_ref,
|
||||
impl_span) {
|
||||
Some(method_target_def_id) => {
|
||||
field_info.push(method_static(method_target_def_id));
|
||||
}
|
||||
None => {
|
||||
let trait_str = pprust::path_to_str(
|
||||
trait_ref.path, tcx.sess.parse_sess.interner);
|
||||
tcx.sess.span_err(impl_span,
|
||||
fmt!("cannot automatically derive an \
|
||||
implementation for `%s`: field \
|
||||
`%s` does not implement the \
|
||||
trait `%s`",
|
||||
trait_str,
|
||||
tcx.sess.str_of(field.ident),
|
||||
trait_str));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let field_info = @dvec::unwrap(move field_info);
|
||||
tcx.deriving_struct_methods.insert(local_def(impl_id), field_info);
|
||||
}
|
||||
|
||||
fn check_deriving(crate: @crate) {
|
||||
let tcx = self.crate_context.tcx;
|
||||
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, _substs) => {
|
||||
// XXX: Handle enums.
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
..*default_simple_visitor()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_deriving(crate_context: @crate_ctxt, crate: @crate) {
|
||||
let deriving_checker = @DerivingChecker_new(crate_context);
|
||||
deriving_checker.check_deriving(crate);
|
||||
}
|
||||
|
|
@ -89,6 +89,7 @@ mod middle {
|
|||
#[legacy_exports]
|
||||
mod reachable;
|
||||
mod machine;
|
||||
mod deriving;
|
||||
}
|
||||
#[legacy_exports]
|
||||
mod ty;
|
||||
|
@ -146,6 +147,7 @@ mod middle {
|
|||
mod collect;
|
||||
#[legacy_exports]
|
||||
mod coherence;
|
||||
mod deriving;
|
||||
}
|
||||
#[legacy_exports]
|
||||
mod check_loop;
|
||||
|
|
|
@ -221,11 +221,17 @@ fn merge_method_attrs(
|
|||
})
|
||||
}
|
||||
ast_map::node_item(@{
|
||||
node: ast::item_impl(_, _, _, methods), _
|
||||
node: ast::item_impl(_, _, _, methods_opt), _
|
||||
}, _) => {
|
||||
vec::map(methods, |method| {
|
||||
(to_str(method.ident), attr_parser::parse_desc(method.attrs))
|
||||
})
|
||||
match methods_opt {
|
||||
None => ~[],
|
||||
Some(methods) => {
|
||||
vec::map(methods, |method| {
|
||||
(to_str(method.ident),
|
||||
attr_parser::parse_desc(method.attrs))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => fail ~"unexpected item"
|
||||
}
|
||||
|
|
|
@ -258,20 +258,25 @@ fn should_extract_trait_methods() {
|
|||
|
||||
fn impldoc_from_impl(
|
||||
itemdoc: doc::ItemDoc,
|
||||
methods: ~[@ast::method]
|
||||
methods_opt: Option<~[@ast::method]>
|
||||
) -> doc::ImplDoc {
|
||||
{
|
||||
item: itemdoc,
|
||||
trait_types: ~[],
|
||||
self_ty: None,
|
||||
methods: do vec::map(methods) |method| {
|
||||
{
|
||||
name: to_str(method.ident),
|
||||
brief: None,
|
||||
desc: None,
|
||||
sections: ~[],
|
||||
sig: None,
|
||||
implementation: doc::Provided,
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -207,20 +207,25 @@ fn get_method_sig(
|
|||
}
|
||||
}
|
||||
ast_map::node_item(@{
|
||||
node: ast::item_impl(_, _, _, methods), _
|
||||
node: ast::item_impl(_, _, _, methods_opt), _
|
||||
}, _) => {
|
||||
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()
|
||||
))
|
||||
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"
|
||||
}
|
||||
}
|
||||
None => fail ~"method not found"
|
||||
}
|
||||
}
|
||||
_ => fail ~"get_method_sig: item ID not bound to trait or impl"
|
||||
|
|
Loading…
Add table
Reference in a new issue