]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //! # Type Coercion |
2 | //! | |
3 | //! Under certain circumstances we will coerce from one type to another, | |
9fa01778 | 4 | //! for example by auto-borrowing. This occurs in situations where the |
1a4d82fc JJ |
5 | //! compiler has a firm 'expected type' that was supplied from the user, |
6 | //! and where the actual type is similar to that expected type in purpose | |
7 | //! but not in representation (so actual subtyping is inappropriate). | |
8 | //! | |
9 | //! ## Reborrowing | |
10 | //! | |
11 | //! Note that if we are expecting a reference, we will *reborrow* | |
9fa01778 | 12 | //! even if the argument provided was already a reference. This is |
f035d41b XL |
13 | //! useful for freezing mut things (that is, when the expected type is &T |
14 | //! but you have &mut T) and also for avoiding the linearity | |
9fa01778 | 15 | //! of mut things (when the expected is &mut T and you have &mut T). See |
9c376795 | 16 | //! the various `tests/ui/coerce/*.rs` tests for |
1a4d82fc JJ |
17 | //! examples of where this is useful. |
18 | //! | |
19 | //! ## Subtle note | |
20 | //! | |
5e7ed085 | 21 | //! When inferring the generic arguments of functions, the argument |
f035d41b | 22 | //! order is relevant, which can lead to the following edge case: |
1a4d82fc | 23 | //! |
04454e1e | 24 | //! ```ignore (illustrative) |
f035d41b XL |
25 | //! fn foo<T>(a: T, b: T) { |
26 | //! // ... | |
27 | //! } | |
1a4d82fc | 28 | //! |
f035d41b XL |
29 | //! foo(&7i32, &mut 7i32); |
30 | //! // This compiles, as we first infer `T` to be `&i32`, | |
31 | //! // and then coerce `&mut 7i32` to `&7i32`. | |
1a4d82fc | 32 | //! |
f035d41b XL |
33 | //! foo(&mut 7i32, &7i32); |
34 | //! // This does not compile, as we first infer `T` to be `&mut i32` | |
35 | //! // and are then unable to coerce `&7i32` to `&mut i32`. | |
36 | //! ``` | |
1a4d82fc | 37 | |
2b03887a | 38 | use crate::FnCtxt; |
5e7ed085 | 39 | use rustc_errors::{ |
f2b60f7d | 40 | struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, |
5e7ed085 | 41 | }; |
dfeec247 | 42 | use rustc_hir as hir; |
29967ef6 | 43 | use rustc_hir::def_id::DefId; |
f2b60f7d FG |
44 | use rustc_hir::intravisit::{self, Visitor}; |
45 | use rustc_hir::Expr; | |
2b03887a | 46 | use rustc_hir_analysis::astconv::AstConv; |
74b04a01 | 47 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; |
353b0b11 FG |
48 | use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; |
49 | use rustc_infer::traits::{Obligation, PredicateObligation}; | |
6a06907d | 50 | use rustc_middle::lint::in_external_macro; |
ba9703b0 XL |
51 | use rustc_middle::ty::adjustment::{ |
52 | Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, | |
53 | }; | |
54 | use rustc_middle::ty::error::TypeError; | |
ba9703b0 XL |
55 | use rustc_middle::ty::relate::RelateResult; |
56 | use rustc_middle::ty::subst::SubstsRef; | |
9ffffee4 | 57 | use rustc_middle::ty::visit::TypeVisitableExt; |
487cf647 | 58 | use rustc_middle::ty::{self, Ty, TypeAndMut}; |
ba9703b0 | 59 | use rustc_session::parse::feature_err; |
dfeec247 | 60 | use rustc_span::symbol::sym; |
c295e0f8 | 61 | use rustc_span::{self, BytePos, DesugaringKind, Span}; |
dfeec247 | 62 | use rustc_target::spec::abi::Abi; |
923072b8 | 63 | use rustc_trait_selection::infer::InferCtxtExt as _; |
2b03887a | 64 | use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; |
487cf647 FG |
65 | use rustc_trait_selection::traits::{ |
66 | self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt, | |
67 | }; | |
ba9703b0 | 68 | |
a1dfa0c6 XL |
69 | use smallvec::{smallvec, SmallVec}; |
70 | use std::ops::Deref; | |
60c5eb7d | 71 | |
dc9dc135 XL |
72 | struct Coerce<'a, 'tcx> { |
73 | fcx: &'a FnCtxt<'a, 'tcx>, | |
476ff2be | 74 | cause: ObligationCause<'tcx>, |
54a0048b | 75 | use_lub: bool, |
83c7162d XL |
76 | /// Determines whether or not allow_two_phase_borrow is set on any |
77 | /// autoref adjustments we create while coercing. We don't want to | |
78 | /// allow deref coercions to create two-phase borrows, at least initially, | |
79 | /// but we do need two-phase borrows for function argument reborrows. | |
80 | /// See #47489 and #48598 | |
81 | /// See docs on the "AllowTwoPhase" type for a more detailed discussion | |
82 | allow_two_phase: AllowTwoPhase, | |
85aaf69f SL |
83 | } |
84 | ||
dc9dc135 XL |
85 | impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { |
86 | type Target = FnCtxt<'a, 'tcx>; | |
a7813a04 XL |
87 | fn deref(&self) -> &Self::Target { |
88 | &self.fcx | |
89 | } | |
90 | } | |
91 | ||
7cac9316 | 92 | type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>; |
54a0048b | 93 | |
f2b60f7d FG |
94 | struct CollectRetsVisitor<'tcx> { |
95 | ret_exprs: Vec<&'tcx hir::Expr<'tcx>>, | |
96 | } | |
97 | ||
98 | impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> { | |
99 | fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { | |
100 | if let hir::ExprKind::Ret(_) = expr.kind { | |
101 | self.ret_exprs.push(expr); | |
102 | } | |
103 | intravisit::walk_expr(self, expr); | |
104 | } | |
105 | } | |
106 | ||
f035d41b XL |
107 | /// Coercing a mutable reference to an immutable works, while |
108 | /// coercing `&T` to `&mut T` should be forbidden. | |
dfeec247 XL |
109 | fn coerce_mutbls<'tcx>( |
110 | from_mutbl: hir::Mutability, | |
111 | to_mutbl: hir::Mutability, | |
112 | ) -> RelateResult<'tcx, ()> { | |
487cf647 | 113 | if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) } |
54a0048b | 114 | } |
1a4d82fc | 115 | |
f9f354fc | 116 | /// Do not require any adjustments, i.e. coerce `x -> x`. |
dfeec247 XL |
117 | fn identity(_: Ty<'_>) -> Vec<Adjustment<'_>> { |
118 | vec![] | |
119 | } | |
7cac9316 | 120 | |
9c376795 | 121 | fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'_>> { |
7cac9316 | 122 | move |target| vec![Adjustment { kind, target }] |
8bb4bdeb XL |
123 | } |
124 | ||
f9f354fc | 125 | /// This always returns `Ok(...)`. |
dfeec247 XL |
126 | fn success<'tcx>( |
127 | adj: Vec<Adjustment<'tcx>>, | |
128 | target: Ty<'tcx>, | |
129 | obligations: traits::PredicateObligations<'tcx>, | |
130 | ) -> CoerceResult<'tcx> { | |
131 | Ok(InferOk { value: (adj, target), obligations }) | |
8bb4bdeb XL |
132 | } |
133 | ||
dc9dc135 XL |
134 | impl<'f, 'tcx> Coerce<'f, 'tcx> { |
135 | fn new( | |
136 | fcx: &'f FnCtxt<'f, 'tcx>, | |
137 | cause: ObligationCause<'tcx>, | |
138 | allow_two_phase: AllowTwoPhase, | |
139 | ) -> Self { | |
dfeec247 | 140 | Coerce { fcx, cause, allow_two_phase, use_lub: false } |
54a0048b SL |
141 | } |
142 | ||
8bb4bdeb | 143 | fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { |
f9f354fc | 144 | debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); |
a7813a04 | 145 | self.commit_if_ok(|_| { |
353b0b11 | 146 | let at = self.at(&self.cause, self.fcx.param_env); |
54a0048b | 147 | if self.use_lub { |
353b0b11 | 148 | at.lub(DefineOpaqueTypes::Yes, b, a) |
54a0048b | 149 | } else { |
353b0b11 | 150 | at.sup(DefineOpaqueTypes::Yes, b, a) |
7cac9316 | 151 | .map(|InferOk { value: (), obligations }| InferOk { value: a, obligations }) |
54a0048b SL |
152 | } |
153 | }) | |
85aaf69f SL |
154 | } |
155 | ||
8bb4bdeb | 156 | /// Unify two types (using sub or lub) and produce a specific coercion. |
dfeec247 XL |
157 | fn unify_and<F>(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) -> CoerceResult<'tcx> |
158 | where | |
159 | F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>, | |
7cac9316 | 160 | { |
5099ac24 | 161 | self.unify(a, b) |
dfeec247 | 162 | .and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations)) |
54a0048b SL |
163 | } |
164 | ||
c295e0f8 | 165 | #[instrument(skip(self))] |
7cac9316 | 166 | fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { |
94222f64 | 167 | // First, remove any resolved type variables (at the top level, at least): |
a7813a04 | 168 | let a = self.shallow_resolve(a); |
94222f64 | 169 | let b = self.shallow_resolve(b); |
54a0048b | 170 | debug!("Coerce.tys({:?} => {:?})", a, b); |
92a42be0 SL |
171 | |
172 | // Just ignore error types. | |
9ffffee4 | 173 | if let Err(guar) = (a, b).error_reported() { |
9c376795 FG |
174 | // Best-effort try to unify these types -- we're already on the error path, |
175 | // so this will have the side-effect of making sure we have no ambiguities | |
176 | // due to `[type error]` and `_` not coercing together. | |
9ffffee4 | 177 | let _ = self.commit_if_ok(|_| { |
353b0b11 | 178 | self.at(&self.cause, self.param_env).eq(DefineOpaqueTypes::Yes, a, b) |
9ffffee4 FG |
179 | }); |
180 | return success(vec![], self.fcx.tcx.ty_error(guar), vec![]); | |
92a42be0 SL |
181 | } |
182 | ||
94222f64 | 183 | // Coercing from `!` to any type is allowed: |
5bcae85e | 184 | if a.is_never() { |
c295e0f8 | 185 | return success(simple(Adjust::NeverToAny)(b), b, vec![]); |
5bcae85e SL |
186 | } |
187 | ||
94222f64 XL |
188 | // Coercing *from* an unresolved inference variable means that |
189 | // we have no information about the source type. This will always | |
190 | // ultimately fall back to some form of subtyping. | |
191 | if a.is_ty_var() { | |
192 | return self.coerce_from_inference_variable(a, b, identity); | |
193 | } | |
194 | ||
1a4d82fc | 195 | // Consider coercing the subtype to a DST |
ea8adc8c XL |
196 | // |
197 | // NOTE: this is wrapped in a `commit_if_ok` because it creates | |
198 | // a "spurious" type variable, and we don't want to have that | |
199 | // type variable in memory if the coercion fails. | |
200 | let unsize = self.commit_if_ok(|_| self.coerce_unsized(a, b)); | |
e74abb32 XL |
201 | match unsize { |
202 | Ok(_) => { | |
203 | debug!("coerce: unsize successful"); | |
204 | return unsize; | |
205 | } | |
3c0e092e XL |
206 | Err(error) => { |
207 | debug!(?error, "coerce: unsize failed"); | |
208 | } | |
1a4d82fc JJ |
209 | } |
210 | ||
211 | // Examine the supertype and consider auto-borrowing. | |
1b1a35ee | 212 | match *b.kind() { |
b7449926 | 213 | ty::RawPtr(mt_b) => { |
92a42be0 | 214 | return self.coerce_unsafe_ptr(a, b, mt_b.mutbl); |
1a4d82fc | 215 | } |
f9f354fc XL |
216 | ty::Ref(r_b, _, mutbl_b) => { |
217 | return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b); | |
1a4d82fc | 218 | } |
2b03887a FG |
219 | ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => { |
220 | return self.coerce_dyn_star(a, b, predicates, region); | |
221 | } | |
1a4d82fc JJ |
222 | _ => {} |
223 | } | |
224 | ||
1b1a35ee | 225 | match *a.kind() { |
b7449926 | 226 | ty::FnDef(..) => { |
92a42be0 SL |
227 | // Function items are coercible to any closure |
228 | // type; function pointers are not (that would | |
229 | // require double indirection). | |
c30ab7b3 SL |
230 | // Additionally, we permit coercion of function |
231 | // items to drop the unsafe qualifier. | |
041b39d2 | 232 | self.coerce_from_fn_item(a, b) |
1a4d82fc | 233 | } |
b7449926 | 234 | ty::FnPtr(a_f) => { |
92a42be0 SL |
235 | // We permit coercion of fn pointers to drop the |
236 | // unsafe qualifier. | |
237 | self.coerce_from_fn_pointer(a, a_f, b) | |
238 | } | |
29967ef6 | 239 | ty::Closure(closure_def_id_a, substs_a) => { |
8bb4bdeb | 240 | // Non-capturing closures are coercible to |
532ac7d7 XL |
241 | // function pointers or unsafe function pointers. |
242 | // It cannot convert closures that require unsafe. | |
29967ef6 | 243 | self.coerce_closure_to_fn(a, closure_def_id_a, substs_a, b) |
8bb4bdeb | 244 | } |
92a42be0 | 245 | _ => { |
54a0048b | 246 | // Otherwise, just use unification rules. |
7cac9316 | 247 | self.unify_and(a, b, identity) |
92a42be0 SL |
248 | } |
249 | } | |
1a4d82fc JJ |
250 | } |
251 | ||
94222f64 XL |
252 | /// Coercing *from* an inference variable. In this case, we have no information |
253 | /// about the source type, so we can't really do a true coercion and we always | |
254 | /// fall back to subtyping (`unify_and`). | |
255 | fn coerce_from_inference_variable( | |
256 | &self, | |
257 | a: Ty<'tcx>, | |
258 | b: Ty<'tcx>, | |
259 | make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>, | |
260 | ) -> CoerceResult<'tcx> { | |
261 | debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b); | |
064997fb FG |
262 | assert!(a.is_ty_var() && self.shallow_resolve(a) == a); |
263 | assert!(self.shallow_resolve(b) == b); | |
94222f64 XL |
264 | |
265 | if b.is_ty_var() { | |
266 | // Two unresolved type variables: create a `Coerce` predicate. | |
267 | let target_ty = if self.use_lub { | |
064997fb | 268 | self.next_ty_var(TypeVariableOrigin { |
94222f64 XL |
269 | kind: TypeVariableOriginKind::LatticeVariable, |
270 | span: self.cause.span, | |
271 | }) | |
272 | } else { | |
273 | b | |
274 | }; | |
275 | ||
276 | let mut obligations = Vec::with_capacity(2); | |
277 | for &source_ty in &[a, b] { | |
278 | if source_ty != target_ty { | |
279 | obligations.push(Obligation::new( | |
487cf647 | 280 | self.tcx(), |
94222f64 XL |
281 | self.cause.clone(), |
282 | self.param_env, | |
c295e0f8 | 283 | ty::Binder::dummy(ty::PredicateKind::Coerce(ty::CoercePredicate { |
94222f64 XL |
284 | a: source_ty, |
285 | b: target_ty, | |
487cf647 | 286 | })), |
94222f64 XL |
287 | )); |
288 | } | |
289 | } | |
290 | ||
291 | debug!( | |
292 | "coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}", | |
293 | target_ty, obligations | |
294 | ); | |
295 | let adjustments = make_adjustments(target_ty); | |
296 | InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations }) | |
297 | } else { | |
298 | // One unresolved type variable: just apply subtyping, we may be able | |
299 | // to do something useful. | |
300 | self.unify_and(a, b, make_adjustments) | |
301 | } | |
302 | } | |
303 | ||
85aaf69f SL |
304 | /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. |
305 | /// To match `A` with `B`, autoderef will be performed, | |
306 | /// calling `deref`/`deref_mut` where necessary. | |
dfeec247 XL |
307 | fn coerce_borrowed_pointer( |
308 | &self, | |
309 | a: Ty<'tcx>, | |
310 | b: Ty<'tcx>, | |
311 | r_b: ty::Region<'tcx>, | |
f9f354fc | 312 | mutbl_b: hir::Mutability, |
dfeec247 | 313 | ) -> CoerceResult<'tcx> { |
54a0048b | 314 | debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); |
1a4d82fc JJ |
315 | |
316 | // If we have a parameter of type `&M T_a` and the value | |
317 | // provided is `expr`, we will be adding an implicit borrow, | |
9c376795 | 318 | // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore, |
1a4d82fc JJ |
319 | // to type check, we will construct the type that `&M*expr` would |
320 | // yield. | |
321 | ||
1b1a35ee | 322 | let (r_a, mt_a) = match *a.kind() { |
b7449926 | 323 | ty::Ref(r_a, ty, mutbl) => { |
94b46f34 | 324 | let mt_a = ty::TypeAndMut { ty, mutbl }; |
f9f354fc | 325 | coerce_mutbls(mt_a.mutbl, mutbl_b)?; |
54a0048b | 326 | (r_a, mt_a) |
1a4d82fc | 327 | } |
7cac9316 | 328 | _ => return self.unify_and(a, b, identity), |
54a0048b | 329 | }; |
1a4d82fc | 330 | |
476ff2be | 331 | let span = self.cause.span; |
9346a6ac | 332 | |
85aaf69f | 333 | let mut first_error = None; |
54a0048b | 334 | let mut r_borrow_var = None; |
3157f602 | 335 | let mut autoderef = self.autoderef(span, a); |
8bb4bdeb | 336 | let mut found = None; |
3157f602 XL |
337 | |
338 | for (referent_ty, autoderefs) in autoderef.by_ref() { | |
339 | if autoderefs == 0 { | |
85aaf69f SL |
340 | // Don't let this pass, otherwise it would cause |
341 | // &T to autoref to &&T. | |
c30ab7b3 | 342 | continue; |
85aaf69f | 343 | } |
54a0048b | 344 | |
9c376795 | 345 | // At this point, we have deref'd `a` to `referent_ty`. So |
54a0048b SL |
346 | // imagine we are coercing from `&'a mut Vec<T>` to `&'b mut [T]`. |
347 | // In the autoderef loop for `&'a mut Vec<T>`, we would get | |
348 | // three callbacks: | |
349 | // | |
350 | // - `&'a mut Vec<T>` -- 0 derefs, just ignore it | |
351 | // - `Vec<T>` -- 1 deref | |
352 | // - `[T]` -- 2 deref | |
353 | // | |
354 | // At each point after the first callback, we want to | |
355 | // check to see whether this would match out target type | |
356 | // (`&'b mut [T]`) if we autoref'd it. We can't just | |
357 | // compare the referent types, though, because we still | |
358 | // have to consider the mutability. E.g., in the case | |
359 | // we've been considering, we have an `&mut` reference, so | |
360 | // the `T` in `[T]` needs to be unified with equality. | |
361 | // | |
362 | // Therefore, we construct reference types reflecting what | |
363 | // the types will be after we do the final auto-ref and | |
364 | // compare those. Note that this means we use the target | |
365 | // mutability [1], since it may be that we are coercing | |
366 | // from `&mut T` to `&U`. | |
367 | // | |
368 | // One fine point concerns the region that we use. We | |
369 | // choose the region such that the region of the final | |
370 | // type that results from `unify` will be the region we | |
371 | // want for the autoref: | |
372 | // | |
373 | // - if in sub mode, that means we want to use `'b` (the | |
374 | // region from the target reference) for both | |
375 | // pointers [2]. This is because sub mode (somewhat | |
9c376795 | 376 | // arbitrarily) returns the subtype region. In the case |
54a0048b SL |
377 | // where we are coercing to a target type, we know we |
378 | // want to use that target type region (`'b`) because -- | |
379 | // for the program to type-check -- it must be the | |
380 | // smaller of the two. | |
381 | // - One fine point. It may be surprising that we can | |
382 | // use `'b` without relating `'a` and `'b`. The reason | |
383 | // that this is ok is that what we produce is | |
384 | // effectively a `&'b *x` expression (if you could | |
385 | // annotate the region of a borrow), and regionck has | |
386 | // code that adds edges from the region of a borrow | |
387 | // (`'b`, here) into the regions in the borrowed | |
9c376795 | 388 | // expression (`*x`, here). (Search for "link".) |
54a0048b SL |
389 | // - if in lub mode, things can get fairly complicated. The |
390 | // easiest thing is just to make a fresh | |
391 | // region variable [4], which effectively means we defer | |
392 | // the decision to region inference (and regionck, which will add | |
393 | // some more edges to this variable). However, this can wind up | |
394 | // creating a crippling number of variables in some cases -- | |
0731742a | 395 | // e.g., #32278 -- so we optimize one particular case [3]. |
54a0048b SL |
396 | // Let me try to explain with some examples: |
397 | // - The "running example" above represents the simple case, | |
398 | // where we have one `&` reference at the outer level and | |
399 | // ownership all the rest of the way down. In this case, | |
400 | // we want `LUB('a, 'b)` as the resulting region. | |
401 | // - However, if there are nested borrows, that region is | |
402 | // too strong. Consider a coercion from `&'a &'x Rc<T>` to | |
403 | // `&'b T`. In this case, `'a` is actually irrelevant. | |
404 | // The pointer we want is `LUB('x, 'b`). If we choose `LUB('a,'b)` | |
416331ca | 405 | // we get spurious errors (`ui/regions-lub-ref-ref-rc.rs`). |
54a0048b SL |
406 | // (The errors actually show up in borrowck, typically, because |
407 | // this extra edge causes the region `'a` to be inferred to something | |
408 | // too big, which then results in borrowck errors.) | |
409 | // - We could track the innermost shared reference, but there is already | |
410 | // code in regionck that has the job of creating links between | |
411 | // the region of a borrow and the regions in the thing being | |
412 | // borrowed (here, `'a` and `'x`), and it knows how to handle | |
413 | // all the various cases. So instead we just make a region variable | |
414 | // and let regionck figure it out. | |
415 | let r = if !self.use_lub { | |
416 | r_b // [2] above | |
3157f602 | 417 | } else if autoderefs == 1 { |
54a0048b | 418 | r_a // [3] above |
85aaf69f | 419 | } else { |
c30ab7b3 | 420 | if r_borrow_var.is_none() { |
f9f354fc | 421 | // create var lazily, at most once |
54a0048b | 422 | let coercion = Coercion(span); |
a7813a04 | 423 | let r = self.next_region_var(coercion); |
9e0c209e | 424 | r_borrow_var = Some(r); // [4] above |
54a0048b SL |
425 | } |
426 | r_borrow_var.unwrap() | |
427 | }; | |
dfeec247 XL |
428 | let derefd_ty_a = self.tcx.mk_ref( |
429 | r, | |
430 | TypeAndMut { | |
431 | ty: referent_ty, | |
f9f354fc | 432 | mutbl: mutbl_b, // [1] above |
dfeec247 XL |
433 | }, |
434 | ); | |
54a0048b | 435 | match self.unify(derefd_ty_a, b) { |
8bb4bdeb | 436 | Ok(ok) => { |
7cac9316 | 437 | found = Some(ok); |
c30ab7b3 SL |
438 | break; |
439 | } | |
54a0048b SL |
440 | Err(err) => { |
441 | if first_error.is_none() { | |
442 | first_error = Some(err); | |
443 | } | |
54a0048b | 444 | } |
85aaf69f | 445 | } |
3157f602 | 446 | } |
85aaf69f | 447 | |
54a0048b SL |
448 | // Extract type or return an error. We return the first error |
449 | // we got, which should be from relating the "base" type | |
450 | // (e.g., in example above, the failure from relating `Vec<T>` | |
451 | // to the target type), since that should be the least | |
452 | // confusing. | |
5e7ed085 FG |
453 | let Some(InferOk { value: ty, mut obligations }) = found else { |
454 | let err = first_error.expect("coerce_borrowed_pointer had no error"); | |
455 | debug!("coerce_borrowed_pointer: failed with err = {:?}", err); | |
456 | return Err(err); | |
54a0048b SL |
457 | }; |
458 | ||
487cf647 | 459 | if ty == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 { |
54a0048b SL |
460 | // As a special case, if we would produce `&'a *x`, that's |
461 | // a total no-op. We end up with the type `&'a T` just as | |
9c376795 | 462 | // we started with. In that case, just skip it |
54a0048b SL |
463 | // altogether. This is just an optimization. |
464 | // | |
465 | // Note that for `&mut`, we DO want to reborrow -- | |
466 | // otherwise, this would be a move, which might be an | |
467 | // error. For example `foo(self.x)` where `self` and | |
468 | // `self.x` both have `&mut `type would be a move of | |
469 | // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, | |
470 | // which is a borrow. | |
487cf647 | 471 | assert!(mutbl_b.is_not()); // can only coerce &T -> &U |
7cac9316 | 472 | return success(vec![], ty, obligations); |
85aaf69f | 473 | } |
8bb4bdeb | 474 | |
dfeec247 | 475 | let InferOk { value: mut adjustments, obligations: o } = |
f035d41b | 476 | self.adjust_steps_as_infer_ok(&autoderef); |
7cac9316 XL |
477 | obligations.extend(o); |
478 | obligations.extend(autoderef.into_obligations()); | |
479 | ||
8bb4bdeb XL |
480 | // Now apply the autoref. We have to extract the region out of |
481 | // the final ref type we got. | |
5e7ed085 FG |
482 | let ty::Ref(r_borrow, _, _) = ty.kind() else { |
483 | span_bug!(span, "expected a ref type, got {:?}", ty); | |
54a0048b | 484 | }; |
487cf647 | 485 | let mutbl = AutoBorrowMutability::new(mutbl_b, self.allow_two_phase); |
7cac9316 | 486 | adjustments.push(Adjustment { |
5099ac24 | 487 | kind: Adjust::Borrow(AutoBorrow::Ref(*r_borrow, mutbl)), |
dfeec247 | 488 | target: ty, |
7cac9316 | 489 | }); |
8bb4bdeb | 490 | |
dfeec247 | 491 | debug!("coerce_borrowed_pointer: succeeded ty={:?} adjustments={:?}", ty, adjustments); |
8bb4bdeb | 492 | |
7cac9316 | 493 | success(adjustments, ty, obligations) |
1a4d82fc JJ |
494 | } |
495 | ||
62682a34 SL |
496 | // &[T; n] or &mut [T; n] -> &[T] |
497 | // or &mut [T; n] -> &mut [T] | |
1a4d82fc | 498 | // or &Concrete -> &Trait, etc. |
c295e0f8 | 499 | #[instrument(skip(self), level = "debug")] |
f9f354fc | 500 | fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> { |
f9f354fc XL |
501 | source = self.shallow_resolve(source); |
502 | target = self.shallow_resolve(target); | |
c295e0f8 | 503 | debug!(?source, ?target); |
f9f354fc | 504 | |
487cf647 FG |
505 | // We don't apply any coercions incase either the source or target |
506 | // aren't sufficiently well known but tend to instead just equate | |
507 | // them both. | |
f9f354fc XL |
508 | if source.is_ty_var() { |
509 | debug!("coerce_unsized: source is a TyVar, bailing out"); | |
510 | return Err(TypeError::Mismatch); | |
511 | } | |
512 | if target.is_ty_var() { | |
513 | debug!("coerce_unsized: target is a TyVar, bailing out"); | |
514 | return Err(TypeError::Mismatch); | |
515 | } | |
516 | ||
dfeec247 XL |
517 | let traits = |
518 | (self.tcx.lang_items().unsize_trait(), self.tcx.lang_items().coerce_unsized_trait()); | |
3c0e092e | 519 | let (Some(unsize_did), Some(coerce_unsized_did)) = traits else { |
416331ca | 520 | debug!("missing Unsize or CoerceUnsized traits"); |
c1a9b12d | 521 | return Err(TypeError::Mismatch); |
d9579d0f | 522 | }; |
1a4d82fc JJ |
523 | |
524 | // Note, we want to avoid unnecessary unsizing. We don't want to coerce to | |
525 | // a DST unless we have to. This currently comes out in the wash since | |
526 | // we can't unify [T] with U. But to properly support DST, we need to allow | |
d9579d0f | 527 | // that, at which point we will need extra checks on the target here. |
1a4d82fc | 528 | |
d9579d0f | 529 | // Handle reborrows before selecting `Source: CoerceUnsized<Target>`. |
1b1a35ee | 530 | let reborrow = match (source.kind(), target.kind()) { |
b7449926 | 531 | (&ty::Ref(_, ty_a, mutbl_a), &ty::Ref(_, _, mutbl_b)) => { |
94b46f34 | 532 | coerce_mutbls(mutbl_a, mutbl_b)?; |
d9579d0f | 533 | |
476ff2be | 534 | let coercion = Coercion(self.cause.span); |
a7813a04 | 535 | let r_borrow = self.next_region_var(coercion); |
487cf647 FG |
536 | |
537 | // We don't allow two-phase borrows here, at least for initial | |
538 | // implementation. If it happens that this coercion is a function argument, | |
539 | // the reborrow in coerce_borrowed_ptr will pick it up. | |
540 | let mutbl = AutoBorrowMutability::new(mutbl_b, AllowTwoPhase::No); | |
541 | ||
dfeec247 XL |
542 | Some(( |
543 | Adjustment { kind: Adjust::Deref(None), target: ty_a }, | |
544 | Adjustment { | |
545 | kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)), | |
546 | target: self | |
547 | .tcx | |
548 | .mk_ref(r_borrow, ty::TypeAndMut { mutbl: mutbl_b, ty: ty_a }), | |
549 | }, | |
550 | )) | |
1a4d82fc | 551 | } |
b7449926 | 552 | (&ty::Ref(_, ty_a, mt_a), &ty::RawPtr(ty::TypeAndMut { mutbl: mt_b, .. })) => { |
94b46f34 | 553 | coerce_mutbls(mt_a, mt_b)?; |
8bb4bdeb | 554 | |
dfeec247 XL |
555 | Some(( |
556 | Adjustment { kind: Adjust::Deref(None), target: ty_a }, | |
557 | Adjustment { | |
558 | kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b)), | |
559 | target: self.tcx.mk_ptr(ty::TypeAndMut { mutbl: mt_b, ty: ty_a }), | |
560 | }, | |
561 | )) | |
7cac9316 XL |
562 | } |
563 | _ => None, | |
8bb4bdeb | 564 | }; |
487cf647 | 565 | let coerce_source = reborrow.as_ref().map_or(source, |(_, r)| r.target); |
8bb4bdeb XL |
566 | |
567 | // Setup either a subtyping or a LUB relationship between | |
568 | // the `CoerceUnsized` target type and the expected type. | |
569 | // We only have the latter, so we use an inference variable | |
570 | // for the former and let type inference do the rest. | |
dc9dc135 XL |
571 | let origin = TypeVariableOrigin { |
572 | kind: TypeVariableOriginKind::MiscVariable, | |
573 | span: self.cause.span, | |
574 | }; | |
8bb4bdeb | 575 | let coerce_target = self.next_ty_var(origin); |
7cac9316 | 576 | let mut coercion = self.unify_and(coerce_target, target, |target| { |
dfeec247 | 577 | let unsize = Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target }; |
7cac9316 XL |
578 | match reborrow { |
579 | None => vec![unsize], | |
dfeec247 | 580 | Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone(), unsize], |
7cac9316 XL |
581 | } |
582 | })?; | |
d9579d0f | 583 | |
a7813a04 | 584 | let mut selcx = traits::SelectionContext::new(self); |
d9579d0f | 585 | |
d9579d0f | 586 | // Create an obligation for `Source: CoerceUnsized<Target>`. |
e74abb32 XL |
587 | let cause = ObligationCause::new( |
588 | self.cause.span, | |
589 | self.body_id, | |
590 | ObligationCauseCode::Coercion { source, target }, | |
591 | ); | |
a1dfa0c6 XL |
592 | |
593 | // Use a FIFO queue for this custom fulfillment procedure. | |
594 | // | |
595 | // A Vec (or SmallVec) is not a natural choice for a queue. However, | |
596 | // this code path is hot, and this queue usually has a max length of 1 | |
597 | // and almost never more than 3. By using a SmallVec we avoid an | |
598 | // allocation, at the (very small) cost of (occasionally) having to | |
599 | // shift subsequent elements down when removing the front element. | |
353b0b11 | 600 | let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new( |
dfeec247 | 601 | self.tcx, |
dfeec247 | 602 | cause, |
353b0b11 | 603 | self.fcx.param_env, |
49aad941 | 604 | ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]) |
dfeec247 | 605 | )]; |
d9579d0f | 606 | |
041b39d2 | 607 | let mut has_unsized_tuple_coercion = false; |
923072b8 | 608 | let mut has_trait_upcasting_coercion = None; |
041b39d2 | 609 | |
d9579d0f AL |
610 | // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid |
611 | // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where | |
612 | // inference might unify those two inner type variables later. | |
613 | let traits = [coerce_unsized_did, unsize_did]; | |
a1dfa0c6 XL |
614 | while !queue.is_empty() { |
615 | let obligation = queue.remove(0); | |
62682a34 | 616 | debug!("coerce_unsized resolve step: {:?}", obligation); |
5869c6ff | 617 | let bound_predicate = obligation.predicate.kind(); |
29967ef6 | 618 | let trait_pred = match bound_predicate.skip_binder() { |
487cf647 FG |
619 | ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) |
620 | if traits.contains(&trait_pred.def_id()) => | |
621 | { | |
ba9703b0 | 622 | if unsize_did == trait_pred.def_id() { |
94222f64 | 623 | let self_ty = trait_pred.self_ty(); |
3dfed10e | 624 | let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty(); |
94222f64 XL |
625 | if let (ty::Dynamic(ref data_a, ..), ty::Dynamic(ref data_b, ..)) = |
626 | (self_ty.kind(), unsize_ty.kind()) | |
04454e1e | 627 | && data_a.principal_def_id() != data_b.principal_def_id() |
94222f64 | 628 | { |
04454e1e | 629 | debug!("coerce_unsized: found trait upcasting coercion"); |
923072b8 | 630 | has_trait_upcasting_coercion = Some((self_ty, unsize_ty)); |
94222f64 | 631 | } |
1b1a35ee | 632 | if let ty::Tuple(..) = unsize_ty.kind() { |
041b39d2 XL |
633 | debug!("coerce_unsized: found unsized tuple coercion"); |
634 | has_unsized_tuple_coercion = true; | |
635 | } | |
636 | } | |
29967ef6 | 637 | bound_predicate.rebind(trait_pred) |
041b39d2 | 638 | } |
d9579d0f | 639 | _ => { |
8bb4bdeb | 640 | coercion.obligations.push(obligation); |
d9579d0f AL |
641 | continue; |
642 | } | |
643 | }; | |
487cf647 | 644 | match selcx.select(&obligation.with(selcx.tcx(), trait_pred)) { |
d9579d0f | 645 | // Uncertain or unimplemented. |
0731742a | 646 | Ok(None) => { |
ba9703b0 | 647 | if trait_pred.def_id() == unsize_did { |
fc512014 | 648 | let trait_pred = self.resolve_vars_if_possible(trait_pred); |
ba9703b0 XL |
649 | let self_ty = trait_pred.skip_binder().self_ty(); |
650 | let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty(); | |
651 | debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); | |
353b0b11 FG |
652 | match (self_ty.kind(), unsize_ty.kind()) { |
653 | (&ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) | |
654 | if self.type_var_is_sized(v) => | |
dfeec247 | 655 | { |
0731742a XL |
656 | debug!("coerce_unsized: have sized infer {:?}", v); |
657 | coercion.obligations.push(obligation); | |
658 | // `$0: Unsize<dyn Trait>` where we know that `$0: Sized`, try going | |
659 | // for unsizing. | |
660 | } | |
661 | _ => { | |
662 | // Some other case for `$0: Unsize<Something>`. Note that we | |
663 | // hit this case even if `Something` is a sized type, so just | |
664 | // don't do the coercion. | |
665 | debug!("coerce_unsized: ambiguous unsize"); | |
666 | return Err(TypeError::Mismatch); | |
667 | } | |
668 | } | |
669 | } else { | |
670 | debug!("coerce_unsized: early return - ambiguous"); | |
671 | return Err(TypeError::Mismatch); | |
672 | } | |
673 | } | |
c30ab7b3 | 674 | Err(traits::Unimplemented) => { |
d9579d0f | 675 | debug!("coerce_unsized: early return - can't prove obligation"); |
c1a9b12d | 676 | return Err(TypeError::Mismatch); |
c34b1796 | 677 | } |
d9579d0f AL |
678 | |
679 | // Object safety violations or miscellaneous. | |
680 | Err(err) => { | |
487cf647 | 681 | self.err_ctxt().report_selection_error(obligation.clone(), &obligation, &err); |
d9579d0f AL |
682 | // Treat this like an obligation and follow through |
683 | // with the unsizing - the lack of a coercion should | |
684 | // be silent, as it causes a type mismatch later. | |
685 | } | |
686 | ||
f035d41b | 687 | Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()), |
1a4d82fc | 688 | } |
d9579d0f AL |
689 | } |
690 | ||
0531ce1d | 691 | if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { |
dfeec247 | 692 | feature_err( |
60c5eb7d XL |
693 | &self.tcx.sess.parse_sess, |
694 | sym::unsized_tuple_coercion, | |
695 | self.cause.span, | |
696 | "unsized tuple coercion is not stable enough for use and is subject to change", | |
697 | ) | |
698 | .emit(); | |
041b39d2 XL |
699 | } |
700 | ||
923072b8 FG |
701 | if let Some((sub, sup)) = has_trait_upcasting_coercion |
702 | && !self.tcx().features().trait_upcasting | |
703 | { | |
704 | // Renders better when we erase regions, since they're not really the point here. | |
705 | let (sub, sup) = self.tcx.erase_regions((sub, sup)); | |
706 | let mut err = feature_err( | |
94222f64 XL |
707 | &self.tcx.sess.parse_sess, |
708 | sym::trait_upcasting, | |
709 | self.cause.span, | |
49aad941 | 710 | format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"), |
923072b8 | 711 | ); |
49aad941 | 712 | err.note(format!("required when coercing `{source}` into `{target}`")); |
923072b8 | 713 | err.emit(); |
94222f64 XL |
714 | } |
715 | ||
8bb4bdeb | 716 | Ok(coercion) |
1a4d82fc JJ |
717 | } |
718 | ||
2b03887a FG |
719 | fn coerce_dyn_star( |
720 | &self, | |
721 | a: Ty<'tcx>, | |
722 | b: Ty<'tcx>, | |
487cf647 | 723 | predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, |
2b03887a FG |
724 | b_region: ty::Region<'tcx>, |
725 | ) -> CoerceResult<'tcx> { | |
726 | if !self.tcx.features().dyn_star { | |
727 | return Err(TypeError::Mismatch); | |
728 | } | |
729 | ||
730 | if let ty::Dynamic(a_data, _, _) = a.kind() | |
731 | && let ty::Dynamic(b_data, _, _) = b.kind() | |
487cf647 | 732 | && a_data.principal_def_id() == b_data.principal_def_id() |
2b03887a | 733 | { |
487cf647 | 734 | return self.unify_and(a, b, |_| vec![]); |
2b03887a FG |
735 | } |
736 | ||
737 | // Check the obligations of the cast -- for example, when casting | |
738 | // `usize` to `dyn* Clone + 'static`: | |
487cf647 | 739 | let mut obligations: Vec<_> = predicates |
2b03887a FG |
740 | .iter() |
741 | .map(|predicate| { | |
742 | // For each existential predicate (e.g., `?Self: Clone`) substitute | |
743 | // the type of the expression (e.g., `usize` in our example above) | |
744 | // and then require that the resulting predicate (e.g., `usize: Clone`) | |
745 | // holds (it does). | |
746 | let predicate = predicate.with_self_ty(self.tcx, a); | |
487cf647 | 747 | Obligation::new(self.tcx, self.cause.clone(), self.param_env, predicate) |
2b03887a | 748 | }) |
487cf647 FG |
749 | .chain([ |
750 | // Enforce the region bound (e.g., `usize: 'static`, in our example). | |
751 | Obligation::new( | |
752 | self.tcx, | |
753 | self.cause.clone(), | |
754 | self.param_env, | |
755 | ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::TypeOutlives( | |
756 | ty::OutlivesPredicate(a, b_region), | |
757 | ))), | |
758 | ), | |
759 | ]) | |
2b03887a FG |
760 | .collect(); |
761 | ||
487cf647 FG |
762 | // Enforce that the type is `usize`/pointer-sized. |
763 | obligations.push(Obligation::new( | |
764 | self.tcx, | |
765 | self.cause.clone(), | |
766 | self.param_env, | |
49aad941 FG |
767 | ty::TraitRef::from_lang_item( |
768 | self.tcx, | |
769 | hir::LangItem::PointerLike, | |
770 | self.cause.span, | |
771 | [a], | |
487cf647 FG |
772 | ), |
773 | )); | |
774 | ||
2b03887a FG |
775 | Ok(InferOk { |
776 | value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b), | |
777 | obligations, | |
778 | }) | |
779 | } | |
780 | ||
dfeec247 XL |
781 | fn coerce_from_safe_fn<F, G>( |
782 | &self, | |
783 | a: Ty<'tcx>, | |
784 | fn_ty_a: ty::PolyFnSig<'tcx>, | |
785 | b: Ty<'tcx>, | |
786 | to_unsafe: F, | |
787 | normal: G, | |
788 | ) -> CoerceResult<'tcx> | |
789 | where | |
790 | F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>, | |
791 | G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>, | |
7cac9316 | 792 | { |
064997fb | 793 | self.commit_if_ok(|snapshot| { |
923072b8 FG |
794 | let result = if let ty::FnPtr(fn_ty_b) = b.kind() |
795 | && let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) = | |
796 | (fn_ty_a.unsafety(), fn_ty_b.unsafety()) | |
797 | { | |
798 | let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); | |
799 | self.unify_and(unsafe_a, b, to_unsafe) | |
800 | } else { | |
801 | self.unify_and(a, b, normal) | |
802 | }; | |
803 | ||
804 | // FIXME(#73154): This is a hack. Currently LUB can generate | |
805 | // unsolvable constraints. Additionally, it returns `a` | |
806 | // unconditionally, even when the "LUB" is `b`. In the future, we | |
807 | // want the coerced type to be the actual supertype of these two, | |
808 | // but for now, we want to just error to ensure we don't lock | |
809 | // ourselves into a specific behavior with NLL. | |
810 | self.leak_check(false, snapshot)?; | |
811 | ||
812 | result | |
813 | }) | |
1a4d82fc JJ |
814 | } |
815 | ||
dfeec247 XL |
816 | fn coerce_from_fn_pointer( |
817 | &self, | |
818 | a: Ty<'tcx>, | |
819 | fn_ty_a: ty::PolyFnSig<'tcx>, | |
820 | b: Ty<'tcx>, | |
821 | ) -> CoerceResult<'tcx> { | |
c30ab7b3 SL |
822 | //! Attempts to coerce from the type of a Rust function item |
823 | //! into a closure or a `proc`. | |
824 | //! | |
825 | ||
826 | let b = self.shallow_resolve(b); | |
827 | debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); | |
828 | ||
dfeec247 XL |
829 | self.coerce_from_safe_fn( |
830 | a, | |
831 | fn_ty_a, | |
832 | b, | |
833 | simple(Adjust::Pointer(PointerCast::UnsafeFnPointer)), | |
834 | identity, | |
835 | ) | |
c30ab7b3 SL |
836 | } |
837 | ||
dfeec247 | 838 | fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { |
c30ab7b3 SL |
839 | //! Attempts to coerce from the type of a Rust function item |
840 | //! into a closure or a `proc`. | |
1a4d82fc | 841 | |
a7813a04 | 842 | let b = self.shallow_resolve(b); |
94222f64 | 843 | let InferOk { value: b, mut obligations } = |
487cf647 | 844 | self.at(&self.cause, self.param_env).normalize(b); |
54a0048b | 845 | debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b); |
1a4d82fc | 846 | |
1b1a35ee | 847 | match b.kind() { |
f9f354fc | 848 | ty::FnPtr(b_sig) => { |
041b39d2 | 849 | let a_sig = a.fn_sig(self.tcx); |
923072b8 FG |
850 | if let ty::FnDef(def_id, _) = *a.kind() { |
851 | // Intrinsics are not coercible to function pointers | |
852 | if self.tcx.is_intrinsic(def_id) { | |
853 | return Err(TypeError::IntrinsicCast); | |
854 | } | |
855 | ||
856 | // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396). | |
f9f354fc | 857 | |
923072b8 FG |
858 | if b_sig.unsafety() == hir::Unsafety::Normal |
859 | && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() | |
860 | { | |
861 | return Err(TypeError::TargetFeatureCast(def_id)); | |
862 | } | |
f9f354fc XL |
863 | } |
864 | ||
94222f64 | 865 | let InferOk { value: a_sig, obligations: o1 } = |
487cf647 | 866 | self.at(&self.cause, self.param_env).normalize(a_sig); |
94222f64 | 867 | obligations.extend(o1); |
041b39d2 XL |
868 | |
869 | let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig); | |
ff7c6d11 XL |
870 | let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn( |
871 | a_fn_pointer, | |
872 | a_sig, | |
873 | b, | |
874 | |unsafe_ty| { | |
875 | vec![ | |
48663c56 XL |
876 | Adjustment { |
877 | kind: Adjust::Pointer(PointerCast::ReifyFnPointer), | |
dfeec247 | 878 | target: a_fn_pointer, |
48663c56 XL |
879 | }, |
880 | Adjustment { | |
881 | kind: Adjust::Pointer(PointerCast::UnsafeFnPointer), | |
dfeec247 | 882 | target: unsafe_ty, |
48663c56 | 883 | }, |
ff7c6d11 XL |
884 | ] |
885 | }, | |
dfeec247 | 886 | simple(Adjust::Pointer(PointerCast::ReifyFnPointer)), |
ff7c6d11 | 887 | )?; |
041b39d2 XL |
888 | |
889 | obligations.extend(o2); | |
890 | Ok(InferOk { value, obligations }) | |
8bb4bdeb | 891 | } |
7cac9316 | 892 | _ => self.unify_and(a, b, identity), |
8bb4bdeb XL |
893 | } |
894 | } | |
895 | ||
dfeec247 XL |
896 | fn coerce_closure_to_fn( |
897 | &self, | |
898 | a: Ty<'tcx>, | |
29967ef6 | 899 | closure_def_id_a: DefId, |
dfeec247 XL |
900 | substs_a: SubstsRef<'tcx>, |
901 | b: Ty<'tcx>, | |
902 | ) -> CoerceResult<'tcx> { | |
8bb4bdeb XL |
903 | //! Attempts to coerce from the type of a non-capturing closure |
904 | //! into a function pointer. | |
905 | //! | |
906 | ||
907 | let b = self.shallow_resolve(b); | |
908 | ||
1b1a35ee | 909 | match b.kind() { |
29967ef6 XL |
910 | // At this point we haven't done capture analysis, which means |
911 | // that the ClosureSubsts just contains an inference variable instead | |
912 | // of tuple of captured types. | |
913 | // | |
914 | // All we care here is if any variable is being captured and not the exact paths, | |
915 | // so we check `upvars_mentioned` for root variables being captured. | |
916 | ty::FnPtr(fn_ty) | |
917 | if self | |
918 | .tcx | |
919 | .upvars_mentioned(closure_def_id_a.expect_local()) | |
920 | .map_or(true, |u| u.is_empty()) => | |
921 | { | |
8bb4bdeb XL |
922 | // We coerce the closure, which has fn type |
923 | // `extern "rust-call" fn((arg0,arg1,...)) -> _` | |
924 | // to | |
925 | // `fn(arg0,arg1,...) -> _` | |
532ac7d7 XL |
926 | // or |
927 | // `unsafe fn(arg0,arg1,...) -> _` | |
ba9703b0 | 928 | let closure_sig = substs_a.as_closure().sig(); |
532ac7d7 | 929 | let unsafety = fn_ty.unsafety(); |
f9f354fc XL |
930 | let pointer_ty = |
931 | self.tcx.mk_fn_ptr(self.tcx.signature_unclosure(closure_sig, unsafety)); | |
dfeec247 XL |
932 | debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); |
933 | self.unify_and( | |
934 | pointer_ty, | |
935 | b, | |
936 | simple(Adjust::Pointer(PointerCast::ClosureFnPointer(unsafety))), | |
937 | ) | |
1a4d82fc | 938 | } |
7cac9316 | 939 | _ => self.unify_and(a, b, identity), |
54a0048b | 940 | } |
1a4d82fc JJ |
941 | } |
942 | ||
dfeec247 XL |
943 | fn coerce_unsafe_ptr( |
944 | &self, | |
945 | a: Ty<'tcx>, | |
946 | b: Ty<'tcx>, | |
947 | mutbl_b: hir::Mutability, | |
948 | ) -> CoerceResult<'tcx> { | |
c30ab7b3 | 949 | debug!("coerce_unsafe_ptr(a={:?}, b={:?})", a, b); |
1a4d82fc | 950 | |
1b1a35ee | 951 | let (is_ref, mt_a) = match *a.kind() { |
b7449926 XL |
952 | ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }), |
953 | ty::RawPtr(mt) => (false, mt), | |
dfeec247 | 954 | _ => return self.unify_and(a, b, identity), |
1a4d82fc | 955 | }; |
f9f354fc | 956 | coerce_mutbls(mt_a.mutbl, mutbl_b)?; |
1a4d82fc JJ |
957 | |
958 | // Check that the types which they point at are compatible. | |
dfeec247 | 959 | let a_unsafe = self.tcx.mk_ptr(ty::TypeAndMut { mutbl: mutbl_b, ty: mt_a.ty }); |
1a4d82fc | 960 | // Although references and unsafe ptrs have the same |
c30ab7b3 | 961 | // representation, we still register an Adjust::DerefRef so that |
1a4d82fc | 962 | // regionck knows that the region for `a` must be valid here. |
7cac9316 XL |
963 | if is_ref { |
964 | self.unify_and(a_unsafe, b, |target| { | |
dfeec247 XL |
965 | vec![ |
966 | Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }, | |
967 | Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), target }, | |
968 | ] | |
7cac9316 | 969 | }) |
8bb4bdeb | 970 | } else if mt_a.mutbl != mutbl_b { |
dfeec247 | 971 | self.unify_and(a_unsafe, b, simple(Adjust::Pointer(PointerCast::MutToConstPointer))) |
8bb4bdeb | 972 | } else { |
7cac9316 XL |
973 | self.unify_and(a_unsafe, b, identity) |
974 | } | |
9346a6ac | 975 | } |
85aaf69f SL |
976 | } |
977 | ||
dc9dc135 | 978 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
a7813a04 XL |
979 | /// Attempt to coerce an expression to a type, and return the |
980 | /// adjusted type of the expression, if successful. | |
981 | /// Adjustments are only recorded if the coercion succeeded. | |
49aad941 | 982 | /// The expressions *must not* have any preexisting adjustments. |
e1599b0c XL |
983 | pub fn try_coerce( |
984 | &self, | |
dfeec247 | 985 | expr: &hir::Expr<'_>, |
e1599b0c XL |
986 | expr_ty: Ty<'tcx>, |
987 | target: Ty<'tcx>, | |
988 | allow_two_phase: AllowTwoPhase, | |
c295e0f8 | 989 | cause: Option<ObligationCause<'tcx>>, |
e1599b0c | 990 | ) -> RelateResult<'tcx, Ty<'tcx>> { |
e74abb32 | 991 | let source = self.resolve_vars_with_obligations(expr_ty); |
a7813a04 XL |
992 | debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); |
993 | ||
c295e0f8 XL |
994 | let cause = |
995 | cause.unwrap_or_else(|| self.cause(expr.span, ObligationCauseCode::ExprAssignable)); | |
83c7162d | 996 | let coerce = Coerce::new(self, cause, allow_two_phase); |
7cac9316 | 997 | let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?; |
cc61c64b | 998 | |
7cac9316 XL |
999 | let (adjustments, _) = self.register_infer_ok_obligations(ok); |
1000 | self.apply_adjustments(expr, adjustments); | |
9ffffee4 | 1001 | Ok(if let Err(guar) = expr_ty.error_reported() { self.tcx.ty_error(guar) } else { target }) |
cc61c64b XL |
1002 | } |
1003 | ||
1004 | /// Same as `try_coerce()`, but without side-effects. | |
c295e0f8 XL |
1005 | /// |
1006 | /// Returns false if the coercion creates any obligations that result in | |
1007 | /// errors. | |
cc61c64b | 1008 | pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool { |
e74abb32 | 1009 | let source = self.resolve_vars_with_obligations(expr_ty); |
c295e0f8 | 1010 | debug!("coercion::can_with_predicates({:?} -> {:?})", source, target); |
cc61c64b | 1011 | |
dfeec247 | 1012 | let cause = self.cause(rustc_span::DUMMY_SP, ObligationCauseCode::ExprAssignable); |
83c7162d XL |
1013 | // We don't ever need two-phase here since we throw out the result of the coercion |
1014 | let coerce = Coerce::new(self, cause, AllowTwoPhase::No); | |
c295e0f8 | 1015 | self.probe(|_| { |
5e7ed085 FG |
1016 | let Ok(ok) = coerce.coerce(source, target) else { |
1017 | return false; | |
c295e0f8 | 1018 | }; |
487cf647 FG |
1019 | let ocx = ObligationCtxt::new_in_snapshot(self); |
1020 | ocx.register_obligations(ok.obligations); | |
1021 | ocx.select_where_possible().is_empty() | |
c295e0f8 | 1022 | }) |
a7813a04 | 1023 | } |
54a0048b | 1024 | |
f9f354fc XL |
1025 | /// Given a type and a target type, this function will calculate and return |
1026 | /// how many dereference steps needed to achieve `expr_ty <: target`. If | |
1027 | /// it's not possible, return `None`. | |
1028 | pub fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option<usize> { | |
1029 | let cause = self.cause(rustc_span::DUMMY_SP, ObligationCauseCode::ExprAssignable); | |
1030 | // We don't ever need two-phase here since we throw out the result of the coercion | |
1031 | let coerce = Coerce::new(self, cause, AllowTwoPhase::No); | |
1032 | coerce | |
1033 | .autoderef(rustc_span::DUMMY_SP, expr_ty) | |
1034 | .find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps)) | |
1035 | } | |
1036 | ||
923072b8 FG |
1037 | /// Given a type, this function will calculate and return the type given |
1038 | /// for `<Ty as Deref>::Target` only if `Ty` also implements `DerefMut`. | |
1039 | /// | |
1040 | /// This function is for diagnostics only, since it does not register | |
1041 | /// trait or region sub-obligations. (presumably we could, but it's not | |
1042 | /// particularly important for diagnostics...) | |
1043 | pub fn deref_once_mutably_for_diagnostic(&self, expr_ty: Ty<'tcx>) -> Option<Ty<'tcx>> { | |
1044 | self.autoderef(rustc_span::DUMMY_SP, expr_ty).nth(1).and_then(|(deref_ty, _)| { | |
1045 | self.infcx | |
1046 | .type_implements_trait( | |
064997fb | 1047 | self.tcx.lang_items().deref_mut_trait()?, |
487cf647 | 1048 | [expr_ty], |
923072b8 FG |
1049 | self.param_env, |
1050 | ) | |
1051 | .may_apply() | |
9ffffee4 | 1052 | .then_some(deref_ty) |
923072b8 FG |
1053 | }) |
1054 | } | |
1055 | ||
a7813a04 XL |
1056 | /// Given some expressions, their known unified type and another expression, |
1057 | /// tries to unify the types, potentially inserting coercions on any of the | |
1058 | /// provided expressions and returns their LUB (aka "common supertype"). | |
cc61c64b XL |
1059 | /// |
1060 | /// This is really an internal helper. From outside the coercion | |
1061 | /// module, you should instantiate a `CoerceMany` instance. | |
dfeec247 XL |
1062 | fn try_find_coercion_lub<E>( |
1063 | &self, | |
1064 | cause: &ObligationCause<'tcx>, | |
1065 | exprs: &[E], | |
1066 | prev_ty: Ty<'tcx>, | |
1067 | new: &hir::Expr<'_>, | |
1068 | new_ty: Ty<'tcx>, | |
1069 | ) -> RelateResult<'tcx, Ty<'tcx>> | |
1070 | where | |
1071 | E: AsCoercionSite, | |
c30ab7b3 | 1072 | { |
e74abb32 XL |
1073 | let prev_ty = self.resolve_vars_with_obligations(prev_ty); |
1074 | let new_ty = self.resolve_vars_with_obligations(new_ty); | |
f035d41b XL |
1075 | debug!( |
1076 | "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)", | |
1077 | prev_ty, | |
1078 | new_ty, | |
1079 | exprs.len() | |
1080 | ); | |
cc61c64b | 1081 | |
c295e0f8 XL |
1082 | // The following check fixes #88097, where the compiler erroneously |
1083 | // attempted to coerce a closure type to itself via a function pointer. | |
1084 | if prev_ty == new_ty { | |
1085 | return Ok(prev_ty); | |
1086 | } | |
1087 | ||
a7813a04 | 1088 | // Special-case that coercion alone cannot handle: |
f9f354fc XL |
1089 | // Function items or non-capturing closures of differing IDs or InternalSubsts. |
1090 | let (a_sig, b_sig) = { | |
487cf647 FG |
1091 | let is_capturing_closure = |ty: Ty<'tcx>| { |
1092 | if let &ty::Closure(closure_def_id, _substs) = ty.kind() { | |
29967ef6 | 1093 | self.tcx.upvars_mentioned(closure_def_id.expect_local()).is_some() |
f9f354fc XL |
1094 | } else { |
1095 | false | |
1096 | } | |
1097 | }; | |
487cf647 | 1098 | if is_capturing_closure(prev_ty) || is_capturing_closure(new_ty) { |
f9f354fc XL |
1099 | (None, None) |
1100 | } else { | |
5869c6ff XL |
1101 | match (prev_ty.kind(), new_ty.kind()) { |
1102 | (ty::FnDef(..), ty::FnDef(..)) => { | |
f9f354fc XL |
1103 | // Don't reify if the function types have a LUB, i.e., they |
1104 | // are the same function and their parameters have a LUB. | |
353b0b11 FG |
1105 | match self.commit_if_ok(|_| { |
1106 | self.at(cause, self.param_env).lub( | |
1107 | DefineOpaqueTypes::No, | |
1108 | prev_ty, | |
1109 | new_ty, | |
1110 | ) | |
1111 | }) { | |
f9f354fc XL |
1112 | // We have a LUB of prev_ty and new_ty, just return it. |
1113 | Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)), | |
1114 | Err(_) => { | |
1115 | (Some(prev_ty.fn_sig(self.tcx)), Some(new_ty.fn_sig(self.tcx))) | |
1116 | } | |
1117 | } | |
1118 | } | |
5869c6ff | 1119 | (ty::Closure(_, substs), ty::FnDef(..)) => { |
f9f354fc XL |
1120 | let b_sig = new_ty.fn_sig(self.tcx); |
1121 | let a_sig = self | |
1122 | .tcx | |
1123 | .signature_unclosure(substs.as_closure().sig(), b_sig.unsafety()); | |
1124 | (Some(a_sig), Some(b_sig)) | |
1125 | } | |
5869c6ff | 1126 | (ty::FnDef(..), ty::Closure(_, substs)) => { |
f9f354fc XL |
1127 | let a_sig = prev_ty.fn_sig(self.tcx); |
1128 | let b_sig = self | |
1129 | .tcx | |
1130 | .signature_unclosure(substs.as_closure().sig(), a_sig.unsafety()); | |
1131 | (Some(a_sig), Some(b_sig)) | |
1132 | } | |
5869c6ff | 1133 | (ty::Closure(_, substs_a), ty::Closure(_, substs_b)) => ( |
f9f354fc XL |
1134 | Some(self.tcx.signature_unclosure( |
1135 | substs_a.as_closure().sig(), | |
1136 | hir::Unsafety::Normal, | |
1137 | )), | |
1138 | Some(self.tcx.signature_unclosure( | |
1139 | substs_b.as_closure().sig(), | |
1140 | hir::Unsafety::Normal, | |
1141 | )), | |
1142 | ), | |
1143 | _ => (None, None), | |
1144 | } | |
041b39d2 | 1145 | } |
f9f354fc XL |
1146 | }; |
1147 | if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) { | |
cdc7bbd5 XL |
1148 | // Intrinsics are not coercible to function pointers. |
1149 | if a_sig.abi() == Abi::RustIntrinsic | |
1150 | || a_sig.abi() == Abi::PlatformIntrinsic | |
1151 | || b_sig.abi() == Abi::RustIntrinsic | |
1152 | || b_sig.abi() == Abi::PlatformIntrinsic | |
1153 | { | |
1154 | return Err(TypeError::IntrinsicCast); | |
1155 | } | |
041b39d2 | 1156 | // The signature must match. |
487cf647 | 1157 | let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig)); |
dfeec247 XL |
1158 | let sig = self |
1159 | .at(cause, self.param_env) | |
1160 | .trace(prev_ty, new_ty) | |
353b0b11 | 1161 | .lub(DefineOpaqueTypes::No, a_sig, b_sig) |
dfeec247 | 1162 | .map(|ok| self.register_infer_ok_obligations(ok))?; |
041b39d2 XL |
1163 | |
1164 | // Reify both sides and return the reified fn pointer type. | |
1165 | let fn_ptr = self.tcx.mk_fn_ptr(sig); | |
1b1a35ee | 1166 | let prev_adjustment = match prev_ty.kind() { |
f9f354fc XL |
1167 | ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety())), |
1168 | ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), | |
1169 | _ => unreachable!(), | |
1170 | }; | |
1b1a35ee | 1171 | let next_adjustment = match new_ty.kind() { |
f9f354fc XL |
1172 | ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety())), |
1173 | ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), | |
1174 | _ => unreachable!(), | |
1175 | }; | |
1176 | for expr in exprs.iter().map(|e| e.as_coercion_site()) { | |
dfeec247 XL |
1177 | self.apply_adjustments( |
1178 | expr, | |
f9f354fc | 1179 | vec![Adjustment { kind: prev_adjustment.clone(), target: fn_ptr }], |
dfeec247 | 1180 | ); |
54a0048b | 1181 | } |
f9f354fc | 1182 | self.apply_adjustments(new, vec![Adjustment { kind: next_adjustment, target: fn_ptr }]); |
041b39d2 | 1183 | return Ok(fn_ptr); |
54a0048b | 1184 | } |
54a0048b | 1185 | |
83c7162d XL |
1186 | // Configure a Coerce instance to compute the LUB. |
1187 | // We don't allow two-phase borrows on any autorefs this creates since we | |
1188 | // probably aren't processing function arguments here and even if we were, | |
1189 | // they're going to get autorefed again anyway and we can apply 2-phase borrows | |
1190 | // at that time. | |
1191 | let mut coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No); | |
a7813a04 | 1192 | coerce.use_lub = true; |
54a0048b | 1193 | |
a7813a04 XL |
1194 | // First try to coerce the new expression to the type of the previous ones, |
1195 | // but only if the new expression has no coercion already applied to it. | |
1196 | let mut first_error = None; | |
3dfed10e | 1197 | if !self.typeck_results.borrow().adjustments().contains_key(new.hir_id) { |
7cac9316 | 1198 | let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty)); |
a7813a04 | 1199 | match result { |
8bb4bdeb | 1200 | Ok(ok) => { |
7cac9316 XL |
1201 | let (adjustments, target) = self.register_infer_ok_obligations(ok); |
1202 | self.apply_adjustments(new, adjustments); | |
f035d41b | 1203 | debug!( |
923072b8 FG |
1204 | "coercion::try_find_coercion_lub: was able to coerce from new type {:?} to previous type {:?} ({:?})", |
1205 | new_ty, prev_ty, target | |
f035d41b | 1206 | ); |
7cac9316 | 1207 | return Ok(target); |
a7813a04 | 1208 | } |
c30ab7b3 | 1209 | Err(e) => first_error = Some(e), |
a7813a04 | 1210 | } |
54a0048b | 1211 | } |
54a0048b | 1212 | |
a7813a04 XL |
1213 | // Then try to coerce the previous expressions to the type of the new one. |
1214 | // This requires ensuring there are no coercions applied to *any* of the | |
1215 | // previous expressions, other than noop reborrows (ignoring lifetimes). | |
cc61c64b XL |
1216 | for expr in exprs { |
1217 | let expr = expr.as_coercion_site(); | |
3dfed10e | 1218 | let noop = match self.typeck_results.borrow().expr_adjustments(expr) { |
a2a8927a XL |
1219 | &[ |
1220 | Adjustment { kind: Adjust::Deref(_), .. }, | |
1221 | Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. }, | |
1222 | ] => { | |
1b1a35ee | 1223 | match *self.node_ty(expr.hir_id).kind() { |
b7449926 | 1224 | ty::Ref(_, _, mt_orig) => { |
2c00a5a8 | 1225 | let mutbl_adj: hir::Mutability = mutbl_adj.into(); |
cc61c64b | 1226 | // Reborrow that we can safely ignore, because |
7cac9316 | 1227 | // the next adjustment can only be a Deref |
cc61c64b | 1228 | // which will be merged into it. |
94b46f34 | 1229 | mutbl_adj == mt_orig |
c30ab7b3 SL |
1230 | } |
1231 | _ => false, | |
a7813a04 | 1232 | } |
c30ab7b3 | 1233 | } |
7cac9316 XL |
1234 | &[Adjustment { kind: Adjust::NeverToAny, .. }] | &[] => true, |
1235 | _ => false, | |
a7813a04 XL |
1236 | }; |
1237 | ||
1238 | if !noop { | |
f035d41b XL |
1239 | debug!( |
1240 | "coercion::try_find_coercion_lub: older expression {:?} had adjustments, requiring LUB", | |
1241 | expr, | |
1242 | ); | |
1243 | ||
dfeec247 | 1244 | return self |
353b0b11 FG |
1245 | .commit_if_ok(|_| { |
1246 | self.at(cause, self.param_env).lub(DefineOpaqueTypes::No, prev_ty, new_ty) | |
1247 | }) | |
dfeec247 | 1248 | .map(|ok| self.register_infer_ok_obligations(ok)); |
54a0048b SL |
1249 | } |
1250 | } | |
a7813a04 | 1251 | |
7cac9316 | 1252 | match self.commit_if_ok(|_| coerce.coerce(prev_ty, new_ty)) { |
a7813a04 XL |
1253 | Err(_) => { |
1254 | // Avoid giving strange errors on failed attempts. | |
1255 | if let Some(e) = first_error { | |
1256 | Err(e) | |
1257 | } else { | |
353b0b11 FG |
1258 | self.commit_if_ok(|_| { |
1259 | self.at(cause, self.param_env).lub(DefineOpaqueTypes::No, prev_ty, new_ty) | |
1260 | }) | |
1261 | .map(|ok| self.register_infer_ok_obligations(ok)) | |
54a0048b SL |
1262 | } |
1263 | } | |
8bb4bdeb | 1264 | Ok(ok) => { |
7cac9316 | 1265 | let (adjustments, target) = self.register_infer_ok_obligations(ok); |
cc61c64b XL |
1266 | for expr in exprs { |
1267 | let expr = expr.as_coercion_site(); | |
7cac9316 | 1268 | self.apply_adjustments(expr, adjustments.clone()); |
cc61c64b | 1269 | } |
923072b8 FG |
1270 | debug!( |
1271 | "coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?} ({:?})", | |
1272 | prev_ty, new_ty, target | |
1273 | ); | |
7cac9316 | 1274 | Ok(target) |
cc61c64b XL |
1275 | } |
1276 | } | |
1277 | } | |
1278 | } | |
1279 | ||
1280 | /// CoerceMany encapsulates the pattern you should use when you have | |
1281 | /// many expressions that are all getting coerced to a common | |
1282 | /// type. This arises, for example, when you have a match (the result | |
1283 | /// of each arm is coerced to a common type). It also arises in less | |
1284 | /// obvious places, such as when you have many `break foo` expressions | |
1285 | /// that target the same loop, or the various `return` expressions in | |
1286 | /// a function. | |
1287 | /// | |
1288 | /// The basic protocol is as follows: | |
1289 | /// | |
1290 | /// - Instantiate the `CoerceMany` with an initial `expected_ty`. | |
1291 | /// This will also serve as the "starting LUB". The expectation is | |
1292 | /// that this type is something which all of the expressions *must* | |
1293 | /// be coercible to. Use a fresh type variable if needed. | |
1294 | /// - For each expression whose result is to be coerced, invoke `coerce()` with. | |
1295 | /// - In some cases we wish to coerce "non-expressions" whose types are implicitly | |
1296 | /// unit. This happens for example if you have a `break` with no expression, | |
1297 | /// or an `if` with no `else`. In that case, invoke `coerce_forced_unit()`. | |
1298 | /// - `coerce()` and `coerce_forced_unit()` may report errors. They hide this | |
1299 | /// from you so that you don't have to worry your pretty head about it. | |
1300 | /// But if an error is reported, the final type will be `err`. | |
1301 | /// - Invoking `coerce()` may cause us to go and adjust the "adjustments" on | |
1302 | /// previously coerced expressions. | |
1303 | /// - When all done, invoke `complete()`. This will return the LUB of | |
1304 | /// all your expressions. | |
1305 | /// - WARNING: I don't believe this final type is guaranteed to be | |
1306 | /// related to your initial `expected_ty` in any particular way, | |
1307 | /// although it will typically be a subtype, so you should check it. | |
1308 | /// - Invoking `complete()` may cause us to go and adjust the "adjustments" on | |
1309 | /// previously coerced expressions. | |
1310 | /// | |
1311 | /// Example: | |
1312 | /// | |
04454e1e | 1313 | /// ```ignore (illustrative) |
cc61c64b XL |
1314 | /// let mut coerce = CoerceMany::new(expected_ty); |
1315 | /// for expr in exprs { | |
1316 | /// let expr_ty = fcx.check_expr_with_expectation(expr, expected); | |
1317 | /// coerce.coerce(fcx, &cause, expr, expr_ty); | |
1318 | /// } | |
1319 | /// let final_ty = coerce.complete(fcx); | |
1320 | /// ``` | |
dc9dc135 | 1321 | pub struct CoerceMany<'tcx, 'exprs, E: AsCoercionSite> { |
cc61c64b XL |
1322 | expected_ty: Ty<'tcx>, |
1323 | final_ty: Option<Ty<'tcx>>, | |
dc9dc135 | 1324 | expressions: Expressions<'tcx, 'exprs, E>, |
cc61c64b XL |
1325 | pushed: usize, |
1326 | } | |
1327 | ||
1328 | /// The type of a `CoerceMany` that is storing up the expressions into | |
1329 | /// a buffer. We use this in `check/mod.rs` for things like `break`. | |
dfeec247 | 1330 | pub type DynamicCoerceMany<'tcx> = CoerceMany<'tcx, 'tcx, &'tcx hir::Expr<'tcx>>; |
cc61c64b | 1331 | |
dc9dc135 | 1332 | enum Expressions<'tcx, 'exprs, E: AsCoercionSite> { |
dfeec247 | 1333 | Dynamic(Vec<&'tcx hir::Expr<'tcx>>), |
cc61c64b XL |
1334 | UpFront(&'exprs [E]), |
1335 | } | |
1336 | ||
dc9dc135 | 1337 | impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { |
cc61c64b XL |
1338 | /// The usual case; collect the set of expressions dynamically. |
1339 | /// If the full set of coercion sites is known before hand, | |
1340 | /// consider `with_coercion_sites()` instead to avoid allocation. | |
1341 | pub fn new(expected_ty: Ty<'tcx>) -> Self { | |
1342 | Self::make(expected_ty, Expressions::Dynamic(vec![])) | |
1343 | } | |
1344 | ||
1345 | /// As an optimization, you can create a `CoerceMany` with a | |
49aad941 | 1346 | /// preexisting slice of expressions. In this case, you are |
cc61c64b XL |
1347 | /// expected to pass each element in the slice to `coerce(...)` in |
1348 | /// order. This is used with arrays in particular to avoid | |
1349 | /// needlessly cloning the slice. | |
dfeec247 | 1350 | pub fn with_coercion_sites(expected_ty: Ty<'tcx>, coercion_sites: &'exprs [E]) -> Self { |
cc61c64b XL |
1351 | Self::make(expected_ty, Expressions::UpFront(coercion_sites)) |
1352 | } | |
1353 | ||
dc9dc135 | 1354 | fn make(expected_ty: Ty<'tcx>, expressions: Expressions<'tcx, 'exprs, E>) -> Self { |
dfeec247 | 1355 | CoerceMany { expected_ty, final_ty: None, expressions, pushed: 0 } |
cc61c64b XL |
1356 | } |
1357 | ||
9fa01778 XL |
1358 | /// Returns the "expected type" with which this coercion was |
1359 | /// constructed. This represents the "downward propagated" type | |
cc61c64b XL |
1360 | /// that was given to us at the start of typing whatever construct |
1361 | /// we are typing (e.g., the match expression). | |
1362 | /// | |
1363 | /// Typically, this is used as the expected type when | |
1364 | /// type-checking each of the alternative expressions whose types | |
1365 | /// we are trying to merge. | |
1366 | pub fn expected_ty(&self) -> Ty<'tcx> { | |
1367 | self.expected_ty | |
1368 | } | |
1369 | ||
1370 | /// Returns the current "merged type", representing our best-guess | |
1371 | /// at the LUB of the expressions we've seen so far (if any). This | |
5e7ed085 | 1372 | /// isn't *final* until you call `self.complete()`, which will return |
cc61c64b XL |
1373 | /// the merged type. |
1374 | pub fn merged_ty(&self) -> Ty<'tcx> { | |
1375 | self.final_ty.unwrap_or(self.expected_ty) | |
1376 | } | |
1377 | ||
1378 | /// Indicates that the value generated by `expression`, which is | |
0bf4aa26 XL |
1379 | /// of type `expression_ty`, is one of the possibilities that we |
1380 | /// could coerce from. This will record `expression`, and later | |
cc61c64b XL |
1381 | /// calls to `coerce` may come back and add adjustments and things |
1382 | /// if necessary. | |
dc9dc135 XL |
1383 | pub fn coerce<'a>( |
1384 | &mut self, | |
1385 | fcx: &FnCtxt<'a, 'tcx>, | |
1386 | cause: &ObligationCause<'tcx>, | |
dfeec247 | 1387 | expression: &'tcx hir::Expr<'tcx>, |
dc9dc135 XL |
1388 | expression_ty: Ty<'tcx>, |
1389 | ) { | |
dfeec247 | 1390 | self.coerce_inner(fcx, cause, Some(expression), expression_ty, None, false) |
cc61c64b XL |
1391 | } |
1392 | ||
1393 | /// Indicates that one of the inputs is a "forced unit". This | |
3b2f2976 | 1394 | /// occurs in a case like `if foo { ... };`, where the missing else |
cc61c64b XL |
1395 | /// generates a "forced unit". Another example is a `loop { break; |
1396 | /// }`, where the `break` has no argument expression. We treat | |
1397 | /// these cases slightly differently for error-reporting | |
1398 | /// purposes. Note that these tend to correspond to cases where | |
1399 | /// the `()` expression is implicit in the source, and hence we do | |
1400 | /// not take an expression argument. | |
1401 | /// | |
1402 | /// The `augment_error` gives you a chance to extend the error | |
1403 | /// message, in case any results (e.g., we use this to suggest | |
1404 | /// removing a `;`). | |
dc9dc135 XL |
1405 | pub fn coerce_forced_unit<'a>( |
1406 | &mut self, | |
1407 | fcx: &FnCtxt<'a, 'tcx>, | |
1408 | cause: &ObligationCause<'tcx>, | |
5e7ed085 | 1409 | augment_error: &mut dyn FnMut(&mut Diagnostic), |
dc9dc135 XL |
1410 | label_unit_as_expected: bool, |
1411 | ) { | |
dfeec247 XL |
1412 | self.coerce_inner( |
1413 | fcx, | |
1414 | cause, | |
1415 | None, | |
1416 | fcx.tcx.mk_unit(), | |
1417 | Some(augment_error), | |
1418 | label_unit_as_expected, | |
1419 | ) | |
cc61c64b XL |
1420 | } |
1421 | ||
1422 | /// The inner coercion "engine". If `expression` is `None`, this | |
1423 | /// is a forced-unit case, and hence `expression_ty` must be | |
1424 | /// `Nil`. | |
94222f64 | 1425 | #[instrument(skip(self, fcx, augment_error, label_expression_as_expected), level = "debug")] |
923072b8 | 1426 | pub(crate) fn coerce_inner<'a>( |
dc9dc135 XL |
1427 | &mut self, |
1428 | fcx: &FnCtxt<'a, 'tcx>, | |
1429 | cause: &ObligationCause<'tcx>, | |
dfeec247 | 1430 | expression: Option<&'tcx hir::Expr<'tcx>>, |
dc9dc135 | 1431 | mut expression_ty: Ty<'tcx>, |
5e7ed085 | 1432 | augment_error: Option<&mut dyn FnMut(&mut Diagnostic)>, |
dc9dc135 XL |
1433 | label_expression_as_expected: bool, |
1434 | ) { | |
cc61c64b XL |
1435 | // Incorporate whatever type inference information we have |
1436 | // until now; in principle we might also want to process | |
1437 | // pending obligations, but doing so should only improve | |
1438 | // compatibility (hopefully that is true) by helping us | |
1439 | // uncover never types better. | |
1440 | if expression_ty.is_ty_var() { | |
1441 | expression_ty = fcx.infcx.shallow_resolve(expression_ty); | |
1442 | } | |
1443 | ||
1444 | // If we see any error types, just propagate that error | |
1445 | // upwards. | |
9ffffee4 FG |
1446 | if let Err(guar) = (expression_ty, self.merged_ty()).error_reported() { |
1447 | self.final_ty = Some(fcx.tcx.ty_error(guar)); | |
cc61c64b XL |
1448 | return; |
1449 | } | |
1450 | ||
1451 | // Handle the actual type unification etc. | |
1452 | let result = if let Some(expression) = expression { | |
1453 | if self.pushed == 0 { | |
1454 | // Special-case the first expression we are coercing. | |
1455 | // To be honest, I'm not entirely sure why we do this. | |
83c7162d | 1456 | // We don't allow two-phase borrows, see comment in try_find_coercion_lub for why |
c295e0f8 XL |
1457 | fcx.try_coerce( |
1458 | expression, | |
1459 | expression_ty, | |
1460 | self.expected_ty, | |
1461 | AllowTwoPhase::No, | |
1462 | Some(cause.clone()), | |
1463 | ) | |
cc61c64b XL |
1464 | } else { |
1465 | match self.expressions { | |
e74abb32 XL |
1466 | Expressions::Dynamic(ref exprs) => fcx.try_find_coercion_lub( |
1467 | cause, | |
1468 | exprs, | |
1469 | self.merged_ty(), | |
1470 | expression, | |
1471 | expression_ty, | |
1472 | ), | |
1473 | Expressions::UpFront(ref coercion_sites) => fcx.try_find_coercion_lub( | |
1474 | cause, | |
1475 | &coercion_sites[0..self.pushed], | |
1476 | self.merged_ty(), | |
1477 | expression, | |
1478 | expression_ty, | |
1479 | ), | |
cc61c64b XL |
1480 | } |
1481 | } | |
1482 | } else { | |
1483 | // this is a hack for cases where we default to `()` because | |
1484 | // the expression etc has been omitted from the source. An | |
1485 | // example is an `if let` without an else: | |
1486 | // | |
1487 | // if let Some(x) = ... { } | |
1488 | // | |
1489 | // we wind up with a second match arm that is like `_ => | |
9c376795 | 1490 | // ()`. That is the case we are considering here. We take |
cc61c64b XL |
1491 | // a different path to get the right "expected, found" |
1492 | // message and so forth (and because we know that | |
1493 | // `expression_ty` will be unit). | |
1494 | // | |
1495 | // Another example is `break` with no argument expression. | |
b7449926 | 1496 | assert!(expression_ty.is_unit(), "if let hack without unit type"); |
7cac9316 | 1497 | fcx.at(cause, fcx.param_env) |
9ffffee4 | 1498 | // needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs |
353b0b11 FG |
1499 | .eq_exp( |
1500 | DefineOpaqueTypes::Yes, | |
1501 | label_expression_as_expected, | |
1502 | expression_ty, | |
1503 | self.merged_ty(), | |
1504 | ) | |
dfeec247 XL |
1505 | .map(|infer_ok| { |
1506 | fcx.register_infer_ok_obligations(infer_ok); | |
1507 | expression_ty | |
1508 | }) | |
cc61c64b XL |
1509 | }; |
1510 | ||
923072b8 | 1511 | debug!(?result); |
cc61c64b XL |
1512 | match result { |
1513 | Ok(v) => { | |
1514 | self.final_ty = Some(v); | |
1515 | if let Some(e) = expression { | |
1516 | match self.expressions { | |
1517 | Expressions::Dynamic(ref mut buffer) => buffer.push(e), | |
1518 | Expressions::UpFront(coercion_sites) => { | |
1519 | // if the user gave us an array to validate, check that we got | |
1520 | // the next expression in the list, as expected | |
dfeec247 XL |
1521 | assert_eq!( |
1522 | coercion_sites[self.pushed].as_coercion_site().hir_id, | |
1523 | e.hir_id | |
1524 | ); | |
5bcae85e | 1525 | } |
a7813a04 | 1526 | } |
cc61c64b | 1527 | self.pushed += 1; |
a7813a04 | 1528 | } |
cc61c64b | 1529 | } |
e74abb32 | 1530 | Err(coercion_error) => { |
f2b60f7d FG |
1531 | // Mark that we've failed to coerce the types here to suppress |
1532 | // any superfluous errors we might encounter while trying to | |
1533 | // emit or provide suggestions on how to fix the initial error. | |
487cf647 FG |
1534 | fcx.set_tainted_by_errors( |
1535 | fcx.tcx.sess.delay_span_bug(cause.span, "coercion error but no error emitted"), | |
1536 | ); | |
7cac9316 | 1537 | let (expected, found) = if label_expression_as_expected { |
cc61c64b XL |
1538 | // In the case where this is a "forced unit", like |
1539 | // `break`, we want to call the `()` "expected" | |
1540 | // since it is implied by the syntax. | |
7cac9316 | 1541 | // (Note: not all force-units work this way.)" |
f2b60f7d | 1542 | (expression_ty, self.merged_ty()) |
cc61c64b XL |
1543 | } else { |
1544 | // Otherwise, the "expected" type for error | |
1545 | // reporting is the current unification type, | |
1546 | // which is basically the LUB of the expressions | |
1547 | // we've seen so far (combined with the expected | |
1548 | // type) | |
f2b60f7d | 1549 | (self.merged_ty(), expression_ty) |
cc61c64b | 1550 | }; |
f2b60f7d | 1551 | let (expected, found) = fcx.resolve_vars_if_possible((expected, found)); |
cc61c64b | 1552 | |
e74abb32 | 1553 | let mut err; |
dfeec247 | 1554 | let mut unsized_return = false; |
f2b60f7d | 1555 | let mut visitor = CollectRetsVisitor { ret_exprs: vec![] }; |
a2a8927a | 1556 | match *cause.code() { |
cc61c64b | 1557 | ObligationCauseCode::ReturnNoExpression => { |
e74abb32 | 1558 | err = struct_span_err!( |
dfeec247 XL |
1559 | fcx.tcx.sess, |
1560 | cause.span, | |
1561 | E0069, | |
1562 | "`return;` in a function whose return type is not `()`" | |
1563 | ); | |
e74abb32 | 1564 | err.span_label(cause.span, "return type is not `()`"); |
cc61c64b | 1565 | } |
041b39d2 | 1566 | ObligationCauseCode::BlockTailExpression(blk_id) => { |
9c376795 | 1567 | let parent_id = fcx.tcx.hir().parent_id(blk_id); |
e74abb32 | 1568 | err = self.report_return_mismatched_types( |
9fa01778 | 1569 | cause, |
8faf50e0 XL |
1570 | expected, |
1571 | found, | |
9c376795 | 1572 | coercion_error, |
9fa01778 XL |
1573 | fcx, |
1574 | parent_id, | |
923072b8 FG |
1575 | expression, |
1576 | Some(blk_id), | |
8faf50e0 | 1577 | ); |
dfeec247 XL |
1578 | if !fcx.tcx.features().unsized_locals { |
1579 | unsized_return = self.is_return_ty_unsized(fcx, blk_id); | |
1580 | } | |
f2b60f7d FG |
1581 | if let Some(expression) = expression |
1582 | && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind { | |
1583 | intravisit::walk_block(& mut visitor, loop_blk); | |
1584 | } | |
9fa01778 | 1585 | } |
e74abb32 XL |
1586 | ObligationCauseCode::ReturnValue(id) => { |
1587 | err = self.report_return_mismatched_types( | |
dfeec247 XL |
1588 | cause, |
1589 | expected, | |
1590 | found, | |
9c376795 | 1591 | coercion_error, |
dfeec247 XL |
1592 | fcx, |
1593 | id, | |
923072b8 | 1594 | expression, |
dfeec247 XL |
1595 | None, |
1596 | ); | |
1597 | if !fcx.tcx.features().unsized_locals { | |
9c376795 | 1598 | let id = fcx.tcx.hir().parent_id(id); |
dfeec247 XL |
1599 | unsized_return = self.is_return_ty_unsized(fcx, id); |
1600 | } | |
041b39d2 | 1601 | } |
cc61c64b | 1602 | _ => { |
2b03887a | 1603 | err = fcx.err_ctxt().report_mismatched_types( |
3c0e092e XL |
1604 | cause, |
1605 | expected, | |
1606 | found, | |
9c376795 | 1607 | coercion_error, |
3c0e092e | 1608 | ); |
cc61c64b XL |
1609 | } |
1610 | } | |
1611 | ||
3b2f2976 | 1612 | if let Some(augment_error) = augment_error { |
e74abb32 | 1613 | augment_error(&mut err); |
cc61c64b XL |
1614 | } |
1615 | ||
923072b8 FG |
1616 | let is_insufficiently_polymorphic = |
1617 | matches!(coercion_error, TypeError::RegionsInsufficientlyPolymorphic(..)); | |
1618 | ||
1619 | if !is_insufficiently_polymorphic && let Some(expr) = expression { | |
3c0e092e XL |
1620 | fcx.emit_coerce_suggestions( |
1621 | &mut err, | |
1622 | expr, | |
1623 | found, | |
1624 | expected, | |
1625 | None, | |
04454e1e | 1626 | Some(coercion_error), |
3c0e092e | 1627 | ); |
60c5eb7d XL |
1628 | } |
1629 | ||
f2b60f7d FG |
1630 | if visitor.ret_exprs.len() > 0 && let Some(expr) = expression { |
1631 | self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs); | |
1632 | } | |
9ffffee4 | 1633 | |
487cf647 | 1634 | let reported = err.emit_unless(unsized_return); |
cc61c64b | 1635 | |
9ffffee4 | 1636 | self.final_ty = Some(fcx.tcx.ty_error(reported)); |
a7813a04 | 1637 | } |
54a0048b | 1638 | } |
1a4d82fc | 1639 | } |
9ffffee4 | 1640 | |
f2b60f7d FG |
1641 | fn note_unreachable_loop_return( |
1642 | &self, | |
1643 | err: &mut Diagnostic, | |
1644 | expr: &hir::Expr<'tcx>, | |
1645 | ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>, | |
1646 | ) { | |
1647 | let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;}; | |
1648 | let mut span: MultiSpan = vec![loop_span].into(); | |
1649 | span.push_span_label(loop_span, "this might have zero elements to iterate on"); | |
1650 | const MAXITER: usize = 3; | |
1651 | let iter = ret_exprs.iter().take(MAXITER); | |
1652 | for ret_expr in iter { | |
1653 | span.push_span_label( | |
1654 | ret_expr.span, | |
1655 | "if the loop doesn't execute, this value would never get returned", | |
1656 | ); | |
1657 | } | |
1658 | err.span_note( | |
1659 | span, | |
1660 | "the function expects a value to always be returned, but loops might run zero times", | |
1661 | ); | |
1662 | if MAXITER < ret_exprs.len() { | |
49aad941 | 1663 | err.note(format!( |
f2b60f7d FG |
1664 | "if the loop doesn't execute, {} other values would never get returned", |
1665 | ret_exprs.len() - MAXITER | |
1666 | )); | |
1667 | } | |
1668 | err.help( | |
1669 | "return a value for the case when the loop has zero elements to iterate on, or \ | |
1670 | consider changing the return type to account for that possibility", | |
1671 | ); | |
1672 | } | |
cc61c64b | 1673 | |
9fa01778 XL |
1674 | fn report_return_mismatched_types<'a>( |
1675 | &self, | |
1676 | cause: &ObligationCause<'tcx>, | |
1677 | expected: Ty<'tcx>, | |
1678 | found: Ty<'tcx>, | |
e74abb32 | 1679 | ty_err: TypeError<'tcx>, |
dc9dc135 | 1680 | fcx: &FnCtxt<'a, 'tcx>, |
532ac7d7 | 1681 | id: hir::HirId, |
923072b8 FG |
1682 | expression: Option<&'tcx hir::Expr<'tcx>>, |
1683 | blk_id: Option<hir::HirId>, | |
5e7ed085 | 1684 | ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { |
2b03887a | 1685 | let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err); |
9fa01778 XL |
1686 | |
1687 | let mut pointing_at_return_type = false; | |
dfeec247 | 1688 | let mut fn_output = None; |
9fa01778 | 1689 | |
9c376795 | 1690 | let parent_id = fcx.tcx.hir().parent_id(id); |
923072b8 FG |
1691 | let parent = fcx.tcx.hir().get(parent_id); |
1692 | if let Some(expr) = expression | |
064997fb FG |
1693 | && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), .. }) = parent |
1694 | && !matches!(fcx.tcx.hir().body(body).value.kind, hir::ExprKind::Block(..)) | |
923072b8 FG |
1695 | { |
1696 | fcx.suggest_missing_semicolon(&mut err, expr, expected, true); | |
1697 | } | |
9fa01778 XL |
1698 | // Verify that this is a tail expression of a function, otherwise the |
1699 | // label pointing out the cause for the type coercion will be wrong | |
1700 | // as prior return coercions would not be relevant (#57664). | |
923072b8 | 1701 | let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) { |
cdc7bbd5 XL |
1702 | pointing_at_return_type = |
1703 | fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id); | |
5869c6ff XL |
1704 | if let (Some(cond_expr), true, false) = ( |
1705 | fcx.tcx.hir().get_if_cause(expr.hir_id), | |
e74abb32 XL |
1706 | expected.is_unit(), |
1707 | pointing_at_return_type, | |
04454e1e | 1708 | ) |
136023e0 XL |
1709 | // If the block is from an external macro or try (`?`) desugaring, then |
1710 | // do not suggest adding a semicolon, because there's nowhere to put it. | |
1711 | // See issues #81943 and #87051. | |
04454e1e | 1712 | && matches!( |
c295e0f8 XL |
1713 | cond_expr.span.desugaring_kind(), |
1714 | None | Some(DesugaringKind::WhileLoop) | |
1715 | ) && !in_external_macro(fcx.tcx.sess, cond_expr.span) | |
136023e0 XL |
1716 | && !matches!( |
1717 | cond_expr.kind, | |
1718 | hir::ExprKind::Match(.., hir::MatchSource::TryDesugar) | |
1719 | ) | |
04454e1e FG |
1720 | { |
1721 | err.span_label(cond_expr.span, "expected this to be `()`"); | |
1722 | if expr.can_have_side_effects() { | |
1723 | fcx.suggest_semicolon_at_end(cond_expr.span, &mut err); | |
e74abb32 XL |
1724 | } |
1725 | } | |
353b0b11 FG |
1726 | fcx.get_node_fn_decl(parent) |
1727 | .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main)) | |
9fa01778 XL |
1728 | } else { |
1729 | fcx.get_fn_decl(parent_id) | |
1730 | }; | |
1731 | ||
353b0b11 | 1732 | if let Some((fn_id, fn_decl, can_suggest)) = fn_decl { |
923072b8 | 1733 | if blk_id.is_none() { |
9fa01778 | 1734 | pointing_at_return_type |= fcx.suggest_missing_return_type( |
dfeec247 XL |
1735 | &mut err, |
1736 | &fn_decl, | |
1737 | expected, | |
1738 | found, | |
1739 | can_suggest, | |
353b0b11 | 1740 | fn_id, |
dfeec247 | 1741 | ); |
9fa01778 XL |
1742 | } |
1743 | if !pointing_at_return_type { | |
dfeec247 | 1744 | fn_output = Some(&fn_decl.output); // `impl Trait` return type |
9fa01778 XL |
1745 | } |
1746 | } | |
6a06907d XL |
1747 | |
1748 | let parent_id = fcx.tcx.hir().get_parent_item(id); | |
2b03887a | 1749 | let parent_item = fcx.tcx.hir().get_by_def_id(parent_id.def_id); |
6a06907d | 1750 | |
353b0b11 | 1751 | if let (Some(expr), Some(_), Some((fn_id, fn_decl, _, _))) = |
923072b8 | 1752 | (expression, blk_id, fcx.get_node_fn_decl(parent_item)) |
6a06907d | 1753 | { |
cdc7bbd5 | 1754 | fcx.suggest_missing_break_or_return_expr( |
353b0b11 | 1755 | &mut err, expr, fn_decl, expected, found, id, fn_id, |
cdc7bbd5 | 1756 | ); |
6a06907d XL |
1757 | } |
1758 | ||
f2b60f7d FG |
1759 | let ret_coercion_span = fcx.ret_coercion_span.get(); |
1760 | ||
1761 | if let Some(sp) = ret_coercion_span | |
1762 | // If the closure has an explicit return type annotation, or if | |
1763 | // the closure's return type has been inferred from outside | |
1764 | // requirements (such as an Fn* trait bound), then a type error | |
1765 | // may occur at the first return expression we see in the closure | |
1766 | // (if it conflicts with the declared return type). Skip adding a | |
1767 | // note in this case, since it would be incorrect. | |
487cf647 FG |
1768 | && let Some(fn_sig) = fcx.body_fn_sig() |
1769 | && fn_sig.output().is_ty_var() | |
f2b60f7d FG |
1770 | { |
1771 | err.span_note( | |
1772 | sp, | |
49aad941 | 1773 | format!( |
f2b60f7d FG |
1774 | "return type inferred to be `{}` here", |
1775 | expected | |
1776 | ), | |
1777 | ); | |
1778 | } | |
1779 | ||
1780 | if let (Some(sp), Some(fn_output)) = (ret_coercion_span, fn_output) { | |
5869c6ff | 1781 | self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output); |
9fa01778 | 1782 | } |
f2b60f7d | 1783 | |
e74abb32 | 1784 | err |
9fa01778 XL |
1785 | } |
1786 | ||
dfeec247 XL |
1787 | fn add_impl_trait_explanation<'a>( |
1788 | &self, | |
5e7ed085 | 1789 | err: &mut Diagnostic, |
1b1a35ee | 1790 | cause: &ObligationCause<'tcx>, |
dfeec247 XL |
1791 | fcx: &FnCtxt<'a, 'tcx>, |
1792 | expected: Ty<'tcx>, | |
1793 | sp: Span, | |
74b04a01 | 1794 | fn_output: &hir::FnRetTy<'_>, |
dfeec247 XL |
1795 | ) { |
1796 | let return_sp = fn_output.span(); | |
1797 | err.span_label(return_sp, "expected because this return type..."); | |
1798 | err.span_label( | |
1799 | sp, | |
1800 | format!("...is found to be `{}` here", fcx.resolve_vars_with_obligations(expected)), | |
1801 | ); | |
1802 | let impl_trait_msg = "for information on `impl Trait`, see \ | |
1803 | <https://doc.rust-lang.org/book/ch10-02-traits.html\ | |
1804 | #returning-types-that-implement-traits>"; | |
1805 | let trait_obj_msg = "for information on trait objects, see \ | |
1806 | <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\ | |
1807 | #using-trait-objects-that-allow-for-values-of-different-types>"; | |
1808 | err.note("to return `impl Trait`, all returned values must be of the same type"); | |
1809 | err.note(impl_trait_msg); | |
1810 | let snippet = fcx | |
1811 | .tcx | |
1812 | .sess | |
1813 | .source_map() | |
1814 | .span_to_snippet(return_sp) | |
1815 | .unwrap_or_else(|_| "dyn Trait".to_string()); | |
1816 | let mut snippet_iter = snippet.split_whitespace(); | |
49aad941 | 1817 | let has_impl = snippet_iter.next().is_some_and(|s| s == "impl"); |
dfeec247 XL |
1818 | // Only suggest `Box<dyn Trait>` if `Trait` in `impl Trait` is object safe. |
1819 | let mut is_object_safe = false; | |
04454e1e | 1820 | if let hir::FnRetTy::Return(ty) = fn_output |
dfeec247 | 1821 | // Get the return type. |
04454e1e FG |
1822 | && let hir::TyKind::OpaqueDef(..) = ty.kind |
1823 | { | |
9c376795 | 1824 | let ty = fcx.astconv().ast_ty_to_ty( ty); |
04454e1e | 1825 | // Get the `impl Trait`'s `DefId`. |
9c376795 | 1826 | if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() |
04454e1e FG |
1827 | // Get the `impl Trait`'s `Item` so that we can get its trait bounds and |
1828 | // get the `Trait`'s `DefId`. | |
1829 | && let hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }) = | |
1830 | fcx.tcx.hir().expect_item(def_id.expect_local()).kind | |
1831 | { | |
1832 | // Are of this `impl Trait`'s traits object safe? | |
1833 | is_object_safe = bounds.iter().all(|bound| { | |
1834 | bound | |
1835 | .trait_ref() | |
1836 | .and_then(|t| t.trait_def_id()) | |
49aad941 | 1837 | .is_some_and(|def_id| { |
9ffffee4 | 1838 | fcx.tcx.check_is_object_safe(def_id) |
dfeec247 | 1839 | }) |
04454e1e | 1840 | }) |
dfeec247 XL |
1841 | } |
1842 | }; | |
1843 | if has_impl { | |
1844 | if is_object_safe { | |
1b1a35ee XL |
1845 | err.multipart_suggestion( |
1846 | "you could change the return type to be a boxed trait object", | |
1847 | vec![ | |
1848 | (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()), | |
1849 | (return_sp.shrink_to_hi(), ">".to_string()), | |
1850 | ], | |
1851 | Applicability::MachineApplicable, | |
1852 | ); | |
5099ac24 | 1853 | let sugg = [sp, cause.span] |
1b1a35ee XL |
1854 | .into_iter() |
1855 | .flat_map(|sp| { | |
5099ac24 | 1856 | [ |
1b1a35ee XL |
1857 | (sp.shrink_to_lo(), "Box::new(".to_string()), |
1858 | (sp.shrink_to_hi(), ")".to_string()), | |
1859 | ] | |
1860 | .into_iter() | |
1861 | }) | |
1862 | .collect::<Vec<_>>(); | |
1863 | err.multipart_suggestion( | |
1864 | "if you change the return type to expect trait objects, box the returned \ | |
1865 | expressions", | |
1866 | sugg, | |
1867 | Applicability::MaybeIncorrect, | |
1868 | ); | |
dfeec247 | 1869 | } else { |
49aad941 | 1870 | err.help(format!( |
dfeec247 XL |
1871 | "if the trait `{}` were object safe, you could return a boxed trait object", |
1872 | &snippet[5..] | |
1873 | )); | |
1874 | } | |
1875 | err.note(trait_obj_msg); | |
1876 | } | |
1b1a35ee | 1877 | err.help("you could instead create a new `enum` with a variant for each returned type"); |
dfeec247 XL |
1878 | } |
1879 | ||
a2a8927a | 1880 | fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool { |
353b0b11 | 1881 | if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id) |
5e7ed085 | 1882 | && let hir::FnRetTy::Return(ty) = fn_decl.output |
9c376795 | 1883 | && let ty = fcx.astconv().ast_ty_to_ty( ty) |
5e7ed085 FG |
1884 | && let ty::Dynamic(..) = ty.kind() |
1885 | { | |
04454e1e | 1886 | return true; |
dfeec247 XL |
1887 | } |
1888 | false | |
1889 | } | |
1890 | ||
dc9dc135 | 1891 | pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> { |
cc61c64b XL |
1892 | if let Some(final_ty) = self.final_ty { |
1893 | final_ty | |
1894 | } else { | |
1895 | // If we only had inputs that were of type `!` (or no | |
1896 | // inputs at all), then the final type is `!`. | |
1897 | assert_eq!(self.pushed, 0); | |
1898 | fcx.tcx.types.never | |
1899 | } | |
1900 | } | |
1901 | } | |
1902 | ||
1903 | /// Something that can be converted into an expression to which we can | |
1904 | /// apply a coercion. | |
1905 | pub trait AsCoercionSite { | |
dfeec247 | 1906 | fn as_coercion_site(&self) -> &hir::Expr<'_>; |
cc61c64b XL |
1907 | } |
1908 | ||
dfeec247 XL |
1909 | impl AsCoercionSite for hir::Expr<'_> { |
1910 | fn as_coercion_site(&self) -> &hir::Expr<'_> { | |
cc61c64b XL |
1911 | self |
1912 | } | |
1913 | } | |
1914 | ||
1915 | impl<'a, T> AsCoercionSite for &'a T | |
dfeec247 XL |
1916 | where |
1917 | T: AsCoercionSite, | |
cc61c64b | 1918 | { |
dfeec247 | 1919 | fn as_coercion_site(&self) -> &hir::Expr<'_> { |
cc61c64b XL |
1920 | (**self).as_coercion_site() |
1921 | } | |
1922 | } | |
1923 | ||
1924 | impl AsCoercionSite for ! { | |
dfeec247 | 1925 | fn as_coercion_site(&self) -> &hir::Expr<'_> { |
cc61c64b XL |
1926 | unreachable!() |
1927 | } | |
1928 | } | |
1929 | ||
dfeec247 XL |
1930 | impl AsCoercionSite for hir::Arm<'_> { |
1931 | fn as_coercion_site(&self) -> &hir::Expr<'_> { | |
cc61c64b XL |
1932 | &self.body |
1933 | } | |
1a4d82fc | 1934 | } |