Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 3 pull requests #116782

Merged
merged 6 commits into from
Oct 16, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Suggest adding return if the type of unused semi return value can c…
…oerce to the fn return type
chenyukang committed Oct 15, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 25d38c48c3c7d06c14ae65e964a114b89c09756e
1 change: 1 addition & 0 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
@@ -507,6 +507,7 @@ pub enum StashKey {
CallAssocMethod,
TraitMissingMethod,
OpaqueHiddenTypeMismatch,
MaybeForgetReturn,
}

fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
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
@@ -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);
}
}

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
@@ -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.
///
Original file line number Diff line number Diff line change
@@ -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;
}
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
@@ -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.