From 5e126c944b83d8402e0414914ef7d6c05004d483 Mon Sep 17 00:00:00 2001 From: Gus Wynn Date: Tue, 1 Sep 2020 15:53:04 -0700 Subject: [PATCH] better diag when const ranges are used in patterns --- compiler/rustc_typeck/src/check/pat.rs | 39 ++++++++++++++++++++++---- src/test/ui/issues/issue-76191.rs | 14 +++++++++ src/test/ui/issues/issue-76191.stderr | 21 ++++++++++++++ 3 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/issues/issue-76191.rs create mode 100644 src/test/ui/issues/issue-76191.stderr diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 1896155e327..171d5ee4ff2 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -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; @@ -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 } @@ -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<'_>>, ) { @@ -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, + ); + } } }; } diff --git a/src/test/ui/issues/issue-76191.rs b/src/test/ui/issues/issue-76191.rs new file mode 100644 index 00000000000..bc327123c6f --- /dev/null +++ b/src/test/ui/issues/issue-76191.rs @@ -0,0 +1,14 @@ +// Regression test for diagnostic issue #76191 +#![allow(non_snake_case)] + +use std::ops::RangeInclusive; +const RANGE: RangeInclusive = 0..=255; + +fn main() { + let n: i32 = 1; + match n { + RANGE => {} + //~^ ERROR mismatched types + _ => {} + } +} diff --git a/src/test/ui/issues/issue-76191.stderr b/src/test/ui/issues/issue-76191.stderr new file mode 100644 index 00000000000..a5544d9e9da --- /dev/null +++ b/src/test/ui/issues/issue-76191.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/issue-76191.rs:10:9 + | +LL | const RANGE: RangeInclusive = 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` + = 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`.