From 91c5c5902669ade5fe050d944df289ed472d47f7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 30 Jan 2025 17:14:35 +0000 Subject: [PATCH] Only allow negation on literals in patterns if it's on integers or floats --- .../src/hir_ty_lowering/mod.rs | 32 +++++++++++- compiler/rustc_hir_typeck/src/pat.rs | 12 ++++- tests/ui/type/pattern_types/signed_ranges.rs | 6 ++- .../type/pattern_types/signed_ranges.stderr | 49 +++++++++++++++++++ 4 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 tests/ui/type/pattern_types/signed_ranges.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 61d5869c19f15..891639e6c9dd9 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -31,7 +31,7 @@ use rustc_errors::{ }; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId}; +use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId, LangItem}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability::AllowUnstable; @@ -46,6 +46,7 @@ use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw}; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt as _; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -2446,6 +2447,35 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::PatExprKind::Lit { lit, negated } => { let lit_input = LitToConstInput { lit: &lit.node, ty, neg: negated }; + let mut ty = ty; + if negated { + let infcx_; + let infcx = match self.infcx() { + Some(infcx) => infcx, + None => { + assert!(!ty.has_infer()); + infcx_ = tcx + .infer_ctxt() + .ignoring_regions() + .build(TypingMode::non_body_analysis()); + &infcx_ + } + }; + let ocx = ObligationCtxt::new_with_diagnostics(infcx); + ocx.register_bound( + ObligationCause::dummy_with_span(expr.span), + self.tcx().param_env(self.item_def_id()), + ty, + self.tcx() + .require_lang_item(LangItem::Neg, Some(expr.span)), + ); + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + let guar = + infcx.err_ctxt().report_fulfillment_errors(errors); + ty = Ty::new_error(tcx, guar); + } + } let ct = tcx.lit_to_const(lit_input); (ct, ty) } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 0aa2f1110fb3d..fcb17618db6d9 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -568,8 +568,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> { let ty = match <.kind { - rustc_hir::PatExprKind::Lit { lit, .. } => { - self.check_expr_lit(lit, Expectation::NoExpectation) + rustc_hir::PatExprKind::Lit { lit, negated } => { + let ty = self.check_expr_lit(lit, Expectation::NoExpectation); + if *negated { + self.register_bound( + ty, + self.tcx.require_lang_item(LangItem::Neg, Some(lt.span)), + ObligationCause::dummy_with_span(lt.span), + ); + } + ty } rustc_hir::PatExprKind::ConstBlock(c) => { self.check_expr_const_block(c, Expectation::NoExpectation) diff --git a/tests/ui/type/pattern_types/signed_ranges.rs b/tests/ui/type/pattern_types/signed_ranges.rs index 9e250309aca42..73891d81dd230 100644 --- a/tests/ui/type/pattern_types/signed_ranges.rs +++ b/tests/ui/type/pattern_types/signed_ranges.rs @@ -1,22 +1,24 @@ #![feature(pattern_types)] #![feature(pattern_type_macro)] -//@ check-pass - use std::pat::pattern_type; type Sign = pattern_type!(u32 is -10..); +//~^ ERROR `u32: Neg` is not satisfied type SignedChar = pattern_type!(char is -'A'..); +//~^ ERROR `char: Neg` is not satisfied fn main() { match 42_u8 { -10..253 => {} + //~^ ERROR `u8: Neg` is not satisfied _ => {} } match 'A' { -'\0'..'a' => {} + //~^ ERROR `char: Neg` is not satisfied _ => {} } } diff --git a/tests/ui/type/pattern_types/signed_ranges.stderr b/tests/ui/type/pattern_types/signed_ranges.stderr new file mode 100644 index 0000000000000..455c03a1806c7 --- /dev/null +++ b/tests/ui/type/pattern_types/signed_ranges.stderr @@ -0,0 +1,49 @@ +error[E0277]: the trait bound `u32: Neg` is not satisfied + --> $DIR/signed_ranges.rs:6:34 + | +LL | type Sign = pattern_type!(u32 is -10..); + | ^^^ the trait `Neg` is not implemented for `u32` + | + = help: the following other types implement trait `Neg`: + &f128 + &f16 + &f32 + &f64 + &i128 + &i16 + &i32 + &i64 + and 12 others + +error[E0277]: the trait bound `char: Neg` is not satisfied + --> $DIR/signed_ranges.rs:9:41 + | +LL | type SignedChar = pattern_type!(char is -'A'..); + | ^^^^ the trait `Neg` is not implemented for `char` + +error[E0277]: the trait bound `u8: Neg` is not satisfied + --> $DIR/signed_ranges.rs:14:9 + | +LL | -10..253 => {} + | ^^^ the trait `Neg` is not implemented for `u8` + | + = help: the following other types implement trait `Neg`: + &f128 + &f16 + &f32 + &f64 + &i128 + &i16 + &i32 + &i64 + and 12 others + +error[E0277]: the trait bound `char: Neg` is not satisfied + --> $DIR/signed_ranges.rs:20:9 + | +LL | -'\0'..'a' => {} + | ^^^^^ the trait `Neg` is not implemented for `char` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`.