Skip to content

Commit

Permalink
Rollup merge of #115196 - chenyukang:yukang-fix-86094, r=estebank
Browse files Browse the repository at this point in the history
Suggest adding `return` if the for semi which can coerce to the fn return type

Fixes #86094
r? `@estebank`
  • Loading branch information
matthiaskrgr authored Oct 16, 2023
2 parents 58352c0 + 25d38c4 commit 1de910f
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 12 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ pub enum StashKey {
CallAssocMethod,
TraitMissingMethod,
OpaqueHiddenTypeMismatch,
MaybeForgetReturn,
}

fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
57 changes: 55 additions & 2 deletions compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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};
Expand Down Expand Up @@ -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() => {
Expand Down Expand Up @@ -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.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
12 changes: 6 additions & 6 deletions tests/ui/traits/new-solver/specialization-unconstrained.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand All @@ -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.
Expand Down

0 comments on commit 1de910f

Please sign in to comment.