Skip to content

Commit 58c13e0

Browse files
authored
Rollup merge of #103987 - compiler-errors:no-in_tail_expr, r=eholk
Remove `in_tail_expr` from FnCtxt Cleans up yet another unneeded member from `FnCtxt`. The `in_tail_expr` condition wasn't even correct -- it was set for true while typechecking the whole fn body.
2 parents 799648a + a0cdc85 commit 58c13e0

File tree

3 files changed

+73
-57
lines changed

3 files changed

+73
-57
lines changed

compiler/rustc_hir_typeck/src/_match.rs

+73-50
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::coercion::{AsCoercionSite, CoerceMany};
22
use crate::{Diverges, Expectation, FnCtxt, Needs};
3-
use rustc_errors::{Applicability, MultiSpan};
3+
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
44
use rustc_hir::{self as hir, ExprKind};
55
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
66
use rustc_infer::traits::Obligation;
@@ -137,55 +137,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
137137
Some(&arm.body),
138138
arm_ty,
139139
Some(&mut |err| {
140-
let Some(ret) = self
141-
.tcx
142-
.hir()
143-
.find_by_def_id(self.body_id.owner.def_id)
144-
.and_then(|owner| owner.fn_decl())
145-
.map(|decl| decl.output.span())
146-
else { return; };
147-
let Expectation::IsLast(stmt) = orig_expected else {
148-
return
149-
};
150-
let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
151-
Some(ret_coercion) if self.in_tail_expr => {
152-
let ret_ty = ret_coercion.borrow().expected_ty();
153-
let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
154-
self.can_coerce(arm_ty, ret_ty)
155-
&& prior_arm.map_or(true, |(_, t, _)| self.can_coerce(t, ret_ty))
156-
// The match arms need to unify for the case of `impl Trait`.
157-
&& !matches!(ret_ty.kind(), ty::Opaque(..))
158-
}
159-
_ => false,
160-
};
161-
if !can_coerce_to_return_ty {
162-
return;
163-
}
164-
165-
let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
166-
let mut ret_span: MultiSpan = semi_span.into();
167-
ret_span.push_span_label(
168-
expr.span,
169-
"this could be implicitly returned but it is a statement, not a \
170-
tail expression",
171-
);
172-
ret_span
173-
.push_span_label(ret, "the `match` arms can conform to this return type");
174-
ret_span.push_span_label(
175-
semi_span,
176-
"the `match` is a statement because of this semicolon, consider \
177-
removing it",
178-
);
179-
err.span_note(
180-
ret_span,
181-
"you might have meant to return the `match` expression",
182-
);
183-
err.tool_only_span_suggestion(
184-
semi_span,
185-
"remove this semicolon",
186-
"",
187-
Applicability::MaybeIncorrect,
188-
);
140+
self.suggest_removing_semicolon_for_coerce(
141+
err,
142+
expr,
143+
orig_expected,
144+
arm_ty,
145+
prior_arm,
146+
)
189147
}),
190148
false,
191149
);
@@ -219,6 +177,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
219177
coercion.complete(self)
220178
}
221179

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.
191+
let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, _), .. }) =
192+
hir.get(self.body_id) else { return; };
193+
let Some(hir::Stmt { kind: hir::StmtKind::Semi(last_expr), .. })
194+
= block.innermost_block().stmts.last() else { return; };
195+
if last_expr.hir_id != expr.hir_id {
196+
return;
197+
}
198+
199+
// Next, make sure that we have no type expectation.
200+
let Some(ret) = hir
201+
.find_by_def_id(self.body_id.owner.def_id)
202+
.and_then(|owner| owner.fn_decl())
203+
.map(|decl| decl.output.span()) else { return; };
204+
let Expectation::IsLast(stmt) = expectation else {
205+
return;
206+
};
207+
208+
let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
209+
Some(ret_coercion) => {
210+
let ret_ty = ret_coercion.borrow().expected_ty();
211+
let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
212+
self.can_coerce(arm_ty, ret_ty)
213+
&& prior_arm.map_or(true, |(_, ty, _)| self.can_coerce(ty, ret_ty))
214+
// The match arms need to unify for the case of `impl Trait`.
215+
&& !matches!(ret_ty.kind(), ty::Opaque(..))
216+
}
217+
_ => false,
218+
};
219+
if !can_coerce_to_return_ty {
220+
return;
221+
}
222+
223+
let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
224+
let mut ret_span: MultiSpan = semi_span.into();
225+
ret_span.push_span_label(
226+
expr.span,
227+
"this could be implicitly returned but it is a statement, not a \
228+
tail expression",
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,
233+
"the `match` is a statement because of this semicolon, consider \
234+
removing it",
235+
);
236+
diag.span_note(ret_span, "you might have meant to return the `match` expression");
237+
diag.tool_only_span_suggestion(
238+
semi_span,
239+
"remove this semicolon",
240+
"",
241+
Applicability::MaybeIncorrect,
242+
);
243+
}
244+
222245
/// When the previously checked expression (the scrutinee) diverges,
223246
/// warn the user about the match arms being unreachable.
224247
fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm<'tcx>]) {

compiler/rustc_hir_typeck/src/check.rs

-2
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ pub(super) fn check_fn<'a, 'tcx>(
100100

101101
inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
102102

103-
fcx.in_tail_expr = true;
104103
if let ty::Dynamic(..) = declared_ret_ty.kind() {
105104
// FIXME: We need to verify that the return type is `Sized` after the return expression has
106105
// been evaluated so that we have types available for all the nodes being returned, but that
@@ -119,7 +118,6 @@ pub(super) fn check_fn<'a, 'tcx>(
119118
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
120119
fcx.check_return_expr(&body.value, false);
121120
}
122-
fcx.in_tail_expr = false;
123121

124122
// We insert the deferred_generator_interiors entry after visiting the body.
125123
// This ensures that all nested generators appear before the entry of this generator.

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

-5
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,6 @@ pub struct FnCtxt<'a, 'tcx> {
6868
/// any).
6969
pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
7070

71-
/// Used exclusively to reduce cost of advanced evaluation used for
72-
/// more helpful diagnostics.
73-
pub(super) in_tail_expr: bool,
74-
7571
/// First span of a return site that we find. Used in error messages.
7672
pub(super) ret_coercion_span: Cell<Option<Span>>,
7773

@@ -130,7 +126,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
130126
param_env,
131127
err_count_on_creation: inh.tcx.sess.err_count(),
132128
ret_coercion: None,
133-
in_tail_expr: false,
134129
ret_coercion_span: Cell::new(None),
135130
resume_yield_tys: None,
136131
ps: Cell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),

0 commit comments

Comments
 (0)