about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2020-09-19 11:47:50 +0200
committerGitHub <noreply@github.com>2020-09-19 11:47:50 +0200
commit5631b5d6843164a776b939cf8ebac7b8ea5e582a (patch)
tree36ae6ef035549d8c7323180df74a0f7013d2ab7d
parent8a7cb1eac1764da047196f7e3572fb12ca1a22d4 (diff)
parent230355f25f10306211a80040bec1561545715383 (diff)
downloadrust-5631b5d6843164a776b939cf8ebac7b8ea5e582a.tar.gz
rust-5631b5d6843164a776b939cf8ebac7b8ea5e582a.zip
Rollup merge of #76749 - guswynn:hir_ranges, r=estebank
give *even better* suggestion when matching a const range

notice that the err already has "constant defined here"
so this is now *exceedingly clear*

extension to #76222

r? @estebank
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs55
-rw-r--r--src/test/ui/issues/issue-76191.rs5
-rw-r--r--src/test/ui/issues/issue-76191.stderr26
3 files changed, 75 insertions, 11 deletions
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 54b0671fab5..321472b8fe8 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -1,5 +1,6 @@
 use crate::check::FnCtxt;
 use rustc_ast as ast;
+
 use rustc_ast::util::lev_distance::find_best_match_for_name;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
@@ -740,6 +741,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         pat_ty
     }
 
+    fn maybe_suggest_range_literal(
+        &self,
+        e: &mut DiagnosticBuilder<'_>,
+        opt_def_id: Option<hir::def_id::DefId>,
+        ident: Ident,
+    ) -> bool {
+        match opt_def_id {
+            Some(def_id) => match self.tcx.hir().get_if_local(def_id) {
+                Some(hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Const(_, body_id), ..
+                })) => match self.tcx.hir().get(body_id.hir_id) {
+                    hir::Node::Expr(expr) => {
+                        if hir::is_range_literal(expr) {
+                            let span = self.tcx.hir().span(body_id.hir_id);
+                            if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
+                                e.span_suggestion_verbose(
+                                    ident.span,
+                                    "you may want to move the range into the match block",
+                                    snip,
+                                    Applicability::MachineApplicable,
+                                );
+                                return true;
+                            }
+                        }
+                    }
+                    _ => (),
+                },
+                _ => (),
+            },
+            _ => (),
+        }
+        false
+    }
+
     fn emit_bad_pat_path(
         &self,
         mut e: DiagnosticBuilder<'_>,
@@ -772,12 +807,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         );
                     }
                     _ => {
-                        let const_def_id = match pat_ty.kind() {
+                        let (type_def_id, item_def_id) = match pat_ty.kind() {
                             Adt(def, _) => match res {
-                                Res::Def(DefKind::Const, _) => Some(def.did),
-                                _ => None,
+                                Res::Def(DefKind::Const, def_id) => (Some(def.did), Some(def_id)),
+                                _ => (None, None),
                             },
-                            _ => None,
+                            _ => (None, None),
                         };
 
                         let ranges = &[
@@ -788,11 +823,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             self.tcx.lang_items().range_inclusive_struct(),
                             self.tcx.lang_items().range_to_inclusive_struct(),
                         ];
-                        if const_def_id != None && ranges.contains(&const_def_id) {
-                            let msg = "constants only support matching by type, \
-                                if you meant to match against a range of values, \
-                                consider using a range pattern like `min ..= max` in the match block";
-                            e.note(msg);
+                        if type_def_id != None && ranges.contains(&type_def_id) {
+                            if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
+                                let msg = "constants only support matching by type, \
+                                    if you meant to match against a range of values, \
+                                    consider using a range pattern like `min ..= max` in the match block";
+                                e.note(msg);
+                            }
                         } else {
                             let msg = "introduce a new binding instead";
                             let sugg = format!("other_{}", ident.as_str().to_lowercase());
diff --git a/src/test/ui/issues/issue-76191.rs b/src/test/ui/issues/issue-76191.rs
index bc327123c6f..d9790d2b56e 100644
--- a/src/test/ui/issues/issue-76191.rs
+++ b/src/test/ui/issues/issue-76191.rs
@@ -2,13 +2,18 @@
 #![allow(non_snake_case)]
 
 use std::ops::RangeInclusive;
+
 const RANGE: RangeInclusive<i32> = 0..=255;
 
+const RANGE2: RangeInclusive<i32> = panic!();
+
 fn main() {
     let n: i32 = 1;
     match n {
         RANGE => {}
         //~^ ERROR mismatched types
+        RANGE2 => {}
+        //~^ ERROR mismatched types
         _ => {}
     }
 }
diff --git a/src/test/ui/issues/issue-76191.stderr b/src/test/ui/issues/issue-76191.stderr
index a5544d9e9da..bdcd2fe1adc 100644
--- a/src/test/ui/issues/issue-76191.stderr
+++ b/src/test/ui/issues/issue-76191.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/issue-76191.rs:10:9
+  --> $DIR/issue-76191.rs:13:9
    |
 LL | const RANGE: RangeInclusive<i32> = 0..=255;
    | ------------------------------------------- constant defined here
@@ -14,8 +14,30 @@ LL |         RANGE => {}
    |
    = note: expected type `i32`
             found struct `RangeInclusive<i32>`
+help: you may want to move the range into the match block
+   |
+LL |         0..=255 => {}
+   |         ^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-76191.rs:15:9
+   |
+LL | const RANGE2: RangeInclusive<i32> = panic!();
+   | --------------------------------------------- constant defined here
+...
+LL |     match n {
+   |           - this expression has type `i32`
+...
+LL |         RANGE2 => {}
+   |         ^^^^^^
+   |         |
+   |         expected `i32`, found struct `RangeInclusive`
+   |         `RANGE2` is interpreted as a constant, not a new binding
+   |
+   = note: expected type `i32`
+            found struct `RangeInclusive<i32>`
    = note: constants only support matching by type, if you meant to match against a range of values, consider using a range pattern like `min ..= max` in the match block
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.