]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #83489 - LeSeulArtichaut:deref-else, r=davidtwco
authorYuki Okushi <jtitor@2k36.org>
Mon, 5 Apr 2021 21:24:09 +0000 (06:24 +0900)
committerGitHub <noreply@github.com>
Mon, 5 Apr 2021 21:24:09 +0000 (06:24 +0900)
Properly suggest deref in else block

Continues #79755, fixes #79736
r? `@davidtwco`

compiler/rustc_typeck/src/check/demand.rs
src/test/ui/deref-suggestion.rs
src/test/ui/deref-suggestion.stderr

index f9f67769e96a41d475960d1493492354c9626eeb..d879b6e97dcfb884098a9915144e3167bd50c90b 100644 (file)
@@ -366,6 +366,29 @@ fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, St
         false
     }
 
+    /// If the given `HirId` corresponds to a block with a trailing expression, return that expression
+    crate fn maybe_get_block_expr(&self, hir_id: hir::HirId) -> Option<&'tcx hir::Expr<'tcx>> {
+        match self.tcx.hir().find(hir_id)? {
+            Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, ..), .. }) => block.expr,
+            _ => None,
+        }
+    }
+
+    /// Returns whether the given expression is an `else if`.
+    crate fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
+        if let hir::ExprKind::If(..) = expr.kind {
+            let parent_id = self.tcx.hir().get_parent_node(expr.hir_id);
+            if let Some(Node::Expr(hir::Expr {
+                kind: hir::ExprKind::If(_, _, Some(else_expr)),
+                ..
+            })) = self.tcx.hir().find(parent_id)
+            {
+                return else_expr.hir_id == expr.hir_id;
+            }
+        }
+        false
+    }
+
     /// This function is used to determine potential "simple" improvements or users' errors and
     /// provide them useful help. For example:
     ///
@@ -652,6 +675,11 @@ pub fn check_ref(
                                 };
                                 let suggestion = if is_struct_pat_shorthand_field {
                                     format!("{}: *{}", code, code)
+                                } else if self.is_else_if_block(expr) {
+                                    // Don't suggest nonsense like `else *if`
+                                    return None;
+                                } else if let Some(expr) = self.maybe_get_block_expr(expr.hir_id) {
+                                    format!("*{}", sm.span_to_snippet(expr.span).unwrap_or(code))
                                 } else {
                                     format!("*{}", code)
                                 };
index 580410aecf4f8b0180cd796ac14a4c43db952926..4fd695585ba06d8190a0b28c008842412d12b123 100644 (file)
@@ -45,4 +45,30 @@ fn main() {
     //~^ ERROR mismatched types
     let r = R { i: i };
     //~^ ERROR mismatched types
+
+
+    let a = &1;
+    let b = &2;
+    let val: i32 = if true {
+        a + 1
+    } else {
+        b
+        //~^ ERROR mismatched types
+    };
+    let val: i32 = if true {
+        let _ = 2;
+        a + 1
+    } else {
+        let _ = 2;
+        b
+        //~^ ERROR mismatched types
+    };
+    let val = if true {
+        *a
+    } else if true {
+    //~^ ERROR incompatible types
+        b
+    } else {
+        &0
+    };
 }
index f59f05db9c047b853dcbf571a12ee34c302c1f2d..632a279d79623b92d8bd87c3cc50c707e08991ea 100644 (file)
@@ -89,6 +89,43 @@ LL |     let r = R { i: i };
    |                    expected `u32`, found `&{integer}`
    |                    help: consider dereferencing the borrow: `*i`
 
-error: aborting due to 10 previous errors
+error[E0308]: mismatched types
+  --> $DIR/deref-suggestion.rs:55:9
+   |
+LL |         b
+   |         ^
+   |         |
+   |         expected `i32`, found `&{integer}`
+   |         help: consider dereferencing the borrow: `*b`
+
+error[E0308]: mismatched types
+  --> $DIR/deref-suggestion.rs:63:9
+   |
+LL |         b
+   |         ^
+   |         |
+   |         expected `i32`, found `&{integer}`
+   |         help: consider dereferencing the borrow: `*b`
+
+error[E0308]: `if` and `else` have incompatible types
+  --> $DIR/deref-suggestion.rs:68:12
+   |
+LL |        let val = if true {
+   |   _______________-
+LL |  |         *a
+   |  |         -- expected because of this
+LL |  |     } else if true {
+   |  |____________^
+LL | ||
+LL | ||         b
+LL | ||     } else {
+LL | ||         &0
+LL | ||     };
+   | ||     ^
+   | ||_____|
+   | |______`if` and `else` have incompatible types
+   |        expected `i32`, found `&{integer}`
+
+error: aborting due to 13 previous errors
 
 For more information about this error, try `rustc --explain E0308`.