Skip to content

Commit 29dc446

Browse files
committed
Allow matching on consts of pattern types
1 parent 7264436 commit 29dc446

File tree

8 files changed

+229
-8
lines changed

8 files changed

+229
-8
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,11 +2192,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
21922192
}
21932193
}
21942194
CastKind::Transmute => {
2195-
span_mirbug!(
2196-
self,
2197-
rvalue,
2198-
"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
2199-
);
2195+
let ty_from = op.ty(body, tcx);
2196+
match ty_from.kind() {
2197+
ty::Pat(base, _) if base == ty => {}
2198+
_ => span_mirbug!(
2199+
self,
2200+
rvalue,
2201+
"Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR",
2202+
),
2203+
}
22002204
}
22012205
}
22022206
}

compiler/rustc_mir_build/src/builder/matches/test.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
147147
let success_block = target_block(TestBranch::Success);
148148
let fail_block = target_block(TestBranch::Failure);
149149

150-
let expect_ty = value.ty();
151-
let expect = self.literal_operand(test.span, value);
150+
let mut expect_ty = value.ty();
151+
let mut expect = self.literal_operand(test.span, value);
152152

153153
let mut place = place;
154154
let mut block = block;
@@ -181,6 +181,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
181181
place = ref_str;
182182
ty = ref_str_ty;
183183
}
184+
&ty::Pat(base, _) => {
185+
assert_eq!(ty, value.ty());
186+
187+
let transmuted_place = self.temp(base, test.span);
188+
self.cfg.push_assign(
189+
block,
190+
self.source_info(scrutinee_span),
191+
transmuted_place,
192+
Rvalue::Cast(CastKind::Transmute, Operand::Copy(place), base),
193+
);
194+
195+
let transmuted_expect = self.temp(base, test.span);
196+
self.cfg.push_assign(
197+
block,
198+
self.source_info(test.span),
199+
transmuted_expect,
200+
Rvalue::Cast(CastKind::Transmute, expect, base),
201+
);
202+
203+
place = transmuted_place;
204+
expect = Operand::Copy(transmuted_expect);
205+
ty = base;
206+
expect_ty = base;
207+
}
184208
_ => {}
185209
}
186210

tests/ui/type/pattern_types/derives.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
//! Check that pattern types don't implement traits of their base automatically
1+
//! Check that pattern types don't implement traits of their base automatically.
2+
//! Exceptions are `Clone` and `Copy`.
23
34
//@ check-pass
45

@@ -7,6 +8,9 @@
78

89
use std::pat::pattern_type;
910

11+
// PartialEq works here as a derive, because internally it calls
12+
// `==` on the field, which causes coercion to coerce the pattern
13+
// type to its base type first.
1014
#[derive(Clone, Copy, PartialEq)]
1115
#[repr(transparent)]
1216
struct Nanoseconds(NanoI32);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//! Check that pattern types don't implement traits of their base automatically.
2+
//! Exceptions are `Clone` and `Copy`.
3+
4+
#![feature(pattern_types)]
5+
#![feature(pattern_type_macro)]
6+
7+
use std::pat::pattern_type;
8+
9+
// PartialEq works here as a derive, because internally it calls
10+
// `==` on the field, which causes coercion to coerce the pattern
11+
// type to its base type first.
12+
#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
13+
#[repr(transparent)]
14+
struct Nanoseconds(NanoI32);
15+
//~^ ERROR: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied
16+
//~| ERROR: `(i32) is 0..=999999999` doesn't implement `Debug`
17+
//~| ERROR: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied
18+
//~| ERROR: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied
19+
//~| ERROR: the trait bound `(i32) is 0..=999999999: Default` is not satisfied
20+
//~| ERROR: can't compare `(i32) is 0..=999999999` with `_`
21+
22+
type NanoI32 = crate::pattern_type!(i32 is 0..=999_999_999);
23+
24+
fn main() {
25+
let x = Nanoseconds(unsafe { std::mem::transmute(42) });
26+
let y = x.clone();
27+
if y == x {}
28+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
error[E0277]: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied
2+
--> $DIR/derives_fail.rs:14:20
3+
|
4+
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
5+
| -- in this derive macro expansion
6+
LL | #[repr(transparent)]
7+
LL | struct Nanoseconds(NanoI32);
8+
| ^^^^^^^ the trait `Eq` is not implemented for `(i32) is 0..=999999999`
9+
|
10+
note: required by a bound in `AssertParamIsEq`
11+
--> $SRC_DIR/core/src/cmp.rs:LL:COL
12+
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
13+
14+
error[E0277]: `(i32) is 0..=999999999` doesn't implement `Debug`
15+
--> $DIR/derives_fail.rs:14:20
16+
|
17+
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
18+
| ----- in this derive macro expansion
19+
LL | #[repr(transparent)]
20+
LL | struct Nanoseconds(NanoI32);
21+
| ^^^^^^^ `(i32) is 0..=999999999` cannot be formatted using `{:?}` because it doesn't implement `Debug`
22+
|
23+
= help: the trait `Debug` is not implemented for `(i32) is 0..=999999999`
24+
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
25+
26+
error[E0277]: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied
27+
--> $DIR/derives_fail.rs:14:20
28+
|
29+
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
30+
| --- in this derive macro expansion
31+
LL | #[repr(transparent)]
32+
LL | struct Nanoseconds(NanoI32);
33+
| ^^^^^^^ the trait `Ord` is not implemented for `(i32) is 0..=999999999`
34+
|
35+
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
36+
37+
error[E0277]: can't compare `(i32) is 0..=999999999` with `_`
38+
--> $DIR/derives_fail.rs:14:20
39+
|
40+
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
41+
| ---------- in this derive macro expansion
42+
LL | #[repr(transparent)]
43+
LL | struct Nanoseconds(NanoI32);
44+
| ^^^^^^^ no implementation for `(i32) is 0..=999999999 < _` and `(i32) is 0..=999999999 > _`
45+
|
46+
= help: the trait `PartialOrd<_>` is not implemented for `(i32) is 0..=999999999`
47+
= note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
48+
49+
error[E0277]: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied
50+
--> $DIR/derives_fail.rs:14:20
51+
|
52+
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
53+
| ---- in this derive macro expansion
54+
LL | #[repr(transparent)]
55+
LL | struct Nanoseconds(NanoI32);
56+
| ^^^^^^^ the trait `Hash` is not implemented for `(i32) is 0..=999999999`
57+
|
58+
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
59+
60+
error[E0277]: the trait bound `(i32) is 0..=999999999: Default` is not satisfied
61+
--> $DIR/derives_fail.rs:14:20
62+
|
63+
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
64+
| ------- in this derive macro expansion
65+
LL | #[repr(transparent)]
66+
LL | struct Nanoseconds(NanoI32);
67+
| ^^^^^^^ the trait `Default` is not implemented for `(i32) is 0..=999999999`
68+
|
69+
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
70+
71+
error: aborting due to 6 previous errors
72+
73+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![feature(pattern_types, pattern_type_macro, structural_match)]
2+
3+
//@ check-pass
4+
5+
use std::marker::StructuralPartialEq;
6+
use std::pat::pattern_type;
7+
8+
#[derive(PartialEq)]
9+
struct Thing(pattern_type!(u32 is 1..));
10+
11+
impl Eq for Thing {}
12+
13+
const TWO: Thing = Thing(2);
14+
15+
const _: () = match TWO {
16+
TWO => {}
17+
_ => unreachable!(),
18+
};
19+
20+
fn main() {}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#![feature(pattern_types, pattern_type_macro, structural_match)]
2+
3+
use std::pat::pattern_type;
4+
5+
const THREE: pattern_type!(u32 is 1..) = 3;
6+
7+
const _: () = match THREE {
8+
THREE => {}
9+
//~^ ERROR non-structural type
10+
_ => unreachable!(),
11+
};
12+
13+
const _: () = match THREE {
14+
3 => {}
15+
//~^ ERROR mismatched types
16+
_ => unreachable!(),
17+
};
18+
19+
const _: () = match 3 {
20+
THREE => {}
21+
//~^ ERROR mismatched types
22+
_ => unreachable!(),
23+
};
24+
25+
fn main() {}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/matching_fail.rs:14:5
3+
|
4+
LL | const _: () = match THREE {
5+
| ----- this expression has type `(u32) is 1..`
6+
LL | 3 => {}
7+
| ^ expected `(u32) is 1..`, found integer
8+
|
9+
= note: expected pattern type `(u32) is 1..`
10+
found type `{integer}`
11+
12+
error[E0308]: mismatched types
13+
--> $DIR/matching_fail.rs:20:5
14+
|
15+
LL | const THREE: pattern_type!(u32 is 1..) = 3;
16+
| -------------------------------------- constant defined here
17+
...
18+
LL | const _: () = match 3 {
19+
| - this expression has type `{integer}`
20+
LL | THREE => {}
21+
| ^^^^^
22+
| |
23+
| expected integer, found `(u32) is 1..`
24+
| `THREE` is interpreted as a constant, not a new binding
25+
| help: introduce a new binding instead: `other_three`
26+
|
27+
= note: expected type `{integer}`
28+
found pattern type `(u32) is 1..`
29+
30+
error: constant of non-structural type `(u32) is 1..` in a pattern
31+
--> $DIR/matching_fail.rs:8:5
32+
|
33+
LL | const THREE: pattern_type!(u32 is 1..) = 3;
34+
| -------------------------------------- constant defined here
35+
...
36+
LL | THREE => {}
37+
| ^^^^^ constant of non-structural type
38+
|
39+
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
40+
41+
error: aborting due to 3 previous errors
42+
43+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)