mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-30 14:01:51 +00:00
Auto merge of #123125 - gurry:122561-bad-note-non-zero-loop-iters-2, r=estebank
Remove suggestion about iteration count in coerce Fixes #122561 The iteration count-centric suggestion was implemented in PR #100094, but it was based on the wrong assumption that the type mismatch error depends on the number of times the loop iterates. As it turns out, that is not true (see this comment for details: https://github.com/rust-lang/rust/pull/122679#issuecomment-2017432531) This PR attempts to remedy the situation by changing the suggestion from the one centered on iteration count to a simple suggestion to add a return value. It should also fix #100285 by simply making it redundant.
This commit is contained in:
commit
06e88c306a
@ -37,11 +37,9 @@
|
||||
|
||||
use crate::errors::SuggestBoxingForReturnImplTrait;
|
||||
use crate::FnCtxt;
|
||||
use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
|
||||
use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::Expr;
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_infer::infer::type_variable::TypeVariableOrigin;
|
||||
use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
|
||||
@ -93,22 +91,6 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> {
|
||||
|
||||
type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>;
|
||||
|
||||
struct CollectRetsVisitor<'tcx> {
|
||||
ret_exprs: Vec<&'tcx hir::Expr<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||
match expr.kind {
|
||||
hir::ExprKind::Ret(_) => self.ret_exprs.push(expr),
|
||||
// `return` in closures does not return from the outer function
|
||||
hir::ExprKind::Closure(_) => return,
|
||||
_ => {}
|
||||
}
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
|
||||
/// Coercing a mutable reference to an immutable works, while
|
||||
/// coercing `&T` to `&mut T` should be forbidden.
|
||||
fn coerce_mutbls<'tcx>(
|
||||
@ -1597,7 +1579,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||
|
||||
let mut err;
|
||||
let mut unsized_return = false;
|
||||
let mut visitor = CollectRetsVisitor { ret_exprs: vec![] };
|
||||
match *cause.code() {
|
||||
ObligationCauseCode::ReturnNoExpression => {
|
||||
err = struct_span_code_err!(
|
||||
@ -1632,11 +1613,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||
if !fcx.tcx.features().unsized_locals {
|
||||
unsized_return = self.is_return_ty_definitely_unsized(fcx);
|
||||
}
|
||||
if let Some(expression) = expression
|
||||
&& let hir::ExprKind::Loop(loop_blk, ..) = expression.kind
|
||||
{
|
||||
intravisit::walk_block(&mut visitor, loop_blk);
|
||||
}
|
||||
}
|
||||
ObligationCauseCode::ReturnValue(id) => {
|
||||
err = self.report_return_mismatched_types(
|
||||
@ -1737,6 +1713,22 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||
augment_error(&mut err);
|
||||
|
||||
if let Some(expr) = expression {
|
||||
if let hir::ExprKind::Loop(
|
||||
_,
|
||||
_,
|
||||
loop_src @ (hir::LoopSource::While | hir::LoopSource::ForLoop),
|
||||
_,
|
||||
) = expr.kind
|
||||
{
|
||||
let loop_type = if loop_src == hir::LoopSource::While {
|
||||
"`while` loops"
|
||||
} else {
|
||||
"`for` loops"
|
||||
};
|
||||
|
||||
err.note(format!("{loop_type} evaluate to unit type `()`"));
|
||||
}
|
||||
|
||||
fcx.emit_coerce_suggestions(
|
||||
&mut err,
|
||||
expr,
|
||||
@ -1745,15 +1737,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||
None,
|
||||
Some(coercion_error),
|
||||
);
|
||||
if visitor.ret_exprs.len() > 0 {
|
||||
self.note_unreachable_loop_return(
|
||||
&mut err,
|
||||
fcx.tcx,
|
||||
&expr,
|
||||
&visitor.ret_exprs,
|
||||
expected,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let reported = err.emit_unless(unsized_return);
|
||||
@ -1827,110 +1810,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||
);
|
||||
}
|
||||
|
||||
fn note_unreachable_loop_return(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
expr: &hir::Expr<'tcx>,
|
||||
ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>,
|
||||
ty: Ty<'tcx>,
|
||||
) {
|
||||
let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else {
|
||||
return;
|
||||
};
|
||||
let mut span: MultiSpan = vec![loop_span].into();
|
||||
span.push_span_label(loop_span, "this might have zero elements to iterate on");
|
||||
const MAXITER: usize = 3;
|
||||
let iter = ret_exprs.iter().take(MAXITER);
|
||||
for ret_expr in iter {
|
||||
span.push_span_label(
|
||||
ret_expr.span,
|
||||
"if the loop doesn't execute, this value would never get returned",
|
||||
);
|
||||
}
|
||||
err.span_note(
|
||||
span,
|
||||
"the function expects a value to always be returned, but loops might run zero times",
|
||||
);
|
||||
if MAXITER < ret_exprs.len() {
|
||||
err.note(format!(
|
||||
"if the loop doesn't execute, {} other values would never get returned",
|
||||
ret_exprs.len() - MAXITER
|
||||
));
|
||||
}
|
||||
let hir = tcx.hir();
|
||||
let item = hir.get_parent_item(expr.hir_id);
|
||||
let ret_msg = "return a value for the case when the loop has zero elements to iterate on";
|
||||
let ret_ty_msg =
|
||||
"otherwise consider changing the return type to account for that possibility";
|
||||
let node = tcx.hir_node(item.into());
|
||||
if let Some(body_id) = node.body_id()
|
||||
&& let Some(sig) = node.fn_sig()
|
||||
&& let hir::ExprKind::Block(block, _) = hir.body(body_id).value.kind
|
||||
&& !ty.is_never()
|
||||
{
|
||||
let indentation = if let None = block.expr
|
||||
&& let [.., last] = &block.stmts
|
||||
{
|
||||
tcx.sess.source_map().indentation_before(last.span).unwrap_or_else(String::new)
|
||||
} else if let Some(expr) = block.expr {
|
||||
tcx.sess.source_map().indentation_before(expr.span).unwrap_or_else(String::new)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
if let None = block.expr
|
||||
&& let [.., last] = &block.stmts
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
last.span.shrink_to_hi(),
|
||||
ret_msg,
|
||||
format!("\n{indentation}/* `{ty}` value */"),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else if let Some(expr) = block.expr {
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_hi(),
|
||||
ret_msg,
|
||||
format!("\n{indentation}/* `{ty}` value */"),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
let mut sugg = match sig.decl.output {
|
||||
hir::FnRetTy::DefaultReturn(span) => {
|
||||
vec![(span, " -> Option<()>".to_string())]
|
||||
}
|
||||
hir::FnRetTy::Return(ty) => {
|
||||
vec![
|
||||
(ty.span.shrink_to_lo(), "Option<".to_string()),
|
||||
(ty.span.shrink_to_hi(), ">".to_string()),
|
||||
]
|
||||
}
|
||||
};
|
||||
for ret_expr in ret_exprs {
|
||||
match ret_expr.kind {
|
||||
hir::ExprKind::Ret(Some(expr)) => {
|
||||
sugg.push((expr.span.shrink_to_lo(), "Some(".to_string()));
|
||||
sugg.push((expr.span.shrink_to_hi(), ")".to_string()));
|
||||
}
|
||||
hir::ExprKind::Ret(None) => {
|
||||
sugg.push((ret_expr.span.shrink_to_hi(), " Some(())".to_string()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if let None = block.expr
|
||||
&& let [.., last] = &block.stmts
|
||||
{
|
||||
sugg.push((last.span.shrink_to_hi(), format!("\n{indentation}None")));
|
||||
} else if let Some(expr) = block.expr {
|
||||
sugg.push((expr.span.shrink_to_hi(), format!("\n{indentation}None")));
|
||||
}
|
||||
err.multipart_suggestion(ret_ty_msg, sugg, Applicability::MaybeIncorrect);
|
||||
} else {
|
||||
err.help(format!("{ret_msg}, {ret_ty_msg}"));
|
||||
}
|
||||
}
|
||||
|
||||
fn report_return_mismatched_types<'a>(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
|
@ -57,7 +57,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|| self.suggest_into(err, expr, expr_ty, expected)
|
||||
|| self.suggest_floating_point_literal(err, expr, expected)
|
||||
|| self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected)
|
||||
|| self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty);
|
||||
|| self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty)
|
||||
|| self.suggest_returning_value_after_loop(err, expr, expected);
|
||||
|
||||
if !suggested {
|
||||
self.note_source_of_type_mismatch_constraint(
|
||||
|
@ -18,8 +18,8 @@ use rustc_hir::def::Res;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{
|
||||
CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node,
|
||||
Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
|
||||
Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId,
|
||||
Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
|
||||
};
|
||||
use rustc_hir_analysis::collect::suggest_impl_trait;
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
@ -1942,6 +1942,91 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
false
|
||||
}
|
||||
|
||||
// If the expr is a while or for loop and is the tail expr of its
|
||||
// enclosing body suggest returning a value right after it
|
||||
pub fn suggest_returning_value_after_loop(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
expr: &hir::Expr<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
) -> bool {
|
||||
let hir = self.tcx.hir();
|
||||
let enclosing_scope =
|
||||
hir.get_enclosing_scope(expr.hir_id).map(|hir_id| self.tcx.hir_node(hir_id));
|
||||
|
||||
// Get tail expr of the enclosing block or body
|
||||
let tail_expr = if let Some(Node::Block(hir::Block { expr, .. })) = enclosing_scope
|
||||
&& expr.is_some()
|
||||
{
|
||||
*expr
|
||||
} else {
|
||||
let body_def_id = hir.enclosing_body_owner(expr.hir_id);
|
||||
let body_id = hir.body_owned_by(body_def_id);
|
||||
let body = hir.body(body_id);
|
||||
|
||||
// Get tail expr of the body
|
||||
match body.value.kind {
|
||||
// Regular function body etc.
|
||||
hir::ExprKind::Block(block, _) => block.expr,
|
||||
// Anon const body (there's no block in this case)
|
||||
hir::ExprKind::DropTemps(expr) => Some(expr),
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
|
||||
let Some(tail_expr) = tail_expr else {
|
||||
return false; // Body doesn't have a tail expr we can compare with
|
||||
};
|
||||
|
||||
// Get the loop expr within the tail expr
|
||||
let loop_expr_in_tail = match expr.kind {
|
||||
hir::ExprKind::Loop(_, _, hir::LoopSource::While, _) => tail_expr,
|
||||
hir::ExprKind::Loop(_, _, hir::LoopSource::ForLoop, _) => {
|
||||
match tail_expr.peel_drop_temps() {
|
||||
Expr { kind: ExprKind::Match(_, [Arm { body, .. }], _), .. } => body,
|
||||
_ => return false, // Not really a for loop
|
||||
}
|
||||
}
|
||||
_ => return false, // Not a while or a for loop
|
||||
};
|
||||
|
||||
// If the expr is the loop expr in the tail
|
||||
// then make the suggestion
|
||||
if expr.hir_id == loop_expr_in_tail.hir_id {
|
||||
let span = expr.span;
|
||||
|
||||
let (msg, suggestion) = if expected.is_never() {
|
||||
(
|
||||
"consider adding a diverging expression here",
|
||||
"`loop {}` or `panic!(\"...\")`".to_string(),
|
||||
)
|
||||
} else {
|
||||
("consider returning a value here", format!("`{expected}` value"))
|
||||
};
|
||||
|
||||
let src_map = self.tcx.sess.source_map();
|
||||
let suggestion = if src_map.is_multiline(expr.span) {
|
||||
let indentation = src_map.indentation_before(span).unwrap_or_else(String::new);
|
||||
format!("\n{indentation}/* {suggestion} */")
|
||||
} else {
|
||||
// If the entire expr is on a single line
|
||||
// put the suggestion also on the same line
|
||||
format!(" /* {suggestion} */")
|
||||
};
|
||||
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
msg,
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// If the expected type is an enum (Issue #55250) with any variants whose
|
||||
/// sole field is of the found type, suggest such variants. (Issue #42764)
|
||||
pub(crate) fn suggest_compatible_variants(
|
||||
|
110
tests/ui/coercion/coerce-loop-issue-122561.rs
Normal file
110
tests/ui/coercion/coerce-loop-issue-122561.rs
Normal file
@ -0,0 +1,110 @@
|
||||
// Regression test for #122561
|
||||
|
||||
fn for_infinite() -> bool {
|
||||
for i in 0.. {
|
||||
//~^ ERROR mismatched types
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fn for_finite() -> String {
|
||||
for i in 0..5 {
|
||||
//~^ ERROR mismatched types
|
||||
return String::from("test");
|
||||
}
|
||||
}
|
||||
|
||||
fn for_zero_times() -> bool {
|
||||
for i in 0..0 {
|
||||
//~^ ERROR mismatched types
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fn for_never_type() -> ! {
|
||||
for i in 0..5 {
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
|
||||
// Entire function on a single line.
|
||||
// Tests that we format the suggestion
|
||||
// correctly in this case
|
||||
fn for_single_line() -> bool { for i in 0.. { return false; } }
|
||||
//~^ ERROR mismatched types
|
||||
|
||||
// Loop in an anon const in function args
|
||||
// Tests that we:
|
||||
// a. deal properly with this complex case
|
||||
// b. format the suggestion correctly so
|
||||
// that it's readable
|
||||
fn for_in_arg(a: &[(); for x in 0..2 {}]) -> bool {
|
||||
//~^ ERROR `for` is not allowed in a `const`
|
||||
//~| ERROR mismatched types
|
||||
true
|
||||
}
|
||||
|
||||
fn while_inifinite() -> bool {
|
||||
while true {
|
||||
//~^ ERROR mismatched types
|
||||
//~| WARN denote infinite loops with `loop { ... }` [while_true]
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fn while_finite() -> bool {
|
||||
let mut i = 0;
|
||||
while i < 3 {
|
||||
//~^ ERROR mismatched types
|
||||
i += 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fn while_zero_times() -> bool {
|
||||
while false {
|
||||
//~^ ERROR mismatched types
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fn while_never_type() -> ! {
|
||||
while true {
|
||||
//~^ ERROR mismatched types
|
||||
//~| WARN denote infinite loops with `loop { ... }` [while_true]
|
||||
}
|
||||
}
|
||||
|
||||
// No type mismatch error in this case
|
||||
fn loop_() -> bool {
|
||||
loop {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const C: i32 = {
|
||||
for i in 0.. {
|
||||
//~^ ERROR `for` is not allowed in a `const`
|
||||
//~| ERROR mismatched types
|
||||
}
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let _ = [10; {
|
||||
for i in 0..5 {
|
||||
//~^ ERROR `for` is not allowed in a `const`
|
||||
//~| ERROR mismatched types
|
||||
}
|
||||
}];
|
||||
|
||||
let _ = [10; {
|
||||
while false {
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
}];
|
||||
|
||||
|
||||
let _ = |a: &[(); for x in 0..2 {}]| {};
|
||||
//~^ ERROR `for` is not allowed in a `const`
|
||||
//~| ERROR mismatched types
|
||||
}
|
299
tests/ui/coercion/coerce-loop-issue-122561.stderr
Normal file
299
tests/ui/coercion/coerce-loop-issue-122561.stderr
Normal file
@ -0,0 +1,299 @@
|
||||
warning: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/coerce-loop-issue-122561.rs:48:5
|
||||
|
|
||||
LL | while true {
|
||||
| ^^^^^^^^^^ help: use `loop`
|
||||
|
|
||||
= note: `#[warn(while_true)]` on by default
|
||||
|
||||
warning: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/coerce-loop-issue-122561.rs:72:5
|
||||
|
|
||||
LL | while true {
|
||||
| ^^^^^^^^^^ help: use `loop`
|
||||
|
||||
error[E0658]: `for` is not allowed in a `const`
|
||||
--> $DIR/coerce-loop-issue-122561.rs:41:24
|
||||
|
|
||||
LL | fn for_in_arg(a: &[(); for x in 0..2 {}]) -> bool {
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
|
||||
= help: add `#![feature(const_for)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: `for` is not allowed in a `const`
|
||||
--> $DIR/coerce-loop-issue-122561.rs:86:5
|
||||
|
|
||||
LL | / for i in 0.. {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
= note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
|
||||
= help: add `#![feature(const_for)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: `for` is not allowed in a `const`
|
||||
--> $DIR/coerce-loop-issue-122561.rs:94:9
|
||||
|
|
||||
LL | / for i in 0..5 {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_________^
|
||||
|
|
||||
= note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
|
||||
= help: add `#![feature(const_for)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: `for` is not allowed in a `const`
|
||||
--> $DIR/coerce-loop-issue-122561.rs:107:23
|
||||
|
|
||||
LL | let _ = |a: &[(); for x in 0..2 {}]| {};
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
|
||||
= help: add `#![feature(const_for)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:41:24
|
||||
|
|
||||
LL | fn for_in_arg(a: &[(); for x in 0..2 {}]) -> bool {
|
||||
| ^^^^^^^^^^^^^^^^ expected `usize`, found `()`
|
||||
|
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL | fn for_in_arg(a: &[(); for x in 0..2 {} /* `usize` value */]) -> bool {
|
||||
| +++++++++++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:86:5
|
||||
|
|
||||
LL | / for i in 0.. {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_____^ expected `i32`, found `()`
|
||||
|
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL ~ }
|
||||
LL + /* `i32` value */
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:4:5
|
||||
|
|
||||
LL | fn for_infinite() -> bool {
|
||||
| ---- expected `bool` because of return type
|
||||
LL | / for i in 0.. {
|
||||
LL | |
|
||||
LL | | return false;
|
||||
LL | | }
|
||||
| |_____^ expected `bool`, found `()`
|
||||
|
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL ~ }
|
||||
LL + /* `bool` value */
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:11:5
|
||||
|
|
||||
LL | fn for_finite() -> String {
|
||||
| ------ expected `String` because of return type
|
||||
LL | / for i in 0..5 {
|
||||
LL | |
|
||||
LL | | return String::from("test");
|
||||
LL | | }
|
||||
| |_____^ expected `String`, found `()`
|
||||
|
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL ~ }
|
||||
LL + /* `String` value */
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:18:5
|
||||
|
|
||||
LL | fn for_zero_times() -> bool {
|
||||
| ---- expected `bool` because of return type
|
||||
LL | / for i in 0..0 {
|
||||
LL | |
|
||||
LL | | return true;
|
||||
LL | | }
|
||||
| |_____^ expected `bool`, found `()`
|
||||
|
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL ~ }
|
||||
LL + /* `bool` value */
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:25:5
|
||||
|
|
||||
LL | fn for_never_type() -> ! {
|
||||
| - expected `!` because of return type
|
||||
LL | / for i in 0..5 {
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_____^ expected `!`, found `()`
|
||||
|
|
||||
= note: expected type `!`
|
||||
found unit type `()`
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
help: consider adding a diverging expression here
|
||||
|
|
||||
LL ~ }
|
||||
LL + /* `loop {}` or `panic!("...")` */
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:33:32
|
||||
|
|
||||
LL | fn for_single_line() -> bool { for i in 0.. { return false; } }
|
||||
| ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
|
||||
| |
|
||||
| expected `bool` because of return type
|
||||
|
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL | fn for_single_line() -> bool { for i in 0.. { return false; } /* `bool` value */ }
|
||||
| ++++++++++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:48:5
|
||||
|
|
||||
LL | fn while_inifinite() -> bool {
|
||||
| ---- expected `bool` because of return type
|
||||
LL | / while true {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | return true;
|
||||
LL | | }
|
||||
| |_____^ expected `bool`, found `()`
|
||||
|
|
||||
= note: `while` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL ~ }
|
||||
LL + /* `bool` value */
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:57:5
|
||||
|
|
||||
LL | fn while_finite() -> bool {
|
||||
| ---- expected `bool` because of return type
|
||||
LL | let mut i = 0;
|
||||
LL | / while i < 3 {
|
||||
LL | |
|
||||
LL | | i += 1;
|
||||
LL | | return true;
|
||||
LL | | }
|
||||
| |_____^ expected `bool`, found `()`
|
||||
|
|
||||
= note: `while` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL ~ }
|
||||
LL + /* `bool` value */
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:65:5
|
||||
|
|
||||
LL | fn while_zero_times() -> bool {
|
||||
| ---- expected `bool` because of return type
|
||||
LL | / while false {
|
||||
LL | |
|
||||
LL | | return true;
|
||||
LL | | }
|
||||
| |_____^ expected `bool`, found `()`
|
||||
|
|
||||
= note: `while` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL ~ }
|
||||
LL + /* `bool` value */
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:72:5
|
||||
|
|
||||
LL | fn while_never_type() -> ! {
|
||||
| - expected `!` because of return type
|
||||
LL | / while true {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_____^ expected `!`, found `()`
|
||||
|
|
||||
= note: expected type `!`
|
||||
found unit type `()`
|
||||
= note: `while` loops evaluate to unit type `()`
|
||||
help: consider adding a diverging expression here
|
||||
|
|
||||
LL ~ }
|
||||
LL + /* `loop {}` or `panic!("...")` */
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:94:9
|
||||
|
|
||||
LL | / for i in 0..5 {
|
||||
LL | |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_________^ expected `usize`, found `()`
|
||||
|
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL ~ }
|
||||
LL + /* `usize` value */
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:101:9
|
||||
|
|
||||
LL | / while false {
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_________^ expected `usize`, found `()`
|
||||
|
|
||||
= note: `while` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL ~ }
|
||||
LL + /* `usize` value */
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/coerce-loop-issue-122561.rs:107:23
|
||||
|
|
||||
LL | let _ = |a: &[(); for x in 0..2 {}]| {};
|
||||
| ^^^^^^^^^^^^^^^^ expected `usize`, found `()`
|
||||
|
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL | let _ = |a: &[(); for x in 0..2 {} /* `usize` value */]| {};
|
||||
| +++++++++++++++++++
|
||||
|
||||
error: aborting due to 18 previous errors; 2 warnings emitted
|
||||
|
||||
Some errors have detailed explanations: E0308, E0658.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
@ -11,6 +11,7 @@ LL | | }
|
||||
|
|
||||
= note: expected enum `Option<()>`
|
||||
found unit type `()`
|
||||
= note: `while` loops evaluate to unit type `()`
|
||||
help: try adding an expression at the end of the block
|
||||
|
|
||||
LL ~ }
|
||||
@ -49,6 +50,7 @@ LL | | }
|
||||
|
|
||||
= note: expected enum `Option<()>`
|
||||
found unit type `()`
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
help: try adding an expression at the end of the block
|
||||
|
|
||||
LL ~ }
|
||||
@ -106,6 +108,7 @@ LL | while false {}
|
||||
|
|
||||
= note: expected enum `Option<()>`
|
||||
found unit type `()`
|
||||
= note: `while` loops evaluate to unit type `()`
|
||||
help: try adding an expression at the end of the block
|
||||
|
|
||||
LL ~ while false {}
|
||||
|
@ -20,6 +20,12 @@ LL | | }
|
||||
|
|
||||
= note: expected type `!`
|
||||
found unit type `()`
|
||||
= note: `while` loops evaluate to unit type `()`
|
||||
help: consider adding a diverging expression here
|
||||
|
|
||||
LL ~ }
|
||||
LL + /* `loop {}` or `panic!("...")` */
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/break-while-condition.rs:24:13
|
||||
@ -31,14 +37,12 @@ LL | | }
|
||||
|
|
||||
= note: expected type `!`
|
||||
found unit type `()`
|
||||
note: the function expects a value to always be returned, but loops might run zero times
|
||||
--> $DIR/break-while-condition.rs:24:13
|
||||
= note: `while` loops evaluate to unit type `()`
|
||||
help: consider adding a diverging expression here
|
||||
|
|
||||
LL ~ }
|
||||
LL + /* `loop {}` or `panic!("...")` */
|
||||
|
|
||||
LL | while false {
|
||||
| ^^^^^^^^^^^ this might have zero elements to iterate on
|
||||
LL | return
|
||||
| ------ if the loop doesn't execute, this value would never get returned
|
||||
= help: return a value for the case when the loop has zero elements to iterate on, otherwise consider changing the return type to account for that possibility
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -40,6 +40,8 @@ error[E0308]: mismatched types
|
||||
LL | / 'c:
|
||||
LL | | for _ in None { break }; // but here we cite the whole loop
|
||||
| |_______________________________^ expected `i32`, found `()`
|
||||
|
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-27042.rs:15:9
|
||||
|
@ -13,6 +13,12 @@ error[E0308]: mismatched types
|
||||
|
|
||||
LL | |y: Vec<[(); for x in 0..2 {}]>| {};
|
||||
| ^^^^^^^^^^^^^^^^ expected `usize`, found `()`
|
||||
|
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL | |y: Vec<[(); for x in 0..2 {} /* `usize` value */]>| {};
|
||||
| +++++++++++++++++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
fn foo(n: i32) -> i32 { //~ HELP otherwise consider changing the return type to account for that possibility
|
||||
fn foo(n: i32) -> i32 {
|
||||
for i in 0..0 { //~ ERROR mismatched types [E0308]
|
||||
if n < 0 {
|
||||
return i;
|
||||
@ -14,7 +14,7 @@ fn foo(n: i32) -> i32 { //~ HELP otherwise consider changing the return type to
|
||||
return 5;
|
||||
}
|
||||
|
||||
} //~ HELP return a value for the case when the loop has zero elements to iterate on
|
||||
} //~ HELP consider returning a value here
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -12,47 +12,12 @@ LL | |
|
||||
LL | | }
|
||||
| |_____^ expected `i32`, found `()`
|
||||
|
|
||||
note: the function expects a value to always be returned, but loops might run zero times
|
||||
--> $DIR/issue-100285.rs:2:5
|
||||
|
|
||||
LL | for i in 0..0 {
|
||||
| ^^^^^^^^^^^^^ this might have zero elements to iterate on
|
||||
LL | if n < 0 {
|
||||
LL | return i;
|
||||
| -------- if the loop doesn't execute, this value would never get returned
|
||||
LL | } else if n < 10 {
|
||||
LL | return 1;
|
||||
| -------- if the loop doesn't execute, this value would never get returned
|
||||
LL | } else if n < 20 {
|
||||
LL | return 2;
|
||||
| -------- if the loop doesn't execute, this value would never get returned
|
||||
= note: if the loop doesn't execute, 3 other values would never get returned
|
||||
help: return a value for the case when the loop has zero elements to iterate on
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL ~ }
|
||||
LL ~ /* `i32` value */
|
||||
|
|
||||
help: otherwise consider changing the return type to account for that possibility
|
||||
|
|
||||
LL ~ fn foo(n: i32) -> Option<i32> {
|
||||
LL | for i in 0..0 {
|
||||
LL | if n < 0 {
|
||||
LL ~ return Some(i);
|
||||
LL | } else if n < 10 {
|
||||
LL ~ return Some(1);
|
||||
LL | } else if n < 20 {
|
||||
LL ~ return Some(2);
|
||||
LL | } else if n < 30 {
|
||||
LL ~ return Some(3);
|
||||
LL | } else if n < 40 {
|
||||
LL ~ return Some(4);
|
||||
LL | } else {
|
||||
LL ~ return Some(5);
|
||||
LL | }
|
||||
LL |
|
||||
LL ~ }
|
||||
LL ~ None
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
fn foo() -> i32 { //~ HELP otherwise consider changing the return type to account for that possibility
|
||||
fn foo() -> i32 {
|
||||
for i in 0..0 { //~ ERROR mismatched types [E0308]
|
||||
return i;
|
||||
} //~ HELP return a value for the case when the loop has zero elements to iterate on
|
||||
} //~ HELP consider returning a value here
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -8,26 +8,12 @@ LL | | return i;
|
||||
LL | | }
|
||||
| |_____^ expected `i32`, found `()`
|
||||
|
|
||||
note: the function expects a value to always be returned, but loops might run zero times
|
||||
--> $DIR/issue-98982.rs:2:5
|
||||
|
|
||||
LL | for i in 0..0 {
|
||||
| ^^^^^^^^^^^^^ this might have zero elements to iterate on
|
||||
LL | return i;
|
||||
| -------- if the loop doesn't execute, this value would never get returned
|
||||
help: return a value for the case when the loop has zero elements to iterate on
|
||||
= note: `for` loops evaluate to unit type `()`
|
||||
help: consider returning a value here
|
||||
|
|
||||
LL ~ }
|
||||
LL ~ /* `i32` value */
|
||||
|
|
||||
help: otherwise consider changing the return type to account for that possibility
|
||||
|
|
||||
LL ~ fn foo() -> Option<i32> {
|
||||
LL | for i in 0..0 {
|
||||
LL ~ return Some(i);
|
||||
LL ~ }
|
||||
LL ~ None
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user