1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use check
::{self, FnCtxt, callee, demand}
;
14 use check
::UnresolvedTypeAction
;
15 use hir
::def_id
::DefId
;
16 use rustc
::ty
::subst
::{self}
;
18 use rustc
::ty
::{self, NoPreference, PreferMutLvalue, Ty, TyCtxt}
;
19 use rustc
::ty
::adjustment
::{AdjustDerefRef, AutoDerefRef, AutoPtr}
;
20 use rustc
::ty
::fold
::TypeFoldable
;
22 use rustc
::infer
::{InferCtxt, TypeOrigin}
;
23 use syntax
::codemap
::Span
;
26 struct ConfirmContext
<'a
, 'tcx
:'a
> {
27 fcx
: &'a FnCtxt
<'a
, 'tcx
>,
29 self_expr
: &'tcx hir
::Expr
,
30 call_expr
: &'tcx hir
::Expr
,
33 struct InstantiatedMethodSig
<'tcx
> {
34 /// Function signature of the method being invoked. The 0th
35 /// argument is the receiver.
36 method_sig
: ty
::FnSig
<'tcx
>,
38 /// Substitutions for all types/early-bound-regions declared on
40 all_substs
: subst
::Substs
<'tcx
>,
42 /// Generic bounds on the method's parameters which must be added
43 /// as pending obligations.
44 method_predicates
: ty
::InstantiatedPredicates
<'tcx
>,
47 pub fn confirm
<'a
, 'tcx
>(fcx
: &FnCtxt
<'a
, 'tcx
>,
49 self_expr
: &'tcx hir
::Expr
,
50 call_expr
: &'tcx hir
::Expr
,
51 unadjusted_self_ty
: Ty
<'tcx
>,
52 pick
: probe
::Pick
<'tcx
>,
53 supplied_method_types
: Vec
<Ty
<'tcx
>>)
54 -> ty
::MethodCallee
<'tcx
>
56 debug
!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
59 supplied_method_types
);
61 let mut confirm_cx
= ConfirmContext
::new(fcx
, span
, self_expr
, call_expr
);
62 confirm_cx
.confirm(unadjusted_self_ty
, pick
, supplied_method_types
)
65 impl<'a
,'tcx
> ConfirmContext
<'a
,'tcx
> {
66 fn new(fcx
: &'a FnCtxt
<'a
, 'tcx
>,
68 self_expr
: &'tcx hir
::Expr
,
69 call_expr
: &'tcx hir
::Expr
)
70 -> ConfirmContext
<'a
, 'tcx
>
72 ConfirmContext { fcx: fcx, span: span, self_expr: self_expr, call_expr: call_expr }
76 unadjusted_self_ty
: Ty
<'tcx
>,
77 pick
: probe
::Pick
<'tcx
>,
78 supplied_method_types
: Vec
<Ty
<'tcx
>>)
79 -> ty
::MethodCallee
<'tcx
>
81 // Adjust the self expression the user provided and obtain the adjusted type.
82 let self_ty
= self.adjust_self_ty(unadjusted_self_ty
, &pick
);
84 // Make sure nobody calls `drop()` explicitly.
85 self.enforce_illegal_method_limitations(&pick
);
87 // Create substitutions for the method's type parameters.
88 let rcvr_substs
= self.fresh_receiver_substs(self_ty
, &pick
);
90 self.instantiate_method_substs(
92 supplied_method_types
,
95 debug
!("all_substs={:?}", all_substs
);
97 // Create the final signature for the method, replacing late-bound regions.
98 let InstantiatedMethodSig
{
99 method_sig
, all_substs
, method_predicates
100 } = self.instantiate_method_sig(&pick
, all_substs
);
101 let all_substs
= self.tcx().mk_substs(all_substs
);
102 let method_self_ty
= method_sig
.inputs
[0];
104 // Unify the (adjusted) self type with what the method expects.
105 self.unify_receivers(self_ty
, method_self_ty
);
107 // Create the method type
108 let def_id
= pick
.item
.def_id();
109 let method_ty
= pick
.item
.as_opt_method().unwrap();
110 let fty
= self.tcx().mk_fn_def(def_id
, all_substs
, ty
::BareFnTy
{
111 sig
: ty
::Binder(method_sig
),
112 unsafety
: method_ty
.fty
.unsafety
,
113 abi
: method_ty
.fty
.abi
.clone(),
116 // Add any trait/regions obligations specified on the method's type parameters.
117 self.add_obligations(fty
, all_substs
, &method_predicates
);
119 // Create the final `MethodCallee`.
120 let callee
= ty
::MethodCallee
{
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
);
133 ///////////////////////////////////////////////////////////////////////////
136 fn adjust_self_ty(&mut self,
137 unadjusted_self_ty
: Ty
<'tcx
>,
138 pick
: &probe
::Pick
<'tcx
>)
141 let (autoref
, unsize
) = if let Some(mutbl
) = pick
.autoref
{
142 let region
= self.infcx().next_region_var(infer
::Autoref(self.span
));
143 let autoref
= AutoPtr(self.tcx().mk_region(region
), mutbl
);
144 (Some(autoref
), pick
.unsize
.map(|target
| {
145 target
.adjust_for_autoref(self.tcx(), Some(autoref
))
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());
156 // Commit the autoderefs by calling `autoderef again, but this
157 // time writing the results into the various tables.
158 let (autoderefd_ty
, n
, result
) = check
::autoderef(self.fcx
,
161 || Some(self.self_expr
),
162 UnresolvedTypeAction
::Error
,
165 if n
== pick
.autoderefs
{
171 assert_eq
!(n
, pick
.autoderefs
);
172 assert_eq
!(result
, Some(()));
174 // Write out the final adjustment.
175 self.fcx
.write_adjustment(self.self_expr
.id
,
176 AdjustDerefRef(AutoDerefRef
{
177 autoderefs
: pick
.autoderefs
,
182 if let Some(target
) = unsize
{
185 autoderefd_ty
.adjust_for_autoref(self.tcx(), autoref
)
189 ///////////////////////////////////////////////////////////////////////////
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.
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,
200 pick
: &probe
::Pick
<'tcx
>)
201 -> subst
::Substs
<'tcx
>
204 probe
::InherentImplPick
=> {
205 let impl_def_id
= pick
.item
.container().id();
206 assert
!(self.tcx().impl_trait_ref(impl_def_id
).is_none(),
207 "impl {:?} is not an inherent impl", impl_def_id
);
208 check
::impl_self_ty(self.fcx
, self.span
, impl_def_id
).substs
211 probe
::ObjectPick
=> {
212 let trait_def_id
= pick
.item
.container().id();
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
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
);
230 debug
!("original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
231 original_poly_trait_ref
,
234 upcast_trait_ref
.substs
.clone()
238 probe
::ExtensionImplPick(impl_def_id
) => {
239 // The method being invoked is the method as defined on the trait,
240 // so return the substitutions from the trait. Consider:
242 // impl<A,B,C> Trait<A,B> for Foo<C> { ... }
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
);
250 self.fcx
.instantiate_type_scheme(
252 &impl_polytype
.substs
,
253 &self.tcx().impl_trait_ref(impl_def_id
).unwrap());
254 impl_trait_ref
.substs
.clone()
257 probe
::TraitPick
=> {
258 let trait_def_id
= pick
.item
.container().id();
259 let trait_def
= self.tcx().lookup_trait_def(trait_def_id
);
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.
266 self.infcx().fresh_substs_for_trait(self.span
,
268 self.infcx().next_ty_var())
271 probe
::WhereClausePick(ref poly_trait_ref
) => {
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.
274 self.replace_late_bound_regions_with_fresh_var(&poly_trait_ref
).substs
.clone()
279 fn extract_trait_ref
<R
, F
>(&mut self, self_ty
: Ty
<'tcx
>, mut closure
: F
) -> R
where
280 F
: FnMut(&mut ConfirmContext
<'a
, 'tcx
>, Ty
<'tcx
>, &ty
::TraitTy
<'tcx
>) -> R
,
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>`
287 let (_
, _
, result
) = check
::autoderef(self.fcx
,
291 UnresolvedTypeAction
::Error
,
295 ty
::TyTrait(ref data
) => Some(closure(self, ty
, &data
)),
305 "self-type `{}` for ObjectPick never dereferenced to an object",
311 fn instantiate_method_substs(&mut self,
312 pick
: &probe
::Pick
<'tcx
>,
313 supplied_method_types
: Vec
<Ty
<'tcx
>>,
314 substs
: subst
::Substs
<'tcx
>)
315 -> subst
::Substs
<'tcx
>
317 // Determine the values for the generic parameters of the method.
318 // If they were not explicitly supplied, just construct fresh
320 let num_supplied_types
= supplied_method_types
.len();
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();
326 // Create subst for early-bound lifetime parameters, combining
327 // parameters from the type and those from the method.
329 // FIXME -- permit users to manually specify lifetimes
331 self.fcx
.infcx().region_vars_for_defs(
333 pick
.item
.as_opt_method().unwrap()
334 .generics
.regions
.get_slice(subst
::FnSpace
));
336 let subst
::Substs { types, regions }
= substs
;
337 let regions
= regions
.with_slice(subst
::FnSpace
, &method_regions
);
338 let mut final_substs
= subst
::Substs { types: types, regions: regions }
;
340 if num_supplied_types
== 0 {
341 self.fcx
.infcx().type_vars_for_defs(
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(
354 } else if num_supplied_types
!= num_method_types
{
355 span_err
!(self.tcx().sess
, self.span
, E0036
,
356 "incorrect number of type parameters given for this method: expected {}, found {}",
357 num_method_types
, num_supplied_types
);
358 final_substs
.types
.replace(
360 vec
![self.tcx().types
.err
; num_method_types
]);
362 final_substs
.types
.replace(subst
::FnSpace
, supplied_method_types
);
368 fn unify_receivers(&mut self,
370 method_self_ty
: Ty
<'tcx
>)
372 match self.fcx
.mk_subty(false, TypeOrigin
::Misc(self.span
), self_ty
, method_self_ty
) {
377 "{} was a subtype of {} but now is not?",
378 self_ty
, method_self_ty
);
383 ///////////////////////////////////////////////////////////////////////////
386 fn instantiate_method_sig(&mut self,
387 pick
: &probe
::Pick
<'tcx
>,
388 all_substs
: subst
::Substs
<'tcx
>)
389 -> InstantiatedMethodSig
<'tcx
>
391 debug
!("instantiate_method_sig(pick={:?}, all_substs={:?})",
395 // Instantiate the bounds on the method with the
396 // type/early-bound-regions substitutions performed. There can
397 // be no late-bound regions appearing here.
398 let method_predicates
= pick
.item
.as_opt_method().unwrap()
399 .predicates
.instantiate(self.tcx(), &all_substs
);
400 let method_predicates
= self.fcx
.normalize_associated_types_in(self.span
,
403 debug
!("method_predicates after subst = {:?}",
406 // Instantiate late-bound regions and substitute the trait
407 // parameters into the method type to get the actual method type.
409 // NB: Instantiate late-bound regions first so that
410 // `instantiate_type_scheme` can normalize associated types that
411 // may reference those regions.
412 let method_sig
= self.replace_late_bound_regions_with_fresh_var(
413 &pick
.item
.as_opt_method().unwrap().fty
.sig
);
414 debug
!("late-bound lifetimes from method instantiated, method_sig={:?}",
417 let method_sig
= self.fcx
.instantiate_type_scheme(self.span
, &all_substs
, &method_sig
);
418 debug
!("type scheme substituted, method_sig={:?}",
421 InstantiatedMethodSig
{
422 method_sig
: method_sig
,
423 all_substs
: all_substs
,
424 method_predicates
: method_predicates
,
428 fn add_obligations(&mut self,
430 all_substs
: &subst
::Substs
<'tcx
>,
431 method_predicates
: &ty
::InstantiatedPredicates
<'tcx
>) {
432 debug
!("add_obligations: fty={:?} all_substs={:?} method_predicates={:?}",
437 self.fcx
.add_obligations_for_parameters(
438 traits
::ObligationCause
::misc(self.span
, self.fcx
.body_id
),
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(
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
);
453 ///////////////////////////////////////////////////////////////////////////
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`
459 fn fixup_derefs_on_method_receiver_if_necessary(&self,
460 method_callee
: &ty
::MethodCallee
) {
461 let sig
= match method_callee
.ty
.sty
{
462 ty
::TyFnDef(_
, _
, ref f
) => f
.sig
.clone(),
466 match sig
.0.inputs
[0].sty
{
467 ty
::TyRef(_
, ty
::TypeAndMut
{
469 mutbl
: hir
::MutMutable
,
474 // Gather up expressions we want to munge.
475 let mut exprs
= Vec
::new();
476 exprs
.push(self.self_expr
);
478 let last
= exprs
[exprs
.len() - 1];
480 hir
::ExprField(ref expr
, _
) |
481 hir
::ExprTupField(ref expr
, _
) |
482 hir
::ExprIndex(ref expr
, _
) |
483 hir
::ExprUnary(hir
::UnDeref
, ref expr
) => exprs
.push(&expr
),
488 debug
!("fixup_derefs_on_method_receiver_if_necessary: exprs={:?}",
491 // Fix up autoderefs and derefs.
492 for (i
, &expr
) in exprs
.iter().rev().enumerate() {
494 let autoderef_count
= match self.fcx
500 Some(&AdjustDerefRef(ref adj
)) => adj
.autoderefs
,
504 debug
!("fixup_derefs_on_method_receiver_if_necessary: i={} expr={:?} \
506 i
, expr
, autoderef_count
);
508 if autoderef_count
> 0 {
509 check
::autoderef(self.fcx
,
511 self.fcx
.expr_ty(expr
),
513 UnresolvedTypeAction
::Error
,
516 if autoderefs
== autoderef_count
+ 1 {
524 // Don't retry the first one or we might infinite loop!
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
)
540 let (autoderefs
, unsize
) = match adj
{
541 Some(AdjustDerefRef(adr
)) => match adr
.autoref
{
543 assert
!(adr
.unsize
.is_none());
544 (adr
.autoderefs
, None
)
546 Some(AutoPtr(_
, _
)) => {
547 (adr
.autoderefs
, adr
.unsize
.map(|target
| {
548 target
.builtin_deref(false, NoPreference
)
549 .expect("fixup: AutoPtr is not &T").ty
555 "unexpected adjustment autoref {:?}",
563 "unexpected adjustment type");
567 let (adjusted_base_ty
, unsize
) = if let Some(target
) = unsize
{
570 (self.fcx
.adjust_expr_ty(base_expr
,
571 Some(&AdjustDerefRef(AutoDerefRef
{
572 autoderefs
: autoderefs
,
577 let index_expr_ty
= self.fcx
.expr_ty(&index_expr
);
579 let result
= check
::try_index_step(
581 ty
::MethodCall
::expr(expr
.id
),
590 if let Some((input_ty
, return_ty
)) = result
{
591 demand
::suptype(self.fcx
, index_expr
.span
, input_ty
, index_expr_ty
);
593 let expr_ty
= self.fcx
.expr_ty(&expr
);
594 demand
::suptype(self.fcx
, expr
.span
, expr_ty
, return_ty
);
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(
606 self.fcx
.expr_ty(&base_expr
),
608 let method
= method
.expect("re-trying deref failed");
609 self.fcx
.inh
.tables
.borrow_mut().method_map
.insert(method_call
, method
);
617 ///////////////////////////////////////////////////////////////////////////
620 fn tcx(&self) -> &'a TyCtxt
<'tcx
> {
624 fn infcx(&self) -> &'a InferCtxt
<'a
, 'tcx
> {
628 fn enforce_illegal_method_limitations(&self, pick
: &probe
::Pick
) {
629 // Disallow calls to the method `drop` defined in the `Drop` trait.
630 match pick
.item
.container() {
631 ty
::TraitContainer(trait_def_id
) => {
632 callee
::check_legal_trait_for_method_call(self.fcx
.ccx
, self.span
, trait_def_id
)
634 ty
::ImplContainer(..) => {}
639 source_trait_ref
: ty
::PolyTraitRef
<'tcx
>,
640 target_trait_def_id
: DefId
)
641 -> ty
::PolyTraitRef
<'tcx
>
643 let upcast_trait_refs
= traits
::upcast(self.tcx(),
644 source_trait_ref
.clone(),
645 target_trait_def_id
);
647 // must be exactly one trait ref or we'd get an ambig error etc
648 if upcast_trait_refs
.len() != 1 {
651 "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
657 upcast_trait_refs
.into_iter().next().unwrap()
660 fn replace_late_bound_regions_with_fresh_var
<T
>(&self, value
: &ty
::Binder
<T
>) -> T
661 where T
: TypeFoldable
<'tcx
>
663 self.infcx().replace_late_bound_regions_with_fresh_var(
664 self.span
, infer
::FnCall
, value
).0