Skip to content

Commit e75ec80

Browse files
committed
Improve vtable resolution.
Improve vtable resolution in a handful of ways. First, if we don't find a vtable for a self/param type, do a regular vtable search. This could find impls of the form "impl for A". Second, we don't require that types be fully resolved before looking up subtables, and we process tables in reverse order. This allows us to gain more information about early type parameters based on how they are used by the impls used to resolve later params. Closes #6967, I believe.
1 parent fbbbc98 commit e75ec80

File tree

1 file changed

+46
-24
lines changed

1 file changed

+46
-24
lines changed

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

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ use syntax::visit;
4545
// *fully* resolved. (We could be less restrictive than that, but it
4646
// would require much more care, and this seems to work decently in
4747
// practice.)
48+
//
49+
// While resolution on a single type requires the type to be fully
50+
// resolved, when resolving a substitution against a list of bounds,
51+
// we do not require all of the types to be resolved in advance.
52+
// Furthermore, we process substitutions in reverse order, which
53+
// allows resolution on later parameters to give information on
54+
// earlier params referenced by the typeclass bounds.
55+
// It may be better to do something more clever, like processing fully
56+
// resolved types first.
57+
4858

4959
/// Location info records the span and ID of the expression or item that is
5060
/// responsible for this vtable instantiation. (This may not be an expression
@@ -83,11 +93,19 @@ fn lookup_vtables(vcx: &VtableContext,
8393
substs.repr(vcx.tcx()));
8494
let _i = indenter();
8595

86-
let mut result = ~[];
87-
for substs.tps.iter().zip(type_param_defs.iter()).advance |(ty, def)| {
88-
result.push(lookup_vtables_for_param(vcx, location_info, Some(substs),
89-
&*def.bounds, *ty, is_early));
90-
}
96+
97+
// We do this backwards for reasons discussed above.
98+
assert_eq!(substs.tps.len(), type_param_defs.len());
99+
let mut result =
100+
substs.tps.rev_iter()
101+
.zip(type_param_defs.rev_iter())
102+
.transform(|(ty, def)|
103+
lookup_vtables_for_param(vcx, location_info, Some(substs),
104+
&*def.bounds, *ty, is_early))
105+
.to_owned_vec();
106+
result.reverse();
107+
108+
assert_eq!(substs.tps.len(), result.len());
91109
debug!("lookup_vtables result(\
92110
location_info=%?, \
93111
type_param_defs=%s, \
@@ -198,8 +216,7 @@ fn relate_trait_refs(vcx: &VtableContext,
198216
}
199217
}
200218

201-
// Look up the vtable to use when treating an item of type `t` as if it has
202-
// type `trait_ty`
219+
// Look up the vtable implementing the trait `trait_ref` at type `t`
203220
fn lookup_vtable(vcx: &VtableContext,
204221
location_info: &LocationInfo,
205222
ty: ty::t,
@@ -261,13 +278,14 @@ fn lookup_vtable(vcx: &VtableContext,
261278
}
262279
}
263280

264-
_ => {
265-
return search_for_vtable(vcx, location_info,
266-
ty, trait_ref, is_early)
267-
}
281+
// Default case just falls through
282+
_ => { }
268283
}
269284

270-
return None;
285+
// If we aren't a self type or param, or it was, but we didn't find it,
286+
// do a search.
287+
return search_for_vtable(vcx, location_info,
288+
ty, trait_ref, is_early)
271289
}
272290

273291
fn search_for_vtable(vcx: &VtableContext,
@@ -359,16 +377,23 @@ fn search_for_vtable(vcx: &VtableContext,
359377
let of_trait_ref = of_trait_ref.subst(tcx, &substs);
360378
relate_trait_refs(vcx, location_info, of_trait_ref, trait_ref);
361379

380+
362381
// Recall that trait_ref -- the trait type we're casting to --
363382
// is the trait with id trait_ref.def_id applied to the substs
364-
// trait_ref.substs. Now we extract out the types themselves
365-
// from trait_ref.substs.
383+
// trait_ref.substs.
384+
385+
// Resolve any sub bounds. Note that there still may be free
386+
// type variables in substs. This might still be OK: the
387+
// process of looking up bounds might constrain some of them.
388+
let im_generics =
389+
ty::lookup_item_type(tcx, im.did).generics;
390+
let subres = lookup_vtables(vcx, location_info,
391+
*im_generics.type_param_defs, &substs,
392+
is_early);
366393

367-
// Recall that substs is the impl self type's list of
368-
// substitutions. That is, if this is an impl of some trait
369-
// for foo<T, U>, then substs is [T, U]. substs might contain
370-
// type variables, so we call fixup_substs to resolve them.
371394

395+
// substs might contain type variables, so we call
396+
// fixup_substs to resolve them.
372397
let substs_f = match fixup_substs(vcx,
373398
location_info,
374399
trait_ref.def_id,
@@ -392,13 +417,10 @@ fn search_for_vtable(vcx: &VtableContext,
392417
// ty with the substitutions from the trait type that we're
393418
// trying to cast to. connect_trait_tps requires these lists
394419
// of types to unify pairwise.
395-
396-
let im_generics =
397-
ty::lookup_item_type(tcx, im.did).generics;
420+
// I am a little confused about this, since it seems to be
421+
// very similar to the relate_trait_refs we already do,
422+
// but problems crop up if it is removed, so... -sully
398423
connect_trait_tps(vcx, location_info, &substs_f, trait_ref, im.did);
399-
let subres = lookup_vtables(vcx, location_info,
400-
*im_generics.type_param_defs, &substs_f,
401-
is_early);
402424

403425
// Finally, we register that we found a matching impl, and
404426
// record the def ID of the impl as well as the resolved list

0 commit comments

Comments
 (0)