Detect bindings assigned blocks without tail expressions
Address #44173 for type check errors.
This commit is contained in:
parent
388538fc96
commit
1983a627b3
3 changed files with 140 additions and 0 deletions
|
@ -75,6 +75,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.note_need_for_fn_pointer(err, expected, expr_ty);
|
||||
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
|
||||
self.check_for_range_as_method_call(err, expr, expr_ty, expected);
|
||||
self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
|
||||
}
|
||||
|
||||
/// Requires that the two types unify, and prints an error message if
|
||||
|
@ -1670,4 +1671,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
/// Identify when the type error is because `()` is found in a binding that was assigned a
|
||||
/// block without a tail expression.
|
||||
fn check_for_binding_assigned_block_without_tail_expression(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
expr: &hir::Expr<'_>,
|
||||
checked_ty: Ty<'tcx>,
|
||||
expected_ty: Ty<'tcx>,
|
||||
) {
|
||||
if !checked_ty.is_unit() {
|
||||
return;
|
||||
}
|
||||
let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; };
|
||||
let hir::def::Res::Local(hir_id) = path.res else { return; };
|
||||
let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else {
|
||||
return;
|
||||
};
|
||||
let Some(hir::Node::Local(hir::Local {
|
||||
ty: None,
|
||||
init: Some(init),
|
||||
..
|
||||
})) = self.tcx.hir().find_parent(pat.hir_id) else { return; };
|
||||
let hir::ExprKind::Block(block, None) = init.kind else { return; };
|
||||
if block.expr.is_some() {
|
||||
return;
|
||||
}
|
||||
let [.., stmt] = block.stmts else {
|
||||
err.span_help(block.span, "this empty block is missing a tail expression");
|
||||
return;
|
||||
};
|
||||
let hir::StmtKind::Semi(tail_expr) = stmt.kind else { return; };
|
||||
let Some(ty) = self.node_ty_opt(tail_expr.hir_id) else { return; };
|
||||
if self.can_eq(self.param_env, expected_ty, ty).is_ok() {
|
||||
err.span_suggestion_verbose(
|
||||
stmt.span.with_lo(tail_expr.span.hi()),
|
||||
"remove this semicolon",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
err.span_help(block.span, "this block is missing a tail expression");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
fn main() {
|
||||
let x = {
|
||||
println!("foo");
|
||||
42;
|
||||
};
|
||||
let y = {};
|
||||
let z = {
|
||||
"hi";
|
||||
};
|
||||
println!("{}", x); //~ ERROR E0277
|
||||
println!("{}", y); //~ ERROR E0277
|
||||
println!("{}", z); //~ ERROR E0277
|
||||
let _: i32 = x; //~ ERROR E0308
|
||||
let _: i32 = y; //~ ERROR E0308
|
||||
let _: i32 = z; //~ ERROR E0308
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
--> $DIR/binding-assigned-block-without-tail-expression.rs:10:20
|
||||
|
|
||||
LL | println!("{}", x);
|
||||
| ^ `()` cannot be formatted with the default formatter
|
||||
|
|
||||
= help: the trait `std::fmt::Display` is not implemented for `()`
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
--> $DIR/binding-assigned-block-without-tail-expression.rs:11:20
|
||||
|
|
||||
LL | println!("{}", y);
|
||||
| ^ `()` cannot be formatted with the default formatter
|
||||
|
|
||||
= help: the trait `std::fmt::Display` is not implemented for `()`
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
--> $DIR/binding-assigned-block-without-tail-expression.rs:12:20
|
||||
|
|
||||
LL | println!("{}", z);
|
||||
| ^ `()` cannot be formatted with the default formatter
|
||||
|
|
||||
= help: the trait `std::fmt::Display` is not implemented for `()`
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/binding-assigned-block-without-tail-expression.rs:13:18
|
||||
|
|
||||
LL | let _: i32 = x;
|
||||
| --- ^ expected `i32`, found `()`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
help: remove this semicolon
|
||||
|
|
||||
LL - 42;
|
||||
LL + 42
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/binding-assigned-block-without-tail-expression.rs:14:18
|
||||
|
|
||||
LL | let _: i32 = y;
|
||||
| --- ^ expected `i32`, found `()`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
help: this empty block is missing a tail expression
|
||||
--> $DIR/binding-assigned-block-without-tail-expression.rs:6:13
|
||||
|
|
||||
LL | let y = {};
|
||||
| ^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/binding-assigned-block-without-tail-expression.rs:15:18
|
||||
|
|
||||
LL | let _: i32 = z;
|
||||
| --- ^ expected `i32`, found `()`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
help: this block is missing a tail expression
|
||||
--> $DIR/binding-assigned-block-without-tail-expression.rs:7:13
|
||||
|
|
||||
LL | let z = {
|
||||
| _____________^
|
||||
LL | | "hi";
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0308.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
Loading…
Add table
Reference in a new issue