Skip to content

Commit 0fe88f5

Browse files
committed
Allow const patterns of matches to contain pattern types
1 parent b9856b6 commit 0fe88f5

File tree

9 files changed

+244
-9
lines changed

9 files changed

+244
-9
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -1568,11 +1568,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
15681568
}
15691569
}
15701570
CastKind::Transmute => {
1571-
span_mirbug!(
1572-
self,
1573-
rvalue,
1574-
"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
1575-
);
1571+
let ty_from = op.ty(self.body, tcx);
1572+
match ty_from.kind() {
1573+
ty::Pat(base, _) if base == ty => {}
1574+
_ => span_mirbug!(
1575+
self,
1576+
rvalue,
1577+
"Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR",
1578+
),
1579+
}
15761580
}
15771581
}
15781582
}

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

+27-2
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
140140
let success_block = target_block(TestBranch::Success);
141141
let fail_block = target_block(TestBranch::Failure);
142142

143-
let expect_ty = value.ty();
144-
let expect = self.literal_operand(test.span, value);
143+
let mut expect_ty = value.ty();
144+
let mut expect = self.literal_operand(test.span, value);
145145

146146
let mut place = place;
147147
let mut block = block;
@@ -174,6 +174,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
174174
place = ref_str;
175175
ty = ref_str_ty;
176176
}
177+
&ty::Pat(base, _) => {
178+
assert_eq!(ty, value.ty());
179+
assert!(base.is_trivially_pure_clone_copy());
180+
181+
let transmuted_place = self.temp(base, test.span);
182+
self.cfg.push_assign(
183+
block,
184+
self.source_info(scrutinee_span),
185+
transmuted_place,
186+
Rvalue::Cast(CastKind::Transmute, Operand::Copy(place), base),
187+
);
188+
189+
let transmuted_expect = self.temp(base, test.span);
190+
self.cfg.push_assign(
191+
block,
192+
self.source_info(test.span),
193+
transmuted_expect,
194+
Rvalue::Cast(CastKind::Transmute, expect, base),
195+
);
196+
197+
place = transmuted_place;
198+
expect = Operand::Copy(transmuted_expect);
199+
ty = base;
200+
expect_ty = base;
201+
}
177202
_ => {}
178203
}
179204

tests/ui/type/pattern_types/derives.rs

+2-1
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
#![feature(pattern_types)]
45
#![feature(pattern_type_macro)]

tests/ui/type/pattern_types/derives.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
2-
--> $DIR/derives.rs:10:20
2+
--> $DIR/derives.rs:14:20
33
|
44
LL | #[derive(Clone, Copy, PartialEq)]
55
| --------- in this derive macro expansion
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
10+
#[repr(transparent)]
11+
struct Nanoseconds(NanoI32);
12+
//~^ ERROR: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied
13+
//~| ERROR: `(i32) is 0..=999999999` doesn't implement `Debug`
14+
//~| ERROR: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied
15+
//~| ERROR: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied
16+
//~| ERROR: the trait bound `(i32) is 0..=999999999: Default` is not satisfied
17+
//~| ERROR: can't compare `(i32) is 0..=999999999` with `_`
18+
//~| ERROR: `==` cannot be applied
19+
20+
type NanoI32 = crate::pattern_type!(i32 is 0..=999_999_999);
21+
22+
fn main() {
23+
let x = Nanoseconds(unsafe { std::mem::transmute(42) });
24+
let y = x.clone();
25+
if y == x {}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
2+
--> $DIR/derives_fail.rs:11: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+
| ^^^^^^^
9+
|
10+
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
11+
12+
error[E0277]: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied
13+
--> $DIR/derives_fail.rs:11:20
14+
|
15+
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
16+
| -- in this derive macro expansion
17+
LL | #[repr(transparent)]
18+
LL | struct Nanoseconds(NanoI32);
19+
| ^^^^^^^ the trait `Eq` is not implemented for `(i32) is 0..=999999999`
20+
|
21+
note: required by a bound in `AssertParamIsEq`
22+
--> $SRC_DIR/core/src/cmp.rs:LL:COL
23+
= note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
24+
25+
error[E0277]: `(i32) is 0..=999999999` doesn't implement `Debug`
26+
--> $DIR/derives_fail.rs:11:20
27+
|
28+
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
29+
| ----- in this derive macro expansion
30+
LL | #[repr(transparent)]
31+
LL | struct Nanoseconds(NanoI32);
32+
| ^^^^^^^ `(i32) is 0..=999999999` cannot be formatted using `{:?}` because it doesn't implement `Debug`
33+
|
34+
= help: the trait `Debug` is not implemented for `(i32) is 0..=999999999`
35+
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
36+
37+
error[E0277]: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied
38+
--> $DIR/derives_fail.rs:11: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+
| ^^^^^^^ the trait `Ord` is not implemented for `(i32) is 0..=999999999`
45+
|
46+
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info)
47+
48+
error[E0277]: can't compare `(i32) is 0..=999999999` with `_`
49+
--> $DIR/derives_fail.rs:11:20
50+
|
51+
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
52+
| ---------- in this derive macro expansion
53+
LL | #[repr(transparent)]
54+
LL | struct Nanoseconds(NanoI32);
55+
| ^^^^^^^ no implementation for `(i32) is 0..=999999999 < _` and `(i32) is 0..=999999999 > _`
56+
|
57+
= help: the trait `PartialOrd<_>` is not implemented for `(i32) is 0..=999999999`
58+
= note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info)
59+
60+
error[E0277]: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied
61+
--> $DIR/derives_fail.rs:11: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 `Hash` is not implemented for `(i32) is 0..=999999999`
68+
|
69+
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
70+
71+
error[E0277]: the trait bound `(i32) is 0..=999999999: Default` is not satisfied
72+
--> $DIR/derives_fail.rs:11:20
73+
|
74+
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
75+
| ------- in this derive macro expansion
76+
LL | #[repr(transparent)]
77+
LL | struct Nanoseconds(NanoI32);
78+
| ^^^^^^^ the trait `Default` is not implemented for `(i32) is 0..=999999999`
79+
|
80+
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
81+
82+
error: aborting due to 7 previous errors
83+
84+
Some errors have detailed explanations: E0277, E0369.
85+
For more information about an error, try `rustc --explain E0277`.
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
struct Thing(pattern_type!(u32 is 1..));
9+
10+
impl StructuralPartialEq for Thing {}
11+
impl PartialEq for Thing {
12+
fn eq(&self, other: &Thing) -> bool {
13+
unsafe { std::mem::transmute::<_, u32>(self.0) == std::mem::transmute::<_, u32>(other.0) }
14+
}
15+
}
16+
17+
impl Eq for Thing {}
18+
19+
const TWO: Thing = Thing(2);
20+
21+
const _: () = match TWO {
22+
TWO => {}
23+
_ => unreachable!(),
24+
};
25+
26+
fn main() {}
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() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error: constant of non-structural type `(u32) is 1..` in a pattern
2+
--> $DIR/matching_fail.rs:8:5
3+
|
4+
LL | const THREE: pattern_type!(u32 is 1..) = 3;
5+
| -------------------------------------- constant defined here
6+
...
7+
LL | THREE => {}
8+
| ^^^^^ constant of non-structural type
9+
|
10+
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
11+
12+
error[E0308]: mismatched types
13+
--> $DIR/matching_fail.rs:14:5
14+
|
15+
LL | const _: () = match THREE {
16+
| ----- this expression has type `(u32) is 1..`
17+
LL | 3 => {}
18+
| ^ expected `(u32) is 1..`, found integer
19+
|
20+
= note: expected pattern type `(u32) is 1..`
21+
found type `{integer}`
22+
23+
error[E0308]: mismatched types
24+
--> $DIR/matching_fail.rs:20:5
25+
|
26+
LL | const THREE: pattern_type!(u32 is 1..) = 3;
27+
| -------------------------------------- constant defined here
28+
...
29+
LL | const _: () = match 3 {
30+
| - this expression has type `{integer}`
31+
LL | THREE => {}
32+
| ^^^^^
33+
| |
34+
| expected integer, found `(u32) is 1..`
35+
| `THREE` is interpreted as a constant, not a new binding
36+
| help: introduce a new binding instead: `other_three`
37+
|
38+
= note: expected type `{integer}`
39+
found pattern type `(u32) is 1..`
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)