Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow const patterns of matches to contain pattern types #138393

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1568,11 +1568,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
CastKind::Transmute => {
span_mirbug!(
self,
rvalue,
"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
);
let ty_from = op.ty(self.body, tcx);
match ty_from.kind() {
ty::Pat(base, _) if base == ty => {}
_ => span_mirbug!(
self,
rvalue,
"Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR",
),
}
}
}
}
Expand Down
29 changes: 27 additions & 2 deletions compiler/rustc_mir_build/src/builder/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let success_block = target_block(TestBranch::Success);
let fail_block = target_block(TestBranch::Failure);

let expect_ty = value.ty();
let expect = self.literal_operand(test.span, value);
let mut expect_ty = value.ty();
let mut expect = self.literal_operand(test.span, value);

let mut place = place;
let mut block = block;
Expand Down Expand Up @@ -174,6 +174,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place = ref_str;
ty = ref_str_ty;
}
&ty::Pat(base, _) => {
assert_eq!(ty, value.ty());
assert!(base.is_trivially_pure_clone_copy());

let transmuted_place = self.temp(base, test.span);
self.cfg.push_assign(
block,
self.source_info(scrutinee_span),
transmuted_place,
Rvalue::Cast(CastKind::Transmute, Operand::Copy(place), base),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment explaining that we only support pattern types on the basic scalar types rn which all implement Copy so its fine to just unconditionally do a Operand::Copy here instead of the usual "is it copy mod regions" thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added an assert for is_trivially_pure_clone_copy()

);

let transmuted_expect = self.temp(base, test.span);
self.cfg.push_assign(
block,
self.source_info(test.span),
transmuted_expect,
Rvalue::Cast(CastKind::Transmute, expect, base),
);

place = transmuted_place;
expect = Operand::Copy(transmuted_expect);
ty = base;
expect_ty = base;
}
_ => {}
}

Expand Down
3 changes: 2 additions & 1 deletion tests/ui/type/pattern_types/derives.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Check that pattern types don't implement traits of their base automatically
//! Check that pattern types don't implement traits of their base automatically.
//! Exceptions are `Clone` and `Copy`.

#![feature(pattern_types)]
#![feature(pattern_type_macro)]
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/type/pattern_types/derives.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
--> $DIR/derives.rs:10:20
--> $DIR/derives.rs:11:20
|
LL | #[derive(Clone, Copy, PartialEq)]
| --------- in this derive macro expansion
Expand Down
26 changes: 26 additions & 0 deletions tests/ui/type/pattern_types/derives_fail.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//! Check that pattern types don't implement traits of their base automatically.
//! Exceptions are `Clone` and `Copy`.

#![feature(pattern_types)]
#![feature(pattern_type_macro)]

use std::pat::pattern_type;

#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
#[repr(transparent)]
struct Nanoseconds(NanoI32);
//~^ ERROR: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied
//~| ERROR: `(i32) is 0..=999999999` doesn't implement `Debug`
//~| ERROR: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied
//~| ERROR: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied
//~| ERROR: the trait bound `(i32) is 0..=999999999: Default` is not satisfied
//~| ERROR: can't compare `(i32) is 0..=999999999` with `_`
//~| ERROR: `==` cannot be applied

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 {}
}
74 changes: 74 additions & 0 deletions tests/ui/type/pattern_types/derives_fail.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
--> $DIR/derives_fail.rs:11:20
|
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
| --------- in this derive macro expansion
LL | #[repr(transparent)]
LL | struct Nanoseconds(NanoI32);
| ^^^^^^^

error[E0277]: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied
--> $DIR/derives_fail.rs:11:20
|
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
| -- in this derive macro expansion
LL | #[repr(transparent)]
LL | struct Nanoseconds(NanoI32);
| ^^^^^^^ the trait `Eq` is not implemented for `(i32) is 0..=999999999`
|
note: required by a bound in `AssertParamIsEq`
--> $SRC_DIR/core/src/cmp.rs:LL:COL

error[E0277]: `(i32) is 0..=999999999` doesn't implement `Debug`
--> $DIR/derives_fail.rs:11:20
|
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
| ----- in this derive macro expansion
LL | #[repr(transparent)]
LL | struct Nanoseconds(NanoI32);
| ^^^^^^^ `(i32) is 0..=999999999` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
= help: the trait `Debug` is not implemented for `(i32) is 0..=999999999`

error[E0277]: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied
--> $DIR/derives_fail.rs:11:20
|
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
| --- in this derive macro expansion
LL | #[repr(transparent)]
LL | struct Nanoseconds(NanoI32);
| ^^^^^^^ the trait `Ord` is not implemented for `(i32) is 0..=999999999`

error[E0277]: can't compare `(i32) is 0..=999999999` with `_`
--> $DIR/derives_fail.rs:11:20
|
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
| ---------- in this derive macro expansion
LL | #[repr(transparent)]
LL | struct Nanoseconds(NanoI32);
| ^^^^^^^ no implementation for `(i32) is 0..=999999999 < _` and `(i32) is 0..=999999999 > _`
|
= help: the trait `PartialOrd<_>` is not implemented for `(i32) is 0..=999999999`

error[E0277]: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied
--> $DIR/derives_fail.rs:11:20
|
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
| ---- in this derive macro expansion
LL | #[repr(transparent)]
LL | struct Nanoseconds(NanoI32);
| ^^^^^^^ the trait `Hash` is not implemented for `(i32) is 0..=999999999`

error[E0277]: the trait bound `(i32) is 0..=999999999: Default` is not satisfied
--> $DIR/derives_fail.rs:11:20
|
LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
| ------- in this derive macro expansion
LL | #[repr(transparent)]
LL | struct Nanoseconds(NanoI32);
| ^^^^^^^ the trait `Default` is not implemented for `(i32) is 0..=999999999`

error: aborting due to 7 previous errors

Some errors have detailed explanations: E0277, E0369.
For more information about an error, try `rustc --explain E0277`.
26 changes: 26 additions & 0 deletions tests/ui/type/pattern_types/matching.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#![feature(pattern_types, pattern_type_macro, structural_match)]

//@ check-pass

use std::marker::StructuralPartialEq;
use std::pat::pattern_type;

struct Thing(pattern_type!(u32 is 1..));

impl StructuralPartialEq for Thing {}
impl PartialEq for Thing {
fn eq(&self, other: &Thing) -> bool {
unsafe { std::mem::transmute::<_, u32>(self.0) == std::mem::transmute::<_, u32>(other.0) }
}
}

impl Eq for Thing {}

const TWO: Thing = Thing(2);

const _: () = match TWO {
TWO => {}
_ => unreachable!(),
};

fn main() {}
25 changes: 25 additions & 0 deletions tests/ui/type/pattern_types/matching_fail.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#![feature(pattern_types, pattern_type_macro, structural_match)]

use std::pat::pattern_type;

const THREE: pattern_type!(u32 is 1..) = 3;

const _: () = match THREE {
THREE => {}
//~^ ERROR non-structural type
_ => unreachable!(),
};

const _: () = match THREE {
3 => {}
//~^ ERROR mismatched types
_ => unreachable!(),
};

const _: () = match 3 {
THREE => {}
//~^ ERROR mismatched types
_ => unreachable!(),
};

fn main() {}
43 changes: 43 additions & 0 deletions tests/ui/type/pattern_types/matching_fail.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
error: constant of non-structural type `(u32) is 1..` in a pattern
--> $DIR/matching_fail.rs:8:5
|
LL | const THREE: pattern_type!(u32 is 1..) = 3;
| -------------------------------------- constant defined here
...
LL | THREE => {}
| ^^^^^ constant of non-structural type
|
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details

error[E0308]: mismatched types
--> $DIR/matching_fail.rs:14:5
|
LL | const _: () = match THREE {
| ----- this expression has type `(u32) is 1..`
LL | 3 => {}
| ^ expected `(u32) is 1..`, found integer
|
= note: expected pattern type `(u32) is 1..`
found type `{integer}`

error[E0308]: mismatched types
--> $DIR/matching_fail.rs:20:5
|
LL | const THREE: pattern_type!(u32 is 1..) = 3;
| -------------------------------------- constant defined here
...
LL | const _: () = match 3 {
| - this expression has type `{integer}`
LL | THREE => {}
| ^^^^^
| |
| expected integer, found `(u32) is 1..`
| `THREE` is interpreted as a constant, not a new binding
| help: introduce a new binding instead: `other_three`
|
= note: expected type `{integer}`
found pattern type `(u32) is 1..`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0308`.
Loading