Skip to content

Commit 409f3dd

Browse files
committed
Revise options for #[refine]
Emphasize the possibility of continuing to use `#[refine]` in future editions, and list out all the options under Unresolved Questions. Include the attribute in examples. Simplify the usage of `#[refine]` in existing editions so that it is needed to refine any aspect of an API, instead of new features being refine-able by default and old ones needing the attribute. Move any discussion of *not* doing a soft transition to Unresolved Questions to simplify the Reference Level Explanation a bit.
1 parent d035998 commit 409f3dd

File tree

1 file changed

+28
-48
lines changed

1 file changed

+28
-48
lines changed

text/3245-refined-impls.md

Lines changed: 28 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ trait Error {
103103
}
104104

105105
impl Error for MyError {
106+
#[refine]
106107
fn description(&self) -> &'static str {
107108
"My Error Message"
108109
}
@@ -130,6 +131,7 @@ trait Iterable {
130131
}
131132

132133
impl<T> Iterable for MyVec<T> {
134+
#[refine]
133135
fn iter(&self) -> impl Iterator + ExactSizeIterator { ... }
134136
}
135137
```
@@ -142,6 +144,7 @@ trait Sink {
142144
}
143145

144146
impl Sink for SimpleSink {
147+
#[refine]
145148
fn consume(&mut self, input: impl Iterator) { ... }
146149
}
147150
```
@@ -187,56 +190,33 @@ Refined APIs are available anywhere knowledge of the impl being used is availabl
187190

188191
## Transitioning away from the current behavior
189192

190-
Because we allow writing impls that look refined, but are [not usable][not-usable] as such, landing this feature means we are auto-stabilizing new ecosystem API surface. There are two ways of dealing with this:
191-
192-
### Do nothing
193-
194-
Assume that public types want to expose the APIs they actually wrote in their implementations, and allow using those APIs immediately.
195-
196-
### Soft transition
193+
Because we allow writing impls that look refined, but are [not usable][not-usable] as such, landing this feature could mean auto-stabilizing new ecosystem API surface. We should probably be conservative and require library authors to opt in to refined APIs with a `#[refine]` attribute. This can be done in two parts.
197194

198-
Be conservative and require library authors to opt in to refined APIs. This can be done in two parts.
199-
200-
#### Lint against unmarked refined impls
195+
### Lint against unmarked refined impls
201196

202197
After this RFC is merged, we should warn when a user writes an impl that looks refined and suggest that they copy the exact API of the trait they are implementing. Once this feature stabilizes, we can should add and suggest using `#[refine]` attribute to mark that an impl is intentionally refined.
203198

204-
#### Automatic migration for the next edition
199+
### Automatic migration for the next edition
205200

206-
Because refinement will be the default behavior for the next edition, we should rewrite users' code to preserve its semantics over edition migrations. That means we will replace trait implementations that look refined with the original API of the trait items being implemented.
201+
We may want to upgrade the above lint to an error in 2024 or make refinement the default without any attribute at all. In either of these cases, we should have an automatic edition migration that rewrites users' code to preserve its semantics. That means we will replace trait implementations that look refined with the original API of the trait items being implemented.
207202

208-
#### Documentation
203+
### Documentation
209204

210-
The following text should be added to document the difference in editions.
205+
The following can be added to the reference to document the difference in editions.
211206

212-
For historical reasons, not all kinds of refinement are automatically supported in older editions.
207+
#### `#[refine]` attribute
213208

214-
| Item kind | Feature | Edition |
215-
| ----------- | ------------------------------- | -------------- |
216-
| Type | - | All editions |
217-
| Method | Unsafe | All editions |
218-
| Method | Const[^future] | All editions|
219-
| Method | impl Trait in return position[^future]| All editions|
220-
| Method | Lifetimes | 2024 and newer |
221-
| Method | Where clauses | 2024 and newer |
222-
| Method | impl Trait in argument position | 2024 and newer |
223-
| Const | Lifetimes | 2024 and newer |
224-
| Const | Where clauses | 2024 and newer |
209+
Refinements of trait items that do not match the API of the trait exactly must be accompanied by a `#[refine]` attribute on the item in Rust 2021 and older editions.[^refine-edition]
225210

226-
[^future]: This feature is not accepted at the time of writing the RFC; it is included here for demonstration purposes.
211+
For historical reasons, we allow valid refinements on the following features in Rust 2021 and earlier without a `#[refine]` attribute. However, no refinements are available to callers without this attribute; it will be as if the trait API was copied directly.
227212

228-
You can opt in to the new behavior in older editions with a `#[refine]` attribute on the associated item.
213+
* Lifetimes
214+
* Where clauses
215+
* impl Trait in argument position
216+
* Lifetimes
217+
* Where clauses
229218

230-
```rust
231-
impl Error for MyError {
232-
#[refine]
233-
fn description(&self) -> &'static str {
234-
"My Error Message"
235-
}
236-
}
237-
```
238-
239-
This enables refining all features in the table above.
219+
[^refine-edition]: Depending on the outcome of the Unresolved Questions in this RFC, this may also be the case for future editions.
240220

241221
## Preventing future ambiguity
242222

@@ -332,23 +312,23 @@ One piece of related prior art here is the [leakage of auto traits][auto-leakage
332312
# Unresolved questions
333313
[unresolved-questions]: #unresolved-questions
334314

335-
## Do we need a soft transition?
336-
337-
In "Transitioning away from the current behavior" we describe two possible paths: immediate stabilization of any API the compiler accepts that happens to look refined today, and doing a soft transition.
315+
## Should `#[refine]` be required in future editions?
338316

339-
While a soft transition is the more conservative approach, it also isn't obvious that it's necessary.
317+
As discussed in [Drawbacks], this feature could lead to library authors accidentally publishing refined APIs that they did not mean to stabilize. We could prevent that by requiring the `#[refine]` attribute on any refined item inside an implementation.
340318

341-
It would help to do an analysis of how frequently "dormant refinements" occur on crates.io today, and of a sample of those, how many look accidental versus an extended API that a crate author might have meant to expose.
319+
There are three main options:
342320

343-
## Should `#[refine]` be required in future editions?
321+
* `#[refine]` is _always required_ for an impl to commit to a refined interface. In the next edition we could make it a hard error to write a refined interface without the `#[refine]` attribute, to reduce confusion.
322+
* `#[refine]` is _recommended_ in the next edition. Refined interfaces always work in future editions, but we warn or emit a deny-by-default lint if `#[refine]` is not used.
323+
* `#[refine]` is _not recommended_ in the next edition. Refined interfaces always work in future editions without any annotation at all.
344324

345-
As discussed in [Drawbacks], this feature could lead to library authors accidentally publishing refined APIs that they did not mean to stabilize. We could prevent that by requiring the `#[refine]` attribute on any refined item inside an implementation.
325+
It would help to do an analysis of how frequently "dormant refinements" occur on crates.io today, and of a sample of those, how many look accidental and how many look like an extended API that a crate author might have meant to expose.
346326

347-
If we decide to require the `#[refine]` annotation in future editions for all refinements, the only edition change would be that the lint in earlier editions becomes a hard error in future editions.
327+
## Do we need a soft transition?
348328

349-
Alternatively, we may even want to require annotations for more subtle features, like lifetimes, while not requiring them for "louder" things like `impl Trait` in return position.
329+
In "Transitioning away from the current behavior" above we describe doing a soft transition. However, the analysis on crates.io just described _could_ reveal that "dormant refinements" are almost never a mistake, and a `#[refine]` attribute is not needed in future editions. In that case we may want to reconsider the soft transition approach for existing editions.
350330

351-
This question would also benefit from the analysis described in the previous section.
331+
In the absence of compelling data demonstrating this, however, we should take the conservative approach of doing a soft transition.
352332

353333
# Future possibilities
354334
[future-possibilities]: #future-possibilities

0 commit comments

Comments
 (0)