Skip to content

Commit 36e3d64

Browse files
committed
Fix a lot of the handling of default methods and type parameters. Closes #4099, #4102.
1 parent 5835158 commit 36e3d64

File tree

5 files changed

+84
-26
lines changed

5 files changed

+84
-26
lines changed

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);

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

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 {

src/test/run-pass/trait-default-method-bound-subst.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// xfail-test
11+
#[allow(default_methods)];
1212

1313
trait A<T> {
14-
fn g<U>(x: T, y: U) -> (T, U) { (x, y) }
14+
fn g<U>(&self, x: T, y: U) -> (T, U) { (x, y) }
1515
}
1616

1717
impl A<int> for int { }

src/test/run-pass/trait-default-method-bound-subst2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// xfail-test
11+
#[allow(default_methods)];
1212

1313
trait A<T> {
1414
fn g(&self, x: T) -> T { x }

0 commit comments

Comments
 (0)