From c17eee6a6aec3cc62431b2a3b651ecd77b6bb572 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 28 Jan 2025 12:07:36 +0000 Subject: [PATCH] Maintain a list of types permitted per pattern --- compiler/rustc_hir_analysis/messages.ftl | 4 +- .../src/errors/pattern_types.rs | 12 ++++ .../src/hir_ty_lowering/mod.rs | 15 ++++- tests/ui/type/pattern_types/chars.rs | 12 ++++ tests/ui/type/pattern_types/nested.rs | 26 ++++++++ tests/ui/type/pattern_types/nested.stderr | 62 +++++++++++++++++++ .../pattern_types/pattern_type_mismatch.rs | 20 ++++++ .../pattern_type_mismatch.stderr | 31 ++++++++++ tests/ui/type/pattern_types/reverse_range.rs | 14 +++++ .../type/pattern_types/reverse_range.stderr | 17 +++++ 10 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 tests/ui/type/pattern_types/chars.rs create mode 100644 tests/ui/type/pattern_types/nested.rs create mode 100644 tests/ui/type/pattern_types/nested.stderr create mode 100644 tests/ui/type/pattern_types/pattern_type_mismatch.rs create mode 100644 tests/ui/type/pattern_types/pattern_type_mismatch.stderr create mode 100644 tests/ui/type/pattern_types/reverse_range.rs create mode 100644 tests/ui/type/pattern_types/reverse_range.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index be4004f5904cc..a4b5a87361ef3 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 bb771d6ea170e..272edbe841b96 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 b4cab3330afaf..5813fdeae7645 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 0000000000000..9073998b387b7 --- /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 0000000000000..519fb3f05b483 --- /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 0000000000000..99d3979e98c49 --- /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 0000000000000..8d375d7932bc6 --- /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 0000000000000..ee413133ab317 --- /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 0000000000000..6a245615f1ac0 --- /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 0000000000000..b714ca7d9ab96 --- /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`.