Skip to content

Commit 972be34

Browse files
committed
Extend and improve reference desugarings
We had included a reference desugaring of `use<..>` in RPIT using ATPIT. Let's add a similar desugaring for `use<..>` in RPITIT. In doing this, we'll make some changes to the RPIT desugaring so that it better parallels the RPITIT one. In particular, we want to turbofish all generic parameters for clarity, and we want to eliminate all function arguments for conciseness. Doing this means that all of the lifetimes become early bound. This seems fine, since it's rather orthogonal to the semantics we're trying to demonstrate here. We also want to demonstrate using const generics in the hidden type. We could do this using arrays, e.g. `[(); N]`, but it seems more clear to just define a type constructor that uses all of the generics, so we'll sacrifice a bit of conciseness to do it that way.
1 parent b02f1aa commit 972be34

File tree

1 file changed

+162
-22
lines changed

1 file changed

+162
-22
lines changed

text/3617-precise-capturing.md

Lines changed: 162 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -205,51 +205,191 @@ The [syntax for `impl Trait`][] is revised and extended as follows:
205205
[_TraitBound_]: https://doc.rust-lang.org/nightly/reference/trait-bounds.html
206206
[_TypeParamBounds_]: https://doc.rust-lang.org/nightly/reference/trait-bounds.html
207207

208-
## Reference desugaring
208+
## Reference desugarings
209209

210-
Associated type position `impl Trait` (ATPIT) can also be used, more verbosely, to control capturing of generic parameters in opaque types. We can use this to describe the semantics of `use<..>`. If we consider the following code:
210+
The desugarings that follow can be used to answer questions about how `use<..>` is expected to work with respect to the capturing of generic parameters in opaque types.
211+
212+
### Reference desugaring for `use<..>` in RPIT
213+
214+
Associated type position `impl Trait` (ATPIT) can be used, more verbosely, to control capturing of generic parameters in opaque types. We can use this to describe the semantics of `use<..>`. If we consider the following code:
211215

212216
```rust
213-
struct Ty<'u, U, const CU: u8>(&'u (), U);
217+
use core::marker::PhantomData;
214218

215-
impl<'u, U, const CU: u8> Ty<'u, U, CU> {
219+
struct C<'s, 't, S, T, const CS: u8, const CT: u8> {
220+
_p: PhantomData<(&'s (), &'t (), S, T)>,
221+
}
222+
223+
struct Ty<'s, S, const CS: u8>(&'s (), S);
224+
impl<'s, S, const CS: u8> Ty<'s, S, CS> {
216225
pub fn f<'t, T, const CT: u8>(
217-
self, x: &'t (), y: T,
218-
) -> impl use<'u, 't, U, T, CU, CT> Sized {
219-
(self, x, y, CU, CT)
226+
) -> impl use<'s, 't, S, T, CS, CT> Sized {
227+
// ^^^^^^^^^^^^^^^^^^^^^^^^^
228+
// This is the `use<..>` specifier to desugar.
229+
C::<'s, 't, S, T, CS, CT> { _p: PhantomData }
220230
}
221231
}
222232
```
223233

224-
Then, using ATPIT, we could desugar this as follows while preserving equivalent semantics:
234+
Then we can desugar this as follows, without the use of a `use<..>` specifier, while preserving equivalent semantics with respect to the capturing of generic parameters:
225235

226236
```rust
227-
struct Ty<'u, U, const CU: u8>(&'u (), U);
237+
use core::marker::PhantomData;
228238

229-
impl<'u, U, const CU: u8> Ty<'u, U, CU> {
239+
struct C<'s, 't, S, T, const CS: u8, const CT: u8> {
240+
_p: PhantomData<(&'s (), &'t (), S, T)>,
241+
}
242+
243+
struct Ty<'s, S, const CS: u8>(&'s (), S);
244+
impl<'s, S, const CS: u8> Ty<'s, S, CS> {
230245
pub fn f<'t, T, const CT: u8>(
231-
self, x: &'t (), y: T,
232-
) -> <() as _0::H>::Opaque<'u, 't, U, T, CU, CT> {
233-
<() as _0::H>::f(self, x, y)
246+
) -> <() as _0::H>::Opaque<'s, 't, S, T, CS, CT> {
247+
// ^^^^^^^^^^^^^^^^^^^^
248+
// These are the arguments given to the `use<..>` specifier.
249+
//
250+
// Reducing what is captured by removing arguments from
251+
// `use<..>` is equivalent to removing arguments from this
252+
// list and as needed below.
253+
<() as _0::H>::f::<'s, 't, S, T, CS, CT>()
234254
}
235255
}
236256

237257
mod _0 {
238258
use super::*;
239259
pub trait H {
240-
type Opaque<'u, 't, U, T, const CU: u8, const CT: u8>;
241-
fn f<'u, 't, U, T, const CU: u8, const CT: u8>(
242-
s: Ty<'u, U, CU>, x: &'t (), y: T,
243-
) -> Self::Opaque<'u, 't, U, T, CU, CT>;
260+
type Opaque<'s, 't, S, T, const CS: u8, const CT: u8>;
261+
fn f<'s, 't, S, T, const CS: u8, const CT: u8>(
262+
) -> Self::Opaque<'s, 't, S, T, CS, CT>;
244263
}
245264
impl H for () {
246-
type Opaque<'u, 't, U, T, const CU: u8, const CT: u8>
265+
type Opaque<'s, 't, S, T, const CS: u8, const CT: u8>
247266
= impl Sized;
248267
#[inline(always)]
249-
fn f<'u, 't, U, T, const CU: u8, const CT: u8>(
250-
s: Ty<'u, U, CU>, x: &'t (), y: T,
251-
) -> Self::Opaque<'u, 't, U, T, CU, CT> {
252-
(s, x, y, CU, CT)
268+
fn f<'s, 't, S, T, const CS: u8, const CT: u8>(
269+
) -> Self::Opaque<'s, 't, S, T, CS, CT> {
270+
C::<'s, 't, S, T, CS, CT> { _p: PhantomData }
271+
}
272+
}
273+
}
274+
```
275+
276+
### Reference desugaring for `use<..>` in RPITIT
277+
278+
Similarly, we can describe the semantics of `use<..>` in return position `impl Trait` in trait (RPITIT) using anonymous associated types and ATPIT. If we consider the following code:
279+
280+
```rust
281+
use core::marker::PhantomData;
282+
283+
struct C<
284+
'r, 's, 't, R, S, T, const CR: u8, const CS: u8, const CT: u8,
285+
> {
286+
_p: PhantomData<(&'r (), &'s (), &'t (), R, S, T)>,
287+
}
288+
289+
trait Trait<'r, R, const CR: u8> {
290+
fn f<'t, T, const CT: u8>(
291+
) -> impl use<'r, 't, R, T, CR, CT, Self> Sized;
292+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
293+
// This is the `use<..>` specifier in the trait definition.
294+
}
295+
296+
struct Ty<'s, S, const CS: u8>(&'s (), S);
297+
impl<'r, 's, R, S, const CR: u8, const CS: u8> Trait<'r, R, CR>
298+
for Ty<'s, S, CS>
299+
{
300+
fn f<'t, T, const CT: u8>(
301+
) -> impl use<'r, 's, 't, R, S, T, CR, CS, CT> Sized {
302+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
303+
// This is the `use<..>` specifier in the
304+
// trait implementation.
305+
C::<'r, 's, 't, R, S, T, CR, CS, CT> { _p: PhantomData }
306+
}
307+
}
308+
```
309+
310+
Then we can desugar this as follows, without the use of `use<..>` specifiers, while preserving equivalent semantics with respect to the capturing of generic parameters:
311+
312+
```rust
313+
use core::marker::PhantomData;
314+
315+
struct C<
316+
'r, 's, 't, R, S, T, const CR: u8, const CS: u8, const CT: u8,
317+
> {
318+
_p: PhantomData<(&'r (), &'s (), &'t (), R, S, T)>,
319+
}
320+
321+
trait Trait<'r, R, const CR: u8>: Sized {
322+
fn f<'t, T, const CT: u8>(
323+
) -> <Self as _0::G<'r, R, CR>>::Opaque<'t, T, CT>
324+
// ^^^^ ^^^^^^^^^ ^^^^^^^^^
325+
// These are the arguments given to the `use<..>` specifier in the
326+
// trait definition.
327+
//
328+
// Reducing what is captured by removing arguments from that
329+
// `use<..>` is equivalent to removing arguments from here
330+
// and as needed below.
331+
//
332+
// If `Self` is removed from the `use<..>` specifier, that's
333+
// equivalent to replacing `Self` with `()` here and in the impl
334+
// below. I.e., removing `Self` means that we can't capture any
335+
// generic parameters in the impl that are not used as input
336+
// arguments to the trait.
337+
//
338+
// Similarly, if trait input parameters are removed from the
339+
// `use<..>` specifier, they must be removed from the input
340+
// parameters to the trait `G` below.
341+
where Self: _0::G<'r, R, CR>;
342+
}
343+
344+
struct Ty<'s, S, const CS: u8>(&'s (), S);
345+
impl<'r, 's, R, S, const CR: u8, const CS: u8> Trait<'r, R, CR>
346+
for Ty<'s, S, CS>
347+
{
348+
fn f<'t, T, const CT: u8>(
349+
) -> <Self as _0::G<'r, R, CR>>::Opaque<'t, T, CT> {
350+
<() as _0::H>::f::<'r, 's, 't, R, S, T, CR, CS, CT>()
351+
}
352+
}
353+
354+
mod _0 {
355+
use super::*;
356+
pub trait G<'r, R, const CR: u8> {
357+
type Opaque<'t, T, const CT: u8>;
358+
}
359+
impl<'r, 's, R, S, const CR: u8, const CS: u8> G<'r, R, CR>
360+
for Ty<'s, S, CS>
361+
{
362+
type Opaque<'t, T, const CT: u8>
363+
= <() as H>::Opaque<'r, 's, 't, R, S, T, CR, CS, CT>;
364+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
365+
// These are the arguments given to the `use<..>` specifier in
366+
// the trait implementation.
367+
//
368+
// Reducing what is captured by removing arguments from that
369+
// `use<..>` is equivalent to removing arguments from this
370+
// list and as needed elsewhere.
371+
}
372+
pub trait H {
373+
type Opaque<
374+
'r, 's, 't, R, S, T,
375+
const CR: u8, const CS: u8, const CT: u8,
376+
>;
377+
fn f<
378+
'r, 's, 't, R, S, T,
379+
const CR: u8, const CS: u8, const CT: u8,
380+
>() -> Self::Opaque<'r, 's, 't, R, S, T, CR, CS, CT>;
381+
}
382+
impl H for () {
383+
type Opaque<
384+
'r, 's, 't, R, S, T,
385+
const CR: u8, const CS: u8, const CT: u8,
386+
> = impl Sized;
387+
#[inline(always)]
388+
fn f<
389+
'r, 's, 't, R, S, T,
390+
const CR: u8, const CS: u8, const CT: u8,
391+
>() -> Self::Opaque<'r, 's, 't, R, S, T, CR, CS, CT> {
392+
C::<'r, 's, 't, R, S, T, CR, CS, CT> { _p: PhantomData }
253393
}
254394
}
255395
}

0 commit comments

Comments
 (0)