Address #44173 for trait errors.
),
}
};
-
+ self.check_for_binding_assigned_block_without_tail_expression(
+ &obligation,
+ &mut err,
+ trait_predicate,
+ );
if self.suggest_add_reference_to_arg(
&obligation,
&mut err,
if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) =
(body_id, subst.map(|subst| subst.unpack()))
{
- struct FindExprBySpan<'hir> {
- span: Span,
- result: Option<&'hir hir::Expr<'hir>>,
- }
-
- impl<'v> hir::intravisit::Visitor<'v> for FindExprBySpan<'v> {
- fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
- if self.span == ex.span {
- self.result = Some(ex);
- } else {
- hir::intravisit::walk_expr(self, ex);
- }
- }
- }
-
- let mut expr_finder = FindExprBySpan { span, result: None };
-
+ let mut expr_finder = FindExprBySpan::new(span);
expr_finder.visit_expr(&self.tcx.hir().body(body_id).value);
if let Some(hir::Expr {
}
}
+/// Crude way of getting back an `Expr` from a `Span`.
+pub struct FindExprBySpan<'hir> {
+ pub span: Span,
+ pub result: Option<&'hir hir::Expr<'hir>>,
+ pub ty_result: Option<&'hir hir::Ty<'hir>>,
+}
+
+impl<'hir> FindExprBySpan<'hir> {
+ fn new(span: Span) -> Self {
+ Self { span, result: None, ty_result: None }
+ }
+}
+
+impl<'v> Visitor<'v> for FindExprBySpan<'v> {
+ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+ if self.span == ex.span {
+ self.result = Some(ex);
+ } else {
+ hir::intravisit::walk_expr(self, ex);
+ }
+ }
+ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+ if self.span == ty.span {
+ self.ty_result = Some(ty);
+ } else {
+ hir::intravisit::walk_ty(self, ty);
+ }
+ }
+}
+
/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
/// `param: ?Sized` would be a valid constraint.
struct FindTypeParam {
// ignore-tidy-filelength
-use super::{DefIdOrName, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation};
+use super::{
+ DefIdOrName, FindExprBySpan, Obligation, ObligationCause, ObligationCauseCode,
+ PredicateObligation,
+};
use crate::autoderef::Autoderef;
use crate::infer::InferCtxt;
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool;
+ fn check_for_binding_assigned_block_without_tail_expression(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ );
+
fn suggest_add_reference_to_arg(
&self,
obligation: &PredicateObligation<'tcx>,
true
}
+ fn check_for_binding_assigned_block_without_tail_expression(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) {
+ let mut span = obligation.cause.span;
+ while span.from_expansion() {
+ // Remove all the desugaring and macro contexts.
+ span.remove_mark();
+ }
+ let mut expr_finder = FindExprBySpan::new(span);
+ let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else { return; };
+ expr_finder.visit_expr(&body);
+ let Some(expr) = expr_finder.result else { return; };
+ let Some(typeck) = &self.typeck_results else { return; };
+ let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else { return; };
+ if !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) = typeck.expr_ty_opt(tail_expr) else {
+ err.span_help(block.span, "this block is missing a tail expression");
+ return;
+ };
+ let ty = self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(ty));
+ let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, ty));
+
+ let new_obligation =
+ self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
+ if self.predicate_must_hold_modulo_regions(&new_obligation) {
+ 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");
+ }
+ }
+
fn suggest_add_reference_to_arg(
&self,
obligation: &PredicateObligation<'tcx>,
+struct S;
fn main() {
let x = {
println!("foo");
let z = {
"hi";
};
+ let s = {
+ S;
+ };
println!("{}", x); //~ ERROR E0277
println!("{}", y); //~ ERROR E0277
println!("{}", z); //~ ERROR E0277
+ println!("{}", s); //~ ERROR E0277
let _: i32 = x; //~ ERROR E0308
let _: i32 = y; //~ ERROR E0308
let _: i32 = z; //~ ERROR E0308
+ let _: i32 = s; //~ ERROR E0308
}
error[E0277]: `()` doesn't implement `std::fmt::Display`
- --> $DIR/binding-assigned-block-without-tail-expression.rs:10:20
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:14: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)
+help: remove this semicolon
+ |
+LL - 42;
+LL + 42
+ |
error[E0277]: `()` doesn't implement `std::fmt::Display`
- --> $DIR/binding-assigned-block-without-tail-expression.rs:11:20
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:15:20
|
LL | println!("{}", y);
| ^ `()` cannot be formatted with the default formatter
|
+help: this empty block is missing a tail expression
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:7:13
+ |
+LL | let y = {};
+ | ^^
= 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
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:16: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)
+help: remove this semicolon
+ |
+LL - "hi";
+LL + "hi"
+ |
+
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:17:20
+ |
+LL | println!("{}", s);
+ | ^ `()` cannot be formatted with the default formatter
+ |
+help: this block is missing a tail expression
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:11:13
+ |
+LL | let s = {
+ | _____________^
+LL | | S;
+LL | | };
+ | |_____^
+ = 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
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:18:18
|
LL | let _: i32 = x;
| --- ^ expected `i32`, found `()`
|
error[E0308]: mismatched types
- --> $DIR/binding-assigned-block-without-tail-expression.rs:14:18
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:19: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
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:7:13
|
LL | let y = {};
| ^^
error[E0308]: mismatched types
- --> $DIR/binding-assigned-block-without-tail-expression.rs:15:18
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:20: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
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:8:13
|
LL | let z = {
| _____________^
LL | | };
| |_____^
-error: aborting due to 6 previous errors
+error[E0308]: mismatched types
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:21:18
+ |
+LL | let _: i32 = s;
+ | --- ^ expected `i32`, found `()`
+ | |
+ | expected due to this
+ |
+help: this block is missing a tail expression
+ --> $DIR/binding-assigned-block-without-tail-expression.rs:11:13
+ |
+LL | let s = {
+ | _____________^
+LL | | S;
+LL | | };
+ | |_____^
+
+error: aborting due to 8 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.