|
1 | 1 | // ignore-tidy-filelength
|
2 | 2 |
|
3 |
| -use super::{DefIdOrName, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation}; |
| 3 | +use super::{ |
| 4 | + DefIdOrName, FindExprBySpan, Obligation, ObligationCause, ObligationCauseCode, |
| 5 | + PredicateObligation, |
| 6 | +}; |
4 | 7 |
|
5 | 8 | use crate::autoderef::Autoderef;
|
6 | 9 | use crate::infer::InferCtxt;
|
@@ -196,6 +199,13 @@ pub trait TypeErrCtxtExt<'tcx> {
|
196 | 199 | trait_pred: ty::PolyTraitPredicate<'tcx>,
|
197 | 200 | ) -> bool;
|
198 | 201 |
|
| 202 | + fn check_for_binding_assigned_block_without_tail_expression( |
| 203 | + &self, |
| 204 | + obligation: &PredicateObligation<'tcx>, |
| 205 | + err: &mut Diagnostic, |
| 206 | + trait_pred: ty::PolyTraitPredicate<'tcx>, |
| 207 | + ); |
| 208 | + |
199 | 209 | fn suggest_add_reference_to_arg(
|
200 | 210 | &self,
|
201 | 211 | obligation: &PredicateObligation<'tcx>,
|
@@ -1032,6 +1042,66 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
1032 | 1042 | true
|
1033 | 1043 | }
|
1034 | 1044 |
|
| 1045 | + fn check_for_binding_assigned_block_without_tail_expression( |
| 1046 | + &self, |
| 1047 | + obligation: &PredicateObligation<'tcx>, |
| 1048 | + err: &mut Diagnostic, |
| 1049 | + trait_pred: ty::PolyTraitPredicate<'tcx>, |
| 1050 | + ) { |
| 1051 | + let mut span = obligation.cause.span; |
| 1052 | + while span.from_expansion() { |
| 1053 | + // Remove all the desugaring and macro contexts. |
| 1054 | + span.remove_mark(); |
| 1055 | + } |
| 1056 | + let mut expr_finder = FindExprBySpan::new(span); |
| 1057 | + let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else { return; }; |
| 1058 | + expr_finder.visit_expr(&body); |
| 1059 | + let Some(expr) = expr_finder.result else { return; }; |
| 1060 | + let Some(typeck) = &self.typeck_results else { return; }; |
| 1061 | + let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else { return; }; |
| 1062 | + if !ty.is_unit() { |
| 1063 | + return; |
| 1064 | + }; |
| 1065 | + let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; }; |
| 1066 | + let hir::def::Res::Local(hir_id) = path.res else { return; }; |
| 1067 | + let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else { |
| 1068 | + return; |
| 1069 | + }; |
| 1070 | + let Some(hir::Node::Local(hir::Local { |
| 1071 | + ty: None, |
| 1072 | + init: Some(init), |
| 1073 | + .. |
| 1074 | + })) = self.tcx.hir().find_parent(pat.hir_id) else { return; }; |
| 1075 | + let hir::ExprKind::Block(block, None) = init.kind else { return; }; |
| 1076 | + if block.expr.is_some() { |
| 1077 | + return; |
| 1078 | + } |
| 1079 | + let [.., stmt] = block.stmts else { |
| 1080 | + err.span_label(block.span, "this empty block is missing a tail expression"); |
| 1081 | + return; |
| 1082 | + }; |
| 1083 | + let hir::StmtKind::Semi(tail_expr) = stmt.kind else { return; }; |
| 1084 | + let Some(ty) = typeck.expr_ty_opt(tail_expr) else { |
| 1085 | + err.span_label(block.span, "this block is missing a tail expression"); |
| 1086 | + return; |
| 1087 | + }; |
| 1088 | + let ty = self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(ty)); |
| 1089 | + let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, ty)); |
| 1090 | + |
| 1091 | + let new_obligation = |
| 1092 | + self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self); |
| 1093 | + if self.predicate_must_hold_modulo_regions(&new_obligation) { |
| 1094 | + err.span_suggestion_short( |
| 1095 | + stmt.span.with_lo(tail_expr.span.hi()), |
| 1096 | + "remove this semicolon", |
| 1097 | + "", |
| 1098 | + Applicability::MachineApplicable, |
| 1099 | + ); |
| 1100 | + } else { |
| 1101 | + err.span_label(block.span, "this block is missing a tail expression"); |
| 1102 | + } |
| 1103 | + } |
| 1104 | + |
1035 | 1105 | fn suggest_add_reference_to_arg(
|
1036 | 1106 | &self,
|
1037 | 1107 | obligation: &PredicateObligation<'tcx>,
|
|
0 commit comments