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

Don't use double ref vars in Debug derive #380

Merged
merged 2 commits into from
Jul 4, 2024
Merged

Conversation

JelteF
Copy link
Owner

@JelteF JelteF commented Jul 3, 2024

Related to #289
Related to #328

Synopsis

While looking into #328 I realized the current situation around Pointer derives
and references was even weirder because we store a double-reference to the
fields in the local variables for Debug, but not for Display. The reason we
were doing this was because of #289.

Solution

This stops storing a double-reference, and only adds the additional reference
in the places where its needed.

@JelteF JelteF added this to the 1.0.0 milestone Jul 3, 2024
@JelteF JelteF added docs and removed docs labels Jul 3, 2024
@JelteF JelteF self-assigned this Jul 3, 2024
@JelteF JelteF requested a review from tyranron July 3, 2024 15:15
@tyranron tyranron enabled auto-merge (squash) July 4, 2024 09:53
@tyranron tyranron merged commit 974824a into master Jul 4, 2024
17 checks passed
@tyranron tyranron deleted the no-double-ref-debug branch July 4, 2024 09:55
tyranron added a commit that referenced this pull request Jul 31, 2024
Resolves #328
Requires #377
Requires #380 

## Synopsis

`Debug` and `Display` derives allow referring fields via short syntax
(`_0` for unnamed fields and `name` for named fields):
```rust
#[derive(Display)]
#[display("{_0:o}")]
struct OctalInt(i32);
```
The way this works is by introducing a local binding in the macro
expansion:
```rust
let _0 = &self.0;
```

This, however, introduces double pointer indirection. For most of the
`fmt` traits, this is totally OK. However, the `fmt::Pointer` is
sensitive to that:
```rust
#[derive(Display)]
#[display("--> {_0:p}")]
struct Int(&'static i32);

// expands to
impl fmt::Display for Int {
    fn fmt(&self, f: fmt::Formatter<'_>) -> fmt::Result {
        let _0 = &self.0; // has `&&i32` type, not `&i32`
        write!(f, "--> {_0:p}") // so, prints address of the `_0` local binding, 
                                // not the one of the `self.0` field as we would expect
    }
}
```


## Solution

Pass all local bindings also as named parameters and dereference them
there.
This allows `"{_0:p}"` to work as expected. Positional arguments and
expressions
still have the previous behaviour. This seems okay IMHO, as we can
explain
that in expressions these local bindings are references and that you
need
to dereference when needed, such as for `Pointer`.

A downside of the current implementation is that users cannot use the
names of our named parameters as names for their own named parameters,
because we already use them. With some additional code this is fixable,
but it doesn't seem important enough to fix. People can simply use a
different name when creating their own named parameters, which is a good
idea anyway because it will be less confusing to any reader of the code.
If it turns out to be important to support this after all, we can still
start to support it in a backwards compatible way (because now it causes
a compilation failure).

Co-authored-by: Kai Ren <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants