about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-04-08 16:25:23 +0000
committerbors <bors@rust-lang.org>2024-04-08 16:25:23 +0000
commit537aab7a2e7fe9cdf50b5ff18485e0793cd8db62 (patch)
treeb6f3591f2040fa12ede5b801a219d63f53b41f64 /tests
parentab3dba92db355b8d97db915a2dca161a117e959c (diff)
parent18ff131c4e06d6e1ebfc19092fe1d6c3535eb78b (diff)
Auto merge of #120131 - oli-obk:pattern_types_syntax, r=compiler-errors
Implement minimal, internal-only pattern types in the type system

rebase of https://github.com/rust-lang/rust/pull/107606

You can create pattern types with `std::pat::pattern_type!(ty is pat)`. The feature is incomplete and will panic on you if you use any pattern other than integral range patterns. The only way to create or deconstruct a pattern type is via `transmute`.

This PR's implementation differs from the MCP's text. Specifically

> This means you could implement different traits for different pattern types with the same base type. Thus, we just forbid implementing any traits for pattern types.

is violated in this PR. The reason is that we do need impls after all in order to make them usable as fields. constants of type `std::time::Nanoseconds` struct are used in patterns, so the type must be structural-eq, which it only can be if you derive several traits on it. It doesn't need to be structural-eq recursively, so we can just manually implement the relevant traits on the pattern type and use the pattern type as a private field.

Waiting on:

* [x] move all unrelated commits into their own PRs.
* [x] fix niche computation (see 2db07f94f44f078daffe5823680d07d4fded883f)
* [x] add lots more tests
* [x] T-types MCP https://github.com/rust-lang/types-team/issues/126 to finish
* [x] some commit cleanup
* [x] full self-review
* [x] remove 61bd325da19a918cc3e02bbbdce97281a389c648, it's not necessary anymore I think.
* [ ] ~~make sure we never accidentally leak pattern types to user code (add stability checks or feature gate checks and appopriate tests)~~ we don't even do this for the new float primitives
* [x] get approval that [the scope expansion to trait impls](https://rust-lang.zulipchat.com/#narrow/stream/326866-t-types.2Fnominated/topic/Pattern.20types.20types-team.23126/near/427670099) is ok

r? `@BoxyUwU`
Diffstat (limited to 'tests')
-rw-r--r--tests/codegen/pattern_type_symbols.rs23
-rw-r--r--tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs1
-rw-r--r--tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr52
-rw-r--r--tests/ui/symbol-names/basic.legacy.stderr4
-rw-r--r--tests/ui/symbol-names/issue-60925.legacy.stderr4
-rw-r--r--tests/ui/type/pattern_types/bad_pat.rs14
-rw-r--r--tests/ui/type/pattern_types/bad_pat.stderr25
-rw-r--r--tests/ui/type/pattern_types/derives.noimpl.stderr14
-rw-r--r--tests/ui/type/pattern_types/derives.rs20
-rw-r--r--tests/ui/type/pattern_types/derives.stderr14
-rw-r--r--tests/ui/type/pattern_types/feature-gate-pattern_types.rs14
-rw-r--r--tests/ui/type/pattern_types/feature-gate-pattern_types.stderr48
-rw-r--r--tests/ui/type/pattern_types/feature-gate-pattern_types2.rs12
-rw-r--r--tests/ui/type/pattern_types/macros.active.stderr10
-rw-r--r--tests/ui/type/pattern_types/macros.gated.stderr10
-rw-r--r--tests/ui/type/pattern_types/macros.rs15
-rw-r--r--tests/ui/type/pattern_types/range_patterns.rs23
-rw-r--r--tests/ui/type/pattern_types/range_patterns.stderr343
-rw-r--r--tests/ui/type/pattern_types/range_patterns_inherent_impls.rs30
-rw-r--r--tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr16
-rw-r--r--tests/ui/type/pattern_types/range_patterns_trait_impls.rs19
-rw-r--r--tests/ui/type/pattern_types/range_patterns_trait_impls2.rs16
-rw-r--r--tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr14
-rw-r--r--tests/ui/type/pattern_types/range_patterns_unusable.rs15
-rw-r--r--tests/ui/type/pattern_types/range_patterns_unusable.stderr12
-rw-r--r--tests/ui/type/pattern_types/range_patterns_unusable_math.rs16
-rw-r--r--tests/ui/type/pattern_types/range_patterns_unusable_math.stderr11
-rw-r--r--tests/ui/type/pattern_types/range_patterns_usage.rs26
28 files changed, 794 insertions, 27 deletions
diff --git a/tests/codegen/pattern_type_symbols.rs b/tests/codegen/pattern_type_symbols.rs
new file mode 100644
index 00000000000..dfe83443348
--- /dev/null
+++ b/tests/codegen/pattern_type_symbols.rs
@@ -0,0 +1,23 @@
+//! Check that symbol names with pattern types in them are
+//! different from the same symbol with the base type
+
+//@ compile-flags: -Csymbol-mangling-version=v0 -Copt-level=0 --crate-type=lib
+
+#![feature(pattern_types)]
+#![feature(core_pattern_types)]
+#![feature(core_pattern_type)]
+
+use std::pat::pattern_type;
+
+type NanoU32 = crate::pattern_type!(u32 is 0..=999_999_999);
+
+fn foo<T>() {}
+
+pub fn bar() {
+    // CHECK: call pattern_type_symbols::foo::<u32>
+    // CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3foomEB2_
+    foo::<u32>();
+    // CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999], [(); true])>
+    // CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_Aub1_EEB2_
+    foo::<NanoU32>();
+}
diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs
index 3152bf23ca5..f77b318039d 100644
--- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs
+++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs
@@ -22,6 +22,7 @@ fn main() {
         TyKind::Foreign(..) => (),          //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Str => (),                  //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Array(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Pat(..) => (),              //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Slice(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::RawPtr(..) => (),           //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Ref(..) => (),              //~ ERROR usage of `ty::TyKind::<kind>`
diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
index 2ff5aad95dd..53bf5cb1a82 100644
--- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
+++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
@@ -67,119 +67,125 @@ LL |         TyKind::Array(..) => (),
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:25:9
    |
-LL |         TyKind::Slice(..) => (),
+LL |         TyKind::Pat(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:26:9
    |
-LL |         TyKind::RawPtr(..) => (),
+LL |         TyKind::Slice(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:27:9
    |
-LL |         TyKind::Ref(..) => (),
+LL |         TyKind::RawPtr(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:28:9
    |
-LL |         TyKind::FnDef(..) => (),
+LL |         TyKind::Ref(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:29:9
    |
-LL |         TyKind::FnPtr(..) => (),
+LL |         TyKind::FnDef(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:30:9
    |
-LL |         TyKind::Dynamic(..) => (),
+LL |         TyKind::FnPtr(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:31:9
    |
-LL |         TyKind::Closure(..) => (),
+LL |         TyKind::Dynamic(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:32:9
    |
-LL |         TyKind::CoroutineClosure(..) => (),
+LL |         TyKind::Closure(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:33:9
    |
-LL |         TyKind::Coroutine(..) => (),
+LL |         TyKind::CoroutineClosure(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:34:9
    |
-LL |         TyKind::CoroutineWitness(..) => (),
+LL |         TyKind::Coroutine(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:35:9
    |
-LL |         TyKind::Never => (),
+LL |         TyKind::CoroutineWitness(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:36:9
    |
-LL |         TyKind::Tuple(..) => (),
+LL |         TyKind::Never => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:37:9
    |
-LL |         TyKind::Alias(..) => (),
+LL |         TyKind::Tuple(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:38:9
    |
-LL |         TyKind::Param(..) => (),
+LL |         TyKind::Alias(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:39:9
    |
-LL |         TyKind::Bound(..) => (),
+LL |         TyKind::Param(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:40:9
    |
-LL |         TyKind::Placeholder(..) => (),
+LL |         TyKind::Bound(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:41:9
    |
-LL |         TyKind::Infer(..) => (),
+LL |         TyKind::Placeholder(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:42:9
    |
+LL |         TyKind::Infer(..) => (),
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
+
+error: usage of `ty::TyKind::<kind>`
+  --> $DIR/ty_tykind_usage.rs:43:9
+   |
 LL |         TyKind::Error(_) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:47:12
+  --> $DIR/ty_tykind_usage.rs:48:12
    |
 LL |     if let TyKind::Int(int_ty) = kind {}
    |            ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:49:24
+  --> $DIR/ty_tykind_usage.rs:50:24
    |
 LL |     fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
    |                        ^^^^^^^^^^
@@ -187,7 +193,7 @@ LL |     fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:51:37
+  --> $DIR/ty_tykind_usage.rs:52:37
    |
 LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    |                                     ^^^^^^^^^^^
@@ -195,7 +201,7 @@ LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:51:53
+  --> $DIR/ty_tykind_usage.rs:52:53
    |
 LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    |                                                     ^^^^^^^^^^^
@@ -203,12 +209,12 @@ LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:54:9
+  --> $DIR/ty_tykind_usage.rs:55:9
    |
 LL |         IrTyKind::Bool
    |         --------^^^^^^
    |         |
    |         help: try using `ty::<kind>` directly: `ty`
 
-error: aborting due to 33 previous errors
+error: aborting due to 34 previous errors
 
diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr
index c1cbefac828..6ce0ae09195 100644
--- a/tests/ui/symbol-names/basic.legacy.stderr
+++ b/tests/ui/symbol-names/basic.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN5basic4main17h6fc0c8d27b1a289fE)
+error: symbol-name(_ZN5basic4main17had874e876c8b1028E)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(basic::main::h6fc0c8d27b1a289f)
+error: demangling(basic::main::had874e876c8b1028)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr
index 7dd68e6e3a8..cc4eec470fb 100644
--- a/tests/ui/symbol-names/issue-60925.legacy.stderr
+++ b/tests/ui/symbol-names/issue-60925.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hab58a402db4ebf3aE)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17haf0d0ad2255e29c6E)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hab58a402db4ebf3a)
+error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::haf0d0ad2255e29c6)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
diff --git a/tests/ui/type/pattern_types/bad_pat.rs b/tests/ui/type/pattern_types/bad_pat.rs
new file mode 100644
index 00000000000..8ad042eeba6
--- /dev/null
+++ b/tests/ui/type/pattern_types/bad_pat.rs
@@ -0,0 +1,14 @@
+#![feature(pattern_types)]
+#![feature(core_pattern_types)]
+#![feature(core_pattern_type)]
+
+use std::pat::pattern_type;
+
+type NonNullU32_2 = pattern_type!(u32 is 1..=);
+//~^ ERROR: inclusive range with no end
+type Positive2 = pattern_type!(i32 is 0..=);
+//~^ ERROR: inclusive range with no end
+type Wild = pattern_type!(() is _);
+//~^ ERROR: wildcard patterns are not permitted for pattern types
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/bad_pat.stderr b/tests/ui/type/pattern_types/bad_pat.stderr
new file mode 100644
index 00000000000..4f0f0bc9742
--- /dev/null
+++ b/tests/ui/type/pattern_types/bad_pat.stderr
@@ -0,0 +1,25 @@
+error[E0586]: inclusive range with no end
+  --> $DIR/bad_pat.rs:7:43
+   |
+LL | type NonNullU32_2 = pattern_type!(u32 is 1..=);
+   |                                           ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/bad_pat.rs:9:40
+   |
+LL | type Positive2 = pattern_type!(i32 is 0..=);
+   |                                        ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error: "wildcard patterns are not permitted for pattern types"
+  --> $DIR/bad_pat.rs:11:33
+   |
+LL | type Wild = pattern_type!(() is _);
+   |                                 ^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0586`.
diff --git a/tests/ui/type/pattern_types/derives.noimpl.stderr b/tests/ui/type/pattern_types/derives.noimpl.stderr
new file mode 100644
index 00000000000..9450e575344
--- /dev/null
+++ b/tests/ui/type/pattern_types/derives.noimpl.stderr
@@ -0,0 +1,14 @@
+error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
+  --> $DIR/derives.rs:14:20
+   |
+LL | #[derive(Clone, Copy, PartialEq)]
+   |                       --------- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+   |                    ^^^^^^^
+   |
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/type/pattern_types/derives.rs b/tests/ui/type/pattern_types/derives.rs
new file mode 100644
index 00000000000..b8b53e61102
--- /dev/null
+++ b/tests/ui/type/pattern_types/derives.rs
@@ -0,0 +1,20 @@
+//! Check that pattern types don't implement traits of their base automatically
+
+#![feature(pattern_types)]
+#![feature(core_pattern_types)]
+#![feature(core_pattern_type)]
+
+use std::pat::pattern_type;
+
+#[derive(Clone, Copy, PartialEq)]
+#[repr(transparent)]
+struct Nanoseconds(NanoI32);
+//~^ ERROR: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
+
+type NanoI32 = crate::pattern_type!(i32 is 0..=999_999_999);
+
+fn main() {
+    let x = Nanoseconds(unsafe { std::mem::transmute(42) });
+    let y = x.clone();
+    if y == x {}
+}
diff --git a/tests/ui/type/pattern_types/derives.stderr b/tests/ui/type/pattern_types/derives.stderr
new file mode 100644
index 00000000000..1d4d3fc55c3
--- /dev/null
+++ b/tests/ui/type/pattern_types/derives.stderr
@@ -0,0 +1,14 @@
+error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
+  --> $DIR/derives.rs:11:20
+   |
+LL | #[derive(Clone, Copy, PartialEq)]
+   |                       --------- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+   |                    ^^^^^^^
+   |
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.rs b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs
new file mode 100644
index 00000000000..3c507a9669d
--- /dev/null
+++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Zno-analysis
+
+use std::pat::pattern_type;
+
+type NonNullU32 = pattern_type!(u32 is 1..);
+//~^ use of unstable library feature 'core_pattern_type'
+type Percent = pattern_type!(u32 is 0..=100);
+//~^ use of unstable library feature 'core_pattern_type'
+type Negative = pattern_type!(i32 is ..=0);
+//~^ use of unstable library feature 'core_pattern_type'
+type Positive = pattern_type!(i32 is 0..);
+//~^ use of unstable library feature 'core_pattern_type'
+type Always = pattern_type!(Option<u32> is Some(_));
+//~^ use of unstable library feature 'core_pattern_type'
diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr
new file mode 100644
index 00000000000..6f74b89d224
--- /dev/null
+++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr
@@ -0,0 +1,48 @@
+error[E0658]: use of unstable library feature 'core_pattern_type'
+  --> $DIR/feature-gate-pattern_types.rs:5:19
+   |
+LL | type NonNullU32 = pattern_type!(u32 is 1..);
+   |                   ^^^^^^^^^^^^
+   |
+   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'core_pattern_type'
+  --> $DIR/feature-gate-pattern_types.rs:7:16
+   |
+LL | type Percent = pattern_type!(u32 is 0..=100);
+   |                ^^^^^^^^^^^^
+   |
+   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'core_pattern_type'
+  --> $DIR/feature-gate-pattern_types.rs:9:17
+   |
+LL | type Negative = pattern_type!(i32 is ..=0);
+   |                 ^^^^^^^^^^^^
+   |
+   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'core_pattern_type'
+  --> $DIR/feature-gate-pattern_types.rs:11:17
+   |
+LL | type Positive = pattern_type!(i32 is 0..);
+   |                 ^^^^^^^^^^^^
+   |
+   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'core_pattern_type'
+  --> $DIR/feature-gate-pattern_types.rs:13:15
+   |
+LL | type Always = pattern_type!(Option<u32> is Some(_));
+   |               ^^^^^^^^^^^^
+   |
+   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs b/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs
new file mode 100644
index 00000000000..d7b3ea58e02
--- /dev/null
+++ b/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: -Zno-analysis
+//@ check-pass
+
+#![feature(core_pattern_type)]
+
+use std::pat::pattern_type;
+
+type NonNullU32 = pattern_type!(u32 is 1..);
+type Percent = pattern_type!(u32 is 0..=100);
+type Negative = pattern_type!(i32 is ..=0);
+type Positive = pattern_type!(i32 is 0..);
+type Always = pattern_type!(Option<u32> is Some(_));
diff --git a/tests/ui/type/pattern_types/macros.active.stderr b/tests/ui/type/pattern_types/macros.active.stderr
new file mode 100644
index 00000000000..002e944fe2e
--- /dev/null
+++ b/tests/ui/type/pattern_types/macros.active.stderr
@@ -0,0 +1,10 @@
+error: `$t:ty` is followed by `is`, which is not allowed for `ty` fragments
+  --> $DIR/macros.rs:10:12
+   |
+LL |     ($t:ty is $p:pat) => {};
+   |            ^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/type/pattern_types/macros.gated.stderr b/tests/ui/type/pattern_types/macros.gated.stderr
new file mode 100644
index 00000000000..002e944fe2e
--- /dev/null
+++ b/tests/ui/type/pattern_types/macros.gated.stderr
@@ -0,0 +1,10 @@
+error: `$t:ty` is followed by `is`, which is not allowed for `ty` fragments
+  --> $DIR/macros.rs:10:12
+   |
+LL |     ($t:ty is $p:pat) => {};
+   |            ^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/type/pattern_types/macros.rs b/tests/ui/type/pattern_types/macros.rs
new file mode 100644
index 00000000000..fd5fe257e8e
--- /dev/null
+++ b/tests/ui/type/pattern_types/macros.rs
@@ -0,0 +1,15 @@
+//@ revisions: gated active
+
+#![cfg_attr(active, feature(pattern_types))]
+#![allow(incomplete_features)]
+
+// Check that pattern types do not affect existing macros.
+// They don't, because pattern types don't have surface syntax.
+
+macro_rules! foo {
+    ($t:ty is $p:pat) => {}; //~ ERROR `$t:ty` is followed by `is`, which is not allowed for `ty` fragments
+}
+
+fn main() {
+    foo!(u32 is 1..)
+}
diff --git a/tests/ui/type/pattern_types/range_patterns.rs b/tests/ui/type/pattern_types/range_patterns.rs
new file mode 100644
index 00000000000..d1fd055dbab
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns.rs
@@ -0,0 +1,23 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+
+//@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
+
+use std::pat::pattern_type;
+
+#[rustc_layout(debug)]
+type X = std::num::NonZeroU32; //~ ERROR layout_of
+#[rustc_layout(debug)]
+type Y = pattern_type!(u32 is 1..); //~ ERROR layout_of
+#[rustc_layout(debug)]
+type Z = Option<pattern_type!(u32 is 1..)>; //~ ERROR layout_of
+#[rustc_layout(debug)]
+type A = Option<std::num::NonZeroU32>; //~ ERROR layout_of
+#[rustc_layout(debug)]
+struct NonZeroU32New(pattern_type!(u32 is 1..)); //~ ERROR layout_of
+
+fn main() {
+    let x: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(42_u32) };
+}
diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr
new file mode 100644
index 00000000000..8465e1b7ff2
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns.stderr
@@ -0,0 +1,343 @@
+error: layout_of(NonZero<u32>) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Scalar(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 1..=4294967295,
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 1..=4294967295,
+               },
+           ),
+           variants: Single {
+               index: 0,
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/range_patterns.rs:11:1
+   |
+LL | type X = std::num::NonZeroU32;
+   | ^^^^^^
+
+error: layout_of((u32) is 1..=) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Scalar(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 1..=4294967295,
+               },
+           ),
+           fields: Primitive,
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 1..=4294967295,
+               },
+           ),
+           variants: Single {
+               index: 0,
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/range_patterns.rs:13:1
+   |
+LL | type Y = pattern_type!(u32 is 1..);
+   | ^^^^^^
+
+error: layout_of(Option<(u32) is 1..=>) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Scalar(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: (..=0) | (1..),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: None,
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: (..=0) | (1..),
+               },
+               tag_encoding: Niche {
+                   untagged_variant: 1,
+                   niche_variants: 0..=0,
+                   niche_start: 0,
+               },
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Scalar(
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 1..=4294967295,
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(0 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: Some(
+                           Niche {
+                               offset: Size(0 bytes),
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 1..=4294967295,
+                           },
+                       ),
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/range_patterns.rs:15:1
+   |
+LL | type Z = Option<pattern_type!(u32 is 1..)>;
+   | ^^^^^^
+
+error: layout_of(Option<NonZero<u32>>) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Scalar(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: (..=0) | (1..),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: None,
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: (..=0) | (1..),
+               },
+               tag_encoding: Niche {
+                   untagged_variant: 1,
+                   niche_variants: 0..=0,
+                   niche_start: 0,
+               },
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Scalar(
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 1..=4294967295,
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(0 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: Some(
+                           Niche {
+                               offset: Size(0 bytes),
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 1..=4294967295,
+                           },
+                       ),
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/range_patterns.rs:17:1
+   |
+LL | type A = Option<std::num::NonZeroU32>;
+   | ^^^^^^
+
+error: layout_of(NonZeroU32New) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Scalar(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 1..=4294967295,
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 1..=4294967295,
+               },
+           ),
+           variants: Single {
+               index: 0,
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/range_patterns.rs:19:1
+   |
+LL | struct NonZeroU32New(pattern_type!(u32 is 1..));
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs b/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs
new file mode 100644
index 00000000000..9653a744c41
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs
@@ -0,0 +1,30 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+
+//! check that pattern types can have traits implemented for them if
+//! their base type is a local type.
+
+use std::pat::pattern_type;
+
+type Y = pattern_type!(u32 is 1..);
+
+impl Y {
+    //~^ ERROR cannot define inherent `impl`
+    fn foo() {}
+}
+
+struct MyStruct<T>(T);
+
+impl MyStruct<Y> {
+    fn foo() {}
+}
+
+struct Wrapper(Y);
+
+impl Wrapper {
+    fn foo() {}
+}
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr b/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr
new file mode 100644
index 00000000000..784ebb0c9f0
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr
@@ -0,0 +1,16 @@
+error[E0390]: cannot define inherent `impl` for primitive types outside of `core`
+  --> $DIR/range_patterns_inherent_impls.rs:13:1
+   |
+LL | impl Y {
+   | ^^^^^^
+   |
+   = help: consider moving this inherent impl into `core` if possible
+help: alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
+  --> $DIR/range_patterns_inherent_impls.rs:15:5
+   |
+LL |     fn foo() {}
+   |     ^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0390`.
diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls.rs b/tests/ui/type/pattern_types/range_patterns_trait_impls.rs
new file mode 100644
index 00000000000..f8c9af86281
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_trait_impls.rs
@@ -0,0 +1,19 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+
+//! check that pattern types can have local traits
+//! implemented for them.
+
+//@ check-pass
+
+use std::pat::pattern_type;
+
+type Y = pattern_type!(u32 is 1..);
+
+trait Trait {}
+
+impl Trait for Y {}
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs b/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs
new file mode 100644
index 00000000000..acde4580c1b
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs
@@ -0,0 +1,16 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+
+//! check that pattern types can have local traits
+//! implemented for them.
+
+use std::pat::pattern_type;
+
+type Y = pattern_type!(u32 is 1..);
+
+impl Eq for Y {}
+//~^ ERROR: only traits defined in the current crate can be implemented for arbitrary types
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr
new file mode 100644
index 00000000000..41f42455bde
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr
@@ -0,0 +1,14 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/range_patterns_trait_impls2.rs:13:1
+   |
+LL | impl Eq for Y {}
+   | ^^^^^^^^^^^^-
+   | |           |
+   | |           `(u32) is 1..=` is not defined in the current crate
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/tests/ui/type/pattern_types/range_patterns_unusable.rs b/tests/ui/type/pattern_types/range_patterns_unusable.rs
new file mode 100644
index 00000000000..7cde44f4133
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_unusable.rs
@@ -0,0 +1,15 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+
+//! Some practical niche checks.
+
+use std::pat::pattern_type;
+
+type Z = Option<pattern_type!(u32 is 1..)>;
+
+fn main() {
+    let z: Z = Some(unsafe { std::mem::transmute(42_u32) });
+    let _: Option<u32> = unsafe { std::mem::transmute(z) }; //~ ERROR: different sizes
+}
diff --git a/tests/ui/type/pattern_types/range_patterns_unusable.stderr b/tests/ui/type/pattern_types/range_patterns_unusable.stderr
new file mode 100644
index 00000000000..aa0e592684b
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_unusable.stderr
@@ -0,0 +1,12 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/range_patterns_unusable.rs:14:35
+   |
+LL |     let _: Option<u32> = unsafe { std::mem::transmute(z) };
+   |                                   ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `Option<(u32) is 1..=>` (32 bits)
+   = note: target type: `Option<u32>` (64 bits)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0512`.
diff --git a/tests/ui/type/pattern_types/range_patterns_unusable_math.rs b/tests/ui/type/pattern_types/range_patterns_unusable_math.rs
new file mode 100644
index 00000000000..bc1ab75429d
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_unusable_math.rs
@@ -0,0 +1,16 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+
+//! check that pattern types don't have an `Add` impl.
+
+use std::pat::pattern_type;
+
+type Y = pattern_type!(u32 is 1..);
+type Z = Option<pattern_type!(u32 is 1..)>;
+
+fn main() {
+    let x: Y = unsafe { std::mem::transmute(42_u32) };
+    let x = x + 1_u32; //~ ERROR cannot add `u32` to `(u32) is 1..=`
+}
diff --git a/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr b/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr
new file mode 100644
index 00000000000..e52d899a703
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr
@@ -0,0 +1,11 @@
+error[E0369]: cannot add `u32` to `(u32) is 1..=`
+  --> $DIR/range_patterns_unusable_math.rs:15:15
+   |
+LL |     let x = x + 1_u32;
+   |             - ^ ----- u32
+   |             |
+   |             (u32) is 1..=
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/type/pattern_types/range_patterns_usage.rs b/tests/ui/type/pattern_types/range_patterns_usage.rs
new file mode 100644
index 00000000000..7fe50423c51
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_usage.rs
@@ -0,0 +1,26 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+//@ check-pass
+
+//! check that pattern types can actually be part of code that compiles successfully.
+
+use std::pat::pattern_type;
+
+type X = std::num::NonZeroU32;
+type Y = pattern_type!(u32 is 1..);
+type Z = Option<pattern_type!(u32 is 1..)>;
+struct NonZeroU32New(pattern_type!(u32 is 1..));
+
+fn main() {
+    let x: Y = unsafe { std::mem::transmute(42_u32) };
+    let z: Z = Some(unsafe { std::mem::transmute(42_u32) });
+    match z {
+        Some(y) => {
+            let _: Y = y;
+        }
+        None => {}
+    }
+    let x: X = unsafe { std::mem::transmute(x) };
+}