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, NoPreference, PreferMutLvalue, callee, demand}
;
14 use check
::UnresolvedTypeAction
;
15 use middle
::mem_categorization
::Typer
;
16 use middle
::subst
::{self}
;
18 use middle
::ty
::{self, Ty}
;
19 use middle
::ty
::{MethodCall
, MethodCallee
, MethodObject
, MethodOrigin
,
20 MethodParam
, MethodStatic
, MethodTraitObject
, MethodTypeParam
};
21 use middle
::ty_fold
::TypeFoldable
;
23 use middle
::infer
::InferCtxt
;
25 use syntax
::codemap
::Span
;
26 use std
::iter
::repeat
;
27 use util
::ppaux
::Repr
;
29 struct ConfirmContext
<'a
, 'tcx
:'a
> {
30 fcx
: &'a FnCtxt
<'a
, 'tcx
>,
32 self_expr
: &'tcx ast
::Expr
,
33 call_expr
: &'tcx ast
::Expr
,
36 struct InstantiatedMethodSig
<'tcx
> {
37 /// Function signature of the method being invoked. The 0th
38 /// argument is the receiver.
39 method_sig
: ty
::FnSig
<'tcx
>,
41 /// Substitutions for all types/early-bound-regions declared on
43 all_substs
: subst
::Substs
<'tcx
>,
45 /// Generic bounds on the method's parameters which must be added
46 /// as pending obligations.
47 method_predicates
: ty
::InstantiatedPredicates
<'tcx
>,
50 pub fn confirm
<'a
, 'tcx
>(fcx
: &FnCtxt
<'a
, 'tcx
>,
52 self_expr
: &'tcx ast
::Expr
,
53 call_expr
: &'tcx ast
::Expr
,
54 unadjusted_self_ty
: Ty
<'tcx
>,
55 pick
: probe
::Pick
<'tcx
>,
56 supplied_method_types
: Vec
<Ty
<'tcx
>>)
59 debug
!("confirm(unadjusted_self_ty={}, pick={}, supplied_method_types={})",
60 unadjusted_self_ty
.repr(fcx
.tcx()),
62 supplied_method_types
.repr(fcx
.tcx()));
64 let mut confirm_cx
= ConfirmContext
::new(fcx
, span
, self_expr
, call_expr
);
65 confirm_cx
.confirm(unadjusted_self_ty
, pick
, supplied_method_types
)
68 impl<'a
,'tcx
> ConfirmContext
<'a
,'tcx
> {
69 fn new(fcx
: &'a FnCtxt
<'a
, 'tcx
>,
71 self_expr
: &'tcx ast
::Expr
,
72 call_expr
: &'tcx ast
::Expr
)
73 -> ConfirmContext
<'a
, 'tcx
>
75 ConfirmContext { fcx: fcx, span: span, self_expr: self_expr, call_expr: call_expr }
79 unadjusted_self_ty
: Ty
<'tcx
>,
80 pick
: probe
::Pick
<'tcx
>,
81 supplied_method_types
: Vec
<Ty
<'tcx
>>)
84 // Adjust the self expression the user provided and obtain the adjusted type.
85 let self_ty
= self.adjust_self_ty(unadjusted_self_ty
, &pick
);
87 // Make sure nobody calls `drop()` explicitly.
88 self.enforce_illegal_method_limitations(&pick
);
90 // Create substitutions for the method's type parameters.
91 let (rcvr_substs
, method_origin
) =
92 self.fresh_receiver_substs(self_ty
, &pick
);
93 let (method_types
, method_regions
) =
94 self.instantiate_method_substs(&pick
, supplied_method_types
);
95 let all_substs
= rcvr_substs
.with_method(method_types
, method_regions
);
96 debug
!("all_substs={}", all_substs
.repr(self.tcx()));
98 // Create the final signature for the method, replacing late-bound regions.
99 let InstantiatedMethodSig
{
100 method_sig
, all_substs
, method_predicates
101 } = self.instantiate_method_sig(&pick
, 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 // Add any trait/regions obligations specified on the method's type parameters.
108 self.add_obligations(&pick
, &all_substs
, &method_predicates
);
110 // Create the final `MethodCallee`.
111 let method_ty
= pick
.item
.as_opt_method().unwrap();
112 let fty
= ty
::mk_bare_fn(self.tcx(), None
, self.tcx().mk_bare_fn(ty
::BareFnTy
{
113 sig
: ty
::Binder(method_sig
),
114 unsafety
: method_ty
.fty
.unsafety
,
115 abi
: method_ty
.fty
.abi
.clone(),
117 let callee
= MethodCallee
{
118 origin
: method_origin
,
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
);
131 ///////////////////////////////////////////////////////////////////////////
134 fn adjust_self_ty(&mut self,
135 unadjusted_self_ty
: Ty
<'tcx
>,
136 pick
: &probe
::Pick
<'tcx
>)
139 let (autoref
, unsize
) = if let Some(mutbl
) = pick
.autoref
{
140 let region
= self.infcx().next_region_var(infer
::Autoref(self.span
));
141 let autoref
= ty
::AutoPtr(self.tcx().mk_region(region
), mutbl
);
142 (Some(autoref
), pick
.unsize
.map(|target
| {
143 ty
::adjust_ty_for_autoref(self.tcx(), target
, Some(autoref
))
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());
154 // Commit the autoderefs by calling `autoderef again, but this
155 // time writing the results into the various tables.
156 let (autoderefd_ty
, n
, result
) = check
::autoderef(self.fcx
,
159 Some(self.self_expr
),
160 UnresolvedTypeAction
::Error
,
163 if n
== pick
.autoderefs
{
169 assert_eq
!(n
, pick
.autoderefs
);
170 assert_eq
!(result
, Some(()));
172 // Write out the final adjustment.
173 self.fcx
.write_adjustment(self.self_expr
.id
,
174 ty
::AdjustDerefRef(ty
::AutoDerefRef
{
175 autoderefs
: pick
.autoderefs
,
180 if let Some(target
) = unsize
{
183 ty
::adjust_ty_for_autoref(self.tcx(), autoderefd_ty
, autoref
)
187 ///////////////////////////////////////////////////////////////////////////
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.
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,
198 pick
: &probe
::Pick
<'tcx
>)
199 -> (subst
::Substs
<'tcx
>, MethodOrigin
<'tcx
>)
202 probe
::InherentImplPick(impl_def_id
) => {
203 assert
!(ty
::impl_trait_ref(self.tcx(), impl_def_id
).is_none(),
204 "impl {:?} is not an inherent impl", impl_def_id
);
205 let impl_polytype
= check
::impl_self_ty(self.fcx
, self.span
, impl_def_id
);
207 (impl_polytype
.substs
, MethodStatic(pick
.item
.def_id()))
210 probe
::ObjectPick(trait_def_id
, method_num
, vtable_index
) => {
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
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
);
228 debug
!("original_poly_trait_ref={} upcast_trait_ref={} target_trait={}",
229 original_poly_trait_ref
.repr(this
.tcx()),
230 upcast_trait_ref
.repr(this
.tcx()),
231 trait_def_id
.repr(this
.tcx()));
232 let substs
= upcast_trait_ref
.substs
.clone();
233 let origin
= MethodTraitObject(MethodObject
{
234 trait_ref
: upcast_trait_ref
,
235 object_trait_id
: trait_def_id
,
236 method_num
: method_num
,
237 vtable_index
: vtable_index
,
243 probe
::ExtensionImplPick(impl_def_id
, method_num
) => {
244 // The method being invoked is the method as defined on the trait,
245 // so return the substitutions from the trait. Consider:
247 // impl<A,B,C> Trait<A,B> for Foo<C> { ... }
249 // If we instantiate A, B, and C with $A, $B, and $C
250 // respectively, then we want to return the type
251 // parameters from the trait ([$A,$B]), not those from
252 // the impl ([$A,$B,$C]) not the receiver type ([$C]).
253 let impl_polytype
= check
::impl_self_ty(self.fcx
, self.span
, impl_def_id
);
255 self.fcx
.instantiate_type_scheme(
257 &impl_polytype
.substs
,
258 &ty
::impl_trait_ref(self.tcx(), impl_def_id
).unwrap());
259 let origin
= MethodTypeParam(MethodParam
{ trait_ref
: impl_trait_ref
.clone(),
260 method_num
: method_num
,
261 impl_def_id
: Some(impl_def_id
) });
262 (impl_trait_ref
.substs
.clone(), origin
)
265 probe
::TraitPick(trait_def_id
, method_num
) => {
266 let trait_def
= ty
::lookup_trait_def(self.tcx(), trait_def_id
);
268 // Make a trait reference `$0 : Trait<$1...$n>`
269 // consisting entirely of type variables. Later on in
270 // the process we will unify the transformed-self-type
271 // of the method with the actual type in order to
272 // unify some of these variables.
273 let substs
= self.infcx().fresh_substs_for_trait(self.span
,
275 self.infcx().next_ty_var());
278 ty
::TraitRef
::new(trait_def_id
, self.tcx().mk_substs(substs
.clone()));
279 let origin
= MethodTypeParam(MethodParam
{ trait_ref
: trait_ref
,
280 method_num
: method_num
,
281 impl_def_id
: None
});
285 probe
::WhereClausePick(ref poly_trait_ref
, method_num
) => {
286 // Where clauses can have bound regions in them. We need to instantiate
287 // those to convert from a poly-trait-ref to a trait-ref.
288 let trait_ref
= self.replace_late_bound_regions_with_fresh_var(&*poly_trait_ref
);
289 let substs
= trait_ref
.substs
.clone();
290 let origin
= MethodTypeParam(MethodParam
{ trait_ref
: trait_ref
,
291 method_num
: method_num
,
292 impl_def_id
: None
});
298 fn extract_trait_ref
<R
, F
>(&mut self, self_ty
: Ty
<'tcx
>, mut closure
: F
) -> R
where
299 F
: FnMut(&mut ConfirmContext
<'a
, 'tcx
>, Ty
<'tcx
>, &ty
::TyTrait
<'tcx
>) -> R
,
301 // If we specified that this is an object method, then the
302 // self-type ought to be something that can be dereferenced to
303 // yield an object-type (e.g., `&Object` or `Box<Object>`
306 let (_
, _
, result
) = check
::autoderef(self.fcx
,
310 UnresolvedTypeAction
::Error
,
314 ty
::ty_trait(ref data
) => Some(closure(self, ty
, &**data
)),
322 self.tcx().sess
.span_bug(
324 &format
!("self-type `{}` for ObjectPick never dereferenced to an object",
325 self_ty
.repr(self.tcx())))
330 fn instantiate_method_substs(&mut self,
331 pick
: &probe
::Pick
<'tcx
>,
332 supplied_method_types
: Vec
<Ty
<'tcx
>>)
333 -> (Vec
<Ty
<'tcx
>>, Vec
<ty
::Region
>)
335 // Determine the values for the generic parameters of the method.
336 // If they were not explicitly supplied, just construct fresh
338 let num_supplied_types
= supplied_method_types
.len();
339 let num_method_types
= pick
.item
.as_opt_method().unwrap()
340 .generics
.types
.len(subst
::FnSpace
);
342 if num_supplied_types
== 0 {
343 self.fcx
.infcx().next_ty_vars(num_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().next_ty_vars(num_method_types
)
348 } else if num_supplied_types
!= num_method_types
{
349 span_err
!(self.tcx().sess
, self.span
, E0036
,
350 "incorrect number of type parameters given for this method");
351 repeat(self.tcx().types
.err
).take(num_method_types
).collect()
353 supplied_method_types
357 // Create subst for early-bound lifetime parameters, combining
358 // parameters from the type and those from the method.
360 // FIXME -- permit users to manually specify lifetimes
362 self.fcx
.infcx().region_vars_for_defs(
364 pick
.item
.as_opt_method().unwrap()
365 .generics
.regions
.get_slice(subst
::FnSpace
));
367 (method_types
, method_regions
)
370 fn unify_receivers(&mut self,
372 method_self_ty
: Ty
<'tcx
>)
374 match self.fcx
.mk_subty(false, infer
::Misc(self.span
), self_ty
, method_self_ty
) {
377 self.tcx().sess
.span_bug(
380 "{} was a subtype of {} but now is not?",
381 self_ty
.repr(self.tcx()),
382 method_self_ty
.repr(self.tcx())));
387 ///////////////////////////////////////////////////////////////////////////
390 fn instantiate_method_sig(&mut self,
391 pick
: &probe
::Pick
<'tcx
>,
392 all_substs
: subst
::Substs
<'tcx
>)
393 -> InstantiatedMethodSig
<'tcx
>
395 debug
!("instantiate_method_sig(pick={}, all_substs={})",
396 pick
.repr(self.tcx()),
397 all_substs
.repr(self.tcx()));
399 // Instantiate the bounds on the method with the
400 // type/early-bound-regions substitutions performed. There can
401 // be no late-bound regions appearing here.
402 let method_predicates
= pick
.item
.as_opt_method().unwrap()
403 .predicates
.instantiate(self.tcx(), &all_substs
);
404 let method_predicates
= self.fcx
.normalize_associated_types_in(self.span
,
407 debug
!("method_predicates after subst = {}",
408 method_predicates
.repr(self.tcx()));
410 // Instantiate late-bound regions and substitute the trait
411 // parameters into the method type to get the actual method type.
413 // NB: Instantiate late-bound regions first so that
414 // `instantiate_type_scheme` can normalize associated types that
415 // may reference those regions.
416 let method_sig
= self.replace_late_bound_regions_with_fresh_var(
417 &pick
.item
.as_opt_method().unwrap().fty
.sig
);
418 debug
!("late-bound lifetimes from method instantiated, method_sig={}",
419 method_sig
.repr(self.tcx()));
421 let method_sig
= self.fcx
.instantiate_type_scheme(self.span
, &all_substs
, &method_sig
);
422 debug
!("type scheme substituted, method_sig={}",
423 method_sig
.repr(self.tcx()));
425 InstantiatedMethodSig
{
426 method_sig
: method_sig
,
427 all_substs
: all_substs
,
428 method_predicates
: method_predicates
,
432 fn add_obligations(&mut self,
433 pick
: &probe
::Pick
<'tcx
>,
434 all_substs
: &subst
::Substs
<'tcx
>,
435 method_predicates
: &ty
::InstantiatedPredicates
<'tcx
>) {
436 debug
!("add_obligations: pick={} all_substs={} method_predicates={}",
437 pick
.repr(self.tcx()),
438 all_substs
.repr(self.tcx()),
439 method_predicates
.repr(self.tcx()));
441 self.fcx
.add_obligations_for_parameters(
442 traits
::ObligationCause
::misc(self.span
, self.fcx
.body_id
),
445 self.fcx
.add_default_region_param_bounds(
450 ///////////////////////////////////////////////////////////////////////////
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`
456 fn fixup_derefs_on_method_receiver_if_necessary(&self,
457 method_callee
: &MethodCallee
) {
458 let sig
= match method_callee
.ty
.sty
{
459 ty
::ty_bare_fn(_
, ref f
) => f
.sig
.clone(),
463 match sig
.0.inputs
[0].sty
{
464 ty
::ty_rptr(_
, ty
::mt
{
466 mutbl
: ast
::MutMutable
,
471 // Gather up expressions we want to munge.
472 let mut exprs
= Vec
::new();
473 exprs
.push(self.self_expr
);
475 let last
= exprs
[exprs
.len() - 1];
477 ast
::ExprParen(ref expr
) |
478 ast
::ExprField(ref expr
, _
) |
479 ast
::ExprTupField(ref expr
, _
) |
480 ast
::ExprIndex(ref expr
, _
) |
481 ast
::ExprUnary(ast
::UnDeref
, ref expr
) => exprs
.push(&**expr
),
486 debug
!("fixup_derefs_on_method_receiver_if_necessary: exprs={}",
487 exprs
.repr(self.tcx()));
489 // Fix up autoderefs and derefs.
490 for (i
, &expr
) in exprs
.iter().rev().enumerate() {
492 let autoderef_count
= match self.fcx
497 Some(&ty
::AdjustDerefRef(ref adj
)) => adj
.autoderefs
,
501 debug
!("fixup_derefs_on_method_receiver_if_necessary: i={} expr={} autoderef_count={}",
502 i
, expr
.repr(self.tcx()), autoderef_count
);
504 if autoderef_count
> 0 {
505 check
::autoderef(self.fcx
,
507 self.fcx
.expr_ty(expr
),
509 UnresolvedTypeAction
::Error
,
512 if autoderefs
== autoderef_count
+ 1 {
520 // Don't retry the first one or we might infinite loop!
523 ast
::ExprIndex(ref base_expr
, ref index_expr
) => {
524 // If this is an overloaded index, the
525 // adjustment will include an extra layer of
526 // autoref because the method is an &self/&mut
527 // self method. We have to peel it off to get
528 // the raw adjustment that `try_index_step`
529 // expects. This is annoying and horrible. We
530 // ought to recode this routine so it doesn't
531 // (ab)use the normal type checking paths.
532 let adj
= self.fcx
.inh
.adjustments
.borrow().get(&base_expr
.id
).cloned();
533 let (autoderefs
, unsize
) = match adj
{
534 Some(ty
::AdjustDerefRef(adr
)) => match adr
.autoref
{
536 assert
!(adr
.unsize
.is_none());
537 (adr
.autoderefs
, None
)
539 Some(ty
::AutoPtr(_
, _
)) => {
540 (adr
.autoderefs
, adr
.unsize
.map(|target
| {
541 ty
::deref(target
, false)
542 .expect("fixup: AutoPtr is not &T").ty
546 self.tcx().sess
.span_bug(
548 &format
!("unexpected adjustment autoref {}",
549 adr
.repr(self.tcx())));
554 self.tcx().sess
.span_bug(
556 "unexpected adjustment type");
560 let (adjusted_base_ty
, unsize
) = if let Some(target
) = unsize
{
563 (self.fcx
.adjust_expr_ty(base_expr
,
564 Some(&ty
::AdjustDerefRef(ty
::AutoDerefRef
{
565 autoderefs
: autoderefs
,
570 let index_expr_ty
= self.fcx
.expr_ty(&**index_expr
);
572 let result
= check
::try_index_step(
574 MethodCall
::expr(expr
.id
),
583 if let Some((input_ty
, return_ty
)) = result
{
584 demand
::suptype(self.fcx
, index_expr
.span
, input_ty
, index_expr_ty
);
586 let expr_ty
= self.fcx
.expr_ty(&*expr
);
587 demand
::suptype(self.fcx
, expr
.span
, expr_ty
, return_ty
);
590 ast
::ExprUnary(ast
::UnDeref
, ref base_expr
) => {
591 // if this is an overloaded deref, then re-evaluate with
592 // a preference for mut
593 let method_call
= MethodCall
::expr(expr
.id
);
594 if self.fcx
.inh
.method_map
.borrow().contains_key(&method_call
) {
595 check
::try_overloaded_deref(
600 self.fcx
.expr_ty(&**base_expr
),
610 ///////////////////////////////////////////////////////////////////////////
613 fn tcx(&self) -> &'a ty
::ctxt
<'tcx
> {
617 fn infcx(&self) -> &'a InferCtxt
<'a
, 'tcx
> {
621 fn enforce_illegal_method_limitations(&self, pick
: &probe
::Pick
) {
622 // Disallow calls to the method `drop` defined in the `Drop` trait.
623 match pick
.item
.container() {
624 ty
::TraitContainer(trait_def_id
) => {
625 callee
::check_legal_trait_for_method_call(self.fcx
.ccx
, self.span
, trait_def_id
)
627 ty
::ImplContainer(..) => {
628 // Since `drop` is a trait method, we expect that any
629 // potential calls to it will wind up in the other
630 // arm. But just to be sure, check that the method id
631 // does not appear in the list of destructors.
632 assert
!(!self.tcx().destructors
.borrow().contains(&pick
.item
.def_id()));
638 source_trait_ref
: ty
::PolyTraitRef
<'tcx
>,
639 target_trait_def_id
: ast
::DefId
)
640 -> ty
::PolyTraitRef
<'tcx
>
642 let upcast_trait_refs
= traits
::upcast(self.tcx(),
643 source_trait_ref
.clone(),
644 target_trait_def_id
);
646 // must be exactly one trait ref or we'd get an ambig error etc
647 if upcast_trait_refs
.len() != 1 {
648 self.tcx().sess
.span_bug(
650 &format
!("cannot uniquely upcast `{}` to `{}`: `{}`",
651 source_trait_ref
.repr(self.tcx()),
652 target_trait_def_id
.repr(self.tcx()),
653 upcast_trait_refs
.repr(self.tcx())));
656 upcast_trait_refs
.into_iter().next().unwrap()
659 fn replace_late_bound_regions_with_fresh_var
<T
>(&self, value
: &ty
::Binder
<T
>) -> T
660 where T
: TypeFoldable
<'tcx
> + Repr
<'tcx
>
662 self.infcx().replace_late_bound_regions_with_fresh_var(
663 self.span
, infer
::FnCall
, value
).0