Skip to content

Commit

Permalink
Rollup merge of #76749 - guswynn:hir_ranges, r=estebank
Browse files Browse the repository at this point in the history
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
  • Loading branch information
RalfJung authored Sep 19, 2020
2 parents 8a7cb1e + 230355f commit 5631b5d
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 11 deletions.
55 changes: 46 additions & 9 deletions compiler/rustc_typeck/src/check/pat.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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<'_>,
Expand Down Expand Up @@ -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 = &[
Expand All @@ -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());
Expand Down
5 changes: 5 additions & 0 deletions src/test/ui/issues/issue-76191.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
_ => {}
}
}
26 changes: 24 additions & 2 deletions src/test/ui/issues/issue-76191.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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`.

0 comments on commit 5631b5d

Please sign in to comment.