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