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