pub fn try_find_coercion_lub<'b, E, I>(&self,
                                           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 = self.resolve_type_vars_with_obligations(prev_ty);
        let new_ty = self.resolve_type_vars_with_obligations(self.expr_ty(new));
        debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);

        let trace = TypeTrace::types(origin, true, prev_ty, new_ty);

        // 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 = self.lub(true, trace.clone(), &a_fty, &b_fty)
                    .map(|InferOk { value, obligations }| {
                        // FIXME(#32730) propagate obligations
                        assert!(obligations.is_empty());
                        value
                    })?;

                if a_def_id == b_def_id {
                    // Same function, maybe the parameters match.
                    let substs = self.commit_if_ok(|_| {
                        self.lub(true, trace.clone(), &a_substs, &b_substs)
                            .map(|InferOk { value, obligations }| {
                                // FIXME(#32730) propagate obligations
                                assert!(obligations.is_empty());
                                value
                            })
                    });

                    if let Ok(substs) = substs {
                        // We have a LUB of prev_ty and new_ty, just return it.
                        return Ok(self.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!(!self.tables.borrow().adjustments.contains_key(&expr.id));
                    self.write_adjustment(expr.id, AdjustReifyFnPointer);
                }
                return Ok(self.tcx.mk_fn_ptr(fty));
            }
            _ => {}
        }

        let mut coerce = Coerce::new(self, 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 !self.tables.borrow().adjustments.contains_key(&new.id) {
            let result = self.commit_if_ok(|_| {
                apply(&mut coerce, &|| Some(new), new_ty, prev_ty)
            });
            match result {
                Ok((ty, adjustment)) => {
                    if !adjustment.is_identity() {
                        self.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 self.tables.borrow().adjustments.get(&expr.id) {
                Some(&AdjustDerefRef(AutoDerefRef {
                    autoderefs: 1,
                    autoref: Some(AutoPtr(_, mutbl_adj)),
                    unsize: None
                })) => match self.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 self.commit_if_ok(|_| {
                    self.lub(true, trace.clone(), &prev_ty, &new_ty)
                        .map(|InferOk { value, obligations }| {
                            // FIXME(#32730) propagate obligations
                            assert!(obligations.is_empty());
                            value
                        })
                });
            }
        }

        match self.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 {
                    self.commit_if_ok(|_| {
                        self.lub(true, trace, &prev_ty, &new_ty)
                            .map(|InferOk { value, obligations }| {
                                // FIXME(#32730) propagate obligations
                                assert!(obligations.is_empty());
                                value
                            })
                    })
                }
            }
            Ok((ty, adjustment)) => {
                if !adjustment.is_identity() {
                    for expr in exprs() {
                        self.write_adjustment(expr.id, adjustment);
                    }
                }
                Ok(ty)
            }
        }
    }
/// 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").
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").
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_coercion_lub<'b, E, I>(&self,
                                           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 = self.resolve_type_vars_with_obligations(prev_ty);
        let new_ty = self.resolve_type_vars_with_obligations(self.expr_ty(new));
        debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);
        let trace = TypeTrace::types(origin, true, prev_ty, new_ty);
        // 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 = self.lub(true, trace.clone(), &a_fty, &b_fty)
                    .map(|InferOk { value, obligations }| {
                        // FIXME(#32730) propagate obligations
                        assert!(obligations.is_empty());
                        value
                    })?;
                if a_def_id == b_def_id {
                    // Same function, maybe the parameters match.
                    let substs = self.commit_if_ok(|_| {
                        self.lub(true, trace.clone(), &a_substs, &b_substs)
                            .map(|InferOk { value, obligations }| {
                                // FIXME(#32730) propagate obligations
                                assert!(obligations.is_empty());
                                value
                            })
                    });
                    if let Ok(substs) = substs {
                        // We have a LUB of prev_ty and new_ty, just return it.
                        return Ok(self.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!(!self.tables.borrow().adjustments.contains_key(&expr.id));
                    self.write_adjustment(expr.id, AdjustReifyFnPointer);
                }
                return Ok(self.tcx.mk_fn_ptr(fty));
            }
            _ => {}
        }
        let mut coerce = Coerce::new(self, 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 !self.tables.borrow().adjustments.contains_key(&new.id) {
            let result = self.commit_if_ok(|_| {
                apply(&mut coerce, &|| Some(new), new_ty, prev_ty)
            });
            match result {
                Ok((ty, adjustment)) => {
                    if !adjustment.is_identity() {
                        self.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 self.tables.borrow().adjustments.get(&expr.id) {
                Some(&AdjustDerefRef(AutoDerefRef {
                    autoderefs: 1,
                    autoref: Some(AutoPtr(_, mutbl_adj)),
                    unsize: None
                })) => match self.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 self.commit_if_ok(|_| {
                    self.lub(true, trace.clone(), &prev_ty, &new_ty)
                        .map(|InferOk { value, obligations }| {
                            // FIXME(#32730) propagate obligations
                            assert!(obligations.is_empty());
                            value
                        })
                });
            }
        }
        match self.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 {
                    self.commit_if_ok(|_| {
                        self.lub(true, trace, &prev_ty, &new_ty)
                            .map(|InferOk { value, obligations }| {
                                // FIXME(#32730) propagate obligations
                                assert!(obligations.is_empty());
                                value
                            })
                    })
                }
            }
            Ok((ty, adjustment)) => {
                if !adjustment.is_identity() {
                    for expr in exprs() {
                        self.write_adjustment(expr.id, adjustment);
                    }
                }
                Ok(ty)
            }
        }
    }
pub fn try_find_coercion_lub < ' b , E , I > ( & self , 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 = self . resolve_type_vars_with_obligations ( prev_ty ) ; let new_ty = self . resolve_type_vars_with_obligations ( self . expr_ty ( new ) ) ; debug ! ( " " prev_ty new_ty ) ; let trace = TypeTrace :: types ( origin , true , prev_ty , new_ty ) ; // 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 = self . lub ( true , trace . clone ( ) , & a_fty , & b_fty ) . map ( | InferOk { value , obligations } | { // FIXME(#32730) propagate obligations assert ! ( obligations is_empty ( ) ) ; value } ) ? ; if a_def_id == b_def_id { // Same function, maybe the parameters match. let substs = self . commit_if_ok ( | _ | { self . lub ( true , trace . clone ( ) , & a_substs , & b_substs ) . map ( | InferOk { value , obligations } | { // FIXME(#32730) propagate obligations assert ! ( obligations is_empty ( ) ) ; value } ) } ) ; if let Ok ( substs ) = substs { // We have a LUB of prev_ty and new_ty, just return it. return Ok ( self . 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 ! ( self tables borrow ( ) adjustments contains_key ( expr id ) ) ; self . write_adjustment ( expr . id , AdjustReifyFnPointer ) ; } return Ok ( self . tcx . mk_fn_ptr ( fty ) ) ; } _ => { } } let mut coerce = Coerce :: new ( self , 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 ! self . tables . borrow ( ) . adjustments . contains_key ( & new . id ) { let result = self . commit_if_ok ( | _ | { apply ( & mut coerce , & | | Some ( new ) , new_ty , prev_ty ) } ) ; match result { Ok ( ( ty , adjustment ) ) => { if ! adjustment . is_identity ( ) { self . 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 self . tables . borrow ( ) . adjustments . get ( & expr . id ) { Some ( & AdjustDerefRef ( AutoDerefRef { autoderefs : 1 , autoref : Some ( AutoPtr ( _ , mutbl_adj ) ) , unsize : None } ) ) => match self . 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 self . commit_if_ok ( | _ | { self . lub ( true , trace . clone ( ) , & prev_ty , & new_ty ) . map ( | InferOk { value , obligations } | { // FIXME(#32730) propagate obligations assert ! ( obligations is_empty ( ) ) ; value } ) } ) ; } } match self . 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 { self . commit_if_ok ( | _ | { self . lub ( true , trace , & prev_ty , & new_ty ) . map ( | InferOk { value , obligations } | { // FIXME(#32730) propagate obligations assert ! ( obligations is_empty ( ) ) ; value } ) } ) } } Ok ( ( ty , adjustment ) ) => { if ! adjustment . is_identity ( ) { for expr in exprs ( ) { self . write_adjustment ( expr . id , adjustment ) ; } } Ok ( ty ) } } }
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").
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 " ) .
&self
origin
TypeOrigin
exprs
E
prev_ty
Ty<'tcx>
new
&'b hir::Expr
&self
origin
TypeOrigin
exprs
E
prev_ty
Ty<'tcx>
new
&'b hir::Expr