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.
This commit is contained in:
parent
faee8e1756
commit
46a38dc183
@ -741,7 +741,28 @@ pub fn is_hir_id_module(&self, hir_id: HirId) -> bool {
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
|
||||
for (hir_id, node) in ParentHirIterator::new(id, &self) {
|
||||
let mut iter = ParentHirIterator::new(id, &self).peekable();
|
||||
let mut ignore_tail = false;
|
||||
if let Some(entry) = self.find_entry(id) {
|
||||
if let Node::Expr(Expr { node: ExprKind::Ret(_), .. }) = entry.node {
|
||||
// When dealing with `return` statements, we don't care about climbing only tail
|
||||
// expressions.
|
||||
ignore_tail = true;
|
||||
}
|
||||
}
|
||||
while let Some((hir_id, node)) = iter.next() {
|
||||
if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
|
||||
match next_node {
|
||||
Node::Block(Block { expr: None, .. }) => return None,
|
||||
Node::Block(Block { expr: Some(expr), .. }) => {
|
||||
if hir_id != expr.hir_id {
|
||||
// The current node is not the tail expression of its parent.
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
match node {
|
||||
Node::Item(_) |
|
||||
Node::ForeignItem(_) |
|
||||
@ -750,10 +771,12 @@ pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
|
||||
Node::ImplItem(_) => return Some(hir_id),
|
||||
Node::Expr(ref expr) => {
|
||||
match expr.kind {
|
||||
// Ignore `return`s on the first iteration
|
||||
ExprKind::Loop(..) | ExprKind::Ret(..) => return None,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Node::Local(_) => return None,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -1563,7 +1563,7 @@ pub enum ExprKind {
|
||||
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
|
||||
/// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
|
||||
MethodCall(P<PathSegment>, Span, HirVec<Expr>),
|
||||
/// A tuple (e.g., `(a, b, c ,d)`).
|
||||
/// A tuple (e.g., `(a, b, c, d)`).
|
||||
Tup(HirVec<Expr>),
|
||||
/// A binary operation (e.g., `a + b`, `a * b`).
|
||||
Binary(BinOp, P<Expr>, P<Expr>),
|
||||
|
@ -620,8 +620,12 @@ fn check_expr_return(
|
||||
expr: &'tcx hir::Expr
|
||||
) -> Ty<'tcx> {
|
||||
if self.ret_coercion.is_none() {
|
||||
struct_span_err!(self.tcx.sess, expr.span, E0572,
|
||||
"return statement outside of function body").emit();
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
expr.span,
|
||||
E0572,
|
||||
"return statement outside of function body",
|
||||
).emit();
|
||||
} else if let Some(ref e) = expr_opt {
|
||||
if self.ret_coercion_span.borrow().is_none() {
|
||||
*self.ret_coercion_span.borrow_mut() = Some(e.span);
|
||||
|
@ -49,9 +49,6 @@ LL | if x == E::V { field } {}
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/struct-literal-variant-in-if.rs:10:20
|
||||
|
|
||||
LL | fn test_E(x: E) {
|
||||
| - help: try adding a return type: `-> bool`
|
||||
LL | let field = true;
|
||||
LL | if x == E::V { field } {}
|
||||
| ^^^^^ expected (), found bool
|
||||
|
|
||||
|
Loading…
Reference in New Issue
Block a user