From 0943ca7d560d29f045ba23dc154ef751a3502773 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 13 May 2024 14:59:23 +0200 Subject: [PATCH 1/3] Add a policy for inclusion in the prelude --- src/SUMMARY.md | 1 + src/policy/prelude.md | 56 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/policy/prelude.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 712c3af..20368e2 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -21,6 +21,7 @@ - [Doc alias policy](./policy/doc-alias.md) - [Safety comments policy](./policy/safety-comments.md) - [Reviewing target-specific code](./policy/target-code.md) + - [Policy for inclusion in the prelude](./policy/prelude.md) - [Tricky situations]() - [Drop and `#[may_dangle]`](./tricky/may-dangle.md) diff --git a/src/policy/prelude.md b/src/policy/prelude.md new file mode 100644 index 0000000..ecd8d97 --- /dev/null +++ b/src/policy/prelude.md @@ -0,0 +1,56 @@ +Policy for inclusion in the prelude +=================================== + +The Rust standard library provides a "prelude": items that Rust programs can +use without having to import anything. For instance, the Rust prelude includes +[`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html), so programs can +write `Vec::with_capacity(4)` without having to first import `Vec` from the +standard library. + +Each edition of Rust has its own prelude, so that new editions of Rust may add +items without making those items available to all code in older editions of +Rust. + +This policy sets out the requirements for what items we add to the prelude, and +whether we add those items to the prelude for a future edition or to the common +prelude for all Rust editions. + +When to use editions +-------------------- + +Adding a trait to the prelude can break existing Rust code, by creating name +resolution ambiguity where none previously existed. While introducing +resolution ambiguities may be "permitted breakage", doing so is quite +disruptive, and we want to avoid doing so. Thus, we generally never add a trait +to the common prelude; we only add traits to the prelude for a new edition of +Rust. + +Adding items *other* than traits to the prelude will never produce conflicts or +other compatibility issues with existing code, since we allow shadowing and +give other sources of names priority over names from the prelude. Thus, if we +choose to add a non-trait item to the prelude, we should typically add it to +the common prelude for all editions of Rust. (Exceptions to this would include +names that form part of an edition transition, such that the same name resolves +to something different in different editions.) + +Criteria for including an item +------------------------------ + +An item included in the prelude can be used by its unqualified name, by any +Rust code. Users can look up the item by name, and easily get documentation for +it. However, in general the name should make sense without any context, such as +within a diff hunk or code sample. Any name we include in the prelude should be +one that will not confuse users if they see it unqualified, without anything +introducing the name. + +In particular, the name should not be something users are likely to +misunderstand as coming from the local crate or its dependencies. While any +crate *could* define any name, the names in the prelude should be *unlikely* to +occur unqualified in another crate. (A conflict with a name typically used +qualified or in a different context is not a problem; for instance, a common +method name `Object::name`, commonly called via `expr.name`, does not +necessarily preclude adding a free function `name` to the prelude.) + +We should only add an item to the prelude if some reasonable number of crates +are likely to use the item. It need not be an item used by the *majority* of +crates, but it should be reasonably frequent across the ecosystem. From 471152ca9b3e363d4630f34eca95352e30af7a6b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 14 Jul 2024 16:55:01 -0700 Subject: [PATCH 2/3] Add information about breaking changes when adding types to the prelude --- src/breaking-changes/prelude.md | 12 +++++++++++- src/policy/prelude.md | 29 +++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/breaking-changes/prelude.md b/src/breaking-changes/prelude.md index cf38517..0f84f72 100644 --- a/src/breaking-changes/prelude.md +++ b/src/breaking-changes/prelude.md @@ -1,7 +1,7 @@ # Breaking changes to the prelude Making changes to the prelude can easily cause breakage because it impacts all Rust code. -In most cases the impact is limited since prelude items have the lowest priority in name lookup (lower than glob imports), but there are two cases where this doesn't work. +In most cases the impact is limited since prelude items have the lowest priority in name lookup (lower than glob imports), but there are three cases where this requires additional care or may not be possible. ## Traits @@ -16,3 +16,13 @@ Unlike other item types, rustc's name resolution for macros does not support giv As a general rule, avoid adding macros to the prelude except at edition boundaries. This issues was encoutered when trying to land the [`assert_matches!` macro](https://github.com/rust-lang/rust/issues/82913). + +## Types + +Adding a new type usually doesn't create any breakage, because prelude types have a lower priority than names in user code. + +However, code that declares an enum, *and* has a derive on that enum, *and* attempts to locally import a variant from that enum (e.g. `use EnumType::Variant;`) will break if the prelude starts exporting a type with the same name as that enum. + +This makes adding a new type to the prelude require a crater run to check for breakage in existing Rust code. + +If Rust code declares a local variable binding and the prelude adds a type of the same name, this can likewise introduce breakage. This case is much less likely to arise, as it requires declaring a variable name using the `CamelCase` convention typically used for types, and ignoring rustc's warnings about doing so. diff --git a/src/policy/prelude.md b/src/policy/prelude.md index ecd8d97..697e9b4 100644 --- a/src/policy/prelude.md +++ b/src/policy/prelude.md @@ -18,20 +18,33 @@ prelude for all Rust editions. When to use editions -------------------- +[Some kinds of additions to the prelude can cause breakage in existing +code](../breaking-changes/prelude.md), so we must either avoid making such +changes entirely or check carefully with crater before making them. + Adding a trait to the prelude can break existing Rust code, by creating name resolution ambiguity where none previously existed. While introducing resolution ambiguities may be "permitted breakage", doing so is quite disruptive, and we want to avoid doing so. Thus, we generally never add a trait -to the common prelude; we only add traits to the prelude for a new edition of +to the common prelude; we only add traits to the preludes for new editions of Rust. -Adding items *other* than traits to the prelude will never produce conflicts or -other compatibility issues with existing code, since we allow shadowing and -give other sources of names priority over names from the prelude. Thus, if we -choose to add a non-trait item to the prelude, we should typically add it to -the common prelude for all editions of Rust. (Exceptions to this would include -names that form part of an edition transition, such that the same name resolves -to something different in different editions.) +Likewise, adding a macro to the prelude can break existing code, so we +generally can't add macros to the common prelude, and can only add macros to +the preludes for new editions of Rust. + +Finally, in some cases adding a type to the prelude can break existing code. +The cases in which this arises are narrower, but still require at a minimum +checking a crater run. + +Adding items other than traits, macros, or types to the prelude will never +produce conflicts or other compatibility issues with existing code, since we +allow shadowing and give other sources of names priority over names from the +prelude. Thus, if we choose to add another kind of item to the prelude, we +should typically add it to the common prelude for all editions of Rust. +(Exceptions to this would include names that form part of an edition +transition, such that the same name resolves to something different in +different editions.) Criteria for including an item ------------------------------ From 8faf5a0c94bcb1fa2915c49432f0738c3c9a1fb0 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 14 Jul 2024 16:55:31 -0700 Subject: [PATCH 3/3] Fix typo --- src/breaking-changes/prelude.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/breaking-changes/prelude.md b/src/breaking-changes/prelude.md index 0f84f72..5b18ac1 100644 --- a/src/breaking-changes/prelude.md +++ b/src/breaking-changes/prelude.md @@ -15,7 +15,7 @@ For this reason, [`TryFrom` and `TryInto`](https://github.com/rust-lang/rust/iss Unlike other item types, rustc's name resolution for macros does not support giving prelude macros a lower priority than other macros, even if the macro is unstable. As a general rule, avoid adding macros to the prelude except at edition boundaries. -This issues was encoutered when trying to land the [`assert_matches!` macro](https://github.com/rust-lang/rust/issues/82913). +This issue was encountered when trying to land the [`assert_matches!` macro](https://github.com/rust-lang/rust/issues/82913). ## Types