Skip to content

Commit 6697731

Browse files
committed
Maintain a list of types permitted per pattern
1 parent cb79d1b commit 6697731

File tree

12 files changed

+253
-2
lines changed

12 files changed

+253
-2
lines changed

compiler/rustc_hir_analysis/messages.ftl

+3-1
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a
234234
.help = consider moving this inherent impl into the crate defining the type if possible
235235
.span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
236236
237+
hir_analysis_invalid_base_type = `{$ty}` is not a valid base type for range patterns
238+
.note = range patterns only support integers
239+
237240
hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}`
238241
.note = type of `self` must not be a method generic parameter type
239242
@@ -438,7 +441,6 @@ hir_analysis_pattern_type_wild_pat = wildcard patterns are not permitted for pat
438441
.label = this type is the same as the inner type without a pattern
439442
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
440443
.label = not allowed in type signatures
441-
442444
hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias
443445
.label = `Self` is not a generic argument, but an alias to the type of the {$what}
444446

compiler/rustc_hir_analysis/src/errors/pattern_types.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_macros::Diagnostic;
2+
use rustc_middle::ty::Ty;
23
use rustc_span::Span;
34

45
#[derive(Diagnostic)]
@@ -7,3 +8,14 @@ pub(crate) struct WildPatTy {
78
#[primary_span]
89
pub span: Span,
910
}
11+
12+
#[derive(Diagnostic)]
13+
#[diag(hir_analysis_invalid_base_type)]
14+
pub(crate) struct InvalidBaseType<'tcx> {
15+
pub ty: Ty<'tcx>,
16+
#[primary_span]
17+
pub ty_span: Span,
18+
pub pat: &'static str,
19+
#[note]
20+
pub pat_span: Span,
21+
}

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use tracing::{debug, instrument};
5353

5454
use crate::bounds::Bounds;
5555
use crate::check::check_abi_fn_ptr;
56-
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, WildPatTy};
56+
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, WildPatTy};
5757
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
5858
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
5959
use crate::middle::resolve_bound_vars as rbv;
@@ -2434,13 +2434,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
24342434
self.ty_infer(None, hir_ty.span)
24352435
}
24362436
hir::TyKind::Pat(ty, pat) => {
2437+
let ty_span = ty.span;
24372438
let ty = self.lower_ty(ty);
24382439
let pat_ty = match pat.kind {
24392440
hir::PatKind::Wild => {
24402441
let err = self.dcx().emit_err(WildPatTy { span: pat.span });
24412442
Ty::new_error(tcx, err)
24422443
}
24432444
hir::PatKind::Range(start, end, include_end) => {
2445+
let ty = match ty.kind() {
2446+
ty::Int(_) | ty::Uint(_) | ty::Char | ty::Bool => ty,
2447+
_ => Ty::new_error(
2448+
tcx,
2449+
self.dcx().emit_err(InvalidBaseType {
2450+
ty,
2451+
pat: "range",
2452+
ty_span,
2453+
pat_span: pat.span,
2454+
}),
2455+
),
2456+
};
24442457
let expr_to_const = |expr: &'tcx hir::PatExpr<'tcx>| -> ty::Const<'tcx> {
24452458
let (c, c_ty) = match expr.kind {
24462459
hir::PatExprKind::Lit { lit, negated } => {

tests/ui/type/pattern_types/bools.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//! Check that bools can be used in ranges
2+
3+
#![feature(pattern_types)]
4+
#![feature(pattern_type_macro)]
5+
6+
use std::pat::pattern_type;
7+
8+
const FALSE: pattern_type!(bool is false..=false) = unsafe { std::mem::transmute(false) };
9+
const TRUE: pattern_type!(bool is true..=true) = unsafe { std::mem::transmute(true) };
10+
const ALL_TRUE: pattern_type!(bool is false..=true) = unsafe { std::mem::transmute(true) };
11+
const ALL_FALSE: pattern_type!(bool is false..=true) = unsafe { std::mem::transmute(false) };
12+
13+
const BAD_FALSE: pattern_type!(bool is false..=false) = unsafe { std::mem::transmute(true) };
14+
//~^ ERROR: it is undefined behavior to use this value
15+
const BAD_TRUE: pattern_type!(bool is true..=true) = unsafe { std::mem::transmute(false) };
16+
//~^ ERROR: it is undefined behavior to use this value
17+
18+
fn main() {}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0080]: it is undefined behavior to use this value
2+
--> $DIR/bools.rs:13:1
3+
|
4+
LL | const BAD_FALSE: pattern_type!(bool is false..=false) = unsafe { std::mem::transmute(true) };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 1, but expected something equal to 0
6+
|
7+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
8+
= note: the raw bytes of the constant (size: 1, align: 1) {
9+
01 │ .
10+
}
11+
12+
error[E0080]: it is undefined behavior to use this value
13+
--> $DIR/bools.rs:15:1
14+
|
15+
LL | const BAD_TRUE: pattern_type!(bool is true..=true) = unsafe { std::mem::transmute(false) };
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something equal to 1
17+
|
18+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
19+
= note: the raw bytes of the constant (size: 1, align: 1) {
20+
00 │ .
21+
}
22+
23+
error: aborting due to 2 previous errors
24+
25+
For more information about this error, try `rustc --explain E0080`.

tests/ui/type/pattern_types/chars.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//! Check that chars can be used in ranges
2+
3+
//@ check-pass
4+
5+
#![feature(pattern_types)]
6+
#![feature(pattern_type_macro)]
7+
8+
use std::pat::pattern_type;
9+
10+
const LOWERCASE: pattern_type!(char is 'a'..='z') = unsafe { std::mem::transmute('b') };
11+
12+
fn main() {}

tests/ui/type/pattern_types/nested.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//! Check that pattern types can only have specific base types
2+
3+
#![feature(pattern_types)]
4+
#![feature(pattern_type_macro)]
5+
6+
use std::pat::pattern_type;
7+
8+
// Undoing an inner pattern type's restrictions should either be forbidden,
9+
// or still validate correctly.
10+
const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!();
11+
//~^ ERROR: not a valid base type for range patterns
12+
13+
// We want to get the most narrowest version that a pattern could be
14+
const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!();
15+
//~^ ERROR: not a valid base type for range patterns
16+
17+
const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!();
18+
//~^ ERROR: not a valid base type for range patterns
19+
20+
const BAD_NESTING4: pattern_type!(() is ..0) = todo!();
21+
//~^ ERROR: not a valid base type for range patterns
22+
23+
const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!();
24+
//~^ ERROR: not a valid base type for range patterns
25+
26+
fn main() {}
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
error: `(u32) is 1..=` is not a valid base type for range patterns
2+
--> $DIR/nested.rs:10:34
3+
|
4+
LL | const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!();
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
note: range patterns only support integers
8+
--> $DIR/nested.rs:10:63
9+
|
10+
LL | const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!();
11+
| ^^^
12+
13+
error: `(i32) is 1..=` is not a valid base type for range patterns
14+
--> $DIR/nested.rs:14:35
15+
|
16+
LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!();
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
18+
|
19+
note: range patterns only support integers
20+
--> $DIR/nested.rs:14:64
21+
|
22+
LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!();
23+
| ^^^^^
24+
25+
error: `(i32) is 1..=` is not a valid base type for range patterns
26+
--> $DIR/nested.rs:17:35
27+
|
28+
LL | const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!();
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
30+
|
31+
note: range patterns only support integers
32+
--> $DIR/nested.rs:17:64
33+
|
34+
LL | const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!();
35+
| ^^^
36+
37+
error: `()` is not a valid base type for range patterns
38+
--> $DIR/nested.rs:20:35
39+
|
40+
LL | const BAD_NESTING4: pattern_type!(() is ..0) = todo!();
41+
| ^^
42+
|
43+
note: range patterns only support integers
44+
--> $DIR/nested.rs:20:41
45+
|
46+
LL | const BAD_NESTING4: pattern_type!(() is ..0) = todo!();
47+
| ^^^
48+
49+
error: `f32` is not a valid base type for range patterns
50+
--> $DIR/nested.rs:23:35
51+
|
52+
LL | const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!();
53+
| ^^^
54+
|
55+
note: range patterns only support integers
56+
--> $DIR/nested.rs:23:42
57+
|
58+
LL | const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!();
59+
| ^^^^^^^^^^
60+
61+
error: aborting due to 5 previous errors
62+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//! Check that pattern types patterns must be of the type of the base type
2+
3+
//@ known-bug: unknown
4+
//@ failure-status: 101
5+
//@ normalize-stderr: "note: .*\n\n" -> ""
6+
//@ normalize-stderr: "thread 'rustc' panicked.*\n" -> ""
7+
//@ normalize-stderr: "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
8+
//@ rustc-env:RUST_BACKTRACE=0
9+
10+
#![feature(pattern_types)]
11+
#![feature(pattern_type_macro)]
12+
13+
use std::pat::pattern_type;
14+
15+
const BAD_NESTING4: pattern_type!(bool is 1..=1) = todo!();
16+
17+
const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!();
18+
19+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error: internal compiler error: ty::ConstKind::Error constructed but no error reported
2+
|
3+
= error: internal compiler error: ty::ConstKind::Error constructed but no error reported
4+
|
5+
= note: delayed at compiler/rustc_mir_build/src/thir/constant.rs:72:21 - disabled backtrace
6+
= error: internal compiler error: mir_const_qualif: MIR had errors
7+
--> $DIR/pattern_type_mismatch.rs:15:1
8+
|
9+
LL | const BAD_NESTING4: pattern_type!(bool is 1..=1) = todo!();
10+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11+
|
12+
note: delayed at compiler/rustc_mir_transform/src/lib.rs:358:19 - disabled backtrace
13+
--> $DIR/pattern_type_mismatch.rs:15:1
14+
|
15+
LL | const BAD_NESTING4: pattern_type!(bool is 1..=1) = todo!();
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17+
18+
error: internal compiler error: mir_const_qualif: MIR had errors
19+
--> $DIR/pattern_type_mismatch.rs:17:1
20+
|
21+
LL | const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!();
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23+
|
24+
note: delayed at compiler/rustc_mir_transform/src/lib.rs:358:19 - disabled backtrace
25+
--> $DIR/pattern_type_mismatch.rs:17:1
26+
|
27+
LL | const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!();
28+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29+
30+
query stack during panic:
31+
end of query stack
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//! Check that the range start must be smaller than the range end
2+
//@ known-bug: unknown
3+
//@ failure-status: 101
4+
//@ normalize-stderr: "note: .*\n\n" -> ""
5+
//@ normalize-stderr: "thread 'rustc' panicked.*\n" -> ""
6+
//@ normalize-stderr: "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
7+
//@ rustc-env:RUST_BACKTRACE=0
8+
9+
#![feature(pattern_types)]
10+
#![feature(pattern_type_macro)]
11+
12+
use std::pat::pattern_type;
13+
14+
const NONE: pattern_type!(bool is true..false) = unsafe { std::mem::transmute(3_u8) };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0601]: `main` function not found in crate `reverse_range`
2+
--> $DIR/reverse_range.rs:14:87
3+
|
4+
LL | const NONE: pattern_type!(bool is true..false) = unsafe { std::mem::transmute(3_u8) };
5+
| ^ consider adding a `main` function to `$DIR/reverse_range.rs`
6+
7+
8+
assertion failed: end <= max_value
9+
error: the compiler unexpectedly panicked. this is a bug.
10+
11+
query stack during panic:
12+
#0 [eval_to_allocation_raw] const-evaluating + checking `NONE`
13+
#1 [eval_to_const_value_raw] simplifying constant for the type system `NONE`
14+
... and 1 other queries... use `env RUST_BACKTRACE=1` to see the full query stack
15+
error: aborting due to 1 previous error
16+
17+
For more information about this error, try `rustc --explain E0601`.

0 commit comments

Comments
 (0)