Skip to content

Commit 76ba91c

Browse files
committed
Only allow negation on literals in patterns if it's on integers or floats
1 parent bce763c commit 76ba91c

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};
@@ -2457,6 +2458,35 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
24572458
hir::PatExprKind::Lit { lit, negated } => {
24582459
let lit_input =
24592460
LitToConstInput { lit: &lit.node, ty, neg: negated };
2461+
let mut ty = ty;
2462+
if negated {
2463+
let infcx_;
2464+
let infcx = match self.infcx() {
2465+
Some(infcx) => infcx,
2466+
None => {
2467+
assert!(!ty.has_infer());
2468+
infcx_ = tcx
2469+
.infer_ctxt()
2470+
.ignoring_regions()
2471+
.build(TypingMode::non_body_analysis());
2472+
&infcx_
2473+
}
2474+
};
2475+
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
2476+
ocx.register_bound(
2477+
ObligationCause::dummy_with_span(expr.span),
2478+
self.tcx().param_env(self.item_def_id()),
2479+
ty,
2480+
self.tcx()
2481+
.require_lang_item(LangItem::Neg, Some(expr.span)),
2482+
);
2483+
let errors = ocx.select_all_or_error();
2484+
if !errors.is_empty() {
2485+
let guar =
2486+
infcx.err_ctxt().report_fulfillment_errors(errors);
2487+
ty = Ty::new_error(tcx, guar);
2488+
}
2489+
}
24602490
let ct = tcx.lit_to_const(lit_input);
24612491
(ct, ty)
24622492
}

compiler/rustc_hir_typeck/src/pat.rs

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

571571
fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
572572
let ty = match &lt.kind {
573-
rustc_hir::PatExprKind::Lit { lit, .. } => {
574-
self.check_expr_lit(lit, Expectation::NoExpectation)
573+
rustc_hir::PatExprKind::Lit { lit, negated } => {
574+
let ty = self.check_expr_lit(lit, Expectation::NoExpectation);
575+
if *negated {
576+
self.register_bound(
577+
ty,
578+
self.tcx.require_lang_item(LangItem::Neg, Some(lt.span)),
579+
ObligationCause::dummy_with_span(lt.span),
580+
);
581+
}
582+
ty
575583
}
576584
rustc_hir::PatExprKind::ConstBlock(c) => {
577585
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)