Skip to content

Commit 46a38dc

Browse files
committed
Account for tail expressions when pointing at return type
When there's a type mismatch we make an effort to check if it was caused by a function's return type. This logic now makes sure to only point at the return type if the error happens in a tail expression.
1 parent faee8e1 commit 46a38dc

File tree

4 files changed

+31
-7
lines changed

4 files changed

+31
-7
lines changed

src/librustc/hir/map/mod.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,28 @@ impl<'hir> Map<'hir> {
741741
/// }
742742
/// ```
743743
pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
744-
for (hir_id, node) in ParentHirIterator::new(id, &self) {
744+
let mut iter = ParentHirIterator::new(id, &self).peekable();
745+
let mut ignore_tail = false;
746+
if let Some(entry) = self.find_entry(id) {
747+
if let Node::Expr(Expr { node: ExprKind::Ret(_), .. }) = entry.node {
748+
// When dealing with `return` statements, we don't care about climbing only tail
749+
// expressions.
750+
ignore_tail = true;
751+
}
752+
}
753+
while let Some((hir_id, node)) = iter.next() {
754+
if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
755+
match next_node {
756+
Node::Block(Block { expr: None, .. }) => return None,
757+
Node::Block(Block { expr: Some(expr), .. }) => {
758+
if hir_id != expr.hir_id {
759+
// The current node is not the tail expression of its parent.
760+
return None;
761+
}
762+
}
763+
_ => {}
764+
}
765+
}
745766
match node {
746767
Node::Item(_) |
747768
Node::ForeignItem(_) |
@@ -750,10 +771,12 @@ impl<'hir> Map<'hir> {
750771
Node::ImplItem(_) => return Some(hir_id),
751772
Node::Expr(ref expr) => {
752773
match expr.kind {
774+
// Ignore `return`s on the first iteration
753775
ExprKind::Loop(..) | ExprKind::Ret(..) => return None,
754776
_ => {}
755777
}
756778
}
779+
Node::Local(_) => return None,
757780
_ => {}
758781
}
759782
}

src/librustc/hir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1563,7 +1563,7 @@ pub enum ExprKind {
15631563
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
15641564
/// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
15651565
MethodCall(P<PathSegment>, Span, HirVec<Expr>),
1566-
/// A tuple (e.g., `(a, b, c ,d)`).
1566+
/// A tuple (e.g., `(a, b, c, d)`).
15671567
Tup(HirVec<Expr>),
15681568
/// A binary operation (e.g., `a + b`, `a * b`).
15691569
Binary(BinOp, P<Expr>, P<Expr>),

src/librustc_typeck/check/expr.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -620,8 +620,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
620620
expr: &'tcx hir::Expr
621621
) -> Ty<'tcx> {
622622
if self.ret_coercion.is_none() {
623-
struct_span_err!(self.tcx.sess, expr.span, E0572,
624-
"return statement outside of function body").emit();
623+
struct_span_err!(
624+
self.tcx.sess,
625+
expr.span,
626+
E0572,
627+
"return statement outside of function body",
628+
).emit();
625629
} else if let Some(ref e) = expr_opt {
626630
if self.ret_coercion_span.borrow().is_none() {
627631
*self.ret_coercion_span.borrow_mut() = Some(e.span);

src/test/ui/struct-literal-variant-in-if.stderr

-3
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ LL | if x == E::V { field } {}
4949
error[E0308]: mismatched types
5050
--> $DIR/struct-literal-variant-in-if.rs:10:20
5151
|
52-
LL | fn test_E(x: E) {
53-
| - help: try adding a return type: `-> bool`
54-
LL | let field = true;
5552
LL | if x == E::V { field } {}
5653
| ^^^^^ expected (), found bool
5754
|

0 commit comments

Comments
 (0)