or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Syncing
xxxxxxxxxx
TAITs ahoy
2022-09-16 - Status Update T-types Deep Dive
Full status board:
https://github.com/orgs/rust-lang/projects/22/views/1
(x, y) = some_value_of_opaque_type
errors very unhelpfullyJust waiting on https://github.com/rust-lang/rust/pull/98933 and https://github.com/rust-lang/rust/pull/95474 to get merged so the last known soundness bugs in TAITs are solved.
Open question: Should TAITs capture all lifetimes?
Original issue: https://github.com/rust-lang/rust/issues/96996
compiles, even though there is no
+ 'a
bound onimpl AsRef<str>
. This is not what the RFC specified, and is different from how RPIT works. It is often convenient, as you don't have to use the+ Captures<'a>'
trick, and instead all lifetimes of the type alias, assoc type or trait are captures.Workarounds exist, so we may just say, that if you don't want to capture all lifetimes, use a free TAIT without the lifetimes you want to capture: https://github.com/rust-lang/rust/issues/91601
Will this be a problem for nested
impl Trait
capturing HKL? I guess we could also use the workaround where this is a problem.So this is mainly a language question: do we want implicit capture or be in sync with RPIT and require explicit capture?
Where are we at now?
Type alias impl trait is the feature where you can use
impl Trait
syntax in the type of a type alias or an associated type:These uses of
impl Bar
each generate a unique type (an opaque type) that has all the same generics (including lifetimes) as the type alias/assoc type. So effectively the above desugars toIt is possible to replace any use of
impl Trait
in return types with a type alias:can be replaced with
without any changes in behaviour. The advantage of using type aliases is that you can re-use the same opaque type in multiple locations, and guarantee to the user that they are the same type.
The type-alias/assoc-type nature has a few effects that may be surprising when compared with other types:
No implied oulives bounds
In contrast to the same program if
Foo
were a struct, this does not compile:playground
Foo<'b>
not add any constraints on'b
, because hidden types don't actually need to reference the lifetimes on the opaque type. Thus they can live arbitrarily longer. The following program would be unsound if we allowed such implications.No inference across separate items
Inference of opaque types only happens within the same function. The following program errors because
foo
infers the type to bei32
via fallback, whilebar
sets the type toi64
Inference at a distance via return types
Opaque types in return types allow type inference between all return sites (no matter if via
return
,?
or via a trailing expression).Not only return sites are constraining hidden types
You can constrain a hidden type in any direction. This means you can also take an opaque type and turn it into a concrete type.
Fields of hidden types can be revealed within the same function
More spooky action at a distance that is actually just following the regular inference logic. If you moved the
if false
block later in the function, the code would not compile as it would not know the type ofy.1
and thus not be able to callpush
.type alias impl trait can be used anywhere another type can
Questions and Notes
nikomatsakis: I think we need to have a way to have explicit capture, but I've become slowly converted to the POV that this may not be
type Foo = impl Trait
. Specifically, I think it might make sense to have this syntax:and then have
type Foo<'a> = impl Trait
desugar tojust as with RPIT (in this case, then, the
'a
would not be captured in the TAIT notation, only in the explicit opaque type notation). One advantage to this distinction is that you can move a function return type into a type alias and the semantics stay the same:It creates (to my eye) a nice parallelism between associated types, and it addresses boats' concern that "TAITs desugar to themselves". Ultimately, though, I think this is a lang-team call, but it makes sense for us to have a recommendation.
I wonder if we could do some targeted experiments to try and measure learnability. I'm going to think about this.
Meeting discussion: Discussed here with the meeting consensus that we ought to open a write-up for lang team and put the following question:
with our recommendation being option 2.
Really? Doesn't that affect the scope of constraining uses, which in turn may make a different in some cases?
Meeting discussion: Discussed here and concluded that it is equivalent, but only if you add modules and things to control the scope.
unsoundness in the project board, not mentioned here:
issue is that coherence uses https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/enum.DefiningAnchor.html#variant.Error while it should treat opaque types as ambiguous. At this point we should also allow explicitly mentioning the opaque type in impl headers. Not really a question, just the statement: "we should also allow explicitly mentioning the opaque type in impl headers"
Meeting discussion: Discussed here and concluded that we should prohibit TAITs from inherent impls, but that we will have to accept them in trait impls, because they can be named indirectly (e.g., through projections). The plan is to treat them equivalently to a projection (i.e., "some unknown type") which should be sound with respect to coherence.
Does this not work for TAITs, then? i.e., this is an error?
edit: rereading the section, I don't believe it is trying to say that. In particular, the example showing "action at a distance" inference effects suggests that all "proposed values" for the hidden type within a single function are unified, and eagerly so:
Meeting discussion: Discussed here, along with the next question (see below).
What's the reason behind constraining hidden types at use site? This allows casting from a hidden type to a more specific type (e.g.
impl Debug
to i32), which might be accidental if you write the use site before the implementation.Meeting discussion: Discussed here, along with the previous question (see below). We discussed how this formulation can be useful and how it is hard to separate unifications in cases like these from other cases, as well as how to think about the previous question. The short version is that all constraints within a single function are combined with one another, and that in the return type in particular we replace opaque types with an inference variable which can lead them to influence coercions (this came up later on another question).
The text did not describe the distinction between a variable of type
Foo
and the hidden type, but I believe it remains significant, right? In other words, given a TAIT……if I have a local variable of type
Foo
, I cannot assume anything but that it implementsDebug
……but if I use the hidden type, I can…
It occurs to me that if we had
impl Trait
in let bindings (soon!), then this behavior is easier to explain, since you can first show……which, to my eyes, reads like we are intentionally limiting ourselves to
Debug
(and that is the way to think oflet x: Foo
as well, I think).(Side note, are we intended to make the two entirely analogous? i.e., a
let x: impl Trait
is just a TAIT scoped to the function? I think that's probably the best thing.)Meeting discussion: Discussed here, we concluded that this description is correct, and that we don't really have to decide what
let x: impl Trait
will do, but desugaring to a TAIT within the function body is the most likely behavior.From zulip:
oli replied "we reverted that and are sticking to the existing behaviour", but what was the change and problem? I never understood it. –nikomatsakis
Meeting discussion: Discussed here. The reversion had to do with the way that RPIT can sometimes take advantage of things that are known from the function context which would not otherwise be known. We uncovered an example where extracting an RPIT to a TAIT caused errors as a result and are considering the best fix.
nikomatsakis: we should talk about a-mir-formality and what this looks like! I'll give that some thought. I think we're at the point where we could plausibly model this.
Meeting discussion: None really. :)
2022-05-12
Issues that need decision
https://github.com/rust-lang/rust/issues?q=is%3Aopen+label%3AI-needs-decision+label%3AF-type_alias_impl_trait
let (a, b) = foo;
, since that is the code that is actually injecting the problem here.if
, allowing it to figure out that it must beVec
. Without this change, the collect expression is unified with the opaque return type, instead of unifying with the other branch of theif
.Conclusion for https://github.com/rust-lang/rust/issues/96552:
The following errors on stable, there is no fallback inside other types
but there is fallback if it is just a plain impl Trait
rust-lang/rust#86732: "min_type_alias_impl_trait doesn't report an error when impl Trait is used in a struct field"
rust-lang/rust#86731 "min-type-alias-impl-trait should not accept impl trait in assoc. type binding"
rust-lang/rust#77989: "Type mismatch when using constant with type_alias_impl_trait "
rust-lang/rust#57961: "Defining scope of existential type defined by associated type"
rust-lang/rust#53092: "FullfillmentError ICE with const fn and existential type"
Next action items, fix everything in https://github.com/rust-lang/rust/issues?q=is%3Aopen+label%3AF-type_alias_impl_trait+assignee%3Aoli-obk (10 issues right now)
Next action item: oli should look at
unconstrained_something_something
2022-01-19
Problem 1
This should compile, but doesn't under lazy TAIT
Problem 2
Doesn't compile with lazy TAIT
2021-11-30
#![feature(never_type_fallback)]
()
u32
()
, ok!
, errori32
u32
()
, error!
, error()
!
()
, ok!
, ok!
()
, error!
, oku32
()
, error!
, errorif we say:
!
type (or()
) if there are no constraintsbut it did not before.
Example 2
2021-08-30
2021-08-23
The test table
the table
Use outside of a “defining use”
Auto trait leakage
Inference cycle
weird return types
Oli's turn
resolve_if_possible
to replace opaque types and not just inference variablestwo out-of-scope opaque types referencing one another
Good
Not so good
two opaque types interacting
test table
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →In test file:
x.py test –report foo
2021-08-20
2021-08-16
lazy_tait2
branch is almost working but hitting some kind of errormin_type_alias_impl_trait
is removed2021-07-19
Status checkin
2021-07-16
Option<DefId>
that is the "impl trait scope"type_of
query, when trying to get the revealed type,fixup_
thing sometimes resolves them to the declarations generics lifetimes (but in some incorrect way)impl Trait
types that appear in the signaturemay_define_opaque_type
)resolve_variables_if_possible
ty::PlaceholderOpaqueType
that you map toty::OpaqueType
2021-07-14
MCP:
2021-07-12
min_type_alias_impl_trait
?min_type_alias_impl_trait
F-min_type_alias_impl_trait
cargo test +rust-0-stage1 src/test/ui
*
Options:
Outcome from this discussion
fn foo(x: impl Trait)
)fn foo() -> impl Trait
)type Foo = impl Trait; fn bar(x: Foo)
– not a defining use todayfn bar(x: <() as Foo>::Output2)
min_type_alias_impl_trait
restrictions by using normalizationx.method()
(who cares)impl Trait
in an impl, it appears as opaqueResult of today's meeting
Make everything be a defining use that typeck figures to be a defining use via https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#structfield.concrete_opaque_types