From 860e7dd9015d95f5e367b63e5607faf3e1952797 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Tue, 22 Oct 2024 17:55:49 -0700 Subject: [PATCH 1/2] Disallow ref like types as iterator elementtypes. --- .../Portable/Binder/ExecutableCodeBinder.cs | 4 + .../CSharp/Portable/CSharpResources.resx | 3 + .../CSharp/Portable/Errors/ErrorCode.cs | 2 + .../CSharp/Portable/Errors/ErrorFacts.cs | 1 + .../Portable/xlf/CSharpResources.cs.xlf | 5 + .../Portable/xlf/CSharpResources.de.xlf | 5 + .../Portable/xlf/CSharpResources.es.xlf | 5 + .../Portable/xlf/CSharpResources.fr.xlf | 5 + .../Portable/xlf/CSharpResources.it.xlf | 5 + .../Portable/xlf/CSharpResources.ja.xlf | 5 + .../Portable/xlf/CSharpResources.ko.xlf | 5 + .../Portable/xlf/CSharpResources.pl.xlf | 5 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 + .../Portable/xlf/CSharpResources.ru.xlf | 5 + .../Portable/xlf/CSharpResources.tr.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 + .../Test/Emit3/RefStructInterfacesTests.cs | 171 ++++++++++++++++++ 18 files changed, 246 insertions(+) diff --git a/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs b/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs index e08152589f822..49fc5d773b0e7 100644 --- a/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs @@ -147,6 +147,10 @@ public static void ValidateIteratorMethod(CSharpCompilation compilation, MethodS Error(diagnostics, ErrorCode.ERR_BadIteratorReturn, errorLocation, iterator, returnType); } } + else if (elementType.IsRefLikeOrAllowsRefLikeType()) + { + Error(diagnostics, ErrorCode.ERR_IteratorRefLikeElementType, errorLocation); + } bool asyncInterface = InMethodBinder.IsAsyncStreamInterface(compilation, refKind, returnType); if (asyncInterface && !iterator.IsAsync) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 02309788c4a15..6bf7a4187ab41 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -8008,4 +8008,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ first-class Span types + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 5aee2f4c0cdac..8c0b94c790157 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2348,6 +2348,8 @@ internal enum ErrorCode WRN_UninitializedNonNullableBackingField = 9264, WRN_UnassignedInternalRefField = 9265, + ERR_IteratorRefLikeElementType = 9266, + // 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 fc3a2fb62ef7c..064670f55e630 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -2464,6 +2464,7 @@ or ErrorCode.ERR_CannotApplyOverloadResolutionPriorityToMember or ErrorCode.ERR_PartialPropertyDuplicateInitializer or ErrorCode.WRN_UninitializedNonNullableBackingField or ErrorCode.WRN_UnassignedInternalRefField + or ErrorCode.ERR_IteratorRefLikeElementType => false, }; #pragma warning restore CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 524688eca6e7f..c980f36730326 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1327,6 +1327,11 @@ Metoda {0} s blokem iterátoru musí být asynchronní, aby vrátila {1}. + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + The contextual keyword 'var' cannot be used as an explicit lambda return type Kontextové klíčové slovo var se nedá použít jako explicitní návratový typ lambda. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 6f82fa98e3036..70a410130f6a0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1327,6 +1327,11 @@ Die Methode "{0}" mit einem Iteratorblock muss "async" lauten, um "{1}" zurückzugeben. + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + The contextual keyword 'var' cannot be used as an explicit lambda return type Das kontextbezogene Schlüsselwort „var“ kann nicht als expliziter Lambdarückgabetyp verwendet werden. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index c34124ffc745c..df4e45e1a4e08 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1327,6 +1327,11 @@ El método "{0}" con un bloqueo de iterador debe ser "asincrónico" para devolver "{1}" + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + The contextual keyword 'var' cannot be used as an explicit lambda return type La palabra clave contextual "var" no se puede utilizar como un tipo de retorno lambda explícito diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index dbb464be7704c..4e0eaec1b1428 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1327,6 +1327,11 @@ La méthode '{0}' avec un bloc itérateur doit être 'async' pour retourner '{1}' + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + The contextual keyword 'var' cannot be used as an explicit lambda return type Le mot clé contextuel 'var' ne peut pas être utilisé comme type de retour lambda explicite diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 71c6ebd82ad29..12e49049a0b36 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1327,6 +1327,11 @@ Il metodo '{0}' con un blocco iteratore deve essere 'async' per restituire '{1}' + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + The contextual keyword 'var' cannot be used as an explicit lambda return type Non è possibile usare la parola chiave contestuale 'var' come tipo restituito dell’espressione lambda diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 0173978341a7d..d30d4b5ffd043 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1327,6 +1327,11 @@ 反復子ブロックを伴うメソッド '{0}' が '{1}' を返すには 'async' でなければなりません + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + The contextual keyword 'var' cannot be used as an explicit lambda return type コンテキスト キーワード "var" を明示的なラムダ戻り値の型として使用することはできません diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index fe60376a96722..c707f3ed1c7e8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1327,6 +1327,11 @@ '{1}'을(를) 반환하려면 반복기 블록이 있는 '{0}' 메서드가 '비동기'여야 합니다. + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + The contextual keyword 'var' cannot be used as an explicit lambda return type 'var' 상황별 키워드는 명시적 람다 반환 형식으로 사용할 수 없습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 5a46a783e9fa0..b08a7790b8347 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1327,6 +1327,11 @@ Metoda „{0}” z blokiem iteratora musi być oznaczona jako „async”, aby zwrócić „{1}” + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + The contextual keyword 'var' cannot be used as an explicit lambda return type Kontekstowego słowa kluczowego „var” nie można użyć jako jawnego zwracanego typu lambda diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 4582d5f210af1..7e9b0d18c82e0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1327,6 +1327,11 @@ O método '{0}' com um bloco do iterador deve ser 'async' para retornar '{1}' + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + The contextual keyword 'var' cannot be used as an explicit lambda return type A palavra-chave contextual 'var' não pode ser usada como um tipo de retorno de lambda explícito diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index f56fe761715c7..6ccb4ed9c59df 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1327,6 +1327,11 @@ Чтобы возвращать "{1}", метод "{0}" с блоком итератора должен быть асинхронным ("async"). + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + The contextual keyword 'var' cannot be used as an explicit lambda return type Контекстное ключевое слово "var" нельзя использовать в качестве явного типа возвращаемого значения лямбда-выражения diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index fe19460a820c6..e4b62af5a6ccc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1327,6 +1327,11 @@ Yineleyici bloku olan '{0}' yönteminin '{1}' döndürmek için 'zaman uyumsuz' olması gerekir + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + The contextual keyword 'var' cannot be used as an explicit lambda return type Bağlamsal 'var' anahtar sözcüğü, açık lambda dönüş türü olarak kullanılamaz diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index c064283b0d316..d586ba59b3a69 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1327,6 +1327,11 @@ 具有迭代器块的方法“{0}”必须是“异步的”,这样才能返回“{1}” + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + The contextual keyword 'var' cannot be used as an explicit lambda return type 上下文关键字 “var” 不能用作显式 lambda 返回类型 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 867c0e405de57..7e63186e68487 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1327,6 +1327,11 @@ 具有迭代區塊的方法 '{0}' 必須為「非同步」才能傳回 '{1}' + + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + + The contextual keyword 'var' cannot be used as an explicit lambda return type 內容關鍵字 'var' 不得做為明確的 Lambda 傳回型別 diff --git a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs index 9eb341f5bb670..b505c4518ad63 100644 --- a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs @@ -28992,5 +28992,176 @@ public ReadOnlySpan GetDirectBuffer2() Diagnostic(ErrorCode.ERR_RefReturnStructThis, "directBuffer").WithLocation(2000, 16) ); } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75569")] + [WorkItem("https://github.com/dotnet/roslyn/issues/75577")] + public void Iterator_01() + { + var source = +@" +using System; +using System.Collections.Generic; + +static class CSharpCompilerCrash +{ + public static IEnumerable> Lines(string data) + { + yield break; + } +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics( + // (7,51): error CS9266: Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + // public static IEnumerable> Lines(string data) + Diagnostic(ErrorCode.ERR_IteratorRefLikeElementType, "Lines").WithLocation(7, 51) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75569")] + [WorkItem("https://github.com/dotnet/roslyn/issues/75577")] + public void Iterator_02() + { + var source = +@" +using System.Collections.Generic; + +static class CSharpCompilerCrash +{ + static IEnumerable B() + { + yield break; + } + + ref struct A; +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics( + // (6,27): error CS9266: Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + // static IEnumerable B() + Diagnostic(ErrorCode.ERR_IteratorRefLikeElementType, "B").WithLocation(6, 27) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75569")] + [WorkItem("https://github.com/dotnet/roslyn/issues/75577")] + public void Iterator_03() + { + var source = +@" +using System.Collections.Generic; + +static class CSharpCompilerCrash +{ + static IEnumerator B + { + get + { + yield break; + } + } + + ref struct A; +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics( + // (8,9): error CS9266: Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + // get + Diagnostic(ErrorCode.ERR_IteratorRefLikeElementType, "get").WithLocation(8, 9) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75569")] + [WorkItem("https://github.com/dotnet/roslyn/issues/75577")] + public void Iterator_04() + { + var source = +@" +#pragma warning disable CS1998 // This async method lacks 'await' operators + +using System.Collections.Generic; + +static class CSharpCompilerCrash +{ + static async IAsyncEnumerable B() + { + yield return default; + yield break; + } + + ref struct RefStructA; +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); + comp.VerifyDiagnostics( + // (8,47): error CS9266: Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + // static async IAsyncEnumerable B() + Diagnostic(ErrorCode.ERR_IteratorRefLikeElementType, "B").WithLocation(8, 47) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75569")] + [WorkItem("https://github.com/dotnet/roslyn/issues/75577")] + public void Iterator_05() + { + var source = +@" +#pragma warning disable CS1998 // This async method lacks 'await' operators + +using System.Collections.Generic; + +static class CSharpCompilerCrash +{ + static async IAsyncEnumerator B() + { + yield return default; + yield break; + } + + ref struct RefStructA; +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); + comp.VerifyDiagnostics( + // (8,47): error CS9266: Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + // static async IAsyncEnumerator B() + Diagnostic(ErrorCode.ERR_IteratorRefLikeElementType, "B").WithLocation(8, 47) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75569")] + [WorkItem("https://github.com/dotnet/roslyn/issues/75577")] + public void Iterator_06() + { + var source = +@" +#pragma warning disable CS1998 // This async method lacks 'await' operators + +using System.Collections.Generic; + +static class CSharpCompilerCrash +{ + static async IAsyncEnumerator B() where T : allows ref struct + { + yield return default; + yield break; + } +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); + comp.VerifyDiagnostics( + // (8,38): error CS9266: Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + // static async IAsyncEnumerator B() where T : allows ref struct + Diagnostic(ErrorCode.ERR_IteratorRefLikeElementType, "B").WithLocation(8, 38) + ); + } } } From c5f277ee1c4d77718dcb7a6393ab7c6bacea0efa Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Tue, 22 Oct 2024 21:09:37 -0700 Subject: [PATCH 2/2] Fixup --- .../CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs index c8b79ddce9d23..a607dbf9aa094 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs @@ -641,7 +641,10 @@ ref struct S { // source(4,65): error CS9244: 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) + Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "M").WithArguments("System.Collections.Generic.IAsyncEnumerable", "T", "S").WithLocation(4, 65), + // source(4,65): error CS9267: Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + // static async System.Collections.Generic.IAsyncEnumerable M() + Diagnostic(ErrorCode.ERR_IteratorRefLikeElementType, "M").WithLocation(4, 65) }; var comp = CreateCompilationWithAsyncIterator(source, options: TestOptions.DebugExe); @@ -655,6 +658,9 @@ ref struct S // source(4,65): error CS9244: 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(4,65): error CS9267: Element type of an iterator may not be a ref struct or a type parameter allowing ref structs + // static async System.Collections.Generic.IAsyncEnumerable M() + Diagnostic(ErrorCode.ERR_IteratorRefLikeElementType, "M").WithLocation(4, 65), // source(11,24): 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 M()) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "var").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(11, 24));