Comments (11)
We discussed this in the lang design meeting today:
The conclusion of the team is that we'll make use<..>
a bound. That is, we'll support impl use<..> + Trait
, impl Trait + use<..>
, etc.
For now, we will support at most one such bound in a list of bounds, and semantically we'll only support these bounds in the item bounds of RPIT-like impl Trait
opaque types (i.e., in the places discussed in the RFC).
We were interested in later extending this so that it could be used in the bounds on associated types and with dyn
. This syntactic choice is the most scalable in that way.
For RPITIT (i.e. within trait definitions), we defer to implementation work and to stabilization whether to support it or to leave this work to later, e.g. to the point at which we support use<..>
in the bounds on associated types.
Note, if we were later to support multiple use<..>
items in a list of bounds, that use<T> + use<U>
would represent a union, and so use<T> + use<U>
would not be equivalent to use<T, U>
.
If the bounds of the opaque type reference generics that are not present in the use<..>
, that's an error of course, and a machine-applicable fix seems possible and desirable here.
We found the idea of this being a bound surprisingly appealing, and people liked that this choice allows for putting + use<..>
at the end of a list of bounds. Doing it this way also means we don't need to migrate the ty
macro matcher fragment specifier.
Thanks to @joshtriplett for proposing this appealing option. We resolved a difficult choice between two good options by finding an even better one. That's Rust at its best.
from rust.
However, in Edition 2021 and lower, the default is to capture only some things. How does
use<>
work with this? There's a few options:
use<>
overrides the default capture list. Therefore it can either remove or add variables to the capture list. Then, it's no longer true thatuse<>
always restricts the hidden type, so it doesn't make sense to add a bound.use<>
only further restricts the default capture list. I find this a bit unfortunate because it means you'll still need the+ Captures<'a>
hack to add a lifetime capture.use<>
is entirely disallowed in Edition 2021 and lower. This is also unfortunate, and IIUC the aim is to add new features to all editions if possible, and it feels like in this case it should be.Neither is particularly great
I think this is possibly the strongest argument against use<>
as a bound, but I'm personally okay with saying that use<>
overrides the default capture list in all editions, therefore it makes slightly less sense to conceptualize it as a bound in earlier editions. This is based on the ideas of joint behavior across editions and that editions are meant to be adopted, so while we prefer to have language features work the same across all editions where possible, we're also okay with only delivering the best possible experience in later editions.
from rust.
Reopening to formally propose FCP on the above change. I think it is a significant enough delta from the RFC that we would be better off doing an FCP and documenting the rationale now, instead of at stabilization time.
This FCP resolves the unresolved question in the RFC about syntax.
@rfcbot fcp merge
from rust.
One additional argument that was raised in the meeting, but never really written out as an example, was the use of use<>
as a bound on GATs. This really cemented for me the value in thinking of it as a bound. As a quick sketch, the bound could go in the trait:
trait BufferedIterator<A: Arena> {
type Item<'a>: use<'a>;
fn next<'a>(&'a mut self, a: &'a mut A) -> Self::Item<'a>;
}
or in use sites:
fn foo(iter: impl BufferedIterator<MyArena, for<'a> Item<'a>: use<'a>>) { ... }
Obviously this is a pretty niche and advanced feature, but it seems to make sense conceptually.
from rust.
Team member @tmandry has proposed to merge this. The next step is review by the rest of the tagged team members:
No concerns currently listed.
Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!
cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns.
See this document for info about what commands tagged team members can give me.
from rust.
I don't know what our official policy is, but @traviscross , would you mind updating the description to reflect the new proposal from #125836 (comment) ?
(Or I guess even just making the line of the description be a link to that comment...)
from rust.
🔔 This is now entering its final comment period, as per the review above. 🔔
from rust.
Also, I do not necessarily agree with "Note, if we were later to support multiple use<..> items in a list of bounds, that use + use would represent a union, and so use + use would not be equivalent to use<T, U>." ; but I do not see us as committing to a union (vs intersection) path via our FCP here, so I'm willing to check my box and not make this a formal concern here.
from rust.
@rfcbot reviewed
I concur with @pnkfelix and I specifically want us to leave room for different interpretations of use
in the future. There are two that I think make sense, described below. However, thanks to the restrictions of "at most one use
" and "must include all generics that appear elsewhere in the bounds", both of these interpretations are equivalent, and I think that's fine for the moment.
To explain the two options, let's start by defining a conceptual bound use_only<G..>
that is implemented for all types that reference the generics in G...
(but not generics outside that set). That is the right formal mechanism and what e.g. I expect a-mir-formality to think about. Lacking a use_only
bound therefore implies any type could be used.
One option then is to desugar use
to use_only
. This has the counterintuitive implication that use<A> + use<B>
is equivalent to use<>
which seems surprising.
An alternative option is to have a more complex desugaring where use
appears in the surface syntax but not in the internal representation. We would translate a "user-facing" set of bounds as follows. If there is a use<G..>
at all, then we take the union G..
of all generics that appear in the bounds anywhere and add use_only<G..>
. Otherwise we don't add anything at all. In this way use<A, B>
is equivalent to use<A> + use<B>
: both would desugar to a single use_only<A, B>
.
I think the second rule is more intuitive but also brings up mild concerns. Specifically we try to avoid "discontinuities" like this, where having no uses is "different" than having one or more uses. These kind of rules can have composability problems, but in this instance it might be that it's more composable. Unclear.
Anyway, we don't have to decide this now, but I do want to leave room for it as a possible future direction (which we may never need).
from rust.
I've got one concern with the + use<>
syntax.
If we make use<>
a bound, then it makes sense that it only restricts the hidden type further. That's what bounds do after all. Adding a bound can only make types no longer be accepted, it can't make a previously-not-accepted type start being accepted.
In Edition 2024, the default is to capture everything in scope. So, use<>
is indeed only restricting. Without use<>
the hidden type is allowed to capture anything, with use<>
it's only allowed to capture the listed variables. Makes sense.
However, in Edition 2021 and lower, the default is to capture only some things. How does use<>
work with this? There's a few options:
use<>
overrides the default capture list. Therefore it can either remove or add variables to the capture list. Then, it's no longer true thatuse<>
always restricts the hidden type, so it doesn't make sense to add a bound.use<>
only further restricts the default capture list. I find this a bit unfortunate because it means you'll still need the+ Captures<'a>
hack to add a lifetime capture.use<>
is entirely disallowed in Edition 2021 and lower. This is also unfortunate, and IIUC the aim is to add new features to all editions if possible, and it feels like in this case it should be.
Neither is particularly great
IMO making use<>
a bound feels somewhat wrong, due to:
- It doesn't make sense in Edition <2021 (see above)
- Having multiple
use<>
doing intersection and not union is unintuitive. - Artificially disallowing
use<> + use<>
is also strange, no other bound in Rust behaves like that today.
I think the use<> impl Trait
syntax makes much more sense. The way I see it, an opaque type is
- a list of captures
- a list of bounds
The list of captures is either automatically inferred (with different rules in <=2021 and >=2024), or explicitly specified with use<>
.
Under this mental model, it makes sense for use<>
to be a "modifier" applied to the impl
keyword, and not a bound. So, use<> impl Trait
syntax .The result makes sense for both <=2021 and >=2024 editions, and avoids the weirdness of two use<>
s by only allowing one.
from rust.
The intuition I'd suggest is that, if a bounds list contains a use<..>
bound, that fully specifies the set of captures, and if it doesn't, then the compiler adds one in lowering that lists all of the generics captured under the rules for that edition.
That is, I'd suggest thinking about it in terms of the use<..>
bound always being present, conceptually, and that there's a convenient elision rule.
from rust.
Related Issues (20)
- Compiler hangs and consumes unbounded memory with complex trait bounds HOT 8
- ICE: `non-Aggregate field with matching ABI but differing alignment` HOT 2
- ICE: unnamed fields: `internal compiler error: could not resolve DefId` HOT 1
- Feature request: Function to join thread with timeout HOT 2
- const Traits not being handled inside const associated functions/methods HOT 2
- rustdoc reproducibility issue due to nondeterministic anon.llvm.<hash> HOT 1
- Fix internal `Wtf8Buf::extend_from_slice` check HOT 2
- ICE: `assertion left == right failed` in `rustc_const_eval/src/interpret/cast.rs unsize_into` HOT 3
- Regression from new lint `out_of_scope_macro_calls` HOT 6
- rustdoc: panic when using `macro@` and `!` for referencing a macro in documentation HOT 2
- If-else type checking fails with trait method calls and closures HOT 5
- Lots of testsuite failures on powerpc-unknown-linux-gnu after #118709 HOT 4
- Taking reference to function gets optimized to be 0x1 HOT 5
- document args for `-Zbuild-std` when folks aren't building everything HOT 5
- Well-formedness analysis pass on trait impl paniced HOT 2
- Unnecessary move in trait object comparison HOT 1
- Type inference complains about unknown size for `dyn Any` HOT 3
- ICE(non_lifetime_binders): const bound params not handled correctly HOT 3
- diagnostics should prefer naming items through the extern prelude instead of doc-hidden type aliases
- async lambda with capture ICE HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rust.