diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 5352feb5461e7..7bdba491ceb3f 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -15,7 +15,7 @@ A minimal repro, with source-code provided, is ideal. Using [sharplab](https:// **Diagnostic Id**: -If this is a report about a bug in an analyzer, please include the diagnostic if possible (e.g. `"IDE0030"`). +If this is a report about a bug in an analyzer, please include the diagnostic ID and message if possible (e.g. `"IDE0030: Use coalesce expression"`). **Expected Behavior**: diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md new file mode 100644 index 0000000000000..0b9cd956cdf28 --- /dev/null +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md @@ -0,0 +1,27 @@ +# This document lists known breaking changes in Roslyn after .NET 8 all the way to .NET 9. + +## Iterators introduce safe context in C# 13 and newer + +***Introduced in Visual Studio 2022 version 17.11*** + +Although the language spec states that iterators introduce a safe context, Roslyn does not implement that in C# 12 and lower. +This will change in C# 13 as part of [a feature which allows unsafe code in iterators](https://github.com/dotnet/roslyn/issues/72662). +The change does not break normal scenarios as it was disallowed to use unsafe constructs directly in iterators anyway. +However, it can break scenarios where an unsafe context was previously inherited into nested local functions, for example: + +```cs +unsafe class C // unsafe context +{ + System.Collections.Generic.IEnumerable M() // an iterator + { + yield return 1; + local(); + void local() + { + int* p = null; // allowed in C# 12; error in C# 13 + } + } +} +``` + +You can work around the break simply by adding the `unsafe` modifier to the local function. diff --git a/docs/compilers/CSharp/Warnversion Warning Waves.md b/docs/compilers/CSharp/Warnversion Warning Waves.md index 65d25e8b1b528..f80c80e658838 100644 --- a/docs/compilers/CSharp/Warnversion Warning Waves.md +++ b/docs/compilers/CSharp/Warnversion Warning Waves.md @@ -13,6 +13,14 @@ In a typical project, this setting is controlled by the `AnalysisLevel` property which determines the `WarningLevel` property (passed to the `Csc` task). For more information on `AnalysisLevel`, see https://devblogs.microsoft.com/dotnet/automatically-find-latent-bugs-in-your-code-with-net-5/ +## Warning level 9 + +The compiler shipped with .NET 9 (the C# 13 compiler) contains the following warnings which are reported only under `/warn:9` or higher. + +| Warning ID | Description | +|------------|-------------| +| CS9237 | ['yield return' should not be used in the body of a lock statement](https://github.com/dotnet/roslyn/issues/72443) | + ## Warning level 8 The compiler shipped with .NET 8 (the C# 12 compiler) contains the following warnings which are reported only under `/warn:8` or higher. diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index e54d02e929a84..6ab6724af1d2a 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -872,12 +872,24 @@ private static bool CheckNotNamespaceOrType(BoundExpression expr, BindingDiagnos } } - private bool CheckLocalValueKind(SyntaxNode node, BoundLocal local, BindValueKind valueKind, bool checkingReceiver, BindingDiagnosticBag diagnostics) + private void CheckAddressOfInAsyncOrIteratorMethod(SyntaxNode node, BindValueKind valueKind, BindingDiagnosticBag diagnostics) { - if (valueKind == BindValueKind.AddressOf && this.IsInAsyncMethod()) + if (valueKind == BindValueKind.AddressOf) { - Error(diagnostics, ErrorCode.WRN_AddressOfInAsync, node); + if (this.IsInAsyncMethod()) + { + Error(diagnostics, ErrorCode.WRN_AddressOfInAsync, node); + } + else if (this.IsDirectlyInIterator && Compilation.IsFeatureEnabled(MessageID.IDS_FeatureRefUnsafeInIteratorAsync)) + { + Error(diagnostics, ErrorCode.ERR_AddressOfInIterator, node); + } } + } + + private bool CheckLocalValueKind(SyntaxNode node, BoundLocal local, BindValueKind valueKind, bool checkingReceiver, BindingDiagnosticBag diagnostics) + { + CheckAddressOfInAsyncOrIteratorMethod(node, valueKind, diagnostics); // Local constants are never variables. Local variables are sometimes // not to be treated as variables, if they are fixed, declared in a using, @@ -968,10 +980,8 @@ internal partial class Binder private bool CheckParameterValueKind(SyntaxNode node, BoundParameter parameter, BindValueKind valueKind, bool checkingReceiver, BindingDiagnosticBag diagnostics) { Debug.Assert(!RequiresAssignableVariable(BindValueKind.AddressOf)); - if (valueKind == BindValueKind.AddressOf && this.IsInAsyncMethod()) - { - Error(diagnostics, ErrorCode.WRN_AddressOfInAsync, node); - } + + CheckAddressOfInAsyncOrIteratorMethod(node, valueKind, diagnostics); ParameterSymbol parameterSymbol = parameter.ParameterSymbol; diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs index 39e48112f4f15..86c3bbd550cf6 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs @@ -171,6 +171,7 @@ public override Binder VisitMethodDeclaration(MethodDeclarationSyntax methodDecl } SourceMemberMethodSymbol method = null; + bool isIteratorBody = false; if (usage != NodeUsage.Normal && methodDecl.TypeParameterList != null) { @@ -181,10 +182,11 @@ public override Binder VisitMethodDeclaration(MethodDeclarationSyntax methodDecl if (usage == NodeUsage.MethodBody) { method = method ?? GetMethodSymbol(methodDecl, resultBinder); + isIteratorBody = method.IsIterator; resultBinder = new InMethodBinder(method, resultBinder); } - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(methodDecl.Modifiers); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(methodDecl.Modifiers, isIteratorBody: isIteratorBody); binderCache.TryAdd(key, resultBinder); } @@ -222,7 +224,7 @@ public override Binder VisitConstructorDeclaration(ConstructorDeclarationSyntax } } - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); binderCache.TryAdd(key, resultBinder); } @@ -249,7 +251,7 @@ public override Binder VisitDestructorDeclaration(DestructorDeclarationSyntax pa SourceMemberMethodSymbol method = GetMethodSymbol(parent, resultBinder); resultBinder = new InMethodBinder(method, resultBinder); - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); binderCache.TryAdd(key, resultBinder); } @@ -311,6 +313,10 @@ public override Binder VisitAccessorDeclaration(AccessorDeclarationSyntax parent if ((object)accessor != null) { resultBinder = new InMethodBinder(accessor, resultBinder); + + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary( + modifiers: default, + isIteratorBody: accessor.IsIterator); } } @@ -338,12 +344,14 @@ private Binder VisitOperatorOrConversionDeclaration(BaseMethodDeclarationSyntax resultBinder = VisitCore(parent.Parent); MethodSymbol method = GetMethodSymbol(parent, resultBinder); + bool isIteratorBody = false; if ((object)method != null && inBody) { + isIteratorBody = method.IsIterator; resultBinder = new InMethodBinder(method, resultBinder); } - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers, isIteratorBody: isIteratorBody); binderCache.TryAdd(key, resultBinder); } @@ -363,24 +371,24 @@ public override Binder VisitConversionOperatorDeclaration(ConversionOperatorDecl public override Binder VisitFieldDeclaration(FieldDeclarationSyntax parent) { - return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers); + return VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); } public override Binder VisitEventDeclaration(EventDeclarationSyntax parent) { - return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers); + return VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); } public override Binder VisitEventFieldDeclaration(EventFieldDeclarationSyntax parent) { - return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers); + return VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); } public override Binder VisitPropertyDeclaration(PropertyDeclarationSyntax parent) { if (!LookupPosition.IsInBody(_position, parent)) { - return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers); + return VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); } return VisitPropertyOrIndexerExpressionBody(parent); @@ -390,7 +398,7 @@ public override Binder VisitIndexerDeclaration(IndexerDeclarationSyntax parent) { if (!LookupPosition.IsInBody(_position, parent)) { - return VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers); + return VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); } return VisitPropertyOrIndexerExpressionBody(parent); @@ -403,12 +411,16 @@ private Binder VisitPropertyOrIndexerExpressionBody(BasePropertyDeclarationSynta Binder resultBinder; if (!binderCache.TryGetValue(key, out resultBinder)) { - resultBinder = VisitCore(parent.Parent).WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = VisitCore(parent.Parent).SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); var propertySymbol = GetPropertySymbol(parent, resultBinder); var accessor = propertySymbol.GetMethod; if ((object)accessor != null) { + // Expression body cannot be an iterator, otherwise we would need to pass + // `isIteratorBody` to `SetOrClearUnsafeRegionIfNecessary` above. + Debug.Assert(!accessor.IsIterator); + resultBinder = new InMethodBinder(accessor, resultBinder); } @@ -663,7 +675,7 @@ public override Binder VisitDelegateDeclaration(DelegateDeclarationSyntax parent resultBinder = new WithClassTypeParametersBinder(container, resultBinder); } - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); binderCache.TryAdd(key, resultBinder); } @@ -691,7 +703,7 @@ public override Binder VisitEnumDeclaration(EnumDeclarationSyntax parent) resultBinder = new InContainerBinder(container, outer); - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); binderCache.TryAdd(key, resultBinder); } @@ -773,7 +785,7 @@ internal Binder VisitTypeDeclarationCore(TypeDeclarationSyntax parent, NodeUsage } } - resultBinder = resultBinder.WithUnsafeRegionIfNecessary(parent.Modifiers); + resultBinder = resultBinder.SetOrClearUnsafeRegionIfNecessary(parent.Modifiers); binderCache.TryAdd(key, resultBinder); } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 95ab2164a2f99..23fef4ab05257 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -3182,21 +3182,13 @@ private BoundExpression BindOutVariableDeclarationArgument( /// /// Reports an error when a bad special by-ref local was found. /// - internal static void CheckRestrictedTypeInAsyncMethod(Symbol containingSymbol, TypeSymbol type, BindingDiagnosticBag diagnostics, SyntaxNode syntax, ErrorCode errorCode = ErrorCode.ERR_BadSpecialByRefLocal) + internal static void CheckRestrictedTypeInAsyncMethod(Symbol containingSymbol, TypeSymbol type, BindingDiagnosticBag diagnostics, SyntaxNode syntax) { - Debug.Assert(errorCode is ErrorCode.ERR_BadSpecialByRefLocal or ErrorCode.ERR_BadSpecialByRefUsing or ErrorCode.ERR_BadSpecialByRefLock); if (containingSymbol.Kind == SymbolKind.Method && ((MethodSymbol)containingSymbol).IsAsync && type.IsRestrictedType()) { - if (errorCode == ErrorCode.ERR_BadSpecialByRefLock) - { - Error(diagnostics, errorCode, syntax); - } - else - { - Error(diagnostics, errorCode, syntax, type); - } + CheckFeatureAvailability(syntax, MessageID.IDS_FeatureRefUnsafeInIteratorAsync, diagnostics); } } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs index 7374ede9d1163..e594a2999aea2 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Flags.cs @@ -91,11 +91,24 @@ internal Binder WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags flags return new BinderWithContainingMemberOrLambda(this, this.Flags | flags, containing); } - internal Binder WithUnsafeRegionIfNecessary(SyntaxTokenList modifiers) + internal Binder SetOrClearUnsafeRegionIfNecessary(SyntaxTokenList modifiers, bool isIteratorBody = false) { - return (this.Flags.Includes(BinderFlags.UnsafeRegion) || !modifiers.Any(SyntaxKind.UnsafeKeyword)) - ? this - : new Binder(this, this.Flags | BinderFlags.UnsafeRegion); + // In C# 13 and above, iterator bodies define a safe context even when nested in an unsafe context. + // In C# 12 and below, we keep the (spec violating) behavior that iterator bodies inherit the safe/unsafe context + // from their containing scope. Since there are errors for unsafe constructs directly in iterators, + // this inherited unsafe context can be observed only in nested non-iterator local functions. + var withoutUnsafe = isIteratorBody && this.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureRefUnsafeInIteratorAsync); + + if (this.Flags.Includes(BinderFlags.UnsafeRegion)) + { + return withoutUnsafe + ? new Binder(this, this.Flags & ~BinderFlags.UnsafeRegion) + : this; + } + + return !withoutUnsafe && modifiers.Any(SyntaxKind.UnsafeKeyword) + ? new Binder(this, this.Flags | BinderFlags.UnsafeRegion) + : this; } internal Binder WithCheckedOrUncheckedRegion(bool @checked) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index 6c3c6d41eae46..936a3bba5ce26 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -176,9 +176,7 @@ private BoundStatement BindUnsafeStatement(UnsafeStatementSyntax node, BindingDi } else if (this.IsIndirectlyInIterator) // called *after* we know the binder map has been created. { - // Spec 8.2: "An iterator block always defines a safe context, even when its declaration - // is nested in an unsafe context." - Error(diagnostics, ErrorCode.ERR_IllegalInnerUnsafe, node.UnsafeKeyword); + CheckFeatureAvailability(node.UnsafeKeyword, MessageID.IDS_FeatureRefUnsafeInIteratorAsync, diagnostics); } return BindEmbeddedBlock(node.Block, diagnostics); @@ -268,6 +266,15 @@ private BoundStatement BindYieldReturnStatement(YieldStatementSyntax node, Bindi { Error(diagnostics, ErrorCode.ERR_YieldNotAllowedInScript, node.YieldKeyword); } + else if (InUnsafeRegion && Compilation.IsFeatureEnabled(MessageID.IDS_FeatureRefUnsafeInIteratorAsync)) + { + Error(diagnostics, ErrorCode.ERR_BadYieldInUnsafe, node.YieldKeyword); + } + // NOTE: Error conditions should be checked above this point; only warning conditions below. + else if (this.Flags.Includes(BinderFlags.InLockBody)) + { + Error(diagnostics, ErrorCode.WRN_BadYieldInLock, node.YieldKeyword); + } CheckRequiredLangVersionForIteratorMethods(node, diagnostics); return new BoundYieldReturnStatement(node, argument); @@ -1165,15 +1172,9 @@ protected BoundLocalDeclaration BindVariableDeclaration( protected bool CheckRefLocalInAsyncOrIteratorMethod(SyntaxToken identifierToken, BindingDiagnosticBag diagnostics) { - if (IsInAsyncMethod()) - { - Error(diagnostics, ErrorCode.ERR_BadAsyncLocalType, identifierToken); - return true; - } - else if (IsDirectlyInIterator) + if (IsDirectlyInIterator || IsInAsyncMethod()) { - Error(diagnostics, ErrorCode.ERR_BadIteratorLocalType, identifierToken); - return true; + return !CheckFeatureAvailability(identifierToken, MessageID.IDS_FeatureRefUnsafeInIteratorAsync, diagnostics); } return false; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Unsafe.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Unsafe.cs index ec8cd5d3885b7..2c4d9b6a7fb88 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Unsafe.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Unsafe.cs @@ -56,18 +56,16 @@ private CSDiagnosticInfo GetUnsafeDiagnosticInfo(TypeSymbol sizeOfTypeOpt) { return null; } - else if (this.IsIndirectlyInIterator) - { - // Spec 8.2: "An iterator block always defines a safe context, even when its declaration - // is nested in an unsafe context." - return new CSDiagnosticInfo(ErrorCode.ERR_IllegalInnerUnsafe); - } else if (!this.InUnsafeRegion) { return ((object)sizeOfTypeOpt == null) ? new CSDiagnosticInfo(ErrorCode.ERR_UnsafeNeeded) : new CSDiagnosticInfo(ErrorCode.ERR_SizeofUnsafe, sizeOfTypeOpt); } + else if (this.IsIndirectlyInIterator && MessageID.IDS_FeatureRefUnsafeInIteratorAsync.GetFeatureAvailabilityDiagnosticInfo(Compilation) is { } unsafeInIteratorDiagnosticInfo) + { + return unsafeInIteratorDiagnosticInfo; + } else { return null; diff --git a/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs b/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs index edffa7f5535d3..e08152589f822 100644 --- a/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs @@ -129,7 +129,7 @@ public static void ValidateIteratorMethod(CSharpCompilation compilation, MethodS if (((iterator as SourceMemberMethodSymbol)?.IsUnsafe == true || (iterator as LocalFunctionSymbol)?.IsUnsafe == true) && compilation.Options.AllowUnsafe) // Don't cascade { - diagnostics.Add(ErrorCode.ERR_IllegalInnerUnsafe, errorLocation); + MessageID.IDS_FeatureRefUnsafeInIteratorAsync.CheckFeatureAvailability(diagnostics, compilation, errorLocation); } var returnType = iterator.ReturnType; diff --git a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs index 0695fe3f94395..1e6ee6bfc4953 100644 --- a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs +++ b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs @@ -416,7 +416,9 @@ public override void VisitLocalFunctionStatement(LocalFunctionStatementSyntax no ? new WithMethodTypeParametersBinder(match, _enclosing) : _enclosing; - binder = binder.WithUnsafeRegionIfNecessary(node.Modifiers); + binder = binder.SetOrClearUnsafeRegionIfNecessary(node.Modifiers, + isIteratorBody: match.IsIterator); + binder = new InMethodBinder(match, binder); } diff --git a/src/Compilers/CSharp/Portable/Binder/LockBinder.cs b/src/Compilers/CSharp/Portable/Binder/LockBinder.cs index c29d038662a25..0899da0cfdb69 100644 --- a/src/Compilers/CSharp/Portable/Binder/LockBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/LockBinder.cs @@ -64,13 +64,6 @@ internal override BoundStatement BindLockStatementParts(BindingDiagnosticBag dia _ = diagnostics.ReportUseSite(lockTypeInfo.EnterScopeMethod, exprSyntax) || diagnostics.ReportUseSite(lockTypeInfo.ScopeType, exprSyntax) || diagnostics.ReportUseSite(lockTypeInfo.ScopeDisposeMethod, exprSyntax); - - CheckRestrictedTypeInAsyncMethod( - originalBinder.ContainingMemberOrLambda, - lockTypeInfo.ScopeType, - diagnostics, - exprSyntax, - errorCode: ErrorCode.ERR_BadSpecialByRefLock); } BoundStatement stmt = originalBinder.BindPossibleEmbeddedStatement(_syntax.Statement, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs index e93e456b8d9cf..9d4659c8e3637 100644 --- a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs @@ -119,7 +119,7 @@ internal static BoundStatement BindUsingStatementOrDeclarationFromParts(SyntaxNo Debug.Assert(expressionOpt is not null); if (expressionOpt.Type is not null) { - CheckRestrictedTypeInAsyncMethod(originalBinder.ContainingMemberOrLambda, expressionOpt.Type, diagnostics, expressionOpt.Syntax, errorCode: ErrorCode.ERR_BadSpecialByRefUsing); + CheckRestrictedTypeInAsyncMethod(originalBinder.ContainingMemberOrLambda, expressionOpt.Type, diagnostics, expressionOpt.Syntax); } } else diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index d681f0b302910..4c09a80debc1a 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -2947,9 +2947,6 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep Cannot use ref, out, or in parameter '{0}' inside an anonymous method, lambda expression, query expression, or local function - - Unsafe code may not appear in iterators - Cannot yield a value in the body of a catch clause @@ -3807,7 +3804,7 @@ Give the compiler some way to differentiate the methods. For example, you can gi __arglist is not allowed in the parameter list of async methods - 'await' cannot be used in an expression containing the type '{0}' + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. Async methods cannot have pointer type parameters @@ -3848,15 +3845,12 @@ Give the compiler some way to differentiate the methods. For example, you can gi The 'async' modifier can only be used in methods that have a body. - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Security attribute '{0}' cannot be applied to an Async method. @@ -5287,12 +5281,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Cannot use ref local '{0}' inside an anonymous method, lambda expression, or query expression - - Iterators cannot have by-reference locals - - - Async methods cannot have by-reference locals - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. @@ -7854,9 +7842,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement. - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - Lock object @@ -7926,6 +7911,24 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ The data argument to InterceptsLocationAttribute refers to an invalid position in file '{0}'. + + 'yield return' should not be used in the body of a lock statement + + + 'yield return' should not be used in the body of a lock statement + + + ref and unsafe in async and iterator methods + + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + + Cannot use 'yield return' in an 'unsafe' block + + + The '&' operator cannot be used on parameters or local variables in iterator methods. + ref struct interfaces diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index bc6c2e8928216..4a532e27f6b31 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -792,7 +792,7 @@ internal enum ErrorCode ERR_BadYieldInTryOfCatch = 1626, ERR_EmptyYield = 1627, ERR_AnonDelegateCantUse = 1628, - ERR_IllegalInnerUnsafe = 1629, + // ERR_IllegalInnerUnsafe = 1629, //ERR_BadWatsonMode = 1630, ERR_BadYieldInCatch = 1631, ERR_BadDelegateLeave = 1632, @@ -1111,7 +1111,7 @@ internal enum ErrorCode ERR_NonTaskMainCantBeAsync = 4009, ERR_CantConvAsyncAnonFuncReturns = 4010, ERR_BadAwaiterPattern = 4011, - ERR_BadSpecialByRefLocal = 4012, + ERR_BadSpecialByRefParameter = 4012, ERR_SpecialByRefInLambda = 4013, WRN_UnobservedAwaitableExpression = 4014, ERR_SynchronizedAsyncMethod = 4015, @@ -1429,8 +1429,8 @@ internal enum ErrorCode ERR_RefAssignmentMustHaveIdentityConversion = 8173, ERR_ByReferenceVariableMustBeInitialized = 8174, ERR_AnonDelegateCantUseLocal = 8175, - ERR_BadIteratorLocalType = 8176, - ERR_BadAsyncLocalType = 8177, + // ERR_BadIteratorLocalType = 8176, + // ERR_BadAsyncLocalType = 8177, ERR_RefReturningCallAndAwait = 8178, #endregion diagnostics for ref locals and ref returns introduced in C# 7 @@ -2161,7 +2161,7 @@ internal enum ErrorCode ERR_UnscopedRefAttributeUnsupportedMemberTarget = 9101, ERR_UnscopedRefAttributeInterfaceImplementation = 9102, ERR_UnrecognizedRefSafetyRulesAttributeVersion = 9103, - ERR_BadSpecialByRefUsing = 9104, + // ERR_BadSpecialByRefUsing = 9104, ERR_InvalidPrimaryConstructorParameterReference = 9105, ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver = 9106, @@ -2286,7 +2286,7 @@ internal enum ErrorCode ERR_CollectionExpressionMissingAdd = 9215, WRN_ConvertingLock = 9216, - ERR_BadSpecialByRefLock = 9217, + ERR_RefLocalAcrossAwait = 9217, ERR_DynamicDispatchToParamsCollection = 9218, ERR_ParamsCollectionAmbiguousDynamicArgument = 9219, @@ -2321,6 +2321,10 @@ internal enum ErrorCode #endregion + WRN_BadYieldInLock = 9237, + ERR_BadYieldInUnsafe = 9238, + ERR_AddressOfInIterator = 9239, + // Note: you will need to do the following after adding errors: // 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index 62bbe6b94e202..03a75fda22f79 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -207,6 +207,10 @@ internal static int GetWarningLevel(ErrorCode code) // docs/compilers/CSharp/Warnversion Warning Waves.md switch (code) { + case ErrorCode.WRN_BadYieldInLock: + // Warning level 9 is exclusively for warnings introduced in the compiler + // shipped with dotnet 9 (C# 13) and that can be reported for pre-existing code. + return 9; case ErrorCode.WRN_AddressOfInAsync: case ErrorCode.WRN_ByValArraySizeConstRequired: // Warning level 8 is exclusively for warnings introduced in the compiler @@ -623,6 +627,7 @@ or ErrorCode.ERR_InterceptorCannotBeGeneric or ErrorCode.ERR_InterceptableMethodMustBeOrdinary or ErrorCode.ERR_PossibleAsyncIteratorWithoutYield or ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait + or ErrorCode.ERR_RefLocalAcrossAwait // Update src\EditorFeatures\CSharp\LanguageServer\CSharpLspBuildOnlyDiagnostics.cs // whenever new values are added here. => true, @@ -1275,7 +1280,6 @@ or ErrorCode.ERR_UnsupportedPrimaryConstructorParameterCapturingRef or ErrorCode.ERR_UnsupportedPrimaryConstructorParameterCapturingRefLike or ErrorCode.ERR_AnonDelegateCantUseStructPrimaryConstructorParameterInMember or ErrorCode.ERR_AnonDelegateCantUseStructPrimaryConstructorParameterCaptured - or ErrorCode.ERR_IllegalInnerUnsafe or ErrorCode.ERR_BadYieldInCatch or ErrorCode.ERR_BadDelegateLeave or ErrorCode.WRN_IllegalPragma @@ -1535,7 +1539,7 @@ or ErrorCode.ERR_BadAwaitArgVoidCall or ErrorCode.ERR_NonTaskMainCantBeAsync or ErrorCode.ERR_CantConvAsyncAnonFuncReturns or ErrorCode.ERR_BadAwaiterPattern - or ErrorCode.ERR_BadSpecialByRefLocal + or ErrorCode.ERR_BadSpecialByRefParameter or ErrorCode.WRN_UnobservedAwaitableExpression or ErrorCode.ERR_SynchronizedAsyncMethod or ErrorCode.ERR_BadAsyncReturnExpression @@ -1778,8 +1782,6 @@ or ErrorCode.ERR_InitializeByReferenceVariableWithValue or ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion or ErrorCode.ERR_ByReferenceVariableMustBeInitialized or ErrorCode.ERR_AnonDelegateCantUseLocal - or ErrorCode.ERR_BadIteratorLocalType - or ErrorCode.ERR_BadAsyncLocalType or ErrorCode.ERR_PredefinedValueTupleTypeNotFound or ErrorCode.ERR_SemiOrLBraceOrArrowExpected or ErrorCode.ERR_NewWithTupleTypeSyntax @@ -2330,7 +2332,6 @@ or ErrorCode.WRN_ParamsArrayInLambdaOnly or ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget or ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation or ErrorCode.ERR_UnrecognizedRefSafetyRulesAttributeVersion - or ErrorCode.ERR_BadSpecialByRefUsing or ErrorCode.ERR_InvalidPrimaryConstructorParameterReference or ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver or ErrorCode.WRN_CapturedPrimaryConstructorParameterPassedToBase @@ -2419,7 +2420,6 @@ or ErrorCode.ERR_CollectionExpressionTargetNoElementType or ErrorCode.ERR_CollectionExpressionMissingConstructor or ErrorCode.ERR_CollectionExpressionMissingAdd or ErrorCode.WRN_ConvertingLock - or ErrorCode.ERR_BadSpecialByRefLock or ErrorCode.ERR_DynamicDispatchToParamsCollection or ErrorCode.ERR_ParamsCollectionAmbiguousDynamicArgument or ErrorCode.WRN_DynamicDispatchToParamsCollectionMethod @@ -2439,6 +2439,9 @@ or ErrorCode.ERR_InterceptsLocationDuplicateFile or ErrorCode.ERR_InterceptsLocationFileNotFound or ErrorCode.ERR_InterceptsLocationDataInvalidPosition or ErrorCode.INF_TooManyBoundLambdas + or ErrorCode.WRN_BadYieldInLock + or ErrorCode.ERR_BadYieldInUnsafe + or ErrorCode.ERR_AddressOfInIterator or ErrorCode.ERR_RuntimeDoesNotSupportByRefLikeGenerics or ErrorCode.ERR_RefStructConstraintAlreadySpecified or ErrorCode.ERR_AllowsClauseMustBeLast diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index de89cced38570..15f4d28a240f6 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -283,6 +283,8 @@ internal enum MessageID IDS_FeatureParamsCollections = MessageBase + 12842, + IDS_FeatureRefUnsafeInIteratorAsync = MessageBase + 12843, + IDS_FeatureRefStructInterfaces = MessageBase + 12950, // PROTOTYPE(RefStructInterfaces): Pack numbers } @@ -468,6 +470,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureImplicitIndexerInitializer: case MessageID.IDS_FeatureLockObject: case MessageID.IDS_FeatureParamsCollections: + case MessageID.IDS_FeatureRefUnsafeInIteratorAsync: case MessageID.IDS_FeatureRefStructInterfaces: return LanguageVersion.Preview; diff --git a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs index 62d7b4c68bec6..ac6ebf95db21f 100644 --- a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs @@ -341,6 +341,7 @@ public static bool IsWarning(ErrorCode code) case ErrorCode.WRN_DynamicDispatchToParamsCollectionMethod: case ErrorCode.WRN_DynamicDispatchToParamsCollectionIndexer: case ErrorCode.WRN_DynamicDispatchToParamsCollectionConstructor: + case ErrorCode.WRN_BadYieldInLock: return true; default: return false; diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs index 91d75e4f81586..d8ce97fa4088f 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs @@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.CSharp /// /// /// Data flow analysis is used to calculate the locals. At yield/await we mark all variables as "unassigned". - /// When a read from an unassigned variables is reported we add the variable to the captured set. + /// When a read from an unassigned variable is reported we add the variable to the captured set. /// "this" parameter is captured if a reference to "this", "base" or an instance field is encountered. /// Variables used in finally also need to be captured if there is a yield in the corresponding try block. /// @@ -76,19 +76,33 @@ public static OrderedSet Analyze(CSharpCompilation compilation, MethodSy foreach (var kvp in lazyDisallowedCaptures) { var variable = kvp.Key; - var type = (variable.Kind == SymbolKind.Local) ? ((LocalSymbol)variable).Type : ((ParameterSymbol)variable).Type; - if (variable is SynthesizedLocal local && local.SynthesizedKind == SynthesizedLocalKind.Spill) + if (variable is LocalSymbol local) { - Debug.Assert(local.TypeWithAnnotations.IsRestrictedType()); - diagnostics.Add(ErrorCode.ERR_ByRefTypeAndAwait, local.GetFirstLocation(), local.TypeWithAnnotations); + foreach (var syntax in kvp.Value) + { + if (local.TypeWithAnnotations.IsRestrictedType()) + { + // CS4007: Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + diagnostics.Add(ErrorCode.ERR_ByRefTypeAndAwait, syntax.Location, local.TypeWithAnnotations); + } + else + { + Debug.Assert(local.RefKind != RefKind.None); + // CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + diagnostics.Add(ErrorCode.ERR_RefLocalAcrossAwait, syntax.Location); + } + } } else { - foreach (CSharpSyntaxNode syntax in kvp.Value) + var parameter = (ParameterSymbol)variable; + Debug.Assert(parameter.TypeWithAnnotations.IsRestrictedType()); + + foreach (var syntax in kvp.Value) { - // CS4013: Instance of type '{0}' cannot be used inside an anonymous function, query expression, iterator block or async method - diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, type); + // CS4007: Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + diagnostics.Add(ErrorCode.ERR_ByRefTypeAndAwait, syntax.Location, parameter.TypeWithAnnotations); } } } @@ -195,14 +209,23 @@ protected override ImmutableArray Scan(ref bool badRegion) private void CaptureVariable(Symbol variable, SyntaxNode syntax) { var type = (variable.Kind == SymbolKind.Local) ? ((LocalSymbol)variable).Type : ((ParameterSymbol)variable).Type; - if (type.IsRestrictedType()) + if (type.IsRestrictedType() || + (variable is LocalSymbol { RefKind: not RefKind.None } refLocal && !canRefLocalBeHoisted(refLocal))) { (_lazyDisallowedCaptures ??= new MultiDictionary()).Add(variable, syntax); } else { if (_variablesToHoist.Add(variable) && variable is LocalSymbol local && _boundRefLocalInitializers.TryGetValue(local, out var variableInitializer)) - CaptureRefInitializer(variableInitializer, syntax); + CaptureRefInitializer(variableInitializer, local.SynthesizedKind != SynthesizedLocalKind.UserDefined ? variableInitializer.Syntax : syntax); + } + + static bool canRefLocalBeHoisted(LocalSymbol refLocal) + { + return refLocal.SynthesizedKind == SynthesizedLocalKind.Spill || + (refLocal.SynthesizedKind == SynthesizedLocalKind.ForEachArray && + refLocal.Type.HasInlineArrayAttribute(out _) && + refLocal.Type.TryGetInlineArrayElementField() is not null); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs index cd3aec6946c79..d502a7080b83c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs @@ -58,7 +58,7 @@ public LocalFunctionSymbol( ScopeBinder = binder; - binder = binder.WithUnsafeRegionIfNecessary(syntax.Modifiers); + binder = binder.SetOrClearUnsafeRegionIfNecessary(syntax.Modifiers); if (syntax.TypeParameterList != null) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs index a1771beb99a70..8cce2057e5200 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs @@ -72,7 +72,7 @@ internal void ReportAsyncParameterErrors(BindingDiagnosticBag diagnostics, Locat } else if (parameter.Type.IsRestrictedType()) { - diagnostics.Add(ErrorCode.ERR_BadSpecialByRefLocal, getLocation(parameter, location), parameter.Type); + diagnostics.Add(ErrorCode.ERR_BadSpecialByRefParameter, getLocation(parameter, location), parameter.Type); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index af93d12c934ff..eb6c3ff553bfa 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -59,7 +59,7 @@ private static SourcePropertySymbol Create( bool isExpressionBodied = !hasAccessorList && GetArrowExpression(syntax) != null; - binder = binder.WithUnsafeRegionIfNecessary(modifiersTokenList); + binder = binder.SetOrClearUnsafeRegionIfNecessary(modifiersTokenList); TypeSymbol? explicitInterfaceType; string? aliasQualifierOpt; string memberName = ExplicitInterfaceHelpers.GetMemberNameAndInterfaceSymbol(binder, explicitInterfaceSpecifier, name, diagnostics, out explicitInterfaceType, out aliasQualifierOpt); @@ -431,7 +431,7 @@ private Binder CreateBinderForTypeAndParameters() var binderFactory = compilation.GetBinderFactory(syntaxTree); var binder = binderFactory.GetBinder(syntax, syntax, this); SyntaxTokenList modifiers = GetModifierTokensSyntax(syntax); - binder = binder.WithUnsafeRegionIfNecessary(modifiers); + binder = binder.SetOrClearUnsafeRegionIfNecessary(modifiers); return binder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks, this); } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 6bc888cca671b..482f74b8c1b7e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -32,6 +32,11 @@ {0}: abstraktní událost nemůže používat syntaxi přístupového objektu události. + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees '&' pro skupiny metod se nedá použít ve stromech výrazů. @@ -282,14 +287,14 @@ Člen záznamu {0} musí být čitelná vlastnost instance nebo pole typu {1}, která se bude shodovat s pozičním parametrem {2}. - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - Příkaz lock pro hodnotu typu System.Threading.Lock nejde použít v asynchronních metodách nebo asynchronních výrazech lambda. + + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - Prostředek použitého příkazu typu {0} nejde použít v asynchronních metodách ani v asynchronních výrazech lambda. + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -317,6 +322,11 @@ Typ {0} není platný pro using static. Lze použít pouze třídu, strukturu, rozhraní, výčet, delegáta nebo obor názvů. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. Atribut AsyncMethodBuilder je u anonymních metod bez explicitního návratového typu zakázaný. @@ -1767,6 +1777,11 @@ Pole ref lze deklarovat pouze ve struktuře ref. + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + The left-hand side of a ref assignment must be a ref variable. Levá strana přiřazení odkazu musí být parametr Ref. @@ -2422,6 +2437,11 @@ ref struct interfaces + + ref and unsafe in async and iterator methods + ref and unsafe in async and iterator methods + + relaxed shift operator uvolněný operátor směny @@ -2597,6 +2617,16 @@ Modifikátor ref pro argument odpovídající parametru in je ekvivalentem in. Místo toho zvažte použití in. + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + Attribute parameter 'SizeConst' must be specified. Je nutné zadat parametr atributu SizeConst. @@ -9221,11 +9251,6 @@ Blok catch() po bloku catch (System.Exception e) může zachytit výjimky, kter Parametr ref, out nebo in {0} nejde použít uvnitř anonymní metody, výrazu lambda, výrazu dotazu nebo lokální funkce. - - Unsafe code may not appear in iterators - Iterátory nesmí obsahovat nezabezpečený kód. - - Cannot yield a value in the body of a catch clause V těle klauzule catch nejde použít hodnotu získanou příkazem yield. @@ -10610,8 +10635,8 @@ Poskytněte kompilátoru nějaký způsob, jak metody rozlišit. Můžete např - 'await' cannot be used in an expression containing the type '{0}' - 'Operátor await nejde použít ve výrazu, který obsahuje typ {0}. + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + 'Operátor await nejde použít ve výrazu, který obsahuje typ {0}. @@ -10679,16 +10704,6 @@ Poskytněte kompilátoru nějaký způsob, jak metody rozlišit. Můžete např Modifikátor async se dá použít jenom v metodách, které mají tělo. - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - Parametry nebo lokální proměnné typu {0} nemůžou být deklarované v asynchronních metodách nebo asynchronních výrazech lambda. - - - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - Výraz foreach nejde použít na enumerátorech typu {0} v asynchronních metodách nebo metodách iterátoru, protože {0} je struktura REF. - - Security attribute '{0}' cannot be applied to an Async method. Atribut zabezpečení {0} nejde použít pro metodu Async. @@ -11208,7 +11223,7 @@ Potlačení upozornění zvažte jenom v případě, když určitě nechcete če Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method - Instance typu {0} nelze použít uvnitř vnořené funkce, výrazu dotazu, bloku iterátoru nebo asynchronní metody. + Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method @@ -12519,16 +12534,6 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference Místní hodnotu odkazu {0} nejde použít uvnitř anonymní metody, výrazu lambda nebo výrazu dotazu. - - Iterators cannot have by-reference locals - Iterátory nemůžou mít lokální proměnné podle odkazu. - - - - Async methods cannot have by-reference locals - Asynchronní metody nemůžou mít lokální proměnné podle odkazu. - - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. Odkaz vrácený voláním funkce {0} nelze zachovat v rámci hranice await nebo yield. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 798fc08ecb8a3..458820646f0bd 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -32,6 +32,11 @@ {0}: Das abstrakte Ereignis kann die Ereignisaccessorsyntax nicht verwenden. + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees "&" für Methodengruppen kann in Ausdrucksbaumstrukturen nicht verwendet werden. @@ -282,14 +287,14 @@ Das Datensatzelement "{0}" muss eine lesbare Instanzeigenschaft oder ein Feld vom Typ "{1}" sein, um dem Positionsparameter "{2}" zu entsprechen. - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - Eine Sperranweisung für einen Wert vom Typ „System.Threading.Lock“ kann nicht in asynchronen Methoden oder asynchronen Lambdaausdrücken verwendet werden. + + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - Eine using-Anweisungsressource vom Typ „{0}“ kann nicht in asynchronen Methoden oder asynchronen Lambdaausdrücken verwendet werden. + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -317,6 +322,11 @@ Der Typ "{0}" ist für "using static" ungültig. Nur eine Klasse, Struktur, Schnittstelle, Enumeration, ein Delegat oder ein Namespace kann verwendet werden. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. Das AsyncMethodBuilder-Attribut ist für anonyme Methoden ohne expliziten Rückgabetyp unzulässig. @@ -1767,6 +1777,11 @@ Ein Verweisfeld kann nur in einer Verweisstruktur deklariert werden. + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + The left-hand side of a ref assignment must be a ref variable. Die linke Seite einer Ref-Zuweisung muss eine Ref-Variable sein. @@ -2422,6 +2437,11 @@ ref struct interfaces + + ref and unsafe in async and iterator methods + ref and unsafe in async and iterator methods + + relaxed shift operator entspannter Schichtoperator @@ -2597,6 +2617,16 @@ Der ref-Modifizierer für ein Argument, das dem in-Parameter entspricht, entspricht "in". Erwägen Sie stattdessen die Verwendung von "in". + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + Attribute parameter 'SizeConst' must be specified. Der Attributparameter "SizeConst" muss angegeben werden. @@ -9221,11 +9251,6 @@ Ein catch()-Block nach einem catch (System.Exception e)-Block kann nicht-CLS-Aus Der ref-, out-, oder in-Parameter "{0}" kann nicht in einer anonymen Methode, einem Lambdaausdruck, einem Abfrageausdruck oder einer lokalen Funktion verwendet werden. - - Unsafe code may not appear in iterators - Unsicherer Code wird möglicherweise nicht in Iteratoren angezeigt. - - Cannot yield a value in the body of a catch clause Mit "yield" kann im Text einer catch-Klausel kein Wert zurückgegeben werden. @@ -10610,8 +10635,8 @@ Unterstützen Sie den Compiler bei der Unterscheidung zwischen den Methoden. Daz - 'await' cannot be used in an expression containing the type '{0}' - '"await" kann nicht in einem Ausdruck verwendet werden, der den Typ "{0}" enthält + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + '"await" kann nicht in einem Ausdruck verwendet werden, der den Typ "{0}" enthält @@ -10679,16 +10704,6 @@ Unterstützen Sie den Compiler bei der Unterscheidung zwischen den Methoden. Daz Der Modifizierer "async" kann nur in Methoden verwendet werden, die über einen Textkörper verfügen. - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - Parameter oder lokale Variablen des Typs "{0}" können nicht in asynchronen Methoden oder in asynchronen Lambdaausdrücken deklariert werden. - - - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - Die foreach-Anweisung kann nicht für Enumeratoren vom Typ "{0}" in asynchronen oder Iteratormethoden verwendet werden, weil "{0}" eine Referenzstruktur ist. - - Security attribute '{0}' cannot be applied to an Async method. Das Sicherheitsattribut "{0}" kann nicht auf eine Async-Methode angewendet werden. @@ -11208,7 +11223,7 @@ Sie sollten das Unterdrücken der Warnung nur in Betracht ziehen, wenn Sie siche Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method - Eine Instanz des Typs "{0}" kann nicht in einer geschachtelten Funktion, einem Abfrageausdruck, einem Iteratorblock oder einer Async-Methode verwendet werden. + Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method @@ -12519,16 +12534,6 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett Der lokale Verweis "{0}" kann nicht in einer anonymen Methode, einem Lambdaausdruck oder einem Abfrageausdruck verwendet werden. - - Iterators cannot have by-reference locals - Iteratoren dürfen keine lokalen by-reference-Elemente aufweisen. - - - - Async methods cannot have by-reference locals - Asynchrone Methoden dürfen keine lokalen by-reference-Elemente aufweisen. - - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. Ein Verweis, der von einem Aufruf von "{0}" zurückgegeben wird, kann nicht über die Grenzen "await" oder "yield" hinweg beibehalten werden. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 2308721ead667..de96942b43ca1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -32,6 +32,11 @@ "{0}": un evento abstracto no puede usar la sintaxis de descriptor de acceso de eventos + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees No se puede usar "&" para los grupos de métodos en los árboles de expresión. @@ -282,14 +287,14 @@ El miembro de registro '{0}' debe ser una propiedad de instancia legible o un campo de tipo '{1}' para coincidir con el parámetro posicional '{2}'. - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - No se puede usar una instrucción de bloqueo en un valor de tipo 'System.Threading.Lock' en métodos asincrónicos ni expresiones lambda asincrónicas. + + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - Un recurso de instrucción using de tipo '{0}' no se puede usar en métodos asincrónicos ni expresiones lambda asincrónicas. + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -317,6 +322,11 @@ El tipo '{0}' no es válido para 'using static'. Solo se puede usar una clase, estructura, interfaz, enumeración, delegado o espacio de nombres. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. El atributo AsyncMethodBuilder no se permite en métodos anónimos sin un tipo de valor devuelto explícito. @@ -1767,6 +1777,11 @@ Un campo ref solo se puede declarar en una estructura ref. + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + The left-hand side of a ref assignment must be a ref variable. La parte izquierda de una asignación de referencias debe ser una variable local. @@ -2422,6 +2437,11 @@ ref struct interfaces + + ref and unsafe in async and iterator methods + ref and unsafe in async and iterator methods + + relaxed shift operator operador de cambios relajado @@ -2597,6 +2617,16 @@ El modificador "ref" de un argumento correspondiente al parámetro "in" es equivalente a "in". Considere la posibilidad de usar "in" en su lugar. + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + Attribute parameter 'SizeConst' must be specified. Se debe especificar el parámetro de atributo "SizeConst". @@ -9221,11 +9251,6 @@ Un bloque catch() después de un bloque catch (System.Exception e) puede abarcar No se puede usar el parámetro ref, out o in "{0}" dentro de un método anónimo, una expresión lambda, una expresión de consulta o una función local - - Unsafe code may not appear in iterators - No puede aparecer código no seguro en iteradores - - Cannot yield a value in the body of a catch clause No se puede proporcionar ningún valor en el cuerpo de una cláusula catch @@ -10610,8 +10635,8 @@ Indique al compilador alguna forma de diferenciar los métodos. Por ejemplo, pue - 'await' cannot be used in an expression containing the type '{0}' - 'await' no se puede usar en una expresión que contenga el tipo '{0}' + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + 'await' no se puede usar en una expresión que contenga el tipo '{0}' @@ -10679,16 +10704,6 @@ Indique al compilador alguna forma de diferenciar los métodos. Por ejemplo, pue El modificador 'async' solo se puede usar en métodos que tengan un cuerpo. - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - Los parámetros o locales de tipo '{0}' no pueden declararse en expresiones lambda o métodos asincrónicos. - - - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - La instrucción foreach no puede funcionar en enumeradores de tipo "{0}" en métodos async o iterator porque "{0}" es una estructura ref. - - Security attribute '{0}' cannot be applied to an Async method. El atributo de seguridad '{0}' no se puede aplicar a un método Async. @@ -11208,7 +11223,7 @@ Considere la posibilidad de suprimir la advertencia solo si tiene la seguridad d Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method - La instancia de tipo "{0}" no se puede usar dentro de una función anidada, una expresión de consulta, un bloque iterador ni un método asincrónico. + Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method @@ -12519,16 +12534,6 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe No se puede usar la variable local de tipo ref '{0}' dentro de un método anónimo, una expresión lambda o una expresión de consulta. - - Iterators cannot have by-reference locals - Los iteradores no pueden tener variables locales por referencia. - - - - Async methods cannot have by-reference locals - Los métodos asincrónicos no pueden tener variables locales por referencia. - - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. Una referencia devuelta por una llamada a '{0}' no se puede conservar a través del límite "await" o "yield". diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 8585fb986186d..cd8e3b4571564 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -32,6 +32,11 @@ '{0}' : un événement abstrait ne peut pas utiliser une syntaxe d'accesseur d'événement + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees '&' des groupes de méthodes ne peut pas être utilisé dans les arborescences d'expression @@ -282,14 +287,14 @@ Le membre d'enregistrement '{0}' doit être une propriété d'instance our champ lisible de type '{1}' pour correspondre au paramètre positionnel '{2}'. - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - Vous ne pouvez pas utiliser une instruction lock sur une valeur de type « System.Threading.Lock » dans des méthodes asynchrones ou des expressions lambda asynchrones. + + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - Une ressource d’instruction d’utilisation de type '{0}' ne peut pas être utilisée dans des méthodes asynchrones ou des expressions lambda asynchrones. + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -317,6 +322,11 @@ Le type '{0}' n'est pas valide pour 'en utilisant statique'. Seuls une classe, une structure, une interface, une énumération, un délégué ou un espace de noms peuvent être utilisés. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. L'attribut AsyncMethodBuilder n'est pas autorisé pour les méthodes anonymes sans type de retour explicite. @@ -1767,6 +1777,11 @@ Un champ de référence ne peut être déclaré que dans une sructure de référence. + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + The left-hand side of a ref assignment must be a ref variable. Le côté gauche d’une affectation ref doit être une variable ref. @@ -2422,6 +2437,11 @@ ref struct interfaces + + ref and unsafe in async and iterator methods + ref and unsafe in async and iterator methods + + relaxed shift operator opérateur shift souple @@ -2597,6 +2617,16 @@ Le modificateur « ref » d’un argument correspondant au paramètre « in » est équivalent à « in ». Envisagez d’utiliser « in » à la place. + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + Attribute parameter 'SizeConst' must be specified. Vous devez spécifier un paramètre d’attribut « SizeConst ». @@ -9221,11 +9251,6 @@ Un bloc catch() après un bloc catch (System.Exception e) peut intercepter des e Impossible d'utiliser le paramètre ref, out ou in '{0}' dans une méthode anonyme, une expression lambda, une expression de requête ou une fonction locale - - Unsafe code may not appear in iterators - Du code unsafe ne peut pas s'afficher dans des itérateurs - - Cannot yield a value in the body of a catch clause Impossible de générer une valeur dans le corps d'une clause catch @@ -10610,8 +10635,8 @@ Permettez au compilateur de différencier les méthodes. Par exemple, vous pouve - 'await' cannot be used in an expression containing the type '{0}' - 'await' ne peut pas être utilisé dans une expression contenant le type '{0}' + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + 'await' ne peut pas être utilisé dans une expression contenant le type '{0}' @@ -10679,16 +10704,6 @@ Permettez au compilateur de différencier les méthodes. Par exemple, vous pouve Le modificateur 'async' ne peut être utilisé que dans des méthodes ayant un corps. - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - Les paramètres ou variables locales de type '{0}' ne peuvent pas être déclarés dans des méthodes asynchrones ou des expressions asynchrones lambda. - - - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - L'instruction foreach ne peut pas fonctionner sur les énumérateurs de type '{0}' dans les méthodes asynchrones ou les méthodes d'itérateurs, car '{0}' est un struct par référence. - - Security attribute '{0}' cannot be applied to an Async method. Impossible d'appliquer l'attribut de sécurité '{0}' à une méthode Async. @@ -11208,7 +11223,7 @@ Supprimez l'avertissement seulement si vous êtes sûr de ne pas vouloir attendr Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method - Impossible d'utiliser une instance de type '{0}' dans une fonction imbriquée, une expression de requête, un bloc itérateur ou une méthode async + Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method @@ -12519,16 +12534,6 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé Impossible d'utiliser ref local '{0}' dans une méthode anonyme, une expression lambda ou une expression de requête - - Iterators cannot have by-reference locals - Les itérateurs ne peuvent pas avoir de variables locales par référence - - - - Async methods cannot have by-reference locals - Les méthodes async ne peuvent pas avoir de variables locales par référence - - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. Une référence renvoyée par un appel à '{0}' ne peut pas être conservée à travers la limite 'wait' ou 'yield'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index bb19c5576466c..ee6c972ccf03d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -32,6 +32,11 @@ '{0}': l'evento astratto non può usare la sintassi della funzione di accesso agli eventi + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees Non è possibile usare '&' su gruppi di metodi in alberi delle espressioni @@ -282,14 +287,14 @@ Il membro di record '{0}' deve essere una proprietà di istanza leggibile o campo di tipo '{1}' per corrispondere al parametro posizionale '{2}'. - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - Non è possibile usare un'istruzione lock in un valore di tipo 'System.Threading.Lock' nei metodi asincroni o nelle espressioni lambda asincrone. + + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - Non è possibile usare una risorsa di istruzione using di tipo '{0}' in metodi asincroni o espressioni lambda asincrone. + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -317,6 +322,11 @@ '{0}' tipo non valido per 'using static'. È possibile usare solo una classe, una struttura, un'interfaccia, un'enumerazione, un delegato o uno spazio dei nomi. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. L'attributo AsyncMethodBuilder non è consentito in metodi anonimi senza un tipo restituito esplicito. @@ -1767,6 +1777,11 @@ Un campo ref può essere dichiarato solo in uno struct ref. + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + The left-hand side of a ref assignment must be a ref variable. La parte sinistra di un'assegnazione ref deve essere una variabile ref. @@ -2422,6 +2437,11 @@ ref struct interfaces + + ref and unsafe in async and iterator methods + ref and unsafe in async and iterator methods + + relaxed shift operator operatore di spostamento rilassato @@ -2597,6 +2617,16 @@ Il modificatore 'ref' per un argomento corrispondente al parametro 'in' equivale a 'in'. Provare a usare 'in'. + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + Attribute parameter 'SizeConst' must be specified. È necessario specificare il parametro di attributo 'SizeConst'. @@ -9221,11 +9251,6 @@ Un blocco catch() dopo un blocco catch (System.Exception e) può rilevare eccezi Non è possibile usare il parametro ref, out o in '{0}' all'interno di un metodo anonimo, di un'espressione lambda, di un'espressione di query o di una funzione locale - - Unsafe code may not appear in iterators - Gli iteratori non possono contenere codice unsafe - - Cannot yield a value in the body of a catch clause Impossibile produrre un valore nel corpo di una clausola catch @@ -10610,8 +10635,8 @@ Impostare il compilatore in modo tale da distinguere i metodi, ad esempio assegn - 'await' cannot be used in an expression containing the type '{0}' - 'non è possibile usare 'await' in un'espressione contenente il tipo '{0}' + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + 'non è possibile usare 'await' in un'espressione contenente il tipo '{0}' @@ -10679,16 +10704,6 @@ Impostare il compilatore in modo tale da distinguere i metodi, ad esempio assegn Il modificatore 'async' può essere usato solo nei metodi con un corpo. - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - Non è possibile dichiarare parametri o variabili locali di tipo '{0}' in metodi asincroni o espressioni lambda asincrone. - - - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - L'istruzione foreach non può funzionare con enumeratori di tipo '{0}' in metodi async o iterator perché '{0}' è uno struct ref. - - Security attribute '{0}' cannot be applied to an Async method. Non è possibile applicare l'attributo di sicurezza '{0}' a un metodo Async @@ -11208,7 +11223,7 @@ Come procedura consigliata, è consigliabile attendere sempre la chiamata. Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method - L'istanza di tipo '{0}' non può essere usata all'interno di una funzione annidata, un'espressione di query, un blocco iteratore o un metodo asincrono + Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method @@ -12519,16 +12534,6 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr Non è possibile usare la variabile locale ref '{0}' in un metodo anonimo, in un'espressione lambda o in un'espressione di query - - Iterators cannot have by-reference locals - Gli iteratori non possono includere variabili locali per riferimento - - - - Async methods cannot have by-reference locals - I metodi Async non possono includere variabili locali per riferimento - - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. Non è possibile mantenere un riferimento restituito da una chiamata a '{0}' oltre il limite 'await' o 'yield'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index a95aa54b87139..049964d81ce3a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -32,6 +32,11 @@ '{0}': 抽象イベントはイベント アクセサーの構文を使用できません + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees メソッド グループの '&' を式ツリーで使用することはできません @@ -282,14 +287,14 @@ レコード メンバー '{0}' は、位置指定パラメーター '{2}' に一致させるための型 '{1}' の読み取り可能なインスタンス プロパティまたはフィールドである必要があります。 - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - 型 'System.Threading.Lock' の値に対する lock ステートメントは、非同期メソッドまたは非同期ラムダ式では使用できません。 + + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - 型 '{0}' の using ステートメント リソースは、非同期メソッドまたは非同期ラムダ式では使用できません。 + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -317,6 +322,11 @@ '{0}' 型は 'using static' では無効です。使用できるのは、クラス、構造体、インターフェイス、列挙型、デリゲート、名前空間のみです。 + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. AsyncMethodBuilder 属性は、明示的な戻り値の型のない匿名メソッドでは許可されていません。 @@ -1767,6 +1777,11 @@ ref フィールドは ref 構造体でのみ宣言できます。 + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + The left-hand side of a ref assignment must be a ref variable. ref 代入の左辺は ref 変数である必要があります。 @@ -2422,6 +2437,11 @@ ref struct interfaces + + ref and unsafe in async and iterator methods + ref and unsafe in async and iterator methods + + relaxed shift operator 緩和されたシフト演算子 @@ -2597,6 +2617,16 @@ 'in' パラメーターに対応する引数の 'ref' 修飾子は 'in' と同じです。代わりに 'in' を使用することを検討してください。 + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + Attribute parameter 'SizeConst' must be specified. 属性パラメーター 'SizeConst' を指定する必要があります。 @@ -9221,11 +9251,6 @@ AssemblyInfo.cs ファイルで RuntimeCompatibilityAttribute が false に設 ref、out、in パラメーター '{0}' は、匿名メソッド、ラムダ式、クエリ式、ローカル関数の内部では使用できません - - Unsafe code may not appear in iterators - アンセーフ コードは反復子には記述できません - - Cannot yield a value in the body of a catch clause catch 句の本体で値を生成することはできません @@ -10610,8 +10635,8 @@ C# では out と ref を区別しますが、CLR では同じと認識します - 'await' cannot be used in an expression containing the type '{0}' - 'await' は、型 '{0}' を含む式では使用できません + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + 'await' は、型 '{0}' を含む式では使用できません @@ -10679,16 +10704,6 @@ C# では out と ref を区別しますが、CLR では同じと認識します async' 修飾子は、本体があるメソッドでのみ使用できます。 - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - '{0}' 型のパラメーターまたはローカルは、非同期メソッドまたは非同期ラムダ式で宣言することができません。 - - - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - '{0}' は ref 構造体であるため、非同期または反復子のメソッド内で型 '{0}' の列挙子に対して foreach ステートメントは機能しません。 - - Security attribute '{0}' cannot be applied to an Async method. セキュリティ属性 '{0}' を非同期メソッドに適用することはできません。 @@ -11208,7 +11223,7 @@ You should consider suppressing the warning only if you're sure that you don't w Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method - 型 '{0}' のインスタンスは、入れ子になった関数、クエリ式、反復子ブロック、または非同期メソッドの中では使用できません + Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method @@ -12519,16 +12534,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ 匿名メソッド、ラムダ式、クエリ式内で ref ローカル変数 '{0}' は使用できません - - Iterators cannot have by-reference locals - 反復子は参照渡しのローカル変数を持つことができません - - - - Async methods cannot have by-reference locals - 非同期メソッドは参照渡しのローカル変数を持つことができません - - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. '{0}' への呼び出しによって返された参照は、'await' または 'yield' 境界を越えて保持することはできません。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 3a0a76cc1b697..dd8ef848b9a66 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -32,6 +32,11 @@ '{0}': 추상 이벤트는 이벤트 접근자 구문을 사용할 수 없습니다. + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees 식 트리에서는 메서드 그룹에 '&'를 사용할 수 없습니다. @@ -282,14 +287,14 @@ 위치 매개 변수 '{0}'과(와) 일치하려면 레코드 멤버 '{1}'이(가) 유형 '{2}'의 읽을 수 있는 인스턴스 속성 또는 필드여야 합니다. - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - 'System.Threading.Lock' 형식의 값에 대한 lock 문은 비동기 메서드 또는 비동기 람다 식에서 사용할 수 없습니다. + + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - '{0}' 형식의 using 문 리소스는 비동기 메서드 또는 비동기 람다 식에 사용할 수 없습니다. + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -317,6 +322,11 @@ '{0}' 유형은 '정적 사용'에 유효하지 않습니다. 클래스, 구조체, 인터페이스, 열거형, 대리자 또는 네임스페이스만 사용할 수 있습니다. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. AsyncMethodBuilder 특성은 명시적 반환 형식이 없는 익명 메서드에서 허용되지 않습니다. @@ -1767,6 +1777,11 @@ ref 필드는 ref 구조체에서만 선언할 수 있습니다. + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + The left-hand side of a ref assignment must be a ref variable. ref 할당의 왼쪽은 ref 변수여야 합니다. @@ -2422,6 +2437,11 @@ ref struct interfaces + + ref and unsafe in async and iterator methods + ref and unsafe in async and iterator methods + + relaxed shift operator 완화된 시프트 연산자 @@ -2597,6 +2617,16 @@ 'in' 매개 변수에 해당하는 인수의 'ref' 한정자는 'in'에 해당합니다. 대신 'in'을 사용하는 것이 좋습니다. + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + Attribute parameter 'SizeConst' must be specified. 특성 매개 변수 'SizeConst'를 지정해야 합니다. @@ -9221,11 +9251,6 @@ catch (System.Exception e) 블록 뒤의 catch() 블록은 RuntimeCompatibilityA 무명 메서드, 람다 식, 쿼리 식 또는 로컬 함수 안에서는 ref, out 또는 in 매개 변수 '{0}'을(를) 사용할 수 없습니다. - - Unsafe code may not appear in iterators - 반복기에는 안전하지 않은 코드를 사용할 수 없습니다. - - Cannot yield a value in the body of a catch clause catch 절 본문에서는 값을 생성할 수 없습니다. @@ -10610,8 +10635,8 @@ C#에서는 out과 ref를 구분하지만 CLR에서는 동일한 것으로 간 - 'await' cannot be used in an expression containing the type '{0}' - 'await'는 '{0}' 형식이 포함된 식에 사용할 수 없습니다. + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + 'await'는 '{0}' 형식이 포함된 식에 사용할 수 없습니다. @@ -10679,16 +10704,6 @@ C#에서는 out과 ref를 구분하지만 CLR에서는 동일한 것으로 간 async' 한정자는 본문이 있는 메서드에서만 사용할 수 있습니다. - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - '{0}' 형식의 매개 변수 또는 로컬은 비동기 메서드나 비동기 람다 식에서 선언할 수 없습니다. - - - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - '{0}'은(는) ref struct이므로 비동기 또는 반복기 메서드의 '{0}' 형식 열거자에서 foreach 문을 수행할 수 없습니다. - - Security attribute '{0}' cannot be applied to an Async method. '{0}' 보안 특성은 비동기 메서드에 적용할 수 없습니다. @@ -11208,7 +11223,7 @@ You should consider suppressing the warning only if you're sure that you don't w Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method - '{0}' 형식의 인스턴스는 중첩된 함수, 쿼리 식, 반복기 블록 또는 비동기 메서드 내에서 사용할 수 없습니다. + Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method @@ -12519,16 +12534,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ 무명 메서드, 람다 식 또는 쿼리 식에는 참조 로컬 '{0}'을(를) 사용할 수 없습니다. - - Iterators cannot have by-reference locals - 반복기에 by-reference 로컬을 사용할 수 없습니다. - - - - Async methods cannot have by-reference locals - 비동기 메서드에 by-reference 로컬을 사용할 수 없습니다. - - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. '{0}'에 대한 호출로 반환된 참조는 'await' 또는 'yield' 경계에서 보존할 수 없습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 740896f6f0ab0..871593fc5cad5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -32,6 +32,11 @@ „{0}”: zdarzenie abstrakcyjne nie może używać składni metody dostępu zdarzenia + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees Znak „&” dla grup metod nie może być używany w drzewach wyrażeń @@ -282,14 +287,14 @@ Składowa rekordu "{0}" musi być możliwą do odczytu właściwością wystąpienia typu "{1}", aby dopasować parametr pozycyjny "{2}". - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - Instrukcja blokady na wartości typu „System.Threading.Lock” nie może być używana w metodach asynchronicznych lub asynchronicznych wyrażeniach lambda. + + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - Zasobu instrukcji przy użyciu typu '{0}' nie można używać w metodach asynchronicznych ani asynchronicznych wyrażeniach lambda. + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -317,6 +322,11 @@ Typ „{0}” jest nieprawidłowy dla „using static”. Można używać tylko klasy, struktury, interfejsu, wyliczenia, delegata lub przestrzeni nazw. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. Atrybut AsyncMethodBuilder jest niedozwolony w metodach anonimowych bez jawnego zwracanego typu. @@ -1767,6 +1777,11 @@ Pole referencyjne można zadeklarować tylko w strukturze referencyjnej. + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + The left-hand side of a ref assignment must be a ref variable. Lewa strona przypisania referencyjnego musi być zmienną referencyjną. @@ -2422,6 +2437,11 @@ ref struct interfaces + + ref and unsafe in async and iterator methods + ref and unsafe in async and iterator methods + + relaxed shift operator operator swobodnej zmiany @@ -2597,6 +2617,16 @@ Modyfikator „ref” dla argumentu odpowiadającego parametrowi „in” jest równoważny parametrowi „in”. Zamiast tego rozważ użycie parametru „in”. + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + Attribute parameter 'SizeConst' must be specified. Należy określić parametr atrybutu „SizeConst”. @@ -9221,11 +9251,6 @@ Blok catch() po bloku catch (System.Exception e) może przechwytywać wyjątki n Nie można użyć parametru ref, out ani in „{0}” wewnątrz metody anonimowej, wyrażenia lambda, wyrażenia zapytania lub funkcji lokalnej - - Unsafe code may not appear in iterators - Niebezpieczny kod nie może występować w iteratorach. - - Cannot yield a value in the body of a catch clause Nie można użyć instrukcji yield z wartością w treści klauzuli catch. @@ -10610,8 +10635,8 @@ Musisz umożliwić kompilatorowi rozróżnienie metod. Możesz na przykład nada - 'await' cannot be used in an expression containing the type '{0}' - 'Operatora „await” nie można użyć w wyrażeniu zawierającym typ „{0}” + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + 'Operatora „await” nie można użyć w wyrażeniu zawierającym typ „{0}” @@ -10679,16 +10704,6 @@ Musisz umożliwić kompilatorowi rozróżnienie metod. Możesz na przykład nada Modyfikatora „async” można używać tylko w metodach mających treść. - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - Parametrów ani elementów lokalnych typu „{0}” nie można deklarować w metodach asynchronicznych ani wyrażeniach lambda. - - - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - Instrukcja foreach nie może działać na modułach wyliczających typu „{0}” w metodach asynchronicznych lub iteratora, ponieważ element „{0}” jest strukturą ref. - - Security attribute '{0}' cannot be applied to an Async method. Atrybutu zabezpieczeń „{0}” nie można zastosować dla metody asynchronicznej. @@ -11208,7 +11223,7 @@ Pominięcie ostrzeżenia należy wziąć pod uwagę tylko w sytuacji, gdy na pew Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method - Wystąpienia typu „{0}” nie można użyć wewnątrz funkcji zagnieżdżonej, wyrażenia zapytania, bloku iteratora ani metody asynchronicznej + Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method @@ -12519,16 +12534,6 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w Nie można użyć zmiennej lokalnej typu ref „{0}” wewnątrz metody anonimowej, wyrażenia lambda ani wyrażenia zapytania - - Iterators cannot have by-reference locals - Iteratory nie mogą mieć zmiennych lokalnych dostępnych przez odwołanie - - - - Async methods cannot have by-reference locals - Metody asynchroniczne nie mogą mieć zmiennych lokalnych dostępnych przez odwołanie - - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. Odwołanie zwrócone przez wywołanie „{0}” nie może zostać zachowane w granicach „await” lub „yield”. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index beac0aa629b3f..a4f21ff34b491 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -32,6 +32,11 @@ '{0}': o evento abstrato não pode usar a sintaxe do acessador de eventos + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees '&' nos grupos de métodos não pode ser usado em árvores de expressão @@ -282,14 +287,14 @@ O membro do registro '{0}' precisa ser uma propriedade de instância legível ou campo do tipo '{1}' para corresponder ao parâmetro posicional '{2}'. - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - Uma instrução lock em um valor do tipo "System.Threading.Lock" não pode ser usada em métodos assíncronos ou em expressões lambda assíncronas. + + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - Um recurso de instrução using do tipo "{0}" não pode ser usado em métodos assíncronos ou expressões lambda assíncronas. + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -317,6 +322,11 @@ '{0}' tipo não é válido para 'using static'. Somente uma classe, struct, interface, enumeração, delegado ou namespace podem ser usados. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. O atributo AsyncMethodBuilder não é permitido em métodos anônimos sem um tipo de retorno explícito. @@ -1767,6 +1777,11 @@ Um campo ref só pode ser declarado em uma estrutura ref. + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + The left-hand side of a ref assignment must be a ref variable. O lado esquerdo de uma atribuição ref deve ser uma variável ref. @@ -2422,6 +2437,11 @@ ref struct interfaces + + ref and unsafe in async and iterator methods + ref and unsafe in async and iterator methods + + relaxed shift operator operador de deslocamento flexível @@ -2597,6 +2617,16 @@ O modificador 'ref' do argumento correspondente ao parâmetro 'in' é equivalente a 'in'. Considere usar 'in' em vez disso. + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + Attribute parameter 'SizeConst' must be specified. O parâmetro de atribuição 'SizeConst' deve ser especificado. @@ -9221,11 +9251,6 @@ Um bloco catch() depois de um bloco catch (System.Exception e) poderá capturar Não é possível usar os parâmetro ref, out ou in '{0}' dentro de um método anônimo, de uma expressão lambda de uma expressão de consulta ou de uma função local - - Unsafe code may not appear in iterators - Código sem segurança só pode aparecer em iteradores - - Cannot yield a value in the body of a catch clause Não é possível usar a instrução yield no corpo de uma cláusula catch @@ -10610,8 +10635,8 @@ Forneça ao compilador alguma forma de diferenciar os métodos. Por exemplo, voc - 'await' cannot be used in an expression containing the type '{0}' - 'aguardar' não pode ser usado em uma expressão que contém o tipo '{0}' + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + 'aguardar' não pode ser usado em uma expressão que contém o tipo '{0}' @@ -10679,16 +10704,6 @@ Forneça ao compilador alguma forma de diferenciar os métodos. Por exemplo, voc O modificador 'async' só pode ser usado em métodos que têm um corpo. - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - Os parâmetros ou locais do tipo '{0}' não podem ser declarados nos métodos async ou expressões async lambda. - - - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - a instrução foreach não pode operar em enumeradores do tipo '{0}' em métodos assíncronos ou iteradores porque '{0}' é uma struct de referência. - - Security attribute '{0}' cannot be applied to an Async method. Atributo de segurança "{0}" não pode ser aplicado a um método Assíncrono. @@ -11208,7 +11223,7 @@ Você pode suprimir o aviso se tiver certeza de que não vai querer aguardar a c Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method - A instância do tipo '{0}' não pode ser usada dentro de uma função aninhada, expressão de consulta, bloco de iteradores ou método assíncrono + Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method @@ -12519,16 +12534,6 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl Não é possível usar a referência local '{0}' em um método anônimo, expressão lambda ou expressão de consulta - - Iterators cannot have by-reference locals - Os iteradores não podem ter locais por referência - - - - Async methods cannot have by-reference locals - Os métodos assíncronos não podem ter locais por referência - - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. Uma referência retornada por uma chamada para '{0}' não pode ser preservada no limite 'await' ou 'yield'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 9fe64263348de..7bc750767181d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -32,6 +32,11 @@ "{0}": абстрактное событие не может использовать синтаксис метода доступа к событиям. + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees "&" в группах методов не может использоваться в деревьях выражений @@ -282,14 +287,14 @@ Элемент записи "{0}" должен быть доступным для чтения свойством экземпляра или полем типа "{1}", чтобы соответствовать позиционному параметру "{2}". - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - Оператор блокировки над значением типа "System.Threading.Lock" нельзя использовать в асинхронных методах и в асинхронных лямбда-выражениях. + + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - Ресурс оператора использования типа "{0}" нельзя применять в асинхронных методах или асинхронных лямбда-выражениях. + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -317,6 +322,11 @@ ' {0} ' недопустим для 'использования статики'. Можно использовать только класс, структуру, интерфейс, перечисление, делегат или пространство имен. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. Атрибут AsyncMethodBuilder запрещен для анонимных методов без явного типа возвращаемого значения. @@ -1767,6 +1777,11 @@ Поле ссылки может быть объявлено только в структуре ссылки. + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + The left-hand side of a ref assignment must be a ref variable. Левая сторона назначения ref должна быть переменной ref. @@ -2422,6 +2437,11 @@ ref struct interfaces + + ref and unsafe in async and iterator methods + ref and unsafe in async and iterator methods + + relaxed shift operator нестрогий оператор сдвига @@ -2597,6 +2617,16 @@ Модификатор "ref" для аргумента, соответствующего параметру "in", эквивалентен "in". Попробуйте вместо этого использовать "in". + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + Attribute parameter 'SizeConst' must be specified. Должен быть указан параметр атрибута "SizeConst". @@ -9222,11 +9252,6 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep Недопустимо использовать параметр "{0}" с модификаторами ref, out или in внутри анонимного метода, лямбда-выражения, выражения запроса или локальной функции - - Unsafe code may not appear in iterators - Небезопасный код не может использоваться в итераторах. - - Cannot yield a value in the body of a catch clause Нельзя использовать оператор yield в теле предложения catch. @@ -10611,8 +10636,8 @@ Give the compiler some way to differentiate the methods. For example, you can gi - 'await' cannot be used in an expression containing the type '{0}' - '"await" нельзя использовать в выражении, содержащем тип "{0}" + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + '"await" нельзя использовать в выражении, содержащем тип "{0}" @@ -10680,16 +10705,6 @@ Give the compiler some way to differentiate the methods. For example, you can gi Модификатор "async" можно использовать только в методах, имеющих тело. - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - Параметры или локальные переменные типа "{0}" не могут объявляться в асинхронных методах и в асинхронных лямбда-выражениях. - - - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - Оператор foreach нельзя использовать с перечислителями типа "{0}" в методах с модификатором Async или Iterator, так как "{0}" является ссылочной структурой. - - Security attribute '{0}' cannot be applied to an Async method. Атрибут безопасности "{0}" нельзя применить к асинхронному методу. @@ -11209,7 +11224,7 @@ You should consider suppressing the warning only if you're sure that you don't w Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method - Экземпляр типа "{0}" нельзя использовать внутри вложенной функции, выражения запроса, блока итератора или асинхронного метода. + Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method @@ -12520,16 +12535,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Невозможно использовать локальную переменную ref "{0}" внутри анонимного метода, лямбда-выражения или выражения запроса - - Iterators cannot have by-reference locals - Итераторы не могут иметь локальных переменных по ссылке - - - - Async methods cannot have by-reference locals - Асинхронные методы не могут иметь локальных переменных по ссылке - - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. Ссылка, возвращенная вызовом ' {0} ', не может быть сохранена за границей 'wait' или 'yield'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 12d5367482f69..61a78dded475d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -32,6 +32,11 @@ '{0}': soyut olay, olay erişeni söz dizimini kullanamaz + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees Metot gruplarındaki '&', ifade ağaçlarında kullanılamaz @@ -282,14 +287,14 @@ {0} kayıt üyesi, {1} konumsal parametresi ile eşleşmesi için {2} türünde okunabilir bir örnek özelliği veya alan olmalıdır. - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - 'System.Threading.Lock' türündeki bir değere ilişkin lock deyimi, asenkron yöntemlerde veya asenkron lambda ifadelerinde kullanılamaz. + + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - '{0}' türündeki bir using deyimi kaynağı, asenkron yöntemlerde veya asenkron lambda ifadelerinde kullanılamaz. + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -317,6 +322,11 @@ '{0}' türü 'using static' için geçerli değil. Yalnızca bir sınıf, yapı, arabirim, sabit liste, temsilci veya ad alanı kullanılabilir. + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. Açık dönüş türü olmadan, anonim yöntemlerde AsyncMethodBuilder özniteliğine izin verilmez. @@ -1767,6 +1777,11 @@ Başvuru alanı yalnızca başvuru yapısında bildirilebilir. + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + The left-hand side of a ref assignment must be a ref variable. ref atamasının sol tarafı, ref değişkeni olmalıdır. @@ -2422,6 +2437,11 @@ ref struct interfaces + + ref and unsafe in async and iterator methods + ref and unsafe in async and iterator methods + + relaxed shift operator esnek kaydırma işleci @@ -2597,6 +2617,16 @@ 'in' parametresine karşılık gelen bir bağımsız değişken için 'ref' değiştiricisi 'in' ile eşdeğerdir. Bunun yerine 'in' kullanmayı düşünün. + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + Attribute parameter 'SizeConst' must be specified. 'SizeConst' öznitelik parametresi belirtilmelidir. @@ -9221,11 +9251,6 @@ RuntimeCompatibilityAttribute AssemblyInfo.cs dosyasında false olarak ayarlanm Anonim metot, lambda ifadesi, sorgu ifadesi veya yerel işlev içinde '{0}' ref, out veya in parametresi kullanılamaz - - Unsafe code may not appear in iterators - Güvenli olmayan kod yineleyicilerde görünmeyebilir - - Cannot yield a value in the body of a catch clause Catch yan tümcesinin gövdesinde yield ile bir değer döndürülemez @@ -10610,8 +10635,8 @@ Derleyiciye yöntemleri ayrıştırma yolu verin. Örneğin, bunlara farklı adl - 'await' cannot be used in an expression containing the type '{0}' - 'await', '{0}' türünü içeren bir ifadede kullanılamaz + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + 'await', '{0}' türünü içeren bir ifadede kullanılamaz @@ -10679,16 +10704,6 @@ Derleyiciye yöntemleri ayrıştırma yolu verin. Örneğin, bunlara farklı adl Async' değiştiricisi yalnızca gövdesi olan metotlarda kullanılabilir. - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - Zaman uyumsuz yöntemlerde veya zaman uyumsuz lambda ifadelerinde '{0}' türündeki parametreler veya yerel öğeler bildirilemez. - - - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - '{0}' bir başvuru yapısı olduğundan foreach deyimi, async veya iterator metotlarındaki '{0}' türü numaralandırıcılar üzerinde çalışamaz. - - Security attribute '{0}' cannot be applied to an Async method. '{0}' güvenlik özniteliği bir Async yöntemine uygulanamaz. @@ -11208,7 +11223,7 @@ Yalnızca asenkron çağrının tamamlanmasını beklemek istemediğinizden ve Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method - '{0}' türünün örneği iç içe geçmiş bir işlevde, sorgu ifadesinde, yineleyici bloğunda veya zaman uyumsuz bir metotta kullanılamaz + Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method @@ -12519,16 +12534,6 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T '{0}' ref yerel değeri bir anonim metotta, lambda ifadesinde veya sorgu ifadesinde kullanılamaz - - Iterators cannot have by-reference locals - Yineleyiciler başvuruya göre yerel değerlere sahip olamaz - - - - Async methods cannot have by-reference locals - Zaman uyumsuz metotlar başvuruya göre yerel değerlere sahip olamaz - - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. '{0}' hedefine bir çağrı tarafından döndürülen başvuru, 'await' veya 'yield' sınırında korunamıyor. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 8474baffa7512..b0175426fa302 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -32,6 +32,11 @@ “{0}”: 抽象事件不可使用事件访问器语法 + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees 不可在表达式树中使用方法组上的 "&" @@ -282,14 +287,14 @@ 记录成员 '{0}' 必须为类型 '{1}' 的可读实例属性或字段,以匹配位置参数 '{2}'。 - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - 类型“System.Threading.Lock”的值的 lock 语句不能用于异步方法或异步 lambda 表达式。 + + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - 无法在异步方法或异步 lambda 表达式中使用类型为“{0}”的 using 语句资源。 + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -317,6 +322,11 @@ “{0}”类型对于 "using static" 无效。只能使用类、结构、接口、枚举、委托或命名空间。 + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. 没有显式返回类型的匿名方法不允许使用 AsyncMethodBuilder 属性。 @@ -1767,6 +1777,11 @@ ref 字段只能在 ref 结构中声明。 + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + The left-hand side of a ref assignment must be a ref variable. ref 赋值的左侧必须为 ref 变量。 @@ -2422,6 +2437,11 @@ ref struct interfaces + + ref and unsafe in async and iterator methods + ref and unsafe in async and iterator methods + + relaxed shift operator 移位运算符 @@ -2597,6 +2617,16 @@ 与 “in” 参数对应的参数的 “ref” 修饰符等效于 “in”。请考虑改用 “in”。 + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + Attribute parameter 'SizeConst' must be specified. 必须指定属性参数 “SizeConst”。 @@ -9221,11 +9251,6 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep 不能在匿名方法、lambda 表达式、查询表达式或本地函数中使用 ref、out 或 in 参数“{0}” - - Unsafe code may not appear in iterators - 迭代器中不能出现不安全的代码 - - Cannot yield a value in the body of a catch clause 无法在 catch 子句体中生成值 @@ -10610,8 +10635,8 @@ Give the compiler some way to differentiate the methods. For example, you can gi - 'await' cannot be used in an expression containing the type '{0}' - '“等待”不能在包含“{0}”类型的表达式中使用 + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + '“等待”不能在包含“{0}”类型的表达式中使用 @@ -10679,16 +10704,6 @@ Give the compiler some way to differentiate the methods. For example, you can gi 只能在具有正文的方法中使用 "async" 修饰符。 - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - 不能在异步方法或异步 lambda 表达式中声明类型“{0}”的参数或局部变量。 - - - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - foreach 语句无法在类型“{0}”的枚举器上使用异步或迭代器方法操作,因为“{0}”是 ref 结构。 - - Security attribute '{0}' cannot be applied to an Async method. 安全特性“{0}”不可应用于异步方法。 @@ -11208,7 +11223,7 @@ You should consider suppressing the warning only if you're sure that you don't w Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method - “{0}”类型的实例不能在嵌套函数、查询表达式、迭代器块或异步方法中使用 + Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method @@ -12519,16 +12534,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ 不能在匿名方法、lambda 表达式或查询表达式内使用 ref 局部变量“{0}” - - Iterators cannot have by-reference locals - 迭代器不能有按引用局部变量 - - - - Async methods cannot have by-reference locals - 异步方法不能有按引用局部变量 - - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. 调用“{0}”所返回的引用不能跨 "await" 或 "yield" 边界保留。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 2f85585c6f3b6..59932f5945760 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -32,6 +32,11 @@ '{0}' 抽象事件無法使用事件存取子語法 + + The '&' operator cannot be used on parameters or local variables in iterator methods. + The '&' operator cannot be used on parameters or local variables in iterator methods. + + '&' on method groups cannot be used in expression trees 不得在運算式樹狀架構中對方法群組使用 '&' @@ -282,14 +287,14 @@ 記錄成員 '{0}' 必須是類型 '{1}' 的可讀取執行個體屬性或欄位,才能符合位置參數 '{2}'。 - - A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - 型別 'System.Threading.Lock' 的值上的 lock 陳述式不能用在非同步方法或非同步 Lambda 運算式中。 + + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. + foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - - A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions. - 類型 '{0}' 的 using 陳述式資源不能用於非同步方法或非同步 Lambda 運算式。 + + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. + Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -317,6 +322,11 @@ '{0}' 類型對 'using static' 無效。只能使用類別、結構、介面、列舉、委派或命名空間。 + + Cannot use 'yield return' in an 'unsafe' block + Cannot use 'yield return' in an 'unsafe' block + + The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. 沒有明確傳回型別的匿名方法上不允許 AsyncMethodBuilder 屬性。 @@ -1767,6 +1777,11 @@ ref 欄位只能在 ref 結構中宣告。 + + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + + The left-hand side of a ref assignment must be a ref variable. 參考指派的左側必須為 ref 變數。 @@ -2422,6 +2437,11 @@ ref struct interfaces + + ref and unsafe in async and iterator methods + ref and unsafe in async and iterator methods + + relaxed shift operator 寬鬆移位 (Shift) 運算子 @@ -2597,6 +2617,16 @@ 對應至 'in' 參數之引數的 'ref' 修飾元相當於 'in'。請考慮改為使用 'in'。 + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + + + 'yield return' should not be used in the body of a lock statement + 'yield return' should not be used in the body of a lock statement + + Attribute parameter 'SizeConst' must be specified. 必須指定屬性參數 'SizeConst'。 @@ -9221,11 +9251,6 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep 無法在匿名方法、Lambda 運算式、查詢運算式或區域函式中使用 ref、out 或 in 參數 '{0}' - - Unsafe code may not appear in iterators - Unsafe 程式碼不可出現在迭代器中 - - Cannot yield a value in the body of a catch clause 無法在 catch 子句主體中使用 yield 產生值 @@ -10610,8 +10635,8 @@ Give the compiler some way to differentiate the methods. For example, you can gi - 'await' cannot be used in an expression containing the type '{0}' - 'await' 不得用於包含類型 '{0}' 的運算式中 + Instance of type '{0}' cannot be preserved across 'await' or 'yield' boundary. + 'await' 不得用於包含類型 '{0}' 的運算式中 @@ -10679,16 +10704,6 @@ Give the compiler some way to differentiate the methods. For example, you can gi async' 修飾元只可用於具有主體的方法。 - - Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions. - 類型 '{0}' 的參數或區域變數,不可在非同步方法或非同步 Lambda 運算式中宣告。 - - - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - foreach 陳述式無法對 async 或 iterator 方法中類型 '{0}' 的列舉值進行操作,因為 '{0}' 為 ref struct。 - - Security attribute '{0}' cannot be applied to an Async method. 安全屬性 '{0}' 無法套用至非同步方法。 @@ -11208,7 +11223,7 @@ You should consider suppressing the warning only if you're sure that you don't w Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method - 類型 '{0}' 的執行個體不可用於巢狀函式、查詢運算式、迭代區塊或非同步方法中 + Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method @@ -12519,16 +12534,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ 無法在匿名方法、Lambda 運算式或查詢運算式中使用參考本機 '{0}' - - Iterators cannot have by-reference locals - Iterator 不可有 by-reference local - - - - Async methods cannot have by-reference locals - 非同步方法不可有 by-reference local - - A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary. 對 '{0}' 之呼叫所傳回的參考無法在 'await' 或 'yield' 界限間保留。 diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs index 9842e30b2a710..2ea7b234d8da8 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs @@ -133,7 +133,7 @@ private static void VerifyMissingType(string source, WellKnownType type, params // Instrumentation to investigate CI failure: https://github.com/dotnet/roslyn/issues/34207 private CSharpCompilation CreateCompilationWithAsyncIterator(string source, CSharpCompilationOptions options = null, CSharpParseOptions parseOptions = null) => CreateCompilationWithTasksExtensions(new[] { (CSharpTestSource)CSharpTestBase.Parse(source, filename: "source", parseOptions), CSharpTestBase.Parse(AsyncStreamsTypes, filename: "AsyncStreamsTypes", parseOptions) }, - options: options, parseOptions: parseOptions); + options: options); private CSharpCompilation CreateCompilationWithAsyncIterator(CSharpTestSource source, CSharpCompilationOptions options = null, CSharpParseOptions parseOptions = null) => CreateCompilationWithTasksExtensions(new[] { source, AsyncStreamsTypes }, options: options, parseOptions: parseOptions); @@ -631,15 +631,288 @@ static async System.Threading.Tasks.Task Main() ref struct S { }"; + + var expectedDiagnostics = new[] + { + // source(4,65): error CS9504: The type 'S' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'T' in the generic type or method 'IAsyncEnumerable' + // static async System.Collections.Generic.IAsyncEnumerable M() + Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "M").WithArguments("System.Collections.Generic.IAsyncEnumerable", "T", "S").WithLocation(4, 65) + }; + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular12); comp.VerifyDiagnostics( // source(4,65): error CS9504: The type 'S' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'T' in the generic type or method 'IAsyncEnumerable' // static async System.Collections.Generic.IAsyncEnumerable M() Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "M").WithArguments("System.Collections.Generic.IAsyncEnumerable", "T", "S").WithLocation(4, 65), - // source(11,24): error CS4012: Parameters or locals of type 'S' cannot be declared in async methods or async lambda expressions. + // source(11,24): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // await foreach (var s in M()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "var").WithArguments("S").WithLocation(11, 24) - ); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 24)); + } + + [Fact] + public void RefStructElementType_NonGeneric() + { + string source = """ + using System.Threading.Tasks; + + class C + { + public E GetAsyncEnumerator() => new E(); + static async Task Main() + { + await foreach (var s in new C()) + { + System.Console.Write(s.F); + } + } + } + class E + { + bool _done; + public S Current => new S { F = 123 }; + public async Task MoveNextAsync() + { + await Task.Yield(); + return !_done ? (_done = true) : false; + } + } + ref struct S + { + public int F; + } + """; + + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular12); + comp.VerifyDiagnostics( + // source(8,24): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 24)); + + comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); + var verifier = CompileAndVerify(comp, expectedOutput: "123", verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C.
d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 238 (0xee) + .maxstack 3 + .locals init (int V_0, + S V_1, //s + System.Runtime.CompilerServices.TaskAwaiter V_2, + C.
d__1 V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld "int C.
d__1.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: beq.s IL_0014 + IL_0010: br.s IL_0016 + IL_0012: br.s IL_0082 + IL_0014: br.s IL_0082 + IL_0016: nop + IL_0017: nop + IL_0018: ldarg.0 + IL_0019: newobj "C..ctor()" + IL_001e: call "E C.GetAsyncEnumerator()" + IL_0023: stfld "E C.
d__1.<>s__1" + IL_0028: br.s IL_0044 + IL_002a: ldarg.0 + IL_002b: ldfld "E C.
d__1.<>s__1" + IL_0030: callvirt "S E.Current.get" + IL_0035: stloc.1 + IL_0036: nop + IL_0037: ldloc.1 + IL_0038: ldfld "int S.F" + IL_003d: call "void System.Console.Write(int)" + IL_0042: nop + IL_0043: nop + IL_0044: ldarg.0 + IL_0045: ldfld "E C.
d__1.<>s__1" + IL_004a: callvirt "System.Threading.Tasks.Task E.MoveNextAsync()" + IL_004f: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_0054: stloc.2 + IL_0055: ldloca.s V_2 + IL_0057: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_005c: brtrue.s IL_009e + IL_005e: ldarg.0 + IL_005f: ldc.i4.0 + IL_0060: dup + IL_0061: stloc.0 + IL_0062: stfld "int C.
d__1.<>1__state" + IL_0067: ldarg.0 + IL_0068: ldloc.2 + IL_0069: stfld "System.Runtime.CompilerServices.TaskAwaiter C.
d__1.<>u__1" + IL_006e: ldarg.0 + IL_006f: stloc.3 + IL_0070: ldarg.0 + IL_0071: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__1.<>t__builder" + IL_0076: ldloca.s V_2 + IL_0078: ldloca.s V_3 + IL_007a: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, C.
d__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.
d__1)" + IL_007f: nop + IL_0080: leave.s IL_00ed + IL_0082: ldarg.0 + IL_0083: ldfld "System.Runtime.CompilerServices.TaskAwaiter C.
d__1.<>u__1" + IL_0088: stloc.2 + IL_0089: ldarg.0 + IL_008a: ldflda "System.Runtime.CompilerServices.TaskAwaiter C.
d__1.<>u__1" + IL_008f: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_0095: ldarg.0 + IL_0096: ldc.i4.m1 + IL_0097: dup + IL_0098: stloc.0 + IL_0099: stfld "int C.
d__1.<>1__state" + IL_009e: ldarg.0 + IL_009f: ldloca.s V_2 + IL_00a1: call "bool System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_00a6: stfld "bool C.
d__1.<>s__2" + IL_00ab: ldarg.0 + IL_00ac: ldfld "bool C.
d__1.<>s__2" + IL_00b1: brtrue IL_002a + IL_00b6: ldarg.0 + IL_00b7: ldnull + IL_00b8: stfld "E C.
d__1.<>s__1" + IL_00bd: leave.s IL_00d9 + } + catch System.Exception + { + IL_00bf: stloc.s V_4 + IL_00c1: ldarg.0 + IL_00c2: ldc.i4.s -2 + IL_00c4: stfld "int C.
d__1.<>1__state" + IL_00c9: ldarg.0 + IL_00ca: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__1.<>t__builder" + IL_00cf: ldloc.s V_4 + IL_00d1: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_00d6: nop + IL_00d7: leave.s IL_00ed + } + IL_00d9: ldarg.0 + IL_00da: ldc.i4.s -2 + IL_00dc: stfld "int C.
d__1.<>1__state" + IL_00e1: ldarg.0 + IL_00e2: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__1.<>t__builder" + IL_00e7: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_00ec: nop + IL_00ed: ret + } + """); + } + + [Fact] + public void RefStructElementType_NonGeneric_AwaitAfter() + { + string source = """ + using System.Threading.Tasks; + + class C + { + public E GetAsyncEnumerator() => new E(); + static async Task Main() + { + await foreach (var s in new C()) + { + System.Console.Write(s.F); + await Task.Yield(); + } + } + } + class E + { + bool _done; + public S Current => new S { F = 123 }; + public async Task MoveNextAsync() + { + await Task.Yield(); + return !_done ? (_done = true) : false; + } + } + ref struct S + { + public int F; + } + """; + + var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular12); + comp.VerifyDiagnostics( + // source(8,24): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 24)); + + comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); + var verifier = CompileAndVerify(comp, expectedOutput: "123", verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void RefStructElementType_NonGeneric_AwaitBefore() + { + string source = """ + using System.Threading.Tasks; + + class C + { + public E GetAsyncEnumerator() => new E(); + static async Task Main() + { + await foreach (var s in new C()) + { + await Task.Yield(); + System.Console.Write(s.F); + } + } + } + class E + { + bool _done; + public S Current => new S { F = 123 }; + public async Task MoveNextAsync() + { + await Task.Yield(); + return !_done ? (_done = true) : false; + } + } + ref struct S + { + public int F; + } + """; + + var comp = CreateCompilationWithAsyncIterator(source, parseOptions: TestOptions.Regular12); + comp.VerifyDiagnostics( + // source(8,24): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 24)); + + var expectedDiagnostics = new[] + { + // source(11,34): error CS4007: Instance of type 'S' cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(s.F); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s.F").WithArguments("S").WithLocation(11, 34) + }; + + comp = CreateCompilationWithAsyncIterator(source, parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(expectedDiagnostics); + + comp = CreateCompilationWithAsyncIterator(source); + comp.VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncSpillTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncSpillTests.cs index 0a7f649ff7d64..999bf6667331d 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncSpillTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncSpillTests.cs @@ -3789,9 +3789,11 @@ static async Task Main() var comp = CreateCompilationWithMscorlibAndSpan(source, options: options); comp.VerifyDiagnostics(); comp.VerifyEmitDiagnostics( - // (9,66): error CS4007: 'await' cannot be used in an expression containing the type 'System.Span' - // await Async1(F1(), G(F2(), stackalloc int[] { 1, 2, 3 }, await F3())); - Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await F3()").WithArguments("System.Span").WithLocation(9, 66) + // (8,5): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // { + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"{ + await Async1(F1(), G(F2(), stackalloc int[] { 1, 2, 3 }, await F3())); + }").WithArguments("System.Span").WithLocation(8, 5) ); } } @@ -3897,16 +3899,16 @@ public ref struct S public bool P2 => true; } "; - CreateCompilation(source, options: TestOptions.DebugDll).VerifyDiagnostics().VerifyEmitDiagnostics( - // (9,17): error CS4013: Instance of type 'S' cannot be used inside a nested function, query expression, iterator block or async method - // Q { F: { P1: true } } when await c => r, // error: cached Q.F is alive - Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "F").WithArguments("S").WithLocation(9, 17) - ); - CreateCompilation(source, options: TestOptions.ReleaseDll).VerifyDiagnostics().VerifyEmitDiagnostics( - // (9,17): error CS4013: Instance of type 'S' cannot be used inside a nested function, query expression, iterator block or async method + + var expectedDiagnostics = new[] + { + // (9,17): error CS4007: Instance of type 'S' cannot be preserved across 'await' or 'yield' boundary. // Q { F: { P1: true } } when await c => r, // error: cached Q.F is alive - Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "F").WithArguments("S").WithLocation(9, 17) - ); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "F").WithArguments("S").WithLocation(9, 17) + }; + + CreateCompilation(source, options: TestOptions.DebugDll).VerifyDiagnostics().VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source, options: TestOptions.ReleaseDll).VerifyDiagnostics().VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs index bce2519fce4d0..2dcb0b215b19d 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs @@ -1695,12 +1695,26 @@ public System.Threading.Tasks.Task MoveNextAsync() => throw null; public int Current { get => throw null; } } -}"; - var comp = CreateCompilationWithTasksExtensions(source + s_IAsyncEnumerable); +}" + s_IAsyncEnumerable; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12); comp.VerifyDiagnostics( - // (6,32): error CS8177: Async methods cannot have by-reference locals + // (6,32): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // await foreach (ref var i in new C()) - Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "i").WithLocation(6, 32)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "i").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 32)); + + var expectedDiagnostics = new[] + { + // (6,37): error CS1510: A ref or out value must be an assignable variable + // await foreach (ref var i in new C()) + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new C()").WithLocation(6, 37) + }; + + comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilationWithTasksExtensions(source); + comp.VerifyDiagnostics(expectedDiagnostics); var tree = comp.SyntaxTrees.Single(); var model = (SyntaxTreeSemanticModel)comp.GetSemanticModel(tree, ignoreAccessibility: false); @@ -1708,6 +1722,119 @@ public System.Threading.Tasks.Task MoveNextAsync() Assert.Equal(default, model.GetForEachStatementInfo(foreachSyntax)); } + [Theory, CombinatorialData] + public void TestWithPattern_Ref_Iterator([CombinatorialValues(" ", "readonly")] string modifier) + { + var source = $$""" + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + + class C + { + static async Task Main() + { + await foreach (int i in F()) + { + Console.Write(i); + } + } + + static async IAsyncEnumerable F() + { + await foreach (ref {{modifier}} var i in new C()) + { + yield return i; + } + } + + public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default) => new(); + + public sealed class Enumerator + { + private readonly int[] _array = [1, 2, 3]; + private int _index = -1; + public Task MoveNextAsync() + { + if (_index < _array.Length) _index++; + return Task.FromResult(_index < _array.Length); + } + public ref int Current => ref _array[_index]; + } + } + """ + AsyncStreamsTypes; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12); + comp.VerifyDiagnostics( + // (17,41): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (ref readonly var i in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "i").WithArguments("ref and unsafe in async and iterator methods").WithLocation(17, 41)); + + var expectedOutput = "123"; + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularNext); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_Ref_Iterator_Used() + { + var source = """ + using System.Collections.Generic; + using System.Threading.Tasks; + + class C + { + static async IAsyncEnumerable F() + { + await foreach (ref var i in new C()) + { + yield return i; + M(ref i); + } + } + + static void M(ref int i) { } + + public Enumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default) => new(); + + public sealed class Enumerator + { + private readonly int[] _array = [1, 2, 3]; + private int _index = -1; + public Task MoveNextAsync() + { + if (_index < _array.Length) _index++; + return Task.FromResult(_index < _array.Length); + } + public ref int Current => ref _array[_index]; + } + } + """ + AsyncStreamsTypes; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12); + comp.VerifyDiagnostics( + // (8,32): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (ref var i in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "i").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 32)); + + var expectedDiagnostics = new[] + { + // (11,19): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // M(ref i); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "i").WithLocation(11, 19) + }; + + comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(expectedDiagnostics); + + comp = CreateCompilationWithTasksExtensions(source); + comp.VerifyEmitDiagnostics(expectedDiagnostics); + } + [Fact] public void TestWithPattern_PointerType() { @@ -1935,7 +2062,427 @@ public S(int i) } [Fact] - public void TestWithPattern_RefReturningCurrent() + public void TestWithPattern_RefStructEnumerator_Async() + { + var source = """ + using System.Threading.Tasks; + public class C + { + public static async Task Main() + { + await foreach (var s in new C()) + { + } + } + public Enumerator GetAsyncEnumerator() => new Enumerator(); + public ref struct Enumerator + { + public int Current => 0; + public Task MoveNextAsync() => throw null; + } + } + """; + + var expectedDiagnostics = new[] + { + // (6,15): error CS8344: foreach statement cannot operate on enumerators of type 'C.Enumerator' in async or iterator methods because 'C.Enumerator' is a ref struct. + // await foreach (var s in new C()) + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C.Enumerator").WithLocation(6, 15) + }; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void TestWithPattern_RefStructEnumerator_AsyncIterator() + { + var source = """ + using System.Collections.Generic; + using System.Threading.Tasks; + public class C + { + public static async IAsyncEnumerable M() + { + await foreach (var x in new C()) + { + yield return x; + } + } + public Enumerator GetAsyncEnumerator() => new Enumerator(); + public ref struct Enumerator + { + public int Current => 0; + public Task MoveNextAsync() => throw null; + } + } + """ + s_IAsyncEnumerable; + + var expectedDiagnostics = new[] + { + // (7,15): error CS8344: foreach statement cannot operate on enumerators of type 'C.Enumerator' in async or iterator methods because 'C.Enumerator' is a ref struct. + // await foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C.Enumerator").WithLocation(7, 15) + }; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void TestWithPattern_RefStructEnumerator_Iterator() + { + var source = """ + using System.Collections.Generic; + public class C + { + public static IEnumerable M() + { + foreach (var x in new C()) + { + yield return x; + } + } + public Enumerator GetEnumerator() => new Enumerator(); + public ref struct Enumerator + { + public int Current => 0; + public bool MoveNext() => throw null; + } + } + """; + + var expectedDiagnostics = new[] + { + // (6,9): error CS8344: foreach statement cannot operate on enumerators of type 'C.Enumerator' in async or iterator methods because 'C.Enumerator' is a ref struct. + // foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C.Enumerator").WithLocation(6, 9) + }; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void TestWithPattern_RefStructEnumerable_Async() + { + var source = """ + using System; + using System.Threading.Tasks; + public class C + { + public static async Task Main() + { + await foreach (var x in new Enumerable()) + { + await Task.Yield(); + Console.Write($"{x} "); + } + Console.Write("Done"); + } + public ref struct Enumerable + { + public Enumerator GetAsyncEnumerator() => new(); + } + public class Enumerator + { + int i = 0; + public int Current => i; + public async Task MoveNextAsync() + { + i++; + await Task.Yield(); + return i < 3; + } + } + } + """ + s_IAsyncEnumerable; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "1 2 Done").VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefStructEnumerable_AsyncIterator() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + public class C + { + public static async Task Main() + { + await foreach (var i in M()) + { + Console.Write($"{i} "); + } + Console.Write("Done"); + } + public static async IAsyncEnumerable M() + { + await foreach (var x in new Enumerable()) + { + await Task.Yield(); + yield return x * 2; + } + yield return -1; + } + public ref struct Enumerable + { + public Enumerator GetAsyncEnumerator() => new(); + } + public class Enumerator + { + int i = 0; + public int Current => i; + public async Task MoveNextAsync() + { + i++; + await Task.Yield(); + return i < 3; + } + } + } + """ + AsyncStreamsTypes; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "2 4 -1 Done").VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefStructEnumerable_Iterator() + { + var source = """ + using System; + using System.Collections.Generic; + public class C + { + public static void Main() + { + foreach (var i in M()) + { + Console.Write($"{i} "); + } + Console.Write("Done"); + } + public static IEnumerable M() + { + foreach (var x in new Enumerable()) + { + yield return x * 2; + } + yield return -1; + } + public ref struct Enumerable + { + public Enumerator GetEnumerator() => new(); + } + public class Enumerator + { + int i = 0; + public int Current => i; + public bool MoveNext() + { + i++; + return i < 3; + } + } + } + """; + CompileAndVerify(source, expectedOutput: "2 4 -1 Done").VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefStructCurrent_Async() + { + var source = """ + using System; + using System.Threading.Tasks; + public class C + { + public static async Task Main() + { + await foreach (var s in new C()) + { + Console.Write($"{s.ToString()} "); + } + Console.Write("Done"); + } + public Enumerator GetAsyncEnumerator() => new Enumerator(); + public sealed class Enumerator : IAsyncDisposable + { + int i = 0; + public S Current => new S(i); + public async Task MoveNextAsync() + { + i++; + await Task.Yield(); + return i < 3; + } + public async ValueTask DisposeAsync() + { + await Task.Yield(); + } + } + } + public ref struct S + { + int i; + public S(int i) + { + this.i = i; + } + public override string ToString() => i.ToString(); + } + """ + s_IAsyncEnumerable; + + var expectedDiagnostics = new[] + { + // (7,24): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 24) + }; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + + var expectedOutput = "1 2 Done"; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefStructCurrent_AsyncIterator() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + public class C + { + public static async Task Main() + { + await foreach (var s in M()) + { + Console.Write($"M:{s} "); + } + Console.Write("MainDone"); + } + public static async IAsyncEnumerable M() + { + await foreach (var s in new C()) + { + yield return s.ToString(); + } + yield return "Done"; + } + public Enumerator GetAsyncEnumerator() => new Enumerator(); + public sealed class Enumerator : IAsyncDisposable + { + int i = 0; + public S Current => new S(i); + public async Task MoveNextAsync() + { + i++; + await Task.Yield(); + return i < 3; + } + public async ValueTask DisposeAsync() + { + await Task.Yield(); + } + } + } + public ref struct S + { + int i; + public S(int i) + { + this.i = i; + } + public override string ToString() => i.ToString(); + } + """ + AsyncStreamsTypes; + + var expectedDiagnostics = new[] + { + // (16,24): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(16, 24) + }; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + + var expectedOutput = "M:1 M:2 M:Done MainDone"; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefStructCurrent_Iterator() + { + var source = """ + using System; + using System.Collections.Generic; + public class C + { + public static void Main() + { + foreach (var s in M()) + { + Console.Write($"M:{s} "); + } + Console.Write("MainDone"); + } + public static IEnumerable M() + { + foreach (var s in new C()) + { + yield return s.ToString(); + } + yield return "Done"; + } + public Enumerator GetEnumerator() => new Enumerator(); + public sealed class Enumerator + { + int i = 0; + public S Current => new S(i); + public bool MoveNext() + { + i++; + return i < 3; + } + } + } + public ref struct S + { + int i; + public S(int i) + { + this.i = i; + } + public override string ToString() => i.ToString(); + } + """; + + var expectedOutput = "M:1 M:2 M:Done MainDone"; + + CompileAndVerify(source, parseOptions: TestOptions.Regular12, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefReturningCurrent_Async() { string source = @" using static System.Console; @@ -1986,6 +2533,275 @@ public override string ToString() CompileAndVerify(comp, expectedOutput: "1 2 3 Done", verify: Verification.Fails); } + [Fact] + public void TestWithPattern_RefReturningCurrent_Async_RefVariable() + { + string source = """ + using System; + using System.Threading.Tasks; + public class C + { + public static async Task Main() + { + await foreach (ref var s in new C()) + { + Console.Write($"{s} "); + s.F++; + } + Console.Write("Done"); + } + public Enumerator GetAsyncEnumerator() => new Enumerator(); + public sealed class Enumerator + { + S _current; + public ref S Current => ref _current; + public async Task MoveNextAsync() + { + Current = new S(Current.F + 1); + await Task.Yield(); + return Current.F < 4; + } + } + } + public struct S + { + public int F; + public S(int i) + { + this.F = i; + } + public override string ToString() => F.ToString(); + } + """ + s_IAsyncEnumerable; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,32): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (ref var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "s").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 32)); + + var expectedOutput = "1 3 Done"; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefReturningCurrent_AsyncIterator_RefVariable_01() + { + string source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + public class C + { + public static async Task Main() + { + await foreach (var s in M()) + { + Console.Write($"M:{s} "); + } + Console.Write("MainDone"); + } + public static async IAsyncEnumerable M() + { + await foreach (ref var s in new C()) + { + s.F++; + yield return s.ToString(); + } + yield return "Done"; + } + public Enumerator GetAsyncEnumerator() => new Enumerator(); + public sealed class Enumerator + { + S _current; + public ref S Current => ref _current; + public async Task MoveNextAsync() + { + Current = new S(Current.F + 1); + await Task.Yield(); + return Current.F < 4; + } + } + } + public struct S + { + public int F; + public S(int i) + { + this.F = i; + } + public override string ToString() => F.ToString(); + } + """ + AsyncStreamsTypes; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (16,32): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (ref var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "s").WithArguments("ref and unsafe in async and iterator methods").WithLocation(16, 32)); + + var expectedOutput = "M:2 M:4 M:Done MainDone"; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefReturningCurrent_AsyncIterator_RefVariable_02() + { + string source = """ + using System.Collections.Generic; + using System.Threading.Tasks; + public class C + { + public static async IAsyncEnumerable M() + { + await foreach (ref var s in new C()) + { + yield return s.ToString(); + s.F++; + } + yield return "Done"; + } + public Enumerator GetAsyncEnumerator() => new Enumerator(); + public sealed class Enumerator + { + public ref S Current => throw null; + public Task MoveNextAsync() => throw null; + } + } + public struct S + { + public int F; + } + """ + AsyncStreamsTypes; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,32): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (ref var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "s").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 32)); + + var expectedDiagnostics = new[] + { + // (10,13): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // s.F++; + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "s.F").WithLocation(10, 13) + }; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void TestWithPattern_RefReturningCurrent_Iterator_RefVariable_01() + { + string source = """ + using System; + using System.Collections.Generic; + public class C + { + public static void Main() + { + foreach (var s in M()) + { + Console.Write($"M:{s} "); + } + Console.Write("MainDone"); + } + public static IEnumerable M() + { + foreach (ref var s in new C()) + { + s.F++; + yield return s.ToString(); + } + yield return "Done"; + } + public Enumerator GetEnumerator() => new Enumerator(); + public sealed class Enumerator + { + S _current; + public ref S Current => ref _current; + public bool MoveNext() + { + Current = new S(Current.F + 1); + return Current.F < 4; + } + } + } + public struct S + { + public int F; + public S(int i) + { + this.F = i; + } + public override string ToString() => F.ToString(); + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (15,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "s").WithArguments("ref and unsafe in async and iterator methods").WithLocation(15, 26)); + + var expectedOutput = "M:2 M:4 M:Done MainDone"; + + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void TestWithPattern_RefReturningCurrent_Iterator_RefVariable_02() + { + string source = """ + using System.Collections.Generic; + public class C + { + public static IEnumerable M() + { + foreach (ref var s in new C()) + { + yield return s.ToString(); + s.F++; + } + yield return "Done"; + } + public Enumerator GetEnumerator() => new Enumerator(); + public sealed class Enumerator + { + public ref S Current => throw null; + public bool MoveNext() => throw null; + } + } + public struct S + { + public int F; + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "s").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 26)); + + var expectedDiagnostics = new[] + { + // (9,13): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // s.F++; + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "s.F").WithLocation(9, 13) + }; + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + [Fact] public void TestWithPattern_IterationVariableIsReadOnly() { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitUsingTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitUsingTests.cs index c388178fb6771..7282e99ed475f 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitUsingTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitUsingTests.cs @@ -3084,5 +3084,440 @@ public void Dispose() comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "DISPOSED"); } + + [Fact] + public void RefStruct_AwaitInside() + { + var source = """ + using System.Threading.Tasks; + class C + { + async Task M() + { + using (new R()) + { + await Task.Yield(); + } + } + } + ref struct R + { + public void Dispose() { } + } + """; + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,16): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // using (new R()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new R()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 16)); + + var expectedDiagnostics = new[] + { + // (6,16): error CS4007: Instance of type 'R' cannot be preserved across 'await' or 'yield' boundary. + // using (new R()) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new R()").WithArguments("R").WithLocation(6, 16) + }; + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_YieldReturnInside() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable M() + { + using (new R()) + { + yield return 1; + } + } + } + ref struct R + { + public void Dispose() { } + } + """; + + var expectedDiagnostics = new[] + { + // (6,16): error CS4007: Instance of type 'R' cannot be preserved across 'await' or 'yield' boundary. + // using (new R()) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new R()").WithArguments("R").WithLocation(6, 16) + }; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_YieldBreakInside() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var x in M(true)) { Console.Write(x); } + Console.Write(" "); + foreach (var x in M(false)) { Console.Write(x); } + } + static IEnumerable M(bool b) + { + yield return 123; + using (new R()) + { + if (b) { yield break; } + } + yield return 456; + } + } + ref struct R + { + public R() => Console.Write("C"); + public void Dispose() => Console.Write("D"); + } + """; + + var expectedOutput = "123CD 123CD456"; + + CompileAndVerify(source, expectedOutput: expectedOutput, parseOptions: TestOptions.Regular12).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_AwaitResource() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + Console.Write("1"); + using ((await GetC()).GetR()) + { + Console.Write("2"); + } + Console.Write("3"); + } + static async Task GetC() + { + Console.Write("Ga"); + await Task.Yield(); + Console.Write("Gb"); + return new C(); + } + R GetR() => new R(); + } + ref struct R + { + public R() => Console.Write("C"); + public void Dispose() => Console.Write("D"); + } + """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,16): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // using ((await GetC()).GetR()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "(await GetC()).GetR()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 16)); + + var expectedOutput = "1GaGbC2D3"; + + CompileAndVerify(source, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, verify: Verification.FailsILVerify).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_AwaitOutside() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + Console.Write("1"); + await Task.Yield(); + Console.Write("2"); + using (new R()) + { + Console.Write("3"); + } + Console.Write("4"); + await Task.Yield(); + Console.Write("5"); + } + } + ref struct R + { + public R() => Console.Write("C"); + public void Dispose() => Console.Write("D"); + } + """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (10,16): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // using (new R()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new R()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 16)); + + var expectedOutput = "12C3D45"; + + CompileAndVerify(source, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_YieldReturnOutside() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var x in M()) + { + Console.Write(x); + } + } + static IEnumerable M() + { + Console.Write("1"); + yield return "a"; + Console.Write("2"); + using (new R()) + { + Console.Write("3"); + } + Console.Write("4"); + yield return "b"; + Console.Write("5"); + } + } + ref struct R + { + public R() => Console.Write("C"); + public void Dispose() => Console.Write("D"); + } + """; + + var expectedOutput = "1a2C3D4b5"; + + CompileAndVerify(source, expectedOutput: expectedOutput, parseOptions: TestOptions.Regular12).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_AwaitUsing() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + Console.Write("1"); + await using (new R()) + { + Console.Write("2"); + } + Console.Write("3"); + } + } + ref struct R + { + public R() => Console.Write("C"); + public ValueTask DisposeAsync() + { + Console.Write("D"); + return default; + } + } + """; + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await using (new R()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new R()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 22)); + + var expectedOutput = "1C2D3"; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_AwaitUsing_AwaitInside() + { + var source = """ + using System.Threading.Tasks; + class C + { + async Task M() + { + await using (new R()) + { + await Task.Yield(); + } + } + } + ref struct R + { + public ValueTask DisposeAsync() => default; + } + """; + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await using (new R()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new R()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 22)); + + var expectedDiagnostics = new[] + { + // (6,22): error CS4007: Instance of type 'R' cannot be preserved across 'await' or 'yield' boundary. + // await using (new R()) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new R()").WithArguments("R").WithLocation(6, 22) + }; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_AwaitUsing_YieldReturnInside() + { + var source = """ + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + async IAsyncEnumerable M() + { + await using (new R()) + { + yield return 123; + } + } + } + ref struct R + { + public ValueTask DisposeAsync() => default; + } + """ + AsyncStreamsTypes; + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await using (new R()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new R()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 22)); + + var expectedDiagnostics = new[] + { + // (7,22): error CS4007: Instance of type 'R' cannot be preserved across 'await' or 'yield' boundary. + // await using (new R()) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new R()").WithArguments("R").WithLocation(7, 22) + }; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_AwaitUsing_YieldReturnInside_Var() + { + var source = """ + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + async IAsyncEnumerable M() + { + await using var _ = new R(); + yield return 123; + } + } + ref struct R + { + public ValueTask DisposeAsync() => default; + } + """ + AsyncStreamsTypes; + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,21): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await using var _ = new R(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 21)); + + var expectedDiagnostics = new[] + { + // (7,25): error CS4007: Instance of type 'R' cannot be preserved across 'await' or 'yield' boundary. + // await using var _ = new R(); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "_ = new R()").WithArguments("R").WithLocation(7, 25) + }; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_AwaitUsing_YieldBreakInside() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var x in M(true)) { Console.Write(x); } + Console.Write(" "); + await foreach (var x in M(false)) { Console.Write(x); } + } + static async IAsyncEnumerable M(bool b) + { + yield return 1; + await using (new R()) + { + if (b) { yield break; } + } + yield return 2; + } + } + ref struct R + { + public R() => Console.Write("C"); + public ValueTask DisposeAsync() + { + Console.Write("D"); + return default; + } + } + """ + AsyncStreamsTypes; + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (15,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await using (new R()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new R()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(15, 22)); + + var expectedOutput = "1CD 1CD2"; + + var comp = CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.RegularNext, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + } } } diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs index 028ff1e8ff7d4..d2f3bf455c812 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs @@ -5463,7 +5463,10 @@ static IEnumerable F() var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); - v0.VerifyDiagnostics(); + v0.VerifyDiagnostics( + // (17,34): warning CS9237: 'yield return' should not be used in the body of a lock statement + // yield return 1; + Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(17, 34)); var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); var f0 = compilation0.GetMember("C.F"); diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs index 4760ca1c2c254..458de9f14813a 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/NumericIntPtrTests.cs @@ -1359,20 +1359,44 @@ static IEnumerable F() yield return sizeof(System.UIntPtr); } }"; - var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.Net70); - comp.VerifyDiagnostics( - // (6,22): error CS1629: Unsafe code may not appear in iterators + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + var expectedDiagnostics = new[] + { + // (6,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // yield return sizeof(nint); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(nint)").WithLocation(6, 22), - // (7,22): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 22), + // (7,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // yield return sizeof(nuint); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(nuint)").WithLocation(7, 22), - // (8,22): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nuint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 22), + // (8,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // yield return sizeof(System.IntPtr); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(System.IntPtr)").WithLocation(8, 22), - // (9,22): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(System.IntPtr)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 22), + // (9,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // yield return sizeof(System.UIntPtr); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(System.UIntPtr)").WithLocation(9, 22)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(System.UIntPtr)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 22) + }; + + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); + + expectedDiagnostics = new[] + { + // (6,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 22), + // (7,22): error CS0233: 'nuint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nuint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nuint)").WithArguments("nuint").WithLocation(7, 22), + // (8,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(System.IntPtr); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(System.IntPtr)").WithArguments("nint").WithLocation(8, 22), + // (9,22): error CS0233: 'nuint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(System.UIntPtr); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(System.UIntPtr)").WithArguments("nuint").WithLocation(9, 22) + }; + + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, targetFramework: TargetFramework.Net70).VerifyDiagnostics(expectedDiagnostics); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/InlineArrayTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/InlineArrayTests.cs index 9b88f1fb7d741..0dd97b08e44a8 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/InlineArrayTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/InlineArrayTests.cs @@ -4691,9 +4691,12 @@ static async Task FromResult(T r) "; var comp = CreateCompilation(src + Buffer10Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( - // (24,22): error CS4007: 'await' cannot be used in an expression containing the type 'System.ReadOnlySpan>' - // [Get01()][await FromResult(Get02(x))]; - Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await FromResult(Get02(x))").WithArguments("System.ReadOnlySpan>").WithLocation(24, 22) + // (20,12): error CS4007: Instance of type 'System.ReadOnlySpan>' cannot be preserved across 'await' or 'yield' boundary. + // => MemoryMarshal.CreateReadOnlySpan( + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"MemoryMarshal.CreateReadOnlySpan( + ref Unsafe.As>, Buffer10>( + ref Unsafe.AsRef(in GetC(x).F)), + 10)").WithArguments("System.ReadOnlySpan>").WithLocation(20, 12) ); } @@ -4743,9 +4746,12 @@ static async Task FromResult(T r) "; var comp = CreateCompilation(src + Buffer10Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( - // (24,13): error CS4007: 'await' cannot be used in an expression containing the type 'System.ReadOnlySpan' - // [await FromResult(Get02(x))]; - Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await FromResult(Get02(x))").WithArguments("System.ReadOnlySpan").WithLocation(24, 13) + // (20,12): error CS4007: Instance of type 'System.ReadOnlySpan' cannot be preserved across 'await' or 'yield' boundary. + // => MemoryMarshal.CreateReadOnlySpan( + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"MemoryMarshal.CreateReadOnlySpan( + ref Unsafe.As, int>( + ref Unsafe.AsRef(in GetC(x).F[Get01()])), + 10)").WithArguments("System.ReadOnlySpan").WithLocation(20, 12) ); } @@ -20136,30 +20142,45 @@ .locals init (int V_0, CompileAndVerify(comp, expectedOutput: " 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); } - [Fact] + [ConditionalFact(typeof(CoreClrOnly))] public void Foreach_InAsync_03() { var src = @" class Program { - static async void Test() + static Buffer4 s_buffer; + + static async System.Threading.Tasks.Task Main() { + s_buffer[1] = 3; + foreach (ref int y in GetBuffer()) { + y *= y; + System.Console.Write(y); } await System.Threading.Tasks.Task.Yield(); + + System.Console.Write(s_buffer[1]); } - static ref Buffer4 GetBuffer() => throw null; + static ref Buffer4 GetBuffer() => ref s_buffer; } -"; - var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseDll); - comp.VerifyDiagnostics( - // (6,26): error CS8177: Async methods cannot have by-reference locals +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (10,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // foreach (ref int y in GetBuffer()) - Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "y").WithLocation(6, 26) - ); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 26)); + + var expectedOutput = "09009"; + + CompileAndVerify(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput).VerifyDiagnostics(); + + CompileAndVerify(src, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput).VerifyDiagnostics(); } [Fact] @@ -20580,30 +20601,48 @@ .locals init (int V_0, CompileAndVerify(comp, expectedOutput: " 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); } - [Fact] + [ConditionalFact(typeof(CoreClrOnly))] public void Foreach_InAsync_07() { var src = @" class Program { - static async void Test() + static Buffer4 s_buffer; + + static async System.Threading.Tasks.Task Main() { + s_buffer[1] = 3; + + int i = 0; foreach (ref readonly int y in GetBuffer()) { + System.Console.Write(y); + s_buffer[i++]++; + System.Console.Write(y); + System.Console.Write(' '); } await System.Threading.Tasks.Task.Yield(); + + System.Console.Write(s_buffer[1]); } - static ref readonly Buffer4 GetBuffer() => throw null; + static ref readonly Buffer4 GetBuffer() => ref s_buffer; } -"; - var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseDll); - comp.VerifyDiagnostics( - // (6,35): error CS8177: Async methods cannot have by-reference locals +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (11,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // foreach (ref readonly int y in GetBuffer()) - Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "y").WithLocation(6, 35) - ); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 35)); + + var expectedOutput = "01 34 01 01 4"; + + CompileAndVerify(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe, + verify: Verification.FailsILVerify, expectedOutput: expectedOutput).VerifyDiagnostics(); + + CompileAndVerify(src, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe, + verify: Verification.FailsILVerify, expectedOutput: expectedOutput).VerifyDiagnostics(); } [Fact] @@ -20780,132 +20819,209 @@ .locals init (int V_0, } [ConditionalFact(typeof(CoreClrOnly))] - public void Foreach_InIterator_01() + public void Foreach_InAsync_10() { var src = @" class Program { - static private Buffer4 F = default; - private static int index = 0; + static Buffer4 s_buffer; - static void Main() + static async System.Threading.Tasks.Task Main() { - foreach (var a in Test()) - {} + s_buffer[1] = 3; + + ref Buffer4 buffer = ref GetBuffer(); + foreach (ref int y in buffer) + { + y *= y; + System.Console.Write(y); + } + + await System.Threading.Tasks.Task.Yield(); + + System.Console.Write(s_buffer[1]); } - static System.Collections.Generic.IEnumerable Test() + static ref Buffer4 GetBuffer() => ref s_buffer; +} +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (10,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref Buffer4 buffer = ref GetBuffer(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "buffer").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 26), + // (11,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref int y in buffer) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 26)); + + var expectedOutput = "09009"; + + CompileAndVerify(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput).VerifyDiagnostics(); + + CompileAndVerify(src, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void Foreach_InAsync_11() + { + var src = @" +class Program +{ + static Buffer4 s_buffer; + + static async System.Threading.Tasks.Task Main() { - yield return -1; + s_buffer[1] = 3; - foreach (var y in GetBuffer()) + foreach (ref int y in GetBuffer()) { - Increment(); - System.Console.Write(' '); + await System.Threading.Tasks.Task.Yield(); + y *= y; System.Console.Write(y); } - yield return -2; - } + await System.Threading.Tasks.Task.Yield(); - static ref Buffer4 GetBuffer() - { - System.Console.Write(-1); - return ref F; + System.Console.Write(s_buffer[1]); } - static void Increment() + static ref Buffer4 GetBuffer() => ref s_buffer; +} +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (10,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 26)); + + var expectedDiagnostics = new[] + { + // (13,13): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // y *= y; + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(13, 13), + // (13,18): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // y *= y; + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(13, 18), + // (14,34): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(14, 34) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Foreach_InAsync_12() + { + var src = @" +class Program +{ + static Buffer4 s_buffer; + + static async System.Threading.Tasks.Task Main() { - index++; + s_buffer[1] = 3; - if (index < 4) + foreach (ref int y in GetBuffer()) { - F[index] = index; + y *= y; + System.Console.Write(y); + await System.Threading.Tasks.Task.Yield(); } + + await System.Threading.Tasks.Task.Yield(); + + System.Console.Write(s_buffer[1]); } + + static ref Buffer4 GetBuffer() => ref s_buffer; } -"; - var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); - var verifier = CompileAndVerify(comp, expectedOutput: "-1 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); +" + Buffer4Definition; - verifier.VerifyIL("Program.d__3.System.Collections.IEnumerator.MoveNext", -@" + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (10,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 26)); + + var expectedDiagnostics = new[] + { + // (10,9): error CS8178: A reference returned by a call to 'Program.GetBuffer()' cannot be preserved across 'await' or 'yield' boundary. + // foreach (ref int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, @"foreach (ref int y in GetBuffer()) + { + y *= y; + System.Console.Write(y); + await System.Threading.Tasks.Task.Yield(); + }").WithArguments("Program.GetBuffer()").WithLocation(10, 9) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Foreach_InAsync_13() + { + var src = @" +class Program { - // Code size 126 (0x7e) - .maxstack 2 - .locals init (int V_0, - Buffer4& V_1, - int V_2) - IL_0000: ldarg.0 - IL_0001: ldfld ""int Program.d__3.<>1__state"" - IL_0006: stloc.0 - IL_0007: ldloc.0 - IL_0008: switch ( - IL_001b, - IL_0032, - IL_0075) - IL_0019: ldc.i4.0 - IL_001a: ret - IL_001b: ldarg.0 - IL_001c: ldc.i4.m1 - IL_001d: stfld ""int Program.d__3.<>1__state"" - IL_0022: ldarg.0 - IL_0023: ldc.i4.m1 - IL_0024: stfld ""int Program.d__3.<>2__current"" - IL_0029: ldarg.0 - IL_002a: ldc.i4.1 - IL_002b: stfld ""int Program.d__3.<>1__state"" - IL_0030: ldc.i4.1 - IL_0031: ret - IL_0032: ldarg.0 - IL_0033: ldc.i4.m1 - IL_0034: stfld ""int Program.d__3.<>1__state"" - IL_0039: call ""ref Buffer4 Program.GetBuffer()"" - IL_003e: stloc.1 - IL_003f: ldc.i4.0 - IL_0040: stloc.2 - IL_0041: br.s IL_0060 - IL_0043: ldloc.1 - IL_0044: ldloc.2 - IL_0045: call ""ref int .InlineArrayElementRef, int>(ref Buffer4, int)"" - IL_004a: ldind.i4 - IL_004b: call ""void Program.Increment()"" - IL_0050: ldc.i4.s 32 - IL_0052: call ""void System.Console.Write(char)"" - IL_0057: call ""void System.Console.Write(int)"" - IL_005c: ldloc.2 - IL_005d: ldc.i4.1 - IL_005e: add - IL_005f: stloc.2 - IL_0060: ldloc.2 - IL_0061: ldc.i4.4 - IL_0062: blt.s IL_0043 - IL_0064: ldarg.0 - IL_0065: ldc.i4.s -2 - IL_0067: stfld ""int Program.d__3.<>2__current"" - IL_006c: ldarg.0 - IL_006d: ldc.i4.2 - IL_006e: stfld ""int Program.d__3.<>1__state"" - IL_0073: ldc.i4.1 - IL_0074: ret - IL_0075: ldarg.0 - IL_0076: ldc.i4.m1 - IL_0077: stfld ""int Program.d__3.<>1__state"" - IL_007c: ldc.i4.0 - IL_007d: ret + static Buffer4 s_buffer; + + static async System.Threading.Tasks.Task Main() + { + s_buffer[1] = 3; + + ref Buffer4 buffer = ref GetBuffer(); + foreach (ref int y in buffer) + { + y *= y; + System.Console.Write(y); + await System.Threading.Tasks.Task.Yield(); + } + + await System.Threading.Tasks.Task.Yield(); + + System.Console.Write(s_buffer[1]); + } + + static ref Buffer4 GetBuffer() => ref s_buffer; } -"); - comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: "-1 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (10,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref Buffer4 buffer = ref GetBuffer(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "buffer").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 26), + // (11,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref int y in buffer) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 26)); + + var expectedDiagnostics = new[] + { + // (11,31): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // foreach (ref int y in buffer) + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "buffer").WithLocation(11, 31) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); } - [ConditionalFact(typeof(CoreClrOnly))] - public void Foreach_InIterator_02() + [Fact] + public void Foreach_InAsync_14() { var src = @" +using System.Threading.Tasks; + class C { - public Buffer4 F = default; + public readonly Buffer4 F = default; } class Program @@ -20915,19 +21031,20 @@ class Program static void Main() { - foreach (var a in Test(c)) - {} + Test(c).Wait(); } - static System.Collections.Generic.IEnumerable Test(C x) + static async Task Test(C x) { - foreach (var y in x.F) + ref readonly Buffer4 f = ref x.F; + foreach (var y in f) { Increment(); System.Console.Write(' '); System.Console.Write(y); - yield return -1; + await Task.Yield(); + await Task.Delay(2); } } @@ -20937,146 +21054,266 @@ static void Increment() if (index < 4) { - c.F[index] = index; + System.Runtime.CompilerServices.Unsafe.AsRef(in c.F)[index] = index; } } } -"; - var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); - var verifier = CompileAndVerify(comp, expectedOutput: " 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); +" + Buffer4Definition; - verifier.VerifyIL("Program.d__3.System.Collections.IEnumerator.MoveNext", -@" + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (21,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref readonly Buffer4 f = ref x.F; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "f").WithArguments("ref and unsafe in async and iterator methods").WithLocation(21, 35)); + + var expectedDiagnostics = new[] + { + // (22,27): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // foreach (var y in f) + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "f").WithLocation(22, 27) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Foreach_InAsync_15() + { + var src = @" +class Program { - // Code size 151 (0x97) - .maxstack 3 - .locals init (int V_0) - IL_0000: ldarg.0 - IL_0001: ldfld ""int Program.d__3.<>1__state"" - IL_0006: stloc.0 - IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0010 - IL_000a: ldloc.0 - IL_000b: ldc.i4.1 - IL_000c: beq.s IL_0070 - IL_000e: ldc.i4.0 - IL_000f: ret - IL_0010: ldarg.0 - IL_0011: ldc.i4.m1 - IL_0012: stfld ""int Program.d__3.<>1__state"" - IL_0017: ldarg.0 - IL_0018: ldarg.0 - IL_0019: ldfld ""C Program.d__3.x"" - IL_001e: stfld ""C Program.d__3.<>7__wrap2"" - IL_0023: ldarg.0 - IL_0024: ldfld ""C Program.d__3.<>7__wrap2"" - IL_0029: ldfld ""Buffer4 C.F"" - IL_002e: pop - IL_002f: ldarg.0 - IL_0030: ldc.i4.0 - IL_0031: stfld ""int Program.d__3.<>7__wrap1"" - IL_0036: br.s IL_0085 - IL_0038: ldarg.0 - IL_0039: ldfld ""C Program.d__3.<>7__wrap2"" - IL_003e: ldflda ""Buffer4 C.F"" - IL_0043: ldarg.0 - IL_0044: ldfld ""int Program.d__3.<>7__wrap1"" - IL_0049: call ""ref int .InlineArrayElementRef, int>(ref Buffer4, int)"" - IL_004e: ldind.i4 - IL_004f: call ""void Program.Increment()"" - IL_0054: ldc.i4.s 32 - IL_0056: call ""void System.Console.Write(char)"" - IL_005b: call ""void System.Console.Write(int)"" - IL_0060: ldarg.0 - IL_0061: ldc.i4.m1 - IL_0062: stfld ""int Program.d__3.<>2__current"" - IL_0067: ldarg.0 - IL_0068: ldc.i4.1 - IL_0069: stfld ""int Program.d__3.<>1__state"" - IL_006e: ldc.i4.1 - IL_006f: ret - IL_0070: ldarg.0 - IL_0071: ldc.i4.m1 - IL_0072: stfld ""int Program.d__3.<>1__state"" - IL_0077: ldarg.0 - IL_0078: ldarg.0 - IL_0079: ldfld ""int Program.d__3.<>7__wrap1"" - IL_007e: ldc.i4.1 - IL_007f: add - IL_0080: stfld ""int Program.d__3.<>7__wrap1"" - IL_0085: ldarg.0 - IL_0086: ldfld ""int Program.d__3.<>7__wrap1"" - IL_008b: ldc.i4.4 - IL_008c: blt.s IL_0038 - IL_008e: ldarg.0 - IL_008f: ldnull - IL_0090: stfld ""C Program.d__3.<>7__wrap2"" - IL_0095: ldc.i4.0 - IL_0096: ret + static Buffer4 s_buffer; + + static async System.Threading.Tasks.Task Main() + { + foreach (ref readonly int y in GetBuffer()) + { + System.Console.Write(y); + await System.Threading.Tasks.Task.Yield(); + } + + await System.Threading.Tasks.Task.Yield(); + } + + static ref readonly Buffer4 GetBuffer() => ref s_buffer; } -"); - comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: " 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (8,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref readonly int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 35)); + + var expectedDiagnostics = new[] + { + // (8,9): error CS8178: A reference returned by a call to 'Program.GetBuffer()' cannot be preserved across 'await' or 'yield' boundary. + // foreach (ref readonly int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, @"foreach (ref readonly int y in GetBuffer()) + { + System.Console.Write(y); + await System.Threading.Tasks.Task.Yield(); + }").WithArguments("Program.GetBuffer()").WithLocation(8, 9) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] - public void Foreach_InIterator_03() + public void Foreach_InAsync_16() { var src = @" class Program { - static System.Collections.Generic.IEnumerable Test() + static Buffer4 s_buffer; + + static async System.Threading.Tasks.Task Main() { - foreach (ref int y in GetBuffer()) + foreach (ref readonly int y in GetBuffer()) { + await System.Threading.Tasks.Task.Yield(); + System.Console.Write(y); } - yield return -1; + await System.Threading.Tasks.Task.Yield(); } - static ref Buffer4 GetBuffer() => throw null; + static ref readonly Buffer4 GetBuffer() => ref s_buffer; } -"; - var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseDll); - comp.VerifyDiagnostics( - // (6,26): error CS8176: Iterators cannot have by-reference locals - // foreach (ref int y in GetBuffer()) - Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "y").WithLocation(6, 26) - ); +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (8,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref readonly int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 35)); + + var expectedDiagnostics = new[] + { + // (11,34): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(11, 34) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void Foreach_InAsync_17() + { + var src = @" +using System.Threading.Tasks; + +class C +{ + public readonly Buffer4 F = default; +} + +class Program +{ + private static C c = new C(); + private static int index = 0; + + static void Main() + { + Test(c).Wait(); + } + + static async Task Test(C x) + { + foreach (ref readonly int y in x.F) + { + Increment(); + System.Console.Write(' '); + System.Console.Write(y); + + await Task.Yield(); + await Task.Delay(2); + } + } + + static void Increment() + { + index++; + + if (index < 4) + { + System.Runtime.CompilerServices.Unsafe.AsRef(in c.F)[index] = index; + } + } +} +" + Buffer4Definition; + var expectedOutput = " 0 1 2 3"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyDiagnostics(); + comp = CreateCompilation(src, targetFramework: TargetFramework.Net80, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyDiagnostics(); } [Fact] - public void Foreach_InIterator_04() + public void Foreach_InAsync_18() { var src = @" +using System.Threading.Tasks; + +class C +{ + public readonly Buffer4 F = default; +} + class Program { - static System.Collections.Generic.IEnumerable Test() + static async Task Test(C x) { - foreach (int y in GetBuffer()) + foreach (ref readonly int y in x.F) { - yield return -1; + await Task.Yield(); + System.Console.Write(y); } } +} +" + Buffer4Definition; - static ref Buffer4 GetBuffer() => throw null; + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (13,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref readonly int y in x.F) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(13, 35)); + + var expectedDiagnostics = new[] + { + // (16,34): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(16, 34) + }; + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Foreach_InAsync_19() + { + var src = @" +using System.Threading.Tasks; + +class C +{ + public readonly Buffer4 F = default; } -"; - var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseDll); - comp.VerifyEmitDiagnostics( - // (6,9): error CS8178: A reference returned by a call to 'Program.GetBuffer()' cannot be preserved across 'await' or 'yield' boundary. - // foreach (int y in GetBuffer()) - Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, - @"foreach (int y in GetBuffer()) +class Program +{ + static async Task Test(C x) + { + ref readonly Buffer4 f = ref x.F; + + foreach (var i in f) System.Console.Write(i); + + foreach (var y in f) { - yield return -1; - }").WithArguments("Program.GetBuffer()").WithLocation(6, 9) - ); + System.Console.Write(y); + await Task.Yield(); + } + + foreach (var j in f) System.Console.Write(j); + + foreach (var z in f) + { + System.Console.Write(z); + await Task.Yield(); + } + } +} +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (13,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref readonly Buffer4 f = ref x.F; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "f").WithArguments("ref and unsafe in async and iterator methods").WithLocation(13, 35)); + + var expectedDiagnostics = new[] + { + // (17,27): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // foreach (var y in f) + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "f").WithLocation(17, 27), + // (23,27): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // foreach (var j in f) System.Console.Write(j); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "f").WithLocation(23, 27), + // (25,27): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // foreach (var z in f) + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "f").WithLocation(25, 27) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); } [ConditionalFact(typeof(CoreClrOnly))] - public void Foreach_InIterator_05() + public void Foreach_InIterator_01() { var src = @" class Program @@ -21104,7 +21341,7 @@ static System.Collections.Generic.IEnumerable Test() yield return -2; } - static ref readonly Buffer4 GetBuffer() + static ref Buffer4 GetBuffer() { System.Console.Write(-1); return ref F; @@ -21156,14 +21393,14 @@ .locals init (int V_0, IL_0032: ldarg.0 IL_0033: ldc.i4.m1 IL_0034: stfld ""int Program.d__3.<>1__state"" - IL_0039: call ""ref readonly Buffer4 Program.GetBuffer()"" + IL_0039: call ""ref Buffer4 Program.GetBuffer()"" IL_003e: stloc.1 IL_003f: ldc.i4.0 IL_0040: stloc.2 IL_0041: br.s IL_0060 IL_0043: ldloc.1 IL_0044: ldloc.2 - IL_0045: call ""ref readonly int .InlineArrayElementRefReadOnly, int>(in Buffer4, int)"" + IL_0045: call ""ref int .InlineArrayElementRef, int>(ref Buffer4, int)"" IL_004a: ldind.i4 IL_004b: call ""void Program.Increment()"" IL_0050: ldc.i4.s 32 @@ -21190,13 +21427,1009 @@ .locals init (int V_0, IL_007c: ldc.i4.0 IL_007d: ret } -"); - comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: "-1 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); +"); + comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "-1 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void Foreach_InIterator_02() + { + var src = @" +class C +{ + public Buffer4 F = default; +} + +class Program +{ + private static C c = new C(); + private static int index = 0; + + static void Main() + { + foreach (var a in Test(c)) + {} + } + + static System.Collections.Generic.IEnumerable Test(C x) + { + foreach (var y in x.F) + { + Increment(); + System.Console.Write(' '); + System.Console.Write(y); + + yield return -1; + } + } + + static void Increment() + { + index++; + + if (index < 4) + { + c.F[index] = index; + } + } +} +"; + var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, expectedOutput: " 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); + + verifier.VerifyIL("Program.d__3.System.Collections.IEnumerator.MoveNext", +@" +{ + // Code size 151 (0x97) + .maxstack 3 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""int Program.d__3.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0010 + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: beq.s IL_0070 + IL_000e: ldc.i4.0 + IL_000f: ret + IL_0010: ldarg.0 + IL_0011: ldc.i4.m1 + IL_0012: stfld ""int Program.d__3.<>1__state"" + IL_0017: ldarg.0 + IL_0018: ldarg.0 + IL_0019: ldfld ""C Program.d__3.x"" + IL_001e: stfld ""C Program.d__3.<>7__wrap2"" + IL_0023: ldarg.0 + IL_0024: ldfld ""C Program.d__3.<>7__wrap2"" + IL_0029: ldfld ""Buffer4 C.F"" + IL_002e: pop + IL_002f: ldarg.0 + IL_0030: ldc.i4.0 + IL_0031: stfld ""int Program.d__3.<>7__wrap1"" + IL_0036: br.s IL_0085 + IL_0038: ldarg.0 + IL_0039: ldfld ""C Program.d__3.<>7__wrap2"" + IL_003e: ldflda ""Buffer4 C.F"" + IL_0043: ldarg.0 + IL_0044: ldfld ""int Program.d__3.<>7__wrap1"" + IL_0049: call ""ref int .InlineArrayElementRef, int>(ref Buffer4, int)"" + IL_004e: ldind.i4 + IL_004f: call ""void Program.Increment()"" + IL_0054: ldc.i4.s 32 + IL_0056: call ""void System.Console.Write(char)"" + IL_005b: call ""void System.Console.Write(int)"" + IL_0060: ldarg.0 + IL_0061: ldc.i4.m1 + IL_0062: stfld ""int Program.d__3.<>2__current"" + IL_0067: ldarg.0 + IL_0068: ldc.i4.1 + IL_0069: stfld ""int Program.d__3.<>1__state"" + IL_006e: ldc.i4.1 + IL_006f: ret + IL_0070: ldarg.0 + IL_0071: ldc.i4.m1 + IL_0072: stfld ""int Program.d__3.<>1__state"" + IL_0077: ldarg.0 + IL_0078: ldarg.0 + IL_0079: ldfld ""int Program.d__3.<>7__wrap1"" + IL_007e: ldc.i4.1 + IL_007f: add + IL_0080: stfld ""int Program.d__3.<>7__wrap1"" + IL_0085: ldarg.0 + IL_0086: ldfld ""int Program.d__3.<>7__wrap1"" + IL_008b: ldc.i4.4 + IL_008c: blt.s IL_0038 + IL_008e: ldarg.0 + IL_008f: ldnull + IL_0090: stfld ""C Program.d__3.<>7__wrap2"" + IL_0095: ldc.i4.0 + IL_0096: ret +} +"); + comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: " 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void Foreach_InIterator_03() + { + var src = @" +class Program +{ + static Buffer4 s_buffer; + + static void Main() + { + s_buffer[2] = 3; + + foreach (int x in Test()) + { + System.Console.Write(x); + } + } + + static System.Collections.Generic.IEnumerable Test() + { + foreach (ref int y in GetBuffer()) + { + y *= y; + System.Console.Write(y); + } + + yield return -1; + + System.Console.Write(s_buffer[2]); + } + + static ref Buffer4 GetBuffer() => ref s_buffer; +} +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (18,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(18, 26)); + + var expectedOutput = "0090-19"; + + CompileAndVerify(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput).VerifyDiagnostics(); + + CompileAndVerify(src, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void Foreach_InIterator_04() + { + var src = @" +class Program +{ + static System.Collections.Generic.IEnumerable Test() + { + foreach (int y in GetBuffer()) + { + yield return -1; + } + } + + static ref Buffer4 GetBuffer() => throw null; +} +"; + var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseDll); + + comp.VerifyEmitDiagnostics( + // (6,9): error CS8178: A reference returned by a call to 'Program.GetBuffer()' cannot be preserved across 'await' or 'yield' boundary. + // foreach (int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, + @"foreach (int y in GetBuffer()) + { + yield return -1; + }").WithArguments("Program.GetBuffer()").WithLocation(6, 9) + ); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void Foreach_InIterator_05() + { + var src = @" +class Program +{ + static private Buffer4 F = default; + private static int index = 0; + + static void Main() + { + foreach (var a in Test()) + {} + } + + static System.Collections.Generic.IEnumerable Test() + { + yield return -1; + + foreach (var y in GetBuffer()) + { + Increment(); + System.Console.Write(' '); + System.Console.Write(y); + } + + yield return -2; + } + + static ref readonly Buffer4 GetBuffer() + { + System.Console.Write(-1); + return ref F; + } + + static void Increment() + { + index++; + + if (index < 4) + { + F[index] = index; + } + } +} +"; + var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, expectedOutput: "-1 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); + + verifier.VerifyIL("Program.d__3.System.Collections.IEnumerator.MoveNext", +@" +{ + // Code size 126 (0x7e) + .maxstack 2 + .locals init (int V_0, + Buffer4& V_1, + int V_2) + IL_0000: ldarg.0 + IL_0001: ldfld ""int Program.d__3.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: switch ( + IL_001b, + IL_0032, + IL_0075) + IL_0019: ldc.i4.0 + IL_001a: ret + IL_001b: ldarg.0 + IL_001c: ldc.i4.m1 + IL_001d: stfld ""int Program.d__3.<>1__state"" + IL_0022: ldarg.0 + IL_0023: ldc.i4.m1 + IL_0024: stfld ""int Program.d__3.<>2__current"" + IL_0029: ldarg.0 + IL_002a: ldc.i4.1 + IL_002b: stfld ""int Program.d__3.<>1__state"" + IL_0030: ldc.i4.1 + IL_0031: ret + IL_0032: ldarg.0 + IL_0033: ldc.i4.m1 + IL_0034: stfld ""int Program.d__3.<>1__state"" + IL_0039: call ""ref readonly Buffer4 Program.GetBuffer()"" + IL_003e: stloc.1 + IL_003f: ldc.i4.0 + IL_0040: stloc.2 + IL_0041: br.s IL_0060 + IL_0043: ldloc.1 + IL_0044: ldloc.2 + IL_0045: call ""ref readonly int .InlineArrayElementRefReadOnly, int>(in Buffer4, int)"" + IL_004a: ldind.i4 + IL_004b: call ""void Program.Increment()"" + IL_0050: ldc.i4.s 32 + IL_0052: call ""void System.Console.Write(char)"" + IL_0057: call ""void System.Console.Write(int)"" + IL_005c: ldloc.2 + IL_005d: ldc.i4.1 + IL_005e: add + IL_005f: stloc.2 + IL_0060: ldloc.2 + IL_0061: ldc.i4.4 + IL_0062: blt.s IL_0043 + IL_0064: ldarg.0 + IL_0065: ldc.i4.s -2 + IL_0067: stfld ""int Program.d__3.<>2__current"" + IL_006c: ldarg.0 + IL_006d: ldc.i4.2 + IL_006e: stfld ""int Program.d__3.<>1__state"" + IL_0073: ldc.i4.1 + IL_0074: ret + IL_0075: ldarg.0 + IL_0076: ldc.i4.m1 + IL_0077: stfld ""int Program.d__3.<>1__state"" + IL_007c: ldc.i4.0 + IL_007d: ret +} +"); + comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "-1 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void Foreach_InIterator_06() + { + var src = @" +class C +{ + public readonly Buffer4 F = default; +} + +class Program +{ + private static C c = new C(); + private static int index = 0; + + static void Main() + { + foreach (var a in Test(c)) + {} + } + + static System.Collections.Generic.IEnumerable Test(C x) + { + foreach (var y in x.F) + { + Increment(); + System.Console.Write(' '); + System.Console.Write(y); + + yield return -1; + } + } + + static void Increment() + { + index++; + + if (index < 4) + { + System.Runtime.CompilerServices.Unsafe.AsRef(in c.F)[index] = index; + } + } +} +"; + var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, expectedOutput: " 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); + + verifier.VerifyIL("Program.d__3.System.Collections.IEnumerator.MoveNext", +@" +{ + // Code size 151 (0x97) + .maxstack 3 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""int Program.d__3.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0010 + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: beq.s IL_0070 + IL_000e: ldc.i4.0 + IL_000f: ret + IL_0010: ldarg.0 + IL_0011: ldc.i4.m1 + IL_0012: stfld ""int Program.d__3.<>1__state"" + IL_0017: ldarg.0 + IL_0018: ldarg.0 + IL_0019: ldfld ""C Program.d__3.x"" + IL_001e: stfld ""C Program.d__3.<>7__wrap2"" + IL_0023: ldarg.0 + IL_0024: ldfld ""C Program.d__3.<>7__wrap2"" + IL_0029: ldfld ""Buffer4 C.F"" + IL_002e: pop + IL_002f: ldarg.0 + IL_0030: ldc.i4.0 + IL_0031: stfld ""int Program.d__3.<>7__wrap1"" + IL_0036: br.s IL_0085 + IL_0038: ldarg.0 + IL_0039: ldfld ""C Program.d__3.<>7__wrap2"" + IL_003e: ldflda ""Buffer4 C.F"" + IL_0043: ldarg.0 + IL_0044: ldfld ""int Program.d__3.<>7__wrap1"" + IL_0049: call ""ref readonly int .InlineArrayElementRefReadOnly, int>(in Buffer4, int)"" + IL_004e: ldind.i4 + IL_004f: call ""void Program.Increment()"" + IL_0054: ldc.i4.s 32 + IL_0056: call ""void System.Console.Write(char)"" + IL_005b: call ""void System.Console.Write(int)"" + IL_0060: ldarg.0 + IL_0061: ldc.i4.m1 + IL_0062: stfld ""int Program.d__3.<>2__current"" + IL_0067: ldarg.0 + IL_0068: ldc.i4.1 + IL_0069: stfld ""int Program.d__3.<>1__state"" + IL_006e: ldc.i4.1 + IL_006f: ret + IL_0070: ldarg.0 + IL_0071: ldc.i4.m1 + IL_0072: stfld ""int Program.d__3.<>1__state"" + IL_0077: ldarg.0 + IL_0078: ldarg.0 + IL_0079: ldfld ""int Program.d__3.<>7__wrap1"" + IL_007e: ldc.i4.1 + IL_007f: add + IL_0080: stfld ""int Program.d__3.<>7__wrap1"" + IL_0085: ldarg.0 + IL_0086: ldfld ""int Program.d__3.<>7__wrap1"" + IL_008b: ldc.i4.4 + IL_008c: blt.s IL_0038 + IL_008e: ldarg.0 + IL_008f: ldnull + IL_0090: stfld ""C Program.d__3.<>7__wrap2"" + IL_0095: ldc.i4.0 + IL_0096: ret +} +"); + comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: " 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void Foreach_InIterator_07() + { + var src = @" +class Program +{ + static Buffer4 s_buffer; + + static void Main() + { + s_buffer[2] = 3; + + foreach (int x in Test()) + { + System.Console.Write(x); + } + } + + static System.Collections.Generic.IEnumerable Test() + { + int i = 0; + foreach (ref readonly int y in GetBuffer()) + { + System.Console.Write(y); + s_buffer[i++]++; + System.Console.Write(y); + System.Console.Write(' '); + } + + yield return -1; + + System.Console.Write(s_buffer[2]); + } + + static ref readonly Buffer4 GetBuffer() => ref s_buffer; +} +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (19,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref readonly int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(19, 35)); + + var expectedOutput = "01 01 34 01 -14"; + + CompileAndVerify(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe, + verify: Verification.FailsILVerify, expectedOutput: expectedOutput).VerifyDiagnostics(); + + CompileAndVerify(src, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe, + verify: Verification.FailsILVerify, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void Foreach_InIterator_08() + { + var src = @" +class Program +{ + static System.Collections.Generic.IEnumerable Test() + { + foreach (int y in GetBuffer()) + { + yield return -1; + } + } + + static ref readonly Buffer4 GetBuffer() => throw null; +} +"; + var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseDll); + + comp.VerifyEmitDiagnostics( + // (6,9): error CS8178: A reference returned by a call to 'Program.GetBuffer()' cannot be preserved across 'await' or 'yield' boundary. + // foreach (int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, + @"foreach (int y in GetBuffer()) + { + yield return -1; + }").WithArguments("Program.GetBuffer()").WithLocation(6, 9) + ); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void Foreach_InIterator_09() + { + var src = @" +class Program +{ + static void Main() + { + foreach (var a in Test()) + {} + } + + static System.Collections.Generic.IEnumerable Test() + { + foreach (var y in GetBuffer()) + { + System.Console.Write(' '); + System.Console.Write(y); + yield return -1; + } + } + + static Buffer4 GetBuffer() + { + Buffer4 x = default; + x[0] = 111; + x[1] = 112; + x[2] = 113; + x[3] = 114; + + System.Console.Write(-1); + return x; + } +} +"; + var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, expectedOutput: "-1 111 112 113 114").VerifyDiagnostics(); + + verifier.VerifyIL("Program.d__1.System.Collections.IEnumerator.MoveNext", +@" +{ + // Code size 121 (0x79) + .maxstack 3 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""int Program.d__1.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0010 + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: beq.s IL_0059 + IL_000e: ldc.i4.0 + IL_000f: ret + IL_0010: ldarg.0 + IL_0011: ldc.i4.m1 + IL_0012: stfld ""int Program.d__1.<>1__state"" + IL_0017: ldarg.0 + IL_0018: call ""Buffer4 Program.GetBuffer()"" + IL_001d: stfld ""Buffer4 Program.d__1.<>7__wrap1"" + IL_0022: ldarg.0 + IL_0023: ldc.i4.0 + IL_0024: stfld ""int Program.d__1.<>7__wrap2"" + IL_0029: br.s IL_006e + IL_002b: ldarg.0 + IL_002c: ldflda ""Buffer4 Program.d__1.<>7__wrap1"" + IL_0031: ldarg.0 + IL_0032: ldfld ""int Program.d__1.<>7__wrap2"" + IL_0037: call ""ref readonly int .InlineArrayElementRefReadOnly, int>(in Buffer4, int)"" + IL_003c: ldind.i4 + IL_003d: ldc.i4.s 32 + IL_003f: call ""void System.Console.Write(char)"" + IL_0044: call ""void System.Console.Write(int)"" + IL_0049: ldarg.0 + IL_004a: ldc.i4.m1 + IL_004b: stfld ""int Program.d__1.<>2__current"" + IL_0050: ldarg.0 + IL_0051: ldc.i4.1 + IL_0052: stfld ""int Program.d__1.<>1__state"" + IL_0057: ldc.i4.1 + IL_0058: ret + IL_0059: ldarg.0 + IL_005a: ldc.i4.m1 + IL_005b: stfld ""int Program.d__1.<>1__state"" + IL_0060: ldarg.0 + IL_0061: ldarg.0 + IL_0062: ldfld ""int Program.d__1.<>7__wrap2"" + IL_0067: ldc.i4.1 + IL_0068: add + IL_0069: stfld ""int Program.d__1.<>7__wrap2"" + IL_006e: ldarg.0 + IL_006f: ldfld ""int Program.d__1.<>7__wrap2"" + IL_0074: ldc.i4.4 + IL_0075: blt.s IL_002b + IL_0077: ldc.i4.0 + IL_0078: ret +} +"); + comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: "-1 111 112 113 114").VerifyDiagnostics(); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void Foreach_InIterator_10() + { + var src = @" +class Program +{ + static Buffer4 s_buffer; + + static void Main() + { + s_buffer[2] = 3; + + foreach (int x in Test()) + { + System.Console.Write(x); + } + } + + static System.Collections.Generic.IEnumerable Test() + { + ref Buffer4 buffer = ref GetBuffer(); + foreach (ref int y in buffer) + { + y *= y; + System.Console.Write(y); + } + + yield return -1; + + System.Console.Write(s_buffer[2]); + } + + static ref Buffer4 GetBuffer() => ref s_buffer; +} +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (18,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref Buffer4 buffer = ref GetBuffer(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "buffer").WithArguments("ref and unsafe in async and iterator methods").WithLocation(18, 26), + // (19,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref int y in buffer) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(19, 26)); + + var expectedOutput = "0090-19"; + + CompileAndVerify(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput).VerifyDiagnostics(); + + CompileAndVerify(src, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void Foreach_InIterator_11() + { + var src = @" +class Program +{ + static Buffer4 s_buffer; + + static void Main() + { + s_buffer[2] = 3; + + foreach (int x in Test()) + { + System.Console.Write(x); + } + } + + static System.Collections.Generic.IEnumerable Test() + { + foreach (ref int y in GetBuffer()) + { + yield return 1; + y *= y; + System.Console.Write(y); + } + + yield return -1; + + System.Console.Write(s_buffer[2]); + } + + static ref Buffer4 GetBuffer() => ref s_buffer; +} +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (18,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(18, 26)); + + var expectedDiagnostics = new[] + { + // (21,13): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // y *= y; + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(21, 13), + // (21,18): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // y *= y; + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(21, 18), + // (22,34): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(22, 34) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Foreach_InIterator_12() + { + var src = @" +class Program +{ + static Buffer4 s_buffer; + + static void Main() + { + s_buffer[2] = 3; + + foreach (int x in Test()) + { + System.Console.Write(x); + } + } + + static System.Collections.Generic.IEnumerable Test() + { + foreach (ref int y in GetBuffer()) + { + y *= y; + System.Console.Write(y); + yield return 1; + } + + yield return -1; + + System.Console.Write(s_buffer[2]); + } + + static ref Buffer4 GetBuffer() => ref s_buffer; +} +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (18,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(18, 26)); + + var expectedDiagnostics = new[] + { + // (18,9): error CS8178: A reference returned by a call to 'Program.GetBuffer()' cannot be preserved across 'await' or 'yield' boundary. + // foreach (ref int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, @"foreach (ref int y in GetBuffer()) + { + y *= y; + System.Console.Write(y); + yield return 1; + }").WithArguments("Program.GetBuffer()").WithLocation(18, 9) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Foreach_InIterator_13() + { + var src = @" +class Program +{ + static Buffer4 s_buffer; + + static void Main() + { + s_buffer[2] = 3; + + foreach (int x in Test()) + { + System.Console.Write(x); + } + } + + static System.Collections.Generic.IEnumerable Test() + { + ref Buffer4 buffer = ref GetBuffer(); + foreach (ref int y in buffer) + { + y *= y; + System.Console.Write(y); + yield return 1; + } + + yield return -1; + + System.Console.Write(s_buffer[2]); + } + + static ref Buffer4 GetBuffer() => ref s_buffer; +} +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (18,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref Buffer4 buffer = ref GetBuffer(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "buffer").WithArguments("ref and unsafe in async and iterator methods").WithLocation(18, 26), + // (19,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref int y in buffer) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(19, 26)); + + var expectedDiagnostics = new[] + { + // (19,31): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // foreach (ref int y in buffer) + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "buffer").WithLocation(19, 31) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Foreach_InIterator_14() + { + var src = @" +class C +{ + public readonly Buffer4 F = default; +} + +class Program +{ + private static C c = new C(); + private static int index = 0; + + static void Main() + { + foreach (var a in Test(c)) + {} + } + + static System.Collections.Generic.IEnumerable Test(C x) + { + ref readonly Buffer4 f = ref x.F; + foreach (var y in f) + { + Increment(); + System.Console.Write(' '); + System.Console.Write(y); + + yield return -1; + } + } + + static void Increment() + { + index++; + + if (index < 4) + { + System.Runtime.CompilerServices.Unsafe.AsRef(in c.F)[index] = index; + } + } +} +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (20,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref readonly Buffer4 f = ref x.F; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "f").WithArguments("ref and unsafe in async and iterator methods").WithLocation(20, 35)); + + var expectedDiagnostics = new[] + { + // (21,27): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // foreach (var y in f) + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "f").WithLocation(21, 27) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Foreach_InIterator_15() + { + var src = @" +class Program +{ + static Buffer4 s_buffer; + + static System.Collections.Generic.IEnumerable Test() + { + foreach (ref readonly int y in GetBuffer()) + { + System.Console.Write(y); + yield return 1; + } + + yield return -1; + } + + static ref readonly Buffer4 GetBuffer() => ref s_buffer; +} +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (8,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref readonly int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 35)); + + var expectedDiagnostics = new[] + { + // (8,9): error CS8178: A reference returned by a call to 'Program.GetBuffer()' cannot be preserved across 'await' or 'yield' boundary. + // foreach (ref readonly int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, @"foreach (ref readonly int y in GetBuffer()) + { + System.Console.Write(y); + yield return 1; + }").WithArguments("Program.GetBuffer()").WithLocation(8, 9) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Foreach_InIterator_16() + { + var src = @" +class Program +{ + static Buffer4 s_buffer; + + static System.Collections.Generic.IEnumerable Test() + { + foreach (ref readonly int y in GetBuffer()) + { + yield return 1; + System.Console.Write(y); + } + + yield return -1; + } + + static ref readonly Buffer4 GetBuffer() => ref s_buffer; +} +" + Buffer4Definition; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (8,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref readonly int y in GetBuffer()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 35)); + + var expectedDiagnostics = new[] + { + // (11,34): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(11, 34) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); } [ConditionalFact(typeof(CoreClrOnly))] - public void Foreach_InIterator_06() + public void Foreach_InIterator_17() { var src = @" class C @@ -21217,7 +22450,7 @@ static void Main() static System.Collections.Generic.IEnumerable Test(C x) { - foreach (var y in x.F) + foreach (ref readonly int y in x.F) { Increment(); System.Console.Write(' '); @@ -21237,240 +22470,107 @@ static void Increment() } } } -"; - var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); - var verifier = CompileAndVerify(comp, expectedOutput: " 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); - - verifier.VerifyIL("Program.d__3.System.Collections.IEnumerator.MoveNext", -@" -{ - // Code size 151 (0x97) - .maxstack 3 - .locals init (int V_0) - IL_0000: ldarg.0 - IL_0001: ldfld ""int Program.d__3.<>1__state"" - IL_0006: stloc.0 - IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0010 - IL_000a: ldloc.0 - IL_000b: ldc.i4.1 - IL_000c: beq.s IL_0070 - IL_000e: ldc.i4.0 - IL_000f: ret - IL_0010: ldarg.0 - IL_0011: ldc.i4.m1 - IL_0012: stfld ""int Program.d__3.<>1__state"" - IL_0017: ldarg.0 - IL_0018: ldarg.0 - IL_0019: ldfld ""C Program.d__3.x"" - IL_001e: stfld ""C Program.d__3.<>7__wrap2"" - IL_0023: ldarg.0 - IL_0024: ldfld ""C Program.d__3.<>7__wrap2"" - IL_0029: ldfld ""Buffer4 C.F"" - IL_002e: pop - IL_002f: ldarg.0 - IL_0030: ldc.i4.0 - IL_0031: stfld ""int Program.d__3.<>7__wrap1"" - IL_0036: br.s IL_0085 - IL_0038: ldarg.0 - IL_0039: ldfld ""C Program.d__3.<>7__wrap2"" - IL_003e: ldflda ""Buffer4 C.F"" - IL_0043: ldarg.0 - IL_0044: ldfld ""int Program.d__3.<>7__wrap1"" - IL_0049: call ""ref readonly int .InlineArrayElementRefReadOnly, int>(in Buffer4, int)"" - IL_004e: ldind.i4 - IL_004f: call ""void Program.Increment()"" - IL_0054: ldc.i4.s 32 - IL_0056: call ""void System.Console.Write(char)"" - IL_005b: call ""void System.Console.Write(int)"" - IL_0060: ldarg.0 - IL_0061: ldc.i4.m1 - IL_0062: stfld ""int Program.d__3.<>2__current"" - IL_0067: ldarg.0 - IL_0068: ldc.i4.1 - IL_0069: stfld ""int Program.d__3.<>1__state"" - IL_006e: ldc.i4.1 - IL_006f: ret - IL_0070: ldarg.0 - IL_0071: ldc.i4.m1 - IL_0072: stfld ""int Program.d__3.<>1__state"" - IL_0077: ldarg.0 - IL_0078: ldarg.0 - IL_0079: ldfld ""int Program.d__3.<>7__wrap1"" - IL_007e: ldc.i4.1 - IL_007f: add - IL_0080: stfld ""int Program.d__3.<>7__wrap1"" - IL_0085: ldarg.0 - IL_0086: ldfld ""int Program.d__3.<>7__wrap1"" - IL_008b: ldc.i4.4 - IL_008c: blt.s IL_0038 - IL_008e: ldarg.0 - IL_008f: ldnull - IL_0090: stfld ""C Program.d__3.<>7__wrap2"" - IL_0095: ldc.i4.0 - IL_0096: ret -} -"); - comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: " 0 1 2 3", verify: Verification.Fails).VerifyDiagnostics(); +" + Buffer4Definition; + var expectedOutput = " 0 1 2 3"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyDiagnostics(); + comp = CreateCompilation(src, targetFramework: TargetFramework.Net80, options: TestOptions.DebugExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.Fails).VerifyDiagnostics(); } [Fact] - public void Foreach_InIterator_07() + public void Foreach_InIterator_18() { var src = @" -class Program +class C { - static System.Collections.Generic.IEnumerable Test() - { - foreach (ref readonly int y in GetBuffer()) - { - } - - yield return -1; - } - - static ref readonly Buffer4 GetBuffer() => throw null; + public readonly Buffer4 F = default; } -"; - var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseDll); - comp.VerifyDiagnostics( - // (6,35): error CS8176: Iterators cannot have by-reference locals - // foreach (ref readonly int y in GetBuffer()) - Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "y").WithLocation(6, 35) - ); - } - [Fact] - public void Foreach_InIterator_08() - { - var src = @" class Program { - static System.Collections.Generic.IEnumerable Test() + static System.Collections.Generic.IEnumerable Test(C x) { - foreach (int y in GetBuffer()) + foreach (ref readonly int y in x.F) { yield return -1; + System.Console.Write(y); } } - - static ref readonly Buffer4 GetBuffer() => throw null; } -"; - var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseDll); +" + Buffer4Definition; - comp.VerifyEmitDiagnostics( - // (6,9): error CS8178: A reference returned by a call to 'Program.GetBuffer()' cannot be preserved across 'await' or 'yield' boundary. - // foreach (int y in GetBuffer()) - Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, - @"foreach (int y in GetBuffer()) - { - yield return -1; - }").WithArguments("Program.GetBuffer()").WithLocation(6, 9) - ); + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (11,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (ref readonly int y in x.F) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 35)); + + var expectedDiagnostics = new[] + { + // (14,34): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(14, 34) + }; + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); } - [ConditionalFact(typeof(CoreClrOnly))] - public void Foreach_InIterator_09() + [Fact] + public void Foreach_InIterator_19() { var src = @" +class C +{ + public readonly Buffer4 F = default; +} + class Program { - static void Main() + static System.Collections.Generic.IEnumerable Test(C x) { - foreach (var a in Test()) - {} - } + ref readonly Buffer4 f = ref x.F; - static System.Collections.Generic.IEnumerable Test() - { - foreach (var y in GetBuffer()) + foreach (var i in f) System.Console.Write(i); + + foreach (var y in f) { - System.Console.Write(' '); System.Console.Write(y); yield return -1; } - } - static Buffer4 GetBuffer() - { - Buffer4 x = default; - x[0] = 111; - x[1] = 112; - x[2] = 113; - x[3] = 114; - - System.Console.Write(-1); - return x; + foreach (var j in f) System.Console.Write(j); + + foreach (var z in f) + { + System.Console.Write(z); + yield return -2; + } } } -"; - var comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); - var verifier = CompileAndVerify(comp, expectedOutput: "-1 111 112 113 114").VerifyDiagnostics(); +" + Buffer4Definition; - verifier.VerifyIL("Program.d__1.System.Collections.IEnumerator.MoveNext", -@" -{ - // Code size 121 (0x79) - .maxstack 3 - .locals init (int V_0) - IL_0000: ldarg.0 - IL_0001: ldfld ""int Program.d__1.<>1__state"" - IL_0006: stloc.0 - IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0010 - IL_000a: ldloc.0 - IL_000b: ldc.i4.1 - IL_000c: beq.s IL_0059 - IL_000e: ldc.i4.0 - IL_000f: ret - IL_0010: ldarg.0 - IL_0011: ldc.i4.m1 - IL_0012: stfld ""int Program.d__1.<>1__state"" - IL_0017: ldarg.0 - IL_0018: call ""Buffer4 Program.GetBuffer()"" - IL_001d: stfld ""Buffer4 Program.d__1.<>7__wrap1"" - IL_0022: ldarg.0 - IL_0023: ldc.i4.0 - IL_0024: stfld ""int Program.d__1.<>7__wrap2"" - IL_0029: br.s IL_006e - IL_002b: ldarg.0 - IL_002c: ldflda ""Buffer4 Program.d__1.<>7__wrap1"" - IL_0031: ldarg.0 - IL_0032: ldfld ""int Program.d__1.<>7__wrap2"" - IL_0037: call ""ref readonly int .InlineArrayElementRefReadOnly, int>(in Buffer4, int)"" - IL_003c: ldind.i4 - IL_003d: ldc.i4.s 32 - IL_003f: call ""void System.Console.Write(char)"" - IL_0044: call ""void System.Console.Write(int)"" - IL_0049: ldarg.0 - IL_004a: ldc.i4.m1 - IL_004b: stfld ""int Program.d__1.<>2__current"" - IL_0050: ldarg.0 - IL_0051: ldc.i4.1 - IL_0052: stfld ""int Program.d__1.<>1__state"" - IL_0057: ldc.i4.1 - IL_0058: ret - IL_0059: ldarg.0 - IL_005a: ldc.i4.m1 - IL_005b: stfld ""int Program.d__1.<>1__state"" - IL_0060: ldarg.0 - IL_0061: ldarg.0 - IL_0062: ldfld ""int Program.d__1.<>7__wrap2"" - IL_0067: ldc.i4.1 - IL_0068: add - IL_0069: stfld ""int Program.d__1.<>7__wrap2"" - IL_006e: ldarg.0 - IL_006f: ldfld ""int Program.d__1.<>7__wrap2"" - IL_0074: ldc.i4.4 - IL_0075: blt.s IL_002b - IL_0077: ldc.i4.0 - IL_0078: ret -} -"); - comp = CreateCompilation(src + Buffer4Definition, targetFramework: TargetFramework.Net80, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: "-1 111 112 113 114").VerifyDiagnostics(); + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (11,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref readonly Buffer4 f = ref x.F; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "f").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 35)); + + var expectedDiagnostics = new[] + { + // (15,27): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // foreach (var y in f) + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "f").WithLocation(15, 27), + // (21,27): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // foreach (var j in f) System.Console.Write(j); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "f").WithLocation(21, 27), + // (23,27): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // foreach (var z in f) + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "f").WithLocation(23, 27) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics(expectedDiagnostics); } [ConditionalFact(typeof(CoreClrOnly))] @@ -21988,5 +23088,218 @@ struct ThreeStringBuffer { var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify(comp, expectedOutput: "123124").VerifyDiagnostics(); } + + [Fact] + public void Initialization_Await_RefStruct() + { + var src = """ + using System.Threading.Tasks; + + var b = new Buffer(); + b[0] = await GetInt(); + b[1] = await GetInt(); + + static Task GetInt() => Task.FromResult(42); + + [System.Runtime.CompilerServices.InlineArray(4)] + ref struct Buffer + { + private int _element0; + } + """; + + CreateCompilation(src, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (3,1): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var b = new Buffer(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 1), + // (4,1): error CS0306: The type 'Buffer' may not be used as a type argument + // b[0] = await GetInt(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "b[0]").WithArguments("Buffer").WithLocation(4, 1), + // (5,1): error CS0306: The type 'Buffer' may not be used as a type argument + // b[1] = await GetInt(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "b[1]").WithArguments("Buffer").WithLocation(5, 1), + // (10,12): warning CS9184: 'Inline arrays' language feature is not supported for an inline array type that is not valid as a type argument, or has element type that is not valid as a type argument. + // ref struct Buffer + Diagnostic(ErrorCode.WRN_InlineArrayNotSupportedByLanguage, "Buffer").WithLocation(10, 12)); + + var expectedDiagnostics = new[] + { + // (4,1): error CS0306: The type 'Buffer' may not be used as a type argument + // b[0] = await GetInt(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "b[0]").WithArguments("Buffer").WithLocation(4, 1), + // (5,1): error CS0306: The type 'Buffer' may not be used as a type argument + // b[1] = await GetInt(); + Diagnostic(ErrorCode.ERR_BadTypeArgument, "b[1]").WithArguments("Buffer").WithLocation(5, 1), + // (10,12): warning CS9184: 'Inline arrays' language feature is not supported for an inline array type that is not valid as a type argument, or has element type that is not valid as a type argument. + // ref struct Buffer + Diagnostic(ErrorCode.WRN_InlineArrayNotSupportedByLanguage, "Buffer").WithLocation(10, 12) + }; + + CreateCompilation(src, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net80).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(src, targetFramework: TargetFramework.Net80).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Initialization_Await() + { + var src = """ + using System.Threading.Tasks; + + var b = new Buffer(); + b[0] = await GetInt(); + System.Console.Write(b[1]); + b[1] = await GetInt(); + System.Console.Write(b[1]); + + static Task GetInt() => Task.FromResult(42); + + [System.Runtime.CompilerServices.InlineArray(4)] + struct Buffer + { + private int _element0; + } + """; + foreach (var parseOptions in new[] { TestOptions.Regular12, TestOptions.RegularNext, TestOptions.RegularPreview }) + { + var verifier = CompileAndVerify(src, expectedOutput: ExecutionConditionUtil.IsDesktop ? null : "042", + parseOptions: parseOptions, targetFramework: TargetFramework.Net80, verify: Verification.FailsPEVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.<
$>d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", """ + { + // Code size 316 (0x13c) + .maxstack 3 + .locals init (int V_0, + int V_1, + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) + IL_0000: ldarg.0 + IL_0001: ldfld "int Program.<
$>d__0.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0054 + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: beq IL_00cb + IL_0011: ldarg.0 + IL_0012: ldflda "Buffer Program.<
$>d__0.5__2" + IL_0017: initobj "Buffer" + IL_001d: call "System.Threading.Tasks.Task Program.<
$>g__GetInt|0_0()" + IL_0022: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_0027: stloc.2 + IL_0028: ldloca.s V_2 + IL_002a: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_002f: brtrue.s IL_0070 + IL_0031: ldarg.0 + IL_0032: ldc.i4.0 + IL_0033: dup + IL_0034: stloc.0 + IL_0035: stfld "int Program.<
$>d__0.<>1__state" + IL_003a: ldarg.0 + IL_003b: ldloc.2 + IL_003c: stfld "System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1" + IL_0041: ldarg.0 + IL_0042: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder" + IL_0047: ldloca.s V_2 + IL_0049: ldarg.0 + IL_004a: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.<
$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.<
$>d__0)" + IL_004f: leave IL_013b + IL_0054: ldarg.0 + IL_0055: ldfld "System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1" + IL_005a: stloc.2 + IL_005b: ldarg.0 + IL_005c: ldflda "System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1" + IL_0061: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_0067: ldarg.0 + IL_0068: ldc.i4.m1 + IL_0069: dup + IL_006a: stloc.0 + IL_006b: stfld "int Program.<
$>d__0.<>1__state" + IL_0070: ldloca.s V_2 + IL_0072: call "int System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_0077: stloc.1 + IL_0078: ldarg.0 + IL_0079: ldflda "Buffer Program.<
$>d__0.5__2" + IL_007e: call "ref int .InlineArrayFirstElementRef(ref Buffer)" + IL_0083: ldloc.1 + IL_0084: stind.i4 + IL_0085: ldarg.0 + IL_0086: ldflda "Buffer Program.<
$>d__0.5__2" + IL_008b: ldc.i4.1 + IL_008c: call "ref int .InlineArrayElementRef(ref Buffer, int)" + IL_0091: ldind.i4 + IL_0092: call "void System.Console.Write(int)" + IL_0097: call "System.Threading.Tasks.Task Program.<
$>g__GetInt|0_0()" + IL_009c: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_00a1: stloc.2 + IL_00a2: ldloca.s V_2 + IL_00a4: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_00a9: brtrue.s IL_00e7 + IL_00ab: ldarg.0 + IL_00ac: ldc.i4.1 + IL_00ad: dup + IL_00ae: stloc.0 + IL_00af: stfld "int Program.<
$>d__0.<>1__state" + IL_00b4: ldarg.0 + IL_00b5: ldloc.2 + IL_00b6: stfld "System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1" + IL_00bb: ldarg.0 + IL_00bc: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder" + IL_00c1: ldloca.s V_2 + IL_00c3: ldarg.0 + IL_00c4: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.<
$>d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.<
$>d__0)" + IL_00c9: leave.s IL_013b + IL_00cb: ldarg.0 + IL_00cc: ldfld "System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1" + IL_00d1: stloc.2 + IL_00d2: ldarg.0 + IL_00d3: ldflda "System.Runtime.CompilerServices.TaskAwaiter Program.<
$>d__0.<>u__1" + IL_00d8: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_00de: ldarg.0 + IL_00df: ldc.i4.m1 + IL_00e0: dup + IL_00e1: stloc.0 + IL_00e2: stfld "int Program.<
$>d__0.<>1__state" + IL_00e7: ldloca.s V_2 + IL_00e9: call "int System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_00ee: stloc.1 + IL_00ef: ldarg.0 + IL_00f0: ldflda "Buffer Program.<
$>d__0.5__2" + IL_00f5: ldc.i4.1 + IL_00f6: call "ref int .InlineArrayElementRef(ref Buffer, int)" + IL_00fb: ldloc.1 + IL_00fc: stind.i4 + IL_00fd: ldarg.0 + IL_00fe: ldflda "Buffer Program.<
$>d__0.5__2" + IL_0103: ldc.i4.1 + IL_0104: call "ref int .InlineArrayElementRef(ref Buffer, int)" + IL_0109: ldind.i4 + IL_010a: call "void System.Console.Write(int)" + IL_010f: leave.s IL_0128 + } + catch System.Exception + { + IL_0111: stloc.3 + IL_0112: ldarg.0 + IL_0113: ldc.i4.s -2 + IL_0115: stfld "int Program.<
$>d__0.<>1__state" + IL_011a: ldarg.0 + IL_011b: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder" + IL_0120: ldloc.3 + IL_0121: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_0126: leave.s IL_013b + } + IL_0128: ldarg.0 + IL_0129: ldc.i4.s -2 + IL_012b: stfld "int Program.<
$>d__0.<>1__state" + IL_0130: ldarg.0 + IL_0131: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<
$>d__0.<>t__builder" + IL_0136: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_013b: ret + } + """); + } + } } } diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/LockTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/LockTests.cs index 61b08bdf399e5..61614ef54b64e 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/LockTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/LockTests.cs @@ -1861,9 +1861,6 @@ public void Await() } """; CreateCompilation([source, LockTypeDefinition]).VerifyDiagnostics( - // (4,7): error CS9217: A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - // lock (new Lock()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefLock, "new Lock()").WithLocation(4, 7), // (6,5): error CS1996: Cannot await in the body of a lock statement // await Task.Yield(); Diagnostic(ErrorCode.ERR_BadAwaitInLock, "await Task.Yield()").WithLocation(6, 5)); @@ -1875,19 +1872,137 @@ public void AsyncMethod() var source = """ #pragma warning disable 1998 // async method lacks 'await' operators using System.Threading; + using System.Threading.Tasks; class C { - async void M() + static async Task Main() { - lock (new Lock()) { } + lock (new Lock()) { System.Console.Write("L"); } } } """; - CreateCompilation([source, LockTypeDefinition]).VerifyDiagnostics( - // (8,15): error CS9217: A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - // lock (new Lock()) { } - Diagnostic(ErrorCode.ERR_BadSpecialByRefLock, "new Lock()").WithLocation(8, 15)); + var expectedOutput = "ELD"; + var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C.
d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 94 (0x5e) + .maxstack 2 + .locals init (int V_0, + System.Threading.Lock.Scope V_1, + System.Exception V_2) + IL_0000: ldarg.0 + IL_0001: ldfld "int C.
d__0.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: nop + IL_0008: newobj "System.Threading.Lock..ctor()" + IL_000d: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0012: stloc.1 + .try + { + IL_0013: nop + IL_0014: ldstr "L" + IL_0019: call "void System.Console.Write(string)" + IL_001e: nop + IL_001f: nop + IL_0020: leave.s IL_002f + } + finally + { + IL_0022: ldloc.0 + IL_0023: ldc.i4.0 + IL_0024: bge.s IL_002e + IL_0026: ldloca.s V_1 + IL_0028: call "void System.Threading.Lock.Scope.Dispose()" + IL_002d: nop + IL_002e: endfinally + } + IL_002f: leave.s IL_0049 + } + catch System.Exception + { + IL_0031: stloc.2 + IL_0032: ldarg.0 + IL_0033: ldc.i4.s -2 + IL_0035: stfld "int C.
d__0.<>1__state" + IL_003a: ldarg.0 + IL_003b: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_0040: ldloc.2 + IL_0041: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_0046: nop + IL_0047: leave.s IL_005d + } + IL_0049: ldarg.0 + IL_004a: ldc.i4.s -2 + IL_004c: stfld "int C.
d__0.<>1__state" + IL_0051: ldarg.0 + IL_0052: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_0057: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_005c: nop + IL_005d: ret + } + """); + + verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C.
d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 87 (0x57) + .maxstack 2 + .locals init (int V_0, + System.Threading.Lock.Scope V_1, + System.Exception V_2) + IL_0000: ldarg.0 + IL_0001: ldfld "int C.
d__0.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: newobj "System.Threading.Lock..ctor()" + IL_000c: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0011: stloc.1 + .try + { + IL_0012: ldstr "L" + IL_0017: call "void System.Console.Write(string)" + IL_001c: leave.s IL_002a + } + finally + { + IL_001e: ldloc.0 + IL_001f: ldc.i4.0 + IL_0020: bge.s IL_0029 + IL_0022: ldloca.s V_1 + IL_0024: call "void System.Threading.Lock.Scope.Dispose()" + IL_0029: endfinally + } + IL_002a: leave.s IL_0043 + } + catch System.Exception + { + IL_002c: stloc.2 + IL_002d: ldarg.0 + IL_002e: ldc.i4.s -2 + IL_0030: stfld "int C.
d__0.<>1__state" + IL_0035: ldarg.0 + IL_0036: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_003b: ldloc.2 + IL_003c: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_0041: leave.s IL_0056 + } + IL_0043: ldarg.0 + IL_0044: ldc.i4.s -2 + IL_0046: stfld "int C.
d__0.<>1__state" + IL_004b: ldarg.0 + IL_004c: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_0051: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_0056: ret + } + """); } [Fact] @@ -1899,17 +2014,527 @@ public void AsyncMethod_WithAwait() class C { - async void M() + static async Task Main() { await Task.Yield(); - lock (new Lock()) { } + lock (new Lock()) { System.Console.Write("L"); } + await Task.Yield(); } } """; - CreateCompilation([source, LockTypeDefinition]).VerifyDiagnostics( - // (9,15): error CS9217: A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - // lock (new Lock()) { } - Diagnostic(ErrorCode.ERR_BadSpecialByRefLock, "new Lock()").WithLocation(9, 15)); + var expectedOutput = "ELD"; + var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C.
d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 311 (0x137) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1, + System.Runtime.CompilerServices.YieldAwaitable V_2, + C.
d__0 V_3, + System.Threading.Lock.Scope V_4, + System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_5, + System.Exception V_6) + IL_0000: ldarg.0 + IL_0001: ldfld "int C.
d__0.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: beq.s IL_0014 + IL_0010: br.s IL_0019 + IL_0012: br.s IL_0058 + IL_0014: br IL_00e1 + IL_0019: nop + IL_001a: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_001f: stloc.2 + IL_0020: ldloca.s V_2 + IL_0022: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_0027: stloc.1 + IL_0028: ldloca.s V_1 + IL_002a: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_002f: brtrue.s IL_0074 + IL_0031: ldarg.0 + IL_0032: ldc.i4.0 + IL_0033: dup + IL_0034: stloc.0 + IL_0035: stfld "int C.
d__0.<>1__state" + IL_003a: ldarg.0 + IL_003b: ldloc.1 + IL_003c: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.
d__0.<>u__1" + IL_0041: ldarg.0 + IL_0042: stloc.3 + IL_0043: ldarg.0 + IL_0044: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_0049: ldloca.s V_1 + IL_004b: ldloca.s V_3 + IL_004d: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.
d__0)" + IL_0052: nop + IL_0053: leave IL_0136 + IL_0058: ldarg.0 + IL_0059: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.
d__0.<>u__1" + IL_005e: stloc.1 + IL_005f: ldarg.0 + IL_0060: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.
d__0.<>u__1" + IL_0065: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_006b: ldarg.0 + IL_006c: ldc.i4.m1 + IL_006d: dup + IL_006e: stloc.0 + IL_006f: stfld "int C.
d__0.<>1__state" + IL_0074: ldloca.s V_1 + IL_0076: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_007b: nop + IL_007c: newobj "System.Threading.Lock..ctor()" + IL_0081: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0086: stloc.s V_4 + .try + { + IL_0088: nop + IL_0089: ldstr "L" + IL_008e: call "void System.Console.Write(string)" + IL_0093: nop + IL_0094: nop + IL_0095: leave.s IL_00a4 + } + finally + { + IL_0097: ldloc.0 + IL_0098: ldc.i4.0 + IL_0099: bge.s IL_00a3 + IL_009b: ldloca.s V_4 + IL_009d: call "void System.Threading.Lock.Scope.Dispose()" + IL_00a2: nop + IL_00a3: endfinally + } + IL_00a4: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_00a9: stloc.2 + IL_00aa: ldloca.s V_2 + IL_00ac: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_00b1: stloc.s V_5 + IL_00b3: ldloca.s V_5 + IL_00b5: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_00ba: brtrue.s IL_00fe + IL_00bc: ldarg.0 + IL_00bd: ldc.i4.1 + IL_00be: dup + IL_00bf: stloc.0 + IL_00c0: stfld "int C.
d__0.<>1__state" + IL_00c5: ldarg.0 + IL_00c6: ldloc.s V_5 + IL_00c8: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.
d__0.<>u__1" + IL_00cd: ldarg.0 + IL_00ce: stloc.3 + IL_00cf: ldarg.0 + IL_00d0: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_00d5: ldloca.s V_5 + IL_00d7: ldloca.s V_3 + IL_00d9: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.
d__0)" + IL_00de: nop + IL_00df: leave.s IL_0136 + IL_00e1: ldarg.0 + IL_00e2: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.
d__0.<>u__1" + IL_00e7: stloc.s V_5 + IL_00e9: ldarg.0 + IL_00ea: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.
d__0.<>u__1" + IL_00ef: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_00f5: ldarg.0 + IL_00f6: ldc.i4.m1 + IL_00f7: dup + IL_00f8: stloc.0 + IL_00f9: stfld "int C.
d__0.<>1__state" + IL_00fe: ldloca.s V_5 + IL_0100: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_0105: nop + IL_0106: leave.s IL_0122 + } + catch System.Exception + { + IL_0108: stloc.s V_6 + IL_010a: ldarg.0 + IL_010b: ldc.i4.s -2 + IL_010d: stfld "int C.
d__0.<>1__state" + IL_0112: ldarg.0 + IL_0113: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_0118: ldloc.s V_6 + IL_011a: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_011f: nop + IL_0120: leave.s IL_0136 + } + IL_0122: ldarg.0 + IL_0123: ldc.i4.s -2 + IL_0125: stfld "int C.
d__0.<>1__state" + IL_012a: ldarg.0 + IL_012b: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_0130: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_0135: nop + IL_0136: ret + } + """); + + verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C.
d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 282 (0x11a) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1, + System.Runtime.CompilerServices.YieldAwaitable V_2, + System.Threading.Lock.Scope V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld "int C.
d__0.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_004b + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: beq IL_00c8 + IL_0011: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_0016: stloc.2 + IL_0017: ldloca.s V_2 + IL_0019: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_001e: stloc.1 + IL_001f: ldloca.s V_1 + IL_0021: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_0026: brtrue.s IL_0067 + IL_0028: ldarg.0 + IL_0029: ldc.i4.0 + IL_002a: dup + IL_002b: stloc.0 + IL_002c: stfld "int C.
d__0.<>1__state" + IL_0031: ldarg.0 + IL_0032: ldloc.1 + IL_0033: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.
d__0.<>u__1" + IL_0038: ldarg.0 + IL_0039: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_003e: ldloca.s V_1 + IL_0040: ldarg.0 + IL_0041: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.
d__0)" + IL_0046: leave IL_0119 + IL_004b: ldarg.0 + IL_004c: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.
d__0.<>u__1" + IL_0051: stloc.1 + IL_0052: ldarg.0 + IL_0053: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.
d__0.<>u__1" + IL_0058: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_005e: ldarg.0 + IL_005f: ldc.i4.m1 + IL_0060: dup + IL_0061: stloc.0 + IL_0062: stfld "int C.
d__0.<>1__state" + IL_0067: ldloca.s V_1 + IL_0069: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_006e: newobj "System.Threading.Lock..ctor()" + IL_0073: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0078: stloc.3 + .try + { + IL_0079: ldstr "L" + IL_007e: call "void System.Console.Write(string)" + IL_0083: leave.s IL_0091 + } + finally + { + IL_0085: ldloc.0 + IL_0086: ldc.i4.0 + IL_0087: bge.s IL_0090 + IL_0089: ldloca.s V_3 + IL_008b: call "void System.Threading.Lock.Scope.Dispose()" + IL_0090: endfinally + } + IL_0091: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_0096: stloc.2 + IL_0097: ldloca.s V_2 + IL_0099: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_009e: stloc.1 + IL_009f: ldloca.s V_1 + IL_00a1: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_00a6: brtrue.s IL_00e4 + IL_00a8: ldarg.0 + IL_00a9: ldc.i4.1 + IL_00aa: dup + IL_00ab: stloc.0 + IL_00ac: stfld "int C.
d__0.<>1__state" + IL_00b1: ldarg.0 + IL_00b2: ldloc.1 + IL_00b3: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.
d__0.<>u__1" + IL_00b8: ldarg.0 + IL_00b9: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_00be: ldloca.s V_1 + IL_00c0: ldarg.0 + IL_00c1: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.
d__0)" + IL_00c6: leave.s IL_0119 + IL_00c8: ldarg.0 + IL_00c9: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.
d__0.<>u__1" + IL_00ce: stloc.1 + IL_00cf: ldarg.0 + IL_00d0: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.
d__0.<>u__1" + IL_00d5: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_00db: ldarg.0 + IL_00dc: ldc.i4.m1 + IL_00dd: dup + IL_00de: stloc.0 + IL_00df: stfld "int C.
d__0.<>1__state" + IL_00e4: ldloca.s V_1 + IL_00e6: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_00eb: leave.s IL_0106 + } + catch System.Exception + { + IL_00ed: stloc.s V_4 + IL_00ef: ldarg.0 + IL_00f0: ldc.i4.s -2 + IL_00f2: stfld "int C.
d__0.<>1__state" + IL_00f7: ldarg.0 + IL_00f8: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_00fd: ldloc.s V_4 + IL_00ff: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_0104: leave.s IL_0119 + } + IL_0106: ldarg.0 + IL_0107: ldc.i4.s -2 + IL_0109: stfld "int C.
d__0.<>1__state" + IL_010e: ldarg.0 + IL_010f: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_0114: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_0119: ret + } + """); + } + + [Fact] + public void AsyncMethod_AwaitResource() + { + var source = """ + #pragma warning disable 1998 // async method lacks 'await' operators + using System.Threading; + using System.Threading.Tasks; + + class C + { + static async Task Main() + { + lock (await GetLock()) { System.Console.Write("L"); } + } + + static async Task GetLock() => new Lock(); + } + """; + var expectedOutput = "ELD"; + var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C.
d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 211 (0xd3) + .maxstack 3 + .locals init (int V_0, + System.Threading.Lock.Scope V_1, + System.Runtime.CompilerServices.TaskAwaiter V_2, + C.
d__0 V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld "int C.
d__0.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_000c + IL_000a: br.s IL_000e + IL_000c: br.s IL_004a + IL_000e: nop + IL_000f: call "System.Threading.Tasks.Task C.GetLock()" + IL_0014: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_0019: stloc.2 + IL_001a: ldloca.s V_2 + IL_001c: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_0021: brtrue.s IL_0066 + IL_0023: ldarg.0 + IL_0024: ldc.i4.0 + IL_0025: dup + IL_0026: stloc.0 + IL_0027: stfld "int C.
d__0.<>1__state" + IL_002c: ldarg.0 + IL_002d: ldloc.2 + IL_002e: stfld "System.Runtime.CompilerServices.TaskAwaiter C.
d__0.<>u__1" + IL_0033: ldarg.0 + IL_0034: stloc.3 + IL_0035: ldarg.0 + IL_0036: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_003b: ldloca.s V_2 + IL_003d: ldloca.s V_3 + IL_003f: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, C.
d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.
d__0)" + IL_0044: nop + IL_0045: leave IL_00d2 + IL_004a: ldarg.0 + IL_004b: ldfld "System.Runtime.CompilerServices.TaskAwaiter C.
d__0.<>u__1" + IL_0050: stloc.2 + IL_0051: ldarg.0 + IL_0052: ldflda "System.Runtime.CompilerServices.TaskAwaiter C.
d__0.<>u__1" + IL_0057: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_005d: ldarg.0 + IL_005e: ldc.i4.m1 + IL_005f: dup + IL_0060: stloc.0 + IL_0061: stfld "int C.
d__0.<>1__state" + IL_0066: ldarg.0 + IL_0067: ldloca.s V_2 + IL_0069: call "System.Threading.Lock System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_006e: stfld "System.Threading.Lock C.
d__0.<>s__1" + IL_0073: ldarg.0 + IL_0074: ldfld "System.Threading.Lock C.
d__0.<>s__1" + IL_0079: callvirt "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_007e: stloc.1 + IL_007f: ldarg.0 + IL_0080: ldnull + IL_0081: stfld "System.Threading.Lock C.
d__0.<>s__1" + .try + { + IL_0086: nop + IL_0087: ldstr "L" + IL_008c: call "void System.Console.Write(string)" + IL_0091: nop + IL_0092: nop + IL_0093: leave.s IL_00a2 + } + finally + { + IL_0095: ldloc.0 + IL_0096: ldc.i4.0 + IL_0097: bge.s IL_00a1 + IL_0099: ldloca.s V_1 + IL_009b: call "void System.Threading.Lock.Scope.Dispose()" + IL_00a0: nop + IL_00a1: endfinally + } + IL_00a2: leave.s IL_00be + } + catch System.Exception + { + IL_00a4: stloc.s V_4 + IL_00a6: ldarg.0 + IL_00a7: ldc.i4.s -2 + IL_00a9: stfld "int C.
d__0.<>1__state" + IL_00ae: ldarg.0 + IL_00af: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_00b4: ldloc.s V_4 + IL_00b6: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_00bb: nop + IL_00bc: leave.s IL_00d2 + } + IL_00be: ldarg.0 + IL_00bf: ldc.i4.s -2 + IL_00c1: stfld "int C.
d__0.<>1__state" + IL_00c6: ldarg.0 + IL_00c7: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_00cc: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_00d1: nop + IL_00d2: ret + } + """); + + verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C.
d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 172 (0xac) + .maxstack 3 + .locals init (int V_0, + System.Threading.Lock.Scope V_1, + System.Runtime.CompilerServices.TaskAwaiter V_2, + System.Exception V_3) + IL_0000: ldarg.0 + IL_0001: ldfld "int C.
d__0.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_003e + IL_000a: call "System.Threading.Tasks.Task C.GetLock()" + IL_000f: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_0014: stloc.2 + IL_0015: ldloca.s V_2 + IL_0017: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_001c: brtrue.s IL_005a + IL_001e: ldarg.0 + IL_001f: ldc.i4.0 + IL_0020: dup + IL_0021: stloc.0 + IL_0022: stfld "int C.
d__0.<>1__state" + IL_0027: ldarg.0 + IL_0028: ldloc.2 + IL_0029: stfld "System.Runtime.CompilerServices.TaskAwaiter C.
d__0.<>u__1" + IL_002e: ldarg.0 + IL_002f: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_0034: ldloca.s V_2 + IL_0036: ldarg.0 + IL_0037: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, C.
d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.
d__0)" + IL_003c: leave.s IL_00ab + IL_003e: ldarg.0 + IL_003f: ldfld "System.Runtime.CompilerServices.TaskAwaiter C.
d__0.<>u__1" + IL_0044: stloc.2 + IL_0045: ldarg.0 + IL_0046: ldflda "System.Runtime.CompilerServices.TaskAwaiter C.
d__0.<>u__1" + IL_004b: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_0051: ldarg.0 + IL_0052: ldc.i4.m1 + IL_0053: dup + IL_0054: stloc.0 + IL_0055: stfld "int C.
d__0.<>1__state" + IL_005a: ldloca.s V_2 + IL_005c: call "System.Threading.Lock System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_0061: callvirt "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0066: stloc.1 + .try + { + IL_0067: ldstr "L" + IL_006c: call "void System.Console.Write(string)" + IL_0071: leave.s IL_007f + } + finally + { + IL_0073: ldloc.0 + IL_0074: ldc.i4.0 + IL_0075: bge.s IL_007e + IL_0077: ldloca.s V_1 + IL_0079: call "void System.Threading.Lock.Scope.Dispose()" + IL_007e: endfinally + } + IL_007f: leave.s IL_0098 + } + catch System.Exception + { + IL_0081: stloc.3 + IL_0082: ldarg.0 + IL_0083: ldc.i4.s -2 + IL_0085: stfld "int C.
d__0.<>1__state" + IL_008a: ldarg.0 + IL_008b: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_0090: ldloc.3 + IL_0091: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_0096: leave.s IL_00ab + } + IL_0098: ldarg.0 + IL_0099: ldc.i4.s -2 + IL_009b: stfld "int C.
d__0.<>1__state" + IL_00a0: ldarg.0 + IL_00a1: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.
d__0.<>t__builder" + IL_00a6: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_00ab: ret + } + """); } [Fact] @@ -1921,15 +2546,132 @@ public void AsyncLocalFunction() async void local() { - lock (new Lock()) { } + lock (new Lock()) { System.Console.Write("L"); } } local(); """; - CreateCompilation([source, LockTypeDefinition]).VerifyDiagnostics( - // (6,11): error CS9217: A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - // lock (new Lock()) { } - Diagnostic(ErrorCode.ERR_BadSpecialByRefLock, "new Lock()").WithLocation(6, 11)); + var expectedOutput = "ELD"; + var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.<<
$>g__local|0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 94 (0x5e) + .maxstack 2 + .locals init (int V_0, + System.Threading.Lock.Scope V_1, + System.Exception V_2) + IL_0000: ldarg.0 + IL_0001: ldfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: nop + IL_0008: newobj "System.Threading.Lock..ctor()" + IL_000d: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0012: stloc.1 + .try + { + IL_0013: nop + IL_0014: ldstr "L" + IL_0019: call "void System.Console.Write(string)" + IL_001e: nop + IL_001f: nop + IL_0020: leave.s IL_002f + } + finally + { + IL_0022: ldloc.0 + IL_0023: ldc.i4.0 + IL_0024: bge.s IL_002e + IL_0026: ldloca.s V_1 + IL_0028: call "void System.Threading.Lock.Scope.Dispose()" + IL_002d: nop + IL_002e: endfinally + } + IL_002f: leave.s IL_0049 + } + catch System.Exception + { + IL_0031: stloc.2 + IL_0032: ldarg.0 + IL_0033: ldc.i4.s -2 + IL_0035: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_003a: ldarg.0 + IL_003b: ldflda "System.Runtime.CompilerServices.AsyncVoidMethodBuilder Program.<<
$>g__local|0_0>d.<>t__builder" + IL_0040: ldloc.2 + IL_0041: call "void System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetException(System.Exception)" + IL_0046: nop + IL_0047: leave.s IL_005d + } + IL_0049: ldarg.0 + IL_004a: ldc.i4.s -2 + IL_004c: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_0051: ldarg.0 + IL_0052: ldflda "System.Runtime.CompilerServices.AsyncVoidMethodBuilder Program.<<
$>g__local|0_0>d.<>t__builder" + IL_0057: call "void System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetResult()" + IL_005c: nop + IL_005d: ret + } + """); + + verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.<<
$>g__local|0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 87 (0x57) + .maxstack 2 + .locals init (int V_0, + System.Threading.Lock.Scope V_1, + System.Exception V_2) + IL_0000: ldarg.0 + IL_0001: ldfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: newobj "System.Threading.Lock..ctor()" + IL_000c: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0011: stloc.1 + .try + { + IL_0012: ldstr "L" + IL_0017: call "void System.Console.Write(string)" + IL_001c: leave.s IL_002a + } + finally + { + IL_001e: ldloc.0 + IL_001f: ldc.i4.0 + IL_0020: bge.s IL_0029 + IL_0022: ldloca.s V_1 + IL_0024: call "void System.Threading.Lock.Scope.Dispose()" + IL_0029: endfinally + } + IL_002a: leave.s IL_0043 + } + catch System.Exception + { + IL_002c: stloc.2 + IL_002d: ldarg.0 + IL_002e: ldc.i4.s -2 + IL_0030: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_0035: ldarg.0 + IL_0036: ldflda "System.Runtime.CompilerServices.AsyncVoidMethodBuilder Program.<<
$>g__local|0_0>d.<>t__builder" + IL_003b: ldloc.2 + IL_003c: call "void System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetException(System.Exception)" + IL_0041: leave.s IL_0056 + } + IL_0043: ldarg.0 + IL_0044: ldc.i4.s -2 + IL_0046: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_004b: ldarg.0 + IL_004c: ldflda "System.Runtime.CompilerServices.AsyncVoidMethodBuilder Program.<<
$>g__local|0_0>d.<>t__builder" + IL_0051: call "void System.Runtime.CompilerServices.AsyncVoidMethodBuilder.SetResult()" + IL_0056: ret + } + """); } [Fact] @@ -1939,18 +2681,304 @@ public void AsyncLocalFunction_WithAwait() using System.Threading; using System.Threading.Tasks; - async void local() + async Task local() { await Task.Yield(); - lock (new Lock()) { } + lock (new Lock()) { System.Console.Write("L"); } + await Task.Yield(); } - local(); + await local(); """; - CreateCompilation([source, LockTypeDefinition]).VerifyDiagnostics( - // (7,11): error CS9217: A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - // lock (new Lock()) { } - Diagnostic(ErrorCode.ERR_BadSpecialByRefLock, "new Lock()").WithLocation(7, 11)); + var expectedOutput = "ELD"; + var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.<<
$>g__local|0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 311 (0x137) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1, + System.Runtime.CompilerServices.YieldAwaitable V_2, + Program.<<
$>g__local|0_0>d V_3, + System.Threading.Lock.Scope V_4, + System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_5, + System.Exception V_6) + IL_0000: ldarg.0 + IL_0001: ldfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: beq.s IL_0014 + IL_0010: br.s IL_0019 + IL_0012: br.s IL_0058 + IL_0014: br IL_00e1 + IL_0019: nop + IL_001a: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_001f: stloc.2 + IL_0020: ldloca.s V_2 + IL_0022: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_0027: stloc.1 + IL_0028: ldloca.s V_1 + IL_002a: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_002f: brtrue.s IL_0074 + IL_0031: ldarg.0 + IL_0032: ldc.i4.0 + IL_0033: dup + IL_0034: stloc.0 + IL_0035: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_003a: ldarg.0 + IL_003b: ldloc.1 + IL_003c: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<
$>g__local|0_0>d.<>u__1" + IL_0041: ldarg.0 + IL_0042: stloc.3 + IL_0043: ldarg.0 + IL_0044: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<
$>g__local|0_0>d.<>t__builder" + IL_0049: ldloca.s V_1 + IL_004b: ldloca.s V_3 + IL_004d: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted$>g__local|0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<<
$>g__local|0_0>d)" + IL_0052: nop + IL_0053: leave IL_0136 + IL_0058: ldarg.0 + IL_0059: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<
$>g__local|0_0>d.<>u__1" + IL_005e: stloc.1 + IL_005f: ldarg.0 + IL_0060: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<
$>g__local|0_0>d.<>u__1" + IL_0065: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_006b: ldarg.0 + IL_006c: ldc.i4.m1 + IL_006d: dup + IL_006e: stloc.0 + IL_006f: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_0074: ldloca.s V_1 + IL_0076: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_007b: nop + IL_007c: newobj "System.Threading.Lock..ctor()" + IL_0081: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0086: stloc.s V_4 + .try + { + IL_0088: nop + IL_0089: ldstr "L" + IL_008e: call "void System.Console.Write(string)" + IL_0093: nop + IL_0094: nop + IL_0095: leave.s IL_00a4 + } + finally + { + IL_0097: ldloc.0 + IL_0098: ldc.i4.0 + IL_0099: bge.s IL_00a3 + IL_009b: ldloca.s V_4 + IL_009d: call "void System.Threading.Lock.Scope.Dispose()" + IL_00a2: nop + IL_00a3: endfinally + } + IL_00a4: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_00a9: stloc.2 + IL_00aa: ldloca.s V_2 + IL_00ac: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_00b1: stloc.s V_5 + IL_00b3: ldloca.s V_5 + IL_00b5: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_00ba: brtrue.s IL_00fe + IL_00bc: ldarg.0 + IL_00bd: ldc.i4.1 + IL_00be: dup + IL_00bf: stloc.0 + IL_00c0: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_00c5: ldarg.0 + IL_00c6: ldloc.s V_5 + IL_00c8: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<
$>g__local|0_0>d.<>u__1" + IL_00cd: ldarg.0 + IL_00ce: stloc.3 + IL_00cf: ldarg.0 + IL_00d0: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<
$>g__local|0_0>d.<>t__builder" + IL_00d5: ldloca.s V_5 + IL_00d7: ldloca.s V_3 + IL_00d9: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted$>g__local|0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<<
$>g__local|0_0>d)" + IL_00de: nop + IL_00df: leave.s IL_0136 + IL_00e1: ldarg.0 + IL_00e2: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<
$>g__local|0_0>d.<>u__1" + IL_00e7: stloc.s V_5 + IL_00e9: ldarg.0 + IL_00ea: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<
$>g__local|0_0>d.<>u__1" + IL_00ef: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_00f5: ldarg.0 + IL_00f6: ldc.i4.m1 + IL_00f7: dup + IL_00f8: stloc.0 + IL_00f9: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_00fe: ldloca.s V_5 + IL_0100: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_0105: nop + IL_0106: leave.s IL_0122 + } + catch System.Exception + { + IL_0108: stloc.s V_6 + IL_010a: ldarg.0 + IL_010b: ldc.i4.s -2 + IL_010d: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_0112: ldarg.0 + IL_0113: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<
$>g__local|0_0>d.<>t__builder" + IL_0118: ldloc.s V_6 + IL_011a: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_011f: nop + IL_0120: leave.s IL_0136 + } + IL_0122: ldarg.0 + IL_0123: ldc.i4.s -2 + IL_0125: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_012a: ldarg.0 + IL_012b: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<
$>g__local|0_0>d.<>t__builder" + IL_0130: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_0135: nop + IL_0136: ret + } + """); + + verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.<<
$>g__local|0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 282 (0x11a) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1, + System.Runtime.CompilerServices.YieldAwaitable V_2, + System.Threading.Lock.Scope V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_004b + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: beq IL_00c8 + IL_0011: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_0016: stloc.2 + IL_0017: ldloca.s V_2 + IL_0019: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_001e: stloc.1 + IL_001f: ldloca.s V_1 + IL_0021: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_0026: brtrue.s IL_0067 + IL_0028: ldarg.0 + IL_0029: ldc.i4.0 + IL_002a: dup + IL_002b: stloc.0 + IL_002c: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_0031: ldarg.0 + IL_0032: ldloc.1 + IL_0033: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<
$>g__local|0_0>d.<>u__1" + IL_0038: ldarg.0 + IL_0039: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<
$>g__local|0_0>d.<>t__builder" + IL_003e: ldloca.s V_1 + IL_0040: ldarg.0 + IL_0041: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted$>g__local|0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<<
$>g__local|0_0>d)" + IL_0046: leave IL_0119 + IL_004b: ldarg.0 + IL_004c: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<
$>g__local|0_0>d.<>u__1" + IL_0051: stloc.1 + IL_0052: ldarg.0 + IL_0053: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<
$>g__local|0_0>d.<>u__1" + IL_0058: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_005e: ldarg.0 + IL_005f: ldc.i4.m1 + IL_0060: dup + IL_0061: stloc.0 + IL_0062: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_0067: ldloca.s V_1 + IL_0069: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_006e: newobj "System.Threading.Lock..ctor()" + IL_0073: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0078: stloc.3 + .try + { + IL_0079: ldstr "L" + IL_007e: call "void System.Console.Write(string)" + IL_0083: leave.s IL_0091 + } + finally + { + IL_0085: ldloc.0 + IL_0086: ldc.i4.0 + IL_0087: bge.s IL_0090 + IL_0089: ldloca.s V_3 + IL_008b: call "void System.Threading.Lock.Scope.Dispose()" + IL_0090: endfinally + } + IL_0091: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_0096: stloc.2 + IL_0097: ldloca.s V_2 + IL_0099: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_009e: stloc.1 + IL_009f: ldloca.s V_1 + IL_00a1: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_00a6: brtrue.s IL_00e4 + IL_00a8: ldarg.0 + IL_00a9: ldc.i4.1 + IL_00aa: dup + IL_00ab: stloc.0 + IL_00ac: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_00b1: ldarg.0 + IL_00b2: ldloc.1 + IL_00b3: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<
$>g__local|0_0>d.<>u__1" + IL_00b8: ldarg.0 + IL_00b9: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<
$>g__local|0_0>d.<>t__builder" + IL_00be: ldloca.s V_1 + IL_00c0: ldarg.0 + IL_00c1: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted$>g__local|0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<<
$>g__local|0_0>d)" + IL_00c6: leave.s IL_0119 + IL_00c8: ldarg.0 + IL_00c9: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<
$>g__local|0_0>d.<>u__1" + IL_00ce: stloc.1 + IL_00cf: ldarg.0 + IL_00d0: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<<
$>g__local|0_0>d.<>u__1" + IL_00d5: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_00db: ldarg.0 + IL_00dc: ldc.i4.m1 + IL_00dd: dup + IL_00de: stloc.0 + IL_00df: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_00e4: ldloca.s V_1 + IL_00e6: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_00eb: leave.s IL_0106 + } + catch System.Exception + { + IL_00ed: stloc.s V_4 + IL_00ef: ldarg.0 + IL_00f0: ldc.i4.s -2 + IL_00f2: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_00f7: ldarg.0 + IL_00f8: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<
$>g__local|0_0>d.<>t__builder" + IL_00fd: ldloc.s V_4 + IL_00ff: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_0104: leave.s IL_0119 + } + IL_0106: ldarg.0 + IL_0107: ldc.i4.s -2 + IL_0109: stfld "int Program.<<
$>g__local|0_0>d.<>1__state" + IL_010e: ldarg.0 + IL_010f: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<
$>g__local|0_0>d.<>t__builder" + IL_0114: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_0119: ret + } + """); } [Fact] @@ -1962,13 +2990,132 @@ public void AsyncLambda() var lam = async () => { - lock (new Lock()) { } + lock (new Lock()) { System.Console.Write("L"); } }; + + await lam(); """; - CreateCompilation([source, LockTypeDefinition]).VerifyDiagnostics( - // (6,11): error CS9217: A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - // lock (new Lock()) { } - Diagnostic(ErrorCode.ERR_BadSpecialByRefLock, "new Lock()").WithLocation(6, 11)); + var expectedOutput = "ELD"; + var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.<>c.<<
$>b__0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 94 (0x5e) + .maxstack 2 + .locals init (int V_0, + System.Threading.Lock.Scope V_1, + System.Exception V_2) + IL_0000: ldarg.0 + IL_0001: ldfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: nop + IL_0008: newobj "System.Threading.Lock..ctor()" + IL_000d: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0012: stloc.1 + .try + { + IL_0013: nop + IL_0014: ldstr "L" + IL_0019: call "void System.Console.Write(string)" + IL_001e: nop + IL_001f: nop + IL_0020: leave.s IL_002f + } + finally + { + IL_0022: ldloc.0 + IL_0023: ldc.i4.0 + IL_0024: bge.s IL_002e + IL_0026: ldloca.s V_1 + IL_0028: call "void System.Threading.Lock.Scope.Dispose()" + IL_002d: nop + IL_002e: endfinally + } + IL_002f: leave.s IL_0049 + } + catch System.Exception + { + IL_0031: stloc.2 + IL_0032: ldarg.0 + IL_0033: ldc.i4.s -2 + IL_0035: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_003a: ldarg.0 + IL_003b: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<
$>b__0_0>d.<>t__builder" + IL_0040: ldloc.2 + IL_0041: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_0046: nop + IL_0047: leave.s IL_005d + } + IL_0049: ldarg.0 + IL_004a: ldc.i4.s -2 + IL_004c: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_0051: ldarg.0 + IL_0052: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<
$>b__0_0>d.<>t__builder" + IL_0057: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_005c: nop + IL_005d: ret + } + """); + + verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.<>c.<<
$>b__0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 87 (0x57) + .maxstack 2 + .locals init (int V_0, + System.Threading.Lock.Scope V_1, + System.Exception V_2) + IL_0000: ldarg.0 + IL_0001: ldfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: newobj "System.Threading.Lock..ctor()" + IL_000c: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0011: stloc.1 + .try + { + IL_0012: ldstr "L" + IL_0017: call "void System.Console.Write(string)" + IL_001c: leave.s IL_002a + } + finally + { + IL_001e: ldloc.0 + IL_001f: ldc.i4.0 + IL_0020: bge.s IL_0029 + IL_0022: ldloca.s V_1 + IL_0024: call "void System.Threading.Lock.Scope.Dispose()" + IL_0029: endfinally + } + IL_002a: leave.s IL_0043 + } + catch System.Exception + { + IL_002c: stloc.2 + IL_002d: ldarg.0 + IL_002e: ldc.i4.s -2 + IL_0030: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_0035: ldarg.0 + IL_0036: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<
$>b__0_0>d.<>t__builder" + IL_003b: ldloc.2 + IL_003c: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_0041: leave.s IL_0056 + } + IL_0043: ldarg.0 + IL_0044: ldc.i4.s -2 + IL_0046: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_004b: ldarg.0 + IL_004c: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<
$>b__0_0>d.<>t__builder" + IL_0051: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_0056: ret + } + """); } [Fact] @@ -1981,13 +3128,301 @@ public void AsyncLambda_WithAwait() var lam = async () => { await Task.Yield(); - lock (new Lock()) { } + lock (new Lock()) { System.Console.Write("L"); } + await Task.Yield(); }; + + await lam(); """; - CreateCompilation([source, LockTypeDefinition]).VerifyDiagnostics( - // (7,11): error CS9217: A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. - // lock (new Lock()) { } - Diagnostic(ErrorCode.ERR_BadSpecialByRefLock, "new Lock()").WithLocation(7, 11)); + var expectedOutput = "ELD"; + var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.<>c.<<
$>b__0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 311 (0x137) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1, + System.Runtime.CompilerServices.YieldAwaitable V_2, + Program.<>c.<<
$>b__0_0>d V_3, + System.Threading.Lock.Scope V_4, + System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_5, + System.Exception V_6) + IL_0000: ldarg.0 + IL_0001: ldfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: beq.s IL_0014 + IL_0010: br.s IL_0019 + IL_0012: br.s IL_0058 + IL_0014: br IL_00e1 + IL_0019: nop + IL_001a: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_001f: stloc.2 + IL_0020: ldloca.s V_2 + IL_0022: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_0027: stloc.1 + IL_0028: ldloca.s V_1 + IL_002a: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_002f: brtrue.s IL_0074 + IL_0031: ldarg.0 + IL_0032: ldc.i4.0 + IL_0033: dup + IL_0034: stloc.0 + IL_0035: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_003a: ldarg.0 + IL_003b: ldloc.1 + IL_003c: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<
$>b__0_0>d.<>u__1" + IL_0041: ldarg.0 + IL_0042: stloc.3 + IL_0043: ldarg.0 + IL_0044: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<
$>b__0_0>d.<>t__builder" + IL_0049: ldloca.s V_1 + IL_004b: ldloca.s V_3 + IL_004d: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedc.<<
$>b__0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<>c.<<
$>b__0_0>d)" + IL_0052: nop + IL_0053: leave IL_0136 + IL_0058: ldarg.0 + IL_0059: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<
$>b__0_0>d.<>u__1" + IL_005e: stloc.1 + IL_005f: ldarg.0 + IL_0060: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<
$>b__0_0>d.<>u__1" + IL_0065: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_006b: ldarg.0 + IL_006c: ldc.i4.m1 + IL_006d: dup + IL_006e: stloc.0 + IL_006f: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_0074: ldloca.s V_1 + IL_0076: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_007b: nop + IL_007c: newobj "System.Threading.Lock..ctor()" + IL_0081: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0086: stloc.s V_4 + .try + { + IL_0088: nop + IL_0089: ldstr "L" + IL_008e: call "void System.Console.Write(string)" + IL_0093: nop + IL_0094: nop + IL_0095: leave.s IL_00a4 + } + finally + { + IL_0097: ldloc.0 + IL_0098: ldc.i4.0 + IL_0099: bge.s IL_00a3 + IL_009b: ldloca.s V_4 + IL_009d: call "void System.Threading.Lock.Scope.Dispose()" + IL_00a2: nop + IL_00a3: endfinally + } + IL_00a4: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_00a9: stloc.2 + IL_00aa: ldloca.s V_2 + IL_00ac: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_00b1: stloc.s V_5 + IL_00b3: ldloca.s V_5 + IL_00b5: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_00ba: brtrue.s IL_00fe + IL_00bc: ldarg.0 + IL_00bd: ldc.i4.1 + IL_00be: dup + IL_00bf: stloc.0 + IL_00c0: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_00c5: ldarg.0 + IL_00c6: ldloc.s V_5 + IL_00c8: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<
$>b__0_0>d.<>u__1" + IL_00cd: ldarg.0 + IL_00ce: stloc.3 + IL_00cf: ldarg.0 + IL_00d0: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<
$>b__0_0>d.<>t__builder" + IL_00d5: ldloca.s V_5 + IL_00d7: ldloca.s V_3 + IL_00d9: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedc.<<
$>b__0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<>c.<<
$>b__0_0>d)" + IL_00de: nop + IL_00df: leave.s IL_0136 + IL_00e1: ldarg.0 + IL_00e2: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<
$>b__0_0>d.<>u__1" + IL_00e7: stloc.s V_5 + IL_00e9: ldarg.0 + IL_00ea: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<
$>b__0_0>d.<>u__1" + IL_00ef: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_00f5: ldarg.0 + IL_00f6: ldc.i4.m1 + IL_00f7: dup + IL_00f8: stloc.0 + IL_00f9: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_00fe: ldloca.s V_5 + IL_0100: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_0105: nop + IL_0106: leave.s IL_0122 + } + catch System.Exception + { + IL_0108: stloc.s V_6 + IL_010a: ldarg.0 + IL_010b: ldc.i4.s -2 + IL_010d: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_0112: ldarg.0 + IL_0113: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<
$>b__0_0>d.<>t__builder" + IL_0118: ldloc.s V_6 + IL_011a: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_011f: nop + IL_0120: leave.s IL_0136 + } + IL_0122: ldarg.0 + IL_0123: ldc.i4.s -2 + IL_0125: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_012a: ldarg.0 + IL_012b: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<
$>b__0_0>d.<>t__builder" + IL_0130: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_0135: nop + IL_0136: ret + } + """); + + verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe, + expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.<>c.<<
$>b__0_0>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 282 (0x11a) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_1, + System.Runtime.CompilerServices.YieldAwaitable V_2, + System.Threading.Lock.Scope V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_004b + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: beq IL_00c8 + IL_0011: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_0016: stloc.2 + IL_0017: ldloca.s V_2 + IL_0019: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_001e: stloc.1 + IL_001f: ldloca.s V_1 + IL_0021: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_0026: brtrue.s IL_0067 + IL_0028: ldarg.0 + IL_0029: ldc.i4.0 + IL_002a: dup + IL_002b: stloc.0 + IL_002c: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_0031: ldarg.0 + IL_0032: ldloc.1 + IL_0033: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<
$>b__0_0>d.<>u__1" + IL_0038: ldarg.0 + IL_0039: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<
$>b__0_0>d.<>t__builder" + IL_003e: ldloca.s V_1 + IL_0040: ldarg.0 + IL_0041: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedc.<<
$>b__0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<>c.<<
$>b__0_0>d)" + IL_0046: leave IL_0119 + IL_004b: ldarg.0 + IL_004c: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<
$>b__0_0>d.<>u__1" + IL_0051: stloc.1 + IL_0052: ldarg.0 + IL_0053: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<
$>b__0_0>d.<>u__1" + IL_0058: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_005e: ldarg.0 + IL_005f: ldc.i4.m1 + IL_0060: dup + IL_0061: stloc.0 + IL_0062: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_0067: ldloca.s V_1 + IL_0069: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_006e: newobj "System.Threading.Lock..ctor()" + IL_0073: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0078: stloc.3 + .try + { + IL_0079: ldstr "L" + IL_007e: call "void System.Console.Write(string)" + IL_0083: leave.s IL_0091 + } + finally + { + IL_0085: ldloc.0 + IL_0086: ldc.i4.0 + IL_0087: bge.s IL_0090 + IL_0089: ldloca.s V_3 + IL_008b: call "void System.Threading.Lock.Scope.Dispose()" + IL_0090: endfinally + } + IL_0091: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_0096: stloc.2 + IL_0097: ldloca.s V_2 + IL_0099: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_009e: stloc.1 + IL_009f: ldloca.s V_1 + IL_00a1: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_00a6: brtrue.s IL_00e4 + IL_00a8: ldarg.0 + IL_00a9: ldc.i4.1 + IL_00aa: dup + IL_00ab: stloc.0 + IL_00ac: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_00b1: ldarg.0 + IL_00b2: ldloc.1 + IL_00b3: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<
$>b__0_0>d.<>u__1" + IL_00b8: ldarg.0 + IL_00b9: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<
$>b__0_0>d.<>t__builder" + IL_00be: ldloca.s V_1 + IL_00c0: ldarg.0 + IL_00c1: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedc.<<
$>b__0_0>d>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.<>c.<<
$>b__0_0>d)" + IL_00c6: leave.s IL_0119 + IL_00c8: ldarg.0 + IL_00c9: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<
$>b__0_0>d.<>u__1" + IL_00ce: stloc.1 + IL_00cf: ldarg.0 + IL_00d0: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.<>c.<<
$>b__0_0>d.<>u__1" + IL_00d5: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_00db: ldarg.0 + IL_00dc: ldc.i4.m1 + IL_00dd: dup + IL_00de: stloc.0 + IL_00df: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_00e4: ldloca.s V_1 + IL_00e6: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_00eb: leave.s IL_0106 + } + catch System.Exception + { + IL_00ed: stloc.s V_4 + IL_00ef: ldarg.0 + IL_00f0: ldc.i4.s -2 + IL_00f2: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_00f7: ldarg.0 + IL_00f8: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<
$>b__0_0>d.<>t__builder" + IL_00fd: ldloc.s V_4 + IL_00ff: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_0104: leave.s IL_0119 + } + IL_0106: ldarg.0 + IL_0107: ldc.i4.s -2 + IL_0109: stfld "int Program.<>c.<<
$>b__0_0>d.<>1__state" + IL_010e: ldarg.0 + IL_010f: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<>c.<<
$>b__0_0>d.<>t__builder" + IL_0114: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_0119: ret + } + """); } [Fact] @@ -2011,9 +3446,93 @@ IEnumerable M() } """; CreateCompilation([source, LockTypeDefinition]).VerifyEmitDiagnostics( - // (9,15): error CS4013: Instance of type 'Lock.Scope' cannot be used inside a nested function, query expression, iterator block or async method + // (9,15): error CS4007: Instance of type 'System.Threading.Lock.Scope' cannot be preserved across 'await' or 'yield' boundary. // lock (new Lock()) - Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "new Lock()").WithArguments("System.Threading.Lock.Scope").WithLocation(9, 15)); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new Lock()").WithArguments("System.Threading.Lock.Scope").WithLocation(9, 15), + // (11,13): warning CS9237: 'yield return' should not be used in the body of a lock statement + // yield return 2; + Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(11, 13)); + } + + [Fact] + public void Yield_Break() + { + var source = """ + #pragma warning disable CS0162 // Unreachable code detected + using System; + using System.Collections.Generic; + using System.Threading; + + static class Program + { + static void Main() + { + foreach (var x in M()) + { + Console.Write(x); + } + } + + static IEnumerable M() + { + yield return 1; + lock (new Lock()) + { + Console.Write("L"); + yield break; + Console.Write("B"); + } + yield return 2; + } + } + """; + var expectedOutput = "1ELD"; + var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe, + verify: Verification.FailsILVerify, expectedOutput: expectedOutput); + verifier.VerifyDiagnostics(); + + verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe, + verify: Verification.FailsILVerify, expectedOutput: expectedOutput); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void Yield_AroundOnly() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading; + + static class Program + { + static void Main() + { + foreach (var x in M()) + { + Console.Write(x); + } + } + + static IEnumerable M() + { + yield return 1; + lock (new Lock()) + { + Console.Write("L"); + } + yield return 2; + } + } + """; + var expectedOutput = "1ELD2"; + var verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.ReleaseExe, + verify: Verification.FailsILVerify, expectedOutput: expectedOutput); + verifier.VerifyDiagnostics(); + + verifier = CompileAndVerify([source, LockTypeDefinition], options: TestOptions.DebugExe, + verify: Verification.FailsILVerify, expectedOutput: expectedOutput); + verifier.VerifyDiagnostics(); } [Fact] @@ -2038,10 +3557,455 @@ async IAsyncEnumerable M() } } """; - CreateCompilationWithTasksExtensions([source, LockTypeDefinition, AsyncStreamsTypes]).VerifyDiagnostics( - // (10,15): error CS9217: A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions. + CreateCompilationWithTasksExtensions([source, LockTypeDefinition, AsyncStreamsTypes]).VerifyEmitDiagnostics( + // (10,15): error CS4007: Instance of type 'System.Threading.Lock.Scope' cannot be preserved across 'await' or 'yield' boundary. // lock (new Lock()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefLock, "new Lock()").WithLocation(10, 15)); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new Lock()").WithArguments("System.Threading.Lock.Scope").WithLocation(10, 15), + // (12,13): warning CS9237: 'yield return' should not be used in the body of a lock statement + // yield return 2; + Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(12, 13)); + } + + [Fact] + public void Yield_Async_Break() + { + var source = """ + #pragma warning disable CS0162 // Unreachable code detected + using System; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + static class Program + { + static async Task Main() + { + await foreach (var x in M()) + { + Console.Write(x); + } + } + + async static IAsyncEnumerable M() + { + yield return 1; + await Task.Yield(); + lock (new Lock()) + { + Console.Write("L"); + yield break; + Console.Write("B"); + } + await Task.Yield(); + yield return 2; + } + } + """; + var expectedOutput = "1ELD"; + var comp = CreateCompilationWithTasksExtensions([source, LockTypeDefinition, AsyncStreamsTypes], options: TestOptions.ReleaseExe); + var verifier = CompileAndVerify(comp, verify: Verification.FailsILVerify, expectedOutput: expectedOutput); + verifier.VerifyDiagnostics(); + + comp = CreateCompilationWithTasksExtensions([source, LockTypeDefinition, AsyncStreamsTypes], options: TestOptions.DebugExe); + verifier = CompileAndVerify(comp, verify: Verification.FailsILVerify, expectedOutput: expectedOutput); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void Yield_Async_AroundOnly() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + + static class Program + { + static async Task Main() + { + await foreach (var x in M()) + { + Console.Write(x); + } + } + + static async IAsyncEnumerable M() + { + yield return 1; + lock (new Lock()) + { + Console.Write("L"); + } + await Task.Yield(); + yield return 2; + } + } + """; + var expectedOutput = "1ELD2"; + var comp = CreateCompilationWithTasksExtensions([source, LockTypeDefinition, AsyncStreamsTypes], options: TestOptions.DebugExe); + var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 414 (0x19e) + .maxstack 3 + .locals init (int V_0, + System.Threading.Lock.Scope V_1, + System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_2, + System.Runtime.CompilerServices.YieldAwaitable V_3, + Program.d__1 V_4, + System.Exception V_5) + IL_0000: ldarg.0 + IL_0001: ldfld "int Program.d__1.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: ldc.i4.s -5 + IL_000a: sub + IL_000b: switch ( + IL_002a, + IL_002f, + IL_0031, + IL_0038, + IL_0038, + IL_0033) + IL_0028: br.s IL_0038 + IL_002a: br IL_0125 + IL_002f: br.s IL_0065 + IL_0031: br.s IL_0038 + IL_0033: br IL_00ee + IL_0038: ldarg.0 + IL_0039: ldfld "bool Program.d__1.<>w__disposeMode" + IL_003e: brfalse.s IL_0045 + IL_0040: leave IL_0167 + IL_0045: ldarg.0 + IL_0046: ldc.i4.m1 + IL_0047: dup + IL_0048: stloc.0 + IL_0049: stfld "int Program.d__1.<>1__state" + IL_004e: nop + IL_004f: ldarg.0 + IL_0050: ldc.i4.1 + IL_0051: stfld "int Program.d__1.<>2__current" + IL_0056: ldarg.0 + IL_0057: ldc.i4.s -4 + IL_0059: dup + IL_005a: stloc.0 + IL_005b: stfld "int Program.d__1.<>1__state" + IL_0060: leave IL_0190 + IL_0065: ldarg.0 + IL_0066: ldc.i4.m1 + IL_0067: dup + IL_0068: stloc.0 + IL_0069: stfld "int Program.d__1.<>1__state" + IL_006e: ldarg.0 + IL_006f: ldfld "bool Program.d__1.<>w__disposeMode" + IL_0074: brfalse.s IL_007b + IL_0076: leave IL_0167 + IL_007b: newobj "System.Threading.Lock..ctor()" + IL_0080: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0085: stloc.1 + .try + { + IL_0086: nop + IL_0087: ldstr "L" + IL_008c: call "void System.Console.Write(string)" + IL_0091: nop + IL_0092: nop + IL_0093: leave.s IL_00a2 + } + finally + { + IL_0095: ldloc.0 + IL_0096: ldc.i4.m1 + IL_0097: bne.un.s IL_00a1 + IL_0099: ldloca.s V_1 + IL_009b: call "void System.Threading.Lock.Scope.Dispose()" + IL_00a0: nop + IL_00a1: endfinally + } + IL_00a2: ldarg.0 + IL_00a3: ldfld "bool Program.d__1.<>w__disposeMode" + IL_00a8: brfalse.s IL_00af + IL_00aa: leave IL_0167 + IL_00af: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_00b4: stloc.3 + IL_00b5: ldloca.s V_3 + IL_00b7: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_00bc: stloc.2 + IL_00bd: ldloca.s V_2 + IL_00bf: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_00c4: brtrue.s IL_010a + IL_00c6: ldarg.0 + IL_00c7: ldc.i4.0 + IL_00c8: dup + IL_00c9: stloc.0 + IL_00ca: stfld "int Program.d__1.<>1__state" + IL_00cf: ldarg.0 + IL_00d0: ldloc.2 + IL_00d1: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.d__1.<>u__1" + IL_00d6: ldarg.0 + IL_00d7: stloc.s V_4 + IL_00d9: ldarg.0 + IL_00da: ldflda "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder Program.d__1.<>t__builder" + IL_00df: ldloca.s V_2 + IL_00e1: ldloca.s V_4 + IL_00e3: call "void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.d__1)" + IL_00e8: nop + IL_00e9: leave IL_019d + IL_00ee: ldarg.0 + IL_00ef: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.d__1.<>u__1" + IL_00f4: stloc.2 + IL_00f5: ldarg.0 + IL_00f6: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.d__1.<>u__1" + IL_00fb: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_0101: ldarg.0 + IL_0102: ldc.i4.m1 + IL_0103: dup + IL_0104: stloc.0 + IL_0105: stfld "int Program.d__1.<>1__state" + IL_010a: ldloca.s V_2 + IL_010c: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_0111: nop + IL_0112: ldarg.0 + IL_0113: ldc.i4.2 + IL_0114: stfld "int Program.d__1.<>2__current" + IL_0119: ldarg.0 + IL_011a: ldc.i4.s -5 + IL_011c: dup + IL_011d: stloc.0 + IL_011e: stfld "int Program.d__1.<>1__state" + IL_0123: leave.s IL_0190 + IL_0125: ldarg.0 + IL_0126: ldc.i4.m1 + IL_0127: dup + IL_0128: stloc.0 + IL_0129: stfld "int Program.d__1.<>1__state" + IL_012e: ldarg.0 + IL_012f: ldfld "bool Program.d__1.<>w__disposeMode" + IL_0134: brfalse.s IL_0138 + IL_0136: leave.s IL_0167 + IL_0138: leave.s IL_0167 + } + catch System.Exception + { + IL_013a: stloc.s V_5 + IL_013c: ldarg.0 + IL_013d: ldc.i4.s -2 + IL_013f: stfld "int Program.d__1.<>1__state" + IL_0144: ldarg.0 + IL_0145: ldc.i4.0 + IL_0146: stfld "int Program.d__1.<>2__current" + IL_014b: ldarg.0 + IL_014c: ldflda "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder Program.d__1.<>t__builder" + IL_0151: call "void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()" + IL_0156: nop + IL_0157: ldarg.0 + IL_0158: ldflda "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore Program.d__1.<>v__promiseOfValueOrEnd" + IL_015d: ldloc.s V_5 + IL_015f: call "void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)" + IL_0164: nop + IL_0165: leave.s IL_019d + } + IL_0167: ldarg.0 + IL_0168: ldc.i4.s -2 + IL_016a: stfld "int Program.d__1.<>1__state" + IL_016f: ldarg.0 + IL_0170: ldc.i4.0 + IL_0171: stfld "int Program.d__1.<>2__current" + IL_0176: ldarg.0 + IL_0177: ldflda "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder Program.d__1.<>t__builder" + IL_017c: call "void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()" + IL_0181: nop + IL_0182: ldarg.0 + IL_0183: ldflda "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore Program.d__1.<>v__promiseOfValueOrEnd" + IL_0188: ldc.i4.0 + IL_0189: call "void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)" + IL_018e: nop + IL_018f: ret + IL_0190: ldarg.0 + IL_0191: ldflda "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore Program.d__1.<>v__promiseOfValueOrEnd" + IL_0196: ldc.i4.1 + IL_0197: call "void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)" + IL_019c: nop + IL_019d: ret + } + """); + + comp = CreateCompilationWithTasksExtensions([source, LockTypeDefinition, AsyncStreamsTypes], options: TestOptions.ReleaseExe); + verifier = CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 383 (0x17f) + .maxstack 3 + .locals init (int V_0, + System.Threading.Lock.Scope V_1, + System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_2, + System.Runtime.CompilerServices.YieldAwaitable V_3, + Program.d__1 V_4, + System.Exception V_5) + IL_0000: ldarg.0 + IL_0001: ldfld "int Program.d__1.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: ldc.i4.s -5 + IL_000a: sub + IL_000b: switch ( + IL_010e, + IL_0054, + IL_0028, + IL_0028, + IL_0028, + IL_00d8) + IL_0028: ldarg.0 + IL_0029: ldfld "bool Program.d__1.<>w__disposeMode" + IL_002e: brfalse.s IL_0035 + IL_0030: leave IL_014b + IL_0035: ldarg.0 + IL_0036: ldc.i4.m1 + IL_0037: dup + IL_0038: stloc.0 + IL_0039: stfld "int Program.d__1.<>1__state" + IL_003e: ldarg.0 + IL_003f: ldc.i4.1 + IL_0040: stfld "int Program.d__1.<>2__current" + IL_0045: ldarg.0 + IL_0046: ldc.i4.s -4 + IL_0048: dup + IL_0049: stloc.0 + IL_004a: stfld "int Program.d__1.<>1__state" + IL_004f: leave IL_0172 + IL_0054: ldarg.0 + IL_0055: ldc.i4.m1 + IL_0056: dup + IL_0057: stloc.0 + IL_0058: stfld "int Program.d__1.<>1__state" + IL_005d: ldarg.0 + IL_005e: ldfld "bool Program.d__1.<>w__disposeMode" + IL_0063: brfalse.s IL_006a + IL_0065: leave IL_014b + IL_006a: newobj "System.Threading.Lock..ctor()" + IL_006f: call "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0074: stloc.1 + .try + { + IL_0075: ldstr "L" + IL_007a: call "void System.Console.Write(string)" + IL_007f: leave.s IL_008d + } + finally + { + IL_0081: ldloc.0 + IL_0082: ldc.i4.m1 + IL_0083: bne.un.s IL_008c + IL_0085: ldloca.s V_1 + IL_0087: call "void System.Threading.Lock.Scope.Dispose()" + IL_008c: endfinally + } + IL_008d: ldarg.0 + IL_008e: ldfld "bool Program.d__1.<>w__disposeMode" + IL_0093: brfalse.s IL_009a + IL_0095: leave IL_014b + IL_009a: call "System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()" + IL_009f: stloc.3 + IL_00a0: ldloca.s V_3 + IL_00a2: call "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()" + IL_00a7: stloc.2 + IL_00a8: ldloca.s V_2 + IL_00aa: call "bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get" + IL_00af: brtrue.s IL_00f4 + IL_00b1: ldarg.0 + IL_00b2: ldc.i4.0 + IL_00b3: dup + IL_00b4: stloc.0 + IL_00b5: stfld "int Program.d__1.<>1__state" + IL_00ba: ldarg.0 + IL_00bb: ldloc.2 + IL_00bc: stfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.d__1.<>u__1" + IL_00c1: ldarg.0 + IL_00c2: stloc.s V_4 + IL_00c4: ldarg.0 + IL_00c5: ldflda "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder Program.d__1.<>t__builder" + IL_00ca: ldloca.s V_2 + IL_00cc: ldloca.s V_4 + IL_00ce: call "void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref Program.d__1)" + IL_00d3: leave IL_017e + IL_00d8: ldarg.0 + IL_00d9: ldfld "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.d__1.<>u__1" + IL_00de: stloc.2 + IL_00df: ldarg.0 + IL_00e0: ldflda "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter Program.d__1.<>u__1" + IL_00e5: initobj "System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter" + IL_00eb: ldarg.0 + IL_00ec: ldc.i4.m1 + IL_00ed: dup + IL_00ee: stloc.0 + IL_00ef: stfld "int Program.d__1.<>1__state" + IL_00f4: ldloca.s V_2 + IL_00f6: call "void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()" + IL_00fb: ldarg.0 + IL_00fc: ldc.i4.2 + IL_00fd: stfld "int Program.d__1.<>2__current" + IL_0102: ldarg.0 + IL_0103: ldc.i4.s -5 + IL_0105: dup + IL_0106: stloc.0 + IL_0107: stfld "int Program.d__1.<>1__state" + IL_010c: leave.s IL_0172 + IL_010e: ldarg.0 + IL_010f: ldc.i4.m1 + IL_0110: dup + IL_0111: stloc.0 + IL_0112: stfld "int Program.d__1.<>1__state" + IL_0117: ldarg.0 + IL_0118: ldfld "bool Program.d__1.<>w__disposeMode" + IL_011d: pop + IL_011e: leave.s IL_014b + } + catch System.Exception + { + IL_0120: stloc.s V_5 + IL_0122: ldarg.0 + IL_0123: ldc.i4.s -2 + IL_0125: stfld "int Program.d__1.<>1__state" + IL_012a: ldarg.0 + IL_012b: ldc.i4.0 + IL_012c: stfld "int Program.d__1.<>2__current" + IL_0131: ldarg.0 + IL_0132: ldflda "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder Program.d__1.<>t__builder" + IL_0137: call "void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()" + IL_013c: ldarg.0 + IL_013d: ldflda "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore Program.d__1.<>v__promiseOfValueOrEnd" + IL_0142: ldloc.s V_5 + IL_0144: call "void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)" + IL_0149: leave.s IL_017e + } + IL_014b: ldarg.0 + IL_014c: ldc.i4.s -2 + IL_014e: stfld "int Program.d__1.<>1__state" + IL_0153: ldarg.0 + IL_0154: ldc.i4.0 + IL_0155: stfld "int Program.d__1.<>2__current" + IL_015a: ldarg.0 + IL_015b: ldflda "System.Runtime.CompilerServices.AsyncIteratorMethodBuilder Program.d__1.<>t__builder" + IL_0160: call "void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()" + IL_0165: ldarg.0 + IL_0166: ldflda "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore Program.d__1.<>v__promiseOfValueOrEnd" + IL_016b: ldc.i4.0 + IL_016c: call "void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)" + IL_0171: ret + IL_0172: ldarg.0 + IL_0173: ldflda "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore Program.d__1.<>v__promiseOfValueOrEnd" + IL_0178: ldc.i4.1 + IL_0179: call "void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)" + IL_017e: ret + } + """); } [Theory, CombinatorialData] diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/OutVarTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/OutVarTests.cs index 1c2c8c2f59050..213a94c3598ea 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/OutVarTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/OutVarTests.cs @@ -19581,9 +19581,9 @@ static void Test2(object x, System.ArgIterator y) // (11,25): error CS1601: Cannot make reference to variable of type 'ArgIterator' // static object Test1(out System.ArgIterator x) Diagnostic(ErrorCode.ERR_MethodArgCantBeRefAny, "out System.ArgIterator x").WithArguments("System.ArgIterator").WithLocation(11, 25), - // (8,25): error CS4012: Parameters or locals of type 'ArgIterator' cannot be declared in async methods or async lambda expressions. + // (8,25): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // Test2(Test1(out var x1), x1); - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "var").WithArguments("System.ArgIterator").WithLocation(8, 25), + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 25), // (6,16): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. // async void Test() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Test").WithLocation(6, 16) @@ -19630,12 +19630,12 @@ static void Test2(object x, System.ArgIterator y) // (12,25): error CS1601: Cannot make reference to variable of type 'ArgIterator' // static object Test1(out System.ArgIterator x) Diagnostic(ErrorCode.ERR_MethodArgCantBeRefAny, "out System.ArgIterator x").WithArguments("System.ArgIterator").WithLocation(12, 25), - // (8,25): error CS4012: Parameters or locals of type 'ArgIterator' cannot be declared in async methods or async lambda expressions. + // (8,25): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // Test2(Test1(out System.ArgIterator x1), x1); - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(8, 25), - // (9,9): error CS4012: Parameters or locals of type 'ArgIterator' cannot be declared in async methods or async lambda expressions. + Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.ArgIterator").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 25), + // (9,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // var x = default(System.ArgIterator); - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "var").WithArguments("System.ArgIterator").WithLocation(9, 9), + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 9), // (9,13): warning CS0219: The variable 'x' is assigned but its value is never used // var x = default(System.ArgIterator); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(9, 13), diff --git a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs index 5b8b68abbd7b0..a582a8a14aa22 100644 --- a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs @@ -11305,9 +11305,10 @@ static async Task Main() var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( + // PROTOTYPE(RefStructInterfaces): follow up on recent changes due to https://github.com/dotnet/csharplang/blob/main/proposals/ref-unsafe-in-iterators-async.md // (18,22): error CS9104: A using statement resource of type 'S2' cannot be used in async methods or async lambda expressions. // await using (new S2()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefUsing, "new S2()").WithArguments("S2").WithLocation(18, 22) + //Diagnostic(ErrorCode.ERR_BadSpecialByRefUsing, "new S2()").WithArguments("S2").WithLocation(18, 22) ); } @@ -11341,9 +11342,10 @@ static async Task Main() var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( + // PROTOTYPE(RefStructInterfaces): follow up on recent changes due to https://github.com/dotnet/csharplang/blob/main/proposals/ref-unsafe-in-iterators-async.md // (18,22): error CS9104: A using statement resource of type 'S2' cannot be used in async methods or async lambda expressions. // await using (new S2()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefUsing, "new S2()").WithArguments("S2").WithLocation(18, 22) + //Diagnostic(ErrorCode.ERR_BadSpecialByRefUsing, "new S2()").WithArguments("S2").WithLocation(18, 22) ); } @@ -11382,9 +11384,10 @@ static async Task Main() var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( + // PROTOTYPE(RefStructInterfaces): follow up on recent changes due to https://github.com/dotnet/csharplang/blob/main/proposals/ref-unsafe-in-iterators-async.md // (23,22): error CS9104: A using statement resource of type 'T' cannot be used in async methods or async lambda expressions. // await using (new T()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefUsing, "new T()").WithArguments("T").WithLocation(23, 22) + //Diagnostic(ErrorCode.ERR_BadSpecialByRefUsing, "new T()").WithArguments("T").WithLocation(23, 22) ); } @@ -11427,9 +11430,10 @@ static async Task Main() var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); comp.VerifyDiagnostics( + // PROTOTYPE(RefStructInterfaces): follow up on recent changes due to https://github.com/dotnet/csharplang/blob/main/proposals/ref-unsafe-in-iterators-async.md // (27,22): error CS9104: A using statement resource of type 'T' cannot be used in async methods or async lambda expressions. // await using (new T()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefUsing, "new T()").WithArguments("T").WithLocation(27, 22) + //Diagnostic(ErrorCode.ERR_BadSpecialByRefUsing, "new T()").WithArguments("T").WithLocation(27, 22) ); } @@ -11482,10 +11486,12 @@ static async Task Main() Diagnostic(ErrorCode.ERR_AmbigCall, "new T()").WithArguments("IMyAsyncDisposable1.DisposeAsync()", "IMyAsyncDisposable2.DisposeAsync()").WithLocation(32, 22), // (32,22): error CS8410: 'T': type used in an asynchronous using statement must be implicitly convertible to 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. // await using (new T()) - Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "new T()").WithArguments("T").WithLocation(32, 22), + Diagnostic(ErrorCode.ERR_NoConvToIAsyncDisp, "new T()").WithArguments("T").WithLocation(32, 22) + // PROTOTYPE(RefStructInterfaces): follow up on recent changes due to https://github.com/dotnet/csharplang/blob/main/proposals/ref-unsafe-in-iterators-async.md + //, // (32,22): error CS9104: A using statement resource of type 'T' cannot be used in async methods or async lambda expressions. // await using (new T()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefUsing, "new T()").WithArguments("T").WithLocation(32, 22) + //Diagnostic(ErrorCode.ERR_BadSpecialByRefUsing, "new T()").WithArguments("T").WithLocation(32, 22) ); } @@ -11541,10 +11547,12 @@ static async Task Main() comp.VerifyDiagnostics( // (36,22): error CS0121: The call is ambiguous between the following methods or properties: 'IMyAsyncDisposable1.DisposeAsync()' and 'IMyAsyncDisposable2.DisposeAsync()' // await using (new T()) - Diagnostic(ErrorCode.ERR_AmbigCall, "new T()").WithArguments("IMyAsyncDisposable1.DisposeAsync()", "IMyAsyncDisposable2.DisposeAsync()").WithLocation(36, 22), + Diagnostic(ErrorCode.ERR_AmbigCall, "new T()").WithArguments("IMyAsyncDisposable1.DisposeAsync()", "IMyAsyncDisposable2.DisposeAsync()").WithLocation(36, 22) + // PROTOTYPE(RefStructInterfaces): follow up on recent changes due to https://github.com/dotnet/csharplang/blob/main/proposals/ref-unsafe-in-iterators-async.md + //, // (36,22): error CS9104: A using statement resource of type 'T' cannot be used in async methods or async lambda expressions. // await using (new T()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefUsing, "new T()").WithArguments("T").WithLocation(36, 22) + //Diagnostic(ErrorCode.ERR_BadSpecialByRefUsing, "new T()").WithArguments("T").WithLocation(36, 22) ); } @@ -18513,12 +18521,12 @@ ref struct S var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); comp.VerifyDiagnostics( - // (6,34): error CS4012: Parameters or locals of type 'T' cannot be declared in async methods or async lambda expressions. + // (6,34): error CS4012: Parameters of type 'T' cannot be declared in async methods or async lambda expressions. // static async void Test1(T x) - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "x").WithArguments("T").WithLocation(6, 34), - // (11,31): error CS4012: Parameters or locals of type 'S' cannot be declared in async methods or async lambda expressions. + Diagnostic(ErrorCode.ERR_BadSpecialByRefParameter, "x").WithArguments("T").WithLocation(6, 34), + // (11,31): error CS4012: Parameters of type 'S' cannot be declared in async methods or async lambda expressions. // static async void Test2(S y) - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "y").WithArguments("S").WithLocation(11, 31) + Diagnostic(ErrorCode.ERR_BadSpecialByRefParameter, "y").WithArguments("S").WithLocation(11, 31) ); } diff --git a/src/Compilers/CSharp/Test/Emit3/RefUnsafeInIteratorAndAsyncTests.cs b/src/Compilers/CSharp/Test/Emit3/RefUnsafeInIteratorAndAsyncTests.cs new file mode 100644 index 0000000000000..d3b9880ee2a9d --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit3/RefUnsafeInIteratorAndAsyncTests.cs @@ -0,0 +1,1099 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +public class RefUnsafeInIteratorAndAsyncTests : CSharpTestBase +{ + private static string? IfSpans(string expectedOutput) + => ExecutionConditionUtil.IsDesktop ? null : expectedOutput; + + [Fact] + public void LangVersion_RefLocalInAsync() + { + var source = """ + using System.Threading.Tasks; + class C + { + async Task M(int x) + { + ref int y = ref x; + ref readonly int z = ref y; + await Task.Yield(); + } + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 17), + // (7,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref readonly int z = ref y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "z").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 26)); + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact] + public void LangVersion_RefLocalInIterator() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable M(int x) + { + ref int y = ref x; + ref readonly int z = ref y; + yield return x; + } + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 17), + // (7,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref readonly int z = ref y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "z").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 26)); + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact] + public void LangVersion_RefLocalInIterator_IEnumerator() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerator M(int x) + { + ref int y = ref x; + ref readonly int z = ref y; + yield return x; + } + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 17), + // (7,26): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref readonly int z = ref y; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "z").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 26)); + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact] + public void LangVersion_RefStructInAsync() + { + var source = """ + #pragma warning disable CS0219 // variable unused + using System.Threading.Tasks; + class C + { + async Task M() + { + R y = default; + scoped R z = default; + await Task.Yield(); + } + } + ref struct R { } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // R y = default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "R").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 9), + // (8,16): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // scoped R z = default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "R").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 16)); + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact] + public void LangVersion_RefStructInIterator() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable M(R r) + { + M(r); + yield return -1; + } + } + ref struct R { } + """; + + var expectedDiagnostics = new[] + { + // (6,11): error CS4007: Instance of type 'R' cannot be preserved across 'await' or 'yield' boundary. + // M(r); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "r").WithArguments("R").WithLocation(6, 11) + }; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void LangVersion_RestrictedInAsync() + { + var source = """ + #pragma warning disable CS0219 // variable unused + using System.Threading.Tasks; + class C + { + async Task M() + { + System.TypedReference t = default; + await Task.Yield(); + } + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // System.TypedReference t = default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.TypedReference").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 9)); + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact] + public void LangVersion_RestrictedInIterator() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable M(System.TypedReference t) + { + t.GetHashCode(); + yield return -1; + } + } + """; + + var expectedDiagnostics = new[] + { + // (6,9): error CS4007: Instance of type 'System.TypedReference' cannot be preserved across 'await' or 'yield' boundary. + // t.GetHashCode(); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "t").WithArguments("System.TypedReference").WithLocation(6, 9) + }; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Await_RefLocal_Across() + { + var source = """ + using System.Threading.Tasks; + class C + { + async Task M(int x) + { + ref int y = ref x; + await Task.Yield(); + System.Console.Write(y); + } + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (8,30): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(8, 30)); + } + + [Fact] + public void Await_RefLocal_Across_Reassign() + { + var source = """ + using System.Threading.Tasks; + class C + { + static Task Main() => M(123, 456); + static async Task M(int x, int z) + { + ref int y = ref x; + await Task.Yield(); + y = ref z; + System.Console.Write(y); + } + } + """; + CompileAndVerify(source, expectedOutput: "456").VerifyDiagnostics(); + } + + [Fact] + public void Await_RefLocal_Between() + { + var source = """ + using System.Threading.Tasks; + class C + { + static Task Main() => M(123); + static async Task M(int x) + { + ref int y = ref x; + System.Console.Write(y); + await Task.Yield(); + } + } + """; + CompileAndVerify(source, expectedOutput: "123").VerifyDiagnostics(); + } + + [Fact] + public void Await_RefStruct_Across() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + async Task M(int x) + { + Span y = new(ref x); + await Task.Yield(); + Console.Write(y.ToString()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (9,23): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.ToString()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(9, 23)); + } + + [Fact] + public void Await_RefStruct_Across_Reassign() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static Task Main() => M(123, 456); + static async Task M(int x, int z) + { + Span y = new(ref x); + await Task.Yield(); + y = new(ref z); + Console.Write(y[0]); + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("456"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void Await_RefStruct_Between() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static Task Main() => M(123); + static async Task M(int x) + { + Span y = new(ref x); + Console.Write(y[0]); + await Task.Yield(); + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("123"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void Await_Restricted_Across() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + async Task M() + { + TypedReference y = default; + await Task.Yield(); + Console.Write(y.GetHashCode()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (9,23): error CS4007: Instance of type 'System.TypedReference' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.GetHashCode()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.TypedReference").WithLocation(9, 23)); + } + + [Fact] + public void Await_Restricted_Across_Reassign() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + TypedReference y = default; + await Task.Yield(); + y = default; + Console.Write(y.GetHashCode()); + } + } + """; + CompileAndVerify(source, expectedOutput: "0").VerifyDiagnostics(); + } + + [Fact] + public void Await_Restricted_Between() + { + var source = """ + using System; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + TypedReference y = default; + Console.Write(y.GetHashCode()); + await Task.Yield(); + } + } + """; + CompileAndVerify(source, expectedOutput: "0").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefLocal_Across() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable M(int x) + { + ref int y = ref x; + yield return 1; + System.Console.Write(y); + } + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (8,30): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(8, 30)); + } + + [Fact] + public void YieldReturn_RefLocal_Across_Indexer() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable this[int x] + { + get + { + ref int y = ref x; + yield return 1; + System.Console.Write(y); + } + } + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (10,34): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(10, 34)); + } + + [Fact] + public void YieldReturn_RefLocal_Across_NestedBlock() + { + var source = """ + using System.Collections.Generic; + class C + { + IEnumerable M(int x) + { + ref int y = ref x; + if (x != 0) { yield return 1; } + System.Console.Write(y); + } + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (8,30): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(8, 30)); + } + + [Fact] + public void YieldReturn_RefLocal_Across_Async() + { + var source = """ + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + async IAsyncEnumerable M(int x) + { + ref int y = ref x; + yield return 1; await Task.Yield(); + System.Console.Write(y); + } + } + """ + AsyncStreamsTypes; + CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics( + // (9,30): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // System.Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(9, 30)); + } + + [Fact] + public void YieldReturn_RefLocal_Across_Reassign() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in M(123, 456)) + { + Console.Write(i + " "); + } + } + static IEnumerable M(int x, int z) + { + ref int y = ref x; + yield return -1; + y = ref z; + Console.Write(y); + } + } + """; + CompileAndVerify(source, expectedOutput: "-1 456").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefLocal_Across_Reassign_Indexer() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in new C()[123, 456]) + { + Console.Write(i + " "); + } + } + IEnumerable this[int x, int z] + { + get + { + ref int y = ref x; + yield return -1; + y = ref z; + Console.Write(y); + } + } + } + """; + CompileAndVerify(source, expectedOutput: "-1 456").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefLocal_Across_Reassign_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var i in M(123, 456)) + { + Console.Write(i + " "); + } + } + static async IAsyncEnumerable M(int x, int z) + { + ref int y = ref x; + yield return -1; await Task.Yield(); + y = ref z; + Console.Write(y); + } + } + """ + AsyncStreamsTypes; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "-1 456").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefLocal_Between() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in M(123)) + { + Console.Write(i + " "); + } + } + static IEnumerable M(int x) + { + ref int y = ref x; + Console.Write(y); + yield return -1; + } + } + """; + CompileAndVerify(source, expectedOutput: "123-1").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefLocal_Between_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var i in M(123)) + { + Console.Write(i + " "); + } + } + static async IAsyncEnumerable M(int x) + { + ref int y = ref x; + Console.Write(y); + yield return -1; await Task.Yield(); + } + } + """ + AsyncStreamsTypes; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "123-1").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefStruct_Across() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + IEnumerable M(int x) + { + Span y = new(ref x); + yield return -1; + Console.Write(y.ToString()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (9,23): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.ToString()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(9, 23)); + } + + [Fact] + public void YieldReturn_RefStruct_Across_Indexer() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + IEnumerable this[int x] + { + get + { + Span y = new(ref x); + yield return -1; + Console.Write(y.ToString()); + } + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (11,27): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.ToString()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(11, 27)); + } + + [Fact] + public void YieldReturn_RefStruct_Across_NestedBlock() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + IEnumerable M(int x) + { + Span y = new(ref x); + if (x != 0) { yield return -1; } + Console.Write(y.ToString()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (9,23): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.ToString()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(9, 23)); + } + + [Fact] + public void YieldReturn_RefStruct_Across_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + async IAsyncEnumerable M(int x) + { + Span y = new(ref x); + yield return -1; await Task.Yield(); + Console.Write(y.ToString()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (10,23): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.ToString()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(10, 23)); + } + + [Fact] + public void YieldReturn_RefStruct_Across_Reassign() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in M(123, 456)) + { + Console.Write(i + " "); + } + } + static IEnumerable M(int x, int z) + { + Span y = new(ref x); + yield return -1; + y = new(ref z); + Console.Write(y[0]); + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("-1 456"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefStruct_Across_Reassign_Indexer() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in new C()[123, 456]) + { + Console.Write(i + " "); + } + } + IEnumerable this[int x, int z] + { + get + { + Span y = new(ref x); + yield return -1; + y = new(ref z); + Console.Write(y[0]); + } + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("-1 456"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefStruct_Across_Reassign_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var i in M(123, 456)) + { + Console.Write(i + " "); + } + } + static async IAsyncEnumerable M(int x, int z) + { + Span y = new(ref x); + yield return -1; await Task.Yield(); + y = new(ref z); + Console.Write(y[0]); + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("-1 456"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_RefStruct_Between() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in M(123)) + { + Console.Write(i + " "); + } + } + static IEnumerable M(int x) + { + Span y = new(ref x); + Console.Write(y[0]); + yield return -1; + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("123-1"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_Restricted_Across() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + IEnumerable M() + { + TypedReference y = default; + yield return -1; + Console.Write(y.GetHashCode()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (9,23): error CS4007: Instance of type 'System.TypedReference' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.GetHashCode()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.TypedReference").WithLocation(9, 23)); + } + + [Fact] + public void YieldReturn_Restricted_Across_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + async IAsyncEnumerable M() + { + TypedReference y = default; + yield return -1; await Task.Yield(); + Console.Write(y.GetHashCode()); + } + } + """; + CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (10,23): error CS4007: Instance of type 'System.TypedReference' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y.GetHashCode()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.TypedReference").WithLocation(10, 23)); + } + + [Fact] + public void YieldReturn_Restricted_Across_Reassign() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in M()) + { + Console.Write(i + " "); + } + } + static IEnumerable M() + { + TypedReference y = default; + yield return -1; + y = default; + Console.Write(y.GetHashCode()); + } + } + """; + CompileAndVerify(source, expectedOutput: "-1 0").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_Restricted_Across_Reassign_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var i in M()) + { + Console.Write(i + " "); + } + } + static async IAsyncEnumerable M() + { + TypedReference y = default; + yield return -1; await Task.Yield(); + y = default; + Console.Write(y.GetHashCode()); + } + } + """ + AsyncStreamsTypes; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "-1 0").VerifyDiagnostics(); + } + + [Fact] + public void YieldReturn_Restricted_Between() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var i in M()) + { + Console.Write(i + " "); + } + } + static IEnumerable M() + { + TypedReference y = default; + Console.Write(y.GetHashCode()); + yield return -1; + } + } + """; + CompileAndVerify(source, expectedOutput: "0-1").VerifyDiagnostics(); + } + + [Fact] + public void YieldBreak_RefLocal_Across() + { + var source = """ + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var a in M(10)) { throw null; } + foreach (var b in M(123)) { throw null; } + } + static IEnumerable M(int x) + { + ref int y = ref x; + if (x < 100) yield break; + System.Console.Write(y); + } + } + """; + CompileAndVerify(source, expectedOutput: "123").VerifyDiagnostics(); + } + + [Fact] + public void YieldBreak_RefLocal_Across_Async() + { + var source = """ + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var a in M(10)) { throw null; } + await foreach (var b in M(123)) { throw null; } + } + static async IAsyncEnumerable M(int x) + { + ref int y = ref x; + if (x < 100) { await Task.Yield(); yield break; } + System.Console.Write(y); + } + } + """ + AsyncStreamsTypes; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "123").VerifyDiagnostics(); + } + + [Fact] + public void YieldBreak_RefStruct_Across() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var a in M(10)) { throw null; } + foreach (var b in M(123)) { throw null; } + } + static IEnumerable M(int x) + { + Span y = new(ref x); + if (x < 100) yield break; + Console.Write(y[0]); + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("123"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void YieldBreak_RefStruct_Across_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var a in M(10)) { throw null; } + await foreach (var b in M(123)) { throw null; } + } + static async IAsyncEnumerable M(int x) + { + Span y = new(ref x); + if (x < 100) { await Task.Yield(); yield break; } + Console.Write(y[0]); + } + } + """; + CompileAndVerify(source, expectedOutput: IfSpans("123"), verify: Verification.FailsPEVerify, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + } + + [Fact] + public void YieldBreak_Restricted_Across() + { + var source = """ + using System; + using System.Collections.Generic; + class C + { + static void Main() + { + foreach (var a in M(10)) { throw null; } + foreach (var b in M(123)) { throw null; } + } + static IEnumerable M(int x) + { + TypedReference t = default; + if (x < 100) yield break; + Console.Write(x + t.GetHashCode()); + } + } + """; + CompileAndVerify(source, expectedOutput: "123").VerifyDiagnostics(); + } + + [Fact] + public void YieldBreak_Restricted_Across_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + class C + { + static async Task Main() + { + await foreach (var a in M(10)) { throw null; } + await foreach (var b in M(123)) { throw null; } + } + static async IAsyncEnumerable M(int x) + { + TypedReference t = default; + if (x < 100) { await Task.Yield(); yield break; } + Console.Write(x + t.GetHashCode()); + } + } + """ + AsyncStreamsTypes; + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: "123").VerifyDiagnostics(); + } +} diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/AwaitExpressionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/AwaitExpressionTests.cs index 58b403f3ed35f..0cdb4221d7784 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/AwaitExpressionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/AwaitExpressionTests.cs @@ -241,9 +241,9 @@ static async Task Goo() }"; var comp = CreateCompilationWithMscorlib45(text, options: TestOptions.ReleaseDll); comp.VerifyEmitDiagnostics( - // (8,27): error CS4007: 'await' cannot be used in an expression containing the type 'System.TypedReference' + // (8,27): error CS4007: Instance of type 'System.TypedReference' cannot be preserved across 'await' or 'yield' boundary. // Console.WriteLine(new TypedReference().Equals(await Task.FromResult(0))); - Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await Task.FromResult(0)").WithArguments("System.TypedReference").WithLocation(8, 55)); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "new TypedReference()").WithArguments("System.TypedReference").WithLocation(8, 27)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs index 740346725b17a..8e550a2a565e8 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs @@ -3218,9 +3218,9 @@ async Task M1(TypedReference tr) } }"; CreateCompilationWithMscorlib45(source).VerifyDiagnostics( - // (7,34): error CS4012: Parameters or locals of type 'System.TypedReference' cannot be declared in async methods or async lambda expressions + // (7,34): error CS4012: Parameters of type 'System.TypedReference' cannot be declared in async methods or async lambda expressions // async Task M1(TypedReference tr) - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "tr").WithArguments("System.TypedReference")); + Diagnostic(ErrorCode.ERR_BadSpecialByRefParameter, "tr").WithArguments("System.TypedReference")); } [Fact] @@ -3238,10 +3238,7 @@ async Task M1() await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( - // (9,9): error CS4012: Parameters or locals of type 'System.TypedReference' cannot be declared in async methods or async lambda expressions - // TypedReference tr; - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "TypedReference").WithArguments("System.TypedReference"), + CreateCompilationWithMscorlib45(source).VerifyEmitDiagnostics( // (9,24): warning CS0168: The variable 'tr' is declared but never used // TypedReference tr; Diagnostic(ErrorCode.WRN_UnreferencedVar, "tr").WithArguments("tr")); @@ -3257,18 +3254,33 @@ public void BadSpecialByRefVarDeclLocal() class Test { async Task M1(bool truth) + { + var tr = new TypedReference(); // 1 + await Task.Factory.StartNew(() => { }); + } + + async Task M2(bool truth) { var tr = new TypedReference(); await Task.Factory.StartNew(() => { }); + var tr2 = tr; // 2 + } + + async Task M3() + { + var tr = new TypedReference(); + await Task.Factory.StartNew(() => { }); + tr = default; + var tr2 = tr; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( - // (9,9): error CS4012: Parameters or locals of type 'TypedReference' cannot be declared in async methods or async lambda expressions. - // var tr = new TypedReference(); - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "var").WithArguments("System.TypedReference").WithLocation(9, 9), + CreateCompilationWithMscorlib45(source).VerifyEmitDiagnostics( // (9,13): warning CS0219: The variable 'tr' is assigned but its value is never used - // var tr = new TypedReference(); - Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "tr").WithArguments("tr").WithLocation(9, 13)); + // var tr = new TypedReference(); // 1 + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "tr").WithArguments("tr").WithLocation(9, 13), + // (17,19): error CS4007: Instance of type 'System.TypedReference' cannot be preserved across 'await' or 'yield' boundary. + // var tr2 = tr; // 2 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "tr").WithArguments("System.TypedReference").WithLocation(17, 19)); } [Fact] @@ -3288,9 +3300,6 @@ unsafe async public static void F() // (8,31): error CS0209: The type of a local declared in a fixed statement must be a pointer type // fixed (TypedReference tr) { } Diagnostic(ErrorCode.ERR_BadFixedInitType, "tr"), - // (8,16): error CS4012: Parameters or locals of type 'System.TypedReference' cannot be declared in async methods or async lambda expressions. - // fixed (TypedReference tr) { } - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "TypedReference").WithArguments("System.TypedReference"), // (8,31): error CS0210: You must provide an initializer in a fixed or using statement declaration // fixed (TypedReference tr) { } Diagnostic(ErrorCode.ERR_FixedMustInit, "tr"), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs index bb59d99fef196..fd120694a384c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs @@ -3531,10 +3531,7 @@ public async static Task Test() System.Console.Write(x); } } -}").VerifyDiagnostics( - // (20,26): error CS8177: Async methods cannot have by-reference locals - // foreach (ref int x in new E()) - Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "x").WithLocation(20, 26)); +}").VerifyEmitDiagnostics(); } [Fact] @@ -3565,10 +3562,7 @@ public async static Task Test() System.Console.Write(x); } } -}").VerifyDiagnostics( - // (20,35): error CS8177: Async methods cannot have by-reference locals - // foreach (ref readonly int x in new E()) - Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "x").WithLocation(20, 35)); +}").VerifyEmitDiagnostics(); } [Fact] @@ -3597,10 +3591,7 @@ public static IEnumerable Test() yield return x; } } -}").VerifyDiagnostics( - // (18,26): error CS8176: Iterators cannot have by-reference locals - // foreach (ref int x in new E()) - Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "x").WithLocation(18, 26)); +}").VerifyEmitDiagnostics(); } [Fact] @@ -3629,10 +3620,7 @@ public static IEnumerable Test() yield return x; } } -}").VerifyDiagnostics( - // (18,35): error CS8176: Iterators cannot have by-reference locals - // foreach (ref readonly int x in new E()) - Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "x").WithLocation(18, 35)); +}").VerifyEmitDiagnostics(); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs index 34be3f12005c3..06055448cc8b6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs @@ -106,6 +106,168 @@ IEnumerable I() ); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72443")] + public void YieldInLock_Async() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + + public class C + { + public async Task ProcessValueAsync() + { + await foreach (int item in GetValuesAsync()) + { + await Task.Yield(); + Console.Write(item); + } + } + + private async IAsyncEnumerable GetValuesAsync() + { + await Task.Yield(); + lock (this) + { + for (int i = 0; i < 10; i++) + { + yield return i; + + if (i == 3) + { + yield break; + } + } + } + } + } + """ + AsyncStreamsTypes; + + var comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseDll.WithWarningLevel(8)); + CompileAndVerify(comp).VerifyDiagnostics(); + + var expectedDiagnostics = new[] + { + // (23,17): warning CS9237: 'yield return' should not be used in the body of a lock statement + // yield return i; + Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(23, 17) + }; + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseDll.WithWarningLevel(9)); + CompileAndVerify(comp).VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilationWithTasksExtensions(source, options: TestOptions.ReleaseDll); + CompileAndVerify(comp).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72443")] + public void YieldInLock_Sync() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Threading; + + object o = new object(); + Console.WriteLine($"Before: {Monitor.IsEntered(o)}"); + using (IEnumerator e = GetValues(o).GetEnumerator()) + { + Console.WriteLine($"Inside: {Monitor.IsEntered(o)}"); + while (e.MoveNext()) + { + Console.WriteLine($"{e.Current}: {Monitor.IsEntered(o)}"); + } + Console.WriteLine($"Done: {Monitor.IsEntered(o)}"); + } + Console.WriteLine($"After: {Monitor.IsEntered(o)}"); + + static IEnumerable GetValues(object obj) + { + lock (obj) + { + for (int i = 0; i < 3; i++) + { + yield return i; + + if (i == 1) + { + yield break; + } + } + } + } + """; + + var expectedOutput = """ + Before: False + Inside: False + 0: True + 1: True + Done: False + After: False + """; + + CompileAndVerify(source, options: TestOptions.ReleaseExe.WithWarningLevel(8), + expectedOutput: expectedOutput).VerifyDiagnostics(); + + var expectedDiagnostics = new[] + { + // (24,13): warning CS9237: 'yield return' should not be used in the body of a lock statement + // yield return i; + Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(24, 13) + }; + + CompileAndVerify(source, options: TestOptions.ReleaseExe.WithWarningLevel(9), + expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics); + + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72443")] + public void YieldInLock_Nested() + { + var source = """ + using System.Collections.Generic; + + class C + { + IEnumerable M() + { + yield return 1; + lock (this) + { + yield return 2; + + local(); + + IEnumerable local() + { + yield return 3; + + lock (this) + { + yield return 4; + + yield break; + } + } + + yield break; + } + } + } + """; + + CreateCompilation(source).VerifyDiagnostics( + // (10,13): warning CS9237: 'yield return' should not be used in the body of a lock statement + // yield return 2; + Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(10, 13), + // (20,21): warning CS9237: 'yield return' should not be used in the body of a lock statement + // yield return 4; + Diagnostic(ErrorCode.WRN_BadYieldInLock, "yield").WithLocation(20, 21)); + } + [WorkItem(546081, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546081")] [Fact] public void IteratorBlockWithUnreachableCode() diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 9b2f16c772425..2b32616b85553 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -5981,15 +5981,15 @@ static void Main() }"; var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); comp.VerifyDiagnostics( - // (10,39): error CS4012: Parameters or locals of type 'TypedReference' cannot be declared in async methods or async lambda expressions. + // (10,39): error CS4012: Parameters of type 'TypedReference' cannot be declared in async methods or async lambda expressions. // D1 d1 = async (TypedReference r) => { await Task.Yield(); }; - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "r").WithArguments("System.TypedReference").WithLocation(10, 39), - // (11,46): error CS4012: Parameters or locals of type 'RuntimeArgumentHandle' cannot be declared in async methods or async lambda expressions. + Diagnostic(ErrorCode.ERR_BadSpecialByRefParameter, "r").WithArguments("System.TypedReference").WithLocation(10, 39), + // (11,46): error CS4012: Parameters of type 'RuntimeArgumentHandle' cannot be declared in async methods or async lambda expressions. // D2 d2 = async (RuntimeArgumentHandle h) => { await Task.Yield(); }; - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "h").WithArguments("System.RuntimeArgumentHandle").WithLocation(11, 46), - // (12,36): error CS4012: Parameters or locals of type 'ArgIterator' cannot be declared in async methods or async lambda expressions. + Diagnostic(ErrorCode.ERR_BadSpecialByRefParameter, "h").WithArguments("System.RuntimeArgumentHandle").WithLocation(11, 46), + // (12,36): error CS4012: Parameters of type 'ArgIterator' cannot be declared in async methods or async lambda expressions. // D3 d3 = async (ArgIterator i) => { await Task.Yield(); }; - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "i").WithArguments("System.ArgIterator").WithLocation(12, 36)); + Diagnostic(ErrorCode.ERR_BadSpecialByRefParameter, "i").WithArguments("System.ArgIterator").WithLocation(12, 36)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs index 74f8efa9b607c..7e4c694e57ba1 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs @@ -2394,21 +2394,52 @@ public unsafe IEnumerable M4(int* a) // (33,44): error CS1637: Iterators cannot have pointer type parameters // public unsafe IEnumerable M4(int* a) Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(33, 44), - // (33,36): error CS1629: Unsafe code may not appear in iterators + // (33,36): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // public unsafe IEnumerable M4(int* a) - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "M4").WithLocation(33, 36), - // (37,40): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M4").WithArguments("ref and unsafe in async and iterator methods").WithLocation(33, 36), + // (37,40): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // IEnumerable Local(int* b) { yield break; } - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "int*").WithLocation(37, 40), - // (39,23): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(37, 40), + // (39,23): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // Local(&x); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "&x").WithLocation(39, 23), - // (39,17): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(39, 23), + // (39,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // Local(&x); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "Local(&x)").WithLocation(39, 17), + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Local(&x)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(39, 17), // (37,45): error CS1637: Iterators cannot have pointer type parameters // IEnumerable Local(int* b) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "b").WithLocation(37, 45)); + + var expectedDiagnostics = new[] + { + // (8,37): error CS1637: Iterators cannot have pointer type parameters + // IEnumerable Local(int* a) { yield break; } + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(8, 37), + // (17,41): error CS1637: Iterators cannot have pointer type parameters + // IEnumerable Local(int* x) { yield break; } + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "x").WithLocation(17, 41), + // (27,37): error CS1637: Iterators cannot have pointer type parameters + // IEnumerable Local(int* a) { yield break; } + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(27, 37), + // (33,44): error CS1637: Iterators cannot have pointer type parameters + // public unsafe IEnumerable M4(int* a) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(33, 44), + // (37,40): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // IEnumerable Local(int* b) { yield break; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(37, 40), + // (37,45): error CS1637: Iterators cannot have pointer type parameters + // IEnumerable Local(int* b) { yield break; } + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "b").WithLocation(37, 45), + // (39,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // Local(&x); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "Local(&x)").WithLocation(39, 17), + // (39,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // Local(&x); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "&x").WithLocation(39, 23) + }; + + CreateCompilation(src, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.RegularNext.WithFeature("run-nullable-analysis", "never")).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(src, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.RegularPreview.WithFeature("run-nullable-analysis", "never")).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -3516,7 +3547,7 @@ static void Main() // (10,31): error CS0190: The __arglist construct is valid only within a variable argument method // Console.WriteLine(__arglist); Diagnostic(ErrorCode.ERR_ArgsInvalid, "__arglist").WithLocation(10, 31), - // (18,31): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside an anonymous function, query expression, iterator block or async method + // (18,31): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside a nested function, query expression, iterator block or async method // Console.WriteLine(__arglist); Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle").WithLocation(18, 31), // (24,20): error CS1669: __arglist is not valid in this context @@ -3528,7 +3559,7 @@ static void Main() // (32,20): error CS1669: __arglist is not valid in this context // void Local(__arglist) Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(32, 20), - // (34,31): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside an anonymous function, query expression, iterator block or async method + // (34,31): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside a nested function, query expression, iterator block or async method // Console.WriteLine(__arglist); Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle").WithLocation(34, 31) ); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs index 320f13951a7f9..07bd155f06f33 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs @@ -4369,14 +4369,31 @@ static IEnumerable F() yield return sizeof(nuint); } }"; - var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular9); - comp.VerifyDiagnostics( - // (6,22): error CS1629: Unsafe code may not appear in iterators + var expectedDiagnostics = new[] + { + // (6,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 22), + // (7,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // yield return sizeof(nuint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nuint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 22) + }; + + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular9).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + + expectedDiagnostics = new[] + { + // (6,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context // yield return sizeof(nint); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(nint)").WithLocation(6, 22), - // (7,22): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 22), + // (7,22): error CS0233: 'nuint' does not have a predefined size, therefore sizeof can only be used in an unsafe context // yield return sizeof(nuint); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(nuint)").WithLocation(7, 22)); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nuint)").WithArguments("nuint").WithLocation(7, 22) + }; + + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs index 893f9732de04e..f97c3f0a283ce 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs @@ -4969,9 +4969,10 @@ public static unsafe void Test(TestStruct[] ar) [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] + [InlineData(LanguageVersionFacts.CSharpNext)] public void AwaitRefStruct(LanguageVersion languageVersion) { - CreateCompilation(@" + var comp = CreateCompilation(@" using System.Threading.Tasks; ref struct S { } @@ -4991,20 +4992,67 @@ async Task M(Task t) void M(S t, ref S t1) { } -}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseDll).VerifyDiagnostics( - // (8,26): error CS9504: The type 'S' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'TResult' in the generic type or method 'Task' - // async Task M(Task t) - Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "t").WithArguments("System.Threading.Tasks.Task", "TResult", "S").WithLocation(8, 26), - // (12,9): error CS4012: Parameters or locals of type 'S' cannot be declared in async methods or async lambda expressions. - // var a = await t; - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "var").WithArguments("S").WithLocation(12, 9), - // (14,9): error CS4012: Parameters or locals of type 'S' cannot be declared in async methods or async lambda expressions. - // var r = t.Result; - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "var").WithArguments("S").WithLocation(14, 9), - // (15,9): error CS8350: This combination of arguments to 'C.M(S, ref S)' is disallowed because it may expose variables referenced by parameter 't' outside of their declaration scope - // M(await t, ref r); - Diagnostic(ErrorCode.ERR_CallArgMixing, "M(await t, ref r)").WithArguments("C.M(S, ref S)", "t").WithLocation(15, 9) - ); +}", parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), options: TestOptions.ReleaseDll); + if (languageVersion < LanguageVersionFacts.CSharpNext) + { + comp.VerifyDiagnostics( + // (8,26): error CS9504: The type 'S' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'TResult' in the generic type or method 'Task' + // async Task M(Task t) + Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "t").WithArguments("System.Threading.Tasks.Task", "TResult", "S").WithLocation(8, 26), + // (12,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var a = await t; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(12, 9), + // (14,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var r = t.Result; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(14, 9), + // (15,9): error CS8350: This combination of arguments to 'C.M(S, ref S)' is disallowed because it may expose variables referenced by parameter 't' outside of their declaration scope + // M(await t, ref r); + Diagnostic(ErrorCode.ERR_CallArgMixing, "M(await t, ref r)").WithArguments("C.M(S, ref S)", "t").WithLocation(15, 9) + ); + } + else + { + comp.VerifyDiagnostics( + // (8,26): error CS9504: The type 'S' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'TResult' in the generic type or method 'Task' + // async Task M(Task t) + Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "t").WithArguments("System.Threading.Tasks.Task", "TResult", "S").WithLocation(8, 26), + // (15,9): error CS8350: This combination of arguments to 'C.M(S, ref S)' is disallowed because it may expose variables referenced by parameter 't' outside of their declaration scope + // M(await t, ref r); + Diagnostic(ErrorCode.ERR_CallArgMixing, "M(await t, ref r)").WithArguments("C.M(S, ref S)", "t").WithLocation(15, 9) + ); + } + } + + [Fact] + public void AsyncLocals_Reassignment() + { + var code = """ + using System.Threading.Tasks; + class C + { + async Task M1() + { + int x = 42; + ref int y = ref x; + y.ToString(); + await Task.Yield(); + y.ToString(); // 1 + } + async Task M2() + { + int x = 42; + ref int y = ref x; + y.ToString(); + await Task.Yield(); + y = ref x; + y.ToString(); + } + } + """; + CreateCompilation(code).VerifyEmitDiagnostics( + // (10,9): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // y.ToString(); // 1 + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(10, 9)); } [WorkItem(25398, "https://github.com/dotnet/roslyn/issues/25398")] @@ -5345,9 +5393,9 @@ public static IEnumerable Iterator() { } """); compilation.VerifyEmitDiagnostics( - // (20,19): error CS4013: Instance of type 'PooledArrayHandle' cannot be used inside a nested function, query expression, iterator block or async method + // (20,19): error CS4007: Instance of type 'PooledArrayHandle' cannot be preserved across 'await' or 'yield' boundary. // using var handle = RentArray(200, out var array); - Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "handle = RentArray(200, out var array)").WithArguments("PooledArrayHandle").WithLocation(20, 19)); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "handle = RentArray(200, out var array)").WithArguments("PooledArrayHandle").WithLocation(20, 19)); } [Theory(Skip = "https://github.com/dotnet/roslyn/issues/40583")] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs index 825e55fd10807..7299939536559 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs @@ -1209,10 +1209,7 @@ async Task M() await Task.FromResult(false); } }"); - comp.VerifyDiagnostics( - // (7,26): error CS8177: Async methods cannot have by-reference locals - // ref readonly int x = ref (new int[1])[0]; - Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "x").WithLocation(7, 26)); + comp.VerifyEmitDiagnostics(); } [Fact] @@ -1229,10 +1226,87 @@ IEnumerable M() yield return i; } }"); - comp.VerifyDiagnostics( - // (7,26): error CS8176: Iterators cannot have by-reference locals - // ref readonly int x = ref (new int[1])[0]; - Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "x").WithLocation(7, 26)); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void RefReadonlyInIterator_ForEach() + { + var source = """ + using System.Collections.Generic; + class C + { + int[] arr = new int[2]; + IEnumerable M() + { + ref readonly int[] x = ref arr; + + foreach (var i in x) + { + System.Console.Write(i); + yield return 1; + } + + foreach (var j in x) + { + System.Console.Write(j); + yield return 2; + } + } + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,28): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref readonly int[] x = ref arr; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 28)); + + var expectedDiagnostics = new[] + { + // (15,27): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // foreach (var j in x) + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "x").WithLocation(15, 27) + }; + + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefReadonlyInIterator_ForEach_02() + { + var source = """ + using System.Collections.Generic; + + foreach (var i in new C().M()) System.Console.Write(i); + + class C + { + int[] arr = new[] { 4, 5 }; + public IEnumerable M() + { + ref readonly int[] x = ref arr; + + foreach (var i in x) + { + System.Console.Write(i); + yield return 1; + } + } + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (10,28): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref readonly int[] x = ref arr; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 28)); + + var expectedOutput = "4151"; + + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: expectedOutput).VerifyDiagnostics(); + + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); } [Fact] @@ -1247,7 +1321,7 @@ IEnumerable M() switch (this) { default: - ref readonly int x = ref (new int[1])[0]; // 1 + ref readonly int x = ref (new int[1])[0]; yield return 1; yield return x; @@ -1260,10 +1334,10 @@ void local() } } }"); - comp.VerifyDiagnostics( - // (10,34): error CS8176: Iterators cannot have by-reference locals - // ref readonly int x = ref (new int[1])[0]; // 1 - Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "x").WithLocation(10, 34)); + comp.VerifyEmitDiagnostics( + // (12,30): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // yield return x; + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "x").WithLocation(12, 30)); } [Fact] @@ -1278,22 +1352,19 @@ IEnumerable M() switch (this) { default: - ref readonly int x; // 1, 2 + ref readonly int x; // 1 yield return 1; - yield return x; // 3 + yield return x; // 2 break; } } }"); comp.VerifyDiagnostics( - // (10,34): error CS8176: Iterators cannot have by-reference locals - // ref readonly int x; // 1, 2 - Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "x").WithLocation(10, 34), // (10,34): error CS8174: A declaration of a by-reference variable must have an initializer - // ref readonly int x; // 1, 2 + // ref readonly int x; // 1 Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "x").WithLocation(10, 34), // (12,30): error CS0165: Use of unassigned local variable 'x' - // yield return x; // 3 + // yield return x; // 2 Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(12, 30)); } @@ -1316,9 +1387,9 @@ IEnumerable M() } }"); comp.VerifyDiagnostics( - // (10,43): error CS8176: Iterators cannot have by-reference locals + // (10,49): error CS1510: A ref or out value must be an assignable variable // foreach (ref readonly int x in (new int[1])) - Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "x").WithLocation(10, 43)); + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new int[1]").WithLocation(10, 49)); } [Fact] @@ -1331,18 +1402,15 @@ class C IEnumerable M() { if (true) - ref int x = ref (new int[1])[0]; // 1, 2 + ref int x = ref (new int[1])[0]; // 1 yield return 1; } }"); comp.VerifyDiagnostics( // (8,13): error CS1023: Embedded statement cannot be a declaration or labeled statement - // ref int x = ref (new int[1])[0]; // 1, 2 - Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "ref int x = ref (new int[1])[0];").WithLocation(8, 13), - // (8,21): error CS8176: Iterators cannot have by-reference locals - // ref int x = ref (new int[1])[0]; // 1, 2 - Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "x").WithLocation(8, 21)); + // ref int x = ref (new int[1])[0]; // 1 + Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "ref int x = ref (new int[1])[0];").WithLocation(8, 13)); } [Fact] @@ -1355,18 +1423,15 @@ class C async Task M() { if (true) - ref int x = ref (new int[1])[0]; // 1, 2 + ref int x = ref (new int[1])[0]; // 1 await Task.Yield(); } }"); comp.VerifyDiagnostics( // (8,13): error CS1023: Embedded statement cannot be a declaration or labeled statement - // ref int x = ref (new int[1])[0]; // 1, 2 - Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "ref int x = ref (new int[1])[0];").WithLocation(8, 13), - // (8,21): error CS8177: Async methods cannot have by-reference locals - // ref int x = ref (new int[1])[0]; // 1, 2 - Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "x").WithLocation(8, 21)); + // ref int x = ref (new int[1])[0]; // 1 + Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "ref int x = ref (new int[1])[0];").WithLocation(8, 13)); } [Fact] @@ -3087,14 +3152,147 @@ IEnumerable localFunction() } } }"; - - CreateCompilation(code).VerifyDiagnostics( - // (13,21): error CS8176: Iterators cannot have by-reference locals - // ref int z = ref x; - Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "z").WithLocation(13, 21), - // (8,17): error CS8176: Iterators cannot have by-reference locals + CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // ref int y = ref x; - Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "y").WithLocation(8, 17)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 17), + // (13,21): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int z = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "z").WithArguments("ref and unsafe in async and iterator methods").WithLocation(13, 21)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(code).VerifyEmitDiagnostics(); + } + + [Fact] + public void RefLocal_Iterator_LocalFunction_01() + { + var code = """ + using System; + using System.Collections.Generic; + + int x = 5; + + foreach (var z in func()) + { + Console.Write(z); + x++; + } + + IEnumerable func() + { + ref int y = ref x; + yield return y; + y = ref x; + yield return y; + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (14,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(14, 13)); + + var expectedOutput = "56"; + + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void RefLocal_Iterator_LocalFunction_02() + { + var code = """ + using System.Collections.Generic; + + int x = 5; + + IEnumerable func() + { + ref int y = ref x; + yield return y; + yield return y; + } + + func(); + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 13)); + + var expectedDiagnostics = new[] + { + // (9,18): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // yield return y; + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(9, 18) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(code).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_Iterator_LocalFunction_01() + { + var code = """ + using System; + using System.Collections.Generic; + + int x = 5; + + foreach (var z in func()) + { + Console.Write(z); + x++; + } + + IEnumerable func() + { + Span y = new(ref x); + yield return y[0]; + y = new(ref x); + yield return y[0]; + } + """; + + var expectedOutput = ExecutionConditionUtil.IsDesktop ? null : "56"; + + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_Iterator_LocalFunction_02() + { + var code = """ + using System; + using System.Collections.Generic; + + int x = 5; + + IEnumerable func() + { + Span y = new(ref x); + yield return y[0]; + yield return y[0]; + } + + func(); + """; + + var expectedDiagnostics = new[] + { + // (10,18): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // yield return y[0]; + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(10, 18) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(code, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics); } [Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")] @@ -3115,13 +3313,152 @@ await Task.Run(async () => }); } }"; - CreateCompilationWithMscorlib45(code).VerifyDiagnostics( - // (8,17): error CS8177: Async methods cannot have by-reference locals + CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // ref int y = ref x; - Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "y").WithLocation(8, 17), - // (11,21): error CS8177: Async methods cannot have by-reference locals + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 17), + // (11,21): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // ref int z = ref x; - Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "z").WithLocation(11, 21)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "z").WithArguments("ref and unsafe in async and iterator methods").WithLocation(11, 21)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(code).VerifyEmitDiagnostics(); + } + + [Fact] + public void RefLocal_Async_LocalFunction_01() + { + var code = """ + using System; + using System.Threading.Tasks; + + int x = 5; + + await func(); + + async Task func() + { + ref int y = ref x; + Console.Write(y); + await Task.Yield(); + y = ref x; + Console.Write(y); + await Task.Yield(); + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (10,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 13)); + + var expectedOutput = "55"; + + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void RefLocal_Async_LocalFunction_02() + { + var code = """ + using System; + using System.Threading.Tasks; + + int x = 5; + + async Task func() + { + ref int y = ref x; + await Task.Yield(); + Console.Write(y); + } + + await func(); + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int y = ref x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "y").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 13)); + + var expectedDiagnostics = new[] + { + // (10,19): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y); + Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(10, 19) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(code).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefStruct_Async_LocalFunction_01() + { + var code = """ + using System; + using System.Threading.Tasks; + + int x = 5; + + await func(); + + async Task func() + { + Span y = new(ref x); + Console.Write(y[0]); + await Task.Yield(); + y = new(ref x); + Console.Write(y[0]); + await Task.Yield(); + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70).VerifyDiagnostics( + // (10,5): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Span y = new(ref x); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Span").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 5)); + + var expectedOutput = ExecutionConditionUtil.IsDesktop ? null : "55"; + + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics(); + } + + [Fact] + public void RefStruct_Async_LocalFunction_02() + { + var code = """ + using System; + using System.Threading.Tasks; + + int x = 5; + + async Task func() + { + Span y = new(ref x); + await Task.Yield(); + Console.Write(y[0]); + } + + await func(); + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70).VerifyDiagnostics( + // (8,5): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Span y = new(ref x); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Span").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 5)); + + var expectedDiagnostics = new[] + { + // (10,19): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // Console.Write(y[0]); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(10, 19) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(code, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics); } [Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")] @@ -3434,15 +3771,40 @@ static async void Goo() } "; - CreateCompilationWithMscorlib46(text).VerifyDiagnostics( - // (8,17): error CS8177: Async methods cannot have by-reference locals - // ref int i = ref field; - Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "i").WithLocation(8, 17), + CreateCompilationWithMscorlib46(text).VerifyEmitDiagnostics( // (6,23): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. // static async void Goo() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Goo").WithLocation(6, 23)); } + [Fact] + public void RefReturnAcrossAwaitExpression() + { + var code = """ + using System.Threading.Tasks; + + class Program + { + static int field = 1; + + static async Task Main() + { + M1(ref GiveMeRef(), await M2()); + } + + static void M1(ref int i, int j) { } + + static ref int GiveMeRef() => ref field; + + static Task M2() => Task.FromResult(field++); + } + """; + CreateCompilation(code).VerifyEmitDiagnostics( + // (9,16): error CS8178: A reference returned by a call to 'Program.GiveMeRef()' cannot be preserved across 'await' or 'yield' boundary. + // M1(ref GiveMeRef(), await M2()); + Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "GiveMeRef()").WithArguments("Program.GiveMeRef()").WithLocation(9, 16)); + } + [Fact] public void BadRefLocalInIteratorMethod() { @@ -3461,10 +3823,7 @@ static IEnumerable ObjEnumerable() } "; - CreateCompilationWithMscorlib46(text).VerifyDiagnostics( - // (10,17): error CS8931: Iterators cannot have by-reference locals - // ref int i = ref field; - Diagnostic(ErrorCode.ERR_BadIteratorLocalType, "i").WithLocation(10, 17)); + CreateCompilationWithMscorlib46(text).VerifyEmitDiagnostics(); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs index fc678a39411b1..d361b612ede78 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs @@ -7269,15 +7269,15 @@ static void Main() }"; var comp = CreateCompilationWithMscorlib40AndSystemCore(source); comp.VerifyDiagnostics( - // (10,14): error CS4013: Instance of type 'System.RuntimeArgumentHandle' cannot be used inside an anonymous function, query expression, iterator block or async method + // (10,14): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside a nested function, query expression, iterator block or async method // f = x=>f(__arglist); - Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle"), - // (11,29): error CS4013: Instance of type 'System.RuntimeArgumentHandle' cannot be used inside an anonymous function, query expression, iterator block or async method + Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle").WithLocation(10, 14), + // (11,29): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside a nested function, query expression, iterator block or async method // f = delegate { return f(__arglist); }; - Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle"), - // (12,44): error CS4013: Instance of type 'System.RuntimeArgumentHandle' cannot be used inside an anonymous function, query expression, iterator block or async method + Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle").WithLocation(11, 29), + // (12,44): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside a nested function, query expression, iterator block or async method // var q = from x in new int[10] select f(__arglist); - Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle") + Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle").WithLocation(12, 44) ); } @@ -7304,12 +7304,12 @@ static void Main() } }"; CreateCompilationWithMscorlib45(source).VerifyEmitDiagnostics( - // (10,34): error CS4013: Instance of type 'System.RuntimeArgumentHandle' cannot be used inside an anonymous function, query expression, iterator block or async method + // (10,34): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside a nested function, query expression, iterator block or async method // RuntimeArgumentHandle h2 = h; // Bad use of h - Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "h").WithArguments("System.RuntimeArgumentHandle"), - // (11,43): error CS4013: Instance of type 'System.RuntimeArgumentHandle' cannot be used inside an anonymous function, query expression, iterator block or async method + Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "h").WithArguments("System.RuntimeArgumentHandle").WithLocation(10, 34), + // (11,43): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside a nested function, query expression, iterator block or async method // ArgIterator args1 = new ArgIterator(h); // Bad use of h - Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "h").WithArguments("System.RuntimeArgumentHandle")); + Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "h").WithArguments("System.RuntimeArgumentHandle").WithLocation(11, 43)); } [Fact] @@ -7321,9 +7321,9 @@ public void CS4013ERR_SpecialByRefInLambda03() public class C { static void N(RuntimeArgumentHandle x) {} - static IEnumerable M(RuntimeArgumentHandle h1) // Error: hoisted to field + static IEnumerable M(RuntimeArgumentHandle h1) { - N(h1); + N(h1); // Error: hoisted to field yield return 1; RuntimeArgumentHandle h2 = default(RuntimeArgumentHandle); yield return 2; @@ -7339,12 +7339,12 @@ static void Main() CreateCompilation(source).Emit(new System.IO.MemoryStream()).Diagnostics .Verify( - // (7,51): error CS4013: Instance of type 'System.RuntimeArgumentHandle' cannot be used inside an anonymous function, query expression, iterator block or async method - // static IEnumerable M(RuntimeArgumentHandle h1) // Error: hoisted to field - Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "h1").WithArguments("System.RuntimeArgumentHandle"), - // (13,7): error CS4013: Instance of type 'System.RuntimeArgumentHandle' cannot be used inside an anonymous function, query expression, iterator block or async method + // (9,7): error CS4007: Instance of type 'System.RuntimeArgumentHandle' cannot be preserved across 'await' or 'yield' boundary. + // N(h1); // Error: hoisted to field + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "h1").WithArguments("System.RuntimeArgumentHandle").WithLocation(9, 7), + // (13,7): error CS4007: Instance of type 'System.RuntimeArgumentHandle' cannot be preserved across 'await' or 'yield' boundary. // N(h2); // Error: hoisted to field - Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "h2").WithArguments("System.RuntimeArgumentHandle") + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "h2").WithArguments("System.RuntimeArgumentHandle").WithLocation(13, 7) ); } @@ -15318,35 +15318,48 @@ class C { IEnumerator IteratorMeth() { int i; - unsafe // CS1629 + unsafe { int *p = &i; yield return *p; } } - unsafe IEnumerator IteratorMeth2() { // CS1629 + unsafe IEnumerator IteratorMeth2() { yield break; } } "; - CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (7,7): error CS1629: Unsafe code may not appear in iterators - // unsafe // CS1629 - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "unsafe"), - // (9,10): error CS1629: Unsafe code may not appear in iterators + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,7): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 7), + // (9,10): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // int *p = &i; - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "int *"), - // (9,19): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 10), + // (9,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // int *p = &i; - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "&i"), - // (10,24): error CS1629: Unsafe code may not appear in iterators + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&i").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 19), + // (10,24): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // yield return *p; - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "p"), - // (14,29): error CS1629: Unsafe code may not appear in iterators - // unsafe IEnumerator IteratorMeth2() { // CS1629 - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "IteratorMeth2") + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 24), + // (14,29): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe IEnumerator IteratorMeth2() { + Diagnostic(ErrorCode.ERR_FeatureInPreview, "IteratorMeth2").WithArguments("ref and unsafe in async and iterator methods").WithLocation(14, 29) ); + + var expectedDiagnostics = new[] + { + // (9,20): error CS9239: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &i; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "i").WithLocation(9, 20), + // (10,10): error CS9238: Cannot use 'yield return' in an 'unsafe' block + // yield return *p; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(10, 10) + }; + + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs index a66cc2a843bb2..fac0d3fe54188 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs @@ -1158,9 +1158,9 @@ public static async Task M1(Span arg) CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); comp.VerifyDiagnostics( - // (11,48): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. + // (11,48): error CS4012: Parameters of type 'Span' cannot be declared in async methods or async lambda expressions. // public static async Task M1(Span arg) - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "arg").WithArguments("System.Span").WithLocation(11, 48) + Diagnostic(ErrorCode.ERR_BadSpecialByRefParameter, "arg").WithArguments("System.Span").WithLocation(11, 48) ); } @@ -1179,48 +1179,77 @@ static void Main() public static async Task M1() { - Span local1 = default(Span); // 1 - var local2 = default(Span); // 2 + Span local1 = default(Span); + var local2 = default(Span); await Task.Yield(); return 42; } + + public static async Task M2() + { + Span local1 = default(Span); + var local2 = default(Span); + + await Task.Yield(); + return local1.Length; // 1 + } + + public static async Task M3() + { + Span local1 = default(Span); + var local2 = default(Span); + + await Task.Yield(); + return local2.Length; // 2 + } + + public static async Task M4() + { + Span local1 = default(Span); + var local2 = default(Span); + + await Task.Yield(); + return local1.Length + local2.Length; // 3, 4 + } } "; - CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); - - comp.VerifyDiagnostics( - // (13,9): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // Span local1 = default(Span); // 1 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "Span").WithArguments("System.Span").WithLocation(13, 9), + var expectedDiagnostics = new[] + { // (13,19): warning CS0219: The variable 'local1' is assigned but its value is never used - // Span local1 = default(Span); // 1 + // Span local1 = default(Span); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local1").WithArguments("local1").WithLocation(13, 19), - // (14,9): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // var local2 = default(Span); // 2 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "var").WithArguments("System.Span").WithLocation(14, 9), // (14,13): warning CS0219: The variable 'local2' is assigned but its value is never used - // var local2 = default(Span); // 2 - Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local2").WithArguments("local2").WithLocation(14, 13) - ); + // var local2 = default(Span); + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local2").WithArguments("local2").WithLocation(14, 13), + // (23,13): warning CS0219: The variable 'local2' is assigned but its value is never used + // var local2 = default(Span); + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local2").WithArguments("local2").WithLocation(23, 13), + // (26,16): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // return local1.Length; // 1 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "local1").WithArguments("System.Span").WithLocation(26, 16), + // (31,19): warning CS0219: The variable 'local1' is assigned but its value is never used + // Span local1 = default(Span); + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local1").WithArguments("local1").WithLocation(31, 19), + // (35,16): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // return local2.Length; // 2 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "local2").WithArguments("System.Span").WithLocation(35, 16), + // (44,16): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // return local1.Length + local2.Length; // 3, 4 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "local1").WithArguments("System.Span").WithLocation(44, 16), + // (44,32): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // return local1.Length + local2.Length; // 3, 4 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "local2").WithArguments("System.Span").WithLocation(44, 32) + }; + + CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + + comp.VerifyEmitDiagnostics(expectedDiagnostics); comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.DebugExe); - comp.VerifyDiagnostics( - // (13,9): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // Span local1 = default(Span); // 1 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "Span").WithArguments("System.Span").WithLocation(13, 9), - // (13,19): warning CS0219: The variable 'local1' is assigned but its value is never used - // Span local1 = default(Span); // 1 - Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local1").WithArguments("local1").WithLocation(13, 19), - // (14,9): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // var local2 = default(Span); // 2 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "var").WithArguments("System.Span").WithLocation(14, 9), - // (14,13): warning CS0219: The variable 'local2' is assigned but its value is never used - // var local2 = default(Span); // 2 - Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local2").WithArguments("local2").WithLocation(14, 13) - ); + comp.VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] @@ -1234,27 +1263,44 @@ public class Program { public static async Task M1() { - M2(out var local1); // 1 - M2(out Span local2); // 2 + M2(out var local1); + M2(out Span local2); await Task.Yield(); return 42; } + public static async Task M3() + { + M2(out var local1); + M2(out Span local2); + + await Task.Yield(); + return local1.Length; // 1 + } + + public static async Task M4() + { + M2(out var local1); + M2(out Span local2); + + await Task.Yield(); + return local2.Length; // 2 + } + static void M2(out Span s) => throw null; } "; CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); - comp.VerifyDiagnostics( - // (9,16): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // M2(out var local1); // 1 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "var").WithArguments("System.Span").WithLocation(9, 16), - // (10,16): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // M2(out Span local2); // 2 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "Span").WithArguments("System.Span").WithLocation(10, 16) - ); + comp.VerifyEmitDiagnostics( + // (22,16): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // return local1.Length; // 1 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "local1").WithArguments("System.Span").WithLocation(22, 16), + // (31,16): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // return local2.Length; // 2 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "local2").WithArguments("System.Span").WithLocation(31, 16)); } [Fact, WorkItem(62747, "https://github.com/dotnet/roslyn/issues/62747")] @@ -1269,30 +1315,49 @@ public class Program { public async Task M(IReadOnlyList o) { - foreach (ReadOnlySpan c1 in o) { } // 1 + foreach (ReadOnlySpan c1 in o) { } var enumerator = ((IEnumerable)o).GetEnumerator(); while (enumerator.MoveNext()) { - ReadOnlySpan c2 = (ReadOnlySpan)(string)enumerator.Current; // 2 + ReadOnlySpan c2 = (ReadOnlySpan)(string)enumerator.Current; _ = c2.Length; } await Task.Yield(); return; } + + public async Task M2(IReadOnlyList o) + { + foreach (ReadOnlySpan c1 in o) + { + await Task.Yield(); + _ = c1.Length; // 1 + } + + var enumerator = ((IEnumerable)o).GetEnumerator(); + while (enumerator.MoveNext()) + { + ReadOnlySpan c2 = (ReadOnlySpan)(string)enumerator.Current; + await Task.Yield(); + _ = c2.Length; // 2 + } + + await Task.Yield(); + return; + } } "; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); - comp.VerifyDiagnostics( - // (10,18): error CS4012: Parameters or locals of type 'ReadOnlySpan' cannot be declared in async methods or async lambda expressions. - // foreach (ReadOnlySpan c1 in o) { } // 1 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "ReadOnlySpan").WithArguments("System.ReadOnlySpan").WithLocation(10, 18), - // (15,13): error CS4012: Parameters or locals of type 'ReadOnlySpan' cannot be declared in async methods or async lambda expressions. - // ReadOnlySpan c2 = (ReadOnlySpan)(string)enumerator.Current; // 2 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "ReadOnlySpan").WithArguments("System.ReadOnlySpan").WithLocation(15, 13) - ); + comp.VerifyEmitDiagnostics( + // (28,17): error CS4007: Instance of type 'System.ReadOnlySpan' cannot be preserved across 'await' or 'yield' boundary. + // _ = c1.Length; // 1 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "c1").WithArguments("System.ReadOnlySpan").WithLocation(28, 17), + // (36,17): error CS4007: Instance of type 'System.ReadOnlySpan' cannot be preserved across 'await' or 'yield' boundary. + // _ = c2.Length; // 2 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "c2").WithArguments("System.ReadOnlySpan").WithLocation(36, 17)); } [Fact, WorkItem(62747, "https://github.com/dotnet/roslyn/issues/62747")] @@ -1306,11 +1371,23 @@ public class Program { public async Task M() { - (Span s1, Span s2) = new Program(); // 1, 2 - var (s3, s4) = new Program(); // 3, 4 - (var s5, var s6) = new Program(); // 5, 6 + (Span s1, Span s2) = new Program(); + var (s3, s4) = new Program(); + (var s5, var s6) = new Program(); + + await Task.Yield(); + return; + } + + public async Task M2() + { + (Span s1, Span s2) = new Program(); + var (s3, s4) = new Program(); + (var s5, var s6) = new Program(); await Task.Yield(); + + _ = s1.Length + s4.Length + s5.Length; // 1, 2, 3 return; } @@ -1318,26 +1395,16 @@ public async Task M() } "; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); - comp.VerifyDiagnostics( - // (9,10): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // (Span s1, Span s2) = new Program(); // 1, 2 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "Span").WithArguments("System.Span").WithLocation(9, 10), - // (9,24): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // (Span s1, Span s2) = new Program(); // 1, 2 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "Span").WithArguments("System.Span").WithLocation(9, 24), - // (10,14): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // var (s3, s4) = new Program(); // 3, 4 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "s3").WithArguments("System.Span").WithLocation(10, 14), - // (10,18): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // var (s3, s4) = new Program(); // 3, 4 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "s4").WithArguments("System.Span").WithLocation(10, 18), - // (11,10): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // (var s5, var s6) = new Program(); // 5, 6 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "var").WithArguments("System.Span").WithLocation(11, 10), - // (11,18): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // (var s5, var s6) = new Program(); // 5, 6 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "var").WithArguments("System.Span").WithLocation(11, 18) - ); + comp.VerifyEmitDiagnostics( + // (25,13): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // _ = s1.Length + s4.Length + s5.Length; // 1, 2, 3 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s1").WithArguments("System.Span").WithLocation(25, 13), + // (25,25): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // _ = s1.Length + s4.Length + s5.Length; // 1, 2, 3 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s4").WithArguments("System.Span").WithLocation(25, 25), + // (25,37): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // _ = s1.Length + s4.Length + s5.Length; // 1, 2, 3 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s5").WithArguments("System.Span").WithLocation(25, 37)); } [Fact, WorkItem(62747, "https://github.com/dotnet/roslyn/issues/62747")] @@ -1350,11 +1417,26 @@ public class Program { public async Task M() { - using (default(RS)) { } // 1 - using (var s1 = default(RS)) { } // 2 - using (RS s2 = default(RS)) { } // 3 - using RS s3 = default(RS); // 4 - using var s4 = default(RS); // 5 + using (default(RS)) { } + using (var s1 = default(RS)) { } + using (RS s2 = default(RS)) { } + using RS s3 = default(RS); // 1 + using var s4 = default(RS); // 2 + + await Task.Yield(); + return; + } + + public async Task M2() + { + using (default(RS)) { await Task.Yield(); } // 3 + using (var s1 = default(RS)) { await Task.Yield(); } // 4 + using (RS s2 = default(RS)) { await Task.Yield(); } // 5 + { + using RS s3 = default(RS); // 6 + await Task.Yield(); + using var s4 = default(RS); + } await Task.Yield(); return; @@ -1367,23 +1449,25 @@ public void Dispose() { } } "; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); - comp.VerifyDiagnostics( - // (8,16): error CS9104: A using statement resource of type 'RS' cannot be used in async methods or async lambda expressions. - // using (default(RS)) { } // 1 - Diagnostic(ErrorCode.ERR_BadSpecialByRefUsing, "default(RS)").WithArguments("RS").WithLocation(8, 16), - // (9,16): error CS4012: Parameters or locals of type 'RS' cannot be declared in async methods or async lambda expressions. - // using (var s1 = default(RS)) { } // 2 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "var").WithArguments("RS").WithLocation(9, 16), - // (10,16): error CS4012: Parameters or locals of type 'RS' cannot be declared in async methods or async lambda expressions. - // using (RS s2 = default(RS)) { } // 3 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "RS").WithArguments("RS").WithLocation(10, 16), - // (11,15): error CS4012: Parameters or locals of type 'RS' cannot be declared in async methods or async lambda expressions. - // using RS s3 = default(RS); // 4 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "RS").WithArguments("RS").WithLocation(11, 15), - // (12,15): error CS4012: Parameters or locals of type 'RS' cannot be declared in async methods or async lambda expressions. - // using var s4 = default(RS); // 5 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "var").WithArguments("RS").WithLocation(12, 15) - ); + comp.VerifyEmitDiagnostics( + // (11,18): error CS4007: Instance of type 'RS' cannot be preserved across 'await' or 'yield' boundary. + // using RS s3 = default(RS); // 1 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s3 = default(RS)").WithArguments("RS").WithLocation(11, 18), + // (12,19): error CS4007: Instance of type 'RS' cannot be preserved across 'await' or 'yield' boundary. + // using var s4 = default(RS); // 2 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s4 = default(RS)").WithArguments("RS").WithLocation(12, 19), + // (20,16): error CS4007: Instance of type 'RS' cannot be preserved across 'await' or 'yield' boundary. + // using (default(RS)) { await Task.Yield(); } // 3 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "default(RS)").WithArguments("RS").WithLocation(20, 16), + // (21,20): error CS4007: Instance of type 'RS' cannot be preserved across 'await' or 'yield' boundary. + // using (var s1 = default(RS)) { await Task.Yield(); } // 4 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s1 = default(RS)").WithArguments("RS").WithLocation(21, 20), + // (22,19): error CS4007: Instance of type 'RS' cannot be preserved across 'await' or 'yield' boundary. + // using (RS s2 = default(RS)) { await Task.Yield(); } // 5 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s2 = default(RS)").WithArguments("RS").WithLocation(22, 19), + // (24,22): error CS4007: Instance of type 'RS' cannot be preserved across 'await' or 'yield' boundary. + // using RS s3 = default(RS); // 6 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s3 = default(RS)").WithArguments("RS").WithLocation(24, 22)); } [Fact] @@ -1397,24 +1481,76 @@ public class Program { public async Task M() { - if (M2() is var s1) { } // 1 - if (M2() is Span s2) { } // 2 + if (M2() is var s1) { } + if (M2() is Span s2) { } + if (M2() is var s3) { await Task.Yield(); } + if (M2() is Span s4) { await Task.Yield(); } + + await Task.Yield(); + return; + } + + public async Task M3() + { + if (M2() is var s1) + { + await Task.Yield(); + _ = s1.Length; // 1 + } + if (M2() is Span s2) + { + await Task.Yield(); + _ = s2.Length; // 2 + } await Task.Yield(); return; } + static Span M2() => throw null; } "; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net70); - comp.VerifyDiagnostics( - // (9,25): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // if (M2() is var s1) { } // 1 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "s1").WithArguments("System.Span").WithLocation(9, 25), - // (10,21): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // if (M2() is Span s2) { } // 2 - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "Span").WithArguments("System.Span").WithLocation(10, 21) - ); + comp.VerifyEmitDiagnostics( + // (23,17): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // _ = s1.Length; + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s1").WithArguments("System.Span").WithLocation(23, 17), + // (28,17): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // _ = s2.Length; + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "s2").WithArguments("System.Span").WithLocation(28, 17)); + } + + [Fact] + public void AsyncLocals_Reassignment() + { + var code = """ + using System; + using System.Threading.Tasks; + class C + { + async Task M1() + { + int x = 42; + Span y = new(ref x); + y.ToString(); + await Task.Yield(); + y.ToString(); // 1 + } + async Task M2() + { + int x = 42; + Span y = new(ref x); + y.ToString(); + await Task.Yield(); + y = new(ref x); + y.ToString(); + } + } + """; + CreateCompilation(code, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics( + // (11,9): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. + // y.ToString(); // 1 + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span").WithLocation(11, 9)); } [Fact] @@ -1463,19 +1599,18 @@ public static async Task I1() CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); - comp.VerifyEmitDiagnostics( - // (17,39): error CS4007: 'await' cannot be used in an expression containing the type 'System.Span' + var expectedDiagnostics = new[] + { + // (17,19): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. // TakesSpan(default(Span), await I1()); - Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span") - ); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "default(Span)").WithArguments("System.Span").WithLocation(17, 19) + }; + + comp.VerifyEmitDiagnostics(expectedDiagnostics); comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.DebugExe); - comp.VerifyEmitDiagnostics( - // (17,39): error CS4007: 'await' cannot be used in an expression containing the type 'System.Span' - // TakesSpan(default(Span), await I1()); - Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span") - ); + comp.VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] @@ -1514,19 +1649,49 @@ public static async Task I1() CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); - comp.VerifyEmitDiagnostics( - // (14,45): error CS4007: 'await' cannot be used in an expression containing the type 'Span' + var expectedDiagnostics = new[] + { + // (14,22): error CS4007: Instance of type 'System.Span' cannot be preserved across 'await' or 'yield' boundary. // TakesSpan(s: default(Span), i: await I1()); - Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span").WithLocation(14, 45) - ); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "default(Span)").WithArguments("System.Span").WithLocation(14, 22) + }; + + comp.VerifyEmitDiagnostics(expectedDiagnostics); comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.DebugExe); - comp.VerifyEmitDiagnostics( - // (14,45): error CS4007: 'await' cannot be used in an expression containing the type 'Span' - // TakesSpan(s: default(Span), i: await I1()); - Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span").WithLocation(14, 45) - ); + comp.VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void AwaitAssignSpan() + { + var source = """ + using System; + using System.Threading.Tasks; + + ReadOnlySpan r = await M(); + Console.Write(r[1]); + + async Task M() + { + await Task.Yield(); + return new[] { 4, 5, 6 }; + } + """; + + CreateCompilationWithSpan(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,1): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ReadOnlySpan r = await M(); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ReadOnlySpan").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 1)); + + var expectedOutput = "5"; + + var comp = CreateCompilationWithSpan(source, parseOptions: TestOptions.RegularNext); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); + + comp = CreateCompilationWithSpan(source); + CompileAndVerify(comp, expectedOutput: expectedOutput).VerifyDiagnostics(); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/StackAllocInitializerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/StackAllocInitializerTests.cs index 2bc18e34ce28a..232f168d07c00 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/StackAllocInitializerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/StackAllocInitializerTests.cs @@ -757,13 +757,29 @@ async void M() comp.VerifyDiagnostics( // (8,38): error CS0150: A constant value is expected // Span p = stackalloc int[await Task.FromResult(1)] { await Task.FromResult(2) }; - Diagnostic(ErrorCode.ERR_ConstantExpected, "await Task.FromResult(1)").WithLocation(8, 38), - // (8,9): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or async lambda expressions. - // Span p = stackalloc int[await Task.FromResult(1)] { await Task.FromResult(2) }; - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "Span").WithArguments("System.Span").WithLocation(8, 9) + Diagnostic(ErrorCode.ERR_ConstantExpected, "await Task.FromResult(1)").WithLocation(8, 38) ); } + [Fact] + public void TestAwait_Span_02() + { + var comp = CreateCompilationWithMscorlibAndSpan(""" + using System; + using System.Threading.Tasks; + class Test + { + static async Task Main() + { + Span p = stackalloc int[1] { await Task.FromResult(2) }; + Console.WriteLine(p[0]); + } + } + """, TestOptions.UnsafeReleaseExe); + + CompileAndVerify(comp, expectedOutput: "2", verify: Verification.Fails).VerifyDiagnostics(); + } + [Fact] public void TestSelfInSize() { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs index 6ab50856c1131..a8723ce4cb72b 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs @@ -1113,13 +1113,24 @@ public void LocalDeclarationStatement_18() await System.Threading.Tasks.Task.Yield(); "; + var expectedDiagnostics = new[] + { + // (3,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // ref int d = ref c; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "d").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 9) + }; + var comp = CreateCompilation(text, options: TestOptions.DebugExe, parseOptions: DefaultParseOptions); + comp.VerifyDiagnostics(expectedDiagnostics); - comp.VerifyDiagnostics( - // (3,9): error CS8177: Async methods cannot have by-reference locals - // ref int d = ref c; - Diagnostic(ErrorCode.ERR_BadAsyncLocalType, "d").WithLocation(3, 9) - ); + comp = CreateCompilation(text, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular12); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(text, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(text, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics(); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 12753c86accd8..ccfc049d18034 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -275,67 +275,2326 @@ unsafe System.Collections.Generic.IEnumerator Goo() } "; - CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (4,56): error CS1629: Unsafe code may not appear in iterators - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "Goo")); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe System.Collections.Generic.IEnumerator Goo() + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Goo").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56)); + + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [Fact] + public void IteratorUnsafe3() + { + var text = @" +class C +{ + System.Collections.Generic.IEnumerator Goo() + { + unsafe { } + yield return 1; + } +} +"; + + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe { } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); + + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [Fact] + public void IteratorUnsafe4() + { + var text = @" +unsafe class C +{ + System.Collections.Generic.IEnumerator Goo() + { + unsafe { } + yield return 1; + } +} +"; + + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe { } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9)); + + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [WorkItem(546657, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546657")] + [Fact] + public void IteratorUnsafe5() + { + var text = @" +unsafe class C +{ + System.Collections.Generic.IEnumerator Goo() + { + System.Action a = () => { unsafe { } }; + yield return 1; + } +} +"; + + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,35): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // System.Action a = () => { unsafe { } }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 35)); + + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73280")] + public void Iterator_UnsafeBlock_LangVersion() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M1() + { + unsafe // langversion error in C# 12 + { + int* p = null; // unnecessary langversion error in C# 12 + } + yield break; + } + System.Collections.Generic.IEnumerable M2() + { + int* p = null; // necessary langversion error in C# 12 + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe // langversion error in C# 12 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9), + // (7,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int* p = null; // unnecessary langversion error in C# 12 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 13), + // (13,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int* p = null; // necessary langversion error in C# 12 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(13, 9)); + + var expectedDiagnostics = new[] + { + // (13,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* p = null; // necessary langversion error in C# 12 + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(13, 9) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeBlock_Local() + { + var code = """ + class C + { + public System.Collections.Generic.IEnumerable M() + { + int x = 1; + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield return x; + } + } + """; + + // https://github.com/dotnet/roslyn/issues/73280 - diagnostics inside the unsafe block are unnecessary + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (6,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 9), + // (8,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 13), + // (8,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 22), + // (9,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 14), + // (9,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 19)); + + var expectedDiagnostics = new[] + { + // (8,23): error CS9239: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(8, 23) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeBlock_Parameter() + { + var code = """ + class C + { + public System.Collections.Generic.IEnumerable M(int x) + { + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield return x; + } + } + """; + + // https://github.com/dotnet/roslyn/issues/73280 - diagnostics inside the unsafe block are unnecessary + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9), + // (7,13): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int *").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 13), + // (7,22): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int *p = &x; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "&x").WithArguments("ref and unsafe in async and iterator methods").WithLocation(7, 22), + // (8,14): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 14), + // (8,19): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // *p = *p + 1; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "p").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 19)); + + var expectedDiagnostics = new[] + { + // (7,23): error CS9239: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(7, 23) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeBlock_Field_01() + { + var code = """ + class Program + { + static int _f; + static System.Collections.Generic.IEnumerable F() + { + unsafe + { + fixed (int* p = &_f) { } + } + yield break; + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void Iterator_UnsafeBlock_Field_02() + { + var code = """ + #pragma warning disable CS0649 // field is never assigned to + unsafe class Program + { + static int* _p; + static System.Collections.Generic.IEnumerable F() + { + unsafe + { + int* p = _p; + p = &p[1]; + } + yield break; + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void Iterator_UnsafeBlock_Field_03() + { + var code = """ + struct S + { + public int F; + } + class Program + { + static System.Collections.Generic.IEnumerable F() + { + unsafe + { + S s = default; + int* p = &s.F; + } + yield break; + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (12,23): error CS9239: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int* p = &s.F; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "s.F").WithLocation(12, 23)); + } + + [Fact] + public void Iterator_UnsafeBlock_Field_04() + { + var code = """ + class Program + { + static int _f; + static System.Collections.Generic.IEnumerable F() + { + unsafe + { + int* p = &_f; + (*p)++; + } + yield break; + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (8,22): error CS0212: You can only take the address of an unfixed expression inside of a fixed statement initializer + // int* p = &_f; + Diagnostic(ErrorCode.ERR_FixedNeeded, "&_f").WithLocation(8, 22)); + } + + [Fact] + public void Iterator_UnsafeBlock_SizeOf() + { + var code = """ + foreach (var x in new C().M()) System.Console.Write(x); + + class C + { + public System.Collections.Generic.IEnumerable M() + { + int x; + unsafe + { + x = sizeof(nint); + } + yield return x; + } + } + """; + + // https://github.com/dotnet/roslyn/issues/73280 - diagnostics inside the unsafe block are unnecessary + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (8,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(8, 9), + // (10,17): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // x = sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 17)); + + var expectedOutput = IntPtr.Size.ToString(); + CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CompileAndVerify(code, expectedOutput: expectedOutput, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + } + + [Fact] + public void Iterator_UnsafeBlock_YieldBreak() + { + var code = """ + class C + { + public System.Collections.Generic.IEnumerable M() + { + unsafe + { + yield break; + } + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [Fact] + public void Iterator_UnsafeBlock_YieldReturn() + { + var code = """ + class C + { + public System.Collections.Generic.IEnumerable M() + { + unsafe + { + yield return 1; + } + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe + Diagnostic(ErrorCode.ERR_FeatureInPreview, "unsafe").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9)); + + var expectedDiagnostics = new[] + { + // (7,13): error CS9238: Cannot use 'yield return' in an 'unsafe' block + // yield return 1; + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(7, 13) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_UnsafeBlock_Async_01() + { + var code = """ + await foreach (var x in new C().M()) System.Console.Write(x); + + class C + { + public async System.Collections.Generic.IAsyncEnumerable M() + { + int x = 1; + await System.Threading.Tasks.Task.Yield(); + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield return x; + } + } + """ + AsyncStreamsTypes; + + var comp = CreateCompilationWithTasksExtensions(code, options: TestOptions.UnsafeReleaseExe); + CompileAndVerify(comp, expectedOutput: "1", verify: Verification.Fails).VerifyDiagnostics( + // (11,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(11, 23)); + } + + // Should behave equivalently to AwaitBetweenUnsafeBlocks. + [Fact] + public void Iterator_UnsafeBlock_Async_02() + { + var code = """ + class C + { + public System.Collections.Generic.IEnumerable M() + { + int x = 1; + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield return x; + unsafe + { + int *p = &x; + *p = *p + 1; + } + yield return x; + unsafe + { + int *p = &x; + if (*p == 3) yield break; + } + yield return x; + } + } + """; + + var expectedDiagnostics = new[] + { + // (8,23): error CS9239: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(8, 23), + // (14,23): error CS9239: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(14, 23), + // (20,23): error CS9239: The '&' operator cannot be used on parameters or local variables in iterator methods. + // int *p = &x; + Diagnostic(ErrorCode.ERR_AddressOfInIterator, "x").WithLocation(20, 23) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + // Should behave equivalently to Iterator_UnsafeBlock_Async_02. + [Fact] + public void AwaitBetweenUnsafeBlocks() + { + var code = """ + using System; + using System.Threading.Tasks; + + await new C().M(); + + class C + { + async Task Report(int x) + { + Console.Write(x); + await Task.Yield(); + } + public async Task M() + { + int x = 1; + unsafe + { + int *p = &x; + *p = *p + 1; + } + await Report(x); + unsafe + { + int *p = &x; + *p = *p + 1; + } + await Report(x); + unsafe + { + int *p = &x; + if (*p == 3) return; + } + await Report(x); + } + } + """; + var expectedDiagnostics = new[] + { + // (18,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(18, 23), + // (24,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(24, 23), + // (30,23): warning CS9123: The '&' operator should not be used on parameters or local variables in async methods. + // int *p = &x; + Diagnostic(ErrorCode.WRN_AddressOfInAsync, "x").WithLocation(30, 23) + }; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void Iterator_LocalFunction_Nested() + { + var code = """ + class Program + { + static void F() + { + unsafe + { + static System.Collections.Generic.IEnumerable G(int x) + { + unsafe + { + x = sizeof(nint); + } + yield return x; + + unsafe + { + G2(new int*[0]); + static System.Collections.Generic.IEnumerable G2(int*[] x) + { + int y; + unsafe + { + y = *x[0]; + } + yield return y; + } + } + } + G(0); + } + } + } + """; + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [Fact] + public void UnsafeContext_LambdaInIterator_Async() + { + var code = """ + using System.Collections.Generic; + using System.Threading.Tasks; + unsafe class C + { + IEnumerable M() + { + yield return 1; + var lam = async () => await Task.Yield(); + } + } + """; + + // https://github.com/dotnet/roslyn/issues/73280 - these should ideally be langversion errors + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,31): error CS4004: Cannot await in an unsafe context + // var lam = async () => await Task.Yield(); + Diagnostic(ErrorCode.ERR_AwaitInUnsafeContext, "await Task.Yield()").WithLocation(8, 31)); + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [Fact] + public void UnsafeContext_LocalFunctionInIterator_Async() + { + var code = """ + using System.Collections.Generic; + using System.Threading.Tasks; + unsafe class C + { + IEnumerable M() + { + yield return 1; + local(); + async void local() { await Task.Yield(); } + } + } + """; + + // https://github.com/dotnet/roslyn/issues/73280 - these should ideally be langversion errors + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (9,30): error CS4004: Cannot await in an unsafe context + // async void local() { await Task.Yield(); } + Diagnostic(ErrorCode.ERR_AwaitInUnsafeContext, "await Task.Yield()").WithLocation(9, 30)); + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [Fact] + public void UnsafeContext_LambdaInIterator_Unsafe() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + yield return 1; + var lam = () => sizeof(nint); + } + } + """; + + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,25): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var lam = () => sizeof(nint); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "sizeof(nint)").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 25)); + + var expectedDiagnostics = new[] + { + // (6,25): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // var lam = () => sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 25) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_LocalFunctionInIterator_BreakingChange() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + yield return 1; + local(); + void local() { int* p = null; } + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); + + var expectedDiagnostics = new[] + { + // (7,24): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void local() { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(7, 24) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_LocalFunctionInIterator_BreakingChangeWorkaround() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + yield return 1; + local(); + unsafe void local() { int* p = null; } + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + } + + [Fact] + public void UnsafeContext_LocalFunctionInIterator_BreakingChange_Property() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable P + { + get + { + yield return 1; + local(); + void local() { int* p = null; } + } + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); + + var expectedDiagnostics = new[] + { + // (9,28): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void local() { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(9, 28) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_LocalFunctionInIterator_BreakingChange_Operator() + { + var code = """ + unsafe class C + { + public static System.Collections.Generic.IEnumerable operator+(C c1, C c2) + { + yield return 1; + local(); + void local() { int* p = null; } + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); + + var expectedDiagnostics = new[] + { + // (7,24): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void local() { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(7, 24) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_LocalFunctionInIterator_BreakingChange_Nested_01() + { + var code = """ + unsafe class C + { + void M() + { + local1(); + System.Collections.Generic.IEnumerable local1() + { + yield return 1; + local2(); + void local2() { int* p = null; } + } + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); + + var expectedDiagnostics = new[] + { + // (10,29): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void local2() { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 29) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_LocalFunctionInIterator_BreakingChange_Nested_02() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + yield return 1; + local1(); + void local1() + { + local2(); + void local2() { int* p = null; } + } + } + } + """; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); + + var expectedDiagnostics = new[] + { + // (10,29): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void local2() { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(10, 29) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73280")] + public void UnsafeContext_LangVersion() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + int* p = null; + yield break; + } + } + """; + + // https://github.com/dotnet/roslyn/issues/73280 - should not be a langversion error since this remains an error in C# 13 + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int* p = null; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "int*").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9)); + + var expectedDiagnostics = new[] + { + // (5,9): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* p = null; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(5, 9) + }; + + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Method_Signature_Unsafe(bool unsafeClass, bool unsafeMethod) + { + if (!unsafeClass && !unsafeMethod) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeMethod ? "unsafe" : "")}} void M(int* p) { } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Method_Signature_Safe() + { + var code = """ + class C + { + void M(int* p) { } + } + """; + + var expectedDiagnostics = new[] + { + // (3,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void M(int* p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 12) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Method_Body_Unsafe(bool unsafeClass, bool unsafeMethod) + { + if (!unsafeClass && !unsafeMethod) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeMethod ? "unsafe" : "")}} int M() + { + return sizeof(nint); + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Method_Body_Safe() + { + var code = """ + class C + { + int M() + { + return sizeof(nint); + } + } + """; + + var expectedDiagnostics = new[] + { + // (5,16): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 16) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Method_Iterator_Signature_UnsafeClass() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M(int*[] p) + { + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Method_Iterator_Signature_UnsafeMethod(bool unsafeClass) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + unsafe System.Collections.Generic.IEnumerable M(int*[] p) + { + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (3,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe System.Collections.Generic.IEnumerable M(int*[] p) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 56)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Method_Iterator_Signature_Safe() + { + var code = """ + class C + { + System.Collections.Generic.IEnumerable M(int*[] p) + { + yield break; + } + } + """; + + var expectedDiagnostics = new[] + { + // (3,51): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // System.Collections.Generic.IEnumerable M(int*[] p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 51) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Method_Iterator_Body_CSharp12_Safe() + { + var code = """ + class C + { + System.Collections.Generic.IEnumerable M() + { + yield return sizeof(nint); + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22)); + } + + [Fact] + public void UnsafeContext_Method_Iterator_Body_CSharp12_Safe_NestedBlock() + { + var code = """ + class C + { + System.Collections.Generic.IEnumerable M() + { + { + yield return sizeof(nint); + } + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (6,26): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 26)); + } + + [Fact] + public void UnsafeContext_Method_Iterator_Body_CSharp12_Unsafe() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + yield return local(); + int local() => sizeof(nint); + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Method_Iterator_Body_CSharp12_Unsafe_NestedBlock() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable M() + { + { + yield return local(); + } + int local() => sizeof(nint); + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Method_Iterator_Body_CSharp13(bool unsafeClass, bool unsafeMethod) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeMethod ? "unsafe" : "")}} System.Collections.Generic.IEnumerable M() + { + yield return sizeof(nint); + } + } + """; + + var expectedDiagnostics = new[] + { + // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Method_Iterator_Body_CSharp13_NestedBlock(bool unsafeClass, bool unsafeMethod) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeMethod ? "unsafe" : "")}} System.Collections.Generic.IEnumerable M() + { + { + yield return sizeof(nint); + } + } + } + """; + + var expectedDiagnostics = new[] + { + // (6,26): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 26) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Operator_Signature_Unsafe(bool unsafeClass, bool unsafeOperator) + { + if (!unsafeClass && !unsafeOperator) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeOperator ? "unsafe" : "")}} public static C operator+(C c, int* p) + { + return c; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Operator_Signature_Safe() + { + var code = """ + class C + { + public static C operator+(C c, int* p) + { + return c; + } + } + """; + + var expectedDiagnostics = new[] + { + // (3,36): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // public static C operator+(C c, int* p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 36) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Operator_Body_Unsafe(bool unsafeClass, bool unsafeOperator) + { + if (!unsafeClass && !unsafeOperator) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeOperator ? "unsafe" : "")}} public static int operator+(C c1, C c2) + { + return sizeof(nint); + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Operator_Body_Safe() + { + var code = """ + class C + { + public static int operator+(C c1, C c2) + { + return sizeof(nint); + } + } + """; + + var expectedDiagnostics = new[] + { + // (5,16): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 16) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Operator_Iterator_Signature_UnsafeClass() + { + var code = """ + unsafe class C + { + public static System.Collections.Generic.IEnumerable operator+(C c, int*[] p) + { + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Operator_Iterator_Signature_UnsafeOperator(bool unsafeClass) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + public static unsafe System.Collections.Generic.IEnumerable operator+(C c, int*[] p) + { + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (3,78): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static unsafe System.Collections.Generic.IEnumerable operator+(C c, int*[] p) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "+").WithArguments("ref and unsafe in async and iterator methods").WithLocation(3, 78)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Operator_Iterator_Signature_Safe() + { + var code = """ + class C + { + public static System.Collections.Generic.IEnumerable operator+(C c, int*[] p) + { + yield break; + } + } + """; + + var expectedDiagnostics = new[] + { + // (3,78): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // public static System.Collections.Generic.IEnumerable operator+(C c, int*[] p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 78) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Operator_Iterator_Body_CSharp12_Safe() + { + var code = """ + class C + { + public static System.Collections.Generic.IEnumerable operator+(C c1, C c2) + { + yield return sizeof(nint); + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22)); + } + + [Fact] + public void UnsafeContext_Operator_Iterator_Body_CSharp12_Unsafe() + { + var code = """ + unsafe class C + { + public static System.Collections.Generic.IEnumerable operator+(C c1, C c2) + { + yield return local(); + int local() => sizeof(nint); + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Operator_Iterator_Body_CSharp13(bool unsafeClass, bool unsafeIndexer) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeIndexer ? "unsafe" : "")}} public static System.Collections.Generic.IEnumerable operator+(C c1, C c2) + { + yield return sizeof(nint); + } + } + """; + + var expectedDiagnostics = new[] + { + // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Indexer_Signature_Unsafe(bool unsafeClass, bool unsafeIndexer) + { + if (!unsafeClass && !unsafeIndexer) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeIndexer ? "unsafe" : "")}} int this[int* p] + { + get { return 0; } + set { } + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Indexer_Signature_Safe() + { + var code = """ + class C + { + int this[int* p] + { + get { return 0; } + set { } + } + } + """; + + var expectedDiagnostics = new[] + { + // (3,14): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int this[int* p] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 14) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Indexer_Body_Unsafe(bool unsafeClass, bool unsafeIndexer) + { + if (!unsafeClass && !unsafeIndexer) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeIndexer ? "unsafe" : "")}} int this[int x] + { + get { return sizeof(nint); } + set { int* p = null; } + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Indexer_Body_Safe() + { + var code = """ + class C + { + int this[int x] + { + get { return sizeof(nint); } + set { int* p = null; } + } + } + """; + + var expectedDiagnostics = new[] + { + // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22), + // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Indexer_Iterator_Signature_UnsafeClass() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable this[int*[] p] + { + get { yield break; } + set { } + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Indexer_Iterator_Signature_UnsafeIndexer(bool unsafeClass) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + unsafe System.Collections.Generic.IEnumerable this[int*[] p] + { + get { yield break; } + set { } + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // get { yield break; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "get").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Indexer_Iterator_Signature_Safe() + { + var code = """ + class C + { + System.Collections.Generic.IEnumerable this[int*[] p] + { + get { yield break; } + set { } + } + } + """; + + var expectedDiagnostics = new[] + { + // (3,54): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // System.Collections.Generic.IEnumerable this[int*[] p] + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 54) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Indexer_Iterator_Body_CSharp12_Safe() + { + var code = """ + class C + { + System.Collections.Generic.IEnumerable this[int x] + { + get { yield return sizeof(nint); } + set { int* p = null; } + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 28), + // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15)); + } + + [Fact] + public void UnsafeContext_Indexer_Iterator_Body_CSharp12_Unsafe() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable this[int x] + { + get + { + yield return local(); + int local() => sizeof(nint); + } + set { int* p = null; } + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Indexer_Iterator_Body_CSharp13_UnsafeSetter(bool unsafeClass, bool unsafeIndexer) + { + if (!unsafeClass && !unsafeIndexer) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeIndexer ? "unsafe" : "")}} System.Collections.Generic.IEnumerable this[int x] + { + get { yield return sizeof(nint); } + set { int* p = null; } + } + } + """; + + var expectedDiagnostics = new[] + { + // (5,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 28) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Indexer_Iterator_Body_CSharp13_SafeSetter() + { + var code = """ + class C + { + System.Collections.Generic.IEnumerable this[int x] + { + get { yield return sizeof(nint); } + set { int* p = null; } + } + } + """; + + var expectedDiagnostics = new[] + { + // (5,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 28), + // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Property_Signature_Unsafe(bool unsafeClass, bool unsafeProperty) + { + if (!unsafeClass && !unsafeProperty) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeProperty ? "unsafe" : "")}} int* P + { + get { throw null; } + set { } + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Property_Signature_Safe() + { + var code = """ + class C + { + int* P + { + get { throw null; } + set { } + } + } + """; + + var expectedDiagnostics = new[] + { + // (3,5): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // int* P + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 5) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Property_Body_Unsafe(bool unsafeClass, bool unsafeProperty) + { + if (!unsafeClass && !unsafeProperty) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeProperty ? "unsafe" : "")}} int P + { + get { return sizeof(nint); } + set { int* p = null; } + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Property_Body_Safe() + { + var code = """ + class C + { + int P + { + get { return sizeof(nint); } + set { int* p = null; } + } + } + """; + + var expectedDiagnostics = new[] + { + // (5,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 22), + // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Property_Iterator_Signature_UnsafeClass() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable P + { + get { yield break; } + set { } + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Property_Iterator_Signature_UnsafeProperty(bool unsafeClass) + { + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + unsafe System.Collections.Generic.IEnumerable P + { + get { yield break; } + set { } + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,9): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // get { yield break; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "get").WithArguments("ref and unsafe in async and iterator methods").WithLocation(5, 9)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Property_Iterator_Signature_Safe() + { + var code = """ + class C + { + System.Collections.Generic.IEnumerable P + { + get { yield break; } + set { } + } + } + """; + + var expectedDiagnostics = new[] + { + // (3,44): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // System.Collections.Generic.IEnumerable P + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(3, 44) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Property_Iterator_Body_CSharp12_Safe() + { + var code = """ + class C + { + System.Collections.Generic.IEnumerable P + { + get { yield return sizeof(nint); } + set { int* p = null; } + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (5,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 28), + // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15)); + } + + [Fact] + public void UnsafeContext_Property_Iterator_Body_CSharp12_Unsafe() + { + var code = """ + unsafe class C + { + System.Collections.Generic.IEnumerable P + { + get + { + yield return local(); + int local() => sizeof(nint); + } + set { int* p = null; } + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void UnsafeContext_Property_Iterator_Body_CSharp13_UnsafeSetter(bool unsafeClass, bool unsafeProperty) + { + if (!unsafeClass && !unsafeProperty) + { + return; + } + + var code = $$""" + {{(unsafeClass ? "unsafe" : "")}} class C + { + {{(unsafeProperty ? "unsafe" : "")}} System.Collections.Generic.IEnumerable P + { + get { yield return sizeof(nint); } + set { int* p = null; } + } + } + """; + + var expectedDiagnostics = new[] + { + // (5,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 28) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] - public void IteratorUnsafe3() + public void UnsafeContext_Property_Iterator_Body_CSharp13_SafeSetter() { - var text = @" -class C -{ - System.Collections.Generic.IEnumerator Goo() - { - unsafe { } - yield return 1; - } -} -"; + var code = """ + class C + { + System.Collections.Generic.IEnumerable P + { + get { yield return sizeof(nint); } + set { int* p = null; } + } + } + """; - CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (6,9): error CS1629: Unsafe code may not appear in iterators - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "unsafe")); + var expectedDiagnostics = new[] + { + // (5,28): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // get { yield return sizeof(nint); } + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(5, 28), + // (6,15): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // set { int* p = null; } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(6, 15) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_LocalFunction_Signature_Unsafe(bool unsafeBlock, bool unsafeFunction) + { + if (!unsafeBlock && !unsafeFunction) + { + return; + } + + var code = $$""" + #pragma warning disable CS8321 // The local function 'M' is declared but never used + {{(unsafeBlock ? "unsafe" : "")}} + { + {{(unsafeFunction ? "unsafe" : "")}} void M(int* p) { } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } [Fact] - public void IteratorUnsafe4() + public void UnsafeContext_LocalFunction_Signature_Safe() { - var text = @" -unsafe class C -{ - System.Collections.Generic.IEnumerator Goo() - { - unsafe { } - yield return 1; - } -} -"; + var code = """ + #pragma warning disable CS8321 // The local function 'M' is declared but never used + void M(int* p) { } + """; - CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (6,9): error CS1629: Unsafe code may not appear in iterators - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "unsafe")); + var expectedDiagnostics = new[] + { + // (2,8): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // void M(int* p) { } + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(2, 8) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory, CombinatorialData] + public void UnsafeContext_LocalFunction_Body_Unsafe(bool unsafeBlock, bool unsafeFunction) + { + if (!unsafeBlock && !unsafeFunction) + { + return; + } + + var code = $$""" + #pragma warning disable CS8321 // The local function 'M' is declared but never used + {{(unsafeBlock ? "unsafe" : "")}} + { + {{(unsafeFunction ? "unsafe" : "")}} int M() + { + return sizeof(nint); + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); } - [WorkItem(546657, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546657")] [Fact] - public void IteratorUnsafe5() + public void UnsafeContext_LocalFunction_Body_Safe() { - var text = @" -unsafe class C -{ - System.Collections.Generic.IEnumerator Goo() - { - System.Action a = () => { unsafe { } }; - yield return 1; - } -} -"; + var code = """ + #pragma warning disable CS8321 // The local function 'M' is declared but never used + int M() + { + return sizeof(nint); + } + """; - CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (6,9): error CS1629: Unsafe code may not appear in iterators - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "unsafe")); + var expectedDiagnostics = new[] + { + // (4,12): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(4, 12) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_LocalFunction_Iterator_Signature_UnsafeBlock() + { + var code = """ + #pragma warning disable CS8321 // The local function 'M' is declared but never used + unsafe + { + System.Collections.Generic.IEnumerable M(int*[] p) + { + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void UnsafeContext_LocalFunction_Iterator_Signature_UnsafeFunction(bool unsafeBlock) + { + var code = $$""" + #pragma warning disable CS8321 // The local function 'M' is declared but never used + {{(unsafeBlock ? "unsafe" : "")}} + { + unsafe System.Collections.Generic.IEnumerable M(int*[] p) + { + yield break; + } + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (4,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe System.Collections.Generic.IEnumerable M(int*[] p) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "M").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56)); + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_LocalFunction_Iterator_Signature_Safe() + { + var code = """ + #pragma warning disable CS8321 // The local function 'M' is declared but never used + System.Collections.Generic.IEnumerable M(int*[] p) + { + yield break; + } + """; + + var expectedDiagnostics = new[] + { + // (2,47): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // System.Collections.Generic.IEnumerable M(int*[] p) + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(2, 47) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_LocalFunction_Iterator_Body_CSharp12_Safe() + { + var code = """ + #pragma warning disable CS8321 // The local function 'M' is declared but never used + System.Collections.Generic.IEnumerable M() + { + yield return sizeof(nint); + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics( + // (4,18): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(4, 18)); + } + + [Fact] + public void UnsafeContext_LocalFunction_Iterator_Body_CSharp12_Unsafe() + { + var code = """ + #pragma warning disable CS8321 // The local function 'M' is declared but never used + unsafe + { + System.Collections.Generic.IEnumerable M() + { + yield return local(); + int local() => sizeof(nint); + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + } + + [Theory, CombinatorialData] + public void UnsafeContext_LocalFunction_Iterator_Body_CSharp13(bool unsafeBlock, bool unsafeFunction) + { + var code = $$""" + #pragma warning disable CS8321 // The local function 'M' is declared but never used + {{(unsafeBlock ? "unsafe" : "")}} + { + {{(unsafeFunction ? "unsafe" : "")}} System.Collections.Generic.IEnumerable M() + { + yield return sizeof(nint); + } + } + """; + + var expectedDiagnostics = new[] + { + // (6,22): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(6, 22) + }; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Lambda_Signature_Unsafe() + { + var code = """ + unsafe + { + var lam = (int* p) => { }; + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Lambda_Signature_Safe() + { + var code = """ + var lam = (int* p) => { }; + """; + + var expectedDiagnostics = new[] + { + // (1,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // var lam = (int* p) => { }; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 12), + // (1,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // var lam = (int* p) => { }; + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(1, 17) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Lambda_Body_Unsafe() + { + var code = """ + unsafe + { + var lam = () => + { + return sizeof(nint); + }; + } + """; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(); + } + + [Fact] + public void UnsafeContext_Lambda_Body_Safe() + { + var code = """ + var lam = () => + { + return sizeof(nint); + }; + """; + + var expectedDiagnostics = new[] + { + // (3,12): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(3, 12) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Lambda_Iterator_Signature_Unsafe() + { + var code = """ + unsafe + { + var lam = (int*[] p) => + { + yield break; + }; + } + """; + + var expectedDiagnostics = new[] + { + // (5,9): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield break; + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(5, 9) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Lambda_Iterator_Signature_Safe() + { + var code = """ + var lam = (int*[] p) => + { + yield break; + }; + """; + + var expectedDiagnostics = new[] + { + // (1,12): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // var lam = (int*[] p) => + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(1, 12), + // (1,19): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // var lam = (int*[] p) => + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "p").WithLocation(1, 19), + // (3,5): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield break; + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(3, 5) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Lambda_Iterator_Body_Unsafe() + { + var code = """ + unsafe + { + var lam = () => + { + yield return sizeof(nint); + }; + } + """; + + var expectedDiagnostics = new[] + { + // (5,9): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(5, 9) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + + expectedDiagnostics = [ + // (5,9): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(5, 9), + // (5,9): error CS9238: Cannot use 'yield return' in an 'unsafe' block + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_BadYieldInUnsafe, "yield").WithLocation(5, 9) + ]; + + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeContext_Lambda_Iterator_Body_Safe() + { + var code = """ + var lam = () => + { + yield return sizeof(nint); + }; + """; + + var expectedDiagnostics = new[] + { + // (3,5): error CS1621: The yield statement cannot be used inside an anonymous method or lambda expression + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_YieldInAnonMeth, "yield").WithLocation(3, 5), + // (3,18): error CS0233: 'nint' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // yield return sizeof(nint); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(nint)").WithArguments("nint").WithLocation(3, 18) + }; + + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(code, options: TestOptions.UnsafeReleaseExe).VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UnsafeBlock_InAsyncMethod() + { + var code = """ + using System.Threading.Tasks; + class C + { + async Task M(int x) + { + unsafe { x = sizeof(nint); } + await Task.Yield(); + } + } + """; + CreateCompilation(code, parseOptions: TestOptions.Regular12, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + CreateCompilation(code, parseOptions: TestOptions.RegularNext, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + CreateCompilation(code, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); } [Fact] @@ -936,18 +3195,41 @@ public void UnsafeIteratorSignatures() Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p")); var withUnsafeOnMembers = string.Format(template, "", "unsafe"); - CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (4,64): error CS1637: Iterators cannot have pointer type parameters - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p"), - // (4,56): error CS1629: Unsafe code may not appear in iterators - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "Iterator")); //this is for putting "unsafe" on an iterator, not for the parameter type + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,70): error CS1637: Iterators cannot have pointer type parameters + // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(4, 70), + // (4,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Iterator").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56)); //this is for putting "unsafe" on an iterator, not for the parameter type + + var expectedDiagnostics = new[] + { + // (4,70): error CS1637: Iterators cannot have pointer type parameters + // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(4, 70) + }; + + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); var withUnsafeOnTypeAndMembers = string.Format(template, "unsafe", "unsafe"); - CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (4,64): error CS1637: Iterators cannot have pointer type parameters - Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p"), - // (4,56): error CS1629: Unsafe code may not appear in iterators - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "Iterator")); //this is for putting "unsafe" on an iterator, not for the parameter type + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,70): error CS1637: Iterators cannot have pointer type parameters + // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(4, 70), + // (4,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Iterator").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56)); //this is for putting "unsafe" on an iterator, not for the parameter type + + expectedDiagnostics = [ + // (4,70): error CS1637: Iterators cannot have pointer type parameters + // unsafe System.Collections.Generic.IEnumerable Iterator(int* p) + Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "p").WithLocation(4, 70) + ]; + + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -974,18 +3256,24 @@ public void UnsafeIteratorSignatures_PointerArray() CreateCompilation(withUnsafeOnType, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(); var withUnsafeOnMembers = string.Format(template, "", "unsafe"); - CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (4,56): error CS1629: Unsafe code may not appear in iterators + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // unsafe System.Collections.Generic.IEnumerable Iterator(int*[] p) - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "Iterator").WithLocation(4, 56) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Iterator").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56) ); + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(withUnsafeOnMembers, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); + var withUnsafeOnTypeAndMembers = string.Format(template, "unsafe", "unsafe"); - CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( - // (4,56): error CS1629: Unsafe code may not appear in iterators + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,56): error CS8652: The feature 'ref and unsafe in async and iterator methods' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // unsafe System.Collections.Generic.IEnumerable Iterator(int*[] p) - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "Iterator").WithLocation(4, 56) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Iterator").WithArguments("ref and unsafe in async and iterator methods").WithLocation(4, 56) ); + + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(withUnsafeOnTypeAndMembers, options: TestOptions.UnsafeReleaseDll).VerifyEmitDiagnostics(); } [Fact] @@ -8156,10 +10444,17 @@ System.Collections.Generic.IEnumerable M() } } "; - CreateCompilation(text).VerifyDiagnostics( - // (6,22): error CS1629: Unsafe code may not appear in iterators + + var expectedDiagnostics = new[] + { + // (6,22): error CS0233: 'S' does not have a predefined size, therefore sizeof can only be used in an unsafe context // yield return sizeof(S); - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "sizeof(S)")); + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(S)").WithArguments("S").WithLocation(6, 22) + }; + + CreateCompilation(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(text, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(text).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -8522,10 +10817,17 @@ System.Collections.Generic.IEnumerable M() } } "; - CreateCompilation(text).VerifyDiagnostics( - // (6,17): error CS1629: Unsafe code may not appear in iterators + + var expectedDiagnostics = new[] + { + // (6,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // var p = stackalloc int[1]; - Diagnostic(ErrorCode.ERR_IllegalInnerUnsafe, "stackalloc int[1]")); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "stackalloc int[1]").WithLocation(6, 17) + }; + + CreateCompilation(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(text, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(text).VerifyDiagnostics(expectedDiagnostics); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UsingStatementTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UsingStatementTests.cs index 3b9371a1c3769..610897b83d561 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UsingStatementTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UsingStatementTests.cs @@ -1127,12 +1127,67 @@ static async Task Main() } } }"; - var compilation = CreateCompilationWithTasksExtensions(new[] { source, IAsyncDisposableDefinition }).VerifyDiagnostics( - // (16,22): error CS4012: Parameters or locals of type 'S1' cannot be declared in async methods or async lambda expressions. + var compilation = CreateCompilationWithTasksExtensions(new[] { source, IAsyncDisposableDefinition }, options: TestOptions.ReleaseExe); + CompileAndVerify(compilation, expectedOutput: "Dispose async").VerifyDiagnostics(); + } + + [Fact] + public void UsingPatternAsyncTest_02() + { + var source = """ + using System.Threading.Tasks; + ref struct S1 + { + public ValueTask DisposeAsync() + { + System.Console.WriteLine("Dispose async"); + return new ValueTask(Task.CompletedTask); + } + } + class C2 + { + static async Task Main() + { + await using (S1 c = new S1()) + { + await Task.Yield(); + } + } + } + """; + var compilation = CreateCompilationWithTasksExtensions(new[] { source, IAsyncDisposableDefinition }); + compilation.VerifyEmitDiagnostics( + // 0.cs(14,25): error CS4007: Instance of type 'S1' cannot be preserved across 'await' or 'yield' boundary. // await using (S1 c = new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "S1").WithArguments("S1").WithLocation(16, 22) - ); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "c = new S1()").WithArguments("S1").WithLocation(14, 25)); + } + [Fact] + public void UsingPatternAsyncTest_03() + { + var source = """ + using System.Threading.Tasks; + ref struct S1 + { + public S1(int x) { } + public ValueTask DisposeAsync() + { + System.Console.WriteLine("Dispose async"); + return new ValueTask(Task.CompletedTask); + } + } + class C2 + { + static async Task Main() + { + await using (S1 c = new S1(await Task.FromResult(1))) + { + } + } + } + """; + var compilation = CreateCompilationWithTasksExtensions(new[] { source, IAsyncDisposableDefinition }, options: TestOptions.ReleaseExe); + CompileAndVerify(compilation, expectedOutput: "Dispose async").VerifyDiagnostics(); } [Fact] diff --git a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs index 587107287652c..9f5490d05adac 100644 --- a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs +++ b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs @@ -471,6 +471,10 @@ public void WarningLevel_2() // These are the warnings introduced with the warning "wave" shipped with dotnet 8 and C# 12. Assert.Equal(8, ErrorFacts.GetWarningLevel(errorCode)); break; + case ErrorCode.WRN_BadYieldInLock: + // These are the warnings introduced with the warning "wave" shipped with dotnet 9 and C# 13. + Assert.Equal(9, ErrorFacts.GetWarningLevel(errorCode)); + break; default: // If a new warning is added, this test will fail // and whoever is adding the new warning will have to update it with the expected error level. @@ -2979,6 +2983,7 @@ public void TestIsBuildOnlyDiagnostic() case ErrorCode.ERR_InterceptableMethodMustBeOrdinary: case ErrorCode.ERR_PossibleAsyncIteratorWithoutYield: case ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait: + case ErrorCode.ERR_RefLocalAcrossAwait: Assert.True(isBuildOnly, $"Check failed for ErrorCode.{errorCode}"); break; diff --git a/src/Features/CSharp/Portable/Diagnostics/LanguageServer/CSharpLspBuildOnlyDiagnostics.cs b/src/Features/CSharp/Portable/Diagnostics/LanguageServer/CSharpLspBuildOnlyDiagnostics.cs index 8a81b6d09d4b1..6bd117bf73410 100644 --- a/src/Features/CSharp/Portable/Diagnostics/LanguageServer/CSharpLspBuildOnlyDiagnostics.cs +++ b/src/Features/CSharp/Portable/Diagnostics/LanguageServer/CSharpLspBuildOnlyDiagnostics.cs @@ -59,7 +59,8 @@ namespace Microsoft.CodeAnalysis.CSharp.LanguageServer; "CS9178", // ErrorCode.ERR_InterceptorCannotBeGeneric "CS9207", // ErrorCode.ERR_InterceptableMethodMustBeOrdinary "CS8419", // ErrorCode.ERR_PossibleAsyncIteratorWithoutYield - "CS8420" // ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait + "CS8420", // ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait + "CS9217" // ErrorCode.ERR_RefLocalAcrossAwait )] [Shared] internal sealed class CSharpLspBuildOnlyDiagnostics : ILspBuildOnlyDiagnostics diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/RazorDynamicDocumentSyncRegistration.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/RazorDynamicDocumentSyncRegistration.cs index d255899e89c82..c9e35dd4f0c46 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/RazorDynamicDocumentSyncRegistration.cs +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/RazorDynamicDocumentSyncRegistration.cs @@ -46,7 +46,7 @@ public async Task OnInitializedAsync(ClientCapabilities clientCapabilities, Requ { var languageServerManager = context.GetRequiredLspService(); - var documentFilters = new[] { new DocumentFilter() { Pattern = "**/*.razor" }, new DocumentFilter() { Pattern = "**/*.cshtml" } }; + var documentFilters = new[] { new DocumentFilter() { Pattern = "**/*.{razor, cshtml}", Language = "aspnetcorerazor" } }; var registrationOptions = new TextDocumentRegistrationOptions() { DocumentSelector = documentFilters @@ -66,7 +66,11 @@ await languageServerManager.SendRequestAsync(Methods.ClientRegisterCapabilityNam { Id = Guid.NewGuid().ToString(), // No need to save this for unregistering Method = Methods.TextDocumentDidChangeName, - RegisterOptions = registrationOptions + RegisterOptions = new TextDocumentChangeRegistrationOptions() + { + DocumentSelector = documentFilters, + SyncKind = TextDocumentSyncKind.Incremental + } }, new() { diff --git a/src/Features/LanguageServer/Protocol/Protocol/TextDocumentChangeRegistrationOptions.cs b/src/Features/LanguageServer/Protocol/Protocol/TextDocumentChangeRegistrationOptions.cs new file mode 100644 index 0000000000000..39de99b3501a0 --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Protocol/TextDocumentChangeRegistrationOptions.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using Roslyn.LanguageServer.Protocol; + +namespace Roslyn.LanguageServer.Protocol +{ + /// + /// Class representing the registration options for didChange events. + /// + /// See the Language Server Protocol specification for additional information. + /// + [DataContract] + internal class TextDocumentChangeRegistrationOptions : TextDocumentRegistrationOptions + { + /// + /// How documents are synced to the server. See + /// and . + /// + [DataMember(Name = "syncKind")] + public TextDocumentSyncKind SyncKind + { + get; + set; + } + } +} diff --git a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs index f3075ecfe3cea..7b46d9a52c515 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs @@ -10,18 +10,21 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Utilities; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Simplification; [ExportLanguageService(typeof(ISimplificationService), LanguageNames.CSharp), Shared] -internal partial class CSharpSimplificationService : AbstractSimplificationService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal partial class CSharpSimplificationService() + : AbstractSimplificationService(s_reducers) { // 1. the cast simplifier should run earlier then everything else to minimize the type expressions // 2. Extension method reducer may insert parentheses. So run it before the parentheses remover. @@ -40,12 +43,6 @@ internal partial class CSharpSimplificationService : AbstractSimplificationServi new CSharpDefaultExpressionReducer(), ]; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpSimplificationService() : base(s_reducers) - { - } - public override SimplifierOptions DefaultOptions => CSharpSimplifierOptions.Default; @@ -230,4 +227,26 @@ private static bool IsTupleInDeconstruction(SyntaxNode tuple) } while (true); } + + protected override void AddImportDeclarations(CompilationUnitSyntax root, ArrayBuilder importDeclarations) + { + importDeclarations.AddRange(root.Usings); + + foreach (var member in root.Members) + { + if (member is BaseNamespaceDeclarationSyntax baseNamespace) + AddImportDeclarations(baseNamespace, importDeclarations); + } + + static void AddImportDeclarations(BaseNamespaceDeclarationSyntax baseNamespace, ArrayBuilder importDeclarations) + { + importDeclarations.AddRange(baseNamespace.Usings); + + foreach (var member in baseNamespace.Members) + { + if (member is BaseNamespaceDeclarationSyntax childNamespace) + AddImportDeclarations(childNamespace, importDeclarations); + } + } + } } diff --git a/src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs b/src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs index f852e4a0ef741..2ad302dcb1782 100644 --- a/src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs +++ b/src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs @@ -10,10 +10,10 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -22,7 +22,8 @@ namespace Microsoft.CodeAnalysis.Simplification; -internal abstract class AbstractSimplificationService : ISimplificationService +internal abstract class AbstractSimplificationService : ISimplificationService + where TCompilationUnitSyntax : SyntaxNode where TExpressionSyntax : SyntaxNode where TStatementSyntax : SyntaxNode where TCrefSyntax : SyntaxNode @@ -38,6 +39,7 @@ protected AbstractSimplificationService(ImmutableArray reducers protected abstract ImmutableArray GetNodesAndTokensToReduce(SyntaxNode root, Func isNodeOrTokenOutsideSimplifySpans); protected abstract SemanticModel GetSpeculativeSemanticModel(ref SyntaxNode nodeToSpeculate, SemanticModel originalSemanticModel, SyntaxNode originalNode); protected abstract bool NodeRequiresNonSpeculativeSemanticModel(SyntaxNode node); + protected abstract void AddImportDeclarations(TCompilationUnitSyntax root, ArrayBuilder importDeclarations); public abstract SimplifierOptions DefaultOptions { get; } public abstract SimplifierOptions GetSimplifierOptions(IOptionsReader options, SimplifierOptions? fallbackOptions); @@ -103,27 +105,22 @@ private async Task ReduceCoreAsync( // Create a simple interval tree for simplification spans. var spansTree = new TextSpanIntervalTree(spans); - bool isNodeOrTokenOutsideSimplifySpans(SyntaxNodeOrToken nodeOrToken) - => !spansTree.HasIntervalThatOverlapsWith(nodeOrToken.FullSpan.Start, nodeOrToken.FullSpan.Length); - - var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var root = await semanticModel.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); + var root = (TCompilationUnitSyntax)await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); // prep namespace imports marked for simplification var removeIfUnusedAnnotation = new SyntaxAnnotation(); var originalRoot = root; - root = PrepareNamespaceImportsForRemovalIfUnused(document, root, removeIfUnusedAnnotation, isNodeOrTokenOutsideSimplifySpans); + root = PrepareNamespaceImportsForRemovalIfUnused(root, removeIfUnusedAnnotation, IsNodeOrTokenOutsideSimplifySpans); var hasImportsToSimplify = root != originalRoot; if (hasImportsToSimplify) { document = document.WithSyntaxRoot(root); - semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - root = await semanticModel.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); + root = (TCompilationUnitSyntax)await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); } // Get the list of syntax nodes and tokens that need to be reduced. - var nodesAndTokensToReduce = this.GetNodesAndTokensToReduce(root, isNodeOrTokenOutsideSimplifySpans); + var nodesAndTokensToReduce = this.GetNodesAndTokensToReduce(root, IsNodeOrTokenOutsideSimplifySpans); if (nodesAndTokensToReduce.Any()) { @@ -143,7 +140,7 @@ bool isNodeOrTokenOutsideSimplifySpans(SyntaxNodeOrToken nodeOrToken) // Reduce all the nodesAndTokensToReduce using the given reducers/rewriters and // store the reduced nodes and/or tokens in the reduced nodes/tokens maps. // Note that this method doesn't update the original syntax tree. - await this.ReduceAsync(document, root, nodesAndTokensToReduce, reducers, options, semanticModel, reducedNodesMap, reducedTokensMap, cancellationToken).ConfigureAwait(false); + await this.ReduceAsync(document, root, nodesAndTokensToReduce, reducers, options, reducedNodesMap, reducedTokensMap, cancellationToken).ConfigureAwait(false); if (reducedNodesMap.Any() || reducedTokensMap.Any()) { @@ -167,6 +164,9 @@ bool isNodeOrTokenOutsideSimplifySpans(SyntaxNodeOrToken nodeOrToken) } return document; + + bool IsNodeOrTokenOutsideSimplifySpans(SyntaxNodeOrToken nodeOrToken) + => !spansTree.HasIntervalThatOverlapsWith(nodeOrToken.FullSpan.Start, nodeOrToken.FullSpan.Length); } private async Task ReduceAsync( @@ -175,7 +175,6 @@ private async Task ReduceAsync( ImmutableArray nodesAndTokensToReduce, ImmutableArray reducers, SimplifierOptions options, - SemanticModel semanticModel, ConcurrentDictionary reducedNodesMap, ConcurrentDictionary reducedTokensMap, CancellationToken cancellationToken) @@ -185,6 +184,9 @@ private async Task ReduceAsync( Contract.ThrowIfFalse(nodesAndTokensToReduce.Any()); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + + // Reduce each node or token in the given list by running it through each reducer. if (executeSerially) { foreach (var nodeOrTokenToReduce in nodesAndTokensToReduce) @@ -207,8 +209,8 @@ async ValueTask ReduceOneNodeOrTokenAsync( var nodeOrToken = nodeOrTokenToReduce.OriginalNodeOrToken; var simplifyAllDescendants = nodeOrTokenToReduce.SimplifyAllDescendants; - var semanticModelForReduce = semanticModel; var currentNodeOrToken = nodeOrTokenToReduce.NodeOrToken; + var semanticModelForReduce = semanticModel; var isNode = nodeOrToken.IsNode; foreach (var reducer in reducers) @@ -230,10 +232,7 @@ async ValueTask ReduceOneNodeOrTokenAsync( // However, the reduced nodes haven't been parented yet, so do the required parenting using the original node's parent. if (currentNodeOrToken.Parent == null && nodeOrToken.Parent != null && - (currentNodeOrToken.IsToken || - currentNodeOrToken.AsNode() is TExpressionSyntax || - currentNodeOrToken.AsNode() is TStatementSyntax || - currentNodeOrToken.AsNode() is TCrefSyntax)) + (currentNodeOrToken.IsToken || currentNodeOrToken.AsNode() is TExpressionSyntax or TStatementSyntax or TCrefSyntax)) { var annotation = new SyntaxAnnotation(); currentNodeOrToken = currentNodeOrToken.WithAdditionalAnnotations(annotation); @@ -292,20 +291,18 @@ async ValueTask ReduceOneNodeOrTokenAsync( // find any namespace imports / using directives marked for simplification in the specified spans // and add removeIfUnused annotation - private static SyntaxNode PrepareNamespaceImportsForRemovalIfUnused( - Document document, - SyntaxNode root, + private TCompilationUnitSyntax PrepareNamespaceImportsForRemovalIfUnused( + TCompilationUnitSyntax root, SyntaxAnnotation removeIfUnusedAnnotation, Func isNodeOrTokenOutsideSimplifySpan) { - var gen = SyntaxGenerator.GetGenerator(document); + using var _ = ArrayBuilder.GetInstance(out var importDeclarations); - var importsToSimplify = root.DescendantNodes().Where(n => - !isNodeOrTokenOutsideSimplifySpan(n) - && gen.GetDeclarationKind(n) == DeclarationKind.NamespaceImport - && n.HasAnnotation(Simplifier.Annotation)); + this.AddImportDeclarations(root, importDeclarations); - return root.ReplaceNodes(importsToSimplify, (o, r) => r.WithAdditionalAnnotations(removeIfUnusedAnnotation)); + return root.ReplaceNodes( + importDeclarations.Where(n => !isNodeOrTokenOutsideSimplifySpan(n) && n.HasAnnotation(Simplifier.Annotation)), + (o, r) => r.WithAdditionalAnnotations(removeIfUnusedAnnotation)); } private async Task RemoveUnusedNamespaceImportsAsync( diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/CSharpFormatEngine.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/CSharpFormatEngine.cs index 11c3eb47cef74..792e58bfdb761 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/CSharpFormatEngine.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/CSharpFormatEngine.cs @@ -29,7 +29,7 @@ public CSharpFormatEngine( internal override IHeaderFacts HeaderFacts => CSharpHeaderFacts.Instance; protected override AbstractTriviaDataFactory CreateTriviaFactory() - => new TriviaDataFactory(this.TreeData, this.Options); + => new TriviaDataFactory(this.TreeData, this.Options.LineFormatting); protected override AbstractFormattingResult CreateFormattingResult(TokenStream tokenStream) => new FormattingResult(this.TreeData, tokenStream, this.SpanToFormat); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/CSharpStructuredTriviaFormatEngine.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/CSharpStructuredTriviaFormatEngine.cs index 182588d383675..cec283c043333 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/CSharpStructuredTriviaFormatEngine.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/CSharpStructuredTriviaFormatEngine.cs @@ -43,7 +43,7 @@ private CSharpStructuredTriviaFormatEngine( internal override IHeaderFacts HeaderFacts => CSharpHeaderFacts.Instance; protected override AbstractTriviaDataFactory CreateTriviaFactory() - => new TriviaDataFactory(this.TreeData, this.Options); + => new TriviaDataFactory(this.TreeData, this.Options.LineFormatting); protected override FormattingContext CreateFormattingContext(TokenStream tokenStream, CancellationToken cancellationToken) => new(this, tokenStream); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ComplexTrivia.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ComplexTrivia.cs index 85172a3f82170..21c63a5e8f9a0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ComplexTrivia.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ComplexTrivia.cs @@ -19,9 +19,9 @@ internal partial class TriviaDataFactory /// represents a general trivia between two tokens. slightly more expensive than others since it /// needs to calculate stuff unlike other cases /// - private class ComplexTrivia : AbstractComplexTrivia + private sealed class ComplexTrivia : AbstractComplexTrivia { - public ComplexTrivia(SyntaxFormattingOptions options, TreeData treeInfo, SyntaxToken token1, SyntaxToken token2) + public ComplexTrivia(LineFormattingOptions options, TreeData treeInfo, SyntaxToken token1, SyntaxToken token2) : base(options, treeInfo, token1, token2) { } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.FormattedComplexTrivia.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.FormattedComplexTrivia.cs index 4a525360d5b33..d62c4c9a6d9a4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.FormattedComplexTrivia.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.FormattedComplexTrivia.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Formatting; internal partial class TriviaDataFactory { - private class FormattedComplexTrivia : TriviaDataWithList + private sealed class FormattedComplexTrivia : TriviaDataWithList { private readonly CSharpTriviaFormatter _formatter; private readonly IList _textChanges; @@ -27,7 +27,7 @@ public FormattedComplexTrivia( int spaces, string originalString, CancellationToken cancellationToken) - : base(context.Options, LanguageNames.CSharp) + : base(context.Options.LineFormatting) { Contract.ThrowIfNull(context); Contract.ThrowIfNull(formattingRules); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ModifiedComplexTrivia.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ModifiedComplexTrivia.cs index 5bce6fbd0fd38..1db933c501f3b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ModifiedComplexTrivia.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.ModifiedComplexTrivia.cs @@ -14,12 +14,12 @@ namespace Microsoft.CodeAnalysis.CSharp.Formatting; internal partial class TriviaDataFactory { - private class ModifiedComplexTrivia : TriviaDataWithList + private sealed class ModifiedComplexTrivia : TriviaDataWithList { private readonly ComplexTrivia _original; - public ModifiedComplexTrivia(SyntaxFormattingOptions options, ComplexTrivia original, int lineBreaks, int space) - : base(options, original.Token1.Language) + public ModifiedComplexTrivia(LineFormattingOptions options, ComplexTrivia original, int lineBreaks, int space) + : base(options) { Contract.ThrowIfNull(original); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.cs index a7313cb07f61c..1ec647df3cd22 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Engine/Trivia/TriviaDataFactory.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Formatting; /// internal partial class TriviaDataFactory : AbstractTriviaDataFactory { - public TriviaDataFactory(TreeData treeInfo, SyntaxFormattingOptions options) + public TriviaDataFactory(TreeData treeInfo, LineFormattingOptions options) : base(treeInfo, options) { } @@ -118,7 +118,7 @@ private static bool ContainsOnlyWhitespace(Analyzer.AnalysisResult result) { // calculate actual space size from tab var spaces = CalculateSpaces(token1, token2); - return new ModifiedWhitespace(this.Options, result.LineBreaks, indentation: spaces, elastic: result.TreatAsElastic, language: LanguageNames.CSharp); + return new ModifiedWhitespace(this.Options, result.LineBreaks, indentation: spaces, elastic: result.TreatAsElastic); } // check whether we can cache trivia info for current indentation diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeExtensions.cs index 782139a28ab85..67fe1c29206da 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeExtensions.cs @@ -178,12 +178,18 @@ public static SyntaxNode GetCommonRoot(this SyntaxNode node1, SyntaxNode node2) { Contract.ThrowIfTrue(node1.RawKind == 0 || node2.RawKind == 0); - // find common starting node from two nodes. - // as long as two nodes belong to same tree, there must be at least one common root (Ex, compilation unit) - var ancestors = node1.GetAncestorsOrThis(); - var set = new HashSet(node2.GetAncestorsOrThis()); + // find common starting node from two nodes. as long as two nodes belong to same tree, there must be at least + // one common root (Ex, compilation unit) + using var _ = PooledHashSet.GetInstance(out var set); + set.AddRange(node2.GetAncestorsOrThis()); - return ancestors.First(set.Contains); + foreach (var ancestor in node1.AncestorsAndSelf()) + { + if (set.Contains(ancestor)) + return ancestor; + } + + throw ExceptionUtilities.Unreachable(); } public static int Width(this SyntaxNode node) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.AbstractComplexTrivia.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.AbstractComplexTrivia.cs index 8e14ebe0b9565..c081c5813c4b4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.AbstractComplexTrivia.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.AbstractComplexTrivia.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Threading; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; @@ -21,8 +20,8 @@ protected abstract class AbstractComplexTrivia : TriviaDataWithList private readonly bool _treatAsElastic; - public AbstractComplexTrivia(SyntaxFormattingOptions options, TreeData treeInfo, SyntaxToken token1, SyntaxToken token2) - : base(options, token1.Language) + public AbstractComplexTrivia(LineFormattingOptions options, TreeData treeInfo, SyntaxToken token1, SyntaxToken token2) + : base(options) { Contract.ThrowIfNull(treeInfo); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.FormattedWhitespace.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.FormattedWhitespace.cs index 82ae7747c65b3..2e1c7f1a60ce4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.FormattedWhitespace.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.FormattedWhitespace.cs @@ -13,12 +13,12 @@ namespace Microsoft.CodeAnalysis.Formatting; internal abstract partial class AbstractTriviaDataFactory { - protected class FormattedWhitespace : TriviaData + protected sealed class FormattedWhitespace : TriviaData { private readonly string _newString; - public FormattedWhitespace(SyntaxFormattingOptions options, int lineBreaks, int indentation, string language) - : base(options, language) + public FormattedWhitespace(LineFormattingOptions options, int lineBreaks, int indentation) + : base(options) { this.LineBreaks = Math.Max(0, lineBreaks); this.Spaces = Math.Max(0, indentation); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.ModifiedWhitespace.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.ModifiedWhitespace.cs index bca9cdecd1006..474e09b6a354d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.ModifiedWhitespace.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.ModifiedWhitespace.cs @@ -11,18 +11,18 @@ namespace Microsoft.CodeAnalysis.Formatting; internal abstract partial class AbstractTriviaDataFactory { - protected class ModifiedWhitespace : Whitespace + protected sealed class ModifiedWhitespace : Whitespace { private readonly Whitespace? _original; - public ModifiedWhitespace(SyntaxFormattingOptions options, int lineBreaks, int indentation, bool elastic, string language) - : base(options, lineBreaks, indentation, elastic, language) + public ModifiedWhitespace(LineFormattingOptions options, int lineBreaks, int indentation, bool elastic) + : base(options, lineBreaks, indentation, elastic) { _original = null; } - public ModifiedWhitespace(SyntaxFormattingOptions options, Whitespace original, int lineBreaks, int indentation, bool elastic, string language) - : base(options, lineBreaks, indentation, elastic, language) + public ModifiedWhitespace(LineFormattingOptions options, Whitespace original, int lineBreaks, int indentation, bool elastic) + : base(options, lineBreaks, indentation, elastic) { Contract.ThrowIfNull(original); _original = original; @@ -83,7 +83,7 @@ public override void Format( CancellationToken cancellationToken, int tokenPairIndex = TokenPairIndexNotNeeded) { - formattingResultApplier(tokenPairIndex, context.TokenStream, new FormattedWhitespace(this.Options, this.LineBreaks, this.Spaces, this.Language)); + formattingResultApplier(tokenPairIndex, context.TokenStream, new FormattedWhitespace(this.Options, this.LineBreaks, this.Spaces)); } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.Whitespace.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.Whitespace.cs index 116dda5456313..bda9b5b3785b4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.Whitespace.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.Whitespace.cs @@ -21,14 +21,14 @@ protected class Whitespace : TriviaData { private readonly bool _elastic; - public Whitespace(SyntaxFormattingOptions options, int space, bool elastic, string language) - : this(options, lineBreaks: 0, indentation: space, elastic: elastic, language: language) + public Whitespace(LineFormattingOptions options, int space, bool elastic) + : this(options, lineBreaks: 0, indentation: space, elastic: elastic) { Contract.ThrowIfFalse(space >= 0); } - public Whitespace(SyntaxFormattingOptions options, int lineBreaks, int indentation, bool elastic, string language) - : base(options, language) + public Whitespace(LineFormattingOptions options, int lineBreaks, int indentation, bool elastic) + : base(options) { _elastic = elastic; @@ -47,11 +47,9 @@ public Whitespace(SyntaxFormattingOptions options, int lineBreaks, int indentati public override TriviaData WithSpace(int space, FormattingContext context, ChainedFormattingRules formattingRules) { if (this.LineBreaks == 0 && this.Spaces == space) - { return this; - } - return new ModifiedWhitespace(this.Options, this, /*lineBreak*/0, space, elastic: false, language: this.Language); + return new ModifiedWhitespace(this.Options, this, /*lineBreak*/0, space, elastic: false); } public override TriviaData WithLine(int line, int indentation, FormattingContext context, ChainedFormattingRules formattingRules, CancellationToken cancellationToken) @@ -63,7 +61,7 @@ public override TriviaData WithLine(int line, int indentation, FormattingContext return this; } - return new ModifiedWhitespace(this.Options, this, line, indentation, elastic: false, language: this.Language); + return new ModifiedWhitespace(this.Options, this, line, indentation, elastic: false); } public override TriviaData WithIndentation( @@ -74,7 +72,7 @@ public override TriviaData WithIndentation( return this; } - return new ModifiedWhitespace(this.Options, this, this.LineBreaks, indentation, elastic: false, language: this.Language); + return new ModifiedWhitespace(this.Options, this, this.LineBreaks, indentation, elastic: false); } public override void Format( diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.cs index 19b2882c81115..71a0fce380856 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.cs @@ -2,6 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; +using System.Collections.Generic; +using System.Security.Principal; using System.Threading; using Microsoft.CodeAnalysis.Diagnostics; using Roslyn.Utilities; @@ -14,23 +17,73 @@ internal abstract partial class AbstractTriviaDataFactory private const int LineBreakCacheSize = 5; private const int IndentationLevelCacheSize = 20; + private static readonly Dictionary s_optionsToWhitespace = new(); + private static Tuple? s_lastOptionAndWhitespace; + protected readonly TreeData TreeInfo; - protected readonly SyntaxFormattingOptions Options; + protected readonly LineFormattingOptions Options; private readonly Whitespace[] _spaces; - private readonly Whitespace?[,] _whitespaces = new Whitespace[LineBreakCacheSize, IndentationLevelCacheSize]; + private readonly Whitespace[,] _whitespaces; - protected AbstractTriviaDataFactory(TreeData treeInfo, SyntaxFormattingOptions options) + protected AbstractTriviaDataFactory(TreeData treeInfo, LineFormattingOptions options) { Contract.ThrowIfNull(treeInfo); TreeInfo = treeInfo; Options = options; - _spaces = new Whitespace[SpaceCacheSize]; - for (var i = 0; i < SpaceCacheSize; i++) + (_spaces, _whitespaces) = GetSpacesAndWhitespaces(options); + } + + private static (Whitespace[] spaces, Whitespace[,] whitespaces) GetSpacesAndWhitespaces(LineFormattingOptions options) + { + // Fast path where we'er asking for the same options as last time + var lastOptionAndWhitespace = s_lastOptionAndWhitespace; + if (lastOptionAndWhitespace?.Item1 == options) + return lastOptionAndWhitespace.Item2; + + // Otherwise, get from the dictionary, computing if necessary. + var (spaces, whitespaces) = ComputeAndCacheSpacesAndWhitespaces(options); + + // Cache this result for the next time. + s_lastOptionAndWhitespace = Tuple.Create(options, (spaces, whitespaces)); + return (spaces, whitespaces); + + static (Whitespace[] spaces, Whitespace[,] whitespaces) ComputeAndCacheSpacesAndWhitespaces(LineFormattingOptions options) { - _spaces[i] = new Whitespace(Options, space: i, elastic: false, language: treeInfo.Root.Language); + // First check if it's already in the cache. + lock (s_optionsToWhitespace) + { + if (s_optionsToWhitespace.TryGetValue(options, out var result)) + return result; + } + + // If not, compute it. + var spaces = new Whitespace[SpaceCacheSize]; + for (var i = 0; i < SpaceCacheSize; i++) + spaces[i] = new Whitespace(options, space: i, elastic: false); + + var whitespaces = new Whitespace[LineBreakCacheSize, IndentationLevelCacheSize]; + for (var lineIndex = 0; lineIndex < LineBreakCacheSize; lineIndex++) + { + for (var indentationLevel = 0; indentationLevel < IndentationLevelCacheSize; indentationLevel++) + { + var indentation = indentationLevel * options.IndentationSize; + whitespaces[lineIndex, indentationLevel] = new Whitespace( + options, lineBreaks: lineIndex + 1, indentation: indentation, elastic: false); + } + } + + // Attempt to store in cache. But defer to any other thread that may have already stored it. + lock (s_optionsToWhitespace) + { + if (s_optionsToWhitespace.TryGetValue(options, out var result)) + return result; + + s_optionsToWhitespace[options] = (spaces, whitespaces); + return (spaces, whitespaces); + } } } @@ -41,7 +94,7 @@ protected TriviaData GetSpaceTriviaData(int space, bool elastic = false) // if result has elastic trivia in them, never use cache if (elastic) { - return new Whitespace(this.Options, space, elastic: true, language: this.TreeInfo.Root.Language); + return new Whitespace(this.Options, space, elastic: true); } if (space < SpaceCacheSize) @@ -50,7 +103,7 @@ protected TriviaData GetSpaceTriviaData(int space, bool elastic = false) } // create a new space - return new Whitespace(this.Options, space, elastic: false, language: this.TreeInfo.Root.Language); + return new Whitespace(this.Options, space, elastic: false); } protected TriviaData GetWhitespaceTriviaData(int lineBreaks, int indentation, bool useTriviaAsItIs, bool elastic) @@ -75,29 +128,13 @@ protected TriviaData GetWhitespaceTriviaData(int lineBreaks, int indentation, bo if (indentationLevel < IndentationLevelCacheSize) { var lineIndex = lineBreaks - 1; - EnsureWhitespaceTriviaInfo(lineIndex, indentationLevel); return _whitespaces[lineIndex, indentationLevel]!; } } - return - useTriviaAsItIs - ? new Whitespace(this.Options, lineBreaks, indentation, elastic, language: this.TreeInfo.Root.Language) - : new ModifiedWhitespace(this.Options, lineBreaks, indentation, elastic, language: this.TreeInfo.Root.Language); - } - - private void EnsureWhitespaceTriviaInfo(int lineIndex, int indentationLevel) - { - Contract.ThrowIfFalse(lineIndex is >= 0 and < LineBreakCacheSize); - Contract.ThrowIfFalse(indentationLevel >= 0 && indentationLevel < _whitespaces.Length / _whitespaces.Rank); - - // set up caches - if (_whitespaces[lineIndex, indentationLevel] == null) - { - var indentation = indentationLevel * Options.IndentationSize; - var triviaInfo = new Whitespace(Options, lineBreaks: lineIndex + 1, indentation: indentation, elastic: false, language: this.TreeInfo.Root.Language); - Interlocked.CompareExchange(ref _whitespaces[lineIndex, indentationLevel], triviaInfo, null); - } + return useTriviaAsItIs + ? new Whitespace(this.Options, lineBreaks, indentation, elastic) + : new ModifiedWhitespace(this.Options, lineBreaks, indentation, elastic); } public abstract TriviaData CreateLeadingTrivia(SyntaxToken token); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenData.cs index e50090dda0738..1bc2f1c870430 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenData.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -63,50 +64,47 @@ public int CompareTo(TokenData other) Contract.ThrowIfFalse(this.TokenStream == other.TokenStream); if (this.IndexInStream >= 0 && other.IndexInStream >= 0) - { return this.IndexInStream - other.IndexInStream; - } + + if (this.Token == other.Token) + return 0; var start = this.Token.SpanStart - other.Token.SpanStart; if (start != 0) - { return start; - } var end = this.Token.Span.End - other.Token.Span.End; if (end != 0) - { return end; - } - // this is expansive check. but there is no other way to check. + // We have two different tokens, which are at the same location. This can happen with things like empty/missing + // tokens. In order to give a strict ordering, we need to walk up the tree to find the first common ancestor + // and see which token we hit first in that ancestor. var commonRoot = this.Token.GetCommonRoot(other.Token); - RoslynDebug.Assert(commonRoot != null); + Contract.ThrowIfNull(commonRoot); - var tokens = commonRoot.DescendantTokens(); + // Now, figure out the ancestor of each token parented by the common root. + var thisTokenAncestor = GetAncestorUnderRoot(this.Token, commonRoot); + var otherTokenAncestor = GetAncestorUnderRoot(other.Token, commonRoot); - var index1 = Index(tokens, this.Token); - var index2 = Index(tokens, other.Token); - Contract.ThrowIfFalse(index1 >= 0 && index2 >= 0); - - return index1 - index2; - } + foreach (var child in commonRoot.ChildNodesAndTokens()) + { + if (child == thisTokenAncestor) + return -1; + else if (child == otherTokenAncestor) + return 1; + } - private static int Index(IEnumerable tokens, SyntaxToken token) - { - var index = 0; + throw ExceptionUtilities.Unreachable(); - foreach (var current in tokens) + static SyntaxNodeOrToken GetAncestorUnderRoot(SyntaxNodeOrToken start, SyntaxNode root) { - if (current == token) - { - return index; - } + var current = start; + while (current.Parent != root) + current = current.Parent; - index++; + return current; } - - return -1; } public static bool operator <(TokenData left, TokenData right) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TriviaData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TriviaData.cs index 5d39109a8d864..4f62d0df988a8 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TriviaData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TriviaData.cs @@ -18,16 +18,12 @@ internal abstract class TriviaData { protected const int TokenPairIndexNotNeeded = int.MinValue; - private readonly string _language; - - protected TriviaData(SyntaxFormattingOptions options, string language) + protected TriviaData(LineFormattingOptions options) { Options = options; - _language = language; } - protected SyntaxFormattingOptions Options { get; } - protected string Language => _language; + protected LineFormattingOptions Options { get; } public int LineBreaks { get; protected set; } public int Spaces { get; protected set; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TriviaDataWithList.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TriviaDataWithList.cs index dff9d8703a24c..9cc7dc29fce5e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TriviaDataWithList.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TriviaDataWithList.cs @@ -3,11 +3,10 @@ // See the LICENSE file in the project root for more information. using System.Threading; -using Microsoft.CodeAnalysis.Diagnostics; namespace Microsoft.CodeAnalysis.Formatting; -internal abstract class TriviaDataWithList(SyntaxFormattingOptions options, string language) : TriviaData(options, language) +internal abstract class TriviaDataWithList(LineFormattingOptions options) : TriviaData(options) { public abstract SyntaxTriviaList GetTriviaList(CancellationToken cancellationToken); } diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.AbstractLineBreakTrivia.vb b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.AbstractLineBreakTrivia.vb index d75d120ab0a90..4b543b4e32ee7 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.AbstractLineBreakTrivia.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.AbstractLineBreakTrivia.vb @@ -15,12 +15,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting Protected ReadOnly _original As String Protected ReadOnly _newString As String - Public Sub New(options As SyntaxFormattingOptions, + Public Sub New(options As LineFormattingOptions, original As String, lineBreaks As Integer, indentation As Integer, elastic As Boolean) - MyBase.New(options, lineBreaks, indentation, elastic, LanguageNames.VisualBasic) + MyBase.New(options, lineBreaks, indentation, elastic) Me._original = original Me._newString = CreateStringFromState() diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.ComplexTrivia.vb b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.ComplexTrivia.vb index 7644e750dd40b..71c51db59f694 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.ComplexTrivia.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.ComplexTrivia.vb @@ -17,7 +17,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting Private Class ComplexTrivia Inherits AbstractComplexTrivia - Public Sub New(options As SyntaxFormattingOptions, treeInfo As TreeData, token1 As SyntaxToken, token2 As SyntaxToken) + Public Sub New(options As LineFormattingOptions, treeInfo As TreeData, token1 As SyntaxToken, token2 As SyntaxToken) MyBase.New(options, treeInfo, token1, token2) Contract.ThrowIfNull(treeInfo) End Sub diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.FormattedComplexTrivia.vb b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.FormattedComplexTrivia.vb index ba33b5201885f..07fc99fba20f8 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.FormattedComplexTrivia.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.FormattedComplexTrivia.vb @@ -8,7 +8,7 @@ Imports Microsoft.CodeAnalysis.Text Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting Partial Friend Class TriviaDataFactory - Private Class FormattedComplexTrivia + Private NotInheritable Class FormattedComplexTrivia Inherits TriviaDataWithList Private ReadOnly _formatter As VisualBasicTriviaFormatter @@ -22,7 +22,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting spaces As Integer, originalString As String, cancellationToken As CancellationToken) - MyBase.New(context.Options, LanguageNames.VisualBasic) + MyBase.New(context.Options.LineFormatting) Contract.ThrowIfNull(context) Contract.ThrowIfNull(formattingRules) diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.LineContinuationTrivia.vb b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.LineContinuationTrivia.vb index 83e0d3bf3d7dd..52007299afb51 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.LineContinuationTrivia.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.LineContinuationTrivia.vb @@ -16,7 +16,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting Private Class LineContinuationTrivia Inherits AbstractLineBreakTrivia - Public Sub New(options As SyntaxFormattingOptions, + Public Sub New(options As LineFormattingOptions, originalString As String, indentation As Integer) MyBase.New(options, originalString, 1, indentation, False) diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.ModifiedComplexTrivia.vb b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.ModifiedComplexTrivia.vb index 2062779935531..4dcd37bdaca7e 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.ModifiedComplexTrivia.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.ModifiedComplexTrivia.vb @@ -3,19 +3,18 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading -Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Text Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting Partial Friend Class TriviaDataFactory - Private Class ModifiedComplexTrivia + Private NotInheritable Class ModifiedComplexTrivia Inherits TriviaDataWithList Private ReadOnly _original As ComplexTrivia - Public Sub New(options As SyntaxFormattingOptions, original As ComplexTrivia, lineBreaks As Integer, space As Integer) - MyBase.New(options, LanguageNames.VisualBasic) + Public Sub New(options As LineFormattingOptions, original As ComplexTrivia, lineBreaks As Integer, space As Integer) + MyBase.New(options) Contract.ThrowIfNull(original) Me._original = original diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.vb b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.vb index 11bdd60ff1700..3475c8aad1dc2 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/TriviaDataFactory.vb @@ -20,7 +20,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting Private ReadOnly _lineContinuations(s_lineContinuationCacheSize) As LineContinuationTrivia - Public Sub New(treeInfo As TreeData, options As SyntaxFormattingOptions) + Public Sub New(treeInfo As TreeData, options As LineFormattingOptions) MyBase.New(treeInfo, options) End Sub @@ -160,7 +160,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting If result.LineBreaks = 0 AndAlso result.Tab > 0 Then ' calculate actual space size from tab Dim spaces = CalculateSpaces(token1, token2) - Return New ModifiedWhitespace(Me.Options, result.LineBreaks, indentation:=spaces, elastic:=result.TreatAsElastic, language:=LanguageNames.VisualBasic) + Return New ModifiedWhitespace(Me.Options, result.LineBreaks, indentation:=spaces, elastic:=result.TreatAsElastic) End If ' check whether we can cache trivia info for current indentation diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/VisualBasicFormatEngine.vb b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/VisualBasicFormatEngine.vb index d6b00a74ecdb5..4e89985b11d94 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/VisualBasicFormatEngine.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/VisualBasicFormatEngine.vb @@ -27,7 +27,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting Friend Overrides ReadOnly Property HeaderFacts As IHeaderFacts = VisualBasicHeaderFacts.Instance Protected Overrides Function CreateTriviaFactory() As AbstractTriviaDataFactory - Return New TriviaDataFactory(Me.TreeData, Me.Options) + Return New TriviaDataFactory(Me.TreeData, Me.Options.LineFormatting) End Function Protected Overrides Function CreateFormattingResult(tokenStream As TokenStream) As AbstractFormattingResult diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/VisualBasicStructuredTriviaFormatEngine.vb b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/VisualBasicStructuredTriviaFormatEngine.vb index ac7baf64c323a..e683b19beacec 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/VisualBasicStructuredTriviaFormatEngine.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/VisualBasicStructuredTriviaFormatEngine.vb @@ -35,7 +35,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting Friend Overrides ReadOnly Property HeaderFacts As IHeaderFacts = VisualBasicHeaderFacts.Instance Protected Overrides Function CreateTriviaFactory() As AbstractTriviaDataFactory - Return New TriviaDataFactory(Me.TreeData, Me.Options) + Return New TriviaDataFactory(Me.TreeData, Me.Options.LineFormatting) End Function Protected Overrides Function CreateFormattingContext(tokenStream As TokenStream, cancellationToken As CancellationToken) As FormattingContext diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.NodesAndTokensToReduceComputer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.NodesAndTokensToReduceComputer.vb index 12ab6a61cad72..c313960a29eed 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.NodesAndTokensToReduceComputer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.NodesAndTokensToReduceComputer.vb @@ -9,10 +9,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification - Partial Friend Class VisualBasicSimplificationService - Inherits AbstractSimplificationService(Of ExpressionSyntax, ExecutableStatementSyntax, CrefReferenceSyntax) - Private Class NodesAndTokensToReduceComputer Inherits VisualBasicSyntaxRewriter @@ -98,7 +95,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Me._simplifyAllDescendants = Me._simplifyAllDescendants OrElse token.HasAnnotation(Simplifier.Annotation) If Me._simplifyAllDescendants AndAlso Not Me._insideSpeculatedNode AndAlso token.Kind <> SyntaxKind.None Then - Me._nodesAndTokensToReduce.Add(New NodeOrTokenToReduce(token, simplifyAllDescendants:=True, originalNodeOrToken:=token)) + Me._nodesAndTokensToReduce.Add(New NodeOrTokenToReduce(token, SimplifyAllDescendants:=True, OriginalNodeOrToken:=token)) End If If token.ContainsAnnotations OrElse savedSimplifyAllDescendants Then diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb index e4d912a910015..9246a9f11d22e 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb @@ -6,10 +6,10 @@ Imports System.Collections.Immutable Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Internal.Log Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.Utilities @@ -17,7 +17,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Partial Friend Class VisualBasicSimplificationService - Inherits AbstractSimplificationService(Of ExpressionSyntax, ExecutableStatementSyntax, CrefReferenceSyntax) + Inherits AbstractSimplificationService(Of CompilationUnitSyntax, ExpressionSyntax, ExecutableStatementSyntax, CrefReferenceSyntax) Private Shared ReadOnly s_reducers As ImmutableArray(Of AbstractReducer) = ImmutableArray.Create(Of AbstractReducer)( @@ -177,5 +177,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Next End Sub + Protected Overrides Sub AddImportDeclarations(root As CompilationUnitSyntax, importDeclarations As ArrayBuilder(Of SyntaxNode)) + importDeclarations.AddRange(root.Imports) + End Sub End Class End Namespace