Try   HackMD

Removal of auto trait in favor of #[rustc_auto_trait]

Introduction

Auto traits are no longer intended to be stabilized and made available to the general public[1].
They should remain solely an implementation detail of blessed libraries like core and std.

Proposal

To reflect this new status of auto traits, I hereby propose to remove the syntax auto trait alongside the feature auto_traits it is gated behind and to introduce the attribute #[rustc_auto_trait] as part of the internal feature rustc_attrs.

#![feature(auto_traits)]

auto trait Trait {}

// ---->

#![feature(rustc_attrs)]
#![allow(internal_features)]

#[rustc_auto_trait]
trait Trait {}

Motivation

It sends the wrong signals to have custom syntax for this, for all intents and purposes, internal feature. It may mislead end users to believe that auto traits will eventually be stabilized which is unlikely.

An internal attribute with an off-putting name like rustc_auto_trait should slowly steer users away from this feature. People who currently make use of auto traits in their projects will hopefully think twice about opting into rustc_attrs in order to continue using auto traits when they migrate to the latest nightly compiler and regard it only as a short-term solution if they do end up keeping their auto traits around.

Regarding the motivation to not stabilize the feature for others to use freely, I can't speak for T-lang but I can list the biggest pitfalls of auto traits. See Pitfalls of Auto Traits.

Lastly, it allows us to simplify the HIR.

Drawbacks

  • Obviously, experimental features don't come with stability guarantees. Still, in reality some users like to think that experimental features will generally be stabilized someday modulo some adjustments and use them anyway in their larger projects. For them this change would be quite disruptive and require them to potentially do a lot of non-trivial work to migrate away from auto traits causing churn in the ecosystem. See Affected Projects.
  • Fully removing the syntax is a breaking change for stable users since cfg'ed out auto traits successfully compile on stable as auto_traits uses a post-expansion feature gate due to historical reasons. Unfortunately, this is not a hypothetical, stable users of leptos-rs/leptos and Pyo3/pyo3 would be affected.
    Note however that the plan is to keep parsing auto trait for now and to reject it after macro expansion which would solve this in the meantime. See Steps.
    As a matter of fact, to this day we accept the original syntax of auto traits (or rather opt-in built-in traits) if it's cfg'ed out: #[cfg(FALSE)] impl Trait for .. {} which could be a warning to us.
  • The following points are less about the proposed changes to the surface language and more about the notion of considering auto traits as internal only:
    • With the prospect of auto traits being stabilized at some point gone, standard library traits like Send, Sync, Unpin, UnwindSafe and RefUnwindSafe may feel more “special” and more “exotic”.
    • Auto traits might be essential or at least very nice to model certain problem domains (see Affected Projects) and if so should be available to all users.

Alternatives

  • Don't do anything. This may lead to more and more users adapting and starting to rely on auto traits together with all of their pitfalls (see Pitfalls of Auto Traits).
  • Keep the syntax but mark auto_traits as internal. This would lead to less churn in the ecosystem but it might not send a strong enough message to users already depending on auto traits (contrary to first-time users) since it's easier to silence the warning than to address it properly.

Steps

  1. PR #116126: Reject auto trait after macro expansion but continue to parse it which is necessary for bootstrapping. Introduce #[rustc_auto_trait] behind the rustc_attrs feature and remove the auto_traits feature.
  2. Issue #116121: Emit a future-incompat warning for auto trait before macro expansion to successfully lint against cfg'ed out auto traits etc.
  3. After a set grace period which at the earliest starts after the next beta bump that occurs after the PR above has been merged, the syntax can be removed from the parser and the AST if at all possible (see Drawbacks).

Future Possibilities

It's always possible to move the status of the feature from internal back to experimental and change the attribute from #[rustc_auto_trait] to #[auto_trait]. We can also reintroduce the syntax auto trait. However, it's unclear how the macro fragment specifier item can then be updated without breaking backward compatibility. Generally, macro fragment specifiers are not forward compatible (see inline_const for example) which needs be solved at some point.

Pitfalls of Auto Traits

  • Private struct fields leak auto trait implementations into the public API
    • Changing the type of a private field of a public ADT may accidentally result in the whole type not implementing a given auto trait which can break downstream users unbeknownst to the library author
    • If the standard library is the only one allowed to define auto traits, the issue will persist but it will also be more manageable since end users can theoretically enumerate all auto traits in their head before changing the type of a field or use one of the many assert_impls_auto_trait!(Ty, Tr0, Tr1, …) helper macros available on crates.io to ensure that they don't introduce regressions.
      If auto_traits was stabilized, it would be plain out impossible to do anything remotely similar since downstream users could define arbitrary amounts of auto traits together with negative implementations which the upstream user has not the slightest clue about.
  • Opaque types like RPIT and TAIT leak auto trait implementations. This leads to a very similar situation as described above.

Affected Projects

There might be many more since the ones above are merely from the first few pages of the search results (GitHub Advanced Search / Code Search).


  1. https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Removal.20of.20.60auto.20trait.60.20syntax/near/392487050 ↩︎