1 // Copyright 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 check::{self, FnCtxt, callee, demand};
14 use check::UnresolvedTypeAction;
15 use middle::def_id::DefId;
16 use middle::subst::{self};
18 use middle::ty::{self, NoPreference, PreferMutLvalue, Ty};
19 use middle::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
20 use middle::ty::fold::TypeFoldable;
22 use middle::infer::InferCtxt;
23 use syntax::codemap::Span;
26 struct ConfirmContext<'a, 'tcx:'a> {
27 fcx: &'a FnCtxt<'a, 'tcx>,
29 self_expr: &'tcx hir::Expr,
30 call_expr: &'tcx hir::Expr,
33 struct InstantiatedMethodSig<'tcx> {
34 /// Function signature of the method being invoked. The 0th
35 /// argument is the receiver.
36 method_sig: ty::FnSig<'tcx>,
38 /// Substitutions for all types/early-bound-regions declared on
40 all_substs: subst::Substs<'tcx>,
42 /// Generic bounds on the method's parameters which must be added
43 /// as pending obligations.
44 method_predicates: ty::InstantiatedPredicates<'tcx>,
47 pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
49 self_expr: &'tcx hir::Expr,
50 call_expr: &'tcx hir::Expr,
51 unadjusted_self_ty: Ty<'tcx>,
52 pick: probe::Pick<'tcx>,
53 supplied_method_types: Vec<Ty<'tcx>>)
54 -> ty::MethodCallee<'tcx>
56 debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
59 supplied_method_types);
61 let mut confirm_cx = ConfirmContext::new(fcx, span, self_expr, call_expr);
62 confirm_cx.confirm(unadjusted_self_ty, pick, supplied_method_types)
65 impl<'a,'tcx> ConfirmContext<'a,'tcx> {
66 fn new(fcx: &'a FnCtxt<'a, 'tcx>,
68 self_expr: &'tcx hir::Expr,
69 call_expr: &'tcx hir::Expr)
70 -> ConfirmContext<'a, 'tcx>
72 ConfirmContext { fcx: fcx, span: span, self_expr: self_expr, call_expr: call_expr }
76 unadjusted_self_ty: Ty<'tcx>,
77 pick: probe::Pick<'tcx>,
78 supplied_method_types: Vec<Ty<'tcx>>)
79 -> ty::MethodCallee<'tcx>
81 // Adjust the self expression the user provided and obtain the adjusted type.
82 let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick);
84 // Make sure nobody calls `drop()` explicitly.
85 self.enforce_illegal_method_limitations(&pick);
87 // Create substitutions for the method's type parameters.
88 let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick);
90 self.instantiate_method_substs(
92 supplied_method_types,
95 debug!("all_substs={:?}", all_substs);
97 // Create the final signature for the method, replacing late-bound regions.
98 let InstantiatedMethodSig {
99 method_sig, all_substs, method_predicates
100 } = self.instantiate_method_sig(&pick, all_substs);
101 let method_self_ty = method_sig.inputs[0];
103 // Unify the (adjusted) self type with what the method expects.
104 self.unify_receivers(self_ty, method_self_ty);
106 // Add any trait/regions obligations specified on the method's type parameters.
107 self.add_obligations(&pick, &all_substs, &method_predicates);
109 // Create the final `MethodCallee`.
110 let method_ty = pick.item.as_opt_method().unwrap();
111 let fty = self.tcx().mk_fn(None, self.tcx().mk_bare_fn(ty::BareFnTy {
112 sig: ty::Binder(method_sig),
113 unsafety: method_ty.fty.unsafety,
114 abi: method_ty.fty.abi.clone(),
116 let callee = ty::MethodCallee {
117 def_id: pick.item.def_id(),
119 substs: self.tcx().mk_substs(all_substs)
122 // If this is an `&mut self` method, bias the receiver
123 // expression towards mutability (this will switch
124 // e.g. `Deref` to `DerefMut` in overloaded derefs and so on).
125 self.fixup_derefs_on_method_receiver_if_necessary(&callee);
130 ///////////////////////////////////////////////////////////////////////////
133 fn adjust_self_ty(&mut self,
134 unadjusted_self_ty: Ty<'tcx>,
135 pick: &probe::Pick<'tcx>)
138 let (autoref, unsize) = if let Some(mutbl) = pick.autoref {
139 let region = self.infcx().next_region_var(infer::Autoref(self.span));
140 let autoref = AutoPtr(self.tcx().mk_region(region), mutbl);
141 (Some(autoref), pick.unsize.map(|target| {
142 target.adjust_for_autoref(self.tcx(), Some(autoref))
145 // No unsizing should be performed without autoref (at
146 // least during method dispach). This is because we
147 // currently only unsize `[T;N]` to `[T]`, and naturally
148 // that must occur being a reference.
149 assert!(pick.unsize.is_none());
153 // Commit the autoderefs by calling `autoderef again, but this
154 // time writing the results into the various tables.
155 let (autoderefd_ty, n, result) = check::autoderef(self.fcx,
158 Some(self.self_expr),
159 UnresolvedTypeAction::Error,
162 if n == pick.autoderefs {
168 assert_eq!(n, pick.autoderefs);
169 assert_eq!(result, Some(()));
171 // Write out the final adjustment.
172 self.fcx.write_adjustment(self.self_expr.id,
173 AdjustDerefRef(AutoDerefRef {
174 autoderefs: pick.autoderefs,
179 if let Some(target) = unsize {
182 autoderefd_ty.adjust_for_autoref(self.tcx(), autoref)
186 ///////////////////////////////////////////////////////////////////////////
189 /// Returns a set of substitutions for the method *receiver* where all type and region
190 /// parameters are instantiated with fresh variables. This substitution does not include any
191 /// parameters declared on the method itself.
193 /// Note that this substitution may include late-bound regions from the impl level. If so,
194 /// these are instantiated later in the `instantiate_method_sig` routine.
195 fn fresh_receiver_substs(&mut self,
197 pick: &probe::Pick<'tcx>)
198 -> subst::Substs<'tcx>
201 probe::InherentImplPick => {
202 let impl_def_id = pick.item.container().id();
203 assert!(self.tcx().impl_trait_ref(impl_def_id).is_none(),
204 "impl {:?} is not an inherent impl", impl_def_id);
205 check::impl_self_ty(self.fcx, self.span, impl_def_id).substs
208 probe::ObjectPick => {
209 let trait_def_id = pick.item.container().id();
210 self.extract_trait_ref(self_ty, |this, object_ty, data| {
211 // The object data has no entry for the Self
212 // Type. For the purposes of this method call, we
213 // substitute the object type itself. This
214 // wouldn't be a sound substitution in all cases,
215 // since each instance of the object type is a
216 // different existential and hence could match
217 // distinct types (e.g., if `Self` appeared as an
218 // argument type), but those cases have already
219 // been ruled out when we deemed the trait to be
221 let original_poly_trait_ref =
222 data.principal_trait_ref_with_self_ty(this.tcx(), object_ty);
223 let upcast_poly_trait_ref =
224 this.upcast(original_poly_trait_ref.clone(), trait_def_id);
225 let upcast_trait_ref =
226 this.replace_late_bound_regions_with_fresh_var(&upcast_poly_trait_ref);
227 debug!("original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
228 original_poly_trait_ref,
231 upcast_trait_ref.substs.clone()
235 probe::ExtensionImplPick(impl_def_id) => {
236 // The method being invoked is the method as defined on the trait,
237 // so return the substitutions from the trait. Consider:
239 // impl<A,B,C> Trait<A,B> for Foo<C> { ... }
241 // If we instantiate A, B, and C with $A, $B, and $C
242 // respectively, then we want to return the type
243 // parameters from the trait ([$A,$B]), not those from
244 // the impl ([$A,$B,$C]) not the receiver type ([$C]).
245 let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id);
247 self.fcx.instantiate_type_scheme(
249 &impl_polytype.substs,
250 &self.tcx().impl_trait_ref(impl_def_id).unwrap());
251 impl_trait_ref.substs.clone()
254 probe::TraitPick => {
255 let trait_def_id = pick.item.container().id();
256 let trait_def = self.tcx().lookup_trait_def(trait_def_id);
258 // Make a trait reference `$0 : Trait<$1...$n>`
259 // consisting entirely of type variables. Later on in
260 // the process we will unify the transformed-self-type
261 // of the method with the actual type in order to
262 // unify some of these variables.
263 self.infcx().fresh_substs_for_trait(self.span,
265 self.infcx().next_ty_var())
268 probe::WhereClausePick(ref poly_trait_ref) => {
269 // Where clauses can have bound regions in them. We need to instantiate
270 // those to convert from a poly-trait-ref to a trait-ref.
271 self.replace_late_bound_regions_with_fresh_var(&*poly_trait_ref).substs.clone()
276 fn extract_trait_ref<R, F>(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R where
277 F: FnMut(&mut ConfirmContext<'a, 'tcx>, Ty<'tcx>, &ty::TraitTy<'tcx>) -> R,
279 // If we specified that this is an object method, then the
280 // self-type ought to be something that can be dereferenced to
281 // yield an object-type (e.g., `&Object` or `Box<Object>`
284 let (_, _, result) = check::autoderef(self.fcx,
288 UnresolvedTypeAction::Error,
292 ty::TyTrait(ref data) => Some(closure(self, ty, &**data)),
300 self.tcx().sess.span_bug(
302 &format!("self-type `{}` for ObjectPick never dereferenced to an object",
308 fn instantiate_method_substs(&mut self,
309 pick: &probe::Pick<'tcx>,
310 supplied_method_types: Vec<Ty<'tcx>>,
311 substs: subst::Substs<'tcx>)
312 -> subst::Substs<'tcx>
314 // Determine the values for the generic parameters of the method.
315 // If they were not explicitly supplied, just construct fresh
317 let num_supplied_types = supplied_method_types.len();
318 let method = pick.item.as_opt_method().unwrap();
319 let method_types = method.generics.types.get_slice(subst::FnSpace);
320 let num_method_types = method_types.len();
323 // Create subst for early-bound lifetime parameters, combining
324 // parameters from the type and those from the method.
326 // FIXME -- permit users to manually specify lifetimes
328 self.fcx.infcx().region_vars_for_defs(
330 pick.item.as_opt_method().unwrap()
331 .generics.regions.get_slice(subst::FnSpace));
333 let subst::Substs { types, regions } = substs;
334 let regions = regions.map(|r| r.with_vec(subst::FnSpace, method_regions));
335 let mut final_substs = subst::Substs { types: types, regions: regions };
337 if num_supplied_types == 0 {
338 self.fcx.infcx().type_vars_for_defs(
343 } else if num_method_types == 0 {
344 span_err!(self.tcx().sess, self.span, E0035,
345 "does not take type parameters");
346 self.fcx.infcx().type_vars_for_defs(
351 } else if num_supplied_types != num_method_types {
352 span_err!(self.tcx().sess, self.span, E0036,
353 "incorrect number of type parameters given for this method");
354 final_substs.types.replace(
356 vec![self.tcx().types.err; num_method_types]);
358 final_substs.types.replace(subst::FnSpace, supplied_method_types);
364 fn unify_receivers(&mut self,
366 method_self_ty: Ty<'tcx>)
368 match self.fcx.mk_subty(false, infer::Misc(self.span), self_ty, method_self_ty) {
371 self.tcx().sess.span_bug(
373 &format!("{} was a subtype of {} but now is not?",
374 self_ty, method_self_ty));
379 ///////////////////////////////////////////////////////////////////////////
382 fn instantiate_method_sig(&mut self,
383 pick: &probe::Pick<'tcx>,
384 all_substs: subst::Substs<'tcx>)
385 -> InstantiatedMethodSig<'tcx>
387 debug!("instantiate_method_sig(pick={:?}, all_substs={:?})",
391 // Instantiate the bounds on the method with the
392 // type/early-bound-regions substitutions performed. There can
393 // be no late-bound regions appearing here.
394 let method_predicates = pick.item.as_opt_method().unwrap()
395 .predicates.instantiate(self.tcx(), &all_substs);
396 let method_predicates = self.fcx.normalize_associated_types_in(self.span,
399 debug!("method_predicates after subst = {:?}",
402 // Instantiate late-bound regions and substitute the trait
403 // parameters into the method type to get the actual method type.
405 // NB: Instantiate late-bound regions first so that
406 // `instantiate_type_scheme` can normalize associated types that
407 // may reference those regions.
408 let method_sig = self.replace_late_bound_regions_with_fresh_var(
409 &pick.item.as_opt_method().unwrap().fty.sig);
410 debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
413 let method_sig = self.fcx.instantiate_type_scheme(self.span, &all_substs, &method_sig);
414 debug!("type scheme substituted, method_sig={:?}",
417 InstantiatedMethodSig {
418 method_sig: method_sig,
419 all_substs: all_substs,
420 method_predicates: method_predicates,
424 fn add_obligations(&mut self,
425 pick: &probe::Pick<'tcx>,
426 all_substs: &subst::Substs<'tcx>,
427 method_predicates: &ty::InstantiatedPredicates<'tcx>) {
428 debug!("add_obligations: pick={:?} all_substs={:?} method_predicates={:?}",
433 self.fcx.add_obligations_for_parameters(
434 traits::ObligationCause::misc(self.span, self.fcx.body_id),
437 // this is a projection from a trait reference, so we have to
438 // make sure that the trait reference inputs are well-formed.
439 self.fcx.add_wf_bounds(
444 ///////////////////////////////////////////////////////////////////////////
447 /// When we select a method with an `&mut self` receiver, we have to go convert any
448 /// auto-derefs, indices, etc from `Deref` and `Index` into `DerefMut` and `IndexMut`
450 fn fixup_derefs_on_method_receiver_if_necessary(&self,
451 method_callee: &ty::MethodCallee) {
452 let sig = match method_callee.ty.sty {
453 ty::TyBareFn(_, ref f) => f.sig.clone(),
457 match sig.0.inputs[0].sty {
458 ty::TyRef(_, ty::TypeAndMut {
460 mutbl: hir::MutMutable,
465 // Gather up expressions we want to munge.
466 let mut exprs = Vec::new();
467 exprs.push(self.self_expr);
469 let last = exprs[exprs.len() - 1];
471 hir::ExprParen(ref expr) |
472 hir::ExprField(ref expr, _) |
473 hir::ExprTupField(ref expr, _) |
474 hir::ExprIndex(ref expr, _) |
475 hir::ExprUnary(hir::UnDeref, ref expr) => exprs.push(&**expr),
480 debug!("fixup_derefs_on_method_receiver_if_necessary: exprs={:?}",
483 // Fix up autoderefs and derefs.
484 for (i, &expr) in exprs.iter().rev().enumerate() {
486 let autoderef_count = match self.fcx
492 Some(&AdjustDerefRef(ref adj)) => adj.autoderefs,
496 debug!("fixup_derefs_on_method_receiver_if_necessary: i={} expr={:?} \
498 i, expr, autoderef_count);
500 if autoderef_count > 0 {
501 check::autoderef(self.fcx,
503 self.fcx.expr_ty(expr),
505 UnresolvedTypeAction::Error,
508 if autoderefs == autoderef_count + 1 {
516 // Don't retry the first one or we might infinite loop!
519 hir::ExprIndex(ref base_expr, ref index_expr) => {
520 // If this is an overloaded index, the
521 // adjustment will include an extra layer of
522 // autoref because the method is an &self/&mut
523 // self method. We have to peel it off to get
524 // the raw adjustment that `try_index_step`
525 // expects. This is annoying and horrible. We
526 // ought to recode this routine so it doesn't
527 // (ab)use the normal type checking paths.
528 let adj = self.fcx.inh.tables.borrow().adjustments.get(&base_expr.id)
530 let (autoderefs, unsize) = match adj {
531 Some(AdjustDerefRef(adr)) => match adr.autoref {
533 assert!(adr.unsize.is_none());
534 (adr.autoderefs, None)
536 Some(AutoPtr(_, _)) => {
537 (adr.autoderefs, adr.unsize.map(|target| {
538 target.builtin_deref(false, NoPreference)
539 .expect("fixup: AutoPtr is not &T").ty
543 self.tcx().sess.span_bug(
545 &format!("unexpected adjustment autoref {:?}",
551 self.tcx().sess.span_bug(
553 "unexpected adjustment type");
557 let (adjusted_base_ty, unsize) = if let Some(target) = unsize {
560 (self.fcx.adjust_expr_ty(base_expr,
561 Some(&AdjustDerefRef(AutoDerefRef {
562 autoderefs: autoderefs,
567 let index_expr_ty = self.fcx.expr_ty(&**index_expr);
569 let result = check::try_index_step(
571 ty::MethodCall::expr(expr.id),
580 if let Some((input_ty, return_ty)) = result {
581 demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty);
583 let expr_ty = self.fcx.expr_ty(&*expr);
584 demand::suptype(self.fcx, expr.span, expr_ty, return_ty);
587 hir::ExprUnary(hir::UnDeref, ref base_expr) => {
588 // if this is an overloaded deref, then re-evaluate with
589 // a preference for mut
590 let method_call = ty::MethodCall::expr(expr.id);
591 if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) {
592 check::try_overloaded_deref(
597 self.fcx.expr_ty(&**base_expr),
607 ///////////////////////////////////////////////////////////////////////////
610 fn tcx(&self) -> &'a ty::ctxt<'tcx> {
614 fn infcx(&self) -> &'a InferCtxt<'a, 'tcx> {
618 fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
619 // Disallow calls to the method `drop` defined in the `Drop` trait.
620 match pick.item.container() {
621 ty::TraitContainer(trait_def_id) => {
622 callee::check_legal_trait_for_method_call(self.fcx.ccx, self.span, trait_def_id)
624 ty::ImplContainer(..) => {
625 // Since `drop` is a trait method, we expect that any
626 // potential calls to it will wind up in the other
627 // arm. But just to be sure, check that the method id
628 // does not appear in the list of destructors.
629 assert!(!self.tcx().destructors.borrow().contains(&pick.item.def_id()));
635 source_trait_ref: ty::PolyTraitRef<'tcx>,
636 target_trait_def_id: DefId)
637 -> ty::PolyTraitRef<'tcx>
639 let upcast_trait_refs = traits::upcast(self.tcx(),
640 source_trait_ref.clone(),
641 target_trait_def_id);
643 // must be exactly one trait ref or we'd get an ambig error etc
644 if upcast_trait_refs.len() != 1 {
645 self.tcx().sess.span_bug(
647 &format!("cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
653 upcast_trait_refs.into_iter().next().unwrap()
656 fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &ty::Binder<T>) -> T
657 where T : TypeFoldable<'tcx>
659 self.infcx().replace_late_bound_regions_with_fresh_var(
660 self.span, infer::FnCall, value).0