Skip to content

Commit

Permalink
Only allow negation on literals in patterns if it's on integers or fl…
Browse files Browse the repository at this point in the history
…oats
  • Loading branch information
oli-obk committed Feb 3, 2025
1 parent bce763c commit 76ba91c
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 5 deletions.
32 changes: 31 additions & 1 deletion compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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};
Expand Down Expand Up @@ -2457,6 +2458,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)
}
Expand Down
12 changes: 10 additions & 2 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,8 +570,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
let ty = match &lt.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)
Expand Down
6 changes: 4 additions & 2 deletions tests/ui/type/pattern_types/signed_ranges.rs
Original file line number Diff line number Diff line change
@@ -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
_ => {}
}
}
49 changes: 49 additions & 0 deletions tests/ui/type/pattern_types/signed_ranges.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 76ba91c

Please sign in to comment.