about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOli Scherer <github333195615777966@oli-obk.de>2025-01-28 12:07:36 +0000
committerOli Scherer <github333195615777966@oli-obk.de>2025-02-02 19:30:53 +0000
commit7e4ccc2f12f29a5c12c5669afd25b7e0481baf52 (patch)
treec857f221ab91eb6626eaa894c7055f50a8ca0a3d
parentded0836c18a0b25f076ee776e1c9eeb989272f3b (diff)
downloadrust-7e4ccc2f12f29a5c12c5669afd25b7e0481baf52.tar.gz
rust-7e4ccc2f12f29a5c12c5669afd25b7e0481baf52.zip
Maintain a list of types permitted per pattern
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl4
-rw-r--r--compiler/rustc_hir_analysis/src/errors/pattern_types.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs15
-rw-r--r--tests/ui/type/pattern_types/chars.rs12
-rw-r--r--tests/ui/type/pattern_types/nested.rs26
-rw-r--r--tests/ui/type/pattern_types/nested.stderr62
-rw-r--r--tests/ui/type/pattern_types/pattern_type_mismatch.rs20
-rw-r--r--tests/ui/type/pattern_types/pattern_type_mismatch.stderr31
-rw-r--r--tests/ui/type/pattern_types/reverse_range.rs14
-rw-r--r--tests/ui/type/pattern_types/reverse_range.stderr17
10 files changed, 211 insertions, 2 deletions
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index be4004f5904..a4b5a87361e 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -234,6 +234,9 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a
     .help = consider moving this inherent impl into the crate defining the type if possible
     .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
 
+hir_analysis_invalid_base_type = `{$ty}` is not a valid base type for range patterns
+    .note = range patterns only support integers
+
 hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}`
     .note = type of `self` must not be a method generic parameter type
 
@@ -438,7 +441,6 @@ hir_analysis_pattern_type_wild_pat = wildcard patterns are not permitted for pat
     .label = this type is the same as the inner type without a pattern
 hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
     .label = not allowed in type signatures
-
 hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias
     .label = `Self` is not a generic argument, but an alias to the type of the {$what}
 
diff --git a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs
index bb771d6ea17..272edbe841b 100644
--- a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs
+++ b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs
@@ -1,4 +1,5 @@
 use rustc_macros::Diagnostic;
+use rustc_middle::ty::Ty;
 use rustc_span::Span;
 
 #[derive(Diagnostic)]
@@ -7,3 +8,14 @@ pub(crate) struct WildPatTy {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_invalid_base_type)]
+pub(crate) struct InvalidBaseType<'tcx> {
+    pub ty: Ty<'tcx>,
+    #[primary_span]
+    pub ty_span: Span,
+    pub pat: &'static str,
+    #[note]
+    pub pat_span: Span,
+}
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 b4cab3330af..5813fdeae76 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -53,7 +53,7 @@ use tracing::{debug, instrument};
 
 use crate::bounds::Bounds;
 use crate::check::check_abi_fn_ptr;
-use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, WildPatTy};
+use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, WildPatTy};
 use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
 use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
 use crate::middle::resolve_bound_vars as rbv;
@@ -2432,6 +2432,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 self.ty_infer(None, hir_ty.span)
             }
             hir::TyKind::Pat(ty, pat) => {
+                let ty_span = ty.span;
                 let ty = self.lower_ty(ty);
                 let pat_ty = match pat.kind {
                     hir::PatKind::Wild => {
@@ -2439,6 +2440,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         Ty::new_error(tcx, err)
                     }
                     hir::PatKind::Range(start, end, include_end) => {
+                        let ty = match ty.kind() {
+                            ty::Int(_) | ty::Uint(_) | ty::Char => ty,
+                            _ => Ty::new_error(
+                                tcx,
+                                self.dcx().emit_err(InvalidBaseType {
+                                    ty,
+                                    pat: "range",
+                                    ty_span,
+                                    pat_span: pat.span,
+                                }),
+                            ),
+                        };
                         let expr_to_const = |expr: &'tcx hir::PatExpr<'tcx>| -> ty::Const<'tcx> {
                             let (c, c_ty) = match expr.kind {
                                 hir::PatExprKind::Lit { lit, negated } => {
diff --git a/tests/ui/type/pattern_types/chars.rs b/tests/ui/type/pattern_types/chars.rs
new file mode 100644
index 00000000000..9073998b387
--- /dev/null
+++ b/tests/ui/type/pattern_types/chars.rs
@@ -0,0 +1,12 @@
+//! Check that chars can be used in ranges
+
+//@ check-pass
+
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+const LOWERCASE: pattern_type!(char is 'a'..='z') = unsafe { std::mem::transmute('b') };
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/nested.rs b/tests/ui/type/pattern_types/nested.rs
new file mode 100644
index 00000000000..519fb3f05b4
--- /dev/null
+++ b/tests/ui/type/pattern_types/nested.rs
@@ -0,0 +1,26 @@
+//! Check that pattern types can only have specific base types
+
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+// Undoing an inner pattern type's restrictions should either be forbidden,
+// or still validate correctly.
+const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!();
+//~^ ERROR: not a valid base type for range patterns
+
+// We want to get the most narrowest version that a pattern could be
+const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!();
+//~^ ERROR: not a valid base type for range patterns
+
+const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!();
+//~^ ERROR: not a valid base type for range patterns
+
+const BAD_NESTING4: pattern_type!(() is ..0) = todo!();
+//~^ ERROR: not a valid base type for range patterns
+
+const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!();
+//~^ ERROR: not a valid base type for range patterns
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/nested.stderr b/tests/ui/type/pattern_types/nested.stderr
new file mode 100644
index 00000000000..99d3979e98c
--- /dev/null
+++ b/tests/ui/type/pattern_types/nested.stderr
@@ -0,0 +1,62 @@
+error: `(u32) is 1..=` is not a valid base type for range patterns
+  --> $DIR/nested.rs:10:34
+   |
+LL | const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!();
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: range patterns only support integers
+  --> $DIR/nested.rs:10:63
+   |
+LL | const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!();
+   |                                                               ^^^
+
+error: `(i32) is 1..=` is not a valid base type for range patterns
+  --> $DIR/nested.rs:14:35
+   |
+LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!();
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: range patterns only support integers
+  --> $DIR/nested.rs:14:64
+   |
+LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!();
+   |                                                                ^^^^^
+
+error: `(i32) is 1..=` is not a valid base type for range patterns
+  --> $DIR/nested.rs:17:35
+   |
+LL | const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!();
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: range patterns only support integers
+  --> $DIR/nested.rs:17:64
+   |
+LL | const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!();
+   |                                                                ^^^
+
+error: `()` is not a valid base type for range patterns
+  --> $DIR/nested.rs:20:35
+   |
+LL | const BAD_NESTING4: pattern_type!(() is ..0) = todo!();
+   |                                   ^^
+   |
+note: range patterns only support integers
+  --> $DIR/nested.rs:20:41
+   |
+LL | const BAD_NESTING4: pattern_type!(() is ..0) = todo!();
+   |                                         ^^^
+
+error: `f32` is not a valid base type for range patterns
+  --> $DIR/nested.rs:23:35
+   |
+LL | const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!();
+   |                                   ^^^
+   |
+note: range patterns only support integers
+  --> $DIR/nested.rs:23:42
+   |
+LL | const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!();
+   |                                          ^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/type/pattern_types/pattern_type_mismatch.rs b/tests/ui/type/pattern_types/pattern_type_mismatch.rs
new file mode 100644
index 00000000000..8d375d7932b
--- /dev/null
+++ b/tests/ui/type/pattern_types/pattern_type_mismatch.rs
@@ -0,0 +1,20 @@
+//! Check that pattern types patterns must be of the type of the base type
+
+//@ known-bug: unknown
+//@ failure-status: 101
+//@ normalize-stderr: "note: .*\n\n" -> ""
+//@ normalize-stderr: "thread 'rustc' panicked.*\n" -> ""
+//@ normalize-stderr: "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
+//@ normalize-stderr: "(delayed at compiler/rustc_mir_transform/src/lib.rs:)\d+:\d+" -> "$1:LL:CC"
+//@ rustc-env:RUST_BACKTRACE=0
+
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!();
+
+const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!();
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/pattern_type_mismatch.stderr b/tests/ui/type/pattern_types/pattern_type_mismatch.stderr
new file mode 100644
index 00000000000..ee413133ab3
--- /dev/null
+++ b/tests/ui/type/pattern_types/pattern_type_mismatch.stderr
@@ -0,0 +1,31 @@
+error: internal compiler error: ty::ConstKind::Error constructed but no error reported
+   |
+   = error: internal compiler error: ty::ConstKind::Error constructed but no error reported
+   |
+   = note: delayed at compiler/rustc_mir_build/src/thir/constant.rs:72:21 - disabled backtrace
+   = error: internal compiler error: mir_const_qualif: MIR had errors
+  --> $DIR/pattern_type_mismatch.rs:16:1
+   |
+LL | const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: delayed at compiler/rustc_mir_transform/src/lib.rs::LL:CC - disabled backtrace
+  --> $DIR/pattern_type_mismatch.rs:16:1
+   |
+LL | const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: internal compiler error: mir_const_qualif: MIR had errors
+  --> $DIR/pattern_type_mismatch.rs:18:1
+   |
+LL | const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: delayed at compiler/rustc_mir_transform/src/lib.rs::LL:CC - disabled backtrace
+  --> $DIR/pattern_type_mismatch.rs:18:1
+   |
+LL | const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+query stack during panic:
+end of query stack
diff --git a/tests/ui/type/pattern_types/reverse_range.rs b/tests/ui/type/pattern_types/reverse_range.rs
new file mode 100644
index 00000000000..6a245615f1a
--- /dev/null
+++ b/tests/ui/type/pattern_types/reverse_range.rs
@@ -0,0 +1,14 @@
+//! Check that the range start must be smaller than the range end
+//@ known-bug: unknown
+//@ failure-status: 101
+//@ normalize-stderr: "note: .*\n\n" -> ""
+//@ normalize-stderr: "thread 'rustc' panicked.*\n" -> ""
+//@ normalize-stderr: "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
+//@ rustc-env:RUST_BACKTRACE=0
+
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+const NONE: pattern_type!(u8 is 1..0) = unsafe { std::mem::transmute(3_u8) };
diff --git a/tests/ui/type/pattern_types/reverse_range.stderr b/tests/ui/type/pattern_types/reverse_range.stderr
new file mode 100644
index 00000000000..b714ca7d9ab
--- /dev/null
+++ b/tests/ui/type/pattern_types/reverse_range.stderr
@@ -0,0 +1,17 @@
+error[E0601]: `main` function not found in crate `reverse_range`
+  --> $DIR/reverse_range.rs:14:78
+   |
+LL | const NONE: pattern_type!(u8 is 1..0) = unsafe { std::mem::transmute(3_u8) };
+   |                                                                              ^ consider adding a `main` function to `$DIR/reverse_range.rs`
+
+
+assertion failed: end <= max_value
+error: the compiler unexpectedly panicked. this is a bug.
+
+query stack during panic:
+#0 [eval_to_allocation_raw] const-evaluating + checking `NONE`
+#1 [eval_to_const_value_raw] simplifying constant for the type system `NONE`
+... and 1 other queries... use `env RUST_BACKTRACE=1` to see the full query stack
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0601`.