hir_ty/infer/
coerce.rs

1//! Coercion logic. Coercions are certain type conversions that can implicitly
2//! happen in certain places, e.g. weakening `&mut` to `&` or deref coercions
3//! like going from `&Vec<T>` to `&[T]`.
4//!
5//! See <https://doc.rust-lang.org/nomicon/coercions.html> and
6//! `rustc_hir_analysis/check/coercion.rs`.
7
8use std::iter;
9
10use chalk_ir::{BoundVar, Goal, Mutability, TyKind, TyVariableKind, cast::Cast};
11use hir_def::{hir::ExprId, lang_item::LangItem};
12use stdx::always;
13use triomphe::Arc;
14
15use crate::{
16    Canonical, DomainGoal, FnAbi, FnPointer, FnSig, InEnvironment, Interner, Lifetime,
17    Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
18    autoderef::{Autoderef, AutoderefKind},
19    db::HirDatabase,
20    infer::{
21        Adjust, Adjustment, AutoBorrow, InferOk, InferenceContext, OverloadedDeref, PointerCast,
22        TypeError, TypeMismatch,
23    },
24    traits::NextTraitSolveResult,
25    utils::ClosureSubst,
26};
27
28use super::unify::InferenceTable;
29
30pub(crate) type CoerceResult = Result<InferOk<(Vec<Adjustment>, Ty)>, TypeError>;
31
32/// Do not require any adjustments, i.e. coerce `x -> x`.
33fn identity(_: Ty) -> Vec<Adjustment> {
34    vec![]
35}
36
37fn simple(kind: Adjust) -> impl FnOnce(Ty) -> Vec<Adjustment> {
38    move |target| vec![Adjustment { kind, target }]
39}
40
41/// This always returns `Ok(...)`.
42fn success(
43    adj: Vec<Adjustment>,
44    target: Ty,
45    goals: Vec<InEnvironment<Goal<Interner>>>,
46) -> CoerceResult {
47    Ok(InferOk { goals, value: (adj, target) })
48}
49
50pub(super) enum CoercionCause {
51    // FIXME: Make better use of this. Right now things like return and break without a value
52    // use it to point to themselves, causing us to report a mismatch on those expressions even
53    // though technically they themselves are `!`
54    Expr(ExprId),
55}
56
57#[derive(Clone, Debug)]
58pub(super) struct CoerceMany {
59    expected_ty: Ty,
60    final_ty: Option<Ty>,
61    expressions: Vec<ExprId>,
62}
63
64impl CoerceMany {
65    pub(super) fn new(expected: Ty) -> Self {
66        CoerceMany { expected_ty: expected, final_ty: None, expressions: vec![] }
67    }
68
69    /// Returns the "expected type" with which this coercion was
70    /// constructed. This represents the "downward propagated" type
71    /// that was given to us at the start of typing whatever construct
72    /// we are typing (e.g., the match expression).
73    ///
74    /// Typically, this is used as the expected type when
75    /// type-checking each of the alternative expressions whose types
76    /// we are trying to merge.
77    pub(super) fn expected_ty(&self) -> Ty {
78        self.expected_ty.clone()
79    }
80
81    /// Returns the current "merged type", representing our best-guess
82    /// at the LUB of the expressions we've seen so far (if any). This
83    /// isn't *final* until you call `self.complete()`, which will return
84    /// the merged type.
85    pub(super) fn merged_ty(&self) -> Ty {
86        self.final_ty.clone().unwrap_or_else(|| self.expected_ty.clone())
87    }
88
89    pub(super) fn complete(self, ctx: &mut InferenceContext<'_>) -> Ty {
90        if let Some(final_ty) = self.final_ty {
91            final_ty
92        } else {
93            ctx.result.standard_types.never.clone()
94        }
95    }
96
97    pub(super) fn coerce_forced_unit(
98        &mut self,
99        ctx: &mut InferenceContext<'_>,
100        cause: CoercionCause,
101    ) {
102        self.coerce(ctx, None, &ctx.result.standard_types.unit.clone(), cause)
103    }
104
105    /// Merge two types from different branches, with possible coercion.
106    ///
107    /// Mostly this means trying to coerce one to the other, but
108    ///  - if we have two function types for different functions or closures, we need to
109    ///    coerce both to function pointers;
110    ///  - if we were concerned with lifetime subtyping, we'd need to look for a
111    ///    least upper bound.
112    pub(super) fn coerce(
113        &mut self,
114        ctx: &mut InferenceContext<'_>,
115        expr: Option<ExprId>,
116        expr_ty: &Ty,
117        cause: CoercionCause,
118    ) {
119        let expr_ty = ctx.resolve_ty_shallow(expr_ty);
120        self.expected_ty = ctx.resolve_ty_shallow(&self.expected_ty);
121
122        // Special case: two function types. Try to coerce both to
123        // pointers to have a chance at getting a match. See
124        // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
125        let sig = match (self.merged_ty().kind(Interner), expr_ty.kind(Interner)) {
126            (TyKind::FnDef(x, _), TyKind::FnDef(y, _))
127                if x == y && ctx.table.unify(&self.merged_ty(), &expr_ty) =>
128            {
129                None
130            }
131            (TyKind::Closure(x, _), TyKind::Closure(y, _)) if x == y => None,
132            (TyKind::FnDef(..) | TyKind::Closure(..), TyKind::FnDef(..) | TyKind::Closure(..)) => {
133                // FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure,
134                // we should be coercing the closure to a fn pointer of the safety of the FnDef
135                cov_mark::hit!(coerce_fn_reification);
136                let sig =
137                    self.merged_ty().callable_sig(ctx.db).expect("FnDef without callable sig");
138                Some(sig)
139            }
140            _ => None,
141        };
142        if let Some(sig) = sig {
143            let target_ty = TyKind::Function(sig.to_fn_ptr()).intern(Interner);
144            let result1 = ctx.table.coerce_inner(self.merged_ty(), &target_ty, CoerceNever::Yes);
145            let result2 = ctx.table.coerce_inner(expr_ty.clone(), &target_ty, CoerceNever::Yes);
146            if let (Ok(result1), Ok(result2)) = (result1, result2) {
147                ctx.table.register_infer_ok(InferOk { value: (), goals: result1.goals });
148                for &e in &self.expressions {
149                    ctx.write_expr_adj(e, result1.value.0.clone().into_boxed_slice());
150                }
151                ctx.table.register_infer_ok(InferOk { value: (), goals: result2.goals });
152                if let Some(expr) = expr {
153                    ctx.write_expr_adj(expr, result2.value.0.into_boxed_slice());
154                    self.expressions.push(expr);
155                }
156                return self.final_ty = Some(target_ty);
157            }
158        }
159
160        // It might not seem like it, but order is important here: If the expected
161        // type is a type variable and the new one is `!`, trying it the other
162        // way around first would mean we make the type variable `!`, instead of
163        // just marking it as possibly diverging.
164        //
165        // - [Comment from rustc](https://github.com/rust-lang/rust/blob/5ff18d0eaefd1bd9ab8ec33dab2404a44e7631ed/compiler/rustc_hir_typeck/src/coercion.rs#L1334-L1335)
166        // First try to coerce the new expression to the type of the previous ones,
167        // but only if the new expression has no coercion already applied to it.
168        if expr.is_none_or(|expr| !ctx.result.expr_adjustments.contains_key(&expr))
169            && let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes)
170        {
171            self.final_ty = Some(res);
172            if let Some(expr) = expr {
173                self.expressions.push(expr);
174            }
175            return;
176        }
177
178        if let Ok((adjustments, res)) =
179            ctx.coerce_inner(&self.merged_ty(), &expr_ty, CoerceNever::Yes)
180        {
181            self.final_ty = Some(res);
182            for &e in &self.expressions {
183                ctx.write_expr_adj(e, adjustments.clone().into_boxed_slice());
184            }
185        } else {
186            match cause {
187                CoercionCause::Expr(id) => {
188                    ctx.result.type_mismatches.insert(
189                        id.into(),
190                        TypeMismatch { expected: self.merged_ty(), actual: expr_ty.clone() },
191                    );
192                }
193            }
194            cov_mark::hit!(coerce_merge_fail_fallback);
195        }
196        if let Some(expr) = expr {
197            self.expressions.push(expr);
198        }
199    }
200}
201
202pub fn could_coerce(
203    db: &dyn HirDatabase,
204    env: Arc<TraitEnvironment>,
205    tys: &Canonical<(Ty, Ty)>,
206) -> bool {
207    coerce(db, env, tys).is_ok()
208}
209
210pub(crate) fn coerce(
211    db: &dyn HirDatabase,
212    env: Arc<TraitEnvironment>,
213    tys: &Canonical<(Ty, Ty)>,
214) -> Result<(Vec<Adjustment>, Ty), TypeError> {
215    let mut table = InferenceTable::new(db, env);
216    let vars = table.fresh_subst(tys.binders.as_slice(Interner));
217    let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
218    let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner);
219    let (adjustments, ty) = table.coerce(&ty1_with_vars, &ty2_with_vars, CoerceNever::Yes)?;
220    // default any type vars that weren't unified back to their original bound vars
221    // (kind of hacky)
222    let find_var = |iv| {
223        vars.iter(Interner).position(|v| match v.interned() {
224            chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(Interner),
225            chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(Interner),
226            chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner),
227        } == Some(iv))
228    };
229    let fallback = |iv, kind, default, binder| match kind {
230        chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv)
231            .map_or(default, |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner)),
232        chalk_ir::VariableKind::Lifetime => find_var(iv)
233            .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)),
234        chalk_ir::VariableKind::Const(ty) => find_var(iv)
235            .map_or(default, |i| BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)),
236    };
237    // FIXME also map the types in the adjustments
238    Ok((adjustments, table.resolve_with_fallback(ty, &fallback)))
239}
240
241#[derive(Clone, Copy, PartialEq, Eq)]
242pub(crate) enum CoerceNever {
243    Yes,
244    No,
245}
246
247impl InferenceContext<'_> {
248    /// Unify two types, but may coerce the first one to the second one
249    /// using "implicit coercion rules" if needed.
250    pub(super) fn coerce(
251        &mut self,
252        expr: Option<ExprId>,
253        from_ty: &Ty,
254        to_ty: &Ty,
255        // [Comment from rustc](https://github.com/rust-lang/rust/blob/4cc494bbfe9911d24f3ee521f98d5c6bb7e3ffe8/compiler/rustc_hir_typeck/src/coercion.rs#L85-L89)
256        // Whether we allow `NeverToAny` coercions. This is unsound if we're
257        // coercing a place expression without it counting as a read in the MIR.
258        // This is a side-effect of HIR not really having a great distinction
259        // between places and values.
260        coerce_never: CoerceNever,
261    ) -> Result<Ty, TypeError> {
262        let (adjustments, ty) = self.coerce_inner(from_ty, to_ty, coerce_never)?;
263        if let Some(expr) = expr {
264            self.write_expr_adj(expr, adjustments.into_boxed_slice());
265        }
266        Ok(ty)
267    }
268
269    fn coerce_inner(
270        &mut self,
271        from_ty: &Ty,
272        to_ty: &Ty,
273        coerce_never: CoerceNever,
274    ) -> Result<(Vec<Adjustment>, Ty), TypeError> {
275        let from_ty = self.resolve_ty_shallow(from_ty);
276        let to_ty = self.resolve_ty_shallow(to_ty);
277        self.table.coerce(&from_ty, &to_ty, coerce_never)
278    }
279}
280
281impl InferenceTable<'_> {
282    /// Unify two types, but may coerce the first one to the second one
283    /// using "implicit coercion rules" if needed.
284    pub(crate) fn coerce(
285        &mut self,
286        from_ty: &Ty,
287        to_ty: &Ty,
288        coerce_never: CoerceNever,
289    ) -> Result<(Vec<Adjustment>, Ty), TypeError> {
290        let from_ty = self.resolve_ty_shallow(from_ty);
291        let to_ty = self.resolve_ty_shallow(to_ty);
292        match self.coerce_inner(from_ty, &to_ty, coerce_never) {
293            Ok(InferOk { value: (adjustments, ty), goals }) => {
294                self.register_infer_ok(InferOk { value: (), goals });
295                Ok((adjustments, ty))
296            }
297            Err(e) => {
298                // FIXME deal with error
299                Err(e)
300            }
301        }
302    }
303
304    fn coerce_inner(&mut self, from_ty: Ty, to_ty: &Ty, coerce_never: CoerceNever) -> CoerceResult {
305        if from_ty.is_never() {
306            if let TyKind::InferenceVar(tv, TyVariableKind::General) = to_ty.kind(Interner) {
307                self.set_diverging(*tv, true);
308            }
309            if coerce_never == CoerceNever::Yes {
310                // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
311                // type variable, we want `?T` to fallback to `!` if not
312                // otherwise constrained. An example where this arises:
313                //
314                //     let _: Option<?T> = Some({ return; });
315                //
316                // here, we would coerce from `!` to `?T`.
317                return success(simple(Adjust::NeverToAny)(to_ty.clone()), to_ty.clone(), vec![]);
318            } else {
319                return self.unify_and(&from_ty, to_ty, identity);
320            }
321        }
322
323        // If we are coercing into a TAIT, coerce into its proxy inference var, instead.
324        let mut to_ty = to_ty;
325        let _to;
326        if let Some(tait_table) = &self.tait_coercion_table
327            && let TyKind::OpaqueType(opaque_ty_id, _) = to_ty.kind(Interner)
328            && !matches!(from_ty.kind(Interner), TyKind::InferenceVar(..) | TyKind::OpaqueType(..))
329            && let Some(ty) = tait_table.get(opaque_ty_id)
330        {
331            _to = ty.clone();
332            to_ty = &_to;
333        }
334
335        // Consider coercing the subtype to a DST
336        if let Ok(ret) = self.try_coerce_unsized(&from_ty, to_ty) {
337            return Ok(ret);
338        }
339
340        // Examine the supertype and consider auto-borrowing.
341        match to_ty.kind(Interner) {
342            TyKind::Raw(mt, _) => return self.coerce_ptr(from_ty, to_ty, *mt),
343            TyKind::Ref(mt, lt, _) => return self.coerce_ref(from_ty, to_ty, *mt, lt),
344            _ => {}
345        }
346
347        match from_ty.kind(Interner) {
348            TyKind::FnDef(..) => {
349                // Function items are coercible to any closure
350                // type; function pointers are not (that would
351                // require double indirection).
352                // Additionally, we permit coercion of function
353                // items to drop the unsafe qualifier.
354                self.coerce_from_fn_item(from_ty, to_ty)
355            }
356            TyKind::Function(from_fn_ptr) => {
357                // We permit coercion of fn pointers to drop the
358                // unsafe qualifier.
359                self.coerce_from_fn_pointer(from_ty.clone(), from_fn_ptr, to_ty)
360            }
361            TyKind::Closure(_, from_substs) => {
362                // Non-capturing closures are coercible to
363                // function pointers or unsafe function pointers.
364                // It cannot convert closures that require unsafe.
365                self.coerce_closure_to_fn(from_ty.clone(), from_substs, to_ty)
366            }
367            _ => {
368                // Otherwise, just use unification rules.
369                self.unify_and(&from_ty, to_ty, identity)
370            }
371        }
372    }
373
374    /// Unify two types (using sub or lub) and produce a specific coercion.
375    fn unify_and<F>(&mut self, t1: &Ty, t2: &Ty, f: F) -> CoerceResult
376    where
377        F: FnOnce(Ty) -> Vec<Adjustment>,
378    {
379        self.try_unify(t1, t2)
380            .and_then(|InferOk { goals, .. }| success(f(t1.clone()), t1.clone(), goals))
381    }
382
383    fn coerce_ptr(&mut self, from_ty: Ty, to_ty: &Ty, to_mt: Mutability) -> CoerceResult {
384        let (is_ref, from_mt, from_inner) = match from_ty.kind(Interner) {
385            TyKind::Ref(mt, _, ty) => (true, mt, ty),
386            TyKind::Raw(mt, ty) => (false, mt, ty),
387            _ => return self.unify_and(&from_ty, to_ty, identity),
388        };
389
390        coerce_mutabilities(*from_mt, to_mt)?;
391
392        // Check that the types which they point at are compatible.
393        let from_raw = TyKind::Raw(to_mt, from_inner.clone()).intern(Interner);
394
395        // Although references and raw ptrs have the same
396        // representation, we still register an Adjust::DerefRef so that
397        // regionck knows that the region for `a` must be valid here.
398        if is_ref {
399            self.unify_and(&from_raw, to_ty, |target| {
400                vec![
401                    Adjustment { kind: Adjust::Deref(None), target: from_inner.clone() },
402                    Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(to_mt)), target },
403                ]
404            })
405        } else if *from_mt != to_mt {
406            self.unify_and(
407                &from_raw,
408                to_ty,
409                simple(Adjust::Pointer(PointerCast::MutToConstPointer)),
410            )
411        } else {
412            self.unify_and(&from_raw, to_ty, identity)
413        }
414    }
415
416    /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
417    /// To match `A` with `B`, autoderef will be performed,
418    /// calling `deref`/`deref_mut` where necessary.
419    fn coerce_ref(
420        &mut self,
421        from_ty: Ty,
422        to_ty: &Ty,
423        to_mt: Mutability,
424        to_lt: &Lifetime,
425    ) -> CoerceResult {
426        let (_from_lt, from_mt) = match from_ty.kind(Interner) {
427            TyKind::Ref(mt, lt, _) => {
428                coerce_mutabilities(*mt, to_mt)?;
429                (lt.clone(), *mt) // clone is probably not good?
430            }
431            _ => return self.unify_and(&from_ty, to_ty, identity),
432        };
433
434        // NOTE: this code is mostly copied and adapted from rustc, and
435        // currently more complicated than necessary, carrying errors around
436        // etc.. This complication will become necessary when we actually track
437        // details of coercion errors though, so I think it's useful to leave
438        // the structure like it is.
439
440        let snapshot = self.snapshot();
441
442        let mut autoderef = Autoderef::new(self, from_ty.clone(), false, false);
443        let mut first_error = None;
444        let mut found = None;
445
446        while let Some((referent_ty, autoderefs)) = autoderef.next() {
447            if autoderefs == 0 {
448                // Don't let this pass, otherwise it would cause
449                // &T to autoref to &&T.
450                continue;
451            }
452
453            // At this point, we have deref'd `a` to `referent_ty`.  So
454            // imagine we are coercing from `&'a mut Vec<T>` to `&'b mut [T]`.
455            // In the autoderef loop for `&'a mut Vec<T>`, we would get
456            // three callbacks:
457            //
458            // - `&'a mut Vec<T>` -- 0 derefs, just ignore it
459            // - `Vec<T>` -- 1 deref
460            // - `[T]` -- 2 deref
461            //
462            // At each point after the first callback, we want to
463            // check to see whether this would match out target type
464            // (`&'b mut [T]`) if we autoref'd it. We can't just
465            // compare the referent types, though, because we still
466            // have to consider the mutability. E.g., in the case
467            // we've been considering, we have an `&mut` reference, so
468            // the `T` in `[T]` needs to be unified with equality.
469            //
470            // Therefore, we construct reference types reflecting what
471            // the types will be after we do the final auto-ref and
472            // compare those. Note that this means we use the target
473            // mutability [1], since it may be that we are coercing
474            // from `&mut T` to `&U`.
475            let lt = to_lt; // FIXME: Involve rustc LUB and SUB flag checks
476            let derefd_from_ty = TyKind::Ref(to_mt, lt.clone(), referent_ty).intern(Interner);
477            match autoderef.table.try_unify(&derefd_from_ty, to_ty) {
478                Ok(result) => {
479                    found = Some(result.map(|()| derefd_from_ty));
480                    break;
481                }
482                Err(err) => {
483                    if first_error.is_none() {
484                        first_error = Some(err);
485                    }
486                }
487            }
488        }
489
490        // Extract type or return an error. We return the first error
491        // we got, which should be from relating the "base" type
492        // (e.g., in example above, the failure from relating `Vec<T>`
493        // to the target type), since that should be the least
494        // confusing.
495        let InferOk { value: ty, goals } = match found {
496            Some(d) => d,
497            None => {
498                self.rollback_to(snapshot);
499                let err = first_error.expect("coerce_borrowed_pointer had no error");
500                return Err(err);
501            }
502        };
503        if ty == from_ty && from_mt == Mutability::Not && autoderef.step_count() == 1 {
504            // As a special case, if we would produce `&'a *x`, that's
505            // a total no-op. We end up with the type `&'a T` just as
506            // we started with.  In that case, just skip it
507            // altogether. This is just an optimization.
508            //
509            // Note that for `&mut`, we DO want to reborrow --
510            // otherwise, this would be a move, which might be an
511            // error. For example `foo(self.x)` where `self` and
512            // `self.x` both have `&mut `type would be a move of
513            // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
514            // which is a borrow.
515            always!(to_mt == Mutability::Not); // can only coerce &T -> &U
516            return success(vec![], ty, goals);
517        }
518
519        let mut adjustments = auto_deref_adjust_steps(&autoderef);
520        adjustments.push(Adjustment {
521            kind: Adjust::Borrow(AutoBorrow::Ref(to_lt.clone(), to_mt)),
522            target: ty.clone(),
523        });
524
525        success(adjustments, ty, goals)
526    }
527
528    /// Attempts to coerce from the type of a Rust function item into a function pointer.
529    fn coerce_from_fn_item(&mut self, from_ty: Ty, to_ty: &Ty) -> CoerceResult {
530        match to_ty.kind(Interner) {
531            TyKind::Function(_) => {
532                let from_sig = from_ty.callable_sig(self.db).expect("FnDef had no sig");
533
534                // FIXME check ABI: Intrinsics are not coercible to function pointers
535                // FIXME Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396)
536
537                // FIXME rustc normalizes assoc types in the sig here, not sure if necessary
538
539                let from_sig = from_sig.to_fn_ptr();
540                let from_fn_pointer = TyKind::Function(from_sig.clone()).intern(Interner);
541                let ok = self.coerce_from_safe_fn(
542                    from_fn_pointer.clone(),
543                    &from_sig,
544                    to_ty,
545                    |unsafe_ty| {
546                        vec![
547                            Adjustment {
548                                kind: Adjust::Pointer(PointerCast::ReifyFnPointer),
549                                target: from_fn_pointer,
550                            },
551                            Adjustment {
552                                kind: Adjust::Pointer(PointerCast::UnsafeFnPointer),
553                                target: unsafe_ty,
554                            },
555                        ]
556                    },
557                    simple(Adjust::Pointer(PointerCast::ReifyFnPointer)),
558                )?;
559
560                Ok(ok)
561            }
562            _ => self.unify_and(&from_ty, to_ty, identity),
563        }
564    }
565
566    fn coerce_from_fn_pointer(
567        &mut self,
568        from_ty: Ty,
569        from_f: &FnPointer,
570        to_ty: &Ty,
571    ) -> CoerceResult {
572        self.coerce_from_safe_fn(
573            from_ty,
574            from_f,
575            to_ty,
576            simple(Adjust::Pointer(PointerCast::UnsafeFnPointer)),
577            identity,
578        )
579    }
580
581    fn coerce_from_safe_fn<F, G>(
582        &mut self,
583        from_ty: Ty,
584        from_fn_ptr: &FnPointer,
585        to_ty: &Ty,
586        to_unsafe: F,
587        normal: G,
588    ) -> CoerceResult
589    where
590        F: FnOnce(Ty) -> Vec<Adjustment>,
591        G: FnOnce(Ty) -> Vec<Adjustment>,
592    {
593        if let TyKind::Function(to_fn_ptr) = to_ty.kind(Interner)
594            && let (chalk_ir::Safety::Safe, chalk_ir::Safety::Unsafe) =
595                (from_fn_ptr.sig.safety, to_fn_ptr.sig.safety)
596        {
597            let from_unsafe =
598                TyKind::Function(safe_to_unsafe_fn_ty(from_fn_ptr.clone())).intern(Interner);
599            return self.unify_and(&from_unsafe, to_ty, to_unsafe);
600        }
601        self.unify_and(&from_ty, to_ty, normal)
602    }
603
604    /// Attempts to coerce from the type of a non-capturing closure into a
605    /// function pointer.
606    fn coerce_closure_to_fn(
607        &mut self,
608        from_ty: Ty,
609        from_substs: &Substitution,
610        to_ty: &Ty,
611    ) -> CoerceResult {
612        match to_ty.kind(Interner) {
613            // if from_substs is non-capturing (FIXME)
614            TyKind::Function(fn_ty) => {
615                // We coerce the closure, which has fn type
616                //     `extern "rust-call" fn((arg0,arg1,...)) -> _`
617                // to
618                //     `fn(arg0,arg1,...) -> _`
619                // or
620                //     `unsafe fn(arg0,arg1,...) -> _`
621                let safety = fn_ty.sig.safety;
622                let pointer_ty = coerce_closure_fn_ty(from_substs, safety);
623                self.unify_and(
624                    &pointer_ty,
625                    to_ty,
626                    simple(Adjust::Pointer(PointerCast::ClosureFnPointer(safety))),
627                )
628            }
629            _ => self.unify_and(&from_ty, to_ty, identity),
630        }
631    }
632
633    /// Coerce a type using `from_ty: CoerceUnsized<ty_ty>`
634    ///
635    /// See: <https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html>
636    fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> CoerceResult {
637        // These 'if' statements require some explanation.
638        // The `CoerceUnsized` trait is special - it is only
639        // possible to write `impl CoerceUnsized<B> for A` where
640        // A and B have 'matching' fields. This rules out the following
641        // two types of blanket impls:
642        //
643        // `impl<T> CoerceUnsized<T> for SomeType`
644        // `impl<T> CoerceUnsized<SomeType> for T`
645        //
646        // Both of these trigger a special `CoerceUnsized`-related error (E0376)
647        //
648        // We can take advantage of this fact to avoid performing unnecessary work.
649        // If either `source` or `target` is a type variable, then any applicable impl
650        // would need to be generic over the self-type (`impl<T> CoerceUnsized<SomeType> for T`)
651        // or generic over the `CoerceUnsized` type parameter (`impl<T> CoerceUnsized<T> for
652        // SomeType`).
653        //
654        // However, these are exactly the kinds of impls which are forbidden by
655        // the compiler! Therefore, we can be sure that coercion will always fail
656        // when either the source or target type is a type variable. This allows us
657        // to skip performing any trait selection, and immediately bail out.
658        if from_ty.is_ty_var() {
659            return Err(TypeError);
660        }
661        if to_ty.is_ty_var() {
662            return Err(TypeError);
663        }
664
665        // Handle reborrows before trying to solve `Source: CoerceUnsized<Target>`.
666        let reborrow = match (from_ty.kind(Interner), to_ty.kind(Interner)) {
667            (TyKind::Ref(from_mt, _, from_inner), &TyKind::Ref(to_mt, _, _)) => {
668                coerce_mutabilities(*from_mt, to_mt)?;
669
670                let lt = self.new_lifetime_var();
671                Some((
672                    Adjustment { kind: Adjust::Deref(None), target: from_inner.clone() },
673                    Adjustment {
674                        kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), to_mt)),
675                        target: TyKind::Ref(to_mt, lt, from_inner.clone()).intern(Interner),
676                    },
677                ))
678            }
679            (TyKind::Ref(from_mt, _, from_inner), &TyKind::Raw(to_mt, _)) => {
680                coerce_mutabilities(*from_mt, to_mt)?;
681
682                Some((
683                    Adjustment { kind: Adjust::Deref(None), target: from_inner.clone() },
684                    Adjustment {
685                        kind: Adjust::Borrow(AutoBorrow::RawPtr(to_mt)),
686                        target: TyKind::Raw(to_mt, from_inner.clone()).intern(Interner),
687                    },
688                ))
689            }
690            _ => None,
691        };
692        let coerce_from =
693            reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone());
694
695        let krate = self.trait_env.krate;
696        let coerce_unsized_trait = match LangItem::CoerceUnsized.resolve_trait(self.db, krate) {
697            Some(trait_) => trait_,
698            _ => return Err(TypeError),
699        };
700
701        let coerce_unsized_tref = {
702            let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait);
703            if b.remaining() != 2 {
704                // The CoerceUnsized trait should have two generic params: Self and T.
705                return Err(TypeError);
706            }
707            b.push(coerce_from).push(to_ty.clone()).build()
708        };
709
710        let goal: InEnvironment<DomainGoal> =
711            InEnvironment::new(&self.trait_env.env, coerce_unsized_tref.cast(Interner));
712
713        let canonicalized = self.canonicalize_with_free_vars(goal);
714
715        // FIXME: rustc's coerce_unsized is more specialized -- it only tries to
716        // solve `CoerceUnsized` and `Unsize` goals at this point and leaves the
717        // rest for later. Also, there's some logic about sized type variables.
718        // Need to find out in what cases this is necessary
719        let solution = self.db.trait_solve(
720            krate,
721            self.trait_env.block,
722            canonicalized.value.clone().cast(Interner),
723        );
724
725        match solution {
726            // FIXME: this is a weaker guarantee than Chalk's `Guidance::Unique`
727            // was. Chalk's unique guidance at least guarantees that the real solution
728            // is some "subset" of the solutions matching the guidance, but the
729            // substs for `Certainty::No` don't have that same guarantee (I think).
730            NextTraitSolveResult::Certain(v) => {
731                canonicalized.apply_solution(
732                    self,
733                    Canonical {
734                        binders: v.binders,
735                        // FIXME handle constraints
736                        value: v.value.subst,
737                    },
738                );
739            }
740            // ...so, should think about how to get some actually get some guidance here
741            NextTraitSolveResult::Uncertain(..) | NextTraitSolveResult::NoSolution => {
742                return Err(TypeError);
743            }
744        }
745
746        let unsize =
747            Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target: to_ty.clone() };
748        let adjustments = match reborrow {
749            None => vec![unsize],
750            Some((deref, autoref)) => vec![deref, autoref, unsize],
751        };
752        success(adjustments, to_ty.clone(), vec![])
753    }
754}
755
756fn coerce_closure_fn_ty(closure_substs: &Substitution, safety: chalk_ir::Safety) -> Ty {
757    let closure_sig = ClosureSubst(closure_substs).sig_ty().clone();
758    match closure_sig.kind(Interner) {
759        TyKind::Function(fn_ty) => TyKind::Function(FnPointer {
760            num_binders: fn_ty.num_binders,
761            sig: FnSig { safety, abi: FnAbi::Rust, variadic: fn_ty.sig.variadic },
762            substitution: fn_ty.substitution.clone(),
763        })
764        .intern(Interner),
765        _ => TyKind::Error.intern(Interner),
766    }
767}
768
769fn safe_to_unsafe_fn_ty(fn_ty: FnPointer) -> FnPointer {
770    FnPointer {
771        num_binders: fn_ty.num_binders,
772        sig: FnSig { safety: chalk_ir::Safety::Unsafe, ..fn_ty.sig },
773        substitution: fn_ty.substitution,
774    }
775}
776
777fn coerce_mutabilities(from: Mutability, to: Mutability) -> Result<(), TypeError> {
778    match (from, to) {
779        (Mutability::Mut, Mutability::Mut | Mutability::Not)
780        | (Mutability::Not, Mutability::Not) => Ok(()),
781        (Mutability::Not, Mutability::Mut) => Err(TypeError),
782    }
783}
784
785pub(super) fn auto_deref_adjust_steps(autoderef: &Autoderef<'_, '_>) -> Vec<Adjustment> {
786    let steps = autoderef.steps();
787    let targets =
788        steps.iter().skip(1).map(|(_, ty)| ty.clone()).chain(iter::once(autoderef.final_ty()));
789    steps
790        .iter()
791        .map(|(kind, _source)| match kind {
792            // We do not know what kind of deref we require at this point yet
793            AutoderefKind::Overloaded => Some(OverloadedDeref(None)),
794            AutoderefKind::Builtin => None,
795        })
796        .zip(targets)
797        .map(|(autoderef, target)| Adjustment { kind: Adjust::Deref(autoderef), target })
798        .collect()
799}