Skip to content

Commit 84bed97

Browse files
committed
auto merge of #7091 : msullivan/rust/default-methods, r=graydon
r? @nikomatsakis
2 parents 26a5c97 + 36e3d64 commit 84bed97

File tree

8 files changed

+109
-125
lines changed

8 files changed

+109
-125
lines changed

Diff for: src/librustc/middle/trans/base.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -506,9 +506,11 @@ pub fn get_res_dtor(ccx: @CrateContext,
506506
did
507507
};
508508
assert_eq!(did.crate, ast::local_crate);
509+
let tsubsts = ty::substs { self_r: None, self_ty: None,
510+
tps: /*bad*/ substs.to_owned() };
509511
let (val, _) = monomorphize::monomorphic_fn(ccx,
510512
did,
511-
substs,
513+
&tsubsts,
512514
None,
513515
None,
514516
None);

Diff for: src/librustc/middle/trans/callee.rs

+71-6
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use middle::trans::meth;
4141
use middle::trans::monomorphize;
4242
use middle::trans::type_of;
4343
use middle::ty;
44+
use middle::subst::Subst;
4445
use middle::typeck;
4546
use util::ppaux::Repr;
4647

@@ -230,11 +231,75 @@ pub fn trans_fn_ref_with_vtables(
230231
// Polytype of the function item (may have type params)
231232
let fn_tpt = ty::lookup_item_type(tcx, def_id);
232233

233-
// Modify the def_id if this is a default method; we want to be
234-
// monomorphizing the trait's code.
235-
let (def_id, opt_impl_did) = match tcx.provided_method_sources.find(&def_id) {
236-
None => (def_id, None),
237-
Some(source) => (source.method_id, Some(source.impl_id))
234+
let substs = ty::substs { self_r: None, self_ty: None,
235+
tps: /*bad*/ type_params.to_owned() };
236+
237+
238+
// We need to do a bunch of special handling for default methods.
239+
// We need to modify the def_id and our substs in order to monomorphize
240+
// the function.
241+
let (def_id, opt_impl_did, substs) = match tcx.provided_method_sources.find(&def_id) {
242+
None => (def_id, None, substs),
243+
Some(source) => {
244+
// There are two relevant substitutions when compiling
245+
// default methods. First, there is the substitution for
246+
// the type parameters of the impl we are using and the
247+
// method we are calling. This substitution is the substs
248+
// argument we already have.
249+
// In order to compile a default method, though, we need
250+
// to consider another substitution: the substitution for
251+
// the type parameters on trait; the impl we are using
252+
// implements the trait at some particular type
253+
// parameters, and we need to substitute for those first.
254+
// So, what we need to do is find this substitution and
255+
// compose it with the one we already have.
256+
257+
// In order to find the substitution for the trait params,
258+
// we look up the impl in the ast map, find its trait_ref
259+
// id, then look up its trait ref. I feel like there
260+
// should be a better way.
261+
let map_node = session::expect(
262+
ccx.sess,
263+
ccx.tcx.items.find_copy(&source.impl_id.node),
264+
|| fmt!("couldn't find node while monomorphizing \
265+
default method: %?", source.impl_id.node));
266+
let item = match map_node {
267+
ast_map::node_item(item, _) => item,
268+
_ => ccx.tcx.sess.bug("Not an item")
269+
};
270+
let ast_trait_ref = match copy item.node {
271+
ast::item_impl(_, Some(tr), _, _) => tr,
272+
_ => ccx.tcx.sess.bug("Not an impl with trait_ref")
273+
};
274+
let trait_ref = ccx.tcx.trait_refs.get(&ast_trait_ref.ref_id);
275+
276+
// The substs from the trait_ref only substitues for the
277+
// trait parameters. Our substitution also needs to be
278+
// able to substitute for the actual method type
279+
// params. To do this, we figure out how many method
280+
// parameters there are and pad out the substitution with
281+
// substitution for the variables.
282+
let item_ty = ty::lookup_item_type(tcx, source.method_id);
283+
let num_params = item_ty.generics.type_param_defs.len() -
284+
trait_ref.substs.tps.len();
285+
let id_subst = do vec::from_fn(num_params) |i| {
286+
ty::mk_param(tcx, i, ast::def_id {crate: 0, node: 0})
287+
};
288+
// Merge the two substitions together now.
289+
let first_subst = ty::substs {tps: trait_ref.substs.tps + id_subst,
290+
.. trait_ref.substs};
291+
292+
// And compose them.
293+
let new_substs = first_subst.subst(tcx, &substs);
294+
debug!("trans_fn_with_vtables - default method: \
295+
substs = %s, id_subst = %s, trait_subst = %s, \
296+
first_subst = %s, new_subst = %s",
297+
substs.repr(tcx),
298+
id_subst.repr(tcx), trait_ref.substs.repr(tcx),
299+
first_subst.repr(tcx), new_substs.repr(tcx));
300+
301+
(source.method_id, Some(source.impl_id), new_substs)
302+
}
238303
};
239304

240305
// Check whether this fn has an inlined copy and, if so, redirect
@@ -279,7 +344,7 @@ pub fn trans_fn_ref_with_vtables(
279344
assert_eq!(def_id.crate, ast::local_crate);
280345

281346
let mut (val, must_cast) =
282-
monomorphize::monomorphic_fn(ccx, def_id, type_params,
347+
monomorphize::monomorphic_fn(ccx, def_id, &substs,
283348
vtables, opt_impl_did, Some(ref_id));
284349
if must_cast && ref_id != 0 {
285350
// Monotype of the REFERENCE to the function (type params

Diff for: src/librustc/middle/trans/meth.rs

+22-47
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,9 @@ pub fn trans_method_callee(bcx: block,
207207
let method_name =
208208
ty::trait_method(tcx, trait_id, method_index).ident;
209209
let method_id =
210-
method_with_name(bcx.ccx(), impl_def_id, method_name);
210+
method_with_name_or_default(bcx.ccx(),
211+
impl_def_id,
212+
method_name);
211213
origin = typeck::method_static(method_id);
212214
}
213215
typeck::method_super(trait_id, method_index) => {
@@ -229,9 +231,10 @@ pub fn trans_method_callee(bcx: block,
229231
ty::method(tcx, supertrait_method_def_ids[method_index]).ident;
230232
// Now that we know the impl ID, we can look up the method
231233
// ID from its name
232-
origin = typeck::method_static(method_with_name(bcx.ccx(),
233-
impl_id,
234-
method_name));
234+
origin = typeck::method_static(
235+
method_with_name_or_default(bcx.ccx(),
236+
impl_id,
237+
method_name));
235238
}
236239
typeck::method_static(*) | typeck::method_param(*) |
237240
typeck::method_trait(*) => {}
@@ -345,7 +348,9 @@ pub fn trans_static_method_callee(bcx: block,
345348
typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => {
346349
assert!(rcvr_substs.all(|t| !ty::type_needs_infer(*t)));
347350

348-
let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
351+
let mth_id = method_with_name_or_default(bcx.ccx(),
352+
impl_did,
353+
mname);
349354
let callee_substs = combine_impl_and_methods_tps(
350355
bcx, mth_id, impl_did, callee_id, *rcvr_substs);
351356
let callee_origins = combine_impl_and_methods_origins(
@@ -374,23 +379,6 @@ pub fn method_from_methods(ms: &[@ast::method], name: ast::ident)
374379
ms.find(|m| m.ident == name).map(|m| ast_util::local_def(m.id))
375380
}
376381

377-
pub fn method_with_name(ccx: @CrateContext, impl_id: ast::def_id,
378-
name: ast::ident) -> ast::def_id {
379-
if impl_id.crate == ast::local_crate {
380-
match ccx.tcx.items.get_copy(&impl_id.node) {
381-
ast_map::node_item(@ast::item {
382-
node: ast::item_impl(_, _, _, ref ms),
383-
_
384-
}, _) => {
385-
method_from_methods(*ms, name).get()
386-
}
387-
_ => fail!("method_with_name")
388-
}
389-
} else {
390-
csearch::get_impl_method(ccx.sess.cstore, impl_id, name)
391-
}
392-
}
393-
394382
pub fn method_with_name_or_default(ccx: @CrateContext,
395383
impl_id: ast::def_id,
396384
name: ast::ident) -> ast::def_id {
@@ -770,17 +758,17 @@ pub fn vtable_id(ccx: @CrateContext,
770758

771759
/// Creates a returns a dynamic vtable for the given type and vtable origin.
772760
/// This is used only for objects.
773-
pub fn get_vtable(ccx: @CrateContext,
761+
pub fn get_vtable(bcx: block,
774762
self_ty: ty::t,
775763
origin: typeck::vtable_origin)
776764
-> ValueRef {
777-
let hash_id = vtable_id(ccx, &origin);
778-
match ccx.vtables.find(&hash_id) {
765+
let hash_id = vtable_id(bcx.ccx(), &origin);
766+
match bcx.ccx().vtables.find(&hash_id) {
779767
Some(&val) => val,
780768
None => {
781769
match origin {
782770
typeck::vtable_static(id, substs, sub_vtables) => {
783-
make_impl_vtable(ccx, id, self_ty, substs, sub_vtables)
771+
make_impl_vtable(bcx, id, self_ty, substs, sub_vtables)
784772
}
785773
_ => fail!("get_vtable: expected a static origin"),
786774
}
@@ -814,12 +802,13 @@ pub fn make_vtable(ccx: @CrateContext,
814802
}
815803

816804
/// Generates a dynamic vtable for objects.
817-
pub fn make_impl_vtable(ccx: @CrateContext,
805+
pub fn make_impl_vtable(bcx: block,
818806
impl_id: ast::def_id,
819807
self_ty: ty::t,
820808
substs: ~[ty::t],
821809
vtables: typeck::vtable_res)
822810
-> ValueRef {
811+
let ccx = bcx.ccx();
823812
let _icx = ccx.insn_ctxt("impl::make_impl_vtable");
824813
let tcx = ccx.tcx;
825814

@@ -829,9 +818,6 @@ pub fn make_impl_vtable(ccx: @CrateContext,
829818
make a vtable for a type impl!")
830819
};
831820

832-
let has_tps =
833-
!ty::lookup_item_type(ccx.tcx, impl_id).generics.type_param_defs.is_empty();
834-
835821
let trait_method_def_ids = ty::trait_method_def_ids(tcx, trt_id);
836822
let methods = do trait_method_def_ids.map |method_def_id| {
837823
let im = ty::method(tcx, *method_def_id);
@@ -846,22 +832,11 @@ pub fn make_impl_vtable(ccx: @CrateContext,
846832
} else {
847833
debug!("(making impl vtable) adding method to vtable: %s",
848834
*tcx.sess.str_of(im.ident));
849-
let mut m_id = method_with_name(ccx, impl_id, im.ident);
850-
if has_tps {
851-
// If the method is in another crate, need to make an inlined
852-
// copy first
853-
if m_id.crate != ast::local_crate {
854-
// XXX: Set impl ID here?
855-
m_id = inline::maybe_instantiate_inline(ccx, m_id, true);
856-
}
857-
let (val, _) = monomorphize::monomorphic_fn(ccx, m_id, substs,
858-
Some(vtables), None, None);
859-
val
860-
} else if m_id.crate == ast::local_crate {
861-
get_item_val(ccx, m_id.node)
862-
} else {
863-
trans_external_path(ccx, m_id, fty)
864-
}
835+
let m_id = method_with_name_or_default(ccx, impl_id, im.ident);
836+
837+
trans_fn_ref_with_vtables(bcx, m_id, 0,
838+
substs, Some(vtables)).llfn
839+
865840
}
866841
};
867842

@@ -903,7 +878,7 @@ pub fn trans_trait_cast(bcx: block,
903878
// Store the vtable into the pair or triple.
904879
let orig = /*bad*/copy ccx.maps.vtable_map.get(&id)[0];
905880
let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig);
906-
let vtable = get_vtable(bcx.ccx(), v_ty, orig);
881+
let vtable = get_vtable(bcx, v_ty, orig);
907882
Store(bcx, vtable, PointerCast(bcx,
908883
GEPi(bcx, lldest, [0u, abi::trt_field_vtable]),
909884
T_ptr(val_ty(vtable))));

Diff for: src/librustc/middle/trans/monomorphize.rs

+7-16
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use syntax::abi::AbiSet;
4343

4444
pub fn monomorphic_fn(ccx: @CrateContext,
4545
fn_id: ast::def_id,
46-
real_substs: &[ty::t],
46+
real_substs: &ty::substs,
4747
vtables: Option<typeck::vtable_res>,
4848
impl_did_opt: Option<ast::def_id>,
4949
ref_id: Option<ast::node_id>)
@@ -61,17 +61,17 @@ pub fn monomorphic_fn(ccx: @CrateContext,
6161
impl_did_opt.repr(ccx.tcx),
6262
ref_id);
6363

64-
assert!(real_substs.all(|t| !ty::type_needs_infer(*t)));
64+
assert!(real_substs.tps.all(|t| !ty::type_needs_infer(*t)));
6565
let _icx = ccx.insn_ctxt("monomorphic_fn");
6666
let mut must_cast = false;
67-
let substs = vec::map(real_substs, |t| {
67+
let substs = vec::map(real_substs.tps, |t| {
6868
match normalize_for_monomorphization(ccx.tcx, *t) {
6969
Some(t) => { must_cast = true; t }
7070
None => *t
7171
}
7272
});
7373

74-
for real_substs.each() |s| { assert!(!ty::type_has_params(*s)); }
74+
for real_substs.tps.each() |s| { assert!(!ty::type_has_params(*s)); }
7575
for substs.each() |s| { assert!(!ty::type_has_params(*s)); }
7676
let param_uses = type_use::type_uses_for(ccx, fn_id, substs.len());
7777
let hash_id = make_mono_id(ccx, fn_id, substs, vtables, impl_did_opt,
@@ -145,17 +145,8 @@ pub fn monomorphic_fn(ccx: @CrateContext,
145145
ast_map::node_struct_ctor(_, i, pt) => (pt, i.ident, i.span)
146146
};
147147

148-
// Look up the impl type if we're translating a default method.
149-
// XXX: Generics.
150-
let impl_ty_opt;
151-
match impl_did_opt {
152-
None => impl_ty_opt = None,
153-
Some(impl_did) => {
154-
impl_ty_opt = Some(ty::lookup_item_type(ccx.tcx, impl_did).ty);
155-
}
156-
}
157-
158-
let mono_ty = ty::subst_tps(ccx.tcx, substs, impl_ty_opt, llitem_ty);
148+
let mono_ty = ty::subst_tps(ccx.tcx, substs,
149+
real_substs.self_ty, llitem_ty);
159150
let llfty = type_of_fn_from_ty(ccx, mono_ty);
160151

161152
ccx.stats.n_monos += 1;
@@ -186,7 +177,7 @@ pub fn monomorphic_fn(ccx: @CrateContext,
186177
tys: substs,
187178
vtables: vtables,
188179
type_param_defs: tpt.generics.type_param_defs,
189-
self_ty: impl_ty_opt
180+
self_ty: real_substs.self_ty
190181
});
191182

192183
let lldecl = match map_node {

Diff for: src/librustc/middle/typeck/check/method.rs

+2-49
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ impl<'self> LookupContext<'self> {
192192

193193
// Prepare the list of candidates
194194
self.push_inherent_candidates(self_ty);
195-
self.push_extension_candidates(self_ty);
195+
self.push_extension_candidates();
196196

197197
let mut enum_dids = ~[];
198198
let mut self_ty = self_ty;
@@ -326,7 +326,7 @@ impl<'self> LookupContext<'self> {
326326
}
327327
}
328328

329-
pub fn push_extension_candidates(&self, self_ty: ty::t) {
329+
pub fn push_extension_candidates(&self) {
330330
// If the method being called is associated with a trait, then
331331
// find all the impls of that trait. Each of those are
332332
// candidates.
@@ -343,17 +343,8 @@ impl<'self> LookupContext<'self> {
343343
for impl_infos.each |impl_info| {
344344
self.push_candidates_from_impl(
345345
self.extension_candidates, *impl_info);
346-
}
347-
}
348346

349-
// Look for default methods.
350-
match self.tcx().provided_methods.find(trait_did) {
351-
Some(&methods) => {
352-
self.push_candidates_from_provided_methods(
353-
self.extension_candidates, self_ty, *trait_did,
354-
methods);
355347
}
356-
None => {}
357348
}
358349
}
359350
}
@@ -580,44 +571,6 @@ impl<'self> LookupContext<'self> {
580571
});
581572
}
582573

583-
pub fn push_candidates_from_provided_methods(&self,
584-
candidates:
585-
&mut ~[Candidate],
586-
self_ty: ty::t,
587-
trait_def_id: def_id,
588-
methods:
589-
&mut ~[@ProvidedMethodInfo])
590-
{
591-
debug!("(pushing candidates from provided methods) considering trait \
592-
id %d:%d",
593-
trait_def_id.crate,
594-
trait_def_id.node);
595-
596-
for methods.each |provided_method_info| {
597-
if provided_method_info.method_info.ident != self.m_name { loop; }
598-
599-
debug!("(pushing candidates from provided methods) adding \
600-
candidate");
601-
602-
let method = ty::method(self.tcx(),
603-
provided_method_info.method_info.did);
604-
605-
// FIXME #4099 (?) Needs to support generics.
606-
let dummy_substs = substs {
607-
self_r: None,
608-
self_ty: None,
609-
tps: ~[]
610-
};
611-
612-
candidates.push(Candidate {
613-
rcvr_ty: self_ty,
614-
rcvr_substs: dummy_substs,
615-
method_ty: method,
616-
origin: method_static(provided_method_info.method_info.did)
617-
});
618-
}
619-
}
620-
621574
// ______________________________________________________________________
622575
// Candidate selection (see comment at start of file)
623576

0 commit comments

Comments
 (0)