Skip to content

Commit 66d404d

Browse files
committed
Do not implement StructuralPartialEq always
1 parent 738aaa0 commit 66d404d

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

text/3869-ignore-derive.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,77 @@ This RFC additionally proposes to add 2 new deny-by-default lints:
483483
because it is logically incorrect for the implementations to differ.
484484
See the [documentation](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) for details.
485485

486+
## Standard library derives supporting the `ignore` attribute
487+
488+
- `PartialEq`
489+
- `PartialOrd`
490+
- `Ord`
491+
- `Debug`
492+
- `Hash`
493+
494+
### `#[derive(PartialEq)]` does not implement `StructuralPartialEq` if any fields are ignored
495+
496+
By default, `#[derive(PartialEq)]` automatically implements [`StructuralPartialEq`](https://doc.rust-lang.org/std/marker/trait.StructuralPartialEq.html),
497+
and the invariant automatically upheld is the following:
498+
499+
> interpreting the value of the constant as a pattern is equivalent to calling PartialEq
500+
501+
Essentially, given any type `Foo` implementing `PartialEq`, both A and B must be identical:
502+
503+
```rust
504+
#[derive(PartialEq)]
505+
struct Foo {
506+
foo: u32,
507+
bar: bool
508+
}
509+
const FOO: Foo = Foo { foo: 10, bar: false };
510+
511+
// A
512+
match foo {
513+
FOO => print!("ok"),
514+
_ => panic!()
515+
}
516+
517+
// B
518+
match foo {
519+
Foo { foo: 10, bar: false } => print!("ok"),
520+
_ => panic!()
521+
}
522+
```
523+
524+
But if any field is `#[ignore(PartialEq)]`d, then the property would be violated:
525+
526+
```rust
527+
#[derive(PartialEq)]
528+
struct Foo {
529+
foo: u32,
530+
#[ignore(PartialEq)]
531+
bar: bool
532+
}
533+
const FOO: Foo = Foo { foo: 10, bar: false };
534+
535+
// Then this
536+
match foo {
537+
FOO => print!("not ok"),
538+
_ => panic!()
539+
}
540+
541+
// Is actually this:
542+
match foo {
543+
Foo { foo: 10, bar /* doesn't matter */ } => print!("not ok"),
544+
_ => panic!()
545+
}
546+
547+
// The above is NOT equivalent to this:
548+
549+
match foo {
550+
Foo { foo: 10, bar: false } => print!("ok"),
551+
_ => panic!()
552+
}
553+
```
554+
555+
Hence any type deriving `PartialEq` with ignored fields will not implement `StructuralPartialEq` automatically
556+
486557
# Drawbacks
487558
[drawbacks]: #drawbacks
488559

@@ -715,3 +786,34 @@ we could upgrade the 2 currently useless forms of `#[ignore]` (without parenthes
715786
deny-by-default future incompatibility lint - just to be safe.
716787

717788
This lint is not part of the RFC, and can be discussed separately.
789+
790+
## `ignore` with arguments
791+
792+
Some derives need to know how to ignore a field. It could be possible to allow passing arguments to paths in `ignore`:
793+
794+
```rust
795+
#[derive(MyTrait)]
796+
struct S {
797+
#[ignore(MyTrait(<args>))] // <args> is any token stream
798+
foo: Foo,
799+
#[ignore(MyTrait)]
800+
bar: Bar,
801+
#[ignore(MyTrait = <arg>)] // <arg> is any expression
802+
baz: Baz,
803+
}
804+
```
805+
806+
Which would give the following input to `MyTrait`:
807+
808+
```rust
809+
struct S {
810+
#[ignore(<args>)]
811+
foo: Foo,
812+
#[ignore]
813+
bar: Bar,
814+
#[ignore = <arg>]
815+
baz: Baz,
816+
}
817+
```
818+
819+
efault field values would

0 commit comments

Comments
 (0)