about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-03-11 19:35:27 +0100
committerGitHub <noreply@github.com>2025-03-11 19:35:27 +0100
commit8a2e3acb450ccbd361394c31334d5b361b28b8fa (patch)
tree651d588542b7ed945a69ad2cbd959298e06c8077 /compiler
parentf2d69d5a7c04617d122facd0a7a5bdde0af928ae (diff)
parentf87e58f1948c493aef6d645f339c2b9043e5ba59 (diff)
downloadrust-8a2e3acb450ccbd361394c31334d5b361b28b8fa.tar.gz
rust-8a2e3acb450ccbd361394c31334d5b361b28b8fa.zip
Rollup merge of #137715 - oli-obk:pattern-type-literals, r=BoxyUwU
Allow int literals for pattern types with int base types

r? ``@BoxyUwU``

I also added an error at layout computation time for layouts that contain wrapping ranges (happens at monomorphization time). This is obviously hacky, but at least prevents such types from making it to codegen for now. It made writing the tests for int literals easier as I didn't have to think about that edge case

Basically this PR allows you to stop using transmutes for creating pattern types and instead just use literals:

```rust
let x: pattern_type!(u32 is 5..10) = 7;
```

works, and if the literal is out of range you get a type mismatch because it just stays at the base type and the base type can't be coerced to the pattern type.

cc ``@joshtriplett`` ``@scottmcm``
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs15
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/as_constant.rs7
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs28
3 files changed, 48 insertions, 2 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index ac911c20222..b8517701667 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1636,7 +1636,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ast::LitKind::Char(_) => tcx.types.char,
             ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => Ty::new_int(tcx, ty::int_ty(t)),
             ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => Ty::new_uint(tcx, ty::uint_ty(t)),
-            ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
+            ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) => {
                 let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
                     ty::Int(_) | ty::Uint(_) => Some(ty),
                     // These exist to direct casts like `0x61 as char` to use
@@ -1645,6 +1645,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     ty::Char => Some(tcx.types.u8),
                     ty::RawPtr(..) => Some(tcx.types.usize),
                     ty::FnDef(..) | ty::FnPtr(..) => Some(tcx.types.usize),
+                    &ty::Pat(base, _) if base.is_integral() => {
+                        let layout = tcx
+                            .layout_of(self.typing_env(self.param_env).as_query_input(ty))
+                            .ok()?;
+                        assert!(!layout.uninhabited);
+
+                        match layout.backend_repr {
+                            rustc_abi::BackendRepr::Scalar(scalar) => {
+                                scalar.valid_range(&tcx).contains(u128::from(i.get())).then_some(ty)
+                            }
+                            _ => unreachable!(),
+                        }
+                    }
                     _ => None,
                 });
                 opt_ty.unwrap_or_else(|| self.next_int_var())
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
index 84c9297e658..f743ea60a45 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
@@ -117,7 +117,12 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>
         ConstValue::Scalar(Scalar::from_uint(result, width))
     };
 
-    let value = match (lit, ty.kind()) {
+    let lit_ty = match *ty.kind() {
+        ty::Pat(base, _) => base,
+        _ => ty,
+    };
+
+    let value = match (lit, lit_ty.kind()) {
         (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
             let s = s.as_str();
             let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 5a4bb2c95da..7334beb52c9 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -220,6 +220,34 @@ fn layout_of_uncached<'tcx>(
                             .try_to_bits(tcx, cx.typing_env)
                             .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
 
+                        // FIXME(pattern_types): create implied bounds from pattern types in signatures
+                        // that require that the range end is >= the range start so that we can't hit
+                        // this error anymore without first having hit a trait solver error.
+                        // Very fuzzy on the details here, but pattern types are an internal impl detail,
+                        // so we can just go with this for now
+                        if scalar.is_signed() {
+                            let range = scalar.valid_range_mut();
+                            let start = layout.size.sign_extend(range.start);
+                            let end = layout.size.sign_extend(range.end);
+                            if end < start {
+                                let guar = tcx.dcx().err(format!(
+                                    "pattern type ranges cannot wrap: {start}..={end}"
+                                ));
+
+                                return Err(error(cx, LayoutError::ReferencesError(guar)));
+                            }
+                        } else {
+                            let range = scalar.valid_range_mut();
+                            if range.end < range.start {
+                                let guar = tcx.dcx().err(format!(
+                                    "pattern type ranges cannot wrap: {}..={}",
+                                    range.start, range.end
+                                ));
+
+                                return Err(error(cx, LayoutError::ReferencesError(guar)));
+                            }
+                        };
+
                         let niche = Niche {
                             offset: Size::ZERO,
                             value: scalar.primitive(),