Skip to content

Commit ba05af7

Browse files
committed
auto merge of #7203 : msullivan/rust/default-methods, r=graydon
This fixes the large number of problems that prevented cross crate methods from ever working. It also fixes a couple lingering bugs with polymorphic default methods and cleans up some of the code paths. Closes #4102. Closes #4103. r? nikomatsakis
2 parents 77ae7ec + 1a8969f commit ba05af7

File tree

10 files changed

+255
-217
lines changed

10 files changed

+255
-217
lines changed

src/librustc/metadata/csearch.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ pub fn get_impl_trait(tcx: ty::ctxt,
229229
pub fn get_impl_method(cstore: @mut cstore::CStore,
230230
def: ast::def_id,
231231
mname: ast::ident)
232-
-> ast::def_id {
232+
-> Option<ast::def_id> {
233233
let cdata = cstore::get_crate_data(cstore, def.crate);
234234
decoder::get_impl_method(cstore.intr, cdata, def.node, mname)
235235
}

src/librustc/metadata/decoder.rs

+7-34
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ pub fn get_impl_trait(cdata: cmd,
415415
}
416416

417417
pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id,
418-
name: ast::ident) -> ast::def_id {
418+
name: ast::ident) -> Option<ast::def_id> {
419419
let items = reader::get_doc(reader::Doc(cdata.data), tag_items);
420420
let mut found = None;
421421
for reader::tagged_docs(find_item(id, items), tag_item_impl_method)
@@ -425,7 +425,7 @@ pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id,
425425
found = Some(translate_def_id(cdata, m_did));
426426
}
427427
}
428-
found.get()
428+
found
429429
}
430430

431431
pub fn get_symbol(data: @~[u8], id: ast::node_id) -> ~str {
@@ -755,40 +755,13 @@ pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd,
755755
let item = lookup_item(id, data);
756756
let mut result = ~[];
757757

758-
for reader::tagged_docs(item, tag_item_trait_method) |mth| {
759-
if item_method_sort(mth) != 'p' { loop; }
760-
761-
let did = item_def_id(mth, cdata);
762-
763-
let type_param_defs =
764-
item_ty_param_defs(mth, tcx, cdata,
765-
tag_items_data_item_ty_param_bounds);
766-
let name = item_name(intr, mth);
767-
let ty = doc_type(mth, tcx, cdata);
758+
for reader::tagged_docs(item, tag_item_trait_method) |mth_id| {
759+
let did = item_def_id(mth_id, cdata);
760+
let mth = lookup_item(did.node, data);
768761

769-
let fty = match ty::get(ty).sty {
770-
ty::ty_bare_fn(ref f) => copy *f,
771-
_ => {
772-
tcx.diag.handler().bug("get_provided_trait_methods(): id \
773-
has non-function type");
774-
}
775-
};
762+
if item_method_sort(mth) != 'p' { loop; }
776763

777-
let transformed_self_ty = doc_transformed_self_ty(mth, tcx, cdata);
778-
let explicit_self = get_explicit_self(mth);
779-
780-
let ty_method = ty::Method::new(
781-
name,
782-
ty::Generics {
783-
type_param_defs: type_param_defs,
784-
region_param: None
785-
},
786-
transformed_self_ty,
787-
fty,
788-
explicit_self,
789-
ast::public,
790-
did
791-
);
764+
let ty_method = get_method(intr, cdata, did.node, tcx);
792765
let provided_trait_method_info = ProvidedTraitMethodInfo {
793766
ty: ty_method,
794767
def_id: did

src/librustc/middle/trans/callee.rs

+13-38
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use middle::trans::type_of;
4242
use middle::ty;
4343
use middle::subst::Subst;
4444
use middle::typeck;
45+
use middle::typeck::coherence::make_substs_for_receiver_types;
4546
use util::ppaux::Repr;
4647

4748
use core::vec;
@@ -253,50 +254,24 @@ pub fn trans_fn_ref_with_vtables(
253254
// So, what we need to do is find this substitution and
254255
// compose it with the one we already have.
255256

256-
// In order to find the substitution for the trait params,
257-
// we look up the impl in the ast map, find its trait_ref
258-
// id, then look up its trait ref. I feel like there
259-
// should be a better way.
260-
let map_node = session::expect(
261-
ccx.sess,
262-
ccx.tcx.items.find_copy(&source.impl_id.node),
263-
|| fmt!("couldn't find node while monomorphizing \
264-
default method: %?", source.impl_id.node));
265-
let item = match map_node {
266-
ast_map::node_item(item, _) => item,
267-
_ => ccx.tcx.sess.bug("Not an item")
268-
};
269-
let ast_trait_ref = match copy item.node {
270-
ast::item_impl(_, Some(tr), _, _) => tr,
271-
_ => ccx.tcx.sess.bug("Not an impl with trait_ref")
272-
};
273-
let trait_ref = ccx.tcx.trait_refs.get(&ast_trait_ref.ref_id);
274-
275-
// The substs from the trait_ref only substitues for the
276-
// trait parameters. Our substitution also needs to be
277-
// able to substitute for the actual method type
278-
// params. To do this, we figure out how many method
279-
// parameters there are and pad out the substitution with
280-
// substitution for the variables.
281-
let item_ty = ty::lookup_item_type(tcx, source.method_id);
282-
let num_params = item_ty.generics.type_param_defs.len() -
283-
trait_ref.substs.tps.len();
284-
let id_subst = do vec::from_fn(num_params) |i| {
285-
ty::mk_param(tcx, i, ast::def_id {crate: 0, node: 0})
286-
};
287-
// Merge the two substitions together now.
288-
let first_subst = ty::substs {tps: trait_ref.substs.tps + id_subst,
289-
.. trait_ref.substs};
257+
let trait_ref = ty::impl_trait_ref(tcx, source.impl_id)
258+
.expect("could not find trait_ref for impl with \
259+
default methods");
260+
let method = ty::method(tcx, source.method_id);
290261

291-
// And compose them.
262+
// Compute the first substitution
263+
let first_subst = make_substs_for_receiver_types(
264+
tcx, source.impl_id, trait_ref, method);
265+
266+
// And compose them
292267
let new_substs = first_subst.subst(tcx, &substs);
293268
debug!("trans_fn_with_vtables - default method: \
294-
substs = %s, id_subst = %s, trait_subst = %s, \
269+
substs = %s, trait_subst = %s, \
295270
first_subst = %s, new_subst = %s",
296-
substs.repr(tcx),
297-
id_subst.repr(tcx), trait_ref.substs.repr(tcx),
271+
substs.repr(tcx), trait_ref.substs.repr(tcx),
298272
first_subst.repr(tcx), new_substs.repr(tcx));
299273

274+
300275
(source.method_id, Some(source.impl_id), new_substs)
301276
}
302277
};

src/librustc/middle/trans/inline.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,16 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id,
9393
csearch::found(ast::ii_method(impl_did, mth)) => {
9494
ccx.stats.n_inlines += 1;
9595
ccx.external.insert(fn_id, Some(mth.id));
96-
let impl_tpt = ty::lookup_item_type(ccx.tcx, impl_did);
97-
let num_type_params =
98-
impl_tpt.generics.type_param_defs.len() +
99-
mth.generics.ty_params.len();
100-
if translate && num_type_params == 0 {
96+
// If this is a default method, we can't look up the
97+
// impl type. But we aren't going to translate anyways, so don't.
98+
if !translate { return local_def(mth.id); }
99+
100+
let impl_tpt = ty::lookup_item_type(ccx.tcx, impl_did);
101+
let num_type_params =
102+
impl_tpt.generics.type_param_defs.len() +
103+
mth.generics.ty_params.len();
104+
105+
if num_type_params == 0 {
101106
let llfn = get_item_val(ccx, mth.id);
102107
let path = vec::append(
103108
ty::item_path(ccx.tcx, impl_did),

src/librustc/middle/trans/meth.rs

+33-56
Original file line numberDiff line numberDiff line change
@@ -383,71 +383,48 @@ pub fn method_with_name_or_default(ccx: @mut CrateContext,
383383
name: ast::ident) -> ast::def_id {
384384
let imp = ccx.impl_method_cache.find_copy(&(impl_id, name));
385385
match imp {
386-
Some(m) => m,
387-
None => {
388-
let imp = if impl_id.crate == ast::local_crate {
389-
match ccx.tcx.items.get_copy(&impl_id.node) {
390-
ast_map::node_item(@ast::item {
391-
node: ast::item_impl(_, _, _, ref ms), _
392-
}, _) => {
393-
let did = method_from_methods(*ms, name);
394-
if did.is_some() {
395-
did.get()
396-
} else {
397-
// Look for a default method
398-
let pmm = ccx.tcx.provided_methods;
399-
match pmm.find(&impl_id) {
400-
Some(pmis) => {
401-
for pmis.each |pmi| {
402-
if pmi.method_info.ident == name {
403-
debug!("pmi.method_info.did = %?", pmi.method_info.did);
404-
return pmi.method_info.did;
405-
}
406-
}
407-
fail!()
408-
}
409-
None => fail!()
410-
}
411-
}
412-
}
413-
_ => fail!("method_with_name")
414-
}
415-
} else {
416-
csearch::get_impl_method(ccx.sess.cstore, impl_id, name)
417-
};
386+
Some(m) => return m,
387+
None => {}
388+
}
418389

419-
ccx.impl_method_cache.insert((impl_id, name), imp);
390+
// None of this feels like it should be the best way to do this.
391+
let mut did = if impl_id.crate == ast::local_crate {
392+
match ccx.tcx.items.get_copy(&impl_id.node) {
393+
ast_map::node_item(@ast::item {
394+
node: ast::item_impl(_, _, _, ref ms), _
395+
}, _) => { method_from_methods(*ms, name) },
396+
_ => fail!("method_with_name")
397+
}
398+
} else {
399+
csearch::get_impl_method(ccx.sess.cstore, impl_id, name)
400+
};
420401

421-
imp
402+
if did.is_none() {
403+
// Look for a default method
404+
let pmm = ccx.tcx.provided_methods;
405+
match pmm.find(&impl_id) {
406+
Some(pmis) => {
407+
for pmis.each |pmi| {
408+
if pmi.method_info.ident == name {
409+
debug!("pmi.method_info.did = %?",
410+
pmi.method_info.did);
411+
did = Some(pmi.method_info.did);
412+
}
413+
}
414+
}
415+
None => {}
422416
}
423417
}
418+
419+
let imp = did.expect("could not find method while translating");
420+
ccx.impl_method_cache.insert((impl_id, name), imp);
421+
imp
424422
}
425423

426424
pub fn method_ty_param_count(ccx: &CrateContext, m_id: ast::def_id,
427425
i_id: ast::def_id) -> uint {
428426
debug!("method_ty_param_count: m_id: %?, i_id: %?", m_id, i_id);
429-
if m_id.crate == ast::local_crate {
430-
match ccx.tcx.items.find(&m_id.node) {
431-
Some(&ast_map::node_method(m, _, _)) => m.generics.ty_params.len(),
432-
None => {
433-
match ccx.tcx.provided_method_sources.find(&m_id) {
434-
Some(source) => {
435-
method_ty_param_count(
436-
ccx, source.method_id, source.impl_id)
437-
}
438-
None => fail!()
439-
}
440-
}
441-
Some(&ast_map::node_trait_method(@ast::provided(@ref m),
442-
_, _)) => {
443-
m.generics.ty_params.len()
444-
}
445-
ref e => fail!("method_ty_param_count %?", *e)
446-
}
447-
} else {
448-
csearch::get_type_param_count(ccx.sess.cstore, m_id) -
449-
csearch::get_type_param_count(ccx.sess.cstore, i_id)
450-
}
427+
ty::method(ccx.tcx, m_id).generics.type_param_defs.len()
451428
}
452429

453430
pub fn trans_monomorphized_callee(bcx: block,

src/librustc/middle/typeck/check/method.rs

+4
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,10 @@ impl<'self> LookupContext<'self> {
541541
if !self.impl_dups.insert(impl_info.did) {
542542
return; // already visited
543543
}
544+
debug!("push_candidates_from_impl: %s %s %s",
545+
self.m_name.repr(self.tcx()),
546+
impl_info.ident.repr(self.tcx()),
547+
impl_info.methods.map(|m| m.ident).repr(self.tcx()));
544548

545549
let idx = {
546550
match impl_info.methods.position(|m| m.ident == self.m_name) {

0 commit comments

Comments
 (0)