]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/method/confirm.rs
Rollup merge of #21964 - semarie:openbsd-env, r=alexcrichton
[rust.git] / src / librustc_typeck / check / method / confirm.rs
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.
4 //
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.
10
11 use super::probe;
12
13 use check::{self, FnCtxt, NoPreference, PreferMutLvalue, callee, demand};
14 use check::UnresolvedTypeAction;
15 use middle::mem_categorization::Typer;
16 use middle::subst::{self};
17 use middle::traits;
18 use middle::ty::{self, Ty};
19 use middle::ty::{MethodCall, MethodCallee, MethodObject, MethodOrigin,
20                  MethodParam, MethodStatic, MethodTraitObject, MethodTypeParam};
21 use middle::ty_fold::TypeFoldable;
22 use middle::infer;
23 use middle::infer::InferCtxt;
24 use syntax::ast;
25 use syntax::codemap::Span;
26 use std::rc::Rc;
27 use std::mem;
28 use std::iter::repeat;
29 use util::ppaux::Repr;
30
31 struct ConfirmContext<'a, 'tcx:'a> {
32     fcx: &'a FnCtxt<'a, 'tcx>,
33     span: Span,
34     self_expr: &'tcx ast::Expr,
35     call_expr: &'tcx ast::Expr,
36 }
37
38 struct InstantiatedMethodSig<'tcx> {
39     /// Function signature of the method being invoked. The 0th
40     /// argument is the receiver.
41     method_sig: ty::FnSig<'tcx>,
42
43     /// Substitutions for all types/early-bound-regions declared on
44     /// the method.
45     all_substs: subst::Substs<'tcx>,
46
47     /// Generic bounds on the method's parameters which must be added
48     /// as pending obligations.
49     method_bounds: ty::GenericBounds<'tcx>,
50 }
51
52 pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
53                          span: Span,
54                          self_expr: &'tcx ast::Expr,
55                          call_expr: &'tcx ast::Expr,
56                          unadjusted_self_ty: Ty<'tcx>,
57                          pick: probe::Pick<'tcx>,
58                          supplied_method_types: Vec<Ty<'tcx>>)
59                          -> MethodCallee<'tcx>
60 {
61     debug!("confirm(unadjusted_self_ty={}, pick={}, supplied_method_types={})",
62            unadjusted_self_ty.repr(fcx.tcx()),
63            pick.repr(fcx.tcx()),
64            supplied_method_types.repr(fcx.tcx()));
65
66     let mut confirm_cx = ConfirmContext::new(fcx, span, self_expr, call_expr);
67     confirm_cx.confirm(unadjusted_self_ty, pick, supplied_method_types)
68 }
69
70 impl<'a,'tcx> ConfirmContext<'a,'tcx> {
71     fn new(fcx: &'a FnCtxt<'a, 'tcx>,
72            span: Span,
73            self_expr: &'tcx ast::Expr,
74            call_expr: &'tcx ast::Expr)
75            -> ConfirmContext<'a, 'tcx>
76     {
77         ConfirmContext { fcx: fcx, span: span, self_expr: self_expr, call_expr: call_expr }
78     }
79
80     fn confirm(&mut self,
81                unadjusted_self_ty: Ty<'tcx>,
82                pick: probe::Pick<'tcx>,
83                supplied_method_types: Vec<Ty<'tcx>>)
84                -> MethodCallee<'tcx>
85     {
86         // Adjust the self expression the user provided and obtain the adjusted type.
87         let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick.adjustment);
88
89         // Make sure nobody calls `drop()` explicitly.
90         self.enforce_illegal_method_limitations(&pick);
91
92         // Create substitutions for the method's type parameters.
93         let (rcvr_substs, method_origin) =
94             self.fresh_receiver_substs(self_ty, &pick);
95         let (method_types, method_regions) =
96             self.instantiate_method_substs(&pick, supplied_method_types);
97         let all_substs = rcvr_substs.with_method(method_types, method_regions);
98         debug!("all_substs={}", all_substs.repr(self.tcx()));
99
100         // Create the final signature for the method, replacing late-bound regions.
101         let InstantiatedMethodSig {
102             method_sig, all_substs, method_bounds
103         } = self.instantiate_method_sig(&pick, all_substs);
104         let method_self_ty = method_sig.inputs[0];
105
106         // Unify the (adjusted) self type with what the method expects.
107         self.unify_receivers(self_ty, method_self_ty);
108
109         // Add any trait/regions obligations specified on the method's type parameters.
110         self.add_obligations(&pick, &all_substs, &method_bounds);
111
112         // Create the final `MethodCallee`.
113         let fty = ty::mk_bare_fn(self.tcx(), None, self.tcx().mk_bare_fn(ty::BareFnTy {
114             sig: ty::Binder(method_sig),
115             unsafety: pick.method_ty.fty.unsafety,
116             abi: pick.method_ty.fty.abi.clone(),
117         }));
118         let callee = MethodCallee {
119             origin: method_origin,
120             ty: fty,
121             substs: all_substs
122         };
123
124         // If this is an `&mut self` method, bias the receiver
125         // expression towards mutability (this will switch
126         // e.g. `Deref` to `DerefMut` in overloaded derefs and so on).
127         self.fixup_derefs_on_method_receiver_if_necessary(&callee);
128
129         callee
130     }
131
132     ///////////////////////////////////////////////////////////////////////////
133     // ADJUSTMENTS
134
135     fn adjust_self_ty(&mut self,
136                       unadjusted_self_ty: Ty<'tcx>,
137                       adjustment: &probe::PickAdjustment)
138                       -> Ty<'tcx>
139     {
140         // Construct the actual adjustment and write it into the table
141         let auto_deref_ref = self.create_ty_adjustment(adjustment);
142
143         // Commit the autoderefs by calling `autoderef again, but this
144         // time writing the results into the various tables.
145         let (autoderefd_ty, n, result) = check::autoderef(self.fcx,
146                                                           self.span,
147                                                           unadjusted_self_ty,
148                                                           Some(self.self_expr),
149                                                           UnresolvedTypeAction::Error,
150                                                           NoPreference,
151                                                           |_, n| {
152             if n == auto_deref_ref.autoderefs {
153                 Some(())
154             } else {
155                 None
156             }
157         });
158         assert_eq!(n, auto_deref_ref.autoderefs);
159         assert_eq!(result, Some(()));
160
161         let final_ty =
162             ty::adjust_ty_for_autoref(self.tcx(), self.span, autoderefd_ty,
163                                       auto_deref_ref.autoref.as_ref());
164
165         // Write out the final adjustment.
166         self.fcx.write_adjustment(self.self_expr.id, self.span, ty::AdjustDerefRef(auto_deref_ref));
167
168         final_ty
169     }
170
171     fn create_ty_adjustment(&mut self,
172                             adjustment: &probe::PickAdjustment)
173                             -> ty::AutoDerefRef<'tcx>
174     {
175         match *adjustment {
176             probe::AutoDeref(num) => {
177                 ty::AutoDerefRef {
178                     autoderefs: num,
179                     autoref: None
180                 }
181             }
182             probe::AutoUnsizeLength(autoderefs, len) => {
183                 ty::AutoDerefRef {
184                     autoderefs: autoderefs,
185                     autoref: Some(ty::AutoUnsize(ty::UnsizeLength(len)))
186                 }
187             }
188             probe::AutoRef(mutability, ref sub_adjustment) => {
189                 let deref = self.create_ty_adjustment(&**sub_adjustment);
190                 let region = self.infcx().next_region_var(infer::Autoref(self.span));
191                 wrap_autoref(deref, |base| ty::AutoPtr(region, mutability, base))
192             }
193         }
194     }
195
196     ///////////////////////////////////////////////////////////////////////////
197     //
198
199     /// Returns a set of substitutions for the method *receiver* where all type and region
200     /// parameters are instantiated with fresh variables. This substitution does not include any
201     /// parameters declared on the method itself.
202     ///
203     /// Note that this substitution may include late-bound regions from the impl level. If so,
204     /// these are instantiated later in the `instantiate_method_sig` routine.
205     fn fresh_receiver_substs(&mut self,
206                              self_ty: Ty<'tcx>,
207                              pick: &probe::Pick<'tcx>)
208                              -> (subst::Substs<'tcx>, MethodOrigin<'tcx>)
209     {
210         match pick.kind {
211             probe::InherentImplPick(impl_def_id) => {
212                 assert!(ty::impl_trait_ref(self.tcx(), impl_def_id).is_none(),
213                         "impl {:?} is not an inherent impl", impl_def_id);
214                 let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id);
215
216                 (impl_polytype.substs, MethodStatic(pick.method_ty.def_id))
217             }
218
219             probe::ObjectPick(trait_def_id, method_num, vtable_index) => {
220                 self.extract_trait_ref(self_ty, |this, object_ty, data| {
221                     // The object data has no entry for the Self
222                     // Type. For the purposes of this method call, we
223                     // substitute the object type itself. This
224                     // wouldn't be a sound substitution in all cases,
225                     // since each instance of the object type is a
226                     // different existential and hence could match
227                     // distinct types (e.g., if `Self` appeared as an
228                     // argument type), but those cases have already
229                     // been ruled out when we deemed the trait to be
230                     // "object safe".
231                     let original_poly_trait_ref =
232                         data.principal_trait_ref_with_self_ty(this.tcx(), object_ty);
233                     let upcast_poly_trait_ref =
234                         this.upcast(original_poly_trait_ref.clone(), trait_def_id);
235                     let upcast_trait_ref =
236                         this.replace_late_bound_regions_with_fresh_var(&upcast_poly_trait_ref);
237                     debug!("original_poly_trait_ref={} upcast_trait_ref={} target_trait={}",
238                            original_poly_trait_ref.repr(this.tcx()),
239                            upcast_trait_ref.repr(this.tcx()),
240                            trait_def_id.repr(this.tcx()));
241                     let substs = upcast_trait_ref.substs.clone();
242                     let origin = MethodTraitObject(MethodObject {
243                         trait_ref: upcast_trait_ref,
244                         object_trait_id: trait_def_id,
245                         method_num: method_num,
246                         vtable_index: vtable_index,
247                     });
248                     (substs, origin)
249                 })
250             }
251
252             probe::ExtensionImplPick(impl_def_id, method_num) => {
253                 // The method being invoked is the method as defined on the trait,
254                 // so return the substitutions from the trait. Consider:
255                 //
256                 //     impl<A,B,C> Trait<A,B> for Foo<C> { ... }
257                 //
258                 // If we instantiate A, B, and C with $A, $B, and $C
259                 // respectively, then we want to return the type
260                 // parameters from the trait ([$A,$B]), not those from
261                 // the impl ([$A,$B,$C]) not the receiver type ([$C]).
262                 let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id);
263                 let impl_trait_ref =
264                     self.fcx.instantiate_type_scheme(
265                         self.span,
266                         &impl_polytype.substs,
267                         &ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap());
268                 let origin = MethodTypeParam(MethodParam { trait_ref: impl_trait_ref.clone(),
269                                                            method_num: method_num,
270                                                            impl_def_id: Some(impl_def_id) });
271                 (impl_trait_ref.substs.clone(), origin)
272             }
273
274             probe::TraitPick(trait_def_id, method_num) => {
275                 let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id);
276
277                 // Make a trait reference `$0 : Trait<$1...$n>`
278                 // consisting entirely of type variables. Later on in
279                 // the process we will unify the transformed-self-type
280                 // of the method with the actual type in order to
281                 // unify some of these variables.
282                 let substs = self.infcx().fresh_substs_for_trait(self.span,
283                                                                  &trait_def.generics,
284                                                                  self.infcx().next_ty_var());
285
286                 let trait_ref =
287                     Rc::new(ty::TraitRef::new(trait_def_id, self.tcx().mk_substs(substs.clone())));
288                 let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref,
289                                                            method_num: method_num,
290                                                            impl_def_id: None });
291                 (substs, origin)
292             }
293
294             probe::WhereClausePick(ref poly_trait_ref, method_num) => {
295                 // Where clauses can have bound regions in them. We need to instantiate
296                 // those to convert from a poly-trait-ref to a trait-ref.
297                 let trait_ref = self.replace_late_bound_regions_with_fresh_var(&*poly_trait_ref);
298                 let substs = trait_ref.substs.clone();
299                 let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref,
300                                                            method_num: method_num,
301                                                            impl_def_id: None });
302                 (substs, origin)
303             }
304         }
305     }
306
307     fn extract_trait_ref<R, F>(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R where
308         F: FnMut(&mut ConfirmContext<'a, 'tcx>, Ty<'tcx>, &ty::TyTrait<'tcx>) -> R,
309     {
310         // If we specified that this is an object method, then the
311         // self-type ought to be something that can be dereferenced to
312         // yield an object-type (e.g., `&Object` or `Box<Object>`
313         // etc).
314
315         let (_, _, result) = check::autoderef(self.fcx,
316                                               self.span,
317                                               self_ty,
318                                               None,
319                                               UnresolvedTypeAction::Error,
320                                               NoPreference,
321                                               |ty, _| {
322             match ty.sty {
323                 ty::ty_trait(ref data) => Some(closure(self, ty, &**data)),
324                 _ => None,
325             }
326         });
327
328         match result {
329             Some(r) => r,
330             None => {
331                 self.tcx().sess.span_bug(
332                     self.span,
333                     &format!("self-type `{}` for ObjectPick never dereferenced to an object",
334                             self_ty.repr(self.tcx()))[])
335             }
336         }
337     }
338
339     fn instantiate_method_substs(&mut self,
340                                  pick: &probe::Pick<'tcx>,
341                                  supplied_method_types: Vec<Ty<'tcx>>)
342                                  -> (Vec<Ty<'tcx>>, Vec<ty::Region>)
343     {
344         // Determine the values for the generic parameters of the method.
345         // If they were not explicitly supplied, just construct fresh
346         // variables.
347         let num_supplied_types = supplied_method_types.len();
348         let num_method_types = pick.method_ty.generics.types.len(subst::FnSpace);
349         let method_types = {
350             if num_supplied_types == 0 {
351                 self.fcx.infcx().next_ty_vars(num_method_types)
352             } else if num_method_types == 0 {
353                 span_err!(self.tcx().sess, self.span, E0035,
354                     "does not take type parameters");
355                 self.fcx.infcx().next_ty_vars(num_method_types)
356             } else if num_supplied_types != num_method_types {
357                 span_err!(self.tcx().sess, self.span, E0036,
358                     "incorrect number of type parameters given for this method");
359                 repeat(self.tcx().types.err).take(num_method_types).collect()
360             } else {
361                 supplied_method_types
362             }
363         };
364
365         // Create subst for early-bound lifetime parameters, combining
366         // parameters from the type and those from the method.
367         //
368         // FIXME -- permit users to manually specify lifetimes
369         let method_regions =
370             self.fcx.infcx().region_vars_for_defs(
371                 self.span,
372                 pick.method_ty.generics.regions.get_slice(subst::FnSpace));
373
374         (method_types, method_regions)
375     }
376
377     fn unify_receivers(&mut self,
378                        self_ty: Ty<'tcx>,
379                        method_self_ty: Ty<'tcx>)
380     {
381         match self.fcx.mk_subty(false, infer::Misc(self.span), self_ty, method_self_ty) {
382             Ok(_) => {}
383             Err(_) => {
384                 self.tcx().sess.span_bug(
385                     self.span,
386                     &format!(
387                         "{} was a subtype of {} but now is not?",
388                         self_ty.repr(self.tcx()),
389                         method_self_ty.repr(self.tcx()))[]);
390             }
391         }
392     }
393
394     ///////////////////////////////////////////////////////////////////////////
395     //
396
397     fn instantiate_method_sig(&mut self,
398                               pick: &probe::Pick<'tcx>,
399                               all_substs: subst::Substs<'tcx>)
400                               -> InstantiatedMethodSig<'tcx>
401     {
402         debug!("instantiate_method_sig(pick={}, all_substs={})",
403                pick.repr(self.tcx()),
404                all_substs.repr(self.tcx()));
405
406         // Instantiate the bounds on the method with the
407         // type/early-bound-regions substitutions performed.  The only
408         // late-bound-regions that can appear in bounds are from the
409         // impl, and those were already instantiated above.
410         //
411         // FIXME(DST). Super hack. For a method on a trait object
412         // `Trait`, the generic signature requires that
413         // `Self:Trait`. Since, for an object, we bind `Self` to the
414         // type `Trait`, this leads to an obligation
415         // `Trait:Trait`. Until such time we DST is fully implemented,
416         // that obligation is not necessarily satisfied. (In the
417         // future, it would be.) But we know that the true `Self` DOES implement
418         // the trait. So we just delete this requirement. Hack hack hack.
419         let mut method_bounds = pick.method_ty.generics.to_bounds(self.tcx(), &all_substs);
420         match pick.kind {
421             probe::ObjectPick(..) => {
422                 assert_eq!(method_bounds.predicates.get_slice(subst::SelfSpace).len(), 1);
423                 method_bounds.predicates.pop(subst::SelfSpace);
424             }
425             _ => { }
426         }
427         let method_bounds = self.fcx.normalize_associated_types_in(self.span, &method_bounds);
428
429         debug!("method_bounds after subst = {}",
430                method_bounds.repr(self.tcx()));
431
432         // Instantiate late-bound regions and substitute the trait
433         // parameters into the method type to get the actual method type.
434         //
435         // NB: Instantiate late-bound regions first so that
436         // `instantiate_type_scheme` can normalize associated types that
437         // may reference those regions.
438         let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.method_ty.fty.sig);
439         debug!("late-bound lifetimes from method instantiated, method_sig={}",
440                method_sig.repr(self.tcx()));
441
442         let method_sig = self.fcx.instantiate_type_scheme(self.span, &all_substs, &method_sig);
443         debug!("type scheme substituted, method_sig={}",
444                method_sig.repr(self.tcx()));
445
446         InstantiatedMethodSig {
447             method_sig: method_sig,
448             all_substs: all_substs,
449             method_bounds: method_bounds,
450         }
451     }
452
453     fn add_obligations(&mut self,
454                        pick: &probe::Pick<'tcx>,
455                        all_substs: &subst::Substs<'tcx>,
456                        method_bounds: &ty::GenericBounds<'tcx>) {
457         debug!("add_obligations: pick={} all_substs={} method_bounds={}",
458                pick.repr(self.tcx()),
459                all_substs.repr(self.tcx()),
460                method_bounds.repr(self.tcx()));
461
462         self.fcx.add_obligations_for_parameters(
463             traits::ObligationCause::misc(self.span, self.fcx.body_id),
464             method_bounds);
465
466         self.fcx.add_default_region_param_bounds(
467             all_substs,
468             self.call_expr);
469     }
470
471     ///////////////////////////////////////////////////////////////////////////
472     // RECONCILIATION
473
474     /// When we select a method with an `&mut self` receiver, we have to go convert any
475     /// auto-derefs, indices, etc from `Deref` and `Index` into `DerefMut` and `IndexMut`
476     /// respectively.
477     fn fixup_derefs_on_method_receiver_if_necessary(&self,
478                                                     method_callee: &MethodCallee) {
479         let sig = match method_callee.ty.sty {
480             ty::ty_bare_fn(_, ref f) => f.sig.clone(),
481             _ => return,
482         };
483
484         match sig.0.inputs[0].sty {
485             ty::ty_rptr(_, ty::mt {
486                 ty: _,
487                 mutbl: ast::MutMutable,
488             }) => {}
489             _ => return,
490         }
491
492         // Gather up expressions we want to munge.
493         let mut exprs = Vec::new();
494         exprs.push(self.self_expr);
495         loop {
496             let last = exprs[exprs.len() - 1];
497             match last.node {
498                 ast::ExprParen(ref expr) |
499                 ast::ExprField(ref expr, _) |
500                 ast::ExprTupField(ref expr, _) |
501                 ast::ExprIndex(ref expr, _) |
502                 ast::ExprUnary(ast::UnDeref, ref expr) => exprs.push(&**expr),
503                 _ => break,
504             }
505         }
506
507         debug!("fixup_derefs_on_method_receiver_if_necessary: exprs={}",
508                exprs.repr(self.tcx()));
509
510         // Fix up autoderefs and derefs.
511         for (i, &expr) in exprs.iter().rev().enumerate() {
512             // Count autoderefs.
513             let autoderef_count = match self.fcx
514                                             .inh
515                                             .adjustments
516                                             .borrow()
517                                             .get(&expr.id) {
518                 Some(&ty::AdjustDerefRef(ty::AutoDerefRef {
519                     autoderefs: autoderef_count,
520                     autoref: _
521                 })) => autoderef_count,
522                 Some(_) | None => 0,
523             };
524
525             debug!("fixup_derefs_on_method_receiver_if_necessary: i={} expr={} autoderef_count={}",
526                    i, expr.repr(self.tcx()), autoderef_count);
527
528             if autoderef_count > 0 {
529                 check::autoderef(self.fcx,
530                                  expr.span,
531                                  self.fcx.expr_ty(expr),
532                                  Some(expr),
533                                  UnresolvedTypeAction::Error,
534                                  PreferMutLvalue,
535                                  |_, autoderefs| {
536                                      if autoderefs == autoderef_count + 1 {
537                                          Some(())
538                                      } else {
539                                          None
540                                      }
541                                  });
542             }
543
544             // Don't retry the first one or we might infinite loop!
545             if i != 0 {
546                 match expr.node {
547                     ast::ExprIndex(ref base_expr, ref index_expr) => {
548                         let mut base_adjustment =
549                             match self.fcx.inh.adjustments.borrow().get(&base_expr.id) {
550                                 Some(&ty::AdjustDerefRef(ref adr)) => (*adr).clone(),
551                                 None => ty::AutoDerefRef { autoderefs: 0, autoref: None },
552                                 Some(_) => {
553                                     self.tcx().sess.span_bug(
554                                         base_expr.span,
555                                         "unexpected adjustment type");
556                                 }
557                             };
558
559                         // If this is an overloaded index, the
560                         // adjustment will include an extra layer of
561                         // autoref because the method is an &self/&mut
562                         // self method. We have to peel it off to get
563                         // the raw adjustment that `try_index_step`
564                         // expects. This is annoying and horrible. We
565                         // ought to recode this routine so it doesn't
566                         // (ab)use the normal type checking paths.
567                         base_adjustment.autoref = match base_adjustment.autoref {
568                             None => { None }
569                             Some(ty::AutoPtr(_, _, None)) => { None }
570                             Some(ty::AutoPtr(_, _, Some(box r))) => { Some(r) }
571                             Some(_) => {
572                                 self.tcx().sess.span_bug(
573                                     base_expr.span,
574                                     "unexpected adjustment autoref");
575                             }
576                         };
577
578                         let adjusted_base_ty =
579                             self.fcx.adjust_expr_ty(
580                                 &**base_expr,
581                                 Some(&ty::AdjustDerefRef(base_adjustment.clone())));
582                         let index_expr_ty = self.fcx.expr_ty(&**index_expr);
583
584                         let result = check::try_index_step(
585                             self.fcx,
586                             MethodCall::expr(expr.id),
587                             expr,
588                             &**base_expr,
589                             adjusted_base_ty,
590                             base_adjustment,
591                             PreferMutLvalue,
592                             index_expr_ty);
593
594                         if let Some((input_ty, return_ty)) = result {
595                             demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty);
596
597                             let expr_ty = self.fcx.expr_ty(&*expr);
598                             demand::suptype(self.fcx, expr.span, expr_ty, return_ty);
599                         }
600                     }
601                     ast::ExprUnary(ast::UnDeref, ref base_expr) => {
602                         // if this is an overloaded deref, then re-evaluate with
603                         // a preference for mut
604                         let method_call = MethodCall::expr(expr.id);
605                         if self.fcx.inh.method_map.borrow().contains_key(&method_call) {
606                             check::try_overloaded_deref(
607                                 self.fcx,
608                                 expr.span,
609                                 Some(method_call),
610                                 Some(&**base_expr),
611                                 self.fcx.expr_ty(&**base_expr),
612                                 PreferMutLvalue);
613                         }
614                     }
615                     _ => {}
616                 }
617             }
618         }
619     }
620
621     ///////////////////////////////////////////////////////////////////////////
622     // MISCELLANY
623
624     fn tcx(&self) -> &'a ty::ctxt<'tcx> {
625         self.fcx.tcx()
626     }
627
628     fn infcx(&self) -> &'a InferCtxt<'a, 'tcx> {
629         self.fcx.infcx()
630     }
631
632     fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
633         // Disallow calls to the method `drop` defined in the `Drop` trait.
634         match pick.method_ty.container {
635             ty::TraitContainer(trait_def_id) => {
636                 callee::check_legal_trait_for_method_call(self.fcx.ccx, self.span, trait_def_id)
637             }
638             ty::ImplContainer(..) => {
639                 // Since `drop` is a trait method, we expect that any
640                 // potential calls to it will wind up in the other
641                 // arm. But just to be sure, check that the method id
642                 // does not appear in the list of destructors.
643                 assert!(!self.tcx().destructors.borrow().contains(&pick.method_ty.def_id));
644             }
645         }
646     }
647
648     fn upcast(&mut self,
649               source_trait_ref: ty::PolyTraitRef<'tcx>,
650               target_trait_def_id: ast::DefId)
651               -> ty::PolyTraitRef<'tcx>
652     {
653         match traits::upcast(self.tcx(), source_trait_ref.clone(), target_trait_def_id) {
654             Some(super_trait_ref) => super_trait_ref,
655             None => {
656                 self.tcx().sess.span_bug(
657                     self.span,
658                     &format!("cannot upcast `{}` to `{}`",
659                              source_trait_ref.repr(self.tcx()),
660                              target_trait_def_id.repr(self.tcx())));
661             }
662         }
663     }
664
665     fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &ty::Binder<T>) -> T
666         where T : TypeFoldable<'tcx> + Repr<'tcx>
667     {
668         self.infcx().replace_late_bound_regions_with_fresh_var(
669             self.span, infer::FnCall, value).0
670     }
671 }
672
673 fn wrap_autoref<'tcx, F>(mut deref: ty::AutoDerefRef<'tcx>,
674                          base_fn: F)
675                          -> ty::AutoDerefRef<'tcx> where
676     F: FnOnce(Option<Box<ty::AutoRef<'tcx>>>) -> ty::AutoRef<'tcx>,
677 {
678     let autoref = mem::replace(&mut deref.autoref, None);
679     let autoref = autoref.map(|r| box r);
680     deref.autoref = Some(base_fn(autoref));
681     deref
682 }