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