-
Notifications
You must be signed in to change notification settings - Fork 84
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
C# 7.x §15.15.1 task type must not have multiple type arguments #856
Comments
Fixing this is complicated by the following paragraph in §15.2.1:
interacting with §15.15.1
when the task type is nested in a generic type. Perhaps then, §15.15.1 should talk about the presence or absence of a type_parameter_list, rather than the type being generic or not. |
- `Task` and `Task<T>` are classified as task types despite not specifying builder types - Interfaces are allowed to be task types - Enums and methods are prohibited from being decorated with AsyncMethodBuilderAttribute - Task types must not be generic in more than one type parameter (including in terms of containing types) Discussion required for all of this, but if merged, would fix dotnet#854, dotnet#856, dotnet#858 and dotnet#859.
Got a funny idea for how to define a task builder for a task type nested in a generic type, without hardcoding the type arguments of the containing type. Alas, Roslyn rejects it, and the current C# 7.x wording doesn't allow it either. using System;
using System.Runtime.CompilerServices;
class C {
// «TaskType»<T> is Outer<char>.CustomTask<int>.
// «TaskBuilderType»<T> is CustomTaskBuilder<int>; the type argument in Outer<char> does not affect this.
async Outer<char>.CustomTask<int> M() => 1; // error CS8204
}
public class Outer<T1> {
[AsyncMethodBuilder(typeof(CustomTaskBuilder<>))]
public struct CustomTask<T2>
{
public static implicit operator CustomTask<T2>(
CustomTaskBuilder<T2>.ConvertibleTask convertibleTask)
=> default;
}
}
public struct CustomTaskBuilder<TResult> {
public static CustomTaskBuilder<TResult> Create() => default;
public void Start<TStateMachine>(
ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine {}
public void SetStateMachine(
IAsyncStateMachine stateMachine) {}
public void SetException(
Exception exception) {}
public void SetResult(TResult result) {}
public void AwaitOnCompleted<TAwaiter,TStateMachine>(
ref TAwaiter awaiter,
ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine {}
public void AwaitUnsafeOnCompleted<TAwaiter,TStateMachine>(
ref TAwaiter awaiter,
ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine {}
// This is not exactly «TaskType»<T>, but has an implicit conversion to that.
public ConvertibleTask Task => default;
public struct ConvertibleTask {}
} |
Thinking about this in the context of #875, I think I'll make a change to prohibit generic containing types entirely. It makes everything much simpler... I think we can leave any laxness on Roslyn's side as an extension for now. |
* Clarify task types - `Task` and `Task<T>` are classified as task types despite not specifying builder types - Interfaces are allowed to be task types - Enums and methods are prohibited from being decorated with AsyncMethodBuilderAttribute - Task types must not be generic in more than one type parameter (including in terms of containing types) Discussion required for all of this, but if merged, would fix #854, #856, #858 and #859. * Prevent nesting within generic types, for task types. This wording follows the wording in 15.15.2 for task builders.
Closed by #875. |
Describe the bug
In the C# 7.x draft, §15.15.1 (Async functions / General) restricts the genericity of a task type:
This allows a constructed task type with more than one type argument, but Roslyn does not support that.
Example
The standard should not allow:
Expected behavior
Declare that the task type shall not have more than one type argument.
(Use "type argument" rather than "type parameter", because task types are constructed types.)
Additional context
Unlike a task builder type, a task type can be nested in a generic type. Example:
The text was updated successfully, but these errors were encountered: