Skip to content

#[derive] fails to detect associated type when qualified path is used #50730

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

Open
durka opened this issue May 14, 2018 · 1 comment
Open

#[derive] fails to detect associated type when qualified path is used #50730

durka opened this issue May 14, 2018 · 1 comment
Labels
A-associated-items Area: Associated items (types, constants & functions) A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@durka
Copy link
Contributor

durka commented May 14, 2018

The deriving code scans the field types in order to generate bounds on associated types, if they happen to be used as a field type (this isn't foolproof but it catches a lot of cases).

/// This method helps to extract all the type parameters referenced from a
/// type. For a type parameter `<T>`, it looks for either a `TyPath` that
/// is not global and starts with `T`, or a `TyQPath`.

The comment in this code implies that field: T::Assoc and field: <T as Trait>::Assoc would both work. However, the second one is missed and the required bound is not generated, resulting in a type error:

#[derive(Debug)]
struct Foo<T: FromStr> {
    field: <T as FromStr>::Err
}
error[E0277]: `<T as std::str::FromStr>::Err` doesn't implement `std::fmt::Debug`
  --> expr.rs:18:77
   |
18 |     field: <T as FromStr>::Err
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ `<T as std::str::FromStr>::Err` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
   |
   = help: the trait `std::fmt::Debug` is not implemented for `<T as std::str::FromStr>::Err`
   = help: consider adding a `where <T as std::str::FromStr>::Err: std::fmt::Debug` bound
   = note: required because of the requirements on the impl of `std::fmt::Debug` for `&<T as std::str::FromStr>::Err`
   = note: required for the cast to the object type `std::fmt::Debug`

cc #26925.

@XAMPPRocky XAMPPRocky added A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-bug Category: This is a bug. labels Oct 2, 2018
bors added a commit to rust-lang/rust-analyzer that referenced this issue Jun 7, 2023
…lbasi

fix: only generate trait bound for associated types in field types

Given the following definitions:

```rust
trait Trait {
    type A;
    type B;
    type C;
}

#[derive(Clone)]
struct S<T: Trait>
where
    T::A: Send,
{
    qualified: <T as Trait>::B,
    shorthand: T::C,
}
```

we currently expand the derive macro to:

```rust
impl<T> Clone for S<T>
where
    T: Trait + Clone,
    T::A: Clone,
    T::B: Clone,
    T::C: Clone,
{ /* ... */ }
```

This does not match how rustc expands it. Specifically, `Clone` bounds for `T::A` and `T::B` should not be generated.

The criteria for associated types to get bound seem to be 1) the associated type appears as part of field types AND 2) it's written in the shorthand form. I have no idea why rustc doesn't consider qualified associated types (there's even a comment that suggests they should be considered; see rust-lang/rust#50730), but it's important to follow rustc.
@fmease fmease added A-associated-items Area: Associated items (types, constants & functions) T-types Relevant to the types team, which will review and decide on the PR/issue. and removed T-types Relevant to the types team, which will review and decide on the PR/issue. labels Aug 29, 2024
@fmease
Copy link
Member

fmease commented Aug 29, 2024

Triage 2024: No change.

@fmease fmease added the T-types Relevant to the types team, which will review and decide on the PR/issue. label Nov 20, 2024
@fmease fmease marked this as a duplicate of #139231 Apr 2, 2025
bors added a commit to rust-lang-ci/rust that referenced this issue May 7, 2025
…pes, r=<try>

Fix derive bounds for fully-qualified field types

Builtin traits like `Clone`, `Debug`, and `PartialEq` which can be derived look for uses of generics when adding type bounds. However, the procedure for adding these trait bounds did not account for fully-qualified type paths. This causes code which does not fully-qualify paths to generate correct derive bounds, while fully-qualified paths do not receive correct bounds. For example:

```
#[derive(Clone)]
struct Foo<T: MyTrait>(T::MyType);
```

Will receive the correct `T::MyType: Clone` bound, but:

```
#[derive(Clone)]
struct Foo<T: MyTrait>(<T>::MyType);
```

Does not. This change modifies generic parameter detection to walk up the chain of `QSelf`s in path types when looking for type parameters, rather than only looking at the outermost type.

Related issues:
- rust-lang#50730
- rkyv/rkyv#602

Note that there are existing tests for this behavior. However, the existing tests accidentally include fields with the working syntax (`T::MyType`) alongside fields with the broken syntax (`<T>::MyType`) and so this issue has gone undiscovered.

This is a conservative fix; it aims only to make previously-invalid code valid. It does not attempt to move the builtin derive macros closer to a perfect derive.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-associated-items Area: Associated items (types, constants & functions) A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants