1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use middle::ty::{AutoAddEnv, AutoDerefRef, AutoObject, param_ty};
14 use middle::ty_fold::TypeFolder;
15 use middle::typeck::astconv::AstConv;
16 use middle::typeck::check::{FnCtxt, impl_self_ty};
17 use middle::typeck::check::{structurally_resolved_type};
18 use middle::typeck::infer::fixup_err_to_str;
19 use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
20 use middle::typeck::infer;
21 use middle::typeck::{vtable_origin, vtable_res, vtable_param_res};
22 use middle::typeck::{vtable_static, vtable_param, impl_res};
23 use middle::typeck::{param_numbered, param_self, param_index};
24 use middle::typeck::MethodCall;
25 use middle::subst::Subst;
26 use util::common::indenter;
28 use util::ppaux::Repr;
31 use collections::HashSet;
34 use syntax::codemap::Span;
35 use syntax::print::pprust::expr_to_str;
37 use syntax::visit::Visitor;
39 // vtable resolution looks for places where trait bounds are
40 // substituted in and figures out which vtable is used. There is some
41 // extra complication thrown in to support early "opportunistic"
42 // vtable resolution. This is a hacky mechanism that is invoked while
43 // typechecking function calls (after typechecking non-closure
44 // arguments and before typechecking closure arguments) in the hope of
45 // solving for the trait parameters from the impl. (For example,
46 // determining that if a parameter bounded by BaseIter<A> is
47 // instantiated with Option<int>, that A = int.)
49 // In early resolution mode, no vtables are recorded, and a number of
50 // errors are ignored. Early resolution only works if a type is
51 // *fully* resolved. (We could be less restrictive than that, but it
52 // would require much more care, and this seems to work decently in
55 // While resolution on a single type requires the type to be fully
56 // resolved, when resolving a substitution against a list of bounds,
57 // we do not require all of the types to be resolved in advance.
58 // Furthermore, we process substitutions in reverse order, which
59 // allows resolution on later parameters to give information on
60 // earlier params referenced by the typeclass bounds.
61 // It may be better to do something more clever, like processing fully
62 // resolved types first.
64 /// A vtable context includes an inference context, a crate context, and a
65 /// callback function to call in case of type error.
66 pub struct VtableContext<'a> {
67 pub infcx: &'a infer::InferCtxt<'a>,
68 pub param_env: &'a ty::ParameterEnvironment,
71 impl<'a> VtableContext<'a> {
72 pub fn tcx(&self) -> &'a ty::ctxt { self.infcx.tcx }
75 fn has_trait_bounds(type_param_defs: &[ty::TypeParameterDef]) -> bool {
76 type_param_defs.iter().any(
77 |type_param_def| !type_param_def.bounds.trait_bounds.is_empty())
80 fn lookup_vtables(vcx: &VtableContext,
82 type_param_defs: &[ty::TypeParameterDef],
84 is_early: bool) -> vtable_res {
85 debug!("lookup_vtables(span={:?}, \
89 type_param_defs.repr(vcx.tcx()),
90 substs.repr(vcx.tcx()));
92 // We do this backwards for reasons discussed above.
93 assert_eq!(substs.tps.len(), type_param_defs.len());
94 let mut result: Vec<vtable_param_res> =
97 .zip(type_param_defs.iter().rev())
99 lookup_vtables_for_param(vcx, span, Some(substs),
100 &*def.bounds, *ty, is_early))
104 assert_eq!(substs.tps.len(), result.len());
105 debug!("lookup_vtables result(\
107 type_param_defs={}, \
111 type_param_defs.repr(vcx.tcx()),
112 substs.repr(vcx.tcx()),
113 result.repr(vcx.tcx()));
117 fn lookup_vtables_for_param(vcx: &VtableContext,
119 // None for substs means the identity
120 substs: Option<&ty::substs>,
121 type_param_bounds: &ty::ParamBounds,
123 is_early: bool) -> vtable_param_res {
126 // ty is the value supplied for the type parameter A...
127 let mut param_result = Vec::new();
129 ty::each_bound_trait_and_supertraits(tcx,
130 type_param_bounds.trait_bounds
133 // ...and here trait_ref is each bound that was declared on A,
134 // expressed in terms of the type parameters.
136 ty::populate_implementations_for_trait_if_necessary(tcx,
139 // Substitute the values of the type parameters that may
140 // appear in the bound.
141 let trait_ref = substs.as_ref().map_or(trait_ref.clone(), |substs| {
142 debug!("about to subst: {}, {}",
143 trait_ref.repr(tcx), substs.repr(tcx));
144 trait_ref.subst(tcx, *substs)
147 debug!("after subst: {}", trait_ref.repr(tcx));
149 match lookup_vtable(vcx, span, ty, trait_ref.clone(), is_early) {
150 Some(vtable) => param_result.push(vtable),
152 vcx.tcx().sess.span_fatal(span,
153 format!("failed to find an implementation of \
155 vcx.infcx.trait_ref_to_str(&*trait_ref),
156 vcx.infcx.ty_to_str(ty)));
162 debug!("lookup_vtables_for_param result(\
164 type_param_bounds={}, \
168 type_param_bounds.repr(vcx.tcx()),
170 param_result.repr(vcx.tcx()));
175 fn relate_trait_refs(vcx: &VtableContext,
177 act_trait_ref: Rc<ty::TraitRef>,
178 exp_trait_ref: Rc<ty::TraitRef>) {
181 * Checks that an implementation of `act_trait_ref` is suitable
182 * for use where `exp_trait_ref` is required and reports an
186 match infer::mk_sub_trait_refs(vcx.infcx,
188 infer::RelateTraitRefs(span),
189 act_trait_ref.clone(),
190 exp_trait_ref.clone()) {
193 // There is an error, but we need to do some work to make
195 // Resolve any type vars in the trait refs
196 let r_act_trait_ref =
197 vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(&*act_trait_ref);
198 let r_exp_trait_ref =
199 vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(&*exp_trait_ref);
200 // Only print the message if there aren't any previous type errors
202 if !ty::trait_ref_contains_error(&r_act_trait_ref) &&
203 !ty::trait_ref_contains_error(&r_exp_trait_ref)
206 tcx.sess.span_err(span,
207 format!("expected {}, but found {} ({})",
208 ppaux::trait_ref_to_str(tcx, &r_exp_trait_ref),
209 ppaux::trait_ref_to_str(tcx, &r_act_trait_ref),
210 ty::type_err_to_str(tcx, err)));
216 // Look up the vtable implementing the trait `trait_ref` at type `t`
217 fn lookup_vtable(vcx: &VtableContext,
220 trait_ref: Rc<ty::TraitRef>,
222 -> Option<vtable_origin> {
223 debug!("lookup_vtable(ty={}, trait_ref={})",
224 vcx.infcx.ty_to_str(ty),
225 vcx.infcx.trait_ref_to_str(&*trait_ref));
228 let ty = match fixup_ty(vcx, span, ty, is_early) {
231 // fixup_ty can only fail if this is early resolution
233 // The type has unconstrained type variables in it, so we can't
234 // do early resolution on it. Return some completely bogus vtable
235 // information: we aren't storing it anyways.
236 return Some(vtable_param(param_self, 0));
240 // If the type is self or a param, we look at the trait/supertrait
241 // bounds to see if they include the trait we are looking for.
242 let vtable_opt = match ty::get(ty).sty {
243 ty::ty_param(param_ty {idx: n, ..}) => {
244 let env_bounds = &vcx.param_env.type_param_bounds;
245 if env_bounds.len() > n {
246 let type_param_bounds: &[Rc<ty::TraitRef>] =
247 env_bounds.get(n).trait_bounds.as_slice();
248 lookup_vtable_from_bounds(vcx, span,
258 let self_param_bound = vcx.param_env.self_param_bound.clone().unwrap();
259 lookup_vtable_from_bounds(vcx, span,
265 // Default case just falls through
269 if vtable_opt.is_some() { return vtable_opt; }
271 // If we aren't a self type or param, or it was, but we didn't find it,
273 search_for_vtable(vcx, span, ty, trait_ref, is_early)
276 // Given a list of bounds on a type, search those bounds to see if any
277 // of them are the vtable we are looking for.
278 fn lookup_vtable_from_bounds(vcx: &VtableContext,
280 bounds: &[Rc<ty::TraitRef>],
282 trait_ref: Rc<ty::TraitRef>)
283 -> Option<vtable_origin> {
288 ty::each_bound_trait_and_supertraits(tcx, bounds, |bound_trait_ref| {
289 debug!("checking bounds trait {}",
290 bound_trait_ref.repr(vcx.tcx()));
292 if bound_trait_ref.def_id == trait_ref.def_id {
293 relate_trait_refs(vcx, span, bound_trait_ref, trait_ref.clone());
294 let vtable = vtable_param(param, n_bound);
295 debug!("found param vtable: {:?}",
307 fn search_for_vtable(vcx: &VtableContext,
310 trait_ref: Rc<ty::TraitRef>,
312 -> Option<vtable_origin> {
315 let mut found = Vec::new();
316 let mut impls_seen = HashSet::new();
318 // Load the implementations from external metadata if necessary.
319 ty::populate_implementations_for_trait_if_necessary(tcx,
322 let impls = match tcx.trait_impls.borrow().find_copy(&trait_ref.def_id) {
323 Some(impls) => impls,
328 // impls is the list of all impls in scope for trait_ref.
329 for &impl_did in impls.borrow().iter() {
330 // im is one specific impl of trait_ref.
332 // First, ensure we haven't processed this impl yet.
333 if impls_seen.contains(&impl_did) {
336 impls_seen.insert(impl_did);
338 // ty::impl_traits gives us the trait im implements.
340 // If foo implements a trait t, and if t is the same trait as
341 // trait_ref, we need to unify it with trait_ref in order to
342 // get all the ty vars sorted out.
343 let r = ty::impl_trait_ref(tcx, impl_did);
344 let of_trait_ref = r.expect("trait_ref missing on trait impl");
345 if of_trait_ref.def_id != trait_ref.def_id { continue; }
347 // At this point, we know that of_trait_ref is the same trait
348 // as trait_ref, but possibly applied to different substs.
350 // Next, we check whether the "for" ty in the impl is
351 // compatible with the type that we're casting to a
352 // trait. That is, if im is:
354 // impl<T> some_trait<T> for self_ty<T> { ... }
356 // we check whether self_ty<T> is the type of the thing that
357 // we're trying to cast to some_trait. If not, then we try
360 // FIXME: document a bit more what this means
362 // FIXME(#5781) this should be mk_eqty not mk_subty
363 let ty::ty_param_substs_and_ty {
366 } = impl_self_ty(vcx, span, impl_did);
367 match infer::mk_subty(vcx.infcx,
369 infer::RelateSelfType(span),
376 // Now, in the previous example, for_ty is bound to
377 // the type self_ty, and substs is bound to [T].
378 debug!("The self ty is {} and its substs are {}",
379 vcx.infcx.ty_to_str(for_ty),
380 vcx.infcx.tys_to_str(substs.tps.as_slice()));
382 // Next, we unify trait_ref -- the type that we want to cast
383 // to -- with of_trait_ref -- the trait that im implements. At
384 // this point, we require that they be unifiable with each
385 // other -- that's what relate_trait_refs does.
387 // For example, in the above example, of_trait_ref would be
388 // some_trait<T>, so we would be unifying trait_ref<U> (for
389 // some value of U) with some_trait<T>. This would fail if T
390 // and U weren't compatible.
392 debug!("(checking vtable) \\#2 relating trait \
393 ty {} to of_trait_ref {}",
394 vcx.infcx.trait_ref_to_str(&*trait_ref),
395 vcx.infcx.trait_ref_to_str(&*of_trait_ref));
397 let of_trait_ref = of_trait_ref.subst(tcx, &substs);
398 relate_trait_refs(vcx, span, of_trait_ref, trait_ref.clone());
401 // Recall that trait_ref -- the trait type we're casting to --
402 // is the trait with id trait_ref.def_id applied to the substs
405 // Resolve any sub bounds. Note that there still may be free
406 // type variables in substs. This might still be OK: the
407 // process of looking up bounds might constrain some of them.
409 ty::lookup_item_type(tcx, impl_did).generics;
410 let subres = lookup_vtables(vcx, span,
411 im_generics.type_param_defs(), &substs,
415 // substs might contain type variables, so we call
416 // fixup_substs to resolve them.
417 let substs_f = match fixup_substs(vcx, span,
421 Some(ref substs) => (*substs).clone(),
424 // Bail out with a bogus answer
425 return Some(vtable_param(param_self, 0));
429 debug!("The fixed-up substs are {} - \
430 they will be unified with the bounds for \
432 vcx.infcx.tys_to_str(substs_f.tps.as_slice()),
433 vcx.infcx.trait_ref_to_str(&*trait_ref));
435 // Next, we unify the fixed-up substitutions for the impl self
436 // ty with the substitutions from the trait type that we're
437 // trying to cast to. connect_trait_tps requires these lists
438 // of types to unify pairwise.
439 // I am a little confused about this, since it seems to be
440 // very similar to the relate_trait_refs we already do,
441 // but problems crop up if it is removed, so... -sully
442 connect_trait_tps(vcx, span, &substs_f, trait_ref.clone(), impl_did);
444 // Finally, we register that we found a matching impl, and
445 // record the def ID of the impl as well as the resolved list
446 // of type substitutions for the target trait.
447 found.push(vtable_static(impl_did, substs_f.tps.clone(), subres));
452 1 => return Some(found.get(0).clone()),
455 vcx.tcx().sess.span_err(span, "multiple applicable methods in scope");
457 return Some(found.get(0).clone());
463 fn fixup_substs(vcx: &VtableContext,
468 -> Option<ty::substs> {
470 // use a dummy type just to package up the substs that need fixing up
471 let t = ty::mk_trait(tcx,
473 ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
474 ty::EmptyBuiltinBounds());
475 fixup_ty(vcx, span, t, is_early).map(|t_f| {
476 match ty::get(t_f).sty {
477 ty::ty_trait(ref inner) => inner.substs.clone(),
478 _ => fail!("t_f should be a trait")
483 fn fixup_ty(vcx: &VtableContext,
489 match resolve_type(vcx.infcx, ty, resolve_and_force_all_but_regions) {
490 Ok(new_type) => Some(new_type),
491 Err(e) if !is_early => {
492 tcx.sess.span_fatal(span,
493 format!("cannot determine a type \
494 for this bounded type parameter: {}",
495 fixup_err_to_str(e)))
503 fn connect_trait_tps(vcx: &VtableContext,
505 impl_substs: &ty::substs,
506 trait_ref: Rc<ty::TraitRef>,
507 impl_did: ast::DefId) {
510 let impl_trait_ref = match ty::impl_trait_ref(tcx, impl_did) {
512 None => vcx.tcx().sess.span_bug(span,
513 "connect_trait_tps invoked on a type impl")
516 let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
517 relate_trait_refs(vcx, span, impl_trait_ref, trait_ref);
520 fn insert_vtables(fcx: &FnCtxt, vtable_key: MethodCall, vtables: vtable_res) {
521 debug!("insert_vtables(vtable_key={}, vtables={:?})",
522 vtable_key, vtables.repr(fcx.tcx()));
523 fcx.inh.vtable_map.borrow_mut().insert(vtable_key, vtables);
526 pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
527 debug!("vtable: early_resolve_expr() ex with id {:?} (early: {}): {}",
528 ex.id, is_early, expr_to_str(ex));
529 let _indent = indenter();
532 let resolve_object_cast = |src: &ast::Expr, target_ty: ty::t| {
533 match ty::get(target_ty).sty {
534 // Bounds of type's contents are not checked here, but in kind.rs.
535 ty::ty_trait(~ty::TyTrait {
536 def_id: target_def_id, substs: ref target_substs, store, ..
538 fn mutability_allowed(a_mutbl: ast::Mutability,
539 b_mutbl: ast::Mutability) -> bool {
540 a_mutbl == b_mutbl ||
541 (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
543 // Look up vtables for the type we're casting to,
544 // passing in the source and target type. The source
545 // must be a pointer type suitable to the object sigil,
546 // e.g.: `&x as &Trait` or `~x as ~Trait`
547 let ty = structurally_resolved_type(fcx, ex.span,
549 match (&ty::get(ty).sty, store) {
550 (&ty::ty_rptr(_, mt), ty::RegionTraitStore(_, mutbl))
551 if !mutability_allowed(mt.mutbl, mutbl) => {
552 fcx.tcx().sess.span_err(ex.span,
553 format!("types differ in mutability"));
556 (&ty::ty_uniq(..), ty::UniqTraitStore) |
557 (&ty::ty_rptr(..), ty::RegionTraitStore(..)) => {
558 let typ = match &ty::get(ty).sty {
559 &ty::ty_box(typ) | &ty::ty_uniq(typ) => typ,
560 &ty::ty_rptr(_, mt) => mt.ty,
561 _ => fail!("shouldn't get here"),
564 let vcx = fcx.vtable_context();
565 let target_trait_ref = Rc::new(ty::TraitRef {
566 def_id: target_def_id,
568 tps: target_substs.tps.clone(),
569 regions: target_substs.regions.clone(),
574 let param_bounds = ty::ParamBounds {
575 builtin_bounds: ty::EmptyBuiltinBounds(),
576 trait_bounds: vec!(target_trait_ref)
579 lookup_vtables_for_param(&vcx,
587 insert_vtables(fcx, MethodCall::expr(ex.id), vec!(vtables));
590 // Now, if this is &trait, we need to link the
592 match (&ty::get(ty).sty, store) {
593 (&ty::ty_rptr(ra, _),
594 ty::RegionTraitStore(rb, _)) => {
595 infer::mk_subr(fcx.infcx(),
597 infer::RelateObjectBound(
606 (_, ty::UniqTraitStore) => {
607 fcx.ccx.tcx.sess.span_err(
609 format!("can only cast an ~-pointer \
610 to a ~-object, not a {}",
611 ty::ty_sort_str(fcx.tcx(), ty)));
614 (_, ty::RegionTraitStore(..)) => {
615 fcx.ccx.tcx.sess.span_err(
617 format!("can only cast an &-pointer \
618 to an &-object, not a {}",
619 ty::ty_sort_str(fcx.tcx(), ty)));
623 _ => { /* not a cast to a trait; ignore */ }
627 ast::ExprPath(..) => {
628 fcx.opt_node_ty_substs(ex.id, |substs| {
629 debug!("vtable resolution on parameter bounds for expr {}",
631 let def = cx.tcx.def_map.borrow().get_copy(&ex.id);
632 let did = ast_util::def_id_of_def(def);
633 let item_ty = ty::lookup_item_type(cx.tcx, did);
634 debug!("early resolve expr: def {:?} {:?}, {:?}, {}", ex.id, did, def,
635 fcx.infcx().ty_to_str(item_ty.ty));
636 if has_trait_bounds(item_ty.generics.type_param_defs()) {
637 debug!("early_resolve_expr: looking up vtables for type params {}",
638 item_ty.generics.type_param_defs().repr(fcx.tcx()));
639 let vcx = fcx.vtable_context();
640 let vtbls = lookup_vtables(&vcx, ex.span,
641 item_ty.generics.type_param_defs(),
644 insert_vtables(fcx, MethodCall::expr(ex.id), vtbls);
651 // Must resolve bounds on methods with bounded params
652 ast::ExprBinary(_, _, _) |
653 ast::ExprUnary(_, _) |
654 ast::ExprAssignOp(_, _, _) |
655 ast::ExprIndex(_, _) |
656 ast::ExprMethodCall(_, _, _) => {
657 match fcx.inh.method_map.borrow().find(&MethodCall::expr(ex.id)) {
659 debug!("vtable resolution on parameter bounds for method call {}",
661 let type_param_defs = ty::method_call_type_param_defs(cx.tcx, method.origin);
662 if has_trait_bounds(type_param_defs.as_slice()) {
663 let substs = fcx.method_ty_substs(ex.id);
664 let vcx = fcx.vtable_context();
665 let vtbls = lookup_vtables(&vcx, ex.span,
666 type_param_defs.as_slice(),
669 insert_vtables(fcx, MethodCall::expr(ex.id), vtbls);
676 ast::ExprCast(src, _) => {
677 debug!("vtable resolution on expr {}", ex.repr(fcx.tcx()));
678 let target_ty = fcx.expr_ty(ex);
679 resolve_object_cast(src, target_ty);
684 // Search for auto-adjustments to find trait coercions
685 match fcx.inh.adjustments.borrow().find(&ex.id) {
686 Some(adjustment) => {
688 AutoDerefRef(adj) => {
689 for autoderef in range(0, adj.autoderefs) {
690 let method_call = MethodCall::autoderef(ex.id, autoderef as u32);
691 match fcx.inh.method_map.borrow().find(&method_call) {
693 debug!("vtable resolution on parameter bounds for autoderef {}",
695 let type_param_defs =
696 ty::method_call_type_param_defs(cx.tcx, method.origin);
697 if has_trait_bounds(type_param_defs.deref().as_slice()) {
698 let vcx = fcx.vtable_context();
699 let vtbls = lookup_vtables(&vcx, ex.span,
700 type_param_defs.deref()
702 &method.substs, is_early);
704 insert_vtables(fcx, method_call, vtbls);
716 debug!("doing trait adjustment for expr {} {} \
722 let object_ty = ty::mk_trait(cx.tcx, def_id,
725 resolve_object_cast(ex, object_ty);
734 pub fn resolve_impl(tcx: &ty::ctxt,
735 impl_item: &ast::Item,
736 impl_generics: &ty::Generics,
737 impl_trait_ref: &ty::TraitRef) {
738 let param_env = ty::construct_parameter_environment(
741 impl_generics.type_param_defs(),
743 impl_generics.region_param_defs(),
747 let impl_trait_ref = impl_trait_ref.subst(tcx, ¶m_env.free_substs);
749 let infcx = &infer::new_infer_ctxt(tcx);
750 let vcx = VtableContext { infcx: infcx, param_env: ¶m_env };
752 // First, check that the impl implements any trait bounds
754 let trait_def = ty::lookup_trait_def(tcx, impl_trait_ref.def_id);
755 let vtbls = lookup_vtables(&vcx, impl_item.span,
756 trait_def.generics.type_param_defs(),
757 &impl_trait_ref.substs,
760 // Now, locate the vtable for the impl itself. The real
761 // purpose of this is to check for supertrait impls,
762 // but that falls out of doing this.
763 let param_bounds = ty::ParamBounds {
764 builtin_bounds: ty::EmptyBuiltinBounds(),
765 trait_bounds: vec!(Rc::new(impl_trait_ref))
767 let t = ty::node_id_to_type(tcx, impl_item.id);
768 let t = t.subst(tcx, ¶m_env.free_substs);
769 debug!("=== Doing a self lookup now.");
771 // Right now, we don't have any place to store this.
772 // We will need to make one so we can use this information
773 // for compiling default methods that refer to supertraits.
774 let self_vtable_res =
775 lookup_vtables_for_param(&vcx, impl_item.span, None,
776 ¶m_bounds, t, false);
780 trait_vtables: vtbls,
781 self_vtables: self_vtable_res
783 let impl_def_id = ast_util::local_def(impl_item.id);
785 tcx.impl_vtables.borrow_mut().insert(impl_def_id, res);
788 /// Resolve vtables for a method call after typeck has finished.
789 /// Used by trans to monomorphize artificial method callees (e.g. drop).
790 pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId,
791 substs: &ty::substs) -> Option<vtable_res> {
792 let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics;
793 let type_param_defs = &*generics.type_param_defs;
794 if has_trait_bounds(type_param_defs.as_slice()) {
795 let vcx = VtableContext {
796 infcx: &infer::new_infer_ctxt(tcx),
797 param_env: &ty::construct_parameter_environment(tcx, None, [], [], [], [], id)
800 Some(lookup_vtables(&vcx,
802 type_param_defs.as_slice(),
810 impl<'a, 'b> visit::Visitor<()> for &'a FnCtxt<'b> {
811 fn visit_expr(&mut self, ex: &ast::Expr, _: ()) {
812 early_resolve_expr(ex, *self, false);
813 visit::walk_expr(self, ex, ());
815 fn visit_item(&mut self, _: &ast::Item, _: ()) {
820 // Detect points where a trait-bounded type parameter is
821 // instantiated, resolve the impls for the parameters.
822 pub fn resolve_in_block(mut fcx: &FnCtxt, bl: &ast::Block) {
823 visit::walk_block(&mut fcx, bl, ());