Skip to content

Commit 1a8969f

Browse files
committed
Get cross crate default methods working.
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.
1 parent 6759ce4 commit 1a8969f

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)