-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Update RuntimeHelpers.Await
rules
#77957
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,10 @@ public static class RuntimeHelpers | |
public static void Await(ValueTask task); | ||
[MethodImpl(MethodImplOptions.Async)] | ||
public static T Await<T>(ValueTask<T> task); | ||
[MethodImpl(MethodImplOptions.Async)] | ||
public static void Await(ConfiguredTaskAwaitable task); | ||
[MethodImpl(MethodImplOptions.Async)] | ||
public static T Await<T>(ConfiguredTaskAwaitable<T> task); | ||
} | ||
``` | ||
|
||
|
@@ -136,11 +140,38 @@ for given scenarios are elaborated in more detail below. | |
|
||
TODO: Async iterators (returning `IAsyncEnumerable<T>`) | ||
|
||
#### `Task`, `Task<T>`, `ValueTask`, `ValueTask<T>` Scenarios | ||
|
||
For any lvalue of one of these types, we'll generally rewrite `await expr` into `System.Runtime.CompilerServices.RuntimeHelpers.Await(expr)`. A number of different example scenarios for this are covered below. The | ||
#### `RuntimeHelpers.Await` Scenarios | ||
|
||
The for any `await expr` with type `E`, the compiler will attempt to match it to a helper method in `System.Runtime.CompilerServices.RuntimeHelpers`. The following algorithm is used: | ||
333fred marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
1. If `E` has generic arity greater than 1, no match is found and instead move to [await any other type]. | ||
2. `System.Runtime.CompilerServices.RuntimeHelpers` from corelib (the library that defines `System.Object` and has no references) is fetched. | ||
3. All methods named `Await` are put into a group called `M`. | ||
4. For every `Mi` in `M`: | ||
1. If `Mi`'s generic arity does not match `E`, it is removed. | ||
2. If `Mi` takes more than 1 parameter (named `P`), it is removed. | ||
3. If `Mi` has a generic arity of 0, all of the following must be true, or `Mi` is removed: | ||
1. The return type is `System.Void` | ||
2. There is an identity or implicit reference conversion from `E` to the type of `P`. | ||
333fred marked this conversation as resolved.
Show resolved
Hide resolved
|
||
4. Otherwise, if `Mi` has a generic arity of 1 with type param `Tm`, all of the following must be true, or `Mi` is removed: | ||
1. The return type is `Tm` | ||
2. There is an identity or implicit reference conversion from `E`'s unsubstituted definition to `P` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm unsure what " There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct. I also struggled to find a better wording, but couldn't come up with one. |
||
3. `E`'s type argument, `Te`, is valid to substitute for `Tm` | ||
6. If only one `Mi` remains, that method is used for the following rewrites. Otherwise, we instead move to [await any other type]. | ||
|
||
We'll generally rewrite `await expr` into `System.Runtime.CompilerServices.RuntimeHelpers.Await(expr)`. A number of different example scenarios for this are covered below. The | ||
main interesting deviations are when `struct` rvalues need to be hoisted across an `await`, and exception handling rewriting. | ||
|
||
These rules are intended cover the following types: | ||
333fred marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
* `Task`, or any subtypes of `Task` | ||
* `Task<T>`, or any subtypes of `Task<T>` | ||
* `ValueTask` | ||
* `ValueTask<T>` | ||
* `ConfiguredTaskAwaitable` | ||
* `ConfiguredTaskAwaitable<T>` | ||
* Any future `Task`-like types the runtime would like to intrinsify | ||
|
||
##### Await `Task`-returning method | ||
|
||
```cs | ||
|
@@ -634,7 +665,8 @@ a[_tmp1] = _tmp2 + _tmp3; | |
} | ||
``` | ||
|
||
#### Await a non-Task/ValueTask | ||
#### Await any other type | ||
[await any other type]: #await-any-other-type | ||
|
||
For anything that isn't a `Task`, `Task<T>`, `ValueTask`, and `ValueTask<T>`, we instead use `System.Runtime.CompilerServices.RuntimeHelpers.AwaitAwaiterFromRuntimeAsync` or | ||
`System.Runtime.CompilerServices.RuntimeHelpers.UnsafeAwaitAwaiterFromRuntimeAsync`. These are covered below. | ||
|
Uh oh!
There was an error while loading. Please reload this page.