Skip to content

Commit

Permalink
better diag when const ranges are used in patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
guswynn committed Sep 11, 2020
1 parent 141bb23 commit 5e126c9
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 5 deletions.
39 changes: 34 additions & 5 deletions compiler/rustc_typeck/src/check/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rustc_hir::{HirId, Pat, PatKind};
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::subst::GenericArg;
use rustc_middle::ty::{self, BindingMode, Ty, TypeFoldable};
use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable};
use rustc_span::hygiene::DesugaringKind;
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::Ident;
Expand Down Expand Up @@ -735,7 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some(err) =
self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty)
{
self.emit_bad_pat_path(err, pat.span, res, pat_res, segments, ti.parent_pat);
self.emit_bad_pat_path(err, pat.span, res, pat_res, pat_ty, segments, ti.parent_pat);
}
pat_ty
}
Expand All @@ -746,6 +746,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pat_span: Span,
res: Res,
pat_res: Res,
pat_ty: Ty<'tcx>,
segments: &'b [hir::PathSegment<'b>],
parent_pat: Option<&Pat<'_>>,
) {
Expand All @@ -771,9 +772,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
_ => {
let msg = "introduce a new binding instead";
let sugg = format!("other_{}", ident.as_str().to_lowercase());
e.span_suggestion(ident.span, msg, sugg, Applicability::HasPlaceholders);
let const_def_id = match pat_ty.kind() {
Adt(def, _) => match res {
Res::Def(DefKind::Const, _) => Some(def.did),
_ => None,
},
_ => None,
};

let ranges = &[
self.tcx.lang_items().range_struct(),
self.tcx.lang_items().range_from_struct(),
self.tcx.lang_items().range_to_struct(),
self.tcx.lang_items().range_full_struct(),
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);
} else {
let msg = "introduce a new binding instead";
let sugg = format!("other_{}", ident.as_str().to_lowercase());
e.span_suggestion(
ident.span,
msg,
sugg,
Applicability::HasPlaceholders,
);
}
}
};
}
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/issues/issue-76191.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Regression test for diagnostic issue #76191
#![allow(non_snake_case)]

use std::ops::RangeInclusive;
const RANGE: RangeInclusive<i32> = 0..=255;

fn main() {
let n: i32 = 1;
match n {
RANGE => {}
//~^ ERROR mismatched types
_ => {}
}
}
21 changes: 21 additions & 0 deletions src/test/ui/issues/issue-76191.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0308]: mismatched types
--> $DIR/issue-76191.rs:10:9
|
LL | const RANGE: RangeInclusive<i32> = 0..=255;
| ------------------------------------------- constant defined here
...
LL | match n {
| - this expression has type `i32`
LL | RANGE => {}
| ^^^^^
| |
| expected `i32`, found struct `RangeInclusive`
| `RANGE` 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

For more information about this error, try `rustc --explain E0308`.

0 comments on commit 5e126c9

Please sign in to comment.