-
Notifications
You must be signed in to change notification settings - Fork 1.7k
RFC: Trait Implementation Privacy with permits
#3903
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
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| # RFC: Trait Implementation Privacy with `permits` | ||
|
|
||
| - Feature Name: `trait_permits` | ||
| - Start Date: 2026-01-03 | ||
| - RFC PR: rust-lang/rfcs#0000 | ||
| - Rust Issue: rust-lang/rust#0000 | ||
|
|
||
| ## Summary | ||
|
|
||
| Introduce a new syntax for restricting trait implementations to specific crates: | ||
|
|
||
| ```rust | ||
| trait Test permits mycrate_extra, crate { | ||
| fn run(&self); | ||
| } | ||
| ``` | ||
|
|
||
| Motivation | ||
HackingRepo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Rust currently allows any downstream crate to implement traits for types they own, subject to the orphan rules. While flexible, this can lead to: | ||
|
|
||
| Accidental or malicious impls: External crates can implement traits in ways that break invariants. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If a malicious impl can cause memory safety issues, then the trait must be marked If it can't, then API design, documentation, assertions, and tests are usually the way this gets resolved. Are there specific scenarios where these aren't enough? |
||
|
|
||
| Audit difficulty: It is hard to know which crates are allowed to implement a trait. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is generally very simple to work out how the Orphan Rule applies. The |
||
|
|
||
| Boilerplate sealed traits: Developers often use the "sealed trait" pattern to prevent external impls, which is verbose and indirect. | ||
|
|
||
| By introducing permits, Rust gains a first-class mechanism for trait implementation privacy, improving safety and clarity. | ||
|
|
||
| Detailed Design | ||
HackingRepo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Syntax | ||
| A trait definition may include a permits clause: | ||
|
|
||
| ```rust | ||
| trait TraitName permits crate, other_crate, another_crate { | ||
| fn method(&self); | ||
| } | ||
| ``` | ||
|
|
||
| crate refers to the defining crate. | ||
|
|
||
| Other identifiers refer to external crates by name. | ||
HackingRepo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| If no permits clause is present, behavior is unchanged (any crate may implement the trait, subject to orphan rules). | ||
|
|
||
| # Semantics | ||
| Only the listed crates may provide impl TraitName for Type. | ||
|
|
||
| Attempting to implement the trait in a non-permitted crate results in a compiler error. | ||
|
|
||
| Trait objects (&dyn TraitName) remain usable across crates, but only permitted crates can provide concrete impls. | ||
|
|
||
| Example | ||
| ```rust | ||
| // In mycrate/lib.rs | ||
| pub trait Test permits crate, mycrate_extra { | ||
| fn run(&self); | ||
| } | ||
|
|
||
| // In mycrate_extra/lib.rs | ||
| use mycrate::Test; | ||
|
|
||
| struct ExtraType; | ||
| impl Test for ExtraType { | ||
| fn run(&self) { println!("extra"); } | ||
| } | ||
|
|
||
| // In othercrate/lib.rs | ||
| use mycrate::Test; | ||
|
|
||
| struct OtherType; | ||
| impl Test for OtherType { | ||
| fn run(&self) { println!("other"); } | ||
| } | ||
| // ERROR: Trait `Test` does not permit implementations in `othercrate` | ||
| ``` | ||
|
|
||
| # Drawbacks | ||
| Reduced flexibility: Downstream crates cannot extend traits unless explicitly permitted. | ||
|
|
||
| Ecosystem impact: Existing crates relying on open trait impls may break if traits adopt permits. | ||
|
|
||
| Complexity: Adds another axis of privacy control to the language. | ||
|
|
||
| Alternatives | ||
| Continue using the sealed trait pattern (private marker traits). | ||
|
|
||
| Use documentation and conventions to discourage external impls. | ||
|
|
||
| Unresolved Questions | ||
| Should permits support paths (e.g., permits crate::submodule)? | ||
|
|
||
| How does this interact with crate renaming in Cargo? | ||
|
|
||
| Should permits apply to blanket impls (impl<T> Trait for T)? | ||
|
|
||
| Future Directions | ||
| Extend permits to allow finer-grained control (e.g., permitting only certain modules). | ||
|
|
||
| Combine with unsafe traits to enforce stricter safety boundaries. | ||
|
|
||
| Explore integration with Cargo features for conditional permitting. | ||
|
|
||
|
|
||
| The permits syntax provides a direct, ergonomic way to restrict trait implementations to specific crates, improving safety, auditability, and clarity compared to current patterns. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how does the upstream trait declaration knows the name of the downstream crate name provide the impls? any crate can call themselves
mycrate_extra, so this does not prevent "malicious impls" mentioned on line 21 at all