about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_errors/src/lib.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs57
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs8
-rw-r--r--tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs61
-rw-r--r--tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr98
-rw-r--r--tests/ui/traits/new-solver/specialization-unconstrained.stderr12
7 files changed, 230 insertions, 12 deletions
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 63226504d37..19b4d0c2bdf 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -507,6 +507,7 @@ pub enum StashKey {
     CallAssocMethod,
     TraitMissingMethod,
     OpaqueHiddenTypeMismatch,
+    MaybeForgetReturn,
 }
 
 fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 5dae74a1f9b..98cdeb64532 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -564,7 +564,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         if !errors.is_empty() {
             self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
+            let errors_causecode = errors
+                .iter()
+                .map(|e| (e.obligation.cause.span, e.root_obligation.cause.code().clone()))
+                .collect::<Vec<_>>();
             self.err_ctxt().report_fulfillment_errors(errors);
+            self.collect_unused_stmts_for_coerce_return_ty(errors_causecode);
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index c762e684480..5979a6e213e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -11,7 +11,7 @@ use crate::{
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{
-    pluralize, Applicability, Diagnostic, DiagnosticId, ErrorGuaranteed, MultiSpan,
+    pluralize, Applicability, Diagnostic, DiagnosticId, ErrorGuaranteed, MultiSpan, StashKey,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -27,6 +27,7 @@ use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::TypeTrace;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
+use rustc_middle::traits::ObligationCauseCode::ExprBindingObligation;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
@@ -1375,7 +1376,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
                 _ => bug!("unexpected type: {:?}", ty.normalized),
             },
-            Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
+            Res::Def(
+                DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy,
+                _,
+            )
             | Res::SelfTyParam { .. }
             | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() {
                 Some(adt) if !adt.is_enum() => {
@@ -1845,6 +1849,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    pub(super) fn collect_unused_stmts_for_coerce_return_ty(
+        &self,
+        errors_causecode: Vec<(Span, ObligationCauseCode<'tcx>)>,
+    ) {
+        for (span, code) in errors_causecode {
+            let Some(mut diag) =
+                self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::MaybeForgetReturn)
+            else {
+                continue;
+            };
+
+            if let Some(fn_sig) = self.body_fn_sig()
+                && let ExprBindingObligation(_, _, hir_id, ..) = code
+                && !fn_sig.output().is_unit()
+            {
+                    let mut block_num = 0;
+                    let mut found_semi = false;
+                    for (_, node) in self.tcx.hir().parent_iter(hir_id) {
+                        match node {
+                            hir::Node::Stmt(stmt) => if let hir::StmtKind::Semi(ref expr) = stmt.kind {
+                                let expr_ty = self.typeck_results.borrow().expr_ty(expr);
+                                let return_ty = fn_sig.output();
+                                if !matches!(expr.kind, hir::ExprKind::Ret(..)) &&
+                                    self.can_coerce(expr_ty, return_ty) {
+                                    found_semi = true;
+                                }
+                            },
+                            hir::Node::Block(_block) => if found_semi {
+                                block_num += 1;
+                            }
+                            hir::Node::Item(item) => if let hir::ItemKind::Fn(..) = item.kind {
+                                break;
+                            }
+                            _ => {}
+                        }
+                    }
+                    if block_num > 1 && found_semi {
+                        diag.span_suggestion_verbose(
+                            span.shrink_to_lo(),
+                            "you might have meant to return this to infer its type parameters",
+                            "return ",
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+            }
+            diag.emit();
+        }
+    }
+
     /// Given a vector of fulfillment errors, try to adjust the spans of the
     /// errors to more accurately point at the cause of the failure.
     ///
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 8adfb27a3f4..96d9873646d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -17,7 +17,7 @@ use crate::traits::{
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-    MultiSpan, Style,
+    MultiSpan, StashKey, Style,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace, Res};
@@ -2049,14 +2049,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 // begin with in those cases.
                 if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
                     if let None = self.tainted_by_errors() {
-                        self.emit_inference_failure_err(
+                        let err = self.emit_inference_failure_err(
                             obligation.cause.body_id,
                             span,
                             trait_ref.self_ty().skip_binder().into(),
                             ErrorCode::E0282,
                             false,
-                        )
-                        .emit();
+                        );
+                        err.stash(span, StashKey::MaybeForgetReturn);
                     }
                     return;
                 }
diff --git a/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs
new file mode 100644
index 00000000000..4544c898ab8
--- /dev/null
+++ b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs
@@ -0,0 +1,61 @@
+struct MyError;
+
+fn foo(x: bool) -> Result<(), MyError> {
+    if x {
+        Err(MyError);
+        //~^ ERROR type annotations needed
+    }
+
+    Ok(())
+}
+
+fn bar(x: bool) -> Result<(), MyError> {
+    if x {
+        Ok(());
+        //~^ ERROR type annotations needed
+    }
+
+    Ok(())
+}
+
+fn baz(x: bool) -> Result<(), MyError> {
+    //~^ ERROR mismatched types
+    if x {
+        1;
+    }
+
+    Err(MyError);
+}
+
+fn error() -> Result<(), MyError> {
+    Err(MyError)
+}
+
+fn bak(x: bool) -> Result<(), MyError> {
+    if x {
+        //~^ ERROR mismatched types
+        error();
+    } else {
+        //~^ ERROR mismatched types
+        error();
+    }
+}
+
+fn bad(x: bool) -> Result<(), MyError> {
+    Err(MyError); //~ ERROR type annotations needed
+    Ok(())
+}
+
+fn with_closure<F, A, B>(_: F) -> i32
+where
+    F: FnOnce(A, B),
+{
+    0
+}
+
+fn a() -> i32 {
+    with_closure(|x: u32, y| {}); //~ ERROR type annotations needed
+    0
+}
+
+fn main() {}
diff --git a/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr
new file mode 100644
index 00000000000..1fea73529a8
--- /dev/null
+++ b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr
@@ -0,0 +1,98 @@
+error[E0282]: type annotations needed
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:5:9
+   |
+LL |         Err(MyError);
+   |         ^^^ cannot infer type of the type parameter `T` declared on the enum `Result`
+   |
+help: consider specifying the generic arguments
+   |
+LL |         Err::<T, MyError>(MyError);
+   |            ++++++++++++++
+help: you might have meant to return this to infer its type parameters
+   |
+LL |         return Err(MyError);
+   |         ++++++
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:14:9
+   |
+LL |         Ok(());
+   |         ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
+   |
+help: consider specifying the generic arguments
+   |
+LL |         Ok::<(), E>(());
+   |           +++++++++
+help: you might have meant to return this to infer its type parameters
+   |
+LL |         return Ok(());
+   |         ++++++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:21:20
+   |
+LL | fn baz(x: bool) -> Result<(), MyError> {
+   |    ---             ^^^^^^^^^^^^^^^^^^^ expected `Result<(), MyError>`, found `()`
+   |    |
+   |    implicitly returns `()` as its body has no tail or `return` expression
+...
+LL |     Err(MyError);
+   |                 - help: remove this semicolon to return this value
+   |
+   = note:   expected enum `Result<(), MyError>`
+           found unit type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:35:10
+   |
+LL |       if x {
+   |  __________^
+LL | |
+LL | |         error();
+   | |                - help: remove this semicolon to return this value
+LL | |     } else {
+   | |_____^ expected `Result<(), MyError>`, found `()`
+   |
+   = note:   expected enum `Result<(), MyError>`
+           found unit type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:38:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |
+LL | |         error();
+   | |                - help: remove this semicolon to return this value
+LL | |     }
+   | |_____^ expected `Result<(), MyError>`, found `()`
+   |
+   = note:   expected enum `Result<(), MyError>`
+           found unit type `()`
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:45:5
+   |
+LL |     Err(MyError);
+   |     ^^^ cannot infer type of the type parameter `T` declared on the enum `Result`
+   |
+help: consider specifying the generic arguments
+   |
+LL |     Err::<T, MyError>(MyError);
+   |        ++++++++++++++
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:57:27
+   |
+LL |     with_closure(|x: u32, y| {});
+   |                           ^
+   |
+help: consider giving this closure parameter an explicit type
+   |
+LL |     with_closure(|x: u32, y: /* Type */| {});
+   |                            ++++++++++++
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0282, E0308.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/traits/new-solver/specialization-unconstrained.stderr b/tests/ui/traits/new-solver/specialization-unconstrained.stderr
index 9915da1a27a..ed4dafa1484 100644
--- a/tests/ui/traits/new-solver/specialization-unconstrained.stderr
+++ b/tests/ui/traits/new-solver/specialization-unconstrained.stderr
@@ -8,12 +8,6 @@ LL | #![feature(specialization)]
    = help: consider using `min_specialization` instead, which is more stable and complete
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0282]: type annotations needed
-  --> $DIR/specialization-unconstrained.rs:14:22
-   |
-LL |    default type Id = T;
-   |                      ^ cannot infer type for associated type `<T as Default>::Id`
-
 error[E0284]: type annotations needed: cannot satisfy `<u32 as Default>::Id == ()`
   --> $DIR/specialization-unconstrained.rs:20:5
    |
@@ -26,6 +20,12 @@ note: required by a bound in `test`
 LL | fn test<T: Default<Id = U>, U>() {}
    |                    ^^^^^^ required by this bound in `test`
 
+error[E0282]: type annotations needed
+  --> $DIR/specialization-unconstrained.rs:14:22
+   |
+LL |    default type Id = T;
+   |                      ^ cannot infer type for associated type `<T as Default>::Id`
+
 error: aborting due to 2 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0282, E0284.