]> git.proxmox.com Git - rustc.git/blame - src/librustc_typeck/check/coercion.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_typeck / check / coercion.rs
CommitLineData
1a4d82fc
JJ
1// Copyright 2012 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//! # Type Coercion
12//!
13//! Under certain circumstances we will coerce from one type to another,
14//! for example by auto-borrowing. This occurs in situations where the
15//! compiler has a firm 'expected type' that was supplied from the user,
16//! and where the actual type is similar to that expected type in purpose
17//! but not in representation (so actual subtyping is inappropriate).
18//!
19//! ## Reborrowing
20//!
21//! Note that if we are expecting a reference, we will *reborrow*
22//! even if the argument provided was already a reference. This is
23//! useful for freezing mut/const things (that is, when the expected is &T
24//! but you have &const T or &mut T) and also for avoiding the linearity
25//! of mut things (when the expected is &mut T and you have &mut T). See
26//! the various `src/test/run-pass/coerce-reborrow-*.rs` tests for
27//! examples of where this is useful.
28//!
29//! ## Subtle note
30//!
31//! When deciding what type coercions to consider, we do not attempt to
32//! resolve any type variables we may encounter. This is because `b`
33//! represents the expected type "as the user wrote it", meaning that if
34//! the user defined a generic function like
35//!
36//! fn foo<A>(a: A, b: A) { ... }
37//!
38//! and then we wrote `foo(&1, @2)`, we will not auto-borrow
39//! either argument. In older code we went to some lengths to
40//! resolve the `b` variable, which could mean that we'd
41//! auto-borrow later arguments but not earlier ones, which
42//! seems very confusing.
43//!
44//! ## Subtler note
45//!
46//! However, right now, if the user manually specifies the
47//! values for the type variables, as so:
48//!
49//! foo::<&int>(@1, @2)
50//!
51//! then we *will* auto-borrow, because we can't distinguish this from a
52//! function that declared `&int`. This is inconsistent but it's easiest
53//! at the moment. The right thing to do, I think, is to consider the
54//! *unsubstituted* type when deciding whether to auto-borrow, but the
55//! *substituted* type when considering the bounds and so forth. But most
56//! of our methods don't give access to the unsubstituted type, and
57//! rightly so because they'd be error-prone. So maybe the thing to do is
58//! to actually determine the kind of coercions that should occur
59//! separately and pass them in. Or maybe it's ok as is. Anyway, it's
60//! sort of a minor point so I've opted to leave it for later---after all
61//! we may want to adjust precisely when coercions occur.
62
e9174d1e 63use check::{autoderef, FnCtxt, UnresolvedTypeAction};
1a4d82fc 64
54a0048b
SL
65use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace};
66use rustc::traits::{self, ObligationCause};
67use rustc::traits::{predicate_for_trait_def, report_selection_error};
68use rustc::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
69use rustc::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
70use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
71use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty, TyCtxt};
72use rustc::ty::fold::TypeFoldable;
73use rustc::ty::error::TypeError;
74use rustc::ty::relate::{RelateResult, TypeRelation};
85aaf69f 75use util::common::indent;
1a4d82fc 76
d9579d0f
AL
77use std::cell::RefCell;
78use std::collections::VecDeque;
54a0048b 79use rustc::hir;
1a4d82fc 80
85aaf69f
SL
81struct Coerce<'a, 'tcx: 'a> {
82 fcx: &'a FnCtxt<'a, 'tcx>,
54a0048b
SL
83 origin: TypeOrigin,
84 use_lub: bool,
d9579d0f 85 unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
85aaf69f
SL
86}
87
54a0048b
SL
88type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, AutoAdjustment<'tcx>)>;
89
90fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
91 to_mutbl: hir::Mutability)
92 -> RelateResult<'tcx, ()> {
93 match (from_mutbl, to_mutbl) {
94 (hir::MutMutable, hir::MutMutable) |
95 (hir::MutImmutable, hir::MutImmutable) |
96 (hir::MutMutable, hir::MutImmutable) => Ok(()),
97 (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability)
98 }
99}
1a4d82fc
JJ
100
101impl<'f, 'tcx> Coerce<'f, 'tcx> {
54a0048b
SL
102 fn new(fcx: &'f FnCtxt<'f, 'tcx>, origin: TypeOrigin) -> Self {
103 Coerce {
104 fcx: fcx,
105 origin: origin,
106 use_lub: false,
107 unsizing_obligations: RefCell::new(vec![])
108 }
109 }
110
111 fn tcx(&self) -> &TyCtxt<'tcx> {
85aaf69f 112 self.fcx.tcx()
1a4d82fc
JJ
113 }
114
54a0048b
SL
115 fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
116 let infcx = self.fcx.infcx();
117 infcx.commit_if_ok(|_| {
118 let trace = TypeTrace::types(self.origin, false, a, b);
119 if self.use_lub {
120 infcx.lub(false, trace, &a, &b)
121 .map(|InferOk { value, obligations }| {
122 // FIXME(#32730) propagate obligations
123 assert!(obligations.is_empty());
124 value
125 })
126 } else {
127 infcx.sub(false, trace, &a, &b)
128 .map(|InferOk { value, obligations }| {
129 // FIXME(#32730) propagate obligations
130 assert!(obligations.is_empty());
131 value
132 })
133 }
134 })
85aaf69f
SL
135 }
136
54a0048b
SL
137 /// Unify two types (using sub or lub) and produce a noop coercion.
138 fn unify_and_identity(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
139 self.unify(&a, &b).and_then(|ty| self.identity(ty))
1a4d82fc
JJ
140 }
141
54a0048b
SL
142 /// Synthesize an identity adjustment.
143 fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> {
144 Ok((ty, AdjustDerefRef(AutoDerefRef {
145 autoderefs: 0,
146 autoref: None,
147 unsize: None
148 })))
149 }
150
151 fn coerce<'a, E, I>(&self,
152 exprs: &E,
153 a: Ty<'tcx>,
154 b: Ty<'tcx>)
155 -> CoerceResult<'tcx>
156 // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
157 where E: Fn() -> I,
158 I: IntoIterator<Item=&'a hir::Expr> {
1a4d82fc 159
92a42be0 160 let a = self.fcx.infcx().shallow_resolve(a);
54a0048b 161 debug!("Coerce.tys({:?} => {:?})", a, b);
92a42be0
SL
162
163 // Just ignore error types.
164 if a.references_error() || b.references_error() {
54a0048b 165 return self.identity(b);
92a42be0
SL
166 }
167
1a4d82fc 168 // Consider coercing the subtype to a DST
92a42be0 169 let unsize = self.coerce_unsized(a, b);
1a4d82fc
JJ
170 if unsize.is_ok() {
171 return unsize;
172 }
173
174 // Examine the supertype and consider auto-borrowing.
175 //
176 // Note: does not attempt to resolve type variables we encounter.
177 // See above for details.
178 match b.sty {
62682a34 179 ty::TyRawPtr(mt_b) => {
92a42be0 180 return self.coerce_unsafe_ptr(a, b, mt_b.mutbl);
1a4d82fc
JJ
181 }
182
54a0048b
SL
183 ty::TyRef(r_b, mt_b) => {
184 return self.coerce_borrowed_pointer(exprs, a, b, r_b, mt_b);
1a4d82fc
JJ
185 }
186
187 _ => {}
188 }
189
92a42be0 190 match a.sty {
54a0048b 191 ty::TyFnDef(_, _, a_f) => {
92a42be0
SL
192 // Function items are coercible to any closure
193 // type; function pointers are not (that would
194 // require double indirection).
195 self.coerce_from_fn_item(a, a_f, b)
1a4d82fc 196 }
54a0048b 197 ty::TyFnPtr(a_f) => {
92a42be0
SL
198 // We permit coercion of fn pointers to drop the
199 // unsafe qualifier.
200 self.coerce_from_fn_pointer(a, a_f, b)
201 }
202 _ => {
54a0048b
SL
203 // Otherwise, just use unification rules.
204 self.unify_and_identity(a, b)
92a42be0
SL
205 }
206 }
1a4d82fc
JJ
207 }
208
85aaf69f
SL
209 /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
210 /// To match `A` with `B`, autoderef will be performed,
211 /// calling `deref`/`deref_mut` where necessary.
54a0048b
SL
212 fn coerce_borrowed_pointer<'a, E, I>(&self,
213 exprs: &E,
214 a: Ty<'tcx>,
215 b: Ty<'tcx>,
216 r_b: &'tcx ty::Region,
217 mt_b: TypeAndMut<'tcx>)
218 -> CoerceResult<'tcx>
219 // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
220 where E: Fn() -> I,
221 I: IntoIterator<Item=&'a hir::Expr> {
222
223 debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b);
1a4d82fc
JJ
224
225 // If we have a parameter of type `&M T_a` and the value
226 // provided is `expr`, we will be adding an implicit borrow,
227 // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore,
228 // to type check, we will construct the type that `&M*expr` would
229 // yield.
230
54a0048b
SL
231 let (r_a, mt_a) = match a.sty {
232 ty::TyRef(r_a, mt_a) => {
233 coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
234 (r_a, mt_a)
1a4d82fc 235 }
54a0048b
SL
236 _ => return self.unify_and_identity(a, b)
237 };
1a4d82fc 238
54a0048b 239 let span = self.origin.span();
9346a6ac 240
54a0048b 241 let lvalue_pref = LvaluePreference::from_mutbl(mt_b.mutbl);
85aaf69f 242 let mut first_error = None;
54a0048b
SL
243 let mut r_borrow_var = None;
244 let (_, autoderefs, success) = autoderef(self.fcx, span, a, exprs,
85aaf69f
SL
245 UnresolvedTypeAction::Ignore,
246 lvalue_pref,
54a0048b
SL
247 |referent_ty, autoderef|
248 {
85aaf69f
SL
249 if autoderef == 0 {
250 // Don't let this pass, otherwise it would cause
251 // &T to autoref to &&T.
252 return None;
253 }
54a0048b
SL
254
255 // At this point, we have deref'd `a` to `referent_ty`. So
256 // imagine we are coercing from `&'a mut Vec<T>` to `&'b mut [T]`.
257 // In the autoderef loop for `&'a mut Vec<T>`, we would get
258 // three callbacks:
259 //
260 // - `&'a mut Vec<T>` -- 0 derefs, just ignore it
261 // - `Vec<T>` -- 1 deref
262 // - `[T]` -- 2 deref
263 //
264 // At each point after the first callback, we want to
265 // check to see whether this would match out target type
266 // (`&'b mut [T]`) if we autoref'd it. We can't just
267 // compare the referent types, though, because we still
268 // have to consider the mutability. E.g., in the case
269 // we've been considering, we have an `&mut` reference, so
270 // the `T` in `[T]` needs to be unified with equality.
271 //
272 // Therefore, we construct reference types reflecting what
273 // the types will be after we do the final auto-ref and
274 // compare those. Note that this means we use the target
275 // mutability [1], since it may be that we are coercing
276 // from `&mut T` to `&U`.
277 //
278 // One fine point concerns the region that we use. We
279 // choose the region such that the region of the final
280 // type that results from `unify` will be the region we
281 // want for the autoref:
282 //
283 // - if in sub mode, that means we want to use `'b` (the
284 // region from the target reference) for both
285 // pointers [2]. This is because sub mode (somewhat
286 // arbitrarily) returns the subtype region. In the case
287 // where we are coercing to a target type, we know we
288 // want to use that target type region (`'b`) because --
289 // for the program to type-check -- it must be the
290 // smaller of the two.
291 // - One fine point. It may be surprising that we can
292 // use `'b` without relating `'a` and `'b`. The reason
293 // that this is ok is that what we produce is
294 // effectively a `&'b *x` expression (if you could
295 // annotate the region of a borrow), and regionck has
296 // code that adds edges from the region of a borrow
297 // (`'b`, here) into the regions in the borrowed
298 // expression (`*x`, here). (Search for "link".)
299 // - if in lub mode, things can get fairly complicated. The
300 // easiest thing is just to make a fresh
301 // region variable [4], which effectively means we defer
302 // the decision to region inference (and regionck, which will add
303 // some more edges to this variable). However, this can wind up
304 // creating a crippling number of variables in some cases --
305 // e.g. #32278 -- so we optimize one particular case [3].
306 // Let me try to explain with some examples:
307 // - The "running example" above represents the simple case,
308 // where we have one `&` reference at the outer level and
309 // ownership all the rest of the way down. In this case,
310 // we want `LUB('a, 'b)` as the resulting region.
311 // - However, if there are nested borrows, that region is
312 // too strong. Consider a coercion from `&'a &'x Rc<T>` to
313 // `&'b T`. In this case, `'a` is actually irrelevant.
314 // The pointer we want is `LUB('x, 'b`). If we choose `LUB('a,'b)`
315 // we get spurious errors (`run-pass/regions-lub-ref-ref-rc.rs`).
316 // (The errors actually show up in borrowck, typically, because
317 // this extra edge causes the region `'a` to be inferred to something
318 // too big, which then results in borrowck errors.)
319 // - We could track the innermost shared reference, but there is already
320 // code in regionck that has the job of creating links between
321 // the region of a borrow and the regions in the thing being
322 // borrowed (here, `'a` and `'x`), and it knows how to handle
323 // all the various cases. So instead we just make a region variable
324 // and let regionck figure it out.
325 let r = if !self.use_lub {
326 r_b // [2] above
327 } else if autoderef == 1 {
328 r_a // [3] above
85aaf69f 329 } else {
54a0048b
SL
330 if r_borrow_var.is_none() { // create var lazilly, at most once
331 let coercion = Coercion(span);
332 let r = self.fcx.infcx().next_region_var(coercion);
333 r_borrow_var = Some(self.tcx().mk_region(r)); // [4] above
334 }
335 r_borrow_var.unwrap()
336 };
337 let derefd_ty_a = self.tcx().mk_ref(r, TypeAndMut {
338 ty: referent_ty,
339 mutbl: mt_b.mutbl // [1] above
340 });
341 match self.unify(derefd_ty_a, b) {
342 Ok(ty) => Some(ty),
343 Err(err) => {
344 if first_error.is_none() {
345 first_error = Some(err);
346 }
347 None
348 }
85aaf69f
SL
349 }
350 });
351
54a0048b
SL
352 // Extract type or return an error. We return the first error
353 // we got, which should be from relating the "base" type
354 // (e.g., in example above, the failure from relating `Vec<T>`
355 // to the target type), since that should be the least
356 // confusing.
357 let ty = match success {
358 Some(ty) => ty,
85aaf69f 359 None => {
54a0048b
SL
360 let err = first_error.expect("coerce_borrowed_pointer had no error");
361 debug!("coerce_borrowed_pointer: failed with err = {:?}", err);
362 return Err(err);
85aaf69f 363 }
54a0048b
SL
364 };
365
366 // Now apply the autoref. We have to extract the region out of
367 // the final ref type we got.
368 if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 {
369 // As a special case, if we would produce `&'a *x`, that's
370 // a total no-op. We end up with the type `&'a T` just as
371 // we started with. In that case, just skip it
372 // altogether. This is just an optimization.
373 //
374 // Note that for `&mut`, we DO want to reborrow --
375 // otherwise, this would be a move, which might be an
376 // error. For example `foo(self.x)` where `self` and
377 // `self.x` both have `&mut `type would be a move of
378 // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
379 // which is a borrow.
380 assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U
381 return self.identity(ty);
85aaf69f 382 }
54a0048b
SL
383 let r_borrow = match ty.sty {
384 ty::TyRef(r_borrow, _) => r_borrow,
385 _ => span_bug!(span, "expected a ref type, got {:?}", ty)
386 };
387 let autoref = Some(AutoPtr(r_borrow, mt_b.mutbl));
388 debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}",
389 ty, autoderefs, autoref);
390 Ok((ty, AdjustDerefRef(AutoDerefRef {
391 autoderefs: autoderefs,
392 autoref: autoref,
393 unsize: None
394 })))
1a4d82fc
JJ
395 }
396
397
62682a34
SL
398 // &[T; n] or &mut [T; n] -> &[T]
399 // or &mut [T; n] -> &mut [T]
1a4d82fc
JJ
400 // or &Concrete -> &Trait, etc.
401 fn coerce_unsized(&self,
d9579d0f
AL
402 source: Ty<'tcx>,
403 target: Ty<'tcx>)
1a4d82fc 404 -> CoerceResult<'tcx> {
62682a34
SL
405 debug!("coerce_unsized(source={:?}, target={:?})",
406 source,
407 target);
d9579d0f
AL
408
409 let traits = (self.tcx().lang_items.unsize_trait(),
410 self.tcx().lang_items.coerce_unsized_trait());
411 let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits {
412 (u, cu)
413 } else {
414 debug!("Missing Unsize or CoerceUnsized traits");
c1a9b12d 415 return Err(TypeError::Mismatch);
d9579d0f 416 };
1a4d82fc
JJ
417
418 // Note, we want to avoid unnecessary unsizing. We don't want to coerce to
419 // a DST unless we have to. This currently comes out in the wash since
420 // we can't unify [T] with U. But to properly support DST, we need to allow
d9579d0f 421 // that, at which point we will need extra checks on the target here.
1a4d82fc 422
d9579d0f
AL
423 // Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
424 let (source, reborrow) = match (&source.sty, &target.sty) {
62682a34 425 (&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => {
54a0048b 426 coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
d9579d0f
AL
427
428 let coercion = Coercion(self.origin.span());
429 let r_borrow = self.fcx.infcx().next_region_var(coercion);
430 let region = self.tcx().mk_region(r_borrow);
e9174d1e 431 (mt_a.ty, Some(AutoPtr(region, mt_b.mutbl)))
1a4d82fc 432 }
62682a34 433 (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
54a0048b 434 coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
e9174d1e 435 (mt_a.ty, Some(AutoUnsafe(mt_b.mutbl)))
1a4d82fc 436 }
d9579d0f
AL
437 _ => (source, None)
438 };
c1a9b12d 439 let source = source.adjust_for_autoref(self.tcx(), reborrow);
d9579d0f 440
c1a9b12d 441 let mut selcx = traits::SelectionContext::new(self.fcx.infcx());
d9579d0f
AL
442
443 // Use a FIFO queue for this custom fulfillment procedure.
444 let mut queue = VecDeque::new();
445 let mut leftover_predicates = vec![];
446
447 // Create an obligation for `Source: CoerceUnsized<Target>`.
448 let cause = ObligationCause::misc(self.origin.span(), self.fcx.body_id);
449 queue.push_back(predicate_for_trait_def(self.tcx(),
450 cause,
451 coerce_unsized_did,
452 0,
453 source,
454 vec![target]));
455
456 // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
457 // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
458 // inference might unify those two inner type variables later.
459 let traits = [coerce_unsized_did, unsize_did];
460 while let Some(obligation) = queue.pop_front() {
62682a34 461 debug!("coerce_unsized resolve step: {:?}", obligation);
d9579d0f
AL
462 let trait_ref = match obligation.predicate {
463 ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
464 tr.clone()
465 }
466 _ => {
467 leftover_predicates.push(obligation);
468 continue;
469 }
470 };
471 match selcx.select(&obligation.with(trait_ref)) {
472 // Uncertain or unimplemented.
473 Ok(None) | Err(traits::Unimplemented) => {
474 debug!("coerce_unsized: early return - can't prove obligation");
c1a9b12d 475 return Err(TypeError::Mismatch);
c34b1796 476 }
d9579d0f
AL
477
478 // Object safety violations or miscellaneous.
479 Err(err) => {
480 report_selection_error(self.fcx.infcx(), &obligation, &err);
481 // Treat this like an obligation and follow through
482 // with the unsizing - the lack of a coercion should
483 // be silent, as it causes a type mismatch later.
484 }
485
486 Ok(Some(vtable)) => {
62682a34
SL
487 for obligation in vtable.nested_obligations() {
488 queue.push_back(obligation);
489 }
d9579d0f 490 }
1a4d82fc 491 }
d9579d0f
AL
492 }
493
54a0048b 494 *self.unsizing_obligations.borrow_mut() = leftover_predicates;
9346a6ac 495
9346a6ac
AL
496 let adjustment = AutoDerefRef {
497 autoderefs: if reborrow.is_some() { 1 } else { 0 },
498 autoref: reborrow,
499 unsize: Some(target)
500 };
62682a34 501 debug!("Success, coerced with {:?}", adjustment);
54a0048b 502 Ok((target, AdjustDerefRef(adjustment)))
1a4d82fc
JJ
503 }
504
c34b1796
AL
505 fn coerce_from_fn_pointer(&self,
506 a: Ty<'tcx>,
507 fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
508 b: Ty<'tcx>)
509 -> CoerceResult<'tcx>
510 {
511 /*!
512 * Attempts to coerce from the type of a Rust function item
513 * into a closure or a `proc`.
514 */
515
54a0048b
SL
516 let b = self.fcx.infcx().shallow_resolve(b);
517 debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
c34b1796 518
54a0048b
SL
519 if let ty::TyFnPtr(fn_ty_b) = b.sty {
520 match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
521 (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
522 let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
523 return self.unify_and_identity(unsafe_a, b).map(|(ty, _)| {
524 (ty, AdjustUnsafeFnPointer)
525 });
1a4d82fc 526 }
54a0048b 527 _ => {}
1a4d82fc 528 }
54a0048b
SL
529 }
530 self.unify_and_identity(a, b)
1a4d82fc
JJ
531 }
532
1a4d82fc
JJ
533 fn coerce_from_fn_item(&self,
534 a: Ty<'tcx>,
1a4d82fc
JJ
535 fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
536 b: Ty<'tcx>)
537 -> CoerceResult<'tcx> {
538 /*!
539 * Attempts to coerce from the type of a Rust function item
540 * into a closure or a `proc`.
541 */
542
54a0048b
SL
543 let b = self.fcx.infcx().shallow_resolve(b);
544 debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
1a4d82fc 545
54a0048b
SL
546 match b.sty {
547 ty::TyFnPtr(_) => {
548 let a_fn_pointer = self.tcx().mk_ty(ty::TyFnPtr(fn_ty_a));
549 self.unify_and_identity(a_fn_pointer, b).map(|(ty, _)| {
550 (ty, AdjustReifyFnPointer)
551 })
1a4d82fc 552 }
54a0048b
SL
553 _ => self.unify_and_identity(a, b)
554 }
1a4d82fc
JJ
555 }
556
85aaf69f
SL
557 fn coerce_unsafe_ptr(&self,
558 a: Ty<'tcx>,
559 b: Ty<'tcx>,
e9174d1e 560 mutbl_b: hir::Mutability)
85aaf69f 561 -> CoerceResult<'tcx> {
62682a34
SL
562 debug!("coerce_unsafe_ptr(a={:?}, b={:?})",
563 a,
564 b);
1a4d82fc 565
62682a34
SL
566 let (is_ref, mt_a) = match a.sty {
567 ty::TyRef(_, mt) => (true, mt),
568 ty::TyRawPtr(mt) => (false, mt),
1a4d82fc 569 _ => {
54a0048b 570 return self.unify_and_identity(a, b);
1a4d82fc
JJ
571 }
572 };
573
574 // Check that the types which they point at are compatible.
c1a9b12d 575 let a_unsafe = self.tcx().mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty });
54a0048b
SL
576 let (ty, noop) = self.unify_and_identity(a_unsafe, b)?;
577 coerce_mutbls(mt_a.mutbl, mutbl_b)?;
1a4d82fc
JJ
578
579 // Although references and unsafe ptrs have the same
580 // representation, we still register an AutoDerefRef so that
581 // regionck knows that the region for `a` must be valid here.
54a0048b
SL
582 Ok((ty, if is_ref {
583 AdjustDerefRef(AutoDerefRef {
62682a34 584 autoderefs: 1,
e9174d1e 585 autoref: Some(AutoUnsafe(mutbl_b)),
62682a34 586 unsize: None
54a0048b 587 })
7453a54e 588 } else if mt_a.mutbl != mutbl_b {
54a0048b 589 AdjustMutToConstPointer
62682a34 590 } else {
54a0048b
SL
591 noop
592 }))
1a4d82fc
JJ
593 }
594}
595
54a0048b
SL
596fn apply<'a, 'b, 'tcx, E, I>(coerce: &mut Coerce<'a, 'tcx>,
597 exprs: &E,
85aaf69f
SL
598 a: Ty<'tcx>,
599 b: Ty<'tcx>)
54a0048b
SL
600 -> CoerceResult<'tcx>
601 where E: Fn() -> I,
602 I: IntoIterator<Item=&'b hir::Expr> {
9346a6ac 603
54a0048b
SL
604 let (ty, adjustment) = indent(|| coerce.coerce(exprs, a, b))?;
605
606 let fcx = coerce.fcx;
607 if let AdjustDerefRef(auto) = adjustment {
d9579d0f 608 if auto.unsize.is_some() {
54a0048b
SL
609 let mut obligations = coerce.unsizing_obligations.borrow_mut();
610 for obligation in obligations.drain(..) {
d9579d0f 611 fcx.register_predicate(obligation);
9346a6ac
AL
612 }
613 }
614 }
615
54a0048b 616 Ok((ty, adjustment))
85aaf69f
SL
617}
618
54a0048b
SL
619/// Attempt to coerce an expression to a type, and return the
620/// adjusted type of the expression, if successful.
621/// Adjustments are only recorded if the coercion succeeded.
622/// The expressions *must not* have any pre-existing adjustments.
623pub fn try<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
624 expr: &hir::Expr,
625 target: Ty<'tcx>)
626 -> RelateResult<'tcx, Ty<'tcx>> {
627 let source = fcx.resolve_type_vars_if_possible(fcx.expr_ty(expr));
628 debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
629
630 let mut coerce = Coerce::new(fcx, TypeOrigin::ExprAssignable(expr.span));
631 fcx.infcx().commit_if_ok(|_| {
632 let (ty, adjustment) =
633 apply(&mut coerce, &|| Some(expr), source, target)?;
634 if !adjustment.is_identity() {
635 debug!("Success, coerced with {:?}", adjustment);
636 assert!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id));
637 fcx.write_adjustment(expr.id, adjustment);
638 }
639 Ok(ty)
640 })
641}
642
643/// Given some expressions, their known unified type and another expression,
644/// tries to unify the types, potentially inserting coercions on any of the
645/// provided expressions and returns their LUB (aka "common supertype").
646pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>,
647 origin: TypeOrigin,
648 exprs: E,
649 prev_ty: Ty<'tcx>,
650 new: &'b hir::Expr)
651 -> RelateResult<'tcx, Ty<'tcx>>
652 // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
653 where E: Fn() -> I,
654 I: IntoIterator<Item=&'b hir::Expr> {
655
656 let prev_ty = fcx.resolve_type_vars_if_possible(prev_ty);
657 let new_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(new));
658 debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);
659
660 let trace = TypeTrace::types(origin, true, prev_ty, new_ty);
661
662 // Special-case that coercion alone cannot handle:
663 // Two function item types of differing IDs or Substs.
664 match (&prev_ty.sty, &new_ty.sty) {
665 (&ty::TyFnDef(a_def_id, a_substs, a_fty),
666 &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
667 // The signature must always match.
668 let fty = fcx.infcx().lub(true, trace.clone(), a_fty, b_fty)
669 .map(|InferOk { value, obligations }| {
670 // FIXME(#32730) propagate obligations
671 assert!(obligations.is_empty());
672 value
673 })?;
674
675 if a_def_id == b_def_id {
676 // Same function, maybe the parameters match.
677 let substs = fcx.infcx().commit_if_ok(|_| {
678 fcx.infcx().lub(true, trace.clone(), a_substs, b_substs)
679 .map(|InferOk { value, obligations }| {
680 // FIXME(#32730) propagate obligations
681 assert!(obligations.is_empty());
682 value
683 })
684 }).map(|s| fcx.tcx().mk_substs(s));
685
686 if let Ok(substs) = substs {
687 // We have a LUB of prev_ty and new_ty, just return it.
688 return Ok(fcx.tcx().mk_fn_def(a_def_id, substs, fty));
689 }
690 }
691
692 // Reify both sides and return the reified fn pointer type.
693 for expr in exprs().into_iter().chain(Some(new)) {
694 // No adjustments can produce a fn item, so this should never trip.
695 assert!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id));
696 fcx.write_adjustment(expr.id, AdjustReifyFnPointer);
697 }
698 return Ok(fcx.tcx().mk_fn_ptr(fty));
699 }
700 _ => {}
701 }
702
703 let mut coerce = Coerce::new(fcx, origin);
704 coerce.use_lub = true;
705
706 // First try to coerce the new expression to the type of the previous ones,
707 // but only if the new expression has no coercion already applied to it.
708 let mut first_error = None;
709 if !fcx.inh.tables.borrow().adjustments.contains_key(&new.id) {
710 let result = fcx.infcx().commit_if_ok(|_| {
711 apply(&mut coerce, &|| Some(new), new_ty, prev_ty)
712 });
713 match result {
714 Ok((ty, adjustment)) => {
715 if !adjustment.is_identity() {
716 fcx.write_adjustment(new.id, adjustment);
717 }
718 return Ok(ty);
719 }
720 Err(e) => first_error = Some(e)
721 }
722 }
723
724 // Then try to coerce the previous expressions to the type of the new one.
725 // This requires ensuring there are no coercions applied to *any* of the
726 // previous expressions, other than noop reborrows (ignoring lifetimes).
727 for expr in exprs() {
728 let noop = match fcx.inh.tables.borrow().adjustments.get(&expr.id) {
729 Some(&AdjustDerefRef(AutoDerefRef {
730 autoderefs: 1,
731 autoref: Some(AutoPtr(_, mutbl_adj)),
732 unsize: None
733 })) => match fcx.expr_ty(expr).sty {
734 ty::TyRef(_, mt_orig) => {
735 // Reborrow that we can safely ignore.
736 mutbl_adj == mt_orig.mutbl
737 }
738 _ => false
739 },
740 Some(_) => false,
741 None => true
742 };
743
744 if !noop {
745 return fcx.infcx().commit_if_ok(|_| {
746 fcx.infcx().lub(true, trace.clone(), &prev_ty, &new_ty)
747 .map(|InferOk { value, obligations }| {
748 // FIXME(#32730) propagate obligations
749 assert!(obligations.is_empty());
750 value
751 })
752 });
753 }
754 }
755
756 match fcx.infcx().commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) {
757 Err(_) => {
758 // Avoid giving strange errors on failed attempts.
759 if let Some(e) = first_error {
760 Err(e)
761 } else {
762 fcx.infcx().commit_if_ok(|_| {
763 fcx.infcx().lub(true, trace, &prev_ty, &new_ty)
764 .map(|InferOk { value, obligations }| {
765 // FIXME(#32730) propagate obligations
766 assert!(obligations.is_empty());
767 value
768 })
769 })
770 }
771 }
772 Ok((ty, adjustment)) => {
773 if !adjustment.is_identity() {
774 for expr in exprs() {
775 fcx.write_adjustment(expr.id, adjustment);
776 }
777 }
778 Ok(ty)
779 }
1a4d82fc
JJ
780 }
781}