Skip to content

Commit ad9068f

Browse files
committed
Auto merge of #57230 - estebank:return-mismatch, r=varkor
Modify mismatched type error for functions with no return Fix #50009. ``` error[E0308]: mismatched types --> $DIR/coercion-missing-tail-expected-type.rs:3:24 | LL | fn plus_one(x: i32) -> i32 { //~ ERROR mismatched types | -------- ^^^ expected i32, found () | | | this function's body doesn't return LL | x + 1; | - help: consider removing this semicolon | = note: expected type `i32` found type `()` ``` instead of ``` error[E0308]: mismatched types --> $DIR/coercion-missing-tail-expected-type.rs:3:28 | LL | fn plus_one(x: i32) -> i32 { //~ ERROR mismatched types | ____________________________^ LL | | x + 1; | | - help: consider removing this semicolon LL | | } | |_^ expected i32, found () | = note: expected type `i32` found type `()` ```
2 parents 68fe518 + 211365d commit ad9068f

14 files changed

+199
-156
lines changed

src/librustc/hir/map/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,7 @@ impl<'hir> Map<'hir> {
667667
Node::Item(_) |
668668
Node::ForeignItem(_) |
669669
Node::TraitItem(_) |
670+
Node::Expr(Expr { node: ExprKind::Closure(..), ..}) |
670671
Node::ImplItem(_) => true,
671672
_ => false,
672673
}
@@ -675,7 +676,7 @@ impl<'hir> Map<'hir> {
675676
match *node {
676677
Node::Expr(ref expr) => {
677678
match expr.node {
678-
ExprKind::While(..) | ExprKind::Loop(..) => true,
679+
ExprKind::While(..) | ExprKind::Loop(..) | ExprKind::Ret(..) => true,
679680
_ => false,
680681
}
681682
}

src/librustc_typeck/check/mod.rs

+85-43
Original file line numberDiff line numberDiff line change
@@ -4843,11 +4843,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
48434843
// #41425 -- label the implicit `()` as being the
48444844
// "found type" here, rather than the "expected type".
48454845
if !self.diverges.get().always() {
4846-
coerce.coerce_forced_unit(self, &self.misc(blk.span), &mut |err| {
4846+
// #50009 -- Do not point at the entire fn block span, point at the return type
4847+
// span, as it is the cause of the requirement, and
4848+
// `consider_hint_about_removing_semicolon` will point at the last expression
4849+
// if it were a relevant part of the error. This improves usability in editors
4850+
// that highlight errors inline.
4851+
let mut sp = blk.span;
4852+
let mut fn_span = None;
4853+
if let Some((decl, ident)) = self.get_parent_fn_decl(blk.id) {
4854+
let ret_sp = decl.output.span();
4855+
if let Some(block_sp) = self.parent_item_span(blk.id) {
4856+
// HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
4857+
// output would otherwise be incorrect and even misleading. Make sure
4858+
// the span we're aiming at correspond to a `fn` body.
4859+
if block_sp == blk.span {
4860+
sp = ret_sp;
4861+
fn_span = Some(ident.span);
4862+
}
4863+
}
4864+
}
4865+
coerce.coerce_forced_unit(self, &self.misc(sp), &mut |err| {
48474866
if let Some(expected_ty) = expected.only_has_type(self) {
4848-
self.consider_hint_about_removing_semicolon(blk,
4849-
expected_ty,
4850-
err);
4867+
self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
4868+
}
4869+
if let Some(fn_span) = fn_span {
4870+
err.span_label(fn_span, "this function's body doesn't return");
48514871
}
48524872
}, false);
48534873
}
@@ -4872,59 +4892,81 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
48724892
ty
48734893
}
48744894

4875-
/// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
4876-
/// suggestion can be made, `None` otherwise.
4877-
pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> {
4878-
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
4879-
// `while` before reaching it, as block tail returns are not available in them.
4880-
if let Some(fn_id) = self.tcx.hir().get_return_block(blk_id) {
4881-
let parent = self.tcx.hir().get(fn_id);
4895+
fn parent_item_span(&self, id: ast::NodeId) -> Option<Span> {
4896+
let node = self.tcx.hir().get(self.tcx.hir().get_parent(id));
4897+
match node {
4898+
Node::Item(&hir::Item {
4899+
node: hir::ItemKind::Fn(_, _, _, body_id), ..
4900+
}) |
4901+
Node::ImplItem(&hir::ImplItem {
4902+
node: hir::ImplItemKind::Method(_, body_id), ..
4903+
}) => {
4904+
let body = self.tcx.hir().body(body_id);
4905+
if let ExprKind::Block(block, _) = &body.value.node {
4906+
return Some(block.span);
4907+
}
4908+
}
4909+
_ => {}
4910+
}
4911+
None
4912+
}
48824913

4883-
if let Node::Item(&hir::Item {
4914+
/// Given a function block's `NodeId`, return its `FnDecl` if it exists, or `None` otherwise.
4915+
fn get_parent_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, ast::Ident)> {
4916+
let parent = self.tcx.hir().get(self.tcx.hir().get_parent(blk_id));
4917+
self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
4918+
}
4919+
4920+
/// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
4921+
fn get_node_fn_decl(&self, node: Node) -> Option<(hir::FnDecl, ast::Ident, bool)> {
4922+
match node {
4923+
Node::Item(&hir::Item {
48844924
ident, node: hir::ItemKind::Fn(ref decl, ..), ..
4885-
}) = parent {
4886-
decl.clone().and_then(|decl| {
4887-
// This is less than ideal, it will not suggest a return type span on any
4888-
// method called `main`, regardless of whether it is actually the entry point,
4889-
// but it will still present it as the reason for the expected type.
4890-
Some((decl, ident.name != Symbol::intern("main")))
4891-
})
4892-
} else if let Node::TraitItem(&hir::TraitItem {
4893-
node: hir::TraitItemKind::Method(hir::MethodSig {
4925+
}) => decl.clone().and_then(|decl| {
4926+
// This is less than ideal, it will not suggest a return type span on any
4927+
// method called `main`, regardless of whether it is actually the entry point,
4928+
// but it will still present it as the reason for the expected type.
4929+
Some((decl, ident, ident.name != Symbol::intern("main")))
4930+
}),
4931+
Node::TraitItem(&hir::TraitItem {
4932+
ident, node: hir::TraitItemKind::Method(hir::MethodSig {
48944933
ref decl, ..
48954934
}, ..), ..
4896-
}) = parent {
4897-
decl.clone().and_then(|decl| {
4898-
Some((decl, true))
4899-
})
4900-
} else if let Node::ImplItem(&hir::ImplItem {
4901-
node: hir::ImplItemKind::Method(hir::MethodSig {
4935+
}) => decl.clone().and_then(|decl| Some((decl, ident, true))),
4936+
Node::ImplItem(&hir::ImplItem {
4937+
ident, node: hir::ImplItemKind::Method(hir::MethodSig {
49024938
ref decl, ..
49034939
}, ..), ..
4904-
}) = parent {
4905-
decl.clone().and_then(|decl| {
4906-
Some((decl, false))
4907-
})
4908-
} else {
4909-
None
4910-
}
4911-
} else {
4912-
None
4940+
}) => decl.clone().and_then(|decl| Some((decl, ident, false))),
4941+
_ => None,
49134942
}
49144943
}
49154944

4945+
/// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
4946+
/// suggestion can be made, `None` otherwise.
4947+
pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> {
4948+
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
4949+
// `while` before reaching it, as block tail returns are not available in them.
4950+
self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
4951+
let parent = self.tcx.hir().get(blk_id);
4952+
self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
4953+
})
4954+
}
4955+
49164956
/// On implicit return expressions with mismatched types, provide the following suggestions:
49174957
///
49184958
/// - Point out the method's return type as the reason for the expected type
49194959
/// - Possible missing semicolon
49204960
/// - Possible missing return type if the return type is the default, and not `fn main()`
4921-
pub fn suggest_mismatched_types_on_tail(&self,
4922-
err: &mut DiagnosticBuilder<'tcx>,
4923-
expression: &'gcx hir::Expr,
4924-
expected: Ty<'tcx>,
4925-
found: Ty<'tcx>,
4926-
cause_span: Span,
4927-
blk_id: ast::NodeId) {
4961+
pub fn suggest_mismatched_types_on_tail(
4962+
&self,
4963+
err: &mut DiagnosticBuilder<'tcx>,
4964+
expression: &'gcx hir::Expr,
4965+
expected: Ty<'tcx>,
4966+
found: Ty<'tcx>,
4967+
cause_span: Span,
4968+
blk_id: ast::NodeId,
4969+
) {
49284970
self.suggest_missing_semicolon(err, expression, expected, cause_span);
49294971
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
49304972
self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);

src/test/ui/block-result/consider-removing-last-semi.stderr

+16-16
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
error[E0308]: mismatched types
2-
--> $DIR/consider-removing-last-semi.rs:1:18
2+
--> $DIR/consider-removing-last-semi.rs:1:11
33
|
4-
LL | fn f() -> String { //~ ERROR mismatched types
5-
| __________________^
6-
LL | | 0u8;
7-
LL | | "bla".to_string();
8-
| | - help: consider removing this semicolon
9-
LL | | }
10-
| |_^ expected struct `std::string::String`, found ()
4+
LL | fn f() -> String { //~ ERROR mismatched types
5+
| - ^^^^^^ expected struct `std::string::String`, found ()
6+
| |
7+
| this function's body doesn't return
8+
LL | 0u8;
9+
LL | "bla".to_string();
10+
| - help: consider removing this semicolon
1111
|
1212
= note: expected type `std::string::String`
1313
found type `()`
1414

1515
error[E0308]: mismatched types
16-
--> $DIR/consider-removing-last-semi.rs:6:18
16+
--> $DIR/consider-removing-last-semi.rs:6:11
1717
|
18-
LL | fn g() -> String { //~ ERROR mismatched types
19-
| __________________^
20-
LL | | "this won't work".to_string();
21-
LL | | "removeme".to_string();
22-
| | - help: consider removing this semicolon
23-
LL | | }
24-
| |_^ expected struct `std::string::String`, found ()
18+
LL | fn g() -> String { //~ ERROR mismatched types
19+
| - ^^^^^^ expected struct `std::string::String`, found ()
20+
| |
21+
| this function's body doesn't return
22+
LL | "this won't work".to_string();
23+
LL | "removeme".to_string();
24+
| - help: consider removing this semicolon
2525
|
2626
= note: expected type `std::string::String`
2727
found type `()`

src/test/ui/block-result/issue-11714.stderr

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
error[E0308]: mismatched types
2-
--> $DIR/issue-11714.rs:1:18
2+
--> $DIR/issue-11714.rs:1:14
33
|
4-
LL | fn blah() -> i32 { //~ ERROR mismatched types
5-
| __________________^
6-
LL | | 1
7-
LL | |
8-
LL | | ;
9-
| | - help: consider removing this semicolon
10-
LL | | }
11-
| |_^ expected i32, found ()
4+
LL | fn blah() -> i32 { //~ ERROR mismatched types
5+
| ---- ^^^ expected i32, found ()
6+
| |
7+
| this function's body doesn't return
8+
...
9+
LL | ;
10+
| - help: consider removing this semicolon
1211
|
1312
= note: expected type `i32`
1413
found type `()`

src/test/ui/block-result/issue-13428.stderr

+16-19
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,27 @@
11
error[E0308]: mismatched types
2-
--> $DIR/issue-13428.rs:3:20
2+
--> $DIR/issue-13428.rs:3:13
33
|
4-
LL | fn foo() -> String { //~ ERROR mismatched types
5-
| ____________________^
6-
LL | | format!("Hello {}",
7-
LL | | "world")
8-
LL | | // Put the trailing semicolon on its own line to test that the
9-
LL | | // note message gets the offending semicolon exactly
10-
LL | | ;
11-
| | - help: consider removing this semicolon
12-
LL | | }
13-
| |_^ expected struct `std::string::String`, found ()
4+
LL | fn foo() -> String { //~ ERROR mismatched types
5+
| --- ^^^^^^ expected struct `std::string::String`, found ()
6+
| |
7+
| this function's body doesn't return
8+
...
9+
LL | ;
10+
| - help: consider removing this semicolon
1411
|
1512
= note: expected type `std::string::String`
1613
found type `()`
1714

1815
error[E0308]: mismatched types
19-
--> $DIR/issue-13428.rs:11:20
16+
--> $DIR/issue-13428.rs:11:13
2017
|
21-
LL | fn bar() -> String { //~ ERROR mismatched types
22-
| ____________________^
23-
LL | | "foobar".to_string()
24-
LL | | ;
25-
| | - help: consider removing this semicolon
26-
LL | | }
27-
| |_^ expected struct `std::string::String`, found ()
18+
LL | fn bar() -> String { //~ ERROR mismatched types
19+
| --- ^^^^^^ expected struct `std::string::String`, found ()
20+
| |
21+
| this function's body doesn't return
22+
LL | "foobar".to_string()
23+
LL | ;
24+
| - help: consider removing this semicolon
2825
|
2926
= note: expected type `std::string::String`
3027
found type `()`

src/test/ui/coercion/coercion-missing-tail-expected-type.stderr

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
error[E0308]: mismatched types
2-
--> $DIR/coercion-missing-tail-expected-type.rs:3:28
2+
--> $DIR/coercion-missing-tail-expected-type.rs:3:24
33
|
4-
LL | fn plus_one(x: i32) -> i32 { //~ ERROR mismatched types
5-
| ____________________________^
6-
LL | | x + 1;
7-
| | - help: consider removing this semicolon
8-
LL | | }
9-
| |_^ expected i32, found ()
4+
LL | fn plus_one(x: i32) -> i32 { //~ ERROR mismatched types
5+
| -------- ^^^ expected i32, found ()
6+
| |
7+
| this function's body doesn't return
8+
LL | x + 1;
9+
| - help: consider removing this semicolon
1010
|
1111
= note: expected type `i32`
1212
found type `()`
1313

1414
error[E0308]: mismatched types
15-
--> $DIR/coercion-missing-tail-expected-type.rs:7:29
15+
--> $DIR/coercion-missing-tail-expected-type.rs:7:13
1616
|
17-
LL | fn foo() -> Result<u8, u64> { //~ ERROR mismatched types
18-
| _____________________________^
19-
LL | | Ok(1);
20-
| | - help: consider removing this semicolon
21-
LL | | }
22-
| |_^ expected enum `std::result::Result`, found ()
17+
LL | fn foo() -> Result<u8, u64> { //~ ERROR mismatched types
18+
| --- ^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found ()
19+
| |
20+
| this function's body doesn't return
21+
LL | Ok(1);
22+
| - help: consider removing this semicolon
2323
|
2424
= note: expected type `std::result::Result<u8, u64>`
2525
found type `()`

src/test/ui/issues/issue-32323.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
error[E0308]: mismatched types
2-
--> $DIR/issue-32323.rs:5:49
2+
--> $DIR/issue-32323.rs:5:30
33
|
44
LL | pub fn f<'a, T: Tr<'a>>() -> <T as Tr<'a>>::Out {}
5-
| ^^ expected associated type, found ()
5+
| - ^^^^^^^^^^^^^^^^^^ expected associated type, found ()
6+
| |
7+
| this function's body doesn't return
68
|
79
= note: expected type `<T as Tr<'a>>::Out`
810
found type `()`

src/test/ui/issues/issue-43162.stderr

+8-8
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ LL | break {}; //~ ERROR E0268
1111
| ^^^^^^^^ cannot break outside of a loop
1212

1313
error[E0308]: mismatched types
14-
--> $DIR/issue-43162.rs:1:18
14+
--> $DIR/issue-43162.rs:1:13
1515
|
16-
LL | fn foo() -> bool {
17-
| __________________^
18-
LL | | //~^ ERROR E0308
19-
LL | | break true; //~ ERROR E0268
20-
| | - help: consider removing this semicolon
21-
LL | | }
22-
| |_^ expected bool, found ()
16+
LL | fn foo() -> bool {
17+
| --- ^^^^ expected bool, found ()
18+
| |
19+
| this function's body doesn't return
20+
LL | //~^ ERROR E0308
21+
LL | break true; //~ ERROR E0268
22+
| - help: consider removing this semicolon
2323
|
2424
= note: expected type `bool`
2525
found type `()`

src/test/ui/issues/issue-44023.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
error[E0308]: mismatched types
2-
--> $DIR/issue-44023.rs:5:42
2+
--> $DIR/issue-44023.rs:5:36
33
|
4-
LL | fn საჭმელად_გემრიელი_სადილი ( ) -> isize { //~ ERROR mismatched types
5-
| __________________________________________^
6-
LL | | }
7-
| |_^ expected isize, found ()
4+
LL | fn საჭმელად_გემრიელი_სადილი ( ) -> isize { //~ ERROR mismatched types
5+
| ------------------------ ^^^^^ expected isize, found ()
6+
| |
7+
| this function's body doesn't return
88
|
99
= note: expected type `isize`
1010
found type `()`

0 commit comments

Comments
 (0)