diff --git a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs index 888094f169b44..42057ac1ae5e1 100644 --- a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs @@ -527,7 +527,7 @@ private BoundForEachStatement BindForEachPartsWorker(BindingDiagnosticBag diagno if (builder.InlineArraySpanType == WellKnownType.Unknown && getEnumeratorType.IsRestrictedType() && (IsDirectlyInIterator || IsInAsyncMethod())) { - diagnostics.Add(ErrorCode.ERR_BadSpecialByRefIterator, foreachKeyword.GetLocation(), getEnumeratorType); + CheckFeatureAvailability(foreachKeyword, MessageID.IDS_FeatureRefUnsafeInIteratorAsync, diagnostics); } diagnostics.Add(_syntax.ForEachKeyword, useSiteInfo); diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 50301b93c6332..ba38ff08894f8 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -3845,9 +3845,6 @@ 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. - - 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. diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 350d7a829cf11..869000904a572 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1529,7 +1529,7 @@ internal enum ErrorCode ERR_AutoPropsInRoStruct = 8341, ERR_FieldlikeEventsInRoStruct = 8342, // ERR_RefStructInterfaceImpl = 8343, - ERR_BadSpecialByRefIterator = 8344, + // ERR_BadSpecialByRefIterator = 8344, ERR_FieldAutoPropCantBeByRefLike = 8345, ERR_StackAllocConversionNotPossible = 8346, diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index 619d08c98c3e8..1df3ca57f327d 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -1837,7 +1837,6 @@ or ErrorCode.ERR_InExtensionMustBeValueType or ErrorCode.ERR_FieldsInRoStruct or ErrorCode.ERR_AutoPropsInRoStruct or ErrorCode.ERR_FieldlikeEventsInRoStruct - or ErrorCode.ERR_BadSpecialByRefIterator or ErrorCode.ERR_FieldAutoPropCantBeByRefLike or ErrorCode.ERR_StackAllocConversionNotPossible or ErrorCode.ERR_EscapeCall diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 7eeb92e8f2550..ec5f536e4ac3a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -287,11 +287,6 @@ Člen záznamu {0} musí být čitelná vlastnost instance nebo pole typu {1}, která se bude shodovat s pozičním parametrem {2}. - - 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 ref struct nebo parametr typu umožňující struktury ref struct. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Parametry typu {0} nemůžou být deklarované v asynchronních metodách nebo asynchronních výrazech lambda. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 5103839ac5cfb..efc98c59f72b0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -287,11 +287,6 @@ Das Datensatzelement "{0}" muss eine lesbare Instanzeigenschaft oder ein Feld vom Typ "{1}" sein, um dem Positionsparameter "{2}" zu entsprechen. - - 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 Anweisung „foreach“ kann nicht für Enumeratoren vom Typ „{0}“ in asynchronen oder Enumeratormethoden verwendet werden, da „{0}“ eine Verweisstruktur oder ein Typparameter ist, der eine Verweisstruktur zulässt. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Parameter vom Typ „{0}“ können nicht in asynchronen Methoden oder asynchronen Lambdaausdrücken deklariert werden. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 3cdbfd68c3ed4..3232e68721acd 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -287,11 +287,6 @@ 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}'. - - 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 asincrónicos o iteradores porque "{0}" es un valor ref struct o un parámetro de tipo que permite ref struct. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Los parámetros de tipo "{0}" no pueden declararse en expresiones lambda o métodos asincrónicos. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index a38956df8bf65..d34c41c68b4e0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -287,11 +287,6 @@ 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}'. - - 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 type ref struct. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Les paramètres de type « {0} » ne peuvent pas être déclarés dans des méthodes asynchrones ou des expressions lambda asynchrones. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index d91e527ec8508..b4afefef62448 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -287,11 +287,6 @@ Il membro di record '{0}' deve essere una proprietà di istanza leggibile o campo di tipo '{1}' per corrispondere al parametro posizionale '{2}'. - - 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}' è un ref struct o un parametro di tipo che consente il ref struct. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Non è possibile dichiarare parametri di tipo '{0}' in metodi asincroni o espressioni lambda asincrone. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 0db8aef6dd8f8..7537fe9243be6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -287,11 +287,6 @@ レコード メンバー '{0}' は、位置指定パラメーター '{2}' に一致させるための型 '{1}' の読み取り可能なインスタンス プロパティまたはフィールドである必要があります。 - - 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 構造体または ref 構造体を許容する型パラメーターであるため、非同期または反復子のメソッド内で '{0}' 型の列挙子に対して foreach ステートメントは機能しません。 - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. '{0}' 型のパラメーターは、非同期メソッドまたは非同期ラムダ式で宣言することができません。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 55d622a071e01..796c9e18e102d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -287,11 +287,6 @@ 위치 매개 변수 '{0}'과(와) 일치하려면 레코드 멤버 '{1}'이(가) 유형 '{2}'의 읽을 수 있는 인스턴스 속성 또는 필드여야 합니다. - - 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}'이(가) ref struct 또는 ref struct를 허용하는 형식 매개 변수이므로 비동기 또는 반복기 메서드에서 '{0}' 형식의 열거자에 대해 작동할 수 없습니다. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. '{0}' 형식의 매개 변수는 비동기 메서드나 비동기 람다 식에서 선언할 수 없습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index f946433f4b555..a47dcd38ed1e3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -287,11 +287,6 @@ Składowa rekordu "{0}" musi być możliwą do odczytu właściwością wystąpienia typu "{1}", aby dopasować parametr pozycyjny "{2}". - - 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 wyliczeniowych typu „{0}” w metodach asynchronicznych lub iteracyjnych, ponieważ „{0}” jest strukturą ref lub parametrem typu, który zezwala na strukturę ref. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Parametry typu „{0}” nie mogą być deklarowane w metodach asynchronicznych ani asynchronicznych wyrażeniach lambda. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 5f03a10fc85b7..0007c0ebfb91e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -287,11 +287,6 @@ 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}'. - - 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}" é um ref struct ou um parâmetro de tipo que permite o ref struct. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Parâmetros do tipo "{0}" não podem ser declarados em métodos assíncronos ou expressões lambda assíncronas. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 8c05dda987742..b995567b12da8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -287,11 +287,6 @@ Элемент записи "{0}" должен быть доступным для чтения свойством экземпляра или полем типа "{1}", чтобы соответствовать позиционному параметру "{2}". - - 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. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Параметры типа "{0}" не могут быть объявлены в асинхронных методах или асинхронных лямбда-выражениях. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 2045c2cb60058..59727bc9a3e79 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -287,11 +287,6 @@ {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. - - 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 deyimi, '{0}' bir başvuru yapısı veya başvuru yapısına izin veren bir tür parametresi olduğundan, zaman uyumsuz veya yineleyici metotlarda '{0}' türündeki numaralandırıcılar üzerinde çalışamaz. - - Parameters 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 bildirilemez. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index c6aa9f6795f8b..8d94be45a089f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -287,11 +287,6 @@ 记录成员 '{0}' 必须为类型 '{1}' 的可读实例属性或字段,以匹配位置参数 '{2}'。 - - 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 结构或允许 ref 结构的类型参数。 - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. 不能在异步方法或异步 lambda 表达式中声明 "{0}" 类型的参数。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 2d4dcfb740382..481135ded4501 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -287,11 +287,6 @@ 記錄成員 '{0}' 必須是類型 '{1}' 的可讀取執行個體屬性或欄位,才能符合位置參數 '{2}'。 - - 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 或允許 ref struct 的型別參數。 - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. 類型 '{0}' 的參數不得在非同步方法或非同步 Lambda 運算式中宣告。 diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs index 940ebc0837026..f0827cb755292 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs @@ -2061,10 +2061,12 @@ public S(int i) CompileAndVerify(comp, expectedOutput: "1 2 Done"); } - [Fact] - public void TestWithPattern_RefStructEnumerator_Async() + [Theory] + [InlineData("")] + [InlineData("await Task.Yield();")] + public void TestWithPattern_RefStructEnumerator_Async(string body) { - var source = """ + var source = $$""" using System.Threading.Tasks; public class C { @@ -2072,6 +2074,7 @@ public static async Task Main() { await foreach (var s in new C()) { + {{body}} } } public Enumerator GetAsyncEnumerator() => new Enumerator(); @@ -2083,22 +2086,34 @@ public ref struct Enumerator } """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // await foreach (var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(6, 15)); + 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. + // (6,9): error CS4007: Instance of type 'C.Enumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var s in new C()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C.Enumerator").WithLocation(6, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var s in new C()) + { + " + body + @" + }").WithArguments("C.Enumerator").WithLocation(6, 9) }; - CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); } - [Fact] - public void TestWithPattern_RefStructEnumerator_AsyncIterator() + [Theory] + [InlineData("")] + [InlineData("await Task.Yield();")] + [InlineData("yield return x;")] + [InlineData("yield return x; await Task.Yield();")] + [InlineData("await Task.Yield(); yield return x;")] + public void TestWithPattern_RefStructEnumerator_AsyncIterator(string body) { - var source = """ + var source = $$""" using System.Collections.Generic; using System.Threading.Tasks; public class C @@ -2107,8 +2122,9 @@ public static async IAsyncEnumerable M() { await foreach (var x in new C()) { - yield return x; + {{body}} } + yield return -1; } public Enumerator GetAsyncEnumerator() => new Enumerator(); public ref struct Enumerator @@ -2117,18 +2133,25 @@ public ref struct Enumerator public Task MoveNextAsync() => throw null; } } - """ + s_IAsyncEnumerable; + """ + AsyncStreamsTypes; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // await foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(7, 15)); 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. + // (7,9): error CS4007: Instance of type 'C.Enumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var x in new C()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C.Enumerator").WithLocation(7, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var x in new C()) + { + " + body + @" + }").WithArguments("C.Enumerator").WithLocation(7, 9) }; - CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); - CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics(expectedDiagnostics); - CreateCompilationWithTasksExtensions(source).VerifyDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] @@ -2154,16 +2177,23 @@ public ref struct Enumerator } """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(6, 9)); + 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. + // (6,9): error CS4007: Instance of type 'C.Enumerator' cannot be preserved across 'await' or 'yield' boundary. // foreach (var x in new C()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C.Enumerator").WithLocation(6, 9) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"foreach (var x in new C()) + { + yield return x; + }").WithArguments("C.Enumerator").WithLocation(6, 9) }; - CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs index 0c993511a7d1e..1b1c0f9830f01 100644 --- a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs @@ -16373,10 +16373,13 @@ static async Task Main() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (27,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (27,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(27, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + System.Console.Write(i); + }").WithArguments("S2").WithLocation(27, 9) ); } @@ -16422,10 +16425,13 @@ static async Task Main() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (30,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (30,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(30, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + System.Console.Write(i); + }").WithArguments("S2").WithLocation(30, 9) ); } @@ -16480,10 +16486,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (39,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (39,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(39, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(39, 9) ); } @@ -16544,10 +16553,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (45,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (45,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(45, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(45, 9) ); } @@ -16733,10 +16745,13 @@ static async Task Main() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (27,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (27,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(27, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + System.Console.Write(i); + }").WithArguments("S2").WithLocation(27, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -16795,10 +16810,13 @@ static async Task Main() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (27,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (27,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(27, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + System.Console.Write(i); + }").WithArguments("S2").WithLocation(27, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -16857,10 +16875,13 @@ static async Task Main() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (27,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (27,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(27, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + System.Console.Write(i); + }").WithArguments("S2").WithLocation(27, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -16938,10 +16959,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (46,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (46,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(46, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(46, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -17023,10 +17047,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (50,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (50,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(50, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(50, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -17113,10 +17140,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (55,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (55,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(55, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(55, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -17207,10 +17237,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (59,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (59,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(59, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(59, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -17288,10 +17321,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (46,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (46,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(46, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(46, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -17354,23 +17390,27 @@ static async Task Main() "; var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (10,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + // (10,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(10, 15) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(10, 15) ); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); comp2.VerifyEmitDiagnostics( - // (10,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + // (10,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(10, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + }").WithArguments("S2").WithLocation(10, 9) ); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); comp2.VerifyEmitDiagnostics( - // (10,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + // (10,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(10, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + }").WithArguments("S2").WithLocation(10, 9) ); } @@ -17429,9 +17469,9 @@ static async System.Threading.Tasks.Task Main() // (6,9): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // await foreach (var i in new S1()) {} Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "await foreach (var i in new S1()) {}").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 9), - // (6,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + // (6,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // await foreach (var i in new S1()) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(6, 15) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(6, 15) ); comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); @@ -17439,23 +17479,23 @@ static async System.Threading.Tasks.Task Main() // (14,24): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // public ref struct S2 : IAsyncDisposable Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "IAsyncDisposable").WithArguments("ref struct interfaces", "13.0").WithLocation(14, 24), - // (40,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + // (40,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // await foreach (var i in new S1()) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(40, 15) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(40, 15) ); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); comp2.VerifyEmitDiagnostics( - // (6,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + // (6,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(6, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await foreach (var i in new S1()) {}").WithArguments("S2").WithLocation(6, 9) ); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); comp2.VerifyEmitDiagnostics( - // (6,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + // (6,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(6, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await foreach (var i in new S1()) {}").WithArguments("S2").WithLocation(6, 9) ); var src3 = @" @@ -17518,23 +17558,23 @@ static async Task Test() // (22,73): error CS9202: Feature 'allows ref struct constraint' is not available in C# 12.0. Please use language version 13.0 or greater. // where TEnumerator : ICustomEnumerator, IAsyncDisposable, allows ref struct Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "ref struct").WithArguments("allows ref struct constraint", "13.0").WithLocation(22, 73), - // (24,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + // (24,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // await foreach (var i in default(TEnumerable)) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(24, 15) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(24, 15) ); comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics( - // (24,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + // (24,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(24, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await foreach (var i in default(TEnumerable)) {}").WithArguments("TEnumerator").WithLocation(24, 9) ); comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); comp.VerifyEmitDiagnostics( - // (24,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + // (24,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(24, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await foreach (var i in default(TEnumerable)) {}").WithArguments("TEnumerator").WithLocation(24, 9) ); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs index 09bf15745a0ba..b8b1b411deac3 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs @@ -941,7 +941,7 @@ .locals init (Program.S1 V_0) [WorkItem(20226, "https://github.com/dotnet/roslyn/issues/20226")] [Fact] - public void RefIteratorInAsync() + public void RefIteratorInAsync_01() { var text = @" using System; @@ -987,18 +987,87 @@ public bool MoveNext() "; - CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (15,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // foreach (var i in obj) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(15, 9)); - comp.VerifyDiagnostics( - // (15,9): error CS8344: foreach statement cannot operate on enumerators of type 'C1.S1' in async or iterator methods because 'C1.S1' is a ref struct or a type parameter that allows ref struct. + var expectedDiagnostics = new[] + { + // (15,9): error CS4007: Instance of type 'C1.S1' cannot be preserved across 'await' or 'yield' boundary. // foreach (var i in obj) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C1.S1").WithLocation(15, 9) - ); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"foreach (var i in obj) + { + await Task.Yield(); + System.Console.WriteLine(i); + }").WithArguments("C1.S1").WithLocation(15, 9) + }; + + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithMscorlibAndSpan(text).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74793")] + public void RefIteratorInAsync_02() + { + var text = @" +using System.Threading.Tasks; + +class Program +{ + static async Task Main() + { + var obj = new C1(); + + foreach (var i in obj) + { + System.Console.Write(i); + } + + await Task.Yield(); + + System.Console.Write(-1); + } +} + +class C1 +{ + public S1 GetEnumerator() + { + return new S1(); + } + + public ref struct S1 + { + public int Current { get; private set; } + + public bool MoveNext() + { + Current++; + return Current < 3; + } + } +} + +"; + + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (10,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // foreach (var i in obj) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(10, 9)); + + var expectedOutput = "12-1"; + + var comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe, TestOptions.Regular13); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + + comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); } [WorkItem(20226, "https://github.com/dotnet/roslyn/issues/20226")] [Fact] - public void RefIteratorInIterator() + public void RefIteratorInIterator_01() { var text = @" using System; @@ -1034,6 +1103,7 @@ static IEnumerable Test() // this is an error foreach (var i in new C1()) { + yield return 0; } yield return 1; @@ -1059,13 +1129,87 @@ public bool MoveNext() } "; - CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (33,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // foreach (var i in new C1()) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(33, 9)); - comp.VerifyDiagnostics( - // (33,9): error CS8344: foreach statement cannot operate on enumerators of type 'C1.S1' in async or iterator methods because 'C1.S1' is a ref struct or a type parameter that allows ref struct. + var expectedDiagnostics = new[] + { + // (33,9): error CS4007: Instance of type 'C1.S1' cannot be preserved across 'await' or 'yield' boundary. // foreach (var i in new C1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C1.S1").WithLocation(33, 9) - ); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"foreach (var i in new C1()) + { + yield return 0; + }").WithArguments("C1.S1").WithLocation(33, 9) + }; + + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithMscorlibAndSpan(text).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefIteratorInIterator_02() + { + var text = @" +using System; +using System.Collections.Generic; + +class Program +{ + static void Main(string[] args) + { + foreach (var i in Test()) + { + Console.Write(i); + } + } + + static IEnumerable Test() + { + foreach (var i in new C1()) + { + Console.Write(i); + } + + yield return -1; + + Console.Write(-2); + } +} + +class C1 +{ + public S1 GetEnumerator() + { + return new S1(); + } + + public ref struct S1 + { + public int Current { get; private set; } + + public bool MoveNext() + { + Current++; + return Current < 3; + } + } +} +"; + + CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe, TestOptions.Regular12).VerifyDiagnostics( + // (17,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // foreach (var i in new C1()) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(17, 9)); + + var expectedOutput = "12-1-2"; + + var comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe, TestOptions.Regular13); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + + comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); } [Fact]