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