未验证 提交 4bf785cb 编写于 作者: J Julien Couvreur 提交者: GitHub

Fix lowering for async-iterator method with type parameter (#30105)

上级 703bfbc5
......@@ -59,6 +59,9 @@ async IAsyncEnumerable<int> GetValuesFromServer()
### Detailed design for async `foreach` statement
PROTOTYPE(async-streams): TODO
Async foreach is disallowed on collections of type dynamic, as there is no async equivalent of the non-generic `IEnumerable` interface.
```C#
E e = ((C)(x)).GetAsyncEnumerator()
try
......@@ -81,13 +84,18 @@ finally { await e.DisposeAsync(); }
### Detailed design for async-iterator methods
An async-iterator method is replaced by a kick-off method, which initializes a state machine. It does not start running the state machine (unlike kick-off methods for regular async method).
The kick-off method method is marked with both `AsyncStateMachineAttribute` and `IteratorStateMachineAttribute`.
The state machine for an async-iterator method primarily implements `IAsyncEnumerable<T>` and `IAsyncEnumerator<T>`.
It is similar to a state machine produced for an async method. It contains builder and awaiter fields, used to run the state machine in the background (when an `await` is reached in the async-iterator).
It is similar to a state machine produced for an async method. It contains builder and awaiter fields, used to run the state machine in the background (when an `await` is reached in the async-iterator). It also captures parameter values (if any) or `this` (if needed).
But it contains additional state:
- a promise of a value-or-end,
- a `bool` flag indicating whether the promise is active or not,
- a current yielded value of type `T`.
The central method of the state machine is `MoveNext()`. It gets run by `WaitForNextAsync()` and `TryGetNext()`, or as a background continuation initiated from these from an `await` in the method.
The promise of a value-or-end is returned from `WaitForNextAsync`. It can be fulfilled with either:
- `true` (when a value becomes available following background execution of the state machine),
- `false` (if the end is reached),
......
......@@ -262,10 +262,12 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
if (IsDirectlyInIterator)
{
diagnostics.Add(ErrorCode.ERR_BadIteratorLocalType, local.IdentifierToken.GetLocation());
hasErrors = true;
}
else if (IsInAsyncMethod())
{
diagnostics.Add(ErrorCode.ERR_BadAsyncLocalType, local.IdentifierToken.GetLocation());
hasErrors = true;
}
}
......@@ -369,8 +371,8 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
{
return new BoundForEachStatement(
_syntax,
null, // can't be sure that it's complete
default(Conversion),
enumeratorInfoOpt: null, // can't be sure that it's complete
elementConversion: default,
boundIterationVariableType,
iterationVariables,
iterationErrorExpression,
......@@ -683,6 +685,12 @@ private EnumeratorResult GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder bui
return EnumeratorResult.FailedAndReported;
}
if (collectionExprType.Kind == SymbolKind.DynamicType && IsAsync)
{
diagnostics.Add(ErrorCode.ERR_BadDynamicAsyncForEach, _syntax.Expression.Location);
return EnumeratorResult.FailedAndReported;
}
// The spec specifically lists the collection, enumerator, and element types for arrays and dynamic.
if (collectionExprType.Kind == SymbolKind.ArrayType || collectionExprType.Kind == SymbolKind.DynamicType)
{
......
......@@ -701,7 +701,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to Async foreach statement cannot operate on variables of type &apos;{0}&apos; because &apos;{0}&apos; does not contain a public definition for &apos;{1}&apos;.
/// Looks up a localized string similar to Async foreach statement cannot operate on variables of type &apos;{0}&apos; because &apos;{0}&apos; does not contain a public instance definition for &apos;{1}&apos;.
/// </summary>
internal static string ERR_AsyncForEachMissingMember {
get {
......@@ -710,7 +710,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to Async foreach statement cannot operate on variables of type &apos;{0}&apos; because &apos;{0}&apos; does not contain a public definition for &apos;{1}&apos;. Did you mean &apos;foreach&apos; rather than &apos;foreach await&apos;?.
/// Looks up a localized string similar to Async foreach statement cannot operate on variables of type &apos;{0}&apos; because &apos;{0}&apos; does not contain a public instance definition for &apos;{1}&apos;. Did you mean &apos;foreach&apos; rather than &apos;foreach await&apos;?.
/// </summary>
internal static string ERR_AsyncForEachMissingMemberWrongAsync {
get {
......@@ -1420,6 +1420,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Cannot use a collection of dynamic type in an asynchronous foreach.
/// </summary>
internal static string ERR_BadDynamicAsyncForEach {
get {
return ResourceManager.GetString("ERR_BadDynamicAsyncForEach", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &apos;{0}&apos;: user-defined conversions to or from the dynamic type are not allowed.
/// </summary>
......
......@@ -2633,13 +2633,13 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep
<value>foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</value>
</data>
<data name="ERR_AsyncForEachMissingMember" xml:space="preserve">
<value>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</value>
<value>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</value>
</data>
<data name="ERR_ForEachMissingMemberWrongAsync" xml:space="preserve">
<value>foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach await'?</value>
</data>
<data name="ERR_AsyncForEachMissingMemberWrongAsync" xml:space="preserve">
<value>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</value>
<value>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</value>
</data>
<data name="WRN_BadXMLRefParamType" xml:space="preserve">
<value>Invalid type for parameter {0} in XML comment cref attribute: '{1}'</value>
......@@ -5390,4 +5390,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="IDS_FeatureUnconstrainedTypeParameterInNullCoalescingOperator" xml:space="preserve">
<value>unconstrained type parameters in null coalescing operator</value>
</data>
</root>
\ No newline at end of file
<data name="ERR_BadDynamicAsyncForEach" xml:space="preserve">
<value>Cannot use a collection of dynamic type in an asynchronous foreach</value>
</data>
</root>
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
......@@ -114,8 +113,8 @@ public override int GetHashCode()
Hash.Combine(ElementType,
Hash.Combine(ElementConversion.GetHashCode(),
Hash.Combine(CurrentConversion.GetHashCode(),
Hash.Combine(WaitForNextAsyncMethod.GetHashCode(),
TryGetNextMethod.GetHashCode()))))))));
Hash.Combine(WaitForNextAsyncMethod,
TryGetNextMethod?.GetHashCode() ?? 0))))))));
}
}
}
......@@ -1592,6 +1592,7 @@ internal enum ErrorCode
ERR_MultipleIAsyncEnumOfT = 9003,
ERR_ForEachMissingMemberWrongAsync = 9004,
ERR_AsyncForEachMissingMemberWrongAsync = 9005,
ERR_BadDynamicAsyncForEach = 9006,
#endregion diagnostics introduced for C# 8.0
// Note: you will need to re-generate compiler code after adding warnings (build\scripts\generate-compiler-code.cmd)
......
......@@ -2157,7 +2157,6 @@ public override BoundNode VisitForEachStatement(BoundForEachStatement node)
{
_pendingBranches.Add(new PendingBranch(node, this.State));
}
//if (_trackExceptions) NotePossibleException(node); // PROTOTYPE(async-streams)
return null;
}
......
......@@ -30,8 +30,6 @@ private sealed class AsyncIteratorRewriter : AsyncRewriter
: base(body, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics)
{
Debug.Assert(method.IteratorElementType != null);
// PROTOTYPE(async-streams): Why does AsyncRewriter have logic to ignore accessibility?
}
protected override void VerifyPresenceOfRequiredAPIs(DiagnosticBag bag)
......@@ -101,8 +99,11 @@ protected override void GenerateControlFields()
boolType,
GeneratedNames.MakeAsyncIteratorPromiseIsActiveFieldName(), isPublic: true);
// the element type may contain method type parameters, which are now alpha-renamed into type parameters of the generated class
TypeSymbol elementType = ((AsyncStateMachine)stateMachineType).IteratorElementType;
// Add a field: T current
_currentField = F.StateMachineField(method.IteratorElementType, GeneratedNames.MakeIteratorCurrentFieldName());
_currentField = F.StateMachineField(elementType, GeneratedNames.MakeIteratorCurrentFieldName());
}
/// <summary>
......@@ -110,8 +111,6 @@ protected override void GenerateControlFields()
/// </summary>
protected override BoundStatement GenerateStateMachineCreation(LocalSymbol stateMachineVariable, NamedTypeSymbol frameType)
{
// PROTOTYPE(async-streams): TODO review this (what is this error case at the start?)
// If the async method's result type is a type parameter of the method, then the AsyncTaskMethodBuilder<T>
// needs to use the method's type parameters inside the rewritten method body. All other methods generated
// during async rewriting are members of the synthesized state machine struct, and use the type parameters
......@@ -154,7 +153,7 @@ protected override BoundStatement GenerateStateMachineCreation(LocalSymbol state
F.Field(F.Local(stateMachineVariable), _promiseIsActiveField.AsMember(frameType)),
F.Literal(true)));
// return local.$stateField;
// return local;
bodyBuilder.Add(F.Return(F.Local(stateMachineVariable)));
return F.Block(
......@@ -225,7 +224,7 @@ private void GenerateIAsyncEnumeratorImplementation_TryGetNext()
// Produce the implementation for `T TryGetNext(out bool success)`:
// if (this._promiseIsActive)
// {
// if (_valueOrEndPromise.GetStatus(_valueOrEndPromise.Version) == ValueTaskSourceStatus.Pending) throw new Exception(); // PROTOTYPE(NullableReferenceTypes): Add this safeguard code
// if (_valueOrEndPromise.GetStatus(_valueOrEndPromise.Version) == ValueTaskSourceStatus.Pending) throw new Exception(); // https://github.com/dotnet/roslyn/issues/30109 Add this safeguard code
// _promiseIsActive = false;
// }
// else
......@@ -264,7 +263,7 @@ private void GenerateIAsyncEnumeratorImplementation_TryGetNext()
// if (this._promiseIsActive)
// {
// if (_valueOrEndPromise.GetStatus(_valueOrEndPromise.Version) == ValueTaskSourceStatus.Pending) throw new Exception();
// if (State == StateMachineStates.NotStartedStateMachine) throw new Exception("You should call WaitForNextAsync first"); // PROTOTYPE(NullableReferenceTypes): Add this safeguard code
// if (State == StateMachineStates.NotStartedStateMachine) throw new Exception("You should call WaitForNextAsync first"); // https://github.com/dotnet/roslyn/issues/30109 Add this safeguard code
// _promiseIsActive = false;
// }
// else
......@@ -504,13 +503,9 @@ private void GenerateIAsyncEnumerableImplementation_GetAsyncEnumerator()
F.WellKnownMethod(WellKnownMember.System_Collections_Generic_IAsyncEnumerable_T__GetAsyncEnumerator)
.AsMember(IAsyncEnumerableOfElementType);
// PROTOTYPE(async-streams): TODO
// result = this;
// result.parameter = this.parameterProxy; // copy all of the parameter proxies // PROTOTYPE(async-streams): No sure what this is for
// The implementation doesn't depend on the method body of the iterator method.
// Generates IAsyncEnumerator<elementType> IAsyncEnumerable<elementType>.GetEnumerator()
OpenMethodImplementation( IAsyncEnumerableOfElementType_GetEnumerator, hasMethodBodyDependency: false);
OpenMethodImplementation(IAsyncEnumerableOfElementType_GetEnumerator, hasMethodBodyDependency: false);
// PROTOTYPE(async-streams): 0 is not the proper state to start with
F.CloseMethod(F.Block(
......
......@@ -12,7 +12,6 @@ internal partial class AsyncRewriter : StateMachineRewriter
private readonly AsyncMethodBuilderMemberCollection _asyncMethodBuilderMemberCollection;
private readonly bool _constructedSuccessfully;
private readonly int _methodOrdinal;
private readonly bool _ignoreAccessibility;
private FieldSymbol _builderField;
......@@ -28,7 +27,6 @@ internal partial class AsyncRewriter : StateMachineRewriter
{
_constructedSuccessfully = AsyncMethodBuilderMemberCollection.TryCreate(F, method, this.stateMachineType.TypeMap, out _asyncMethodBuilderMemberCollection);
_methodOrdinal = methodOrdinal;
_ignoreAccessibility = compilationState.ModuleBuilderOpt.IgnoreAccessibility;
}
/// <summary>
......
......@@ -16,6 +16,7 @@ internal sealed class AsyncStateMachine : StateMachineTypeSymbol
private readonly TypeKind _typeKind;
private readonly MethodSymbol _constructor;
private readonly ImmutableArray<NamedTypeSymbol> _interfaces;
internal readonly TypeSymbol IteratorElementType; // only for async-iterators
public AsyncStateMachine(VariableSlotAllocator variableAllocatorOpt, TypeCompilationState compilationState, MethodSymbol asyncMethod, int asyncMethodOrdinal, TypeKind typeKind)
: base(variableAllocatorOpt, compilationState, asyncMethod, asyncMethodOrdinal)
......@@ -27,8 +28,8 @@ public AsyncStateMachine(VariableSlotAllocator variableAllocatorOpt, TypeCompila
if (asyncMethod.IsIterator)
{
var elementType = asyncMethod.IteratorElementType;
//this.ElementType = TypeMap.SubstituteType(elementType).Type; // PROTOTYPE(async-streams): TODO
var elementType = TypeMap.SubstituteType(asyncMethod.IteratorElementType).Type;
this.IteratorElementType = elementType;
// IAsyncEnumerable<TResult>
interfaces.Add(compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IAsyncEnumerable_T).Construct(elementType));
......
......@@ -174,10 +174,7 @@ protected override void GenerateControlFields()
// if it is an enumerable, and either Environment.CurrentManagedThreadId or Thread.ManagedThreadId are available
// add a field: int initialThreadId
bool addInitialThreadId =
_isEnumerable &&
((object)F.WellKnownMember(WellKnownMember.System_Threading_Thread__ManagedThreadId, isOptional: true) != null ||
(object)F.WellKnownMember(WellKnownMember.System_Environment__CurrentManagedThreadId, isOptional: true) != null);
bool addInitialThreadId = _isEnumerable && CanGetThreadId();
_initialThreadIdField = addInitialThreadId
? F.StateMachineField(F.SpecialType(SpecialType.System_Int32), GeneratedNames.MakeIteratorCurrentThreadIdFieldName())
......@@ -284,23 +281,7 @@ private void GenerateEnumerableImplementation(ref BoundExpression managedThreadI
if ((object)_initialThreadIdField != null)
{
MethodSymbol currentManagedThreadIdMethod = null;
PropertySymbol currentManagedThreadIdProperty = F.WellKnownMember(WellKnownMember.System_Environment__CurrentManagedThreadId, isOptional: true) as PropertySymbol;
if ((object)currentManagedThreadIdProperty != null)
{
currentManagedThreadIdMethod = currentManagedThreadIdProperty.GetMethod;
}
if ((object)currentManagedThreadIdMethod != null)
{
managedThreadId = F.Call(null, currentManagedThreadIdMethod);
}
else
{
managedThreadId = F.Property(F.Property(WellKnownMember.System_Threading_Thread__CurrentThread), WellKnownMember.System_Threading_Thread__ManagedThreadId);
}
managedThreadId = MakeCurrentThreadId();
makeIterator = F.If(
condition: F.LogicalAnd( // if (this.state == -2 && this.initialThreadId == Thread.CurrentThread.ManagedThreadId)
......
......@@ -325,5 +325,33 @@ protected SynthesizedImplementationMethod OpenMoveNextMethodImplementation(Metho
F.CurrentFunction = result;
return result;
}
/// <summary>
/// Produce Environment.CurrentManagedThreadId if available, otherwise CurrentThread.ManagedThreadId
/// </summary>
protected BoundExpression MakeCurrentThreadId()
{
Debug.Assert(CanGetThreadId());
var currentManagedThreadIdProperty = (PropertySymbol)F.WellKnownMember(WellKnownMember.System_Environment__CurrentManagedThreadId, isOptional: true);
if ((object)currentManagedThreadIdProperty != null)
{
MethodSymbol currentManagedThreadIdMethod = currentManagedThreadIdProperty.GetMethod;
if ((object)currentManagedThreadIdMethod != null)
{
return F.Call(null, currentManagedThreadIdMethod);
}
}
return F.Property(F.Property(WellKnownMember.System_Threading_Thread__CurrentThread), WellKnownMember.System_Threading_Thread__ManagedThreadId);
}
/// <summary>
/// Returns true if either Thread.ManagedThreadId or Environment.CurrentManagedThreadId are available
/// </summary>
protected bool CanGetThreadId()
{
return (object)F.WellKnownMember(WellKnownMember.System_Threading_Thread__ManagedThreadId, isOptional: true) != null ||
(object)F.WellKnownMember(WellKnownMember.System_Environment__CurrentManagedThreadId, isOptional: true) != null;
}
}
}
......@@ -1613,35 +1613,44 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r
{
base.AddSynthesizedAttributes(moduleBuilder, ref attributes);
if (this.IsAsync || this.IsIterator)
bool isAsync = this.IsAsync;
bool isIterator = this.IsIterator;
if (!isAsync && !isIterator)
{
var compilation = this.DeclaringCompilation;
// PROTOTYPE(async-streams): Need to review this
return;
}
// The async state machine type is not synthesized until the async method body is rewritten. If we are
// only emitting metadata the method body will not have been rewritten, and the async state machine
// type will not have been created. In this case, omit the attribute.
NamedTypeSymbol stateMachineType;
if (moduleBuilder.CompilationState.TryGetStateMachineType(this, out stateMachineType))
{
WellKnownMember ctor = this.IsAsync ?
WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor :
WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor;
var compilation = this.DeclaringCompilation;
var arg = new TypedConstant(compilation.GetWellKnownType(WellKnownType.System_Type), TypedConstantKind.Type, stateMachineType.GetUnboundGenericTypeOrSelf());
// The async state machine type is not synthesized until the async method body is rewritten. If we are
// only emitting metadata the method body will not have been rewritten, and the async state machine
// type will not have been created. In this case, omit the attribute.
if (moduleBuilder.CompilationState.TryGetStateMachineType(this, out NamedTypeSymbol stateMachineType))
{
var arg = new TypedConstant(compilation.GetWellKnownType(WellKnownType.System_Type),
TypedConstantKind.Type, stateMachineType.GetUnboundGenericTypeOrSelf());
AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(ctor, ImmutableArray.Create(arg)));
if (isAsync)
{
AddSynthesizedAttribute(ref attributes,
compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor,
ImmutableArray.Create(arg)));
}
if (this.IsAsync)
if (isIterator)
{
// Async kick-off method calls MoveNext, which contains user code.
// This means we need to emit DebuggerStepThroughAttribute in order
// to have correct stepping behavior during debugging.
AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDebuggerStepThroughAttribute());
AddSynthesizedAttribute(ref attributes,
compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor,
ImmutableArray.Create(arg)));
}
}
if (isAsync && !isIterator)
{
// Regular async (not async-iterator) kick-off method calls MoveNext, which contains user code.
// This means we need to emit DebuggerStepThroughAttribute in order
// to have correct stepping behavior during debugging.
AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDebuggerStepThroughAttribute());
}
}
/// <summary>
......
......@@ -18,8 +18,13 @@
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMemberWrongAsync">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadDynamicAsyncForEach">
<source>Cannot use a collection of dynamic type in an asynchronous foreach</source>
<target state="new">Cannot use a collection of dynamic type in an asynchronous foreach</target>
<note />
</trans-unit>
<trans-unit id="ERR_CantUseInOrOutInArglist">
......@@ -8813,8 +8818,8 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMember">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadGetAsyncEnumerator">
......
......@@ -18,8 +18,13 @@
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMemberWrongAsync">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadDynamicAsyncForEach">
<source>Cannot use a collection of dynamic type in an asynchronous foreach</source>
<target state="new">Cannot use a collection of dynamic type in an asynchronous foreach</target>
<note />
</trans-unit>
<trans-unit id="ERR_CantUseInOrOutInArglist">
......@@ -8826,8 +8831,8 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMember">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadGetAsyncEnumerator">
......
......@@ -18,8 +18,13 @@
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMemberWrongAsync">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadDynamicAsyncForEach">
<source>Cannot use a collection of dynamic type in an asynchronous foreach</source>
<target state="new">Cannot use a collection of dynamic type in an asynchronous foreach</target>
<note />
</trans-unit>
<trans-unit id="ERR_CantUseInOrOutInArglist">
......@@ -8800,8 +8805,8 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMember">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadGetAsyncEnumerator">
......
......@@ -18,8 +18,13 @@
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMemberWrongAsync">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadDynamicAsyncForEach">
<source>Cannot use a collection of dynamic type in an asynchronous foreach</source>
<target state="new">Cannot use a collection of dynamic type in an asynchronous foreach</target>
<note />
</trans-unit>
<trans-unit id="ERR_CantUseInOrOutInArglist">
......@@ -8801,8 +8806,8 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMember">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadGetAsyncEnumerator">
......
......@@ -18,8 +18,13 @@
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMemberWrongAsync">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadDynamicAsyncForEach">
<source>Cannot use a collection of dynamic type in an asynchronous foreach</source>
<target state="new">Cannot use a collection of dynamic type in an asynchronous foreach</target>
<note />
</trans-unit>
<trans-unit id="ERR_CantUseInOrOutInArglist">
......@@ -8802,8 +8807,8 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMember">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadGetAsyncEnumerator">
......
......@@ -18,8 +18,13 @@
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMemberWrongAsync">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadDynamicAsyncForEach">
<source>Cannot use a collection of dynamic type in an asynchronous foreach</source>
<target state="new">Cannot use a collection of dynamic type in an asynchronous foreach</target>
<note />
</trans-unit>
<trans-unit id="ERR_CantUseInOrOutInArglist">
......@@ -8826,8 +8831,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMember">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadGetAsyncEnumerator">
......
......@@ -18,8 +18,13 @@
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMemberWrongAsync">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadDynamicAsyncForEach">
<source>Cannot use a collection of dynamic type in an asynchronous foreach</source>
<target state="new">Cannot use a collection of dynamic type in an asynchronous foreach</target>
<note />
</trans-unit>
<trans-unit id="ERR_CantUseInOrOutInArglist">
......@@ -8826,8 +8831,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMember">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadGetAsyncEnumerator">
......
......@@ -18,8 +18,13 @@
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMemberWrongAsync">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadDynamicAsyncForEach">
<source>Cannot use a collection of dynamic type in an asynchronous foreach</source>
<target state="new">Cannot use a collection of dynamic type in an asynchronous foreach</target>
<note />
</trans-unit>
<trans-unit id="ERR_CantUseInOrOutInArglist">
......@@ -8805,8 +8810,8 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMember">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadGetAsyncEnumerator">
......
......@@ -18,8 +18,13 @@
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMemberWrongAsync">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadDynamicAsyncForEach">
<source>Cannot use a collection of dynamic type in an asynchronous foreach</source>
<target state="new">Cannot use a collection of dynamic type in an asynchronous foreach</target>
<note />
</trans-unit>
<trans-unit id="ERR_CantUseInOrOutInArglist">
......@@ -8806,8 +8811,8 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMember">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadGetAsyncEnumerator">
......
......@@ -18,8 +18,13 @@
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMemberWrongAsync">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadDynamicAsyncForEach">
<source>Cannot use a collection of dynamic type in an asynchronous foreach</source>
<target state="new">Cannot use a collection of dynamic type in an asynchronous foreach</target>
<note />
</trans-unit>
<trans-unit id="ERR_CantUseInOrOutInArglist">
......@@ -8808,8 +8813,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMember">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadGetAsyncEnumerator">
......
......@@ -18,8 +18,13 @@
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMemberWrongAsync">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadDynamicAsyncForEach">
<source>Cannot use a collection of dynamic type in an asynchronous foreach</source>
<target state="new">Cannot use a collection of dynamic type in an asynchronous foreach</target>
<note />
</trans-unit>
<trans-unit id="ERR_CantUseInOrOutInArglist">
......@@ -8814,8 +8819,8 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMember">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadGetAsyncEnumerator">
......
......@@ -18,8 +18,13 @@
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMemberWrongAsync">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadDynamicAsyncForEach">
<source>Cannot use a collection of dynamic type in an asynchronous foreach</source>
<target state="new">Cannot use a collection of dynamic type in an asynchronous foreach</target>
<note />
</trans-unit>
<trans-unit id="ERR_CantUseInOrOutInArglist">
......@@ -8826,8 +8831,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMember">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadGetAsyncEnumerator">
......
......@@ -18,8 +18,13 @@
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMemberWrongAsync">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'. Did you mean 'foreach' rather than 'foreach await'?</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadDynamicAsyncForEach">
<source>Cannot use a collection of dynamic type in an asynchronous foreach</source>
<target state="new">Cannot use a collection of dynamic type in an asynchronous foreach</target>
<note />
</trans-unit>
<trans-unit id="ERR_CantUseInOrOutInArglist">
......@@ -8826,8 +8831,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<note />
</trans-unit>
<trans-unit id="ERR_AsyncForEachMissingMember">
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public definition for '{1}'</target>
<source>Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</source>
<target state="new">Async foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a public instance definition for '{1}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_BadGetAsyncEnumerator">
......
......@@ -54,7 +54,7 @@ async System.Threading.Tasks.Task M()
}";
var comp = CreateCompilationWithMscorlib46(source);
comp.VerifyDiagnostics(
// (6,33): error CS9001: Async foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public definition for 'GetAsyncEnumerator'
// (6,33): error CS9001: Async foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance definition for 'GetAsyncEnumerator'
// foreach await (var i in new C())
Diagnostic(ErrorCode.ERR_AsyncForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(6, 33)
);
......@@ -82,7 +82,7 @@ public sealed class Enumerator
}";
var comp = CreateCompilationWithMscorlib46(source);
comp.VerifyDiagnostics(
// (6,33): error CS9001: Async foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public definition for 'GetAsyncEnumerator'
// (6,33): error CS9001: Async foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance definition for 'GetAsyncEnumerator'
// foreach await (var i in new C())
Diagnostic(ErrorCode.ERR_AsyncForEachMissingMember, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(6, 33)
);
......@@ -701,6 +701,26 @@ class Element
"Next(26) Convert(0) NextAsync(26) Dispose(37)", verify: Verification.Skipped);
}
[Fact]
public void TestWithDynamicCollection()
{
string source = @"
class C
{
public static async System.Threading.Tasks.Task Main()
{
foreach await (var i in (dynamic)new C())
{
}
}
}";
var comp = CreateCompilationWithTasksExtensions(new[] { source, s_interfaces });
comp.VerifyDiagnostics(
// (6,33): error CS9006: Cannot use a collection of dynamic type in an asynchronous foreach
// foreach await (var i in (dynamic)new C())
Diagnostic(ErrorCode.ERR_BadDynamicAsyncForEach, "(dynamic)new C()").WithLocation(6, 33));
}
[Fact]
public void TestWithIncompleteInterface()
{
......@@ -1079,7 +1099,7 @@ void M(IEnumerable<int> collection)
}";
var comp = CreateCompilationWithTasksExtensions(source + s_interfaces);
comp.VerifyDiagnostics(
// (7,33): error CS9005: Async foreach statement cannot operate on variables of type 'IEnumerable<int>' because 'IEnumerable<int>' does not contain a public definition for 'GetAsyncEnumerator'. Did you mean 'foreach' rather than 'foreach await'?
// (7,33): error CS9005: Async foreach statement cannot operate on variables of type 'IEnumerable<int>' because 'IEnumerable<int>' does not contain a public instance definition for 'GetAsyncEnumerator'. Did you mean 'foreach' rather than 'foreach await'?
// foreach await (var i in collection)
Diagnostic(ErrorCode.ERR_AsyncForEachMissingMemberWrongAsync, "collection").WithArguments("System.Collections.Generic.IEnumerable<int>", "GetAsyncEnumerator").WithLocation(7, 33),
// (7,17): error CS4033: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.
......@@ -1141,7 +1161,7 @@ public bool MoveNext()
}";
var comp = CreateCompilationWithTasksExtensions(source + s_interfaces);
comp.VerifyDiagnostics(
// (6,33): error CS9005: Async foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public definition for 'GetAsyncEnumerator'. Did you mean 'foreach' rather than 'foreach await'?
// (6,33): error CS9005: Async foreach statement cannot operate on variables of type 'C' because 'C' does not contain a public instance definition for 'GetAsyncEnumerator'. Did you mean 'foreach' rather than 'foreach await'?
// foreach await (var i in new C())
Diagnostic(ErrorCode.ERR_AsyncForEachMissingMemberWrongAsync, "new C()").WithArguments("C", "GetAsyncEnumerator").WithLocation(6, 33)
);
......@@ -1199,6 +1219,327 @@ public int TryGetNext(out bool success)
Assert.False(internalInfo.NeedsDisposeMethod);
}
[Fact]
public void TestWithPattern_Ref()
{
string source = @"
class C
{
async System.Threading.Tasks.Task M()
{
foreach await (ref var i in new C())
{
}
}
public Enumerator GetAsyncEnumerator()
=> throw null;
public sealed class Enumerator
{
public System.Threading.Tasks.Task<bool> WaitForNextAsync()
=> throw null;
public int TryGetNext(out bool success)
=> throw null;
}
}";
var comp = CreateCompilationWithTasksExtensions(source + s_interfaces);
comp.VerifyDiagnostics(
// (6,32): error CS8177: Async methods cannot have by-reference locals
// foreach await (ref var i in new C())
Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "i").WithLocation(6, 32));
var tree = comp.SyntaxTrees.Single();
var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
Assert.Equal(default, model.GetForEachStatementInfo(foreachSyntax));
}
[Fact]
public void TestWithPattern_PointerType()
{
string source = @"
unsafe class C
{
async System.Threading.Tasks.Task M()
{
foreach await (var i in new C())
{
}
}
public Enumerator GetAsyncEnumerator()
=> throw null;
public sealed class Enumerator
{
public System.Threading.Tasks.Task<bool> WaitForNextAsync()
=> throw null;
public int* TryGetNext(out bool success)
=> throw null;
}
}";
var comp = CreateCompilationWithTasksExtensions(source + s_interfaces, options: TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (6,17): error CS4004: Cannot await in an unsafe context
// foreach await (var i in new C())
Diagnostic(ErrorCode.ERR_AwaitInUnsafeContext, "await").WithLocation(6, 17));
var tree = comp.SyntaxTrees.Single();
var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
Assert.Equal(default, model.GetForEachStatementInfo(foreachSyntax));
}
[Fact]
public void TestWithPattern_InaccessibleGetAsyncEnumerator()
{
string source = @"
class C
{
async System.Threading.Tasks.Task M()
{
foreach await (var i in new D())
{
}
}
}
class D
{
private Enumerator GetAsyncEnumerator()
=> throw null;
public sealed class Enumerator
{
public System.Threading.Tasks.Task<bool> WaitForNextAsync()
=> throw null;
public int TryGetNext(out bool success)
=> throw null;
}
}";
var comp = CreateCompilationWithTasksExtensions(source + s_interfaces);
comp.VerifyDiagnostics(
// (6,33): error CS9001: Async foreach statement cannot operate on variables of type 'D' because 'D' does not contain a public definition for 'GetAsyncEnumerator'
// foreach await (var i in new D())
Diagnostic(ErrorCode.ERR_AsyncForEachMissingMember, "new D()").WithArguments("D", "GetAsyncEnumerator").WithLocation(6, 33)
);
var tree = comp.SyntaxTrees.Single();
var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
Assert.Equal(default, model.GetForEachStatementInfo(foreachSyntax));
}
[Fact]
public void TestWithPattern_InaccessibleWaitForNextAsync()
{
string source = @"
class C
{
async System.Threading.Tasks.Task M()
{
foreach await (var i in new D())
{
}
}
}
class D
{
public Enumerator GetAsyncEnumerator()
=> throw null;
public sealed class Enumerator
{
private System.Threading.Tasks.Task<bool> WaitForNextAsync()
=> throw null;
public int TryGetNext(out bool success)
=> throw null;
}
}";
var comp = CreateCompilationWithTasksExtensions(source + s_interfaces);
comp.VerifyDiagnostics(
// (6,33): error CS0122: 'D.Enumerator.WaitForNextAsync()' is inaccessible due to its protection level
// foreach await (var i in new D())
Diagnostic(ErrorCode.ERR_BadAccess, "new D()").WithArguments("D.Enumerator.WaitForNextAsync()").WithLocation(6, 33),
// (6,33): error CS9002: Async foreach requires that the return type 'D.Enumerator' of 'D.GetAsyncEnumerator()' must have suitable public WaitForNextAsync and TryGetNext methods
// foreach await (var i in new D())
Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new D()").WithArguments("D.Enumerator", "D.GetAsyncEnumerator()").WithLocation(6, 33)
);
var tree = comp.SyntaxTrees.Single();
var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
Assert.Equal(default, model.GetForEachStatementInfo(foreachSyntax));
}
[Fact]
public void TestWithPattern_InaccessibleTryGetNext()
{
string source = @"
class C
{
async System.Threading.Tasks.Task M()
{
foreach await (var i in new D())
{
}
}
}
class D
{
public Enumerator GetAsyncEnumerator()
=> throw null;
public sealed class Enumerator
{
public System.Threading.Tasks.Task<bool> WaitForNextAsync()
=> throw null;
private int TryGetNext(out bool success)
=> throw null;
}
}";
var comp = CreateCompilationWithTasksExtensions(source + s_interfaces);
comp.VerifyDiagnostics(
// (6,33): error CS0122: 'D.Enumerator.TryGetNext(out bool)' is inaccessible due to its protection level
// foreach await (var i in new D())
Diagnostic(ErrorCode.ERR_BadAccess, "new D()").WithArguments("D.Enumerator.TryGetNext(out bool)").WithLocation(6, 33),
// (6,33): error CS9002: Async foreach requires that the return type 'D.Enumerator' of 'D.GetAsyncEnumerator()' must have suitable public WaitForNextAsync and TryGetNext methods
// foreach await (var i in new D())
Diagnostic(ErrorCode.ERR_BadGetAsyncEnumerator, "new D()").WithArguments("D.Enumerator", "D.GetAsyncEnumerator()").WithLocation(6, 33)
);
var tree = comp.SyntaxTrees.Single();
var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false);
var foreachSyntax = tree.GetRoot().DescendantNodes().OfType<ForEachStatementSyntax>().Single();
Assert.Equal(default, model.GetForEachStatementInfo(foreachSyntax));
}
[Fact]
public void TestWithPattern_RefStruct()
{
string source = @"
using static System.Console;
using System.Threading.Tasks;
public class C
{
public static async System.Threading.Tasks.Task Main()
{
foreach await (var s in new C())
{
Write($""{s.ToString()} "");
}
Write(""Done"");
}
public Enumerator GetAsyncEnumerator() => new Enumerator();
public sealed class Enumerator
{
int i = -1;
public S TryGetNext(out bool success)
{
i++;
success = (i % 10 % 3 != 0);
return new S(i);
}
public async Task<bool> WaitForNextAsync()
{
i = i + 11;
bool more = await Task.FromResult(i < 20);
return more;
}
}
}
public ref struct S
{
int i;
public S(int i)
{
this.i = i;
}
public override string ToString()
=> i.ToString();
}
";
var comp = CreateCompilationWithTasksExtensions(source + s_interfaces, options: TestOptions.DebugExe);
comp.VerifyDiagnostics();
CompileAndVerify(comp, expectedOutput: "11 12 Done");
}
[Fact]
public void TestWithPattern_RefReturningTryGetNext()
{
string source = @"
using static System.Console;
using System.Threading.Tasks;
public class C
{
public static async System.Threading.Tasks.Task Main()
{
foreach await (var s in new C())
{
Write($""{s.ToString()} "");
}
Write(""Done"");
}
public Enumerator GetAsyncEnumerator() => new Enumerator();
public sealed class Enumerator
{
int i = -1;
S current;
public ref S TryGetNext(out bool success)
{
i++;
success = (i % 10 % 3 != 0);
current = new S(i);
return ref current;
}
public async Task<bool> WaitForNextAsync()
{
i = i + 11;
bool more = await Task.FromResult(i < 20);
return more;
}
}
}
public struct S
{
int i;
public S(int i)
{
this.i = i;
}
public override string ToString()
=> i.ToString();
}
";
var comp = CreateCompilationWithTasksExtensions(new[] { source, s_interfaces }, options: TestOptions.DebugExe);
comp.VerifyDiagnostics();
CompileAndVerify(comp, expectedOutput: "11 12 Done", verify: Verification.Fails);
}
[Fact]
public void TestWithPattern_IterationVariableIsReadOnly()
{
string source = @"
class C
{
async System.Threading.Tasks.Task M()
{
foreach await (var i in new C())
{
i = 1;
}
}
public Enumerator GetAsyncEnumerator()
=> throw null;
public sealed class Enumerator
{
public System.Threading.Tasks.Task<bool> WaitForNextAsync()
=> throw null;
public int TryGetNext(out bool success)
=> throw null;
}
}";
var comp = CreateCompilationWithTasksExtensions(new[] { source, s_interfaces });
comp.VerifyDiagnostics(
// (8,13): error CS1656: Cannot assign to 'i' because it is a 'foreach iteration variable'
// i = 1;
Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "i").WithArguments("i", "foreach iteration variable").WithLocation(8, 13)
);
}
[Fact]
public void TestWithPattern_WithStruct_WaitForNextAsyncReturnsTask()
{
......@@ -3397,14 +3738,7 @@ .maxstack 3
", sequencePoints: "C+<Main>d__0.MoveNext", source: source);
}
[Fact]
public void TestFoEachStatementInfo_IEquatable()
{
// PROTOTYPE(async-streams) test ForEachStatementInfo equality and such
}
// PROTOTYPE(async-streams) More test ideas
// block dynamic
// test with captures:
// int[] values = { 7, 9, 13 };
......@@ -3415,10 +3749,7 @@ public void TestFoEachStatementInfo_IEquatable()
//}
// f();
// pointer element type
// verify that the foreach variables are readonly
// nested deconstruction or tuple
// pattern with inaccessible methods
// review instrumentation
// test various things that could go wrong with binding the await for DisposeAsync
// throwing exception from enumerator, or from inside the async-foreach
......@@ -3428,15 +3759,10 @@ public void TestFoEachStatementInfo_IEquatable()
// IOperation
// IDE
// scripting?
// foreach on restricted type (like ref struct) in async or iterator method
// foreach on restricted type in a regular method
// Also try with ref-returning TryGetNext. With both ref iteration variable and ordinary one. Not sure what spec says here, but technically either could work. Especially the ordinary byval case - it could even do implicit conversions. Ref-returning methods can work as rvalues too.
// Also, if ref iteration variables are allowed, check readonliness mismatches. I.E. if method returns a readonly ref, but iterator var is an ordinary ref nd the other way around.
// expression trees
// Misc other test ideas:
// Verify that async-dispose doesn't have a similar bug with struct resource
// cleanup: use statement lists for async-using, instead of blocks
// IAsyncEnumerable has an 'out' type parameter, any tests I need to do related to that?
// spec: struct case should be blocked?
// spec: extension methods don't contribute
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Text;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{
using Roslyn.Test.Utilities;
using static Instruction;
internal enum Instruction
{
......@@ -21,23 +22,21 @@ internal enum Instruction
[CompilerTrait(CompilerFeature.AsyncStreams)]
public class CodeGenAsyncIteratorTests : EmitMetadataTestBase
{
// PROTOTYPE(async-streams)
// Test missing remaining types/members once BCL APIs are finalized (MRVTSL, IStrongBox, IValueTaskSource)
// test missing AsyncTaskMethodBuilder<T> or missing members Create(), Task, ...
// PROTOTYPE(async-streams) Add more tests:
// Test with yield or await in try/catch/finally
// More tests with exception thrown
// There is a case in GetIteratorElementType with IsDirectlyInIterator that relates to speculation, needs testing
// yield break disallowed in finally and top-level script (see BindYieldBreakStatement); same for yield return (see BindYieldReturnStatement)
// binding for yield return (BindYieldReturnStatement) validates escape rules, needs testing
// test yield in async lambda (still error)
// test exception handling (should capture and return the exception via the promise)
// test IAsyncEnumerable<U> M<U>() ...
// test with IAsyncEnumerable<dynamic>
// other tests with dynamic?
// test should cover both case with AwaitOnCompleted and AwaitUnsafeOnCompleted
// test `async IAsyncEnumerable<int> M() { return TaskLike(); }`
// Can we avoid making IAsyncEnumerable<T> special from the start? Making mark it with an attribute like we did for task-like?
// Do some manual validation on debugging scenarios, including with exceptions (thrown after yield and after await).
// Test with one or both or the threadID APIs missing.
// Enable remaining windows/desktop-only to run on Core
private void VerifyMissingMember(WellKnownMember member, params DiagnosticDescription[] expected)
{
......@@ -51,9 +50,9 @@ class C
async System.Collections.Generic.IAsyncEnumerable<int> M() { await Task.CompletedTask; yield return 3; }
}
";
var comp = CreateCompilationWithTasksExtensions(source, references: new[] { lib_ref });
comp.MakeMemberMissing(member);
comp.VerifyEmitDiagnostics(expected);
var comp = CreateCompilationWithTasksExtensions(source, references: new[] { lib_ref });
comp.MakeMemberMissing(member);
comp.VerifyEmitDiagnostics(expected);
}
private void VerifyMissingType(WellKnownType type, params DiagnosticDescription[] expected)
......@@ -68,9 +67,60 @@ class C
async System.Collections.Generic.IAsyncEnumerable<int> M() { await Task.CompletedTask; yield return 3; }
}
";
var comp = CreateCompilationWithTasksExtensions(source, references: new[] { lib_ref });
comp.MakeTypeMissing(type);
comp.VerifyEmitDiagnostics(expected);
var comp = CreateCompilationWithTasksExtensions(source, references: new[] { lib_ref });
comp.MakeTypeMissing(type);
comp.VerifyEmitDiagnostics(expected);
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
public void RefStructElementType()
{
string source = @"
class C
{
static async System.Collections.Generic.IAsyncEnumerable<S> M()
{
await System.Threading.Tasks.Task.CompletedTask;
yield return new S();
}
static async System.Threading.Tasks.Task Main()
{
foreach await (var s in M())
{
}
}
}
ref struct S
{
}";
var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe);
comp.VerifyDiagnostics(
// (4,65): error CS0306: The type 'S' may not be used as a type argument
// static async System.Collections.Generic.IAsyncEnumerable<S> M()
Diagnostic(ErrorCode.ERR_BadTypeArgument, "M").WithArguments("S").WithLocation(4, 65)
);
}
[Fact]
public void AttributesSynthesized()
{
string source = @"
public class C
{
public static async System.Collections.Generic.IAsyncEnumerable<int> M()
{
await System.Threading.Tasks.Task.CompletedTask;
yield return 4;
}
}";
var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugDll);
comp.VerifyDiagnostics();
CompileAndVerify(comp, symbolValidator: module =>
{
var method = module.GlobalNamespace.GetMember<MethodSymbol>("C.M");
AssertEx.SetEqual(new[] { "AsyncStateMachineAttribute", "IteratorStateMachineAttribute" },
GetAttributeNames(method.GetAttributes()));
});
}
[Fact]
......@@ -189,6 +239,16 @@ public void MissingTypeAndMembers_IValueTaskSource()
);
}
[Fact]
public void MissingMember_AsyncVoidMethodBuilder()
{
VerifyMissingMember(WellKnownMember.System_Runtime_CompilerServices_AsyncVoidMethodBuilder__Create,
// (5,64): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Create'
// async System.Collections.Generic.IAsyncEnumerable<int> M() { await Task.CompletedTask; yield return 3; }
Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{ await Task.CompletedTask; yield return 3; }").WithArguments("System.Runtime.CompilerServices.AsyncVoidMethodBuilder", "Create").WithLocation(5, 64)
);
}
[Fact]
public void MissingTypeAndMembers_IAsyncStateMachine()
{
......@@ -1097,6 +1157,134 @@ .maxstack 3
}
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
public void AsyncIteratorWithGenericReturn()
{
string source = @"
using static System.Console;
class C
{
static async System.Collections.Generic.IAsyncEnumerable<T> M<T>(T value)
{
Write(""1 "");
await System.Threading.Tasks.Task.CompletedTask;
Write(""2 "");
yield return value;
Write("" 4 "");
}
static async System.Threading.Tasks.Task Main()
{
Write(""0 "");
foreach await (var i in M(3))
{
Write(i);
}
Write(""5"");
}
}";
var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe);
comp.VerifyDiagnostics();
CompileAndVerify(comp, expectedOutput: "0 1 2 3 4 5");
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
public void AsyncIteratorWithGenericReturnFromContainingType()
{
string source = @"
using static System.Console;
public class C<T>
{
public static async System.Collections.Generic.IAsyncEnumerable<T> M(T value)
{
Write(""1 "");
await System.Threading.Tasks.Task.CompletedTask;
Write(""2 "");
yield return value;
Write("" 4 "");
}
}
class D
{
static async System.Threading.Tasks.Task Main()
{
Write(""0 "");
foreach await (var i in C<int>.M(3))
{
Write(i);
}
Write(""5"");
}
}";
var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe);
comp.VerifyDiagnostics();
CompileAndVerify(comp, expectedOutput: "0 1 2 3 4 5");
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
public void AsyncIteratorWithParameter()
{
string source = @"
using static System.Console;
class C
{
static async System.Collections.Generic.IAsyncEnumerable<int> M(int parameter)
{
Write($""p:{parameter} "");
parameter++;
await System.Threading.Tasks.Task.Delay(10);
Write($""p:{parameter} "");
parameter++;
yield return 42;
Write($""p:{parameter} "");
}
static async System.Threading.Tasks.Task Main()
{
Write(""Start "");
foreach await (var i in M(10))
{
Write(""Value "");
}
Write(""End"");
}
}";
var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe);
comp.VerifyDiagnostics();
CompileAndVerify(comp, expectedOutput: "Start p:10 p:11 Value p:12 End");
}
[ConditionalFact(typeof(WindowsDesktopOnly))]
public void AsyncIteratorWithThis()
{
string source = @"
using static System.Console;
class C
{
int field = 10;
async System.Collections.Generic.IAsyncEnumerable<int> M()
{
Write($""f:{this.field} "");
this.field++;
await System.Threading.Tasks.Task.Delay(10);
Write($""f:{this.field} "");
this.field++;
yield return 42;
Write($""f:{this.field} "");
}
static async System.Threading.Tasks.Task Main()
{
Write(""Start "");
foreach await (var i in new C().M())
{
Write(""Value "");
}
Write(""End"");
}
}";
var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe);
comp.VerifyDiagnostics();
var v = CompileAndVerify(comp, expectedOutput: "Start f:10 f:11 Value f:12 End");
}
[Fact]
public void AsyncIteratorWithReturn()
{
......@@ -1629,7 +1817,7 @@ static void Assert(bool b)
}";
var comp = CreateCompilationWithTasksExtensions(new[] { source, s_common }, options: TestOptions.DebugExe);
comp.VerifyDiagnostics();
// PROTOTYPE(async-streams): need to implement the exception
// https://github.com/dotnet/roslyn/issues/30109 need to implement the guard/exception
//CompileAndVerify(comp, expectedOutput: "Done");
}
......@@ -1730,7 +1918,6 @@ static void Assert(bool b)
CompileAndVerify(comp, expectedOutput: "Done");
}
// PROTOTYPE(async-streams): Consider moving this common test code to TestSources.cs
private static readonly string s_common = @"
namespace System.Collections.Generic
{
......
......@@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.CSharp
{
public class ForEachStatementInfoTests : CSharpTestBase
{
[Fact(Skip = "PROTOTYPE(async-streams)")]
[Fact]
public void Equality()
{
var c = CreateCompilation(@"
......@@ -19,7 +19,7 @@ class E1
public E GetEnumerator() { return null; }
public bool MoveNext() { return false; }
public object Current { get; }
public void Dispose() { }
public void Dispose() { }
}
class E2
......@@ -27,7 +27,21 @@ class E2
public E GetEnumerator() { return null; }
public bool MoveNext() { return false; }
public object Current { get; }
public void Dispose() { }
public void Dispose() { }
}
class E3
{
public E GetAsyncEnumerator() => throw null;
public ValueTask<bool> WaitForNextAsync() => throw null;
public object TryGetNext(out bool success) => throw null;
public ValueTask DisposeAsync() => throw null;
}
class E4
{
public E GetAsyncEnumerator() => throw null;
public ValueTask<bool> WaitForNextAsync() => throw null;
public object TryGetNext(out bool success) => throw null;
public ValueTask DisposeAsync() => throw null;
}
");
var e1 = (TypeSymbol)c.GlobalNamespace.GetMembers("E1").Single();
......@@ -52,6 +66,30 @@ class E2
EqualityTesting.AssertNotEqual(new ForEachStatementInfo(ge1, mn1, cur1, disp2, e1, conv1, conv1), new ForEachStatementInfo(ge1, mn1, cur1, disp1, e1, conv1, conv1));
EqualityTesting.AssertNotEqual(new ForEachStatementInfo(ge1, mn1, cur1, disp1, e1, conv2, conv1), new ForEachStatementInfo(ge1, mn1, cur1, disp1, e1, conv1, conv1));
EqualityTesting.AssertNotEqual(new ForEachStatementInfo(ge1, mn1, cur1, disp1, e1, conv1, conv2), new ForEachStatementInfo(ge1, mn1, cur1, disp1, e1, conv1, conv1));
var e3 = (TypeSymbol)c.GlobalNamespace.GetMembers("E3").Single();
var gae3 = (MethodSymbol)e3.GetMembers("GetAsyncEnumerator").Single();
var wfna3 = (MethodSymbol)e3.GetMembers("WaitForNextAsync").Single();
var tgn3 = (MethodSymbol)e3.GetMembers("TryGetNext").Single();
var disp3 = (MethodSymbol)e3.GetMembers("DisposeAsync").Single();
var conv3 = Conversion.NoConversion;
var e4 = (TypeSymbol)c.GlobalNamespace.GetMembers("E4").Single();
var gae4 = (MethodSymbol)e4.GetMembers("GetAsyncEnumerator").Single();
var wfna4 = (MethodSymbol)e4.GetMembers("WaitForNextAsync").Single();
var tgn4 = (MethodSymbol)e4.GetMembers("TryGetNext").Single();
var disp4 = (MethodSymbol)e4.GetMembers("DisposeAsync").Single();
var conv4 = Conversion.NoConversion;
EqualityTesting.AssertEqual(
new ForEachStatementInfo(gae3, moveNextMethod: null, currentProperty: null, disp3, e3, conv3, conv3, wfna3, tgn3),
new ForEachStatementInfo(gae3, moveNextMethod: null, currentProperty: null, disp3, e3, conv3, conv3, wfna3, tgn3));
EqualityTesting.AssertNotEqual(
new ForEachStatementInfo(gae3, moveNextMethod: null, currentProperty: null, disp3, e3, conv3, conv3, wfna3, tgn3),
new ForEachStatementInfo(gae3, moveNextMethod: null, currentProperty: null, disp3, e3, conv3, conv3, wfna4, tgn3));
EqualityTesting.AssertNotEqual(
new ForEachStatementInfo(gae3, moveNextMethod: null, currentProperty: null, disp3, e3, conv3, conv3, wfna3, tgn3),
new ForEachStatementInfo(gae3, moveNextMethod: null, currentProperty: null, disp3, e3, conv3, conv3, wfna3, tgn4));
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册