]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_infer/src/infer/note.rs
Rollup merge of #103146 - joboet:cleanup_pthread_condvar, r=Mark-Simulacrum
[rust.git] / compiler / rustc_infer / src / infer / note.rs
1 impl<'tcx> TypeErrCtxt<'_, 'tcx> {
2     fn note_error_origin(
3         &self,
4         err: &mut Diagnostic,
5         cause: &ObligationCause<'tcx>,
6         exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
7         terr: TypeError<'tcx>,
8     ) {
9         match *cause.code() {
10             ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
11                 let ty = self.resolve_vars_if_possible(root_ty);
12                 if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)))
13                 {
14                     // don't show type `_`
15                     if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
16                         && let ty::Adt(def, substs) = ty.kind()
17                         && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
18                     {
19                         err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
20                     } else {
21                     err.span_label(span, format!("this expression has type `{}`", ty));
22                 }
23                 }
24                 if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
25                     && ty.is_box() && ty.boxed_ty() == found
26                     && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
27                 {
28                     err.span_suggestion(
29                         span,
30                         "consider dereferencing the boxed value",
31                         format!("*{}", snippet),
32                         Applicability::MachineApplicable,
33                     );
34                 }
35             }
36             ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => {
37                 err.span_label(span, "expected due to this");
38             }
39             ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
40                 arm_block_id,
41                 arm_span,
42                 arm_ty,
43                 prior_arm_block_id,
44                 prior_arm_span,
45                 prior_arm_ty,
46                 source,
47                 ref prior_arms,
48                 scrut_hir_id,
49                 opt_suggest_box_span,
50                 scrut_span,
51                 ..
52             }) => match source {
53                 hir::MatchSource::TryDesugar => {
54                     if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
55                         let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
56                         let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
57                             let arg_expr = args.first().expect("try desugaring call w/out arg");
58                             self.typeck_results.as_ref().and_then(|typeck_results| {
59                                 typeck_results.expr_ty_opt(arg_expr)
60                             })
61                         } else {
62                             bug!("try desugaring w/out call expr as scrutinee");
63                         };
64
65                         match scrut_ty {
66                             Some(ty) if expected == ty => {
67                                 let source_map = self.tcx.sess.source_map();
68                                 err.span_suggestion(
69                                     source_map.end_point(cause.span),
70                                     "try removing this `?`",
71                                     "",
72                                     Applicability::MachineApplicable,
73                                 );
74                             }
75                             _ => {}
76                         }
77                     }
78                 }
79                 _ => {
80                     // `prior_arm_ty` can be `!`, `expected` will have better info when present.
81                     let t = self.resolve_vars_if_possible(match exp_found {
82                         Some(ty::error::ExpectedFound { expected, .. }) => expected,
83                         _ => prior_arm_ty,
84                     });
85                     let source_map = self.tcx.sess.source_map();
86                     let mut any_multiline_arm = source_map.is_multiline(arm_span);
87                     if prior_arms.len() <= 4 {
88                         for sp in prior_arms {
89                             any_multiline_arm |= source_map.is_multiline(*sp);
90                             err.span_label(*sp, format!("this is found to be of type `{}`", t));
91                         }
92                     } else if let Some(sp) = prior_arms.last() {
93                         any_multiline_arm |= source_map.is_multiline(*sp);
94                         err.span_label(
95                             *sp,
96                             format!("this and all prior arms are found to be of type `{}`", t),
97                         );
98                     }
99                     let outer_error_span = if any_multiline_arm {
100                         // Cover just `match` and the scrutinee expression, not
101                         // the entire match body, to reduce diagram noise.
102                         cause.span.shrink_to_lo().to(scrut_span)
103                     } else {
104                         cause.span
105                     };
106                     let msg = "`match` arms have incompatible types";
107                     err.span_label(outer_error_span, msg);
108                     self.suggest_remove_semi_or_return_binding(
109                         err,
110                         prior_arm_block_id,
111                         prior_arm_ty,
112                         prior_arm_span,
113                         arm_block_id,
114                         arm_ty,
115                         arm_span,
116                     );
117                     if let Some(ret_sp) = opt_suggest_box_span {
118                         // Get return type span and point to it.
119                         self.suggest_boxing_for_return_impl_trait(
120                             err,
121                             ret_sp,
122                             prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
123                         );
124                     }
125                 }
126             },
127             ObligationCauseCode::IfExpression(box IfExpressionCause {
128                 then_id,
129                 else_id,
130                 then_ty,
131                 else_ty,
132                 outer_span,
133                 opt_suggest_box_span,
134             }) => {
135                 let then_span = self.find_block_span_from_hir_id(then_id);
136                 let else_span = self.find_block_span_from_hir_id(else_id);
137                 err.span_label(then_span, "expected because of this");
138                 if let Some(sp) = outer_span {
139                     err.span_label(sp, "`if` and `else` have incompatible types");
140                 }
141                 self.suggest_remove_semi_or_return_binding(
142                     err,
143                     Some(then_id),
144                     then_ty,
145                     then_span,
146                     Some(else_id),
147                     else_ty,
148                     else_span,
149                 );
150                 if let Some(ret_sp) = opt_suggest_box_span {
151                     self.suggest_boxing_for_return_impl_trait(
152                         err,
153                         ret_sp,
154                         [then_span, else_span].into_iter(),
155                     );
156                 }
157             }
158             ObligationCauseCode::LetElse => {
159                 err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
160                 err.help("...or use `match` instead of `let...else`");
161             }
162             _ => {
163                 if let ObligationCauseCode::BindingObligation(_, span)
164                 | ObligationCauseCode::ExprBindingObligation(_, span, ..)
165                 = cause.code().peel_derives()
166                     && let TypeError::RegionsPlaceholderMismatch = terr
167                 {
168                     err.span_note( * span,
169                     "the lifetime requirement is introduced here");
170                 }
171             }
172         }
173     }
174 }
175
176 impl<'tcx> InferCtxt<'tcx> {
177     /// Given a [`hir::Block`], get the span of its last expression or
178     /// statement, peeling off any inner blocks.
179     pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
180         let block = block.innermost_block();
181         if let Some(expr) = &block.expr {
182             expr.span
183         } else if let Some(stmt) = block.stmts.last() {
184             // possibly incorrect trailing `;` in the else arm
185             stmt.span
186         } else {
187             // empty block; point at its entirety
188             block.span
189         }
190     }
191
192     /// Given a [`hir::HirId`] for a block, get the span of its last expression
193     /// or statement, peeling off any inner blocks.
194     pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span {
195         match self.tcx.hir().get(hir_id) {
196             hir::Node::Block(blk) => self.find_block_span(blk),
197             // The parser was in a weird state if either of these happen, but
198             // it's better not to panic.
199             hir::Node::Expr(e) => e.span,
200             _ => rustc_span::DUMMY_SP,
201         }
202     }
203 }