owned this note
owned this note
Published
Linked with GitHub
---
title: ITE meeting 2023-10-31
tags: impl-trait-everywhere, triage-meeting, minutes
date: 2023-10-31
discussion: https://rust-lang.zulipchat.com/#narrow/stream/315482-t-compiler.2Fetc.2Fopaque-types/topic/ITE.20triage.20meeting.202023-10-31
url: https://hackmd.io/mHmsSToOSkCFP5cOezFScw
---
# ITE meeting agenda
- Meeting date: 2023-10-31
## Attendance
- People: TC, CE, tmandry
## Meeting roles
- Minutes: TC
## Resolving #107645
### Proposal on nested inner function restriction
In the meeting yesterday, we agreed that we would all prefer to remove the restriction on defining an opaque type in a nested inner function. The new T-types restrictions make the effect of this restriction much more severe.
However, T-lang reached a consensus that included this restriction, and the attempt to revise out this restriction in the 2023-06-27 T-lang triage meeting was unsuccessful.
What do we do about that?
*Proposal:* We resolve the concern on [#107645][] to allow the many other parts of that consensus to proceed. Then we address removing the restriction on nested inner functions as part of the T-types proposal. It makes sense to include it here as the restrictions added by T-types makes the other restriction arguably untenable.
*Alternate proposal:* If, for any reason, we want to break this out from the rest of the T-types proposal, the thing to do would be to still resolve the concern on [#107645][], then open a new issue that seeks to overturn this one aspect of the earlier consensus. We would describe in that new issue how the T-types proposal affects this restriction, and we would provide analysis of the potential impact (or lack thereof) on tooling.
*Consensus*: The inner function restriction from [#107645][] needs to be revised due to the new T-types restrictions. We'll resolve the [#107645][] concern about this and address it as part of the design meeting discussion for the T-types proposal.
#### Motivation
People write code like this:
```rust
#![feature(type_alias_impl_trait)]
use core::future::Future;
type FooRet = impl Future<Output = String>;
fn foo<T: AsRef<str>>(x: T) -> FooRet {
let x = x.as_ref().to_string();
// This actually doesn't work due to #65442.
async move { x }
}
```
To reduced the size of the generated code due to generics (and also due to [#65442][] in this case), people idiomatically rewrite that as:
```rust
#![feature(type_alias_impl_trait)]
use core::future::Future;
type FooRet = impl Future<Output = String>;
fn foo<T: AsRef<str>>(x: T) -> FooRet {
fn inner(x: &str) -> FooRet {
let x = x.to_string();
async move { x }
}
inner(x.as_ref())
}
```
But with the T-types restrictions, this does not work, because the outer `foo` function names the opaque type within the defining scope but is not defining.
[#65442]: https://github.com/rust-lang/rust/issues/65442
### Signature restriction allows ADTs
Discussion yesterday: https://hackmd.io/TsRfxTpfQGKy_zXcQm8KDA
Threads of discussion:
- Is this issue separable from the defines question?
- If so, assuming we settle the defines question, have we settled this question?
*Consensus*: Due to the T-types proposal, a decision has to be made and committed to here, as the specific rules are being relied on and cannot be changed in a backward compatible manner. In that context, and if we choose to do the signature restriction, then it would be too annoying to not allow ADTs containing the opaque type to pass the signature restriction. We'll drop this concern on [#107645][] where this rule was part of that consensus and FCP.
#### Motivation 1: Constructors
```rust
#![feature(type_alias_impl_trait)]
use core::future::Future;
type JobFut = impl Future<Output = u64>;
struct Job {
id: u64,
fut: JobFut,
}
impl Job {
fn new(id: u64) -> Self {
Job { id: id, fut: async move { id } }
}
}
```
#### Motivation 2: Builder pattern
```rust
#![feature(type_alias_impl_trait)]
use core::future::Future;
type JobFut = impl Future<Output = u64>;
struct Job {
id: u64,
fut: JobFut,
}
struct JobBuilder {
id: Option<u64>,
n_iters: Option<u64>,
}
impl JobBuilder {
const fn new() -> Self {
Self { id: None, n_iters: None }
}
fn id(&mut self, id: u64) {
self.id = Some(id);
}
fn n_iters(&mut self, iters: u64) {
self.n_iters = Some(iters);
}
fn build(self) -> Job {
let id = self.id.unwrap();
let n_iters = self.n_iters.unwrap();
Job {
id,
fut: async move {
let mut x: u64 = 1;
for _ in 0..n_iters {
x *= 3;
x -= 1;
}
x
},
}
}
}
```
#### Motivation 3: Making the human into a compiler
As the code becomes more realistic and more complicated, it becomes more difficult to refactor the code such that the type alias can be named directly in the signature, as it requires moving all captured things into named input arguments to one or more functions. This process may itself require introducing new named opaque types that would not otherwise be necessary. Those opaque types themselves may then need special handling to ensure they can be defined appropriately. This process can continue recursively. This argument was touched on earlier in the section ["Making the human into a compiler"](https://hackmd.io/oTC4J-2XRnukxC7lSq_PVA#Making-the-human-into-a-compiler).
Essentially, such a rule would require the human to compile many uses of the feature down to *basic blocks*, manually.
### From the T-types meeting: Proposal :zero: (preferred)
- Forever:
- A function must have the TAIT (or a type that contains it) in the signature.
- or some defines syntax in the future
- For now (we never expect to relax):
- TAITs can only be defined once modulo regions.
- For now (can be relaxed later):
- A function that mentions the TAIT (or a type that contains it) in the signature, it must define it.
- Because of lazy norm and how the new trait solver is more complete, this is an area of difference between the old and new solver. It would be easy to break things here. And the old trait solver is underspecified here. (Oli: It is fixable in the old solver.) So we're saving space here.
- [*May remove this now*:] Only one function in the defining scope can mention the TAIT (or a type that contains it) in the signature.
- Can create a dedicated diagnostic for this case, avoiding all cycle errors and other hard to diagnose issues for users.
- This is the most arbitrary. We have the machinery to allow this. But it prevents people from writing functions that are passthrough. It allows us to write earlier and better diagnostics. But this is an artificial restriction we could lift easily. We could put this behind a separate feature gate.
- [*May remove this now by making it just work*:] Error if projection in signature (except one from the same impl, ITIAT/ATPIT) inside the defining scope normalizes to include a TAIT.
- Saves space for making opaque_types_defined_by query smarter.
- Properties:
- All cycle errors are *real* cycle errors in the new solver.
- Changes that allow more items to define the TAIT to the signature rule would be breaking changes.
### Continuations on signature restriction / defines syntax
*Consensus*: Since the option of an explicit `defines` syntax was not discussed in the last T-lang design meeting on TAIT, we want to ensure it is mentioned in the next meeting. We will include it in the design document for the next meeting along with a discussion of the practical problems that would follow from choosing that option, including how it may impact the timeline for stabilizing the new 2024 lifetime capture rules in the new edition. We may leave a comment on the TAIT tracking issue noting that we want to be sure this is raised for discussion.
#### Option 0: Signature restriction
- Implemented today.
- Least verbose and least noisy for common cases.
- Strict subset of RFC behavior with no new syntax.
- Most symmetric with `dyn Trait`.
- Fewest open implementation or design questions.
- Second-most forward compatible option.
- Forward compatible with:
- Option 1: Signature restriction + defines outside of defining scope
- Option 2: Signature restriction + defines outside of defining scope + optional defines in defining scope
- Option 3: Signature restriction + defines outside of defining scope + optional defines in defining scope + lint for absent defines
- Option 4: Signature restriction + optional defines in defining scope
- Option 5: Signature restriction + optional defines in defining scope + lint for absent defines
- Backward compatible with:
- Option 6: Signature restriction + mandatory defines in defining scope
#### Option 1: Signature restriction + defines outside of defining scope
- We can add this later.
- Putting TAITs into submodule then results in the same experience as defines-only proposals (i.e. Option 9).
- For this and all other defines options, we'd need to work out syntax.
- There are implementation concerns with using an attribute; name resolution doesn't happen inside of attributes.
- Using an attribute may be inconsistent with the decision in [#41619][].
- The tracking issue for RFC 1868 "A portability lint" completed FCP disposition close on the basis that T-lang wanted to go in the direction of using `where` clauses to express "capabilities" rather than using an attribute-based solution. For `defines`, what we're talking about is the *capability* of defining the hidden type, so there may be design and conceptual similarity here.
- There are open questions on the handling of generic parameters.
- If we look through normalization, the generic parameters matter.
- If we don't, we're closing doors.
- We have to think about the effect on `impl Trait` everywhere also.
- Forward compatible with:
- Option 2: Signature restriction + defines outside of defining scope + optional defines in defining scope
- Option 3: Signature restriction + defines outside of defining scope + optional defines in defining scope + lint for absent defines
- Backward compatible with:
- Option 0: Signature restriction
- Option 6: Signature restriction + mandatory defines in defining scope
- Option 7: Signature restriction + mandatory defines in defining scope + defines outside of defining scope
E.g.:
```rust
#![feature(type_alias_impl_trait)]
#![feature(todo_define_tait_anywhere_in_crate)]
use taits::*;
mod taits {
type Tait<T> = impl Sized;
}
fn define<T>()
where
constrains(Tait<T>)
{}
```
[#41619]: https://github.com/rust-lang/rust/issues/41619
#### Option 2: Signature restriction + defines outside of defining scope + optional defines in defining scope
- Forward compatible with:
- Option 3: Signature restriction + defines outside of defining scope + optional defines in defining scope + lint for absent defines
- Backward compatible with:
- Option 0: Signature restriction
- Option 1: Signature restriction + defines outside of defining scope
- Option 3: Signature restriction + defines outside of defining scope + optional defines in defining scope + lint for absent defines
- Option 4: Signature restriction + optional defines in defining scope
- Option 5: Signature restriction + optional defines in defining scope + lint for absent defines
- Option 6: Signature restriction + mandatory defines in defining scope
- Option 7: Signature restriction + mandatory defines in defining scope + defines outside of defining scope
#### Option 3: Signature restriction + defines outside of defining scope + optional defines in defining scope + lint for absent defines
- Forward compatible with:
- Option 2: Signature restriction + defines outside of defining scope + optional defines in defining scope
- Backward compatible with:
- Option 0: Signature restriction
- Option 1: Signature restriction + defines outside of defining scope
- Option 2: Signature restriction + defines outside of defining scope + optional defines in defining scope
- Option 4: Signature restriction + optional defines in defining scope
- Option 5: Signature restriction + optional defines in defining scope + lint for absent defines
- Option 6: Signature restriction + mandatory defines in defining scope
- Option 7: Signature restriction + mandatory defines in defining scope + defines outside of defining scope
#### Option 4: Signature restriction + optional defines in defining scope
- Forward compatible with:
- Option 2: Signature restriction + defines outside of defining scope + optional defines in defining scope
- Option 3: Signature restriction + defines outside of defining scope + optional defines in defining scope + lint for absent defines
- Option 5: Signature restriction + optional defines in defining scope + lint for absent defines
- Backward compatible with:
- Option 0: Signature restriction
- Option 5: Signature restriction + optional defines in defining scope + lint for absent defines
- Option 6: Signature restriction + mandatory defines in defining scope
One could actually define this as a proc macro on top of Option 1. E.g.:
```rust
#[defines(Foo)]
fn foo() { let _: Foo = (); }
// -----------------------------------------
fn foo() where Foo: Any { let _: Foo = (); }
```
#### Option 5: Signature restriction + optional defines in defining scope + lint for absent defines
- Forward compatible with:
- Option 2: Signature restriction + defines outside of defining scope + optional defines in defining scope
- Option 3: Signature restriction + defines outside of defining scope + optional defines in defining scope + lint for absent defines
- Option 4: Signature restriction + optional defines in defining scope
- Backward compatible with:
- Option 0: Signature restriction
- Option 4: Signature restriction + optional defines in defining scope
- Option 6: Signature restriction + mandatory defines in defining scope
#### Option 6: Signature restriction + mandatory defines in defining scope
- Maximum forward compatibility.
- Maximum annoyance.
- Forward compatible with:
- Option 0: Signature restriction
- Option 1: Signature restriction + defines outside of defining scope
- Option 2: Signature restriction + defines outside of defining scope + optional defines in defining scope
- Option 3: Signature restriction + defines outside of defining scope + optional defines in defining scope + lint for absent defines
- Option 4: Signature restriction + optional defines in defining scope
- Option 5: Signature restriction + optional defines in defining scope + lint for absent defines
- Option 7: Signature restriction + mandatory defines in defining scope + defines outside of defining scope
- Option 8: Defines in defining scope
- Option 9: Defines in defining scope + defines outside of defining scope
- Backward compatible with:
- (None)
#### Option 7: Signature restriction + mandatory defines in defining scope + defines outside of defining scope
- Forward compatible with:
- Option 1: Signature restriction + defines outside of defining scope
- Option 2: Signature restriction + defines outside of defining scope + optional defines in defining scope
- Option 3: Signature restriction + defines outside of defining scope + optional defines in defining scope + lint for absent defines
- Option 9: Defines in defining scope + defines outside of defining scope
- Backward compatible with:
- Option 6: Signature restriction + mandatory defines in defining scope
#### Option 8: Defines in defining scope
- Closes door on signature restriction options.
- Not a struct subset of the RFC behavior.
- Some people like the module-scoped behavior in the RFCs; we'd have to build a new consensus against this.
- Forward compatible with:
- Option 9: Defines in defining scope + defines outside of defining scope
- Backward compatible with:
- Option 6: Signature restriction + mandatory defines in defining scope
#### Option 9: Defines in defining scope + defines outside of defining scope
- Forward compatible with:
- (None)
- Backward compatible with:
- Option 6: Signature restriction + mandatory defines in defining scope
- Option 7: Signature restriction + mandatory defines in defining scope + defines outside of defining scope
- Option 8: Defines in defining scope
#### Bonus option: RTN everywhere
Rather than (or in addition to) doing any of the above, we could finalize a design of RTN and extend it to type position. We would need it to support specifying generic arguments to achieve the correct quantification.
#### Option matrix
```mermaid
flowchart TB
subgraph DefinesOnly["Defines Only"]
O8["Option 8\n\nDefines in defining scope"]
O9["Option 9\n\nDefines in defining scope\n+ defines outside of defining scope"]
end
subgraph BothRequired["Both Required"]
O6["Option 6\n\nSignature restriction\n+ mandatory defines in defining scope"]
O7["Option 7\n\nSignature restriction\n+ mandatory defines in defining scope\n+ defines outside of defining scope"]
end
subgraph SignatureRestriction["Signature Restriction"]
subgraph DefinesOutside["Defines Outside of Defining Scope"]
O1["Option 1\n\nSignature restriction\n+ defines outside of defining scope"]
O2["Option 2\n\nSignature restriction\n+ defines outside of defining scope\n+ optional defines in defining scope"]
O3["Option 3\n\nSignature restriction\n+ defines outside of defining scope\n+ optional defines in defining scope\n+ lint for absent defines"]
style O3 stroke:#fff000
end
O0["Option 0\n\nSignature restriction"]
O4["Option 4\n\nSignature restriction\n+ optional defines in defining scope"]
O5["Option 5\n\nSignature restriction\n+ optional defines in defining scope\n+ lint for absent defines"]
style O5 stroke:#fff000
end
O0 --> O1
O0 --> O2
O0 --> O3
O0 --> O4
O0 --> O5
O1 --> O2
O1 --> O3
O2 <--> O3
O4 --> O2
O4 --> O3
O4 <--> O5
O5 --> O2
O5 --> O3
O6 --> O0
O6 --> O1
O6 --> O2
O6 --> O3
O6 --> O4
O6 --> O5
O6 --> O7
O6 --> O8
O6 --> O9
O7 --> O1
O7 --> O2
O7 --> O3
O7 --> O9
O8 --> O9
```
[(Better rendering)](https://mermaid.live/view#pako:eNq9VcFuozAQ_ZWR97itBARCElU9VLkjNb2t9-DCkFgFO2uMqqjqv9cGwrBqu1Tbqrc34zdvnmcseGK5LpBtgJWVfswPwli4u-GKq6a93xtxPMAWS6mwyVR1-sXZEIEPOfvNVbZy2exopVaw4q6SqzNHKig8lGoPTa6P2BesqWA9V8DVzz7lTnVrG1kg6PItWVTFX7ZvtD3c4p9WGixcQx_COe59LMnHsvexk3slbGsQDDbWyNwfdh5qoQphtTmNbt65XEqi6VeI_v8Axr631NaZIzuTfCfAFcCrrfctp4snE9uzid1oAiALaQLh3AQ-djMnGpFo9HlRz9KdmqhmFup6L6j34tt6e1ollYVSGxD3DTo4sAdfjT1V6Nw5YPQDbn6UZRkEgT8ankIWkPPgX867lxsTOZ675geHlyWkmXyB5txQhpEkr0YyDgQuL6_dEyUYEVwQjAkmXWFI7HBkuyCCq0kUEysmzXjg9EoJcZKp0rIPAoIhwYjggmBMMCGYElwRXHdNUlJOSTkl5XTKXo0BuwBWo6mFLPy_4okze8DaLXkDnBXCPHD27DmitXp3UrnLl6Jq0KXao_vG4VYK912pz_nnF1xPNbE)
## References
- [2023-10-31 Attempt to resolve #107645](https://hackmd.io/mHmsSToOSkCFP5cOezFScw) (this document)
- [2023-10-30 Attempt to resolve #107645](https://hackmd.io/TsRfxTpfQGKy_zXcQm8KDA)
- [2023-10-26 Description of T-types proposal](https://hackmd.io/qiy4_I3WRYyhpYvjbYBrew)
- [2023-10-19 Prevent opaque types being instantiated twice with different regions within the same function - #116935](https://github.com/rust-lang/rust/pull/116935)
- [2023-10-16 Normalize when collecting TAITs in signature - #116819](https://github.com/rust-lang/rust/pull/116819)
- [2023-10-11 T-types TAIT session minutes](https://hackmd.io/QOsEaEJtQK-XDS_xN4UyQA)
- [2023-09-13 RPITIT stabilization - #115822](https://github.com/rust-lang/rust/pull/115822)
- [2023-07-26 RFC 3498 - Lifetime capture rules 2024](https://github.com/rust-lang/rfcs/pull/3498) ([design meeting](https://hackmd.io/sFaSIMJOQcuwCdnUvCxtuQ)) ([discussion](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/design.20meeting.202023-07-26))
- [2023-07-11 T-lang triage diffs on TAIT](https://hackmd.io/_eMqgF3JQgGEN4Y6C9C1pg#Diffs-on-TAIT-TC)
- [2023-06-29 TAIT must be constrained if in signature PR](https://github.com/rust-lang/rust/pull/113169)
- [2023-06-29 Oli/lcnr meeting on TAIT](https://rust-lang.zulipchat.com/#narrow/stream/315482-t-compiler.2Fetc.2Fopaque-types/topic/lcnr.20oli.20meeting/near/370710606)
- [2023-06-29 TAIT mini-design meeting](https://hackmd.io/r1oqcjrzTAK5e_T1IOXeXg) ([discussion](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/TAIT.20mini-design.20meeting.202023-06-29))
- [2023-06-27 T-lang triage atempt to revise nested inner functions restriction](https://hackmd.io/hTUmwMrbSSqN1eU2k90Iwg#TAIT-nested-inner-functions-restriction-take-2-TC)
- [2023-06-13 TAIT tracking issue proposed stabilization FCP canceled](https://github.com/rust-lang/rust/issues/63063#issuecomment-1588994092)
- [2023-06-12 T-types TAIT in new trait solver document](https://hackmd.io/llGcGMR7SvCP1C1MulcDQw) ([discussion](https://rust-lang.zulipchat.com/#narrow/stream/326132-t-types.2Fmeetings/topic/2023-06-12.20TAIT.20in.20new.20solver/near/365570768))
- [2023-06-06 lcnr resolves concern about allowing WCs in signature restriction](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/design.20meeting.202023-05-31.20TAITs/near/363984835)
- [2023-06-01 TAIT defining scope options proposed FCP](https://github.com/rust-lang/rust/issues/107645#issuecomment-1571789814)
- [2023-05-31 T-lang TAIT design meeting](https://hackmd.io/IVFExd28TZWm6iyNIq66PA) ([discussion](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/design.20meeting.202023-05-31.20TAITs))
- [2023-05-31 TAIT draft stabilization report](https://hackmd.io/oTC4J-2XRnukxC7lSq_PVA) (not updated with T-types proposal)
- [2023-03-20 lcnr update on new trait solver concern](https://github.com/rust-lang/rust/issues/63063#issuecomment-1476196975)
- [2023-02-06 lcnr concern over new trait solver](https://github.com/rust-lang/rust/issues/63063#issuecomment-1418741032)
- [2023-02-03 TAIT defining scope options - #107645](https://github.com/rust-lang/rust/issues/107645)
- [2023-01-17 TAIT tracking issue concern over defining scope](https://github.com/rust-lang/rust/issues/63063#issuecomment-1386064436)
- [2022-12-24 TAIT tracking issue concern over updating reference](https://github.com/rust-lang/rust/issues/63063#issuecomment-1364525286)
- [2022-12-20 proposed FCP merge of TAIT stabilization](https://github.com/rust-lang/rust/issues/63063#issuecomment-1360043060)
- [2022-12-16 TAIT stabilization report](https://github.com/rust-lang/rust/issues/63063#issuecomment-1354392317)
- [2019-06-28 TAIT tracking issue - #63063](https://github.com/rust-lang/rust/issues/63063)
- [2018-08-05 RFC 2515 - Permit impl Trait in type aliases](https://github.com/rust-lang/rfcs/pull/2515)
- [2017-07-20 RFC 2071 - Named existentials and impl Trait variable declarations](https://github.com/rust-lang/rfcs/pull/2071)
- [2017-03-15 RFC 1951 - Finalize syntax and parameter scoping for impl Trait, while expanding it to arguments](https://github.com/rust-lang/rfcs/pull/1951)
- [2016-03-01 RFC 1522 - Minimal impl Trait](https://github.com/rust-lang/rfcs/pull/1522)
- [impl Trait initiative repository](https://rust-lang.github.io/impl-trait-initiative/)
- [TAIT project tracking board](https://github.com/orgs/rust-lang/projects/22/views/1)
[#107645]: https://github.com/rust-lang/rust/issues/107645