Auto merge of #123812 - compiler-errors:additional-fixes, r=fmease
Follow-up fixes to `report_return_mismatched_types` Some renames, simplifications, fixes, etc. Follow-ups to #123804. I don't think it totally disentangles this code, but it does remove some of the worst offenders on the "I am so confused" scale (e.g. `get_node_fn_decl`).
This commit is contained in:
commit
e875391458
@ -992,7 +992,7 @@ fn expected_fn_found_fn_mut_call(&self, err: &mut Diag<'_>, sp: Span, act: &str)
|
||||
}
|
||||
}
|
||||
|
||||
if look_at_return && hir.get_return_block(closure_id).is_some() {
|
||||
if look_at_return && hir.get_fn_id_for_return_block(closure_id).is_some() {
|
||||
// ...otherwise we are probably in the tail expression of the function, point at the
|
||||
// return type.
|
||||
match self.infcx.tcx.hir_node_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
|
||||
|
@ -1591,31 +1591,28 @@ pub(crate) fn coerce_inner<'a>(
|
||||
err.span_label(cause.span, "return type is not `()`");
|
||||
}
|
||||
ObligationCauseCode::BlockTailExpression(blk_id, ..) => {
|
||||
let parent_id = fcx.tcx.parent_hir_id(blk_id);
|
||||
err = self.report_return_mismatched_types(
|
||||
cause,
|
||||
expected,
|
||||
found,
|
||||
coercion_error,
|
||||
fcx,
|
||||
parent_id,
|
||||
blk_id,
|
||||
expression,
|
||||
Some(blk_id),
|
||||
);
|
||||
if !fcx.tcx.features().unsized_locals {
|
||||
unsized_return = self.is_return_ty_definitely_unsized(fcx);
|
||||
}
|
||||
}
|
||||
ObligationCauseCode::ReturnValue(id) => {
|
||||
ObligationCauseCode::ReturnValue(return_expr_id) => {
|
||||
err = self.report_return_mismatched_types(
|
||||
cause,
|
||||
expected,
|
||||
found,
|
||||
coercion_error,
|
||||
fcx,
|
||||
id,
|
||||
return_expr_id,
|
||||
expression,
|
||||
None,
|
||||
);
|
||||
if !fcx.tcx.features().unsized_locals {
|
||||
unsized_return = self.is_return_ty_definitely_unsized(fcx);
|
||||
@ -1809,13 +1806,14 @@ fn report_return_mismatched_types<'a>(
|
||||
found: Ty<'tcx>,
|
||||
ty_err: TypeError<'tcx>,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
id: hir::HirId,
|
||||
block_or_return_id: hir::HirId,
|
||||
expression: Option<&'tcx hir::Expr<'tcx>>,
|
||||
blk_id: Option<hir::HirId>,
|
||||
) -> Diag<'a> {
|
||||
let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
|
||||
|
||||
let parent_id = fcx.tcx.parent_hir_id(id);
|
||||
let due_to_block = matches!(fcx.tcx.hir_node(block_or_return_id), hir::Node::Block(..));
|
||||
|
||||
let parent_id = fcx.tcx.parent_hir_id(block_or_return_id);
|
||||
let parent = fcx.tcx.hir_node(parent_id);
|
||||
if let Some(expr) = expression
|
||||
&& let hir::Node::Expr(hir::Expr {
|
||||
@ -1829,72 +1827,64 @@ fn report_return_mismatched_types<'a>(
|
||||
// Verify that this is a tail expression of a function, otherwise the
|
||||
// label pointing out the cause for the type coercion will be wrong
|
||||
// as prior return coercions would not be relevant (#57664).
|
||||
let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) {
|
||||
if let Some(expr) = expression
|
||||
&& due_to_block
|
||||
{
|
||||
fcx.suggest_missing_semicolon(&mut err, expr, expected, false);
|
||||
let pointing_at_return_type =
|
||||
fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id);
|
||||
if let (Some(cond_expr), true, false) = (
|
||||
fcx.tcx.hir().get_if_cause(expr.hir_id),
|
||||
expected.is_unit(),
|
||||
pointing_at_return_type,
|
||||
)
|
||||
let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(
|
||||
&mut err,
|
||||
expr,
|
||||
expected,
|
||||
found,
|
||||
block_or_return_id,
|
||||
);
|
||||
if let Some(cond_expr) = fcx.tcx.hir().get_if_cause(expr.hir_id)
|
||||
&& expected.is_unit()
|
||||
&& !pointing_at_return_type
|
||||
// If the block is from an external macro or try (`?`) desugaring, then
|
||||
// do not suggest adding a semicolon, because there's nowhere to put it.
|
||||
// See issues #81943 and #87051.
|
||||
&& matches!(
|
||||
cond_expr.span.desugaring_kind(),
|
||||
None | Some(DesugaringKind::WhileLoop)
|
||||
) && !in_external_macro(fcx.tcx.sess, cond_expr.span)
|
||||
&& !matches!(
|
||||
cond_expr.kind,
|
||||
hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_))
|
||||
)
|
||||
)
|
||||
&& !in_external_macro(fcx.tcx.sess, cond_expr.span)
|
||||
&& !matches!(
|
||||
cond_expr.kind,
|
||||
hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_))
|
||||
)
|
||||
{
|
||||
err.span_label(cond_expr.span, "expected this to be `()`");
|
||||
if expr.can_have_side_effects() {
|
||||
fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
|
||||
}
|
||||
}
|
||||
fcx.get_node_fn_decl(parent)
|
||||
.map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
|
||||
} else {
|
||||
fcx.get_fn_decl(parent_id)
|
||||
};
|
||||
|
||||
if let Some((fn_id, fn_decl, can_suggest)) = fn_decl {
|
||||
if blk_id.is_none() {
|
||||
fcx.suggest_missing_return_type(
|
||||
&mut err,
|
||||
fn_decl,
|
||||
expected,
|
||||
found,
|
||||
can_suggest,
|
||||
fn_id,
|
||||
);
|
||||
}
|
||||
// If this is due to an explicit `return`, suggest adding a return type.
|
||||
if let Some((fn_id, fn_decl, can_suggest)) = fcx.get_fn_decl(parent_id)
|
||||
&& !due_to_block
|
||||
{
|
||||
fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, can_suggest, fn_id);
|
||||
}
|
||||
|
||||
let mut parent_id = fcx.tcx.hir().get_parent_item(id).def_id;
|
||||
let mut parent_item = fcx.tcx.hir_node_by_def_id(parent_id);
|
||||
// When suggesting return, we need to account for closures and async blocks, not just items.
|
||||
for (_, node) in fcx.tcx.hir().parent_iter(id) {
|
||||
match node {
|
||||
hir::Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Closure(hir::Closure { def_id, .. }),
|
||||
..
|
||||
}) => {
|
||||
parent_item = node;
|
||||
parent_id = *def_id;
|
||||
break;
|
||||
}
|
||||
hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(expr), Some(_), Some(fn_decl)) = (expression, blk_id, parent_item.fn_decl()) {
|
||||
// If this is due to a block, then maybe we forgot a `return`/`break`.
|
||||
if due_to_block
|
||||
&& let Some(expr) = expression
|
||||
&& let Some((parent_fn_decl, parent_id)) = fcx
|
||||
.tcx
|
||||
.hir()
|
||||
.parent_iter(block_or_return_id)
|
||||
.find_map(|(_, node)| Some((node.fn_decl()?, node.associated_body()?.0)))
|
||||
{
|
||||
fcx.suggest_missing_break_or_return_expr(
|
||||
&mut err, expr, fn_decl, expected, found, id, parent_id,
|
||||
&mut err,
|
||||
expr,
|
||||
parent_fn_decl,
|
||||
expected,
|
||||
found,
|
||||
block_or_return_id,
|
||||
parent_id,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@
|
||||
use rustc_session::lint;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::FieldIdx;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
@ -867,76 +867,6 @@ pub fn resolve_ty_and_res_fully_qualified_call(
|
||||
)
|
||||
}
|
||||
|
||||
/// Given a function `Node`, return its `HirId` and `FnDecl` if it exists. Given a closure
|
||||
/// that is the child of a function, return that function's `HirId` and `FnDecl` instead.
|
||||
/// This may seem confusing at first, but this is used in diagnostics for `async fn`,
|
||||
/// for example, where most of the type checking actually happens within a nested closure,
|
||||
/// but we often want access to the parent function's signature.
|
||||
///
|
||||
/// Otherwise, return false.
|
||||
pub(crate) fn get_node_fn_decl(
|
||||
&self,
|
||||
node: Node<'tcx>,
|
||||
) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> {
|
||||
match node {
|
||||
Node::Item(&hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => {
|
||||
// This is less than ideal, it will not suggest a return type span on any
|
||||
// method called `main`, regardless of whether it is actually the entry point,
|
||||
// but it will still present it as the reason for the expected type.
|
||||
Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main))
|
||||
}
|
||||
Node::TraitItem(&hir::TraitItem {
|
||||
ident,
|
||||
kind: hir::TraitItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => Some((owner_id.def_id, &sig.decl, ident, true)),
|
||||
Node::ImplItem(&hir::ImplItem {
|
||||
ident,
|
||||
kind: hir::ImplItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => Some((owner_id.def_id, &sig.decl, ident, false)),
|
||||
Node::Expr(&hir::Expr {
|
||||
hir_id,
|
||||
kind:
|
||||
hir::ExprKind::Closure(hir::Closure {
|
||||
kind: hir::ClosureKind::Coroutine(..), ..
|
||||
}),
|
||||
..
|
||||
}) => {
|
||||
let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
|
||||
Node::Item(&hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => (ident, sig, owner_id),
|
||||
Node::TraitItem(&hir::TraitItem {
|
||||
ident,
|
||||
kind: hir::TraitItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => (ident, sig, owner_id),
|
||||
Node::ImplItem(&hir::ImplItem {
|
||||
ident,
|
||||
kind: hir::ImplItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => (ident, sig, owner_id),
|
||||
_ => return None,
|
||||
};
|
||||
Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a
|
||||
/// suggestion can be made, `None` otherwise.
|
||||
pub fn get_fn_decl(
|
||||
@ -945,10 +875,73 @@ pub fn get_fn_decl(
|
||||
) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, bool)> {
|
||||
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
|
||||
// `while` before reaching it, as block tail returns are not available in them.
|
||||
self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
|
||||
let parent = self.tcx.hir_node(blk_id);
|
||||
self.get_node_fn_decl(parent)
|
||||
.map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
|
||||
self.tcx.hir().get_fn_id_for_return_block(blk_id).and_then(|item_id| {
|
||||
match self.tcx.hir_node(item_id) {
|
||||
Node::Item(&hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => {
|
||||
// This is less than ideal, it will not suggest a return type span on any
|
||||
// method called `main`, regardless of whether it is actually the entry point,
|
||||
// but it will still present it as the reason for the expected type.
|
||||
Some((owner_id.def_id, sig.decl, ident.name != sym::main))
|
||||
}
|
||||
Node::TraitItem(&hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => Some((owner_id.def_id, sig.decl, true)),
|
||||
// FIXME: Suggestable if this is not a trait implementation
|
||||
Node::ImplItem(&hir::ImplItem {
|
||||
kind: hir::ImplItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => Some((owner_id.def_id, sig.decl, false)),
|
||||
Node::Expr(&hir::Expr {
|
||||
hir_id,
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { def_id, kind, fn_decl, .. }),
|
||||
..
|
||||
}) => {
|
||||
match kind {
|
||||
hir::ClosureKind::CoroutineClosure(_) => {
|
||||
// FIXME(async_closures): Implement this.
|
||||
return None;
|
||||
}
|
||||
hir::ClosureKind::Closure => Some((def_id, fn_decl, true)),
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
_,
|
||||
hir::CoroutineSource::Fn,
|
||||
)) => {
|
||||
let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
|
||||
Node::Item(&hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => (ident, sig, owner_id),
|
||||
Node::TraitItem(&hir::TraitItem {
|
||||
ident,
|
||||
kind: hir::TraitItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => (ident, sig, owner_id),
|
||||
Node::ImplItem(&hir::ImplItem {
|
||||
ident,
|
||||
kind: hir::ImplItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => (ident, sig, owner_id),
|
||||
_ => return None,
|
||||
};
|
||||
Some((owner_id.def_id, sig.decl, ident.name != sym::main))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1774,7 +1774,7 @@ pub(in super::super) fn check_block_with_expected(
|
||||
// that highlight errors inline.
|
||||
let mut sp = blk.span;
|
||||
let mut fn_span = None;
|
||||
if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) {
|
||||
if let Some((fn_def_id, decl, _)) = self.get_fn_decl(blk.hir_id) {
|
||||
let ret_sp = decl.output.span();
|
||||
if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
|
||||
// HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
|
||||
@ -1782,7 +1782,7 @@ pub(in super::super) fn check_block_with_expected(
|
||||
// the span we're aiming at correspond to a `fn` body.
|
||||
if block_sp == blk.span {
|
||||
sp = ret_sp;
|
||||
fn_span = Some(ident.span);
|
||||
fn_span = self.tcx.def_ident_span(fn_def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1897,15 +1897,6 @@ fn parent_item_span(&self, id: HirId) -> Option<Span> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
|
||||
pub(crate) fn get_parent_fn_decl(
|
||||
&self,
|
||||
blk_id: HirId,
|
||||
) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
|
||||
let parent = self.tcx.hir_node_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
|
||||
self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident))
|
||||
}
|
||||
|
||||
/// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail
|
||||
/// expression's `Span`, otherwise return `expr.span`. This is done to give better errors
|
||||
/// when given code like the following:
|
||||
|
@ -800,6 +800,13 @@ pub(in super::super) fn suggest_missing_return_type(
|
||||
can_suggest: bool,
|
||||
fn_id: LocalDefId,
|
||||
) -> bool {
|
||||
// Can't suggest `->` on a block-like coroutine
|
||||
if let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Block)) =
|
||||
self.tcx.coroutine_kind(fn_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
let found =
|
||||
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
|
||||
// Only suggest changing the return type for methods that
|
||||
@ -1909,7 +1916,7 @@ pub(crate) fn suggest_coercing_result_via_try_operator(
|
||||
let returned = matches!(
|
||||
self.tcx.parent_hir_node(expr.hir_id),
|
||||
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
|
||||
) || map.get_return_block(expr.hir_id).is_some();
|
||||
) || map.get_fn_id_for_return_block(expr.hir_id).is_some();
|
||||
if returned
|
||||
&& let ty::Adt(e, args_e) = expected.kind()
|
||||
&& let ty::Adt(f, args_f) = found.kind()
|
||||
|
@ -511,14 +511,14 @@ pub fn is_inside_const_context(self, hir_id: HirId) -> bool {
|
||||
self.body_const_context(self.enclosing_body_owner(hir_id)).is_some()
|
||||
}
|
||||
|
||||
/// Retrieves the `HirId` for `id`'s enclosing method, unless there's a
|
||||
/// `while` or `loop` before reaching it, as block tail returns are not
|
||||
/// available in them.
|
||||
/// Retrieves the `HirId` for `id`'s enclosing function *if* the `id` block or return is
|
||||
/// in the "tail" position of the function, in other words if it's likely to correspond
|
||||
/// to the return type of the function.
|
||||
///
|
||||
/// ```
|
||||
/// fn foo(x: usize) -> bool {
|
||||
/// if x == 1 {
|
||||
/// true // If `get_return_block` gets passed the `id` corresponding
|
||||
/// true // If `get_fn_id_for_return_block` gets passed the `id` corresponding
|
||||
/// } else { // to this, it will return `foo`'s `HirId`.
|
||||
/// false
|
||||
/// }
|
||||
@ -528,12 +528,12 @@ pub fn is_inside_const_context(self, hir_id: HirId) -> bool {
|
||||
/// ```compile_fail,E0308
|
||||
/// fn foo(x: usize) -> bool {
|
||||
/// loop {
|
||||
/// true // If `get_return_block` gets passed the `id` corresponding
|
||||
/// true // If `get_fn_id_for_return_block` gets passed the `id` corresponding
|
||||
/// } // to this, it will return `None`.
|
||||
/// false
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_return_block(self, id: HirId) -> Option<HirId> {
|
||||
pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
|
||||
let mut iter = self.parent_iter(id).peekable();
|
||||
let mut ignore_tail = false;
|
||||
if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(id) {
|
||||
@ -549,7 +549,11 @@ pub fn get_return_block(self, id: HirId) -> Option<HirId> {
|
||||
Node::Block(Block { expr: None, .. }) => return None,
|
||||
// The current node is not the tail expression of its parent.
|
||||
Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None,
|
||||
Node::Block(Block { expr: Some(e), ..}) if matches!(e.kind, ExprKind::If(_, _, None)) => return None,
|
||||
Node::Block(Block { expr: Some(e), .. })
|
||||
if matches!(e.kind, ExprKind::If(_, _, None)) =>
|
||||
{
|
||||
return None;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,9 @@ LL | | }
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:12:9
|
||||
|
|
||||
LL | call(|| -> Option<()> {
|
||||
| ---------- expected `Option<()>` because of return type
|
||||
...
|
||||
LL | true
|
||||
| ^^^^ expected `Option<()>`, found `bool`
|
||||
|
|
||||
|
@ -13,6 +13,9 @@ LL | return "test";
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/closure-return-type-mismatch.rs:12:20
|
||||
|
|
||||
LL | || -> bool {
|
||||
| ---- expected `bool` because of return type
|
||||
LL | if false {
|
||||
LL | return "hello"
|
||||
| ^^^^^^^ expected `bool`, found `&str`
|
||||
|
||||
|
@ -2,7 +2,9 @@ error[E0308]: mismatched types
|
||||
--> $DIR/issue-99914.rs:9:27
|
||||
|
|
||||
LL | t.and_then(|t| -> _ { bar(t) });
|
||||
| ^^^^^^ expected `Result<_, Error>`, found future
|
||||
| - ^^^^^^ expected `Result<_, Error>`, found future
|
||||
| |
|
||||
| expected `Result<_, Error>` because of return type
|
||||
|
|
||||
help: try wrapping the expression in `Ok`
|
||||
|
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
fn main() -> Result<(), ()> {
|
||||
a(|| {
|
||||
//~^ HELP: try adding a return type
|
||||
b()
|
||||
//~^ ERROR: mismatched types [E0308]
|
||||
//~| NOTE: expected `()`, found `i32`
|
||||
|
@ -1,13 +1,20 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/try-operator-dont-suggest-semicolon.rs:6:9
|
||||
--> $DIR/try-operator-dont-suggest-semicolon.rs:7:9
|
||||
|
|
||||
LL | b()
|
||||
| ^^^- help: consider using a semicolon here: `;`
|
||||
| |
|
||||
| expected `()`, found `i32`
|
||||
| ^^^ expected `()`, found `i32`
|
||||
|
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
LL | b();
|
||||
| +
|
||||
help: try adding a return type
|
||||
|
|
||||
LL | a(|| -> i32 {
|
||||
| ++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/try-operator-dont-suggest-semicolon.rs:16:9
|
||||
--> $DIR/try-operator-dont-suggest-semicolon.rs:17:9
|
||||
|
|
||||
LL | / if true {
|
||||
LL | |
|
||||
|
@ -2,7 +2,9 @@ error[E0308]: mismatched types
|
||||
--> $DIR/issue-81943.rs:7:9
|
||||
|
|
||||
LL | f(|x| lib::d!(x));
|
||||
| ^^^^^^^^^^ expected `()`, found `i32`
|
||||
| -^^^^^^^^^^ expected `()`, found `i32`
|
||||
| |
|
||||
| help: try adding a return type: `-> i32`
|
||||
|
|
||||
= note: this error originates in the macro `lib::d` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
@ -10,28 +12,22 @@ error[E0308]: mismatched types
|
||||
--> $DIR/issue-81943.rs:8:28
|
||||
|
|
||||
LL | f(|x| match x { tmp => { g(tmp) } });
|
||||
| -------------------^^^^^^----
|
||||
| | |
|
||||
| | expected `()`, found `i32`
|
||||
| expected this to be `()`
|
||||
| ^^^^^^ expected `()`, found `i32`
|
||||
|
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
LL | f(|x| match x { tmp => { g(tmp); } });
|
||||
| +
|
||||
help: consider using a semicolon here
|
||||
help: try adding a return type
|
||||
|
|
||||
LL | f(|x| match x { tmp => { g(tmp) } };);
|
||||
| +
|
||||
LL | f(|x| -> i32 match x { tmp => { g(tmp) } });
|
||||
| ++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-81943.rs:10:38
|
||||
|
|
||||
LL | ($e:expr) => { match $e { x => { g(x) } } }
|
||||
| ------------------^^^^----
|
||||
| | |
|
||||
| | expected `()`, found `i32`
|
||||
| expected this to be `()`
|
||||
| ^^^^ expected `()`, found `i32`
|
||||
LL | }
|
||||
LL | f(|x| d!(x));
|
||||
| ----- in this macro invocation
|
||||
@ -41,10 +37,10 @@ help: consider using a semicolon here
|
||||
|
|
||||
LL | ($e:expr) => { match $e { x => { g(x); } } }
|
||||
| +
|
||||
help: consider using a semicolon here
|
||||
help: try adding a return type
|
||||
|
|
||||
LL | ($e:expr) => { match $e { x => { g(x) } }; }
|
||||
| +
|
||||
LL | f(|x| -> i32 d!(x));
|
||||
| ++++++
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user