about summary refs log tree commit diff
path: root/src/librustc
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-09-29 20:34:15 +0200
committerGitHub <noreply@github.com>2019-09-29 20:34:15 +0200
commit8109332a4c7a022aaf9d778a59e855c9e91ee9d4 (patch)
tree57cdd16913e74f63e1b998b4b9a582be62fe256d /src/librustc
parentf34e2b1e7cbbc77d1fadcdb613c3db9c79841e5f (diff)
parentc861e24e7251fcbf0cbb8b85c676afe6b901f8af (diff)
downloadrust-8109332a4c7a022aaf9d778a59e855c9e91ee9d4.tar.gz
rust-8109332a4c7a022aaf9d778a59e855c9e91ee9d4.zip
Rollup merge of #64825 - estebank:match-unit, r=Centril
Point at enclosing match when expecting `()` in arm

When encountering code like the following:

```rust
fn main() {
    match 3 {
        4 => 1,
        3 => {
            println!("Yep it maches.");
            2
        }
        _ => 2
    }
    println!("Bye!")
}
```

point at the enclosing `match` expression and suggest ignoring the
returned value:

```
error[E0308]: mismatched types
  --> $DIR/match-needing-semi.rs:8:13
   |
LL | /     match 3 {
LL | |         4 => 1,
LL | |         3 => {
LL | |             2
   | |             ^ expected (), found integer
LL | |         }
LL | |         _ => 2
LL | |     }
   | |     -- help: consider using a semicolon here
   | |_____|
   |       expected this to be `()`
   |
   = note: expected type `()`
              found type `{integer}
```

Fix #40799.
Diffstat (limited to 'src/librustc')
-rw-r--r--src/librustc/hir/lowering/expr.rs23
-rw-r--r--src/librustc/hir/map/mod.rs26
2 files changed, 37 insertions, 12 deletions
diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs
index 2f0a318d536..9dcecedd97c 100644
--- a/src/librustc/hir/lowering/expr.rs
+++ b/src/librustc/hir/lowering/expr.rs
@@ -1037,10 +1037,9 @@ impl LoweringContext<'_> {
     ) -> hir::Expr {
         // expand <head>
         let mut head = self.lower_expr(head);
-        let head_sp = head.span;
         let desugared_span = self.mark_span_with_reason(
             DesugaringKind::ForLoop,
-            head_sp,
+            head.span,
             None,
         );
         head.span = desugared_span;
@@ -1086,21 +1085,21 @@ impl LoweringContext<'_> {
 
         // `match ::std::iter::Iterator::next(&mut iter) { ... }`
         let match_expr = {
-            let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid));
-            let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
+            let iter = P(self.expr_ident(desugared_span, iter, iter_pat_nid));
+            let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter);
             let next_path = &[sym::iter, sym::Iterator, sym::next];
             let next_expr = P(self.expr_call_std_path(
-                head_sp,
+                desugared_span,
                 next_path,
                 hir_vec![ref_mut_iter],
             ));
             let arms = hir_vec![pat_arm, break_arm];
 
-            self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar)
+            self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
         };
-        let match_stmt = self.stmt_expr(head_sp, match_expr);
+        let match_stmt = self.stmt_expr(desugared_span, match_expr);
 
-        let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid));
+        let next_expr = P(self.expr_ident(desugared_span, next_ident, next_pat_hid));
 
         // `let mut __next`
         let next_let = self.stmt_let_pat(
@@ -1115,7 +1114,7 @@ impl LoweringContext<'_> {
         let pat = self.lower_pat(pat);
         let pat_let = self.stmt_let_pat(
             ThinVec::new(),
-            head_sp,
+            desugared_span,
             Some(next_expr),
             pat,
             hir::LocalSource::ForLoopDesugar,
@@ -1152,14 +1151,14 @@ impl LoweringContext<'_> {
             let into_iter_path =
                 &[sym::iter, sym::IntoIterator, sym::into_iter];
             P(self.expr_call_std_path(
-                head_sp,
+                desugared_span,
                 into_iter_path,
                 hir_vec![head],
             ))
         };
 
         let match_expr = P(self.expr_match(
-            head_sp,
+            desugared_span,
             into_iter_expr,
             hir_vec![iter_arm],
             hir::MatchSource::ForLoopDesugar,
@@ -1171,7 +1170,7 @@ impl LoweringContext<'_> {
         // surrounding scope of the `match` since the `match` is not a terminating scope.
         //
         // Also, add the attributes to the outer returned expr node.
-        self.expr_drop_temps(head_sp, match_expr, e.attrs.clone())
+        self.expr_drop_temps(desugared_span, match_expr, e.attrs.clone())
     }
 
     /// Desugar `ExprKind::Try` from: `<expr>?` into:
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 42a4a9909f8..a1011697ef1 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -818,6 +818,32 @@ impl<'hir> Map<'hir> {
         CRATE_HIR_ID
     }
 
+    /// When on a match arm tail expression or on a match arm, give back the enclosing `match`
+    /// expression.
+    ///
+    /// Used by error reporting when there's a type error in a match arm caused by the `match`
+    /// expression needing to be unit.
+    pub fn get_match_if_cause(&self, hir_id: HirId) -> Option<&Expr> {
+        for (_, node) in ParentHirIterator::new(hir_id, &self) {
+            match node {
+                Node::Item(_) |
+                Node::ForeignItem(_) |
+                Node::TraitItem(_) |
+                Node::ImplItem(_) => break,
+                Node::Expr(expr) => match expr.kind {
+                    ExprKind::Match(_, _, _) => return Some(expr),
+                    _ => {}
+                },
+                Node::Stmt(stmt) => match stmt.kind {
+                    StmtKind::Local(_) => break,
+                    _ => {}
+                }
+                _ => {}
+            }
+        }
+        None
+    }
+
     /// Returns the nearest enclosing scope. A scope is roughly an item or block.
     pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option<HirId> {
         for (hir_id, node) in ParentHirIterator::new(hir_id, &self) {