coercion.rs 24.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

S
Steve Klabnik 已提交
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
//! # Type Coercion
//!
//! Under certain circumstances we will coerce from one type to another,
//! for example by auto-borrowing.  This occurs in situations where the
//! compiler has a firm 'expected type' that was supplied from the user,
//! and where the actual type is similar to that expected type in purpose
//! but not in representation (so actual subtyping is inappropriate).
//!
//! ## Reborrowing
//!
//! Note that if we are expecting a reference, we will *reborrow*
//! even if the argument provided was already a reference.  This is
//! useful for freezing mut/const things (that is, when the expected is &T
//! but you have &const T or &mut T) and also for avoiding the linearity
//! of mut things (when the expected is &mut T and you have &mut T).  See
//! the various `src/test/run-pass/coerce-reborrow-*.rs` tests for
//! examples of where this is useful.
//!
//! ## Subtle note
//!
//! When deciding what type coercions to consider, we do not attempt to
//! resolve any type variables we may encounter.  This is because `b`
//! represents the expected type "as the user wrote it", meaning that if
//! the user defined a generic function like
//!
//!    fn foo<A>(a: A, b: A) { ... }
//!
//! and then we wrote `foo(&1, @2)`, we will not auto-borrow
//! either argument.  In older code we went to some lengths to
//! resolve the `b` variable, which could mean that we'd
//! auto-borrow later arguments but not earlier ones, which
//! seems very confusing.
//!
//! ## Subtler note
//!
//! However, right now, if the user manually specifies the
//! values for the type variables, as so:
//!
//!    foo::<&int>(@1, @2)
//!
//! then we *will* auto-borrow, because we can't distinguish this from a
//! function that declared `&int`.  This is inconsistent but it's easiest
//! at the moment. The right thing to do, I think, is to consider the
//! *unsubstituted* type when deciding whether to auto-borrow, but the
//! *substituted* type when considering the bounds and so forth. But most
//! of our methods don't give access to the unsubstituted type, and
//! rightly so because they'd be error-prone.  So maybe the thing to do is
//! to actually determine the kind of coercions that should occur
//! separately and pass them in.  Or maybe it's ok as is.  Anyway, it's
//! sort of a minor point so I've opted to leave it for later---after all
//! we may want to adjust precisely when coercions occur.
62

63
use check::{autoderef, FnCtxt, UnresolvedTypeAction};
64

65
use middle::infer::{Coercion, TypeOrigin, TypeTrace};
N
Nick Cameron 已提交
66 67
use middle::traits::{self, ObligationCause};
use middle::traits::{predicate_for_trait_def, report_selection_error};
68 69
use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef};
use middle::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer};
70
use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
71
use middle::ty::{self, LvaluePreference, TypeAndMut, Ty, TyCtxt};
N
Niko Matsakis 已提交
72
use middle::ty::fold::TypeFoldable;
73
use middle::ty::error::TypeError;
74
use middle::ty::relate::{relate_substs, RelateResult, TypeRelation};
75
use util::common::indent;
76

N
Nick Cameron 已提交
77 78
use std::cell::RefCell;
use std::collections::VecDeque;
79
use rustc_front::hir;
80

81 82
struct Coerce<'a, 'tcx: 'a> {
    fcx: &'a FnCtxt<'a, 'tcx>,
83 84
    origin: TypeOrigin,
    use_lub: bool,
N
Nick Cameron 已提交
85
    unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
86 87
}

88 89 90 91 92 93 94 95 96 97 98 99
type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, AutoAdjustment<'tcx>)>;

fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
                       to_mutbl: hir::Mutability)
                       -> RelateResult<'tcx, ()> {
    match (from_mutbl, to_mutbl) {
        (hir::MutMutable, hir::MutMutable) |
        (hir::MutImmutable, hir::MutImmutable) |
        (hir::MutMutable, hir::MutImmutable) => Ok(()),
        (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability)
    }
}
100

101
impl<'f, 'tcx> Coerce<'f, 'tcx> {
102
    fn new(fcx: &'f FnCtxt<'f, 'tcx>, origin: TypeOrigin) -> Self {
103 104 105
        Coerce {
            fcx: fcx,
            origin: origin,
106
            use_lub: false,
107 108 109 110
            unsizing_obligations: RefCell::new(vec![])
        }
    }

111
    fn tcx(&self) -> &TyCtxt<'tcx> {
112
        self.fcx.tcx()
113 114
    }

115
    /// Unify two types (using sub or lub) and produce a noop coercion.
116
    fn unify_and_identity(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
        let infcx = self.fcx.infcx();
        infcx.commit_if_ok(|_| {
            let trace = TypeTrace::types(self.origin, false, a, b);
            if self.use_lub {
                infcx.lub(false, trace).relate(&a, &b)
            } else {
                infcx.sub(false, trace).relate(&a, &b)
            }
        }).and_then(|ty| self.identity(ty))
    }

    /// Synthesize an identity adjustment.
    fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> {
        Ok((ty, AdjustDerefRef(AutoDerefRef {
            autoderefs: 0,
            autoref: None,
            unsize: None
        })))
135 136
    }

137 138 139 140 141 142 143 144
    fn coerce<'a, E, I>(&self,
                        exprs: &E,
                        a: Ty<'tcx>,
                        b: Ty<'tcx>)
                        -> CoerceResult<'tcx>
        // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
        where E: Fn() -> I,
              I: IntoIterator<Item=&'a hir::Expr> {
145

146
        let a = self.fcx.infcx().shallow_resolve(a);
147
        debug!("Coerce.tys({:?} => {:?})", a, b);
148 149 150

        // Just ignore error types.
        if a.references_error() || b.references_error() {
151
            return self.identity(b);
152 153
        }

N
Nick Cameron 已提交
154
        // Consider coercing the subtype to a DST
155
        let unsize = self.coerce_unsized(a, b);
N
Nick Cameron 已提交
156 157 158 159
        if unsize.is_ok() {
            return unsize;
        }

160 161 162 163
        // Examine the supertype and consider auto-borrowing.
        //
        // Note: does not attempt to resolve type variables we encounter.
        // See above for details.
164
        match b.sty {
165
            ty::TyRawPtr(mt_b) => {
166
                return self.coerce_unsafe_ptr(a, b, mt_b.mutbl);
167 168
            }

169 170
            ty::TyRef(r_b, mt_b) => {
                return self.coerce_borrowed_pointer(exprs, a, b, r_b, mt_b.mutbl);
171 172
            }

173 174
            _ => {}
        }
175

176
        match a.sty {
177
            ty::TyFnDef(_, _, a_f) => {
178 179 180 181
                // Function items are coercible to any closure
                // type; function pointers are not (that would
                // require double indirection).
                self.coerce_from_fn_item(a, a_f, b)
182
            }
183
            ty::TyFnPtr(a_f) => {
184 185 186 187 188
                // We permit coercion of fn pointers to drop the
                // unsafe qualifier.
                self.coerce_from_fn_pointer(a, a_f, b)
            }
            _ => {
189
                // Otherwise, just use unification rules.
190
                self.unify_and_identity(a, b)
191 192
            }
        }
193 194
    }

195 196 197
    /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
    /// To match `A` with `B`, autoderef will be performed,
    /// calling `deref`/`deref_mut` where necessary.
198 199 200 201
    fn coerce_borrowed_pointer<'a, E, I>(&self,
                                         exprs: &E,
                                         a: Ty<'tcx>,
                                         b: Ty<'tcx>,
202
                                         r_b: &'tcx ty::Region,
203 204 205 206 207 208 209
                                         mutbl_b: hir::Mutability)
                                         -> CoerceResult<'tcx>
        // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
        where E: Fn() -> I,
              I: IntoIterator<Item=&'a hir::Expr> {

        debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b);
210

211 212 213 214 215 216
        // If we have a parameter of type `&M T_a` and the value
        // provided is `expr`, we will be adding an implicit borrow,
        // meaning that we convert `f(expr)` to `f(&M *expr)`.  Therefore,
        // to type check, we will construct the type that `&M*expr` would
        // yield.

217 218
        let (_r_a, _mutbl_a) = match a.sty {
            ty::TyRef(r_a, mt_a) => {
219
                try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
220
                (r_a, mt_a.mutbl)
S
Seo Sanghyeon 已提交
221
            }
222
            _ => return self.unify_and_identity(a, b)
223
        };
224

225 226
        let span = self.origin.span();
        let coercion = Coercion(span);
227 228 229 230 231 232 233 234 235 236 237 238
        let r_borrow = {
            // If are coercing from `&'a T` to `&'b U`, then we want to
            // reborrow the contents of `'a` for the lifetime `'b`
            // (which ought to be a sublifetime of `'a`).
            if !self.use_lub {
                r_b
            } else {
                // With LUB, we need more flexibility.
                let r_borrow = self.fcx.infcx().next_region_var(coercion);
                self.tcx().mk_region(r_borrow)
            }
        };
239
        let autoref = Some(AutoPtr(r_borrow, mutbl_b));
240

241
        let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b);
242
        let mut first_error = None;
243
        let (_, autoderefs, success) = autoderef(self.fcx, span, a, exprs,
244 245 246 247 248 249 250 251
                                                 UnresolvedTypeAction::Ignore,
                                                 lvalue_pref,
                                                 |inner_ty, autoderef| {
            if autoderef == 0 {
                // Don't let this pass, otherwise it would cause
                // &T to autoref to &&T.
                return None;
            }
252
            let ty = self.tcx().mk_ref(r_borrow,
253
                                        TypeAndMut {ty: inner_ty, mutbl: mutbl_b});
254
            match self.unify_and_identity(ty, b) {
255 256 257 258 259
                Err(err) => {
                    if first_error.is_none() {
                        first_error = Some(err);
                    }
                    None
260
                }
261
                Ok((ty, _)) => Some(ty)
262 263 264 265
            }
        });

        match success {
266 267
            Some(ty) => {
                Ok((ty, AdjustDerefRef(AutoDerefRef {
268
                    autoderefs: autoderefs,
269 270
                    autoref: autoref,
                    unsize: None
271 272 273 274 275 276 277 278
                })))
            }
            None => {
                // Return original error as if overloaded deref was never
                // attempted, to avoid irrelevant/confusing error messages.
                Err(first_error.expect("coerce_borrowed_pointer failed with no error?"))
            }
        }
279 280 281
    }


282 283
    // &[T; n] or &mut [T; n] -> &[T]
    // or &mut [T; n] -> &mut [T]
N
Nick Cameron 已提交
284 285
    // or &Concrete -> &Trait, etc.
    fn coerce_unsized(&self,
N
Nick Cameron 已提交
286 287
                      source: Ty<'tcx>,
                      target: Ty<'tcx>)
288
                      -> CoerceResult<'tcx> {
289 290 291
        debug!("coerce_unsized(source={:?}, target={:?})",
               source,
               target);
N
Nick Cameron 已提交
292 293 294 295 296 297 298

        let traits = (self.tcx().lang_items.unsize_trait(),
                      self.tcx().lang_items.coerce_unsized_trait());
        let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits {
            (u, cu)
        } else {
            debug!("Missing Unsize or CoerceUnsized traits");
299
            return Err(TypeError::Mismatch);
N
Nick Cameron 已提交
300
        };
301

N
Nick Cameron 已提交
302 303 304
        // Note, we want to avoid unnecessary unsizing. We don't want to coerce to
        // a DST unless we have to. This currently comes out in the wash since
        // we can't unify [T] with U. But to properly support DST, we need to allow
N
Nick Cameron 已提交
305
        // that, at which point we will need extra checks on the target here.
N
Nick Cameron 已提交
306

N
Nick Cameron 已提交
307 308
        // Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
        let (source, reborrow) = match (&source.sty, &target.sty) {
309
            (&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => {
N
Nick Cameron 已提交
310 311 312 313 314
                try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));

                let coercion = Coercion(self.origin.span());
                let r_borrow = self.fcx.infcx().next_region_var(coercion);
                let region = self.tcx().mk_region(r_borrow);
315
                (mt_a.ty, Some(AutoPtr(region, mt_b.mutbl)))
316
            }
317
            (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
N
Nick Cameron 已提交
318
                try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
319
                (mt_a.ty, Some(AutoUnsafe(mt_b.mutbl)))
320
            }
N
Nick Cameron 已提交
321 322
            _ => (source, None)
        };
323
        let source = source.adjust_for_autoref(self.tcx(), reborrow);
N
Nick Cameron 已提交
324

J
Jared Roesch 已提交
325
        let mut selcx = traits::SelectionContext::new(self.fcx.infcx());
N
Nick Cameron 已提交
326 327 328 329 330 331 332

        // Use a FIFO queue for this custom fulfillment procedure.
        let mut queue = VecDeque::new();
        let mut leftover_predicates = vec![];

        // Create an obligation for `Source: CoerceUnsized<Target>`.
        let cause = ObligationCause::misc(self.origin.span(), self.fcx.body_id);
N
Nick Cameron 已提交
333 334 335 336 337 338
        queue.push_back(predicate_for_trait_def(self.tcx(),
                                                cause,
                                                coerce_unsized_did,
                                                0,
                                                source,
                                                vec![target]));
N
Nick Cameron 已提交
339 340 341 342 343 344

        // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
        // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
        // inference might unify those two inner type variables later.
        let traits = [coerce_unsized_did, unsize_did];
        while let Some(obligation) = queue.pop_front() {
345
            debug!("coerce_unsized resolve step: {:?}", obligation);
N
Nick Cameron 已提交
346 347 348 349 350 351 352 353 354 355 356 357
            let trait_ref =  match obligation.predicate {
                ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
                    tr.clone()
                }
                _ => {
                    leftover_predicates.push(obligation);
                    continue;
                }
            };
            match selcx.select(&obligation.with(trait_ref)) {
                // Uncertain or unimplemented.
                Ok(None) | Err(traits::Unimplemented) => {
N
Nick Cameron 已提交
358
                    debug!("coerce_unsized: early return - can't prove obligation");
359
                    return Err(TypeError::Mismatch);
N
Nick Cameron 已提交
360
                }
N
Nick Cameron 已提交
361 362 363 364 365 366 367 368 369 370

                // Object safety violations or miscellaneous.
                Err(err) => {
                    report_selection_error(self.fcx.infcx(), &obligation, &err);
                    // Treat this like an obligation and follow through
                    // with the unsizing - the lack of a coercion should
                    // be silent, as it causes a type mismatch later.
                }

                Ok(Some(vtable)) => {
371 372 373
                    for obligation in vtable.nested_obligations() {
                        queue.push_back(obligation);
                    }
N
Nick Cameron 已提交
374
                }
N
Nick Cameron 已提交
375
            }
N
Nick Cameron 已提交
376 377
        }

378
        *self.unsizing_obligations.borrow_mut() = leftover_predicates;
379 380 381 382 383 384

        let adjustment = AutoDerefRef {
            autoderefs: if reborrow.is_some() { 1 } else { 0 },
            autoref: reborrow,
            unsize: Some(target)
        };
385
        debug!("Success, coerced with {:?}", adjustment);
386
        Ok((target, AdjustDerefRef(adjustment)))
N
Nick Cameron 已提交
387
    }
388

389 390 391 392 393 394 395 396 397 398 399
    fn coerce_from_fn_pointer(&self,
                           a: Ty<'tcx>,
                           fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
                           b: Ty<'tcx>)
                           -> CoerceResult<'tcx>
    {
        /*!
         * Attempts to coerce from the type of a Rust function item
         * into a closure or a `proc`.
         */

400 401
        let b = self.fcx.infcx().shallow_resolve(b);
        debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
402

403 404 405 406
        if let ty::TyFnPtr(fn_ty_b) = b.sty {
            match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
                (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
                    let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
407
                    return self.unify_and_identity(unsafe_a, b).map(|(ty, _)| {
408 409
                        (ty, AdjustUnsafeFnPointer)
                    });
410
                }
411
                _ => {}
412
            }
413
        }
414
        self.unify_and_identity(a, b)
415 416
    }

417 418
    fn coerce_from_fn_item(&self,
                           a: Ty<'tcx>,
H
Huon Wilson 已提交
419
                           fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
420
                           b: Ty<'tcx>)
421
                           -> CoerceResult<'tcx> {
422 423 424 425
        /*!
         * Attempts to coerce from the type of a Rust function item
         * into a closure or a `proc`.
         */
426

427 428
        let b = self.fcx.infcx().shallow_resolve(b);
        debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
429

430 431 432
        match b.sty {
            ty::TyFnPtr(_) => {
                let a_fn_pointer = self.tcx().mk_ty(ty::TyFnPtr(fn_ty_a));
433
                self.unify_and_identity(a_fn_pointer, b).map(|(ty, _)| {
434 435
                    (ty, AdjustReifyFnPointer)
                })
436
            }
437
            _ => self.unify_and_identity(a, b)
438
        }
439 440
    }

441 442 443
    fn coerce_unsafe_ptr(&self,
                         a: Ty<'tcx>,
                         b: Ty<'tcx>,
444
                         mutbl_b: hir::Mutability)
445
                         -> CoerceResult<'tcx> {
446 447 448
        debug!("coerce_unsafe_ptr(a={:?}, b={:?})",
               a,
               b);
449

450 451 452
        let (is_ref, mt_a) = match a.sty {
            ty::TyRef(_, mt) => (true, mt),
            ty::TyRawPtr(mt) => (false, mt),
453
            _ => {
454
                return self.unify_and_identity(a, b);
455 456 457
            }
        };

458
        // Check that the types which they point at are compatible.
459
        let a_unsafe = self.tcx().mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty });
460
        let (ty, noop) = try!(self.unify_and_identity(a_unsafe, b));
461
        try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
N
Niko Matsakis 已提交
462

463
        // Although references and unsafe ptrs have the same
N
Niko Matsakis 已提交
464
        // representation, we still register an AutoDerefRef so that
465
        // regionck knows that the region for `a` must be valid here.
466 467
        Ok((ty, if is_ref {
            AdjustDerefRef(AutoDerefRef {
468
                autoderefs: 1,
469
                autoref: Some(AutoUnsafe(mutbl_b)),
470
                unsize: None
471
            })
472
        } else if mt_a.mutbl != mutbl_b {
473
            AdjustMutToConstPointer
474
        } else {
475 476
            noop
        }))
477 478
    }
}
479

480 481 482 483
fn apply<'a, 'b, 'tcx, E, I>(coerce: &mut Coerce<'a, 'tcx>,
                             exprs: &E,
                             a: Ty<'tcx>,
                             b: Ty<'tcx>)
484
                             -> CoerceResult<'tcx>
485 486 487 488
    where E: Fn() -> I,
          I: IntoIterator<Item=&'b hir::Expr> {

    let (ty, adjustment) = try!(indent(|| coerce.coerce(exprs, a, b)));
489

490 491
    let fcx = coerce.fcx;
    if let AdjustDerefRef(auto) = adjustment {
N
Nick Cameron 已提交
492
        if auto.unsize.is_some() {
493 494
            let mut obligations = coerce.unsizing_obligations.borrow_mut();
            for obligation in obligations.drain(..) {
N
Nick Cameron 已提交
495
                fcx.register_predicate(obligation);
496 497 498 499
            }
        }
    }

500
    Ok((ty, adjustment))
501 502
}

503 504 505
/// Attempt to coerce an expression to a type, and return the
/// adjusted type of the expression, if successful.
/// Adjustments are only recorded if the coercion succeeded.
506 507 508
/// The expressions *must not* have any pre-existing adjustments.
pub fn try<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     expr: &hir::Expr,
509 510 511 512 513
                     target: Ty<'tcx>)
                     -> RelateResult<'tcx, Ty<'tcx>> {
    let source = fcx.resolve_type_vars_if_possible(fcx.expr_ty(expr));
    debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);

514 515
    let mut coerce = Coerce::new(fcx, TypeOrigin::ExprAssignable(expr.span));
    fcx.infcx().commit_if_ok(|_| {
516 517 518 519 520 521 522 523 524
        let (ty, adjustment) =
            try!(apply(&mut coerce, &|| Some(expr), source, target));
        if !adjustment.is_identity() {
            debug!("Success, coerced with {:?}", adjustment);
            assert!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id));
            fcx.write_adjustment(expr.id, adjustment);
        }
        Ok(ty)
    })
525 526
}

527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
/// Given some expressions, their known unified type and another expression,
/// tries to unify the types, potentially inserting coercions on any of the
/// provided expressions and returns their LUB (aka "common supertype").
pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>,
                                        origin: TypeOrigin,
                                        exprs: E,
                                        prev_ty: Ty<'tcx>,
                                        new: &'b hir::Expr)
                                        -> RelateResult<'tcx, Ty<'tcx>>
    // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
    where E: Fn() -> I,
          I: IntoIterator<Item=&'b hir::Expr> {

    let prev_ty = fcx.resolve_type_vars_if_possible(prev_ty);
    let new_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(new));
    debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);

    let trace = TypeTrace::types(origin, true, prev_ty, new_ty);
    let mut lub = fcx.infcx().lub(true, trace);

    // Special-case that coercion alone cannot handle:
    // Two function item types of differing IDs or Substs.
    match (&prev_ty.sty, &new_ty.sty) {
        (&ty::TyFnDef(a_def_id, a_substs, a_fty),
         &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
            // The signature must always match.
            let fty = try!(lub.relate(a_fty, b_fty));

            if a_def_id == b_def_id {
                // Same function, maybe the parameters match.
                let substs = fcx.infcx().commit_if_ok(|_| {
                    relate_substs(&mut lub, None, a_substs, b_substs)
                }).map(|s| fcx.tcx().mk_substs(s));

                if let Ok(substs) = substs {
                    // We have a LUB of prev_ty and new_ty, just return it.
                    return Ok(fcx.tcx().mk_fn_def(a_def_id, substs, fty));
                }
            }

            // Reify both sides and return the reified fn pointer type.
            for expr in exprs().into_iter().chain(Some(new)) {
                // No adjustments can produce a fn item, so this should never trip.
                assert!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id));
                fcx.write_adjustment(expr.id, AdjustReifyFnPointer);
            }
            return Ok(fcx.tcx().mk_fn_ptr(fty));
        }
        _ => {}
    }

    let mut coerce = Coerce::new(fcx, origin);
    coerce.use_lub = true;

    // First try to coerce the new expression to the type of the previous ones,
    // but only if the new expression has no coercion already applied to it.
    let mut first_error = None;
    if !fcx.inh.tables.borrow().adjustments.contains_key(&new.id) {
        let result = fcx.infcx().commit_if_ok(|_| {
            apply(&mut coerce, &|| Some(new), new_ty, prev_ty)
        });
        match result {
            Ok((ty, adjustment)) => {
                if !adjustment.is_identity() {
                    fcx.write_adjustment(new.id, adjustment);
                }
                return Ok(ty);
            }
            Err(e) => first_error = Some(e)
        }
    }

    // Then try to coerce the previous expressions to the type of the new one.
    // This requires ensuring there are no coercions applied to *any* of the
    // previous expressions, other than noop reborrows (ignoring lifetimes).
    for expr in exprs() {
        let noop = match fcx.inh.tables.borrow().adjustments.get(&expr.id) {
            Some(&AdjustDerefRef(AutoDerefRef {
                autoderefs: 1,
                autoref: Some(AutoPtr(_, mutbl_adj)),
                unsize: None
            })) => match fcx.expr_ty(expr).sty {
                ty::TyRef(_, mt_orig) => {
                    // Reborrow that we can safely ignore.
                    mutbl_adj == mt_orig.mutbl
                }
                _ => false
            },
            Some(_) => false,
            None => true
        };

        if !noop {
            return fcx.infcx().commit_if_ok(|_| lub.relate(&prev_ty, &new_ty));
        }
    }

    match fcx.infcx().commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) {
        Err(_) => {
            // Avoid giving strange errors on failed attempts.
            if let Some(e) = first_error {
                Err(e)
            } else {
                fcx.infcx().commit_if_ok(|_| lub.relate(&prev_ty, &new_ty))
            }
        }
        Ok((ty, adjustment)) => {
            if !adjustment.is_identity() {
                for expr in exprs() {
                    fcx.write_adjustment(expr.id, adjustment);
                }
            }
            Ok(ty)
        }
641 642
    }
}