]>
Commit | Line | Data |
---|---|---|
2b03887a FG |
1 | use crate::coercion::{AsCoercionSite, CoerceMany}; |
2 | use crate::{Diverges, Expectation, FnCtxt, Needs}; | |
487cf647 | 3 | use rustc_errors::{Applicability, Diagnostic, MultiSpan}; |
1b1a35ee | 4 | use rustc_hir::{self as hir, ExprKind}; |
74b04a01 | 5 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; |
1b1a35ee | 6 | use rustc_infer::traits::Obligation; |
487cf647 | 7 | use rustc_middle::ty::{self, Ty}; |
04454e1e | 8 | use rustc_span::Span; |
1b1a35ee XL |
9 | use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; |
10 | use rustc_trait_selection::traits::{ | |
11 | IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, | |
12 | }; | |
1a4d82fc | 13 | |
dc9dc135 | 14 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
f2b60f7d | 15 | #[instrument(skip(self), level = "debug", ret)] |
0731742a XL |
16 | pub fn check_match( |
17 | &self, | |
dfeec247 XL |
18 | expr: &'tcx hir::Expr<'tcx>, |
19 | scrut: &'tcx hir::Expr<'tcx>, | |
20 | arms: &'tcx [hir::Arm<'tcx>], | |
1b1a35ee | 21 | orig_expected: Expectation<'tcx>, |
0731742a XL |
22 | match_src: hir::MatchSource, |
23 | ) -> Ty<'tcx> { | |
a7813a04 XL |
24 | let tcx = self.tcx; |
25 | ||
94222f64 XL |
26 | let acrb = arms_contain_ref_bindings(arms); |
27 | let scrutinee_ty = self.demand_scrutinee_type(scrut, acrb, arms.is_empty()); | |
28 | debug!(?scrutinee_ty); | |
cc61c64b | 29 | |
cc61c64b XL |
30 | // If there are no arms, that is a diverging match; a special case. |
31 | if arms.is_empty() { | |
e1599b0c | 32 | self.diverges.set(self.diverges.get() | Diverges::always(expr.span)); |
cc61c64b XL |
33 | return tcx.types.never; |
34 | } | |
35 | ||
94222f64 | 36 | self.warn_arms_when_scrutinee_diverges(arms); |
0bf4aa26 | 37 | |
dfeec247 XL |
38 | // Otherwise, we have to union together the types that the arms produce and so forth. |
39 | let scrut_diverges = self.diverges.replace(Diverges::Maybe); | |
1a4d82fc | 40 | |
dfeec247 | 41 | // #55810: Type check patterns first so we get types for all bindings. |
064997fb | 42 | let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span); |
dfeec247 | 43 | for arm in arms { |
9ffffee4 | 44 | self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut)); |
dfeec247 | 45 | } |
1a4d82fc | 46 | |
a7813a04 XL |
47 | // Now typecheck the blocks. |
48 | // | |
49 | // The result of the match is the common supertype of all the | |
50 | // arms. Start out the value as bottom, since it's the, well, | |
51 | // bottom the type lattice, and we'll be moving up the lattice as | |
52 | // we process each arm. (Note that any match with 0 arms is matching | |
53 | // on any empty type and is therefore unreachable; should the flow | |
54 | // of execution reach it, we will panic, so bottom is an appropriate | |
55 | // type in that case) | |
476ff2be | 56 | let mut all_arms_diverge = Diverges::WarnedAlways; |
cc61c64b | 57 | |
1b1a35ee | 58 | let expected = orig_expected.adjust_for_branches(self); |
923072b8 | 59 | debug!(?expected); |
cc61c64b XL |
60 | |
61 | let mut coercion = { | |
62 | let coerce_first = match expected { | |
63 | // We don't coerce to `()` so that if the match expression is a | |
64 | // statement it's branches can have any consistent type. That allows | |
65 | // us to give better error messages (pointing to a usually better | |
66 | // arm for inconsistent arms or to the whole match when a `()` type | |
67 | // is required). | |
b7449926 | 68 | Expectation::ExpectHasType(ety) if ety != self.tcx.mk_unit() => ety, |
dc9dc135 XL |
69 | _ => self.next_ty_var(TypeVariableOrigin { |
70 | kind: TypeVariableOriginKind::MiscVariable, | |
71 | span: expr.span, | |
72 | }), | |
cc61c64b XL |
73 | }; |
74 | CoerceMany::with_coercion_sites(coerce_first, arms) | |
54a0048b | 75 | }; |
9e0c209e | 76 | |
dfeec247 | 77 | let mut other_arms = vec![]; // Used only for diagnostics. |
064997fb FG |
78 | let mut prior_arm = None; |
79 | for arm in arms { | |
48663c56 | 80 | if let Some(g) = &arm.guard { |
dfeec247 | 81 | self.diverges.set(Diverges::Maybe); |
b7449926 | 82 | match g { |
e74abb32 | 83 | hir::Guard::If(e) => { |
fc512014 XL |
84 | self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {}); |
85 | } | |
923072b8 FG |
86 | hir::Guard::IfLet(l) => { |
87 | self.check_expr_let(l); | |
e74abb32 | 88 | } |
b7449926 | 89 | }; |
a7813a04 | 90 | } |
476ff2be | 91 | |
dfeec247 | 92 | self.diverges.set(Diverges::Maybe); |
94222f64 XL |
93 | |
94 | let arm_ty = self.check_expr_with_expectation(&arm.body, expected); | |
476ff2be | 95 | all_arms_diverge &= self.diverges.get(); |
1b1a35ee | 96 | |
f2b60f7d FG |
97 | let opt_suggest_box_span = prior_arm.and_then(|(_, prior_arm_ty, _)| { |
98 | self.opt_suggest_box_span(prior_arm_ty, arm_ty, orig_expected) | |
99 | }); | |
1b1a35ee | 100 | |
064997fb FG |
101 | let (arm_block_id, arm_span) = if let hir::ExprKind::Block(blk, _) = arm.body.kind { |
102 | (Some(blk.hir_id), self.find_block_span(blk)) | |
103 | } else { | |
104 | (None, arm.body.span) | |
105 | }; | |
106 | ||
107 | let (span, code) = match prior_arm { | |
94222f64 XL |
108 | // The reason for the first arm to fail is not that the match arms diverge, |
109 | // but rather that there's a prior obligation that doesn't hold. | |
064997fb FG |
110 | None => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)), |
111 | Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => ( | |
94222f64 XL |
112 | expr.span, |
113 | ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause { | |
064997fb | 114 | arm_block_id, |
94222f64 | 115 | arm_span, |
064997fb FG |
116 | arm_ty, |
117 | prior_arm_block_id, | |
118 | prior_arm_ty, | |
119 | prior_arm_span, | |
94222f64 | 120 | scrut_span: scrut.span, |
94222f64 XL |
121 | source: match_src, |
122 | prior_arms: other_arms.clone(), | |
94222f64 XL |
123 | scrut_hir_id: scrut.hir_id, |
124 | opt_suggest_box_span, | |
125 | })), | |
126 | ), | |
127 | }; | |
128 | let cause = self.cause(span, code); | |
129 | ||
130 | // This is the moral equivalent of `coercion.coerce(self, cause, arm.body, arm_ty)`. | |
131 | // We use it this way to be able to expand on the potential error and detect when a | |
132 | // `match` tail statement could be a tail expression instead. If so, we suggest | |
133 | // removing the stray semicolon. | |
134 | coercion.coerce_inner( | |
135 | self, | |
136 | &cause, | |
137 | Some(&arm.body), | |
138 | arm_ty, | |
064997fb | 139 | Some(&mut |err| { |
487cf647 FG |
140 | self.suggest_removing_semicolon_for_coerce( |
141 | err, | |
142 | expr, | |
143 | orig_expected, | |
144 | arm_ty, | |
145 | prior_arm, | |
146 | ) | |
94222f64 XL |
147 | }), |
148 | false, | |
149 | ); | |
6a06907d | 150 | |
94222f64 XL |
151 | other_arms.push(arm_span); |
152 | if other_arms.len() > 5 { | |
153 | other_arms.remove(0); | |
9fa01778 | 154 | } |
064997fb FG |
155 | |
156 | prior_arm = Some((arm_block_id, arm_ty, arm_span)); | |
1a4d82fc | 157 | } |
1a4d82fc | 158 | |
e1599b0c XL |
159 | // If all of the arms in the `match` diverge, |
160 | // and we're dealing with an actual `match` block | |
161 | // (as opposed to a `match` desugared from something else'), | |
162 | // we can emit a better note. Rather than pointing | |
163 | // at a diverging expression in an arbitrary arm, | |
164 | // we can point at the entire `match` expression | |
165 | if let (Diverges::Always { .. }, hir::MatchSource::Normal) = (all_arms_diverge, match_src) { | |
166 | all_arms_diverge = Diverges::Always { | |
167 | span: expr.span, | |
168 | custom_note: Some( | |
dfeec247 XL |
169 | "any code following this `match` expression is unreachable, as all arms diverge", |
170 | ), | |
e1599b0c XL |
171 | }; |
172 | } | |
173 | ||
dfeec247 XL |
174 | // We won't diverge unless the scrutinee or all arms diverge. |
175 | self.diverges.set(scrut_diverges | all_arms_diverge); | |
476ff2be | 176 | |
f2b60f7d | 177 | coercion.complete(self) |
92a42be0 | 178 | } |
92a42be0 | 179 | |
487cf647 FG |
180 | fn suggest_removing_semicolon_for_coerce( |
181 | &self, | |
182 | diag: &mut Diagnostic, | |
183 | expr: &hir::Expr<'tcx>, | |
184 | expectation: Expectation<'tcx>, | |
185 | arm_ty: Ty<'tcx>, | |
186 | prior_arm: Option<(Option<hir::HirId>, Ty<'tcx>, Span)>, | |
187 | ) { | |
188 | let hir = self.tcx.hir(); | |
189 | ||
190 | // First, check that we're actually in the tail of a function. | |
9ffffee4 FG |
191 | let Some(body_id) = hir.maybe_body_owned_by(self.body_id) else { return; }; |
192 | let body = hir.body(body_id); | |
193 | let hir::ExprKind::Block(block, _) = body.value.kind else { return; }; | |
487cf647 FG |
194 | let Some(hir::Stmt { kind: hir::StmtKind::Semi(last_expr), .. }) |
195 | = block.innermost_block().stmts.last() else { return; }; | |
196 | if last_expr.hir_id != expr.hir_id { | |
197 | return; | |
198 | } | |
199 | ||
200 | // Next, make sure that we have no type expectation. | |
201 | let Some(ret) = hir | |
9ffffee4 | 202 | .find_by_def_id(self.body_id) |
487cf647 FG |
203 | .and_then(|owner| owner.fn_decl()) |
204 | .map(|decl| decl.output.span()) else { return; }; | |
205 | let Expectation::IsLast(stmt) = expectation else { | |
206 | return; | |
207 | }; | |
208 | ||
209 | let can_coerce_to_return_ty = match self.ret_coercion.as_ref() { | |
210 | Some(ret_coercion) => { | |
211 | let ret_ty = ret_coercion.borrow().expected_ty(); | |
212 | let ret_ty = self.inh.infcx.shallow_resolve(ret_ty); | |
213 | self.can_coerce(arm_ty, ret_ty) | |
214 | && prior_arm.map_or(true, |(_, ty, _)| self.can_coerce(ty, ret_ty)) | |
215 | // The match arms need to unify for the case of `impl Trait`. | |
9c376795 | 216 | && !matches!(ret_ty.kind(), ty::Alias(ty::Opaque, ..)) |
487cf647 FG |
217 | } |
218 | _ => false, | |
219 | }; | |
220 | if !can_coerce_to_return_ty { | |
221 | return; | |
222 | } | |
223 | ||
224 | let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi()); | |
225 | let mut ret_span: MultiSpan = semi_span.into(); | |
226 | ret_span.push_span_label( | |
227 | expr.span, | |
9c376795 | 228 | "this could be implicitly returned but it is a statement, not a tail expression", |
487cf647 FG |
229 | ); |
230 | ret_span.push_span_label(ret, "the `match` arms can conform to this return type"); | |
231 | ret_span.push_span_label( | |
232 | semi_span, | |
9c376795 | 233 | "the `match` is a statement because of this semicolon, consider removing it", |
487cf647 FG |
234 | ); |
235 | diag.span_note(ret_span, "you might have meant to return the `match` expression"); | |
236 | diag.tool_only_span_suggestion( | |
237 | semi_span, | |
238 | "remove this semicolon", | |
239 | "", | |
240 | Applicability::MaybeIncorrect, | |
241 | ); | |
242 | } | |
243 | ||
48663c56 XL |
244 | /// When the previously checked expression (the scrutinee) diverges, |
245 | /// warn the user about the match arms being unreachable. | |
94222f64 | 246 | fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm<'tcx>]) { |
dfeec247 | 247 | for arm in arms { |
94222f64 | 248 | self.warn_if_unreachable(arm.body.hir_id, arm.body.span, "arm"); |
48663c56 XL |
249 | } |
250 | } | |
251 | ||
252 | /// Handle the fallback arm of a desugared if(-let) like a missing else. | |
e1599b0c XL |
253 | /// |
254 | /// Returns `true` if there was an error forcing the coercion to the `()` type. | |
94222f64 | 255 | pub(super) fn if_fallback_coercion<T>( |
48663c56 XL |
256 | &self, |
257 | span: Span, | |
dfeec247 | 258 | then_expr: &'tcx hir::Expr<'tcx>, |
5869c6ff | 259 | coercion: &mut CoerceMany<'tcx, '_, T>, |
5869c6ff XL |
260 | ) -> bool |
261 | where | |
5869c6ff XL |
262 | T: AsCoercionSite, |
263 | { | |
48663c56 XL |
264 | // If this `if` expr is the parent's function return expr, |
265 | // the cause of the type coercion is the return type, point at it. (#25228) | |
94222f64 | 266 | let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, span); |
48663c56 | 267 | let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse); |
e1599b0c | 268 | let mut error = false; |
dfeec247 XL |
269 | coercion.coerce_forced_unit( |
270 | self, | |
271 | &cause, | |
272 | &mut |err| { | |
273 | if let Some((span, msg)) = &ret_reason { | |
064997fb | 274 | err.span_label(*span, msg); |
04454e1e FG |
275 | } else if let ExprKind::Block(block, _) = &then_expr.kind |
276 | && let Some(expr) = &block.expr | |
277 | { | |
064997fb | 278 | err.span_label(expr.span, "found here"); |
48663c56 | 279 | } |
dfeec247 XL |
280 | err.note("`if` expressions without `else` evaluate to `()`"); |
281 | err.help("consider adding an `else` block that evaluates to the expected type"); | |
282 | error = true; | |
283 | }, | |
2b03887a | 284 | false, |
dfeec247 | 285 | ); |
e1599b0c | 286 | error |
48663c56 XL |
287 | } |
288 | ||
94222f64 XL |
289 | fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, sp: Span) -> Option<(Span, String)> { |
290 | let node = { | |
9c376795 | 291 | let rslt = self.tcx.hir().parent_id(self.tcx.hir().parent_id(hir_id)); |
94222f64 XL |
292 | self.tcx.hir().get(rslt) |
293 | }; | |
294 | if let hir::Node::Block(block) = node { | |
295 | // check that the body's parent is an fn | |
9c376795 | 296 | let parent = self.tcx.hir().get_parent(self.tcx.hir().parent_id(block.hir_id)); |
94222f64 XL |
297 | if let (Some(expr), hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })) = |
298 | (&block.expr, parent) | |
299 | { | |
300 | // check that the `if` expr without `else` is the fn body's expr | |
301 | if expr.span == sp { | |
353b0b11 | 302 | return self.get_fn_decl(hir_id).and_then(|(_, fn_decl, _)| { |
94222f64 XL |
303 | let span = fn_decl.output.span(); |
304 | let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?; | |
04454e1e | 305 | Some((span, format!("expected `{snippet}` because of this return type"))) |
94222f64 XL |
306 | }); |
307 | } | |
308 | } | |
48663c56 | 309 | } |
94222f64 XL |
310 | if let hir::Node::Local(hir::Local { ty: Some(_), pat, .. }) = node { |
311 | return Some((pat.span, "expected because of this assignment".to_string())); | |
48663c56 | 312 | } |
94222f64 XL |
313 | None |
314 | } | |
48663c56 | 315 | |
5869c6ff | 316 | pub(crate) fn if_cause( |
48663c56 XL |
317 | &self, |
318 | span: Span, | |
064997fb | 319 | cond_span: Span, |
dfeec247 XL |
320 | then_expr: &'tcx hir::Expr<'tcx>, |
321 | else_expr: &'tcx hir::Expr<'tcx>, | |
48663c56 XL |
322 | then_ty: Ty<'tcx>, |
323 | else_ty: Ty<'tcx>, | |
1b1a35ee | 324 | opt_suggest_box_span: Option<Span>, |
48663c56 | 325 | ) -> ObligationCause<'tcx> { |
064997fb | 326 | let mut outer_span = if self.tcx.sess.source_map().is_multiline(span) { |
48663c56 XL |
327 | // The `if`/`else` isn't in one line in the output, include some context to make it |
328 | // clear it is an if/else expression: | |
329 | // ``` | |
330 | // LL | let x = if true { | |
331 | // | _____________- | |
332 | // LL || 10i32 | |
333 | // || ----- expected because of this | |
334 | // LL || } else { | |
335 | // LL || 10u32 | |
60c5eb7d | 336 | // || ^^^^^ expected `i32`, found `u32` |
48663c56 | 337 | // LL || }; |
dfeec247 | 338 | // ||_____- `if` and `else` have incompatible types |
48663c56 XL |
339 | // ``` |
340 | Some(span) | |
341 | } else { | |
342 | // The entire expression is in one line, only point at the arms | |
343 | // ``` | |
344 | // LL | let x = if true { 10i32 } else { 10u32 }; | |
60c5eb7d | 345 | // | ----- ^^^^^ expected `i32`, found `u32` |
48663c56 XL |
346 | // | | |
347 | // | expected because of this | |
348 | // ``` | |
349 | None | |
350 | }; | |
351 | ||
064997fb FG |
352 | let (error_sp, else_id) = if let ExprKind::Block(block, _) = &else_expr.kind { |
353 | let block = block.innermost_block(); | |
354 | ||
355 | // Avoid overlapping spans that aren't as readable: | |
356 | // ``` | |
357 | // 2 | let x = if true { | |
358 | // | _____________- | |
359 | // 3 | | 3 | |
360 | // | | - expected because of this | |
361 | // 4 | | } else { | |
362 | // | |____________^ | |
363 | // 5 | || | |
364 | // 6 | || }; | |
365 | // | || ^ | |
366 | // | ||_____| | |
367 | // | |______if and else have incompatible types | |
368 | // | expected integer, found `()` | |
369 | // ``` | |
370 | // by not pointing at the entire expression: | |
371 | // ``` | |
372 | // 2 | let x = if true { | |
373 | // | ------- `if` and `else` have incompatible types | |
374 | // 3 | 3 | |
375 | // | - expected because of this | |
376 | // 4 | } else { | |
377 | // | ____________^ | |
378 | // 5 | | | |
379 | // 6 | | }; | |
380 | // | |_____^ expected integer, found `()` | |
381 | // ``` | |
382 | if block.expr.is_none() && block.stmts.is_empty() | |
383 | && let Some(outer_span) = &mut outer_span | |
384 | && let Some(cond_span) = cond_span.find_ancestor_inside(*outer_span) | |
385 | { | |
386 | *outer_span = outer_span.with_hi(cond_span.hi()) | |
48663c56 | 387 | } |
064997fb FG |
388 | |
389 | (self.find_block_span(block), block.hir_id) | |
dfeec247 | 390 | } else { |
064997fb | 391 | (else_expr.span, else_expr.hir_id) |
48663c56 XL |
392 | }; |
393 | ||
064997fb FG |
394 | let then_id = if let ExprKind::Block(block, _) = &then_expr.kind { |
395 | let block = block.innermost_block(); | |
396 | // Exclude overlapping spans | |
3dfed10e | 397 | if block.expr.is_none() && block.stmts.is_empty() { |
064997fb | 398 | outer_span = None; |
48663c56 | 399 | } |
064997fb | 400 | block.hir_id |
dfeec247 | 401 | } else { |
064997fb | 402 | then_expr.hir_id |
48663c56 XL |
403 | }; |
404 | ||
405 | // Finally construct the cause: | |
dfeec247 XL |
406 | self.cause( |
407 | error_sp, | |
94222f64 | 408 | ObligationCauseCode::IfExpression(Box::new(IfExpressionCause { |
064997fb FG |
409 | else_id, |
410 | then_id, | |
411 | then_ty, | |
412 | else_ty, | |
413 | outer_span, | |
1b1a35ee | 414 | opt_suggest_box_span, |
94222f64 | 415 | })), |
dfeec247 | 416 | ) |
48663c56 XL |
417 | } |
418 | ||
94222f64 | 419 | pub(super) fn demand_scrutinee_type( |
48663c56 | 420 | &self, |
dfeec247 | 421 | scrut: &'tcx hir::Expr<'tcx>, |
fc512014 XL |
422 | contains_ref_bindings: Option<hir::Mutability>, |
423 | no_arms: bool, | |
48663c56 XL |
424 | ) -> Ty<'tcx> { |
425 | // Not entirely obvious: if matches may create ref bindings, we want to | |
dfeec247 XL |
426 | // use the *precise* type of the scrutinee, *not* some supertype, as |
427 | // the "scrutinee type" (issue #23116). | |
48663c56 XL |
428 | // |
429 | // arielb1 [writes here in this comment thread][c] that there | |
430 | // is certainly *some* potential danger, e.g., for an example | |
431 | // like: | |
432 | // | |
433 | // [c]: https://github.com/rust-lang/rust/pull/43399#discussion_r130223956 | |
434 | // | |
435 | // ``` | |
436 | // let Foo(x) = f()[0]; | |
437 | // ``` | |
438 | // | |
439 | // Then if the pattern matches by reference, we want to match | |
440 | // `f()[0]` as a lexpr, so we can't allow it to be | |
441 | // coerced. But if the pattern matches by value, `f()[0]` is | |
442 | // still syntactically a lexpr, but we *do* want to allow | |
443 | // coercions. | |
444 | // | |
445 | // However, *likely* we are ok with allowing coercions to | |
446 | // happen if there are no explicit ref mut patterns - all | |
447 | // implicit ref mut patterns must occur behind a reference, so | |
448 | // they will have the "correct" variance and lifetime. | |
449 | // | |
450 | // This does mean that the following pattern would be legal: | |
451 | // | |
452 | // ``` | |
453 | // struct Foo(Bar); | |
454 | // struct Bar(u32); | |
455 | // impl Deref for Foo { | |
456 | // type Target = Bar; | |
457 | // fn deref(&self) -> &Bar { &self.0 } | |
458 | // } | |
459 | // impl DerefMut for Foo { | |
460 | // fn deref_mut(&mut self) -> &mut Bar { &mut self.0 } | |
461 | // } | |
462 | // fn foo(x: &mut Foo) { | |
463 | // { | |
464 | // let Bar(z): &mut Bar = x; | |
465 | // *z = 42; | |
466 | // } | |
467 | // assert_eq!(foo.0.0, 42); | |
468 | // } | |
469 | // ``` | |
470 | // | |
471 | // FIXME(tschottdorf): don't call contains_explicit_ref_binding, which | |
472 | // is problematic as the HIR is being scraped, but ref bindings may be | |
473 | // implicit after #42640. We need to make sure that pat_adjustments | |
474 | // (once introduced) is populated by the time we get here. | |
475 | // | |
476 | // See #44848. | |
48663c56 | 477 | if let Some(m) = contains_ref_bindings { |
dfeec247 | 478 | self.check_expr_with_needs(scrut, Needs::maybe_mut_place(m)) |
fc512014 | 479 | } else if no_arms { |
f9f354fc | 480 | self.check_expr(scrut) |
48663c56 XL |
481 | } else { |
482 | // ...but otherwise we want to use any supertype of the | |
dfeec247 | 483 | // scrutinee. This is sort of a workaround, see note (*) in |
48663c56 | 484 | // `check_pat` for some details. |
dfeec247 | 485 | let scrut_ty = self.next_ty_var(TypeVariableOrigin { |
dc9dc135 | 486 | kind: TypeVariableOriginKind::TypeInference, |
dfeec247 | 487 | span: scrut.span, |
dc9dc135 | 488 | }); |
dfeec247 XL |
489 | self.check_expr_has_type_or_error(scrut, scrut_ty, |_| {}); |
490 | scrut_ty | |
48663c56 XL |
491 | } |
492 | } | |
3dfed10e | 493 | |
f2b60f7d FG |
494 | /// When we have a `match` as a tail expression in a `fn` with a returned `impl Trait` |
495 | /// we check if the different arms would work with boxed trait objects instead and | |
496 | /// provide a structured suggestion in that case. | |
5869c6ff XL |
497 | pub(crate) fn opt_suggest_box_span( |
498 | &self, | |
f2b60f7d FG |
499 | first_ty: Ty<'tcx>, |
500 | second_ty: Ty<'tcx>, | |
5869c6ff XL |
501 | orig_expected: Expectation<'tcx>, |
502 | ) -> Option<Span> { | |
f2b60f7d FG |
503 | // FIXME(compiler-errors): This really shouldn't need to be done during the |
504 | // "good" path of typeck, but here we are. | |
5e7ed085 | 505 | match orig_expected { |
f2b60f7d FG |
506 | Expectation::ExpectHasType(expected) => { |
507 | let TypeVariableOrigin { | |
508 | span, | |
509 | kind: TypeVariableOriginKind::OpaqueTypeInference(rpit_def_id), | |
510 | .. | |
511 | } = self.type_var_origin(expected)? else { return None; }; | |
512 | ||
487cf647 | 513 | let sig = self.body_fn_sig()?; |
f2b60f7d FG |
514 | |
515 | let substs = sig.output().walk().find_map(|arg| { | |
516 | if let ty::GenericArgKind::Type(ty) = arg.unpack() | |
9c376795 | 517 | && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *ty.kind() |
f2b60f7d FG |
518 | && def_id == rpit_def_id |
519 | { | |
520 | Some(substs) | |
521 | } else { | |
522 | None | |
523 | } | |
524 | })?; | |
f2b60f7d FG |
525 | |
526 | if !self.can_coerce(first_ty, expected) || !self.can_coerce(second_ty, expected) { | |
527 | return None; | |
528 | } | |
529 | ||
530 | for ty in [first_ty, second_ty] { | |
2b03887a FG |
531 | for (pred, _) in self |
532 | .tcx | |
533 | .bound_explicit_item_bounds(rpit_def_id) | |
534 | .subst_iter_copied(self.tcx, substs) | |
535 | { | |
487cf647 FG |
536 | let pred = pred.kind().rebind(match pred.kind().skip_binder() { |
537 | ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => { | |
9c376795 FG |
538 | // FIXME(rpitit): This will need to be fixed when we move to associated types |
539 | assert!(matches!( | |
540 | *trait_pred.trait_ref.self_ty().kind(), | |
353b0b11 FG |
541 | ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) |
542 | if def_id == rpit_def_id && substs == alias_substs | |
9c376795 | 543 | )); |
487cf647 | 544 | ty::PredicateKind::Clause(ty::Clause::Trait( |
9c376795 | 545 | trait_pred.with_self_ty(self.tcx, ty), |
487cf647 | 546 | )) |
5869c6ff | 547 | } |
487cf647 | 548 | ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => { |
9c376795 FG |
549 | assert!(matches!( |
550 | *proj_pred.projection_ty.self_ty().kind(), | |
353b0b11 FG |
551 | ty::Alias(_, ty::AliasTy { def_id, substs: alias_substs, .. }) |
552 | if def_id == rpit_def_id && substs == alias_substs | |
9c376795 FG |
553 | )); |
554 | proj_pred = proj_pred.with_self_ty(self.tcx, ty); | |
487cf647 | 555 | ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred)) |
f2b60f7d FG |
556 | } |
557 | _ => continue, | |
487cf647 | 558 | }); |
f2b60f7d | 559 | if !self.predicate_must_hold_modulo_regions(&Obligation::new( |
487cf647 | 560 | self.tcx, |
f2b60f7d FG |
561 | ObligationCause::misc(span, self.body_id), |
562 | self.param_env, | |
563 | pred, | |
564 | )) { | |
565 | return None; | |
5869c6ff | 566 | } |
5869c6ff XL |
567 | } |
568 | } | |
f2b60f7d FG |
569 | |
570 | Some(span) | |
5869c6ff XL |
571 | } |
572 | _ => None, | |
573 | } | |
574 | } | |
1a4d82fc | 575 | } |
fc512014 | 576 | |
a2a8927a | 577 | fn arms_contain_ref_bindings<'tcx>(arms: &'tcx [hir::Arm<'tcx>]) -> Option<hir::Mutability> { |
487cf647 | 578 | arms.iter().filter_map(|a| a.pat.contains_explicit_ref_binding()).max() |
fc512014 | 579 | } |