From 2f577b776b638969999685d8b07f783d847856d2 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Fri, 17 May 2024 09:59:36 -0700 Subject: [PATCH 1/2] Check language version for more scenarios --- .../Portable/Binder/Binder_Expressions.cs | 9 +- .../Portable/Binder/ForEachLoopBinder.cs | 17 +- .../Semantics/Conversions/ConversionsBase.cs | 36 +- .../Portable/Binder/UsingStatementBinder.cs | 28 +- .../LocalRewriter_ForEachStatement.cs | 2 +- ...ObjectOrCollectionInitializerExpression.cs | 2 +- .../Operations/CSharpOperationFactory.cs | 3 +- .../Test/Emit3/RefStructInterfacesTests.cs | 1610 +++++++++++++++-- 8 files changed, 1516 insertions(+), 191 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 890b8b5d093d7..fbd07fc353ef3 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -6158,8 +6158,15 @@ private bool CollectionInitializerTypeImplementsIEnumerable(TypeSymbol initializ // NOTE: type to the predefined System.Collections.IEnumerable type, so we do the same. CompoundUseSiteInfo useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics); - var result = Conversions.HasImplicitConversionToOrImplementsVarianceCompatibleInterface(initializerType, collectionsIEnumerableType, ref useSiteInfo); + var result = Conversions.HasImplicitConversionToOrImplementsVarianceCompatibleInterface(initializerType, collectionsIEnumerableType, ref useSiteInfo, out bool needSupportForRefStructInterfaces); diagnostics.Add(node, useSiteInfo); + + if (needSupportForRefStructInterfaces && + initializerType.ContainingModule != Compilation.SourceModule) + { + CheckFeatureAvailability(node, MessageID.IDS_FeatureRefStructInterfaces, diagnostics); + } + return result; } else diff --git a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs index 26bcf19b82de5..e37917d6a345c 100644 --- a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs @@ -1259,10 +1259,17 @@ bool implementsInterface(TypeSymbol enumeratorType, bool isAsync, BindingDiagnos bool result = this.Conversions.HasImplicitConversionToOrImplementsVarianceCompatibleInterface(enumeratorType, targetInterface, - ref useSiteInfo); + ref useSiteInfo, + out bool needSupportForRefStructInterfaces); diagnostics.Add(syntax, useSiteInfo); + if (needSupportForRefStructInterfaces && + enumeratorType.ContainingModule != Compilation.SourceModule) + { + CheckFeatureAvailability(syntax, MessageID.IDS_FeatureRefStructInterfaces, diagnostics); + } + return result; } } @@ -1759,11 +1766,17 @@ private bool AllInterfacesContainsIEnumerable( var implementedNonGeneric = this.Compilation.GetSpecialType(SpecialType.System_Collections_IEnumerable); if ((object)implementedNonGeneric != null) { - var implements = this.Conversions.HasImplicitConversionToOrImplementsVarianceCompatibleInterface(type, implementedNonGeneric, ref useSiteInfo); + var implements = this.Conversions.HasImplicitConversionToOrImplementsVarianceCompatibleInterface(type, implementedNonGeneric, ref useSiteInfo, out bool needSupportForRefStructInterfaces); if (implements) { implementedIEnumerable = implementedNonGeneric; + + if (needSupportForRefStructInterfaces && + type.ContainingModule != Compilation.SourceModule) + { + CheckFeatureAvailability(collectionSyntax, MessageID.IDS_FeatureRefStructInterfaces, diagnostics); + } } } } diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs index a345493c4a9c4..28c1c79ac1461 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs @@ -2967,12 +2967,24 @@ internal bool ImplementsVarianceCompatibleInterface(NamedTypeSymbol derivedType, return ImplementsVarianceCompatibleInterface((TypeSymbol)derivedType, baseType, ref useSiteInfo); } - internal bool HasImplicitConversionToOrImplementsVarianceCompatibleInterface(TypeSymbol typeToCheck, NamedTypeSymbol targetInterfaceType, ref CompoundUseSiteInfo useSiteInfo) + internal bool HasImplicitConversionToOrImplementsVarianceCompatibleInterface(TypeSymbol typeToCheck, NamedTypeSymbol targetInterfaceType, ref CompoundUseSiteInfo useSiteInfo, out bool needSupportForRefStructInterfaces) { Debug.Assert(targetInterfaceType.IsErrorType() || targetInterfaceType.IsInterface); - return ClassifyImplicitConversionFromType(typeToCheck, targetInterfaceType, ref useSiteInfo).IsImplicit || - IsRefLikeOrAllowsRefLikeTypeImplementingVarianceCompatibleInterface(typeToCheck, targetInterfaceType, ref useSiteInfo); + if (ClassifyImplicitConversionFromType(typeToCheck, targetInterfaceType, ref useSiteInfo).IsImplicit) + { + needSupportForRefStructInterfaces = false; + return true; + } + + if (IsRefLikeOrAllowsRefLikeTypeImplementingVarianceCompatibleInterface(typeToCheck, targetInterfaceType, ref useSiteInfo)) + { + needSupportForRefStructInterfaces = true; + return true; + } + + needSupportForRefStructInterfaces = false; + return false; } private bool IsRefLikeOrAllowsRefLikeTypeImplementingVarianceCompatibleInterface(TypeSymbol typeToCheck, NamedTypeSymbol targetInterfaceType, ref CompoundUseSiteInfo useSiteInfo) @@ -2989,12 +3001,24 @@ private bool IsRefLikeOrAllowsRefLikeTypeImplementingVarianceCompatibleInterface return false; } - internal bool HasImplicitConversionToOrImplementsVarianceCompatibleInterface(BoundExpression expressionToCheck, NamedTypeSymbol targetInterfaceType, ref CompoundUseSiteInfo useSiteInfo) + internal bool HasImplicitConversionToOrImplementsVarianceCompatibleInterface(BoundExpression expressionToCheck, NamedTypeSymbol targetInterfaceType, ref CompoundUseSiteInfo useSiteInfo, out bool needSupportForRefStructInterfaces) { Debug.Assert(targetInterfaceType.IsErrorType() || targetInterfaceType.IsInterface); - return ClassifyImplicitConversionFromExpression(expressionToCheck, targetInterfaceType, ref useSiteInfo).IsImplicit || - (expressionToCheck.Type is TypeSymbol typeToCheck && IsRefLikeOrAllowsRefLikeTypeImplementingVarianceCompatibleInterface(typeToCheck, targetInterfaceType, ref useSiteInfo)); + if (ClassifyImplicitConversionFromExpression(expressionToCheck, targetInterfaceType, ref useSiteInfo).IsImplicit) + { + needSupportForRefStructInterfaces = false; + return true; + } + + if (expressionToCheck.Type is TypeSymbol typeToCheck && IsRefLikeOrAllowsRefLikeTypeImplementingVarianceCompatibleInterface(typeToCheck, targetInterfaceType, ref useSiteInfo)) + { + needSupportForRefStructInterfaces = true; + return true; + } + + needSupportForRefStructInterfaces = false; + return false; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs index 9d4659c8e3637..8bf71321ff48f 100644 --- a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs @@ -236,10 +236,7 @@ bool bindDisposable(bool fromExpression, out MethodArgumentInfo? patternDisposeI NamedTypeSymbol disposableInterface = getDisposableInterface(hasAwait); Debug.Assert((object)disposableInterface != null); - CompoundUseSiteInfo useSiteInfo = originalBinder.GetNewCompoundUseSiteInfo(diagnostics); - bool implementsIDisposable = implementsInterface(fromExpression, disposableInterface, ref useSiteInfo); - - diagnostics.Add(syntax, useSiteInfo); + bool implementsIDisposable = implementsInterface(fromExpression, disposableInterface, diagnostics); if (implementsIDisposable) { @@ -255,8 +252,7 @@ bool bindDisposable(bool fromExpression, out MethodArgumentInfo? patternDisposeI { // Retry with a different assumption about whether the `using` is async NamedTypeSymbol alternateInterface = getDisposableInterface(!hasAwait); - var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; - bool implementsAlternateIDisposable = implementsInterface(fromExpression, alternateInterface, ref discardedUseSiteInfo); + bool implementsAlternateIDisposable = implementsInterface(fromExpression, alternateInterface, BindingDiagnosticBag.Discarded); ErrorCode errorCode = implementsAlternateIDisposable ? (hasAwait ? ErrorCode.ERR_NoConvToIAsyncDispWrongAsync : ErrorCode.ERR_NoConvToIDispWrongAsync) @@ -268,19 +264,33 @@ bool bindDisposable(bool fromExpression, out MethodArgumentInfo? patternDisposeI return false; } - bool implementsInterface(bool fromExpression, NamedTypeSymbol targetInterface, ref CompoundUseSiteInfo useSiteInfo) + bool implementsInterface(bool fromExpression, NamedTypeSymbol targetInterface, BindingDiagnosticBag diagnostics) { var conversions = originalBinder.Conversions; + CompoundUseSiteInfo useSiteInfo = originalBinder.GetNewCompoundUseSiteInfo(diagnostics); + bool result; + bool needSupportForRefStructInterfaces; + if (fromExpression) { Debug.Assert(expressionOpt is { }); - return conversions.HasImplicitConversionToOrImplementsVarianceCompatibleInterface(expressionOpt, targetInterface, ref useSiteInfo); + result = conversions.HasImplicitConversionToOrImplementsVarianceCompatibleInterface(expressionOpt, targetInterface, ref useSiteInfo, out needSupportForRefStructInterfaces); } else { Debug.Assert(declarationTypeOpt is { }); - return conversions.HasImplicitConversionToOrImplementsVarianceCompatibleInterface(declarationTypeOpt, targetInterface, ref useSiteInfo); + result = conversions.HasImplicitConversionToOrImplementsVarianceCompatibleInterface(declarationTypeOpt, targetInterface, ref useSiteInfo, out needSupportForRefStructInterfaces); } + + diagnostics.Add(syntax, useSiteInfo); + + if (needSupportForRefStructInterfaces && + (fromExpression ? expressionOpt!.Type : declarationTypeOpt)!.ContainingModule != originalBinder.Compilation.SourceModule) + { + CheckFeatureAvailability(syntax, MessageID.IDS_FeatureRefStructInterfaces, diagnostics); + } + + return result; } NamedTypeSymbol getDisposableInterface(bool isAsync) diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs index bf6e62d952567..1336bde261b7c 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs @@ -338,7 +338,7 @@ private bool TryGetDisposeMethod(SyntaxNode forEachSyntax, ForEachEnumeratorInfo var conversions = _factory.CurrentFunction.ContainingAssembly.CorLibrary.TypeConversions; CompoundUseSiteInfo useSiteInfo = GetNewCompoundUseSiteInfo(); - implementsInterface = conversions.HasImplicitConversionToOrImplementsVarianceCompatibleInterface(enumeratorType, idisposableTypeSymbol, ref useSiteInfo); + implementsInterface = conversions.HasImplicitConversionToOrImplementsVarianceCompatibleInterface(enumeratorType, idisposableTypeSymbol, ref useSiteInfo, out _); _diagnostics.Add(forEachSyntax, useSiteInfo); } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectOrCollectionInitializerExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectOrCollectionInitializerExpression.cs index bd8b44b7d3132..fca9eecc90167 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectOrCollectionInitializerExpression.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ObjectOrCollectionInitializerExpression.cs @@ -664,7 +664,7 @@ private BoundExpression MakeObjectInitializerMemberAccess( #if DEBUG var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; Debug.Assert(_compilation.Conversions.ClassifyConversionFromType(rewrittenReceiver.Type, memberSymbol.ContainingType, isChecked: false, ref discardedUseSiteInfo).IsImplicit || - _compilation.Conversions.HasImplicitConversionToOrImplementsVarianceCompatibleInterface(rewrittenReceiver.Type, memberSymbol.ContainingType, ref discardedUseSiteInfo)); + _compilation.Conversions.HasImplicitConversionToOrImplementsVarianceCompatibleInterface(rewrittenReceiver.Type, memberSymbol.ContainingType, ref discardedUseSiteInfo, out _)); // It is possible there are use site diagnostics from the above, but none that we need report as we aren't generating code for the conversion #endif diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs index 2dcdb75056518..2b7e62c5393bc 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs @@ -1881,7 +1881,8 @@ private IForLoopOperation CreateBoundForStatementOperation(BoundForStatement bou compilation.Conversions. HasImplicitConversionToOrImplementsVarianceCompatibleInterface(enumeratorInfoOpt.GetEnumeratorInfo.Method.ReturnType, iDisposable, - ref discardedUseSiteInfo) : + ref discardedUseSiteInfo, + needSupportForRefStructInterfaces: out _) : false, enumeratorInfoOpt.PatternDisposeInfo?.Method.GetPublicSymbol(), BoundNode.GetConversion(enumeratorInfoOpt.CurrentConversion, enumeratorInfoOpt.CurrentPlaceholder), diff --git a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs index 26f83e2985b22..206f9a273aeb6 100644 --- a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs @@ -5853,9 +5853,9 @@ void verify(ModuleSymbol m) Assert.Equal("I1", s1.InterfacesNoUseSiteDiagnostics().Single().ToTestDisplayString()); } - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + CreateCompilation(src, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular12).VerifyDiagnostics( // (5,17): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // ref struct S1 : I1 Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1").WithArguments("ref struct interfaces").WithLocation(5, 17) @@ -7112,6 +7112,130 @@ static void Test(T t, IMyDisposable s) where T : IMyDisposable, allows ref st ); } + [Fact] + public void Using_LanguageVersion_01() + { + var src1 = @" +public ref struct S2 : System.IDisposable +{ + public void Dispose() + { + } +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +class C +{ + static void Main() + { + using (new S2()) + { + } + + using (var s = new S2()) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + + [Fact] + public void Using_LanguageVersion_02() + { + var src1 = @" +public ref struct S2 : System.IDisposable +{ + void System.IDisposable.Dispose() + { + } +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +class C +{ + static void Main() + { + using (new S2()) + { + } + + using (var s = new S2()) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (6,16): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // using (new S2()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S2()").WithArguments("ref struct interfaces").WithLocation(6, 16), + // (10,16): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // using (var s = new S2()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var s = new S2()").WithArguments("ref struct interfaces").WithLocation(10, 16) + ); + + comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (2,24): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public ref struct S2 : System.IDisposable + Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.IDisposable").WithArguments("ref struct interfaces").WithLocation(2, 24) + ); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + + [Fact] + public void Using_LanguageVersion_04() + { + var src = @" +class C +{ + static void Test(T t) where T : System.IDisposable, allows ref struct + { + using (t) + { + } + + using (var s = t) + { + } + } +} +"; + var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp.VerifyEmitDiagnostics( + // (4,67): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static void Test(T t) where T : System.IDisposable, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(4, 67) + ); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp.VerifyEmitDiagnostics(); + } + [Fact] public void Foreach_IEnumerableT_01() { @@ -8343,6 +8467,146 @@ .locals init (System.Collections.Generic.IEnumerator V_0) AssertEx.Equal("System.Int32", op.Info.ElementType.ToTestDisplayString()); } + [Fact] + public void Foreach_IEnumerableT_LanguageVersion_01() + { + var src1 = @" +using System.Collections.Generic; + +public ref struct S : IEnumerable +{ + public IEnumerator GetEnumerator() => throw null; +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +class C +{ + static void Main() + { + foreach (var i in new S()) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + + [Fact] + public void Foreach_IEnumerableT_LanguageVersion_03() + { + var src1 = @" +using System.Collections.Generic; + +public ref struct S : IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() => throw null; + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null; +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +class C +{ + static void Main() + { + foreach (var i in new S()) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + + [Fact] + public void Foreach_IEnumerableT_LanguageVersion_04() + { + var src = @" +using System.Collections.Generic; + +class C +{ + static void Test(T t) where T : IEnumerable, allows ref struct + { + foreach (var i in t) + { + } + } +} +"; + var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp.VerifyEmitDiagnostics( + // (6,65): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static void Test(T t) where T : IEnumerable, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(6, 65) + ); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Foreach_IEnumerableT_LanguageVersion_05() + { + var src1 = @" +using System.Collections.Generic; + +public interface IMyEnumerable +{ + IEnumerator GetEnumerator(); +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +class C +{ + static void Test(T t) where T : IMyEnumerable, allows ref struct + { + foreach (var i in t) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (4,67): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static void Test(T t) where T : IMyEnumerable, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(4, 67) + ); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + [Theory] [CombinatorialData] public void Foreach_IEnumeratorT_01(bool s1IsRefStruct) @@ -11182,10 +11446,10 @@ static void Test(TEnumerable t) } [Fact] - public void Foreach_Pattern_01() + public void Foreach_IDisposable_LanguageVersion_01() { - var src = @" -ref struct S1 + var src1 = @" +public struct S1 { public S2 GetEnumerator() { @@ -11193,51 +11457,42 @@ public S2 GetEnumerator() } } -ref struct S2 +public ref struct S2 : System.IDisposable { - bool stop; - public int Current => 123; - public bool MoveNext() - { - if (!stop) - { - stop = true; - return true; - } - - return false; - } - public void Dispose() - { - System.Console.Write('D'); - } + public int Current => throw null; + public bool MoveNext() => throw null; + public void Dispose() => throw null; } +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + var src2 = @" class C { static void Main() { foreach (var i in new S1()) { - System.Console.Write(i); } } } "; - var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics(); - CompileAndVerify( - comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? @"123D" : null, - verify: ExecutionConditionUtil.IsMonoOrCoreClr ? - Verification.FailsILVerify with { ILVerifyMessage = "[GetEnumerator]: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. { Offset = 0x9 }" } : - Verification.Skipped).VerifyDiagnostics(); + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); } [Fact] - public void Foreach_Pattern_02() + public void Foreach_IDisposable_LanguageVersion_03() { - var src = @" -struct S1 + var src1 = @" +public struct S1 { public S2 GetEnumerator() { @@ -11245,29 +11500,178 @@ public S2 GetEnumerator() } } -ref struct S2 +public ref struct S2 : System.IDisposable { - bool stop; - public int Current => 123; - public bool MoveNext() - { - if (!stop) - { - stop = true; - return true; - } - - return false; - } + public int Current => throw null; + public bool MoveNext() => throw null; + void System.IDisposable.Dispose() => throw null; } +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + var src2 = @" class C { static void Main() { - foreach (var i in new S1()) - { - System.Console.Write(i); + foreach (var i in new S1()) {} + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (6,9): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (var i in new S1()) {} + Diagnostic(ErrorCode.ERR_FeatureInPreview, "foreach (var i in new S1()) {}").WithArguments("ref struct interfaces").WithLocation(6, 9) + ); + + comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (10,24): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public ref struct S2 : System.IDisposable + Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.IDisposable").WithArguments("ref struct interfaces").WithLocation(10, 24) + ); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + + [Fact] + public void Foreach_IDisposable_LanguageVersion_04() + { + var src = @" +interface ICustomEnumerator +{ + int Current {get;} + bool MoveNext(); +} + +interface IGetEnumerator where TEnumerator : ICustomEnumerator, System.IDisposable, allows ref struct +{ + TEnumerator GetEnumerator(); +} + +class C +{ + static void Test(TEnumerable t) + where TEnumerable : IGetEnumerator, allows ref struct + where TEnumerator : ICustomEnumerator, System.IDisposable, allows ref struct + { + foreach (var i in t) {} + } +} +"; + var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp.VerifyEmitDiagnostics( + // (8,105): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // interface IGetEnumerator where TEnumerator : ICustomEnumerator, System.IDisposable, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(8, 105), + // (16,65): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // where TEnumerable : IGetEnumerator, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(16, 65), + // (17,75): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // where TEnumerator : ICustomEnumerator, System.IDisposable, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(17, 75) + ); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Foreach_Pattern_01() + { + var src = @" +ref struct S1 +{ + public S2 GetEnumerator() + { + return new S2(); + } +} + +ref struct S2 +{ + bool stop; + public int Current => 123; + public bool MoveNext() + { + if (!stop) + { + stop = true; + return true; + } + + return false; + } + public void Dispose() + { + System.Console.Write('D'); + } +} + +class C +{ + static void Main() + { + foreach (var i in new S1()) + { + System.Console.Write(i); + } + } +} +"; + var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); + + CompileAndVerify( + comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? @"123D" : null, + verify: ExecutionConditionUtil.IsMonoOrCoreClr ? + Verification.FailsILVerify with { ILVerifyMessage = "[GetEnumerator]: Return type is ByRef, TypedReference, ArgHandle, or ArgIterator. { Offset = 0x9 }" } : + Verification.Skipped).VerifyDiagnostics(); + } + + [Fact] + public void Foreach_Pattern_02() + { + var src = @" +struct S1 +{ + public S2 GetEnumerator() + { + return new S2(); + } +} + +ref struct S2 +{ + bool stop; + public int Current => 123; + public bool MoveNext() + { + if (!stop) + { + stop = true; + return true; + } + + return false; + } +} + +class C +{ + static void Main() + { + foreach (var i in new S1()) + { + System.Console.Write(i); } } } @@ -12930,92 +13334,321 @@ static async Task Main() } [Fact] - public void AwaitForeach_IAsyncEnumerableT_01() + public void AwaitUsing_LanguageVersion_01() { - var src = @" -using System.Collections.Generic; -using System.Threading; + var src1 = @" +using System; using System.Threading.Tasks; -ref struct S : IAsyncEnumerable +public ref struct S2 : IAsyncDisposable { - public IAsyncEnumerator GetAsyncEnumerator(CancellationToken token = default) + public ValueTask DisposeAsync() { - return Get123(); + return ValueTask.CompletedTask; } +} +"; - async static IAsyncEnumerator Get123() + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +class C +{ + static async System.Threading.Tasks.Task Main() { - await Task.Yield(); - yield return 123; + await using (new S2()) + { + } + + await using (var s = new S2()) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (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 S2()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S2()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 22), + // (10,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 (var s = new S2()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 22) + ); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + + [Fact] + public void AwaitUsing_LanguageVersion_02() + { + var src1 = @" +using System; +using System.Threading.Tasks; + +public ref struct S2 : IAsyncDisposable +{ + ValueTask IAsyncDisposable.DisposeAsync() + { + System.Console.Write('D'); + return ValueTask.CompletedTask; } } +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + var src2 = @" class C { - static async Task Main() + static async System.Threading.Tasks.Task Main() { - await foreach (var i in new S()) + await using (new S2()) + { + } + + await using (var s = new S2()) { - System.Console.Write(i); } } } "; - var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (6,22): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await using (new S2()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S2()").WithArguments("ref struct interfaces").WithLocation(6, 22), + // (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 S2()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S2()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(6, 22), + // (10,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 (var s = new S2()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(10, 22), + // (10,22): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await using (var s = new S2()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var s = new S2()").WithArguments("ref struct interfaces").WithLocation(10, 22) + ); - var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? @"123" : null, verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); + comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (5,24): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public ref struct S2 : IAsyncDisposable + Diagnostic(ErrorCode.ERR_FeatureInPreview, "IAsyncDisposable").WithArguments("ref struct interfaces").WithLocation(5, 24), + // (18,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 S2()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S2()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(18, 22), + // (22,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 (var s = new S2()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(22, 22) + ); - verifier.VerifyIL("C.
d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", -@" + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + + [Fact] + public void AwaitUsing_LanguageVersion_04() + { + var src = @" +using System; +using System.Threading.Tasks; + +class C { - // Code size 405 (0x195) - .maxstack 3 - .locals init (int V_0, - S V_1, - System.Threading.CancellationToken V_2, - System.Runtime.CompilerServices.ValueTaskAwaiter V_3, - System.Threading.Tasks.ValueTask V_4, - object V_5, - System.Runtime.CompilerServices.ValueTaskAwaiter V_6, - System.Threading.Tasks.ValueTask V_7, - System.Exception V_8) - 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_003c - IL_000a: ldloc.0 - IL_000b: ldc.i4.1 - IL_000c: beq IL_0111 - IL_0011: ldarg.0 - IL_0012: ldloca.s V_1 - IL_0014: dup - IL_0015: initobj ""S"" - IL_001b: ldloca.s V_2 - IL_001d: initobj ""System.Threading.CancellationToken"" - IL_0023: ldloc.2 - IL_0024: call ""System.Collections.Generic.IAsyncEnumerator S.GetAsyncEnumerator(System.Threading.CancellationToken)"" - IL_0029: stfld ""System.Collections.Generic.IAsyncEnumerator C.
d__0.<>7__wrap1"" - IL_002e: ldarg.0 - IL_002f: ldnull - IL_0030: stfld ""object C.
d__0.<>7__wrap2"" - IL_0035: ldarg.0 - IL_0036: ldc.i4.0 - IL_0037: stfld ""int C.
d__0.<>7__wrap3"" - IL_003c: nop - .try + static async Task Test() where T : IAsyncDisposable, new(), allows ref struct { - IL_003d: ldloc.0 - IL_003e: brfalse.s IL_0093 - IL_0040: br.s IL_0052 - IL_0042: ldarg.0 - IL_0043: ldfld ""System.Collections.Generic.IAsyncEnumerator C.
d__0.<>7__wrap1"" - IL_0048: callvirt ""int System.Collections.Generic.IAsyncEnumerator.Current.get"" - IL_004d: call ""void System.Console.Write(int)"" - IL_0052: ldarg.0 + await using (new T()) + { + } + + await using (var s = new T()) + { + } + } +} + +namespace System +{ + public class Activator + { + public static T CreateInstance() where T : allows ref struct => default; + } +} +"; + var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp.VerifyEmitDiagnostics( + // (7,75): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static async Task Test() where T : IAsyncDisposable, new(), allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(7, 75), + // (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. + // await using (new T()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new T()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 22), + // (13,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 (var s = new T()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(13, 22), + // (23,63): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static T CreateInstance() where T : allows ref struct => default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(23, 63) + ); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void AwaitUsing_LanguageVersion_06() + { + var src = @" + +using System.Threading.Tasks; + +class C +{ + static async Task Test() where T : IMyAsyncDisposable, new(), allows ref struct + { + await using (new T()) + { + } + + await using (var s = new T()) + { + } + } +} + +namespace System +{ + public class Activator + { + public static T CreateInstance() where T : allows ref struct => default; + } +} + +interface IMyAsyncDisposable +{ + ValueTask DisposeAsync(); +} +"; + var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp.VerifyEmitDiagnostics( + // (7,77): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static async Task Test() where T : IMyAsyncDisposable, new(), allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(7, 77), + // (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. + // await using (new T()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new T()").WithArguments("ref and unsafe in async and iterator methods").WithLocation(9, 22), + // (13,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 (var s = new T()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "var").WithArguments("ref and unsafe in async and iterator methods").WithLocation(13, 22), + // (23,63): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static T CreateInstance() where T : allows ref struct => default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(23, 63) + ); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void AwaitForeach_IAsyncEnumerableT_01() + { + var src = @" +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +ref struct S : IAsyncEnumerable +{ + public IAsyncEnumerator GetAsyncEnumerator(CancellationToken token = default) + { + return Get123(); + } + + async static IAsyncEnumerator Get123() + { + await Task.Yield(); + yield return 123; + } +} + +class C +{ + static async Task Main() + { + await foreach (var i in new S()) + { + System.Console.Write(i); + } + } +} +"; + var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); + + var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? @"123" : null, verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); + + verifier.VerifyIL("C.
d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", +@" +{ + // Code size 405 (0x195) + .maxstack 3 + .locals init (int V_0, + S V_1, + System.Threading.CancellationToken V_2, + System.Runtime.CompilerServices.ValueTaskAwaiter V_3, + System.Threading.Tasks.ValueTask V_4, + object V_5, + System.Runtime.CompilerServices.ValueTaskAwaiter V_6, + System.Threading.Tasks.ValueTask V_7, + System.Exception V_8) + 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_003c + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: beq IL_0111 + IL_0011: ldarg.0 + IL_0012: ldloca.s V_1 + IL_0014: dup + IL_0015: initobj ""S"" + IL_001b: ldloca.s V_2 + IL_001d: initobj ""System.Threading.CancellationToken"" + IL_0023: ldloc.2 + IL_0024: call ""System.Collections.Generic.IAsyncEnumerator S.GetAsyncEnumerator(System.Threading.CancellationToken)"" + IL_0029: stfld ""System.Collections.Generic.IAsyncEnumerator C.
d__0.<>7__wrap1"" + IL_002e: ldarg.0 + IL_002f: ldnull + IL_0030: stfld ""object C.
d__0.<>7__wrap2"" + IL_0035: ldarg.0 + IL_0036: ldc.i4.0 + IL_0037: stfld ""int C.
d__0.<>7__wrap3"" + IL_003c: nop + .try + { + IL_003d: ldloc.0 + IL_003e: brfalse.s IL_0093 + IL_0040: br.s IL_0052 + IL_0042: ldarg.0 + IL_0043: ldfld ""System.Collections.Generic.IAsyncEnumerator C.
d__0.<>7__wrap1"" + IL_0048: callvirt ""int System.Collections.Generic.IAsyncEnumerator.Current.get"" + IL_004d: call ""void System.Console.Write(int)"" + IL_0052: ldarg.0 IL_0053: ldfld ""System.Collections.Generic.IAsyncEnumerator C.
d__0.<>7__wrap1"" IL_0058: callvirt ""System.Threading.Tasks.ValueTask System.Collections.Generic.IAsyncEnumerator.MoveNextAsync()"" IL_005d: stloc.s V_4 @@ -15079,6 +15712,158 @@ .locals init (int V_0, AssertEx.Equal("System.Int32", op.Info.ElementType.ToTestDisplayString()); } + [Fact] + public void AwaitForeach_IAsyncEnumerableT_LanguageVersion_01() + { + var src1 = @" +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +public ref struct S : IAsyncEnumerable +{ + public IAsyncEnumerator GetAsyncEnumerator(CancellationToken token = default) => throw null; +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +using System.Threading.Tasks; + +class C +{ + static async Task Main() + { + await foreach (var i in new S()) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + + [Fact] + public void AwaitForeach_IAsyncEnumerableT_LanguageVersion_03() + { + var src1 = @" +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +public ref struct S : IAsyncEnumerable +{ + IAsyncEnumerator IAsyncEnumerable.GetAsyncEnumerator(CancellationToken token = default) => throw null; +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +using System.Threading.Tasks; + +class C +{ + static async Task Main() + { + await foreach (var i in new S()) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + + [Fact] + public void AwaitForeach_IAsyncEnumerableT_LanguageVersion_04() + { + var src = @" +using System.Collections.Generic; +using System.Threading.Tasks; + +class C +{ + static async Task Test() where T : IAsyncEnumerable, allows ref struct + { + await foreach (var i in default(T)) + { + } + } +} +"; + var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp.VerifyEmitDiagnostics( + // (7,73): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static async Task Test() where T : IAsyncEnumerable, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(7, 73) + ); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void AwaitForeach_IAsyncEnumerableT_LanguageVersion_05() + { + var src1 = @" +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +public interface IMyAsyncEnumerable +{ + IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default); +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +using System.Threading.Tasks; + +class C +{ + static async Task Test() where T : IMyAsyncEnumerable, allows ref struct + { + await foreach (var i in default(T)) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (6,75): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static async Task Test() where T : IMyAsyncEnumerable, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(6, 75) + ); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + [Fact] public void AwaitForeach_Pattern() { @@ -16002,20 +16787,233 @@ static async Task Test() var foreachSyntax = tree.GetRoot().DescendantNodes().OfType().Single(); var info = model.GetForEachStatementInfo(foreachSyntax); - Assert.True(info.IsAsynchronous); - AssertEx.Equal("System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()", info.DisposeMethod.ToTestDisplayString()); + Assert.True(info.IsAsynchronous); + AssertEx.Equal("System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()", info.DisposeMethod.ToTestDisplayString()); + + var op = (Operations.ForEachLoopOperation)model.GetOperation(foreachSyntax); + Assert.True(op.Info.IsAsynchronous); + Assert.True(op.Info.NeedsDispose); + Assert.True(op.Info.KnownToImplementIDisposable); + Assert.Null(op.Info.PatternDisposeMethod); + Assert.True(op.Info.DisposeArguments.IsDefault); + } + + [Theory] + [CombinatorialData] + public void AwaitForeach_IAsyncDisposable_09(bool s1IsRefStruct, bool addStructConstraintToTEnumerable, bool addStructConstraintToTEnumerator) + { + var src = @" +using System; +using System.Threading; +using System.Threading.Tasks; + +interface ICustomEnumerator +{ + public int Current {get;} + + public ValueTask MoveNextAsync(); +} + +interface IGetEnumerator where TEnumerator : ICustomEnumerator, allows ref struct +{ + TEnumerator GetAsyncEnumerator(CancellationToken token = default); +} + +" + (s1IsRefStruct ? "ref " : "") + @"struct S1 : IGetEnumerator +{ + public S2 GetAsyncEnumerator(CancellationToken token = default) + { + return new S2(); + } +} + +ref struct S2 : ICustomEnumerator, IAsyncDisposable +{ + public int Current => throw null; + + public ValueTask DisposeAsync() => throw null; + + public ValueTask MoveNextAsync() => throw null; +} + +class C +{ + static async Task Main() + { + await Test(); + } + + static async Task Test() + where TEnumerable : " + (addStructConstraintToTEnumerable ? "struct, " : "") + @"IGetEnumerator, allows ref struct + where TEnumerator : " + (addStructConstraintToTEnumerator ? "struct, " : "") + @"ICustomEnumerator, allows ref struct + { + await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + } + } +} +"; + 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. + // await foreach (var i in default(TEnumerable)) + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(46, 15) + ); + + var tree = comp.SyntaxTrees.Single(); + var node = tree.GetRoot().DescendantNodes().OfType().Where(m => m.Identifier.ValueText == "Main").Single(); + var model = comp.GetSemanticModel(tree); + var foreachSyntax = tree.GetRoot().DescendantNodes().OfType().Single(); + var info = model.GetForEachStatementInfo(foreachSyntax); + + Assert.True(info.IsAsynchronous); + Assert.Null(info.DisposeMethod); + + var op = (Operations.ForEachLoopOperation)model.GetOperation(foreachSyntax); + Assert.True(op.Info.IsAsynchronous); + Assert.False(op.Info.NeedsDispose); + Assert.False(op.Info.KnownToImplementIDisposable); + Assert.Null(op.Info.PatternDisposeMethod); + Assert.True(op.Info.DisposeArguments.IsDefault); + } + + [Fact] + public void AwaitForeach_IAsyncDisposable_LanguageVersion_01() + { + var src1 = @" +using System; +using System.Threading; +using System.Threading.Tasks; + +public struct S1 +{ + public S2 GetAsyncEnumerator(CancellationToken token = default) + { + return new S2(); + } +} + +public ref struct S2 : IAsyncDisposable +{ + public int Current => throw null; + public ValueTask DisposeAsync() => throw null; + public ValueTask MoveNextAsync() => throw null; +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +using System; +using System.Threading; +using System.Threading.Tasks; + +class C +{ + static async Task Main() + { + await foreach (var i in new S1()) + { + } + } +} +"; + 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. + // await foreach (var i in new S1()) + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(10, 15) + ); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + 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. + // await foreach (var i in new S1()) + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(10, 15) + ); + + 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. + // await foreach (var i in new S1()) + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(10, 15) + ); + } + + [Fact] + public void AwaitForeach_IAsyncDisposable_LanguageVersion_03() + { + var src1 = @" +using System; +using System.Threading; +using System.Threading.Tasks; + +public struct S1 +{ + public S2 GetAsyncEnumerator(CancellationToken token = default) + { + return new S2(); + } +} + +public ref struct S2 : IAsyncDisposable +{ + public int Current => throw null; + ValueTask IAsyncDisposable.DisposeAsync() => throw null; + public ValueTask MoveNextAsync() => throw null; +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +class C +{ + static async System.Threading.Tasks.Task Main() + { + await foreach (var i in new S1()) {} + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (6,9): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // await foreach (var i in new S1()) {} + Diagnostic(ErrorCode.ERR_FeatureInPreview, "await foreach (var i in new S1()) {}").WithArguments("ref struct interfaces").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. + // await foreach (var i in new S1()) {} + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(6, 15) + ); + + comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (14,24): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public ref struct S2 : IAsyncDisposable + Diagnostic(ErrorCode.ERR_FeatureInPreview, "IAsyncDisposable").WithArguments("ref struct interfaces").WithLocation(14, 24), + // (25,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. + // await foreach (var i in new S1()) {} + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(25, 15) + ); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + 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. + // await foreach (var i in new S1()) {} + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(6, 15) + ); - var op = (Operations.ForEachLoopOperation)model.GetOperation(foreachSyntax); - Assert.True(op.Info.IsAsynchronous); - Assert.True(op.Info.NeedsDispose); - Assert.True(op.Info.KnownToImplementIDisposable); - Assert.Null(op.Info.PatternDisposeMethod); - Assert.True(op.Info.DisposeArguments.IsDefault); + 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. + // await foreach (var i in new S1()) {} + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(6, 15) + ); } - [Theory] - [CombinatorialData] - public void AwaitForeach_IAsyncDisposable_09(bool s1IsRefStruct, bool addStructConstraintToTEnumerable, bool addStructConstraintToTEnumerator) + [Fact] + public void AwaitForeach_IAsyncDisposable_LanguageVersion_04() { var src = @" using System; @@ -16034,64 +17032,45 @@ interface IGetEnumerator where TEnumerator : ICustomEnumerator, all TEnumerator GetAsyncEnumerator(CancellationToken token = default); } -" + (s1IsRefStruct ? "ref " : "") + @"struct S1 : IGetEnumerator -{ - public S2 GetAsyncEnumerator(CancellationToken token = default) - { - return new S2(); - } -} - -ref struct S2 : ICustomEnumerator, IAsyncDisposable -{ - public int Current => throw null; - - public ValueTask DisposeAsync() => throw null; - - public ValueTask MoveNextAsync() => throw null; -} - class C { - static async Task Main() - { - await Test(); - } - static async Task Test() - where TEnumerable : " + (addStructConstraintToTEnumerable ? "struct, " : "") + @"IGetEnumerator, allows ref struct - where TEnumerator : " + (addStructConstraintToTEnumerator ? "struct, " : "") + @"ICustomEnumerator, allows ref struct + where TEnumerable : IGetEnumerator, allows ref struct + where TEnumerator : ICustomEnumerator, IAsyncDisposable, allows ref struct { - await foreach (var i in default(TEnumerable)) - { - System.Console.Write(i); - } + await foreach (var i in default(TEnumerable)) {} } } "; - 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. - // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(46, 15) + var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp.VerifyEmitDiagnostics( + // (13,85): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // interface IGetEnumerator where TEnumerator : ICustomEnumerator, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(13, 85), + // (21,65): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // where TEnumerable : IGetEnumerator, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(21, 65), + // (22,73): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // where TEnumerator : ICustomEnumerator, IAsyncDisposable, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").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. + // await foreach (var i in default(TEnumerable)) {} + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(24, 15) ); - var tree = comp.SyntaxTrees.Single(); - var node = tree.GetRoot().DescendantNodes().OfType().Where(m => m.Identifier.ValueText == "Main").Single(); - var model = comp.GetSemanticModel(tree); - var foreachSyntax = tree.GetRoot().DescendantNodes().OfType().Single(); - var info = model.GetForEachStatementInfo(foreachSyntax); - - Assert.True(info.IsAsynchronous); - Assert.Null(info.DisposeMethod); + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + 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. + // await foreach (var i in default(TEnumerable)) {} + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(24, 15) + ); - var op = (Operations.ForEachLoopOperation)model.GetOperation(foreachSyntax); - Assert.True(op.Info.IsAsynchronous); - Assert.False(op.Info.NeedsDispose); - Assert.False(op.Info.KnownToImplementIDisposable); - Assert.Null(op.Info.PatternDisposeMethod); - Assert.True(op.Info.DisposeArguments.IsDefault); + 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. + // await foreach (var i in default(TEnumerable)) {} + Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(24, 15) + ); } [Fact] @@ -17363,6 +18342,156 @@ .locals init (System.Collections.IEnumerator V_0, AssertEx.Equal("System.Object", op.Info.ElementType.ToTestDisplayString()); } + [Fact] + public void Foreach_IEnumerable_LanguageVersion_01() + { + var src1 = @" +using System.Collections; + +public ref struct S : IEnumerable +{ + public IEnumerator GetEnumerator() => throw null; +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +class C +{ + static void Main() + { + foreach (var i in new S()) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + + [Fact] + public void Foreach_IEnumerable_LanguageVersion_03() + { + var src1 = @" +using System.Collections; + +public ref struct S : IEnumerable +{ + IEnumerator IEnumerable.GetEnumerator() => throw null; +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +class C +{ + static void Main() + { + foreach (var i in new S()) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (6,27): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // foreach (var i in new S()) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S()").WithArguments("ref struct interfaces").WithLocation(6, 27) + ); + + comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (4,23): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public ref struct S : IEnumerable + Diagnostic(ErrorCode.ERR_FeatureInPreview, "IEnumerable").WithArguments("ref struct interfaces").WithLocation(4, 23) + ); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + + [Fact] + public void Foreach_IEnumerable_LanguageVersion_04() + { + var src = @" +using System.Collections; + +class C +{ + static void Test(T t) where T : IEnumerable, allows ref struct + { + foreach (var i in t) + { + } + } +} +"; + var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp.VerifyEmitDiagnostics( + // (6,60): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static void Test(T t) where T : IEnumerable, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(6, 60) + ); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Foreach_IEnumerable_LanguageVersion_05() + { + var src1 = @" +using System.Collections; + +public interface IMyEnumerable +{ + IEnumerator GetEnumerator(); +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var src2 = @" +class C +{ + static void Test(T t) where T : IMyEnumerable, allows ref struct + { + foreach (var i in t) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (4,62): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static void Test(T t) where T : IMyEnumerable, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(4, 62) + ); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + [Theory] [CombinatorialData] public void Foreach_IEnumerator_01(bool s1IsRefStruct) @@ -25316,6 +26445,147 @@ public interface I1 : System.Collections.IEnumerable ); } + [Fact] + public void ObjectCreation_LanguageVersion_05() + { + var text1 = @" +public ref struct S : I1 +{ + public int P {get;set;} + public void Add(int x) => P += x; + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => null; +} + +public interface I1 : System.Collections.IEnumerable +{ + public void Add(int x); +} +"; + var comp1 = CreateCompilation(text1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var text2 = @" +class Program +{ + static T Test() + where T : I1, new(), allows ref struct + { + return new T() { 100, 20, 3 }; + } + + static void Main() + { + System.Console.Write((new S() { 200, 40, 6 }).P); + } +} + +namespace System +{ + public class Activator + { + public static T CreateInstance() where T : allows ref struct => default; + } +} +"; + + var comp2 = CreateCompilation(text2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (5,37): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // where T : I1, new(), allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(5, 37), + // (12,39): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // System.Console.Write((new S() { 200, 40, 6 }).P); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "{ 200, 40, 6 }").WithArguments("ref struct interfaces").WithLocation(12, 39), + // (20,62): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static T CreateInstance() where T : allows ref struct => default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(20, 62) + ); + + comp2 = CreateCompilation(text2 + text1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (5,37): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // where T : I1, new(), allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(5, 37), + // (20,62): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static T CreateInstance() where T : allows ref struct => default; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(20, 62), + // (24,23): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public ref struct S : I1 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1").WithArguments("ref struct interfaces").WithLocation(24, 23) + ); + + comp2 = CreateCompilation(text2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(text2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + + [Fact] + public void ObjectCreation_LanguageVersion_07() + { + var text1 = @" +public ref struct C + where T : I1, allows ref struct +{ + public T PT => throw null; +} + +public interface I1 : System.Collections.IEnumerable + where T : I1, allows ref struct +{ + public void Add(int x); + abstract static T Create(); +} +"; + var comp1 = CreateCompilation(text1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + + var text2 = @" +class Program +{ + static C Test() + where T : I1, allows ref struct + { + return new C() { PT = { 100, 20, 3 } }; + } +} +"; + + var comp2 = CreateCompilation(text2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (4,17): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static C Test() + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Test").WithArguments("ref struct interfaces").WithLocation(4, 17), + // (4,22): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static C Test() + Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("ref struct interfaces").WithLocation(4, 22), + // (5,33): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // where T : I1, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(5, 33), + // (7,22): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // return new C() { PT = { 100, 20, 3 } }; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "T").WithArguments("ref struct interfaces").WithLocation(7, 22) + ); + + comp2 = CreateCompilation(text2 + text1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); + comp2.VerifyEmitDiagnostics( + // (5,33): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // where T : I1, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(5, 33), + // (12,29): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // where T : I1, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(12, 29), + // (18,29): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // where T : I1, allows ref struct + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ref struct").WithArguments("ref struct interfaces").WithLocation(18, 29) + ); + + comp2 = CreateCompilation(text2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2.VerifyEmitDiagnostics(); + + comp2 = CreateCompilation(text2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp2.VerifyEmitDiagnostics(); + } + [Theory] [CombinatorialData] public void CollectionExpressions_01(bool addStructConstraint) From 94537aae6da5beb146516dd8e1821fe0ab217fc4 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Fri, 17 May 2024 13:05:01 -0700 Subject: [PATCH 2/2] Disable some tests --- src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs index 206f9a273aeb6..b3e050f871b01 100644 --- a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs @@ -13333,7 +13333,8 @@ static async Task Main() ); } - [Fact] + [ConditionalFact(typeof(NoUsedAssembliesValidation))] // https://github.com/dotnet/roslyn/issues/73563 + [WorkItem("https://github.com/dotnet/roslyn/issues/73563")] public void AwaitUsing_LanguageVersion_01() { var src1 = @" @@ -15712,7 +15713,8 @@ .locals init (int V_0, AssertEx.Equal("System.Int32", op.Info.ElementType.ToTestDisplayString()); } - [Fact] + [ConditionalFact(typeof(NoUsedAssembliesValidation))] // https://github.com/dotnet/roslyn/issues/73563 + [WorkItem("https://github.com/dotnet/roslyn/issues/73563")] public void AwaitForeach_IAsyncEnumerableT_LanguageVersion_01() { var src1 = @"