Skip to content

Commit 91c5c59

Browse files
committed
Only allow negation on literals in patterns if it's on integers or floats
1 parent 8ebeaf1 commit 91c5c59

File tree

4 files changed

+94
-5
lines changed

4 files changed

+94
-5
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+31-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use rustc_errors::{
3131
};
3232
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res};
3333
use rustc_hir::def_id::{DefId, LocalDefId};
34-
use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId};
34+
use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId, LangItem};
3535
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
3636
use rustc_infer::traits::ObligationCause;
3737
use rustc_middle::middle::stability::AllowUnstable;
@@ -46,6 +46,7 @@ use rustc_middle::{bug, span_bug};
4646
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
4747
use rustc_span::edit_distance::find_best_match_for_name;
4848
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw};
49+
use rustc_trait_selection::error_reporting::InferCtxtErrorExt as _;
4950
use rustc_trait_selection::infer::InferCtxtExt;
5051
use rustc_trait_selection::traits::wf::object_region_bounds;
5152
use rustc_trait_selection::traits::{self, ObligationCtxt};
@@ -2446,6 +2447,35 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
24462447
hir::PatExprKind::Lit { lit, negated } => {
24472448
let lit_input =
24482449
LitToConstInput { lit: &lit.node, ty, neg: negated };
2450+
let mut ty = ty;
2451+
if negated {
2452+
let infcx_;
2453+
let infcx = match self.infcx() {
2454+
Some(infcx) => infcx,
2455+
None => {
2456+
assert!(!ty.has_infer());
2457+
infcx_ = tcx
2458+
.infer_ctxt()
2459+
.ignoring_regions()
2460+
.build(TypingMode::non_body_analysis());
2461+
&infcx_
2462+
}
2463+
};
2464+
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
2465+
ocx.register_bound(
2466+
ObligationCause::dummy_with_span(expr.span),
2467+
self.tcx().param_env(self.item_def_id()),
2468+
ty,
2469+
self.tcx()
2470+
.require_lang_item(LangItem::Neg, Some(expr.span)),
2471+
);
2472+
let errors = ocx.select_all_or_error();
2473+
if !errors.is_empty() {
2474+
let guar =
2475+
infcx.err_ctxt().report_fulfillment_errors(errors);
2476+
ty = Ty::new_error(tcx, guar);
2477+
}
2478+
}
24492479
let ct = tcx.lit_to_const(lit_input);
24502480
(ct, ty)
24512481
}

compiler/rustc_hir_typeck/src/pat.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -568,8 +568,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
568568

569569
fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
570570
let ty = match &lt.kind {
571-
rustc_hir::PatExprKind::Lit { lit, .. } => {
572-
self.check_expr_lit(lit, Expectation::NoExpectation)
571+
rustc_hir::PatExprKind::Lit { lit, negated } => {
572+
let ty = self.check_expr_lit(lit, Expectation::NoExpectation);
573+
if *negated {
574+
self.register_bound(
575+
ty,
576+
self.tcx.require_lang_item(LangItem::Neg, Some(lt.span)),
577+
ObligationCause::dummy_with_span(lt.span),
578+
);
579+
}
580+
ty
573581
}
574582
rustc_hir::PatExprKind::ConstBlock(c) => {
575583
self.check_expr_const_block(c, Expectation::NoExpectation)
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
#![feature(pattern_types)]
22
#![feature(pattern_type_macro)]
33

4-
//@ check-pass
5-
64
use std::pat::pattern_type;
75

86
type Sign = pattern_type!(u32 is -10..);
7+
//~^ ERROR `u32: Neg` is not satisfied
98

109
type SignedChar = pattern_type!(char is -'A'..);
10+
//~^ ERROR `char: Neg` is not satisfied
1111

1212
fn main() {
1313
match 42_u8 {
1414
-10..253 => {}
15+
//~^ ERROR `u8: Neg` is not satisfied
1516
_ => {}
1617
}
1718

1819
match 'A' {
1920
-'\0'..'a' => {}
21+
//~^ ERROR `char: Neg` is not satisfied
2022
_ => {}
2123
}
2224
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
error[E0277]: the trait bound `u32: Neg` is not satisfied
2+
--> $DIR/signed_ranges.rs:6:34
3+
|
4+
LL | type Sign = pattern_type!(u32 is -10..);
5+
| ^^^ the trait `Neg` is not implemented for `u32`
6+
|
7+
= help: the following other types implement trait `Neg`:
8+
&f128
9+
&f16
10+
&f32
11+
&f64
12+
&i128
13+
&i16
14+
&i32
15+
&i64
16+
and 12 others
17+
18+
error[E0277]: the trait bound `char: Neg` is not satisfied
19+
--> $DIR/signed_ranges.rs:9:41
20+
|
21+
LL | type SignedChar = pattern_type!(char is -'A'..);
22+
| ^^^^ the trait `Neg` is not implemented for `char`
23+
24+
error[E0277]: the trait bound `u8: Neg` is not satisfied
25+
--> $DIR/signed_ranges.rs:14:9
26+
|
27+
LL | -10..253 => {}
28+
| ^^^ the trait `Neg` is not implemented for `u8`
29+
|
30+
= help: the following other types implement trait `Neg`:
31+
&f128
32+
&f16
33+
&f32
34+
&f64
35+
&i128
36+
&i16
37+
&i32
38+
&i64
39+
and 12 others
40+
41+
error[E0277]: the trait bound `char: Neg` is not satisfied
42+
--> $DIR/signed_ranges.rs:20:9
43+
|
44+
LL | -'\0'..'a' => {}
45+
| ^^^^^ the trait `Neg` is not implemented for `char`
46+
47+
error: aborting due to 4 previous errors
48+
49+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)