Skip to content

Commit ab86cec

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 5122091 commit ab86cec

File tree

4 files changed

+32
-8
lines changed

4 files changed

+32
-8
lines changed

src/librustc/hir/map/mod.rs

+25-2
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,28 @@ impl<'hir> Map<'hir> {
743743
/// }
744744
/// ```
745745
pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
746-
for (hir_id, node) in ParentHirIterator::new(id, &self) {
746+
let mut iter = ParentHirIterator::new(id, &self).peekable();
747+
let mut ignore_tail = false;
748+
if let Some(entry) = self.find_entry(id) {
749+
if let Node::Expr(Expr { node: ExprKind::Ret(_), .. }) = entry.node {
750+
// When dealing with `return` statements, we don't care about climbing only tail
751+
// expressions.
752+
ignore_tail = true;
753+
}
754+
}
755+
while let Some((hir_id, node)) = iter.next() {
756+
if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
757+
match next_node {
758+
Node::Block(Block { expr: None, .. }) => return None,
759+
Node::Block(Block { expr: Some(expr), .. }) => {
760+
if hir_id != expr.hir_id {
761+
// The current node is not the tail expression of its parent.
762+
return None;
763+
}
764+
}
765+
_ => {}
766+
}
767+
}
747768
match node {
748769
Node::Item(_) |
749770
Node::ForeignItem(_) |
@@ -752,10 +773,12 @@ impl<'hir> Map<'hir> {
752773
Node::ImplItem(_) => return Some(hir_id),
753774
Node::Expr(ref expr) => {
754775
match expr.node {
755-
ExprKind::Loop(..) | ExprKind::Ret(..) => return None,
776+
// Ignore `return`s on the first iteration
777+
ExprKind::Ret(..) | ExprKind::Loop(..) => return None,
756778
_ => {}
757779
}
758780
}
781+
Node::Local(_) => return None,
759782
_ => {}
760783
}
761784
}

src/librustc/hir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1535,7 +1535,7 @@ pub enum ExprKind {
15351535
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
15361536
/// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
15371537
MethodCall(P<PathSegment>, Span, HirVec<Expr>),
1538-
/// A tuple (e.g., `(a, b, c ,d)`).
1538+
/// A tuple (e.g., `(a, b, c, d)`).
15391539
Tup(HirVec<Expr>),
15401540
/// A binary operation (e.g., `a + b`, `a * b`).
15411541
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)