From 54586cd649650d77c9b86575585f3a400fb05c25 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Fri, 27 May 2022 13:37:43 -0700 Subject: [PATCH] Change natural type of UTF-8 string literals to `ReadOnlySpan` and null terminate the underlying blob. (#61532) https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-18.md#natural-type-of-utf8-literals https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-18.md#should-utf8-literals-be-null-terminated Related to #61517 Closes #60644 --- .../Compiler Breaking Changes - DotNet 7.md | 53 - .../UseUTF8StringLiteralDiagnosticAnalyzer.cs | 3 +- .../UseUTF8StringLiteralTests.cs | 64 +- .../Portable/Binder/Binder.ValueChecks.cs | 2 + .../Portable/Binder/Binder_Expressions.cs | 2 +- .../CSharp/Portable/CSharpResources.resx | 3 - .../Portable/CodeGen/EmitArrayInitializer.cs | 48 +- .../CSharp/Portable/CodeGen/EmitExpression.cs | 31 +- .../CSharp/Portable/Errors/ErrorCode.cs | 3 +- .../DiagnosticsPass_ExpressionTrees.cs | 10 - .../LocalRewriter/LocalRewriter_Conversion.cs | 84 +- .../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 - .../IOperationTests_IUTF8StringOperation.cs | 16 +- .../Semantics/Utf8StringsLiteralsTests.cs | 1233 ++++++++++------- .../Symbol/Symbols/MissingSpecialMember.cs | 1 + .../Test/Syntax/Parsing/CrefParsingTests.cs | 16 +- .../Parsing/MemberDeclarationParsingTests.cs | 6 +- .../Core/Portable/WellKnownMember.cs | 1 + .../Core/Portable/WellKnownMembers.cs | 11 + .../WellKnownTypeValidationTests.vb | 2 + ...nvertToFileScopedNamespaceAnalyzerTests.cs | 9 +- .../QuickInfo/SemanticQuickInfoSourceTests.cs | 38 +- .../ExpressionCompilerTests.cs | 17 +- 35 files changed, 998 insertions(+), 720 deletions(-) diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md index e4a592fca6c1f..5b85be93d498a 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md @@ -97,59 +97,6 @@ A possible workaround is to switch to using `>>>` operator: static C1 Test1(C1 x, int y) => x >>> y; ``` -## UTF8 String Literal conversion - -***Introduced in .NET SDK 6.0.400, Visual Studio 2022 version 17.3.*** -The language added conversions between `string` constants and `byte` sequences -where the text is converted into the equivalent UTF8 byte representation. -Specifically the compiler allowed an implicit conversions from **`string` constants** -to `byte[]`, `Span`, and `ReadOnlySpan` types. - -The conversions can lead to an overload resolution failure due to an ambiguity for a code -that compiled successfully before. For example: -``` C# -Test("s"); // error CS0121: The call is ambiguous between the following methods or properties: 'C.Test(ReadOnlySpan)' and 'C.Test(byte[])' - -static string Test(ReadOnlySpan a) => "ReadOnlySpan"; -static string Test(byte[] a) => "array"; -``` - -A possible workaround is to apply an explicit cast to the constant string argument. - -The conversions can lead to an invocation of a different member. For example: -``` C# -Test("s", (int)1); // Used to call `Test(ReadOnlySpan a, long x)`, but calls `Test(byte[] a, int x)` now - -static string Test(ReadOnlySpan a, long x) => "ReadOnlySpan"; -static string Test(byte[] a, int x) => "array"; -``` - -A possible workaround is to apply an explicit cast to the constant string argument. - -The conversions can lead to an invocation of an instance member where an extension method used to be invoked. -For example: -``` C# -class Program -{ - static void Main() - { - var p = new Program(); - p.M(""); // Used to call E.M, but calls Program.M now - } - - public string M(byte[] b) => "byte[]"; -} - -static class E -{ - public static string M(this object o, string s) => "string"; -} -``` - -Possible workarounds are: -1. Apply an explicit cast to the constant string argument. -2. Call the extension method by using static method invocation syntax. - ## Foreach enumerator as a ref struct ***Introduced in .NET SDK 6.0.300, Visual Studio 2022 version 17.2.*** A `foreach` using a ref struct enumerator type reports an error if the language version is set to 7.3 or earlier. diff --git a/src/Analyzers/CSharp/Analyzers/UseUTF8StringLiteral/UseUTF8StringLiteralDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseUTF8StringLiteral/UseUTF8StringLiteralDiagnosticAnalyzer.cs index af6d671787255..8f20d28c3b174 100644 --- a/src/Analyzers/CSharp/Analyzers/UseUTF8StringLiteral/UseUTF8StringLiteralDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseUTF8StringLiteral/UseUTF8StringLiteralDiagnosticAnalyzer.cs @@ -51,7 +51,8 @@ protected override void InitializeWorker(AnalysisContext context) var expressionType = context.Compilation.GetTypeByMetadataName(typeof(System.Linq.Expressions.Expression<>).FullName!); - context.RegisterOperationAction(c => AnalyzeOperation(c, expressionType), OperationKind.ArrayCreation); + // Temporarily disabling, https://github.com/dotnet/roslyn/issues/61517 tracks the follow up work + // context.RegisterOperationAction(c => AnalyzeOperation(c, expressionType), OperationKind.ArrayCreation); }); private void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol? expressionType) diff --git a/src/Analyzers/CSharp/Tests/UseUTF8StringLiteral/UseUTF8StringLiteralTests.cs b/src/Analyzers/CSharp/Tests/UseUTF8StringLiteral/UseUTF8StringLiteralTests.cs index 191a6c7eea3fc..7939d4cdb3dba 100644 --- a/src/Analyzers/CSharp/Tests/UseUTF8StringLiteral/UseUTF8StringLiteralTests.cs +++ b/src/Analyzers/CSharp/Tests/UseUTF8StringLiteral/UseUTF8StringLiteralTests.cs @@ -183,7 +183,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestSimpleByteArray() { await new VerifyCS.Test @@ -211,7 +211,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestConstant() { await new VerifyCS.Test @@ -241,7 +241,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestImplicitArray() { await new VerifyCS.Test @@ -269,7 +269,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestExplicitCast() { await new VerifyCS.Test @@ -297,7 +297,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestHexLiteral() { await new VerifyCS.Test @@ -325,7 +325,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestBinaryExpression() { await new VerifyCS.Test @@ -353,7 +353,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestEmptyArray() { await new VerifyCS.Test @@ -380,7 +380,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestTrivia1() { await new VerifyCS.Test @@ -408,7 +408,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestTrivia2() { await new VerifyCS.Test @@ -436,7 +436,7 @@ public void M(byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestMultiple() { await new VerifyCS.Test @@ -468,7 +468,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestEscapeChars() { await new VerifyCS.Test @@ -496,7 +496,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestEmoji() { await new VerifyCS.Test @@ -581,7 +581,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestUnicodeReplacementChar() { // The unicode replacement character is what is returned when, for example, an unpaired @@ -612,7 +612,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestCollectionInitializer() { await new VerifyCS.Test @@ -716,7 +716,7 @@ public void Dispose(int a = 1, bool b = true, params byte[] others) { } }.RunAsync(); } - [Theory, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Theory(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] // Various cases copied from https://github.com/dotnet/runtime/blob/main/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs [InlineData(new byte[] { 0x37, 0x02, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x65 }, "7translate")] [InlineData(new byte[] { 0x3f, 0x01 }, "?")] @@ -782,7 +782,7 @@ public class C Assert.NotEqual(bytes, newBytes); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray1() { await new VerifyCS.Test @@ -812,7 +812,7 @@ public void M(params byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray2() { await new VerifyCS.Test @@ -842,7 +842,7 @@ public void M(int i, params byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray3() { await new VerifyCS.Test @@ -872,7 +872,7 @@ public void M(params byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray4() { await new VerifyCS.Test @@ -902,7 +902,7 @@ public void M(params byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray5() { await new VerifyCS.Test @@ -932,7 +932,7 @@ public void M(params byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray6() { await new VerifyCS.Test @@ -981,7 +981,7 @@ public void M(int x, params byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray8() { await new VerifyCS.Test @@ -1011,7 +1011,7 @@ public void M(int x, params byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray9() { await new VerifyCS.Test @@ -1041,7 +1041,7 @@ public void M(int x, params byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray10() { await new VerifyCS.Test @@ -1071,7 +1071,7 @@ public void M(int x, params byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray11() { await new VerifyCS.Test @@ -1101,7 +1101,7 @@ public void M(int x, int y, int z, params byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray12() { await new VerifyCS.Test @@ -1131,7 +1131,7 @@ public C(params byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray13() { await new VerifyCS.Test @@ -1171,7 +1171,7 @@ public void M() }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray14() { await new VerifyCS.Test @@ -1225,7 +1225,7 @@ public sealed class IsExternalInit }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray15() { await new VerifyCS.Test @@ -1313,7 +1313,7 @@ public B(params byte[] bytes) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray16() { await new VerifyCS.Test @@ -1343,7 +1343,7 @@ public void M(int[] i, byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestParamArray17() { await new VerifyCS.Test @@ -1373,7 +1373,7 @@ public void M(int[] i, params byte[] b) }.RunAsync(); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/61517"), Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] public async Task TestMultidimensionalArray() { await new VerifyCS.Test diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index c95023e5083e5..255c0e02626d4 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -2613,6 +2613,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin case BoundKind.DefaultExpression: case BoundKind.Parameter: case BoundKind.ThisReference: + case BoundKind.UTF8String: // always returnable return Binder.ExternalScope; @@ -3018,6 +3019,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint case BoundKind.DefaultExpression: case BoundKind.Parameter: case BoundKind.ThisReference: + case BoundKind.UTF8String: // always returnable return true; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 412df29aee462..b68da7a2b9efd 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -5925,7 +5925,7 @@ private BoundUTF8String BindUTF8StringLiteral(LiteralExpressionSyntax node, Bind CheckFeatureAvailability(node, MessageID.IDS_FeatureUTF8StringLiterals, diagnostics); var value = (string)node.Token.Value; - var type = ArrayTypeSymbol.CreateSZArray(Compilation.Assembly, TypeWithAnnotations.Create(GetSpecialType(SpecialType.System_Byte, diagnostics, node))); + var type = GetWellKnownType(WellKnownType.System_ReadOnlySpan_T, diagnostics, node).Construct(GetSpecialType(SpecialType.System_Byte, diagnostics, node)); return new BoundUTF8String(node, value, type); } diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index caa77fc0a017f..248035e54030b 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7061,9 +7061,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ UTF-8 string literals - - An expression tree may not contain UTF-8 string conversion or literal. - unsigned right shift diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs index fec1322080119..13d42decd09a6 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs @@ -370,18 +370,21 @@ private static bool IsMultidimensionalInitializer(ImmutableArray data = default; int elementCount = -1; - TypeSymbol elementType = null; if (!_module.SupportsPrivateImplClass) { return false; } - var ctor = ((MethodSymbol)this._module.Compilation.GetWellKnownTypeMember(WellKnownMember.System_ReadOnlySpan_T__ctor_Pointer)); + var ctor = ((MethodSymbol?)this._module.Compilation.GetWellKnownTypeMember(WellKnownMember.System_ReadOnlySpan_T__ctor_Pointer)); if (ctor == null) { return false; @@ -390,7 +393,7 @@ private bool TryEmitReadonlySpanAsBlobWrapper(NamedTypeSymbol spanType, BoundExp if (wrappedExpression is BoundArrayCreation ac) { var arrayType = (ArrayTypeSymbol)ac.Type; - elementType = arrayType.ElementType.EnumUnderlyingTypeOrSelf(); + TypeSymbol elementType = arrayType.ElementType.EnumUnderlyingTypeOrSelf(); // NB: we cannot use this approach for element types larger than one byte // the issue is that metadata stores blobs in little-endian format @@ -410,6 +413,39 @@ private bool TryEmitReadonlySpanAsBlobWrapper(NamedTypeSymbol spanType, BoundExp return false; } + if (start is null != length is null) + { + return false; + } + + int lengthForConstructor; + + if (start is not null) + { + if (start.ConstantValue?.IsDefaultValue != true || start.ConstantValue.Discriminator != ConstantValueTypeDiscriminator.Int32) + { + return false; + } + + Debug.Assert(length is not null); + + if (length.ConstantValue?.Discriminator != ConstantValueTypeDiscriminator.Int32) + { + return false; + } + + lengthForConstructor = length.ConstantValue.Int32Value; + + if (lengthForConstructor > elementCount || lengthForConstructor < 0) + { + return false; + } + } + else + { + lengthForConstructor = elementCount; + } + if (!inPlace && !used) { // emitting a value that no one will see @@ -436,7 +472,7 @@ private bool TryEmitReadonlySpanAsBlobWrapper(NamedTypeSymbol spanType, BoundExp } _builder.EmitArrayBlockFieldRef(data, wrappedExpression.Syntax, _diagnostics); - _builder.EmitIntConstant(elementCount); + _builder.EmitIntConstant(lengthForConstructor); if (inPlace) { @@ -455,6 +491,8 @@ private bool TryEmitReadonlySpanAsBlobWrapper(NamedTypeSymbol spanType, BoundExp return true; } +#nullable disable + /// /// Returns a byte blob that matches serialized content of single array initializer. /// returns -1 if the initializer is null or not an array of literals diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index f56738485d80c..b729969d195ad 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -1979,13 +1979,9 @@ private void EmitObjectCreationExpression(BoundObjectCreationExpression expressi } // ReadOnlySpan may just refer to the blob, if possible. - if (this._module.Compilation.IsReadOnlySpanType(expression.Type) && - expression.Arguments.Length == 1) + if (TryEmitReadonlySpanAsBlobWrapper(expression, used, inPlace: false)) { - if (TryEmitReadonlySpanAsBlobWrapper((NamedTypeSymbol)expression.Type, expression.Arguments[0], used, inPlace: false)) - { - return; - } + return; } // none of the above cases, so just create an instance @@ -2002,6 +1998,18 @@ private void EmitObjectCreationExpression(BoundObjectCreationExpression expressi } } + private bool TryEmitReadonlySpanAsBlobWrapper(BoundObjectCreationExpression expression, bool used, bool inPlace) + { + int argumentsLength = expression.Arguments.Length; + return ((argumentsLength == 1 && + expression.Constructor.OriginalDefinition == (object)this._module.Compilation.GetWellKnownTypeMember(WellKnownMember.System_ReadOnlySpan_T__ctor_Array)) || + (argumentsLength == 3 && + expression.Constructor.OriginalDefinition == (object)this._module.Compilation.GetWellKnownTypeMember(WellKnownMember.System_ReadOnlySpan_T__ctor_Array_Start_Length))) && + TryEmitReadonlySpanAsBlobWrapper((NamedTypeSymbol)expression.Type, expression.Arguments[0], used, inPlace, + start: argumentsLength == 3 ? expression.Arguments[1] : null, + length: argumentsLength == 3 ? expression.Arguments[2] : null); + } + /// /// Recognizes constructors known to not have side-effects (which means they can be skipped unless the constructed object is used) /// @@ -2222,16 +2230,13 @@ private void InPlaceCtorCall(BoundExpression target, BoundObjectCreationExpressi Debug.Assert(temp == null, "in-place ctor target should not create temps"); // ReadOnlySpan may just refer to the blob, if possible. - if (this._module.Compilation.IsReadOnlySpanType(objCreation.Type) && objCreation.Arguments.Length == 1) + if (TryEmitReadonlySpanAsBlobWrapper(objCreation, used, inPlace: true)) { - if (TryEmitReadonlySpanAsBlobWrapper((NamedTypeSymbol)objCreation.Type, objCreation.Arguments[0], used, inPlace: true)) + if (used) { - if (used) - { - EmitExpression(target, used: true); - } - return; + EmitExpression(target, used: true); } + return; } var constructor = objCreation.Constructor; diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index df2c38f2554bd..78c6adef4601a 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2070,8 +2070,7 @@ internal enum ErrorCode ERR_CheckedOperatorNeedsMatch = 9025, ERR_CannotBeConvertedToUTF8 = 9026, - ERR_ExpressionTreeContainsUTF8StringLiterals = 9027, - ERR_MisplacedUnchecked = 9028, + ERR_MisplacedUnchecked = 9027, #endregion diff --git a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs index a9c259b6ab9b0..b8cc36c53c381 100644 --- a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs +++ b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs @@ -776,16 +776,6 @@ public override BoundNode VisitConversion(BoundConversion node) return result; } - public override BoundNode VisitUTF8String(BoundUTF8String node) - { - if (_inExpressionLambda) - { - Error(ErrorCode.ERR_ExpressionTreeContainsUTF8StringLiterals, node); - } - - return null; - } - public override BoundNode VisitDelegateCreationExpression(BoundDelegateCreationExpression node) { if (node.Argument.Kind != BoundKind.MethodGroup) diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs index 1f2e6c8c864f2..2b9e9f89da43c 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs @@ -73,45 +73,73 @@ public override BoundNode VisitConversion(BoundConversion node) return result; } - private BoundExpression CreateUTF8ByteRepresentation(SyntaxNode resultSyntax, SyntaxNode valueSyntax, string value, ArrayTypeSymbol byteArray) + public override BoundNode VisitUTF8String(BoundUTF8String node) { - Debug.Assert(byteArray.IsSZArray); - Debug.Assert(byteArray.ElementType.SpecialType == SpecialType.System_Byte); + Debug.Assert(node.Type.OriginalDefinition.Equals(_compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T), TypeCompareKind.AllIgnoreOptions)); + var byteType = ((NamedTypeSymbol)node.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics.Single().Type; + Debug.Assert(byteType.SpecialType == SpecialType.System_Byte); + + var save_Syntax = _factory.Syntax; + _factory.Syntax = node.Syntax; - var utf8 = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); - byte[] bytes; + int length; + BoundExpression utf8Bytes = createUTF8ByteRepresentation(node.Syntax, node.Value, ArrayTypeSymbol.CreateSZArray(_compilation.Assembly, TypeWithAnnotations.Create(byteType)), out length); + BoundNode result; - try + if (!TryGetWellKnownTypeMember(node.Syntax, WellKnownMember.System_ReadOnlySpan_T__ctor_Array_Start_Length, out MethodSymbol ctor)) { - bytes = utf8.GetBytes(value); + result = BadExpression(node.Syntax, node.Type, ImmutableArray.Empty); } - catch (Exception ex) + else { - _diagnostics.Add( - ErrorCode.ERR_CannotBeConvertedToUTF8, - valueSyntax.Location, - ex.Message); - - return BadExpression(resultSyntax, byteArray, ImmutableArray.Empty); + result = new BoundObjectCreationExpression(node.Syntax, ctor.AsMember((NamedTypeSymbol)node.Type), utf8Bytes, _factory.Literal(0), _factory.Literal(length)); } - var builder = ArrayBuilder.GetInstance(bytes.Length); - foreach (byte b in bytes) + _factory.Syntax = save_Syntax; + + return result; + + BoundExpression createUTF8ByteRepresentation(SyntaxNode syntax, string value, ArrayTypeSymbol byteArray, out int length) { - builder.Add(_factory.Literal(b)); - } + Debug.Assert(byteArray.IsSZArray); + Debug.Assert(byteArray.ElementType.SpecialType == SpecialType.System_Byte); - var utf8Bytes = new BoundArrayCreation( - resultSyntax, - ImmutableArray.Create(_factory.Literal(builder.Count)), - new BoundArrayInitialization(resultSyntax, isInferred: false, builder.ToImmutableAndFree()), - byteArray); - return utf8Bytes; - } + var utf8 = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); + byte[] bytes; - public override BoundNode VisitUTF8String(BoundUTF8String node) - { - return CreateUTF8ByteRepresentation(node.Syntax, node.Syntax, node.Value, (ArrayTypeSymbol)node.Type); + try + { + bytes = utf8.GetBytes(value); + } + catch (Exception ex) + { + _diagnostics.Add( + ErrorCode.ERR_CannotBeConvertedToUTF8, + syntax.Location, + ex.Message); + + length = 0; + return BadExpression(syntax, byteArray, ImmutableArray.Empty); + } + + var builder = ArrayBuilder.GetInstance(bytes.Length); + foreach (byte b in bytes) + { + builder.Add(_factory.Literal(b)); + } + + length = builder.Count; + + // Zero terminate memory + builder.Add(_factory.Literal((byte)0)); + + var utf8Bytes = new BoundArrayCreation( + syntax, + ImmutableArray.Create(_factory.Literal(builder.Count)), + new BoundArrayInitialization(syntax, isInferred: false, builder.ToImmutableAndFree()), + byteArray); + return utf8Bytes; + } } private static bool IsFloatingPointExpressionOfUnknownPrecision(BoundExpression rewrittenNode) diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index ba3b15d1f0abf..54d74682e7041 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -497,11 +497,6 @@ Strom výrazů nesmí obsahovat operátor řazené kolekce členů == nebo !=. - - An expression tree may not contain UTF-8 string conversion or literal. - An expression tree may not contain UTF-8 string conversion or literal. - - An expression tree may not contain a with-expression. Strom výrazů nesmí obsahovat výraz with. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 79f910715ca36..ce8ae626726a1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -497,11 +497,6 @@ Eine Ausdrucksbaumstruktur darf keinen ==- oder !=-Tupeloperator enthalten. - - An expression tree may not contain UTF-8 string conversion or literal. - An expression tree may not contain UTF-8 string conversion or literal. - - An expression tree may not contain a with-expression. Eine Ausdrucksbaumstruktur darf keinen with-Ausdruck enthalten. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 170e388434109..ec1b16f021635 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -497,11 +497,6 @@ Un árbol de expresión no puede contener un operador de tupla == o !=. - - An expression tree may not contain UTF-8 string conversion or literal. - An expression tree may not contain UTF-8 string conversion or literal. - - An expression tree may not contain a with-expression. Un árbol de expresión no puede contener una expresión with. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 4a8e541e1e0b3..09530006516cc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -497,11 +497,6 @@ Une arborescence de l'expression ne peut pas contenir un opérateur de tuple == ou != - - An expression tree may not contain UTF-8 string conversion or literal. - An expression tree may not contain UTF-8 string conversion or literal. - - An expression tree may not contain a with-expression. Une arborescence de l'expression ne peut pas contenir d'expression with. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 962c50450508f..cdc9bd83aa9fd 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -497,11 +497,6 @@ Un albero delle espressioni non può contenere un operatore == o != di tupla - - An expression tree may not contain UTF-8 string conversion or literal. - An expression tree may not contain UTF-8 string conversion or literal. - - An expression tree may not contain a with-expression. Un albero delle espressioni non può contenere un'espressione with. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 6066e2340e25e..b9b2570f68a9a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -497,11 +497,6 @@ 式ツリーにタプルの == または != 演算子を含めることはできません - - An expression tree may not contain UTF-8 string conversion or literal. - An expression tree may not contain UTF-8 string conversion or literal. - - An expression tree may not contain a with-expression. 式ツリーは、with 式を含むことはできません diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 24abdf7ca6355..b2c3ae161e9fa 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -497,11 +497,6 @@ 식 트리에는 튜플 == 또는 != 연산자를 사용할 수 없습니다. - - An expression tree may not contain UTF-8 string conversion or literal. - An expression tree may not contain UTF-8 string conversion or literal. - - An expression tree may not contain a with-expression. 식 트리에는 with 식이 포함될 수 없습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 47ffe4dcddf50..612db1badd628 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -497,11 +497,6 @@ Drzewo wyrażenia nie może zawierać operatora == ani != krotki. - - An expression tree may not contain UTF-8 string conversion or literal. - An expression tree may not contain UTF-8 string conversion or literal. - - An expression tree may not contain a with-expression. Drzewo wyrażeń nie może zawierać wyrażenia with. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index ce816956b7222..7a187e14bbad4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -497,11 +497,6 @@ Uma árvore de expressão não pode conter um operador == ou != de tupla - - An expression tree may not contain UTF-8 string conversion or literal. - An expression tree may not contain UTF-8 string conversion or literal. - - An expression tree may not contain a with-expression. Uma árvore de expressão não pode conter uma expressão with. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 49f7e2c6dbfd8..859b291ef2d94 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -497,11 +497,6 @@ Дерево выражений не может содержать оператор == или != кортежа. - - An expression tree may not contain UTF-8 string conversion or literal. - An expression tree may not contain UTF-8 string conversion or literal. - - An expression tree may not contain a with-expression. Дерево выражения не может содержать выражение with. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 0e0a1c7cfc5ff..8f7d57c2c3f19 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -497,11 +497,6 @@ İfade ağacı, demetin == veya != işlecini içeremez. - - An expression tree may not contain UTF-8 string conversion or literal. - An expression tree may not contain UTF-8 string conversion or literal. - - An expression tree may not contain a with-expression. İfade ağacı, with ifadesi içeremez. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index bdd02c1d59861..745b87bac8d45 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -497,11 +497,6 @@ 表达式树不能包含元组 == 或 != 运算符 - - An expression tree may not contain UTF-8 string conversion or literal. - An expression tree may not contain UTF-8 string conversion or literal. - - An expression tree may not contain a with-expression. 表达式树不能包含 with 表达式。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index c27e2f804129f..1e48c3c1d7af0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -497,11 +497,6 @@ 運算式樹狀架構不得包含元組 == 或 != 運算子 - - An expression tree may not contain UTF-8 string conversion or literal. - An expression tree may not contain UTF-8 string conversion or literal. - - An expression tree may not contain a with-expression. 運算式樹狀架構不得包含 with 運算式。 diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IUTF8StringOperation.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IUTF8StringOperation.cs index a8c6d54096f8e..0b2351ccf5952 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IUTF8StringOperation.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IUTF8StringOperation.cs @@ -20,7 +20,7 @@ public void UTF8String_01() string source = @" class Program { - static byte[] Test() + static System.ReadOnlySpan Test() { /**/return ""Abc""u8;/**/ } @@ -29,11 +29,11 @@ static byte[] Test() string expectedOperationTree = @" IReturnOperation (OperationKind.Return, Type: null) (Syntax: 'return ""Abc""u8;') ReturnedValue: - IUTF8StringOperation (Abc) (OperationKind.UTF8String, Type: System.Byte[]) (Syntax: '""Abc""u8') + IUTF8StringOperation (Abc) (OperationKind.UTF8String, Type: System.ReadOnlySpan) (Syntax: '""Abc""u8') "; var expectedDiagnostics = DiagnosticDescription.None; - VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics, targetFramework: Roslyn.Test.Utilities.TargetFramework.NetCoreApp); } [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)] @@ -43,7 +43,7 @@ public void UTF8StringFlow_01() string source = @" class C { - void M(byte[] b) + void M(System.ReadOnlySpan b) /**/{ b = ""ABC""u8; }/**/ @@ -60,18 +60,18 @@ void M(byte[] b) Statements (1) IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = ""ABC""u8;') Expression: - ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Byte[]) (Syntax: 'b = ""ABC""u8') + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.ReadOnlySpan) (Syntax: 'b = ""ABC""u8') Left: - IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Byte[]) (Syntax: 'b') + IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.ReadOnlySpan) (Syntax: 'b') Right: - IUTF8StringOperation (ABC) (OperationKind.UTF8String, Type: System.Byte[]) (Syntax: '""ABC""u8') + IUTF8StringOperation (ABC) (OperationKind.UTF8String, Type: System.ReadOnlySpan) (Syntax: '""ABC""u8') Next (Regular) Block[B2] Block[B2] - Exit Predecessors: [B1] Statements (0) "; - VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, expectedDiagnostics); + VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, expectedDiagnostics, targetFramework: Roslyn.Test.Utilities.TargetFramework.NetCoreApp); } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/Utf8StringsLiteralsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/Utf8StringsLiteralsTests.cs index b4958aafd5f75..bdce70e47243c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/Utf8StringsLiteralsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/Utf8StringsLiteralsTests.cs @@ -21,26 +21,6 @@ public class Utf8StringsLiteralsTests : CompilingTestBase private static string HelpersSource => @" class Helpers { - public static void Print(byte[] span) - { - System.Console.Write(""{""); - foreach (var item in span) - { - System.Console.Write("" 0x{0:X}"", item); - } - System.Console.WriteLine("" }""); - } - - public static void Print(Span span) - { - System.Console.Write(""{""); - foreach (var item in span) - { - System.Console.Write("" 0x{0:X}"", item); - } - System.Console.WriteLine("" }""); - } - public static void Print(ReadOnlySpan span) { System.Console.Write(""{""); @@ -53,7 +33,7 @@ public static void Print(ReadOnlySpan span) } "; - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void ImplicitConversions_01() { var source = @" @@ -83,7 +63,7 @@ static void Main() ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void ImplicitConversions_TupleLiteral_01() { var source = @" @@ -108,7 +88,7 @@ static void Main() ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void ImplicitConversions_Deconstruction_01() { var source = @" @@ -132,7 +112,7 @@ static void Main() ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void ExplicitConversions_01() { var source = @" @@ -162,7 +142,7 @@ static void Main() ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void ExplicitConversions_TupleLiteral_01() { var source = @" @@ -281,7 +261,7 @@ .maxstack 1 ", verify: Verification.Fails).VerifyDiagnostics(); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void NoConversionFromType_01() { var source = @" @@ -312,7 +292,7 @@ static void Main() ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void NoConversionFromType_02() { var source = @" @@ -343,7 +323,7 @@ static void Main() ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void InvalidTargetType_01() { var source = @" @@ -593,7 +573,7 @@ public ReadOnlySpan(T[] arr) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedImplicitConversions_01() { var source = @" @@ -646,7 +626,7 @@ public static implicit operator C3(ReadOnlySpan x) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedImplicitConversions_TupleLiteral_01() { var source = @" @@ -698,7 +678,7 @@ public static implicit operator C3(ReadOnlySpan x) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedImplicitConversions_Deconstruction_01() { var source = @" @@ -749,7 +729,7 @@ public static implicit operator C3(ReadOnlySpan x) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedImplicitConversions_02() { var source = @" @@ -807,7 +787,7 @@ public static implicit operator C3(ReadOnlySpan x) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedImplicitConversions_TupleLiteral_02() { var source = @" @@ -863,7 +843,7 @@ public static implicit operator C3(ReadOnlySpan x) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedExplicitConversions_01() { var source = @" @@ -921,7 +901,7 @@ public static explicit operator C3(ReadOnlySpan x) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedExplicitConversions_TupleLiteral_01() { var source = @" @@ -977,7 +957,7 @@ public static explicit operator C3(ReadOnlySpan x) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedExplicitConversions_02() { var source = @" @@ -1030,7 +1010,7 @@ public static explicit operator C3(ReadOnlySpan x) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedExplicitConversions_TupleLiteral_02() { var source = @" @@ -1082,7 +1062,7 @@ public static explicit operator C3(ReadOnlySpan x) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedExplicitConversions_Deconstruction_02() { var source = @" @@ -1133,7 +1113,7 @@ public static explicit operator C3(ReadOnlySpan x) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void ExpressionTree_02() { var source = @" @@ -1202,7 +1182,7 @@ class C { static void Main() { - Expression> x = () => ""hello""u8; + Expression> x = () => ""hello""u8.ToArray(); System.Console.WriteLine(x); } } @@ -1210,9 +1190,9 @@ static void Main() var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); comp.VerifyDiagnostics( - // (8,44): error CS9101: An expression tree may not contain UTF8 string conversion or literal. - // Expression> x = () => "hello"u8; - Diagnostic(ErrorCode.ERR_ExpressionTreeContainsUTF8StringLiterals, @"""hello""u8").WithLocation(8, 44) + // (8,44): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'ReadOnlySpan'. + // Expression> x = () => "hello"u8.ToArray(); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, @"""hello""u8").WithArguments("ReadOnlySpan").WithLocation(8, 44) ); } @@ -1229,16 +1209,17 @@ static void Main() System.Console.Write(Test(""s""u8)); } - static string Test(ReadOnlySpan a) => ""ReadOnlySpan""; + static string Test(ReadOnlySpan a) => ""ReadOnlySpan""; static string Test(byte[] a) => ""array""; + static string Test(ReadOnlySpan a) => ""ReadOnlySpan""; } "; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: @"ReadOnlySpanarray").VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: @"ReadOnlySpanReadOnlySpan", verify: Verification.Fails).VerifyDiagnostics(); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void OverloadResolution_02() { var source = @" @@ -1257,7 +1238,11 @@ static void Main() "; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: @"ReadOnlySpanarray").VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (8,35): error CS1503: Argument 1: cannot convert from 'System.ReadOnlySpan' to 'byte[]' + // System.Console.Write(Test("s"u8)); + Diagnostic(ErrorCode.ERR_BadArgType, @"""s""u8").WithArguments("1", "System.ReadOnlySpan", "byte[]").WithLocation(8, 35) + ); } [ConditionalFact(typeof(CoreClrOnly))] @@ -1317,7 +1302,7 @@ static void Main() CompileAndVerify(comp, expectedOutput: @"ReadOnlySpan").VerifyDiagnostics(); comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: @"ReadOnlySpan").VerifyDiagnostics(); } [ConditionalFact(typeof(CoreClrOnly))] @@ -1379,11 +1364,10 @@ static class E } "; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: @"string"). - VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: @"string").VerifyDiagnostics(); comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: @"string").VerifyDiagnostics(); } [Fact] @@ -1416,56 +1400,27 @@ class C static void Main() { System.Console.WriteLine(); - Helpers.Print(Test1()); - Helpers.Print(Test2()); Helpers.Print(Test3()); } - static byte[] Test1() => ""hello""" + suffix + @"; - static Span Test2() => ""dog""" + suffix + @"; + + + + static ReadOnlySpan Test3() => ""cat""" + suffix + @"; } "; var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); var verifier = CompileAndVerify(comp, expectedOutput: @" -{ 0x68 0x65 0x6C 0x6C 0x6F } -{ 0x64 0x6F 0x67 } { 0x63 0x61 0x74 } ", verify: Verification.Fails).VerifyDiagnostics(); - verifier.VerifyIL("C.Test1()", @" -{ - // Code size 18 (0x12) - .maxstack 3 - IL_0000: ldc.i4.5 - IL_0001: newarr ""byte"" - IL_0006: dup - IL_0007: ldtoken "".__StaticArrayInitTypeSize=5 .2CF24DBA5FB0A30E26E83B2AC5B9E29E1B161E5C1FA7425E73043362938B9824"" - IL_000c: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0011: ret -} -"); - - verifier.VerifyIL("C.Test2()", @" -{ - // Code size 23 (0x17) - .maxstack 3 - IL_0000: ldc.i4.3 - IL_0001: newarr ""byte"" - IL_0006: dup - IL_0007: ldtoken "".__StaticArrayInitTypeSize=3 .CD6357EFDD966DE8C0CB2F876CC89EC74CE35F0968E11743987084BD42FB8944"" - IL_000c: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0011: call ""System.Span System.Span.op_Implicit(byte[])"" - IL_0016: ret -} -"); - verifier.VerifyIL("C.Test3()", @" { // Code size 12 (0xc) .maxstack 2 - IL_0000: ldsflda "".__StaticArrayInitTypeSize=3 .77AF778B51ABD4A3C51C5DDD97204A9C3AE614EBCCB75A606C3B6865AED6744E"" + IL_0000: ldsflda ""int .F3D4280708A6C4BEA1BAEB5AD5A4B659E705A90BDD448840276EA20CB151BE57"" IL_0005: ldc.i4.3 IL_0006: newobj ""System.ReadOnlySpan..ctor(void*, int)"" IL_000b: ret @@ -1475,19 +1430,11 @@ .maxstack 2 comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); CompileAndVerify(comp, expectedOutput: @" -{ 0x68 0x65 0x6C 0x6C 0x6F } -{ 0x64 0x6F 0x67 } { 0x63 0x61 0x74 } ", verify: Verification.Fails).VerifyDiagnostics(); comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (13,30): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static byte[] Test1() => "hello"u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""hello""" + suffix).WithArguments("UTF-8 string literals").WithLocation(13, 30), - // (14,34): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static Span Test2() => "dog"u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""dog""" + suffix).WithArguments("UTF-8 string literals").WithLocation(14, 34), // (15,42): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => "cat"u8; Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""cat""" + suffix).WithArguments("UTF-8 string literals").WithLocation(15, 42) @@ -1506,56 +1453,27 @@ class C static void Main() { System.Console.WriteLine(); - Helpers.Print(Test1()); - Helpers.Print(Test2()); + + Helpers.Print(Test3()); } - static byte[] Test1() => @""hello""" + suffix + @"; - static Span Test2() => @""dog""" + suffix + @"; + + static ReadOnlySpan Test3() => @""cat""" + suffix + @"; } "; var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); var verifier = CompileAndVerify(comp, expectedOutput: @" -{ 0x68 0x65 0x6C 0x6C 0x6F } -{ 0x64 0x6F 0x67 } { 0x63 0x61 0x74 } ", verify: Verification.Fails).VerifyDiagnostics(); - verifier.VerifyIL("C.Test1()", @" -{ - // Code size 18 (0x12) - .maxstack 3 - IL_0000: ldc.i4.5 - IL_0001: newarr ""byte"" - IL_0006: dup - IL_0007: ldtoken "".__StaticArrayInitTypeSize=5 .2CF24DBA5FB0A30E26E83B2AC5B9E29E1B161E5C1FA7425E73043362938B9824"" - IL_000c: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0011: ret -} -"); - - verifier.VerifyIL("C.Test2()", @" -{ - // Code size 23 (0x17) - .maxstack 3 - IL_0000: ldc.i4.3 - IL_0001: newarr ""byte"" - IL_0006: dup - IL_0007: ldtoken "".__StaticArrayInitTypeSize=3 .CD6357EFDD966DE8C0CB2F876CC89EC74CE35F0968E11743987084BD42FB8944"" - IL_000c: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0011: call ""System.Span System.Span.op_Implicit(byte[])"" - IL_0016: ret -} -"); - verifier.VerifyIL("C.Test3()", @" { // Code size 12 (0xc) .maxstack 2 - IL_0000: ldsflda "".__StaticArrayInitTypeSize=3 .77AF778B51ABD4A3C51C5DDD97204A9C3AE614EBCCB75A606C3B6865AED6744E"" + IL_0000: ldsflda ""int .F3D4280708A6C4BEA1BAEB5AD5A4B659E705A90BDD448840276EA20CB151BE57"" IL_0005: ldc.i4.3 IL_0006: newobj ""System.ReadOnlySpan..ctor(void*, int)"" IL_000b: ret @@ -1565,19 +1483,11 @@ .maxstack 2 comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); CompileAndVerify(comp, expectedOutput: @" -{ 0x68 0x65 0x6C 0x6C 0x6F } -{ 0x64 0x6F 0x67 } { 0x63 0x61 0x74 } ", verify: Verification.Fails).VerifyDiagnostics(); comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (13,30): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static byte[] Test1() => "hello"u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"@""hello""" + suffix).WithArguments("UTF-8 string literals").WithLocation(13, 30), - // (14,34): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static Span Test2() => "dog"u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"@""dog""" + suffix).WithArguments("UTF-8 string literals").WithLocation(14, 34), // (15,42): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => "cat"u8; Diagnostic(ErrorCode.ERR_FeatureInPreview, @"@""cat""" + suffix).WithArguments("UTF-8 string literals").WithLocation(15, 42) @@ -1596,56 +1506,27 @@ class C static void Main() { System.Console.WriteLine(); - Helpers.Print(Test1()); - Helpers.Print(Test2()); + + Helpers.Print(Test3()); } - static byte[] Test1() => """"""hello""""""" + suffix + @"; - static Span Test2() => """"""dog""""""" + suffix + @"; + + static ReadOnlySpan Test3() => """"""cat""""""" + suffix + @"; } "; var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); var verifier = CompileAndVerify(comp, expectedOutput: @" -{ 0x68 0x65 0x6C 0x6C 0x6F } -{ 0x64 0x6F 0x67 } { 0x63 0x61 0x74 } ", verify: Verification.Fails).VerifyDiagnostics(); - verifier.VerifyIL("C.Test1()", @" -{ - // Code size 18 (0x12) - .maxstack 3 - IL_0000: ldc.i4.5 - IL_0001: newarr ""byte"" - IL_0006: dup - IL_0007: ldtoken "".__StaticArrayInitTypeSize=5 .2CF24DBA5FB0A30E26E83B2AC5B9E29E1B161E5C1FA7425E73043362938B9824"" - IL_000c: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0011: ret -} -"); - - verifier.VerifyIL("C.Test2()", @" -{ - // Code size 23 (0x17) - .maxstack 3 - IL_0000: ldc.i4.3 - IL_0001: newarr ""byte"" - IL_0006: dup - IL_0007: ldtoken "".__StaticArrayInitTypeSize=3 .CD6357EFDD966DE8C0CB2F876CC89EC74CE35F0968E11743987084BD42FB8944"" - IL_000c: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0011: call ""System.Span System.Span.op_Implicit(byte[])"" - IL_0016: ret -} -"); - verifier.VerifyIL("C.Test3()", @" { // Code size 12 (0xc) .maxstack 2 - IL_0000: ldsflda "".__StaticArrayInitTypeSize=3 .77AF778B51ABD4A3C51C5DDD97204A9C3AE614EBCCB75A606C3B6865AED6744E"" + IL_0000: ldsflda ""int .F3D4280708A6C4BEA1BAEB5AD5A4B659E705A90BDD448840276EA20CB151BE57"" IL_0005: ldc.i4.3 IL_0006: newobj ""System.ReadOnlySpan..ctor(void*, int)"" IL_000b: ret @@ -1655,25 +1536,11 @@ .maxstack 2 comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); CompileAndVerify(comp, expectedOutput: @" -{ 0x68 0x65 0x6C 0x6C 0x6F } -{ 0x64 0x6F 0x67 } { 0x63 0x61 0x74 } ", verify: Verification.Fails).VerifyDiagnostics(); comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (13,30): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static byte[] Test1() => """hello"""u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""hello""""""" + suffix).WithArguments("raw string literals").WithLocation(13, 30), - // (13,30): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static byte[] Test1() => """hello"""u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""hello""""""" + suffix).WithArguments("UTF-8 string literals").WithLocation(13, 30), - // (14,34): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static Span Test2() => """dog"""u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""dog""""""" + suffix).WithArguments("raw string literals").WithLocation(14, 34), - // (14,34): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static Span Test2() => """dog"""u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""dog""""""" + suffix).WithArguments("UTF-8 string literals").WithLocation(14, 34), // (15,42): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => """cat"""u8; Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""cat""""""" + suffix).WithArguments("raw string literals").WithLocation(15, 42), @@ -1695,17 +1562,17 @@ class C static void Main() { System.Console.WriteLine(); - Helpers.Print(Test1()); - Helpers.Print(Test2()); + + Helpers.Print(Test3()); } - static byte[] Test1() => """""" - hello - """"""" + suffix + @"; - static Span Test2() => """""" - dog - """"""" + suffix + @"; + + + + + + static ReadOnlySpan Test3() => """""" cat """"""" + suffix + @"; @@ -1714,43 +1581,14 @@ static ReadOnlySpan Test3() => """""" var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); var verifier = CompileAndVerify(comp, expectedOutput: @" -{ 0x68 0x65 0x6C 0x6C 0x6F } -{ 0x64 0x6F 0x67 } { 0x63 0x61 0x74 } ", verify: Verification.Fails).VerifyDiagnostics(); - verifier.VerifyIL("C.Test1()", @" -{ - // Code size 18 (0x12) - .maxstack 3 - IL_0000: ldc.i4.5 - IL_0001: newarr ""byte"" - IL_0006: dup - IL_0007: ldtoken "".__StaticArrayInitTypeSize=5 .2CF24DBA5FB0A30E26E83B2AC5B9E29E1B161E5C1FA7425E73043362938B9824"" - IL_000c: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0011: ret -} -"); - - verifier.VerifyIL("C.Test2()", @" -{ - // Code size 23 (0x17) - .maxstack 3 - IL_0000: ldc.i4.3 - IL_0001: newarr ""byte"" - IL_0006: dup - IL_0007: ldtoken "".__StaticArrayInitTypeSize=3 .CD6357EFDD966DE8C0CB2F876CC89EC74CE35F0968E11743987084BD42FB8944"" - IL_000c: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0011: call ""System.Span System.Span.op_Implicit(byte[])"" - IL_0016: ret -} -"); - verifier.VerifyIL("C.Test3()", @" { // Code size 12 (0xc) .maxstack 2 - IL_0000: ldsflda "".__StaticArrayInitTypeSize=3 .77AF778B51ABD4A3C51C5DDD97204A9C3AE614EBCCB75A606C3B6865AED6744E"" + IL_0000: ldsflda ""int .F3D4280708A6C4BEA1BAEB5AD5A4B659E705A90BDD448840276EA20CB151BE57"" IL_0005: ldc.i4.3 IL_0006: newobj ""System.ReadOnlySpan..ctor(void*, int)"" IL_000b: ret @@ -1760,33 +1598,11 @@ .maxstack 2 comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularNext); CompileAndVerify(comp, expectedOutput: @" -{ 0x68 0x65 0x6C 0x6C 0x6F } -{ 0x64 0x6F 0x67 } { 0x63 0x61 0x74 } ", verify: Verification.Fails).VerifyDiagnostics(); comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (13,30): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static byte[] Test1() => """ - Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" - hello - """"""" + suffix).WithArguments("raw string literals").WithLocation(13, 30), - // (13,30): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static byte[] Test1() => """ - Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" - hello - """"""" + suffix).WithArguments("UTF-8 string literals").WithLocation(13, 30), - // (16,34): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static Span Test2() => """ - Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" - dog - """"""" + suffix).WithArguments("raw string literals").WithLocation(16, 34), - // (16,34): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // static Span Test2() => """ - Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" - dog - """"""" + suffix).WithArguments("UTF-8 string literals").WithLocation(16, 34), // (19,42): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => """ Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" @@ -1800,30 +1616,10 @@ .maxstack 2 ); } - [Fact] - public void MissingType_01() - { - var source = @" -using System; -class C -{ - static void Main() - { - _ = ""hello""u8; - } -} -"; - var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); - comp.MakeTypeMissing(SpecialType.System_Byte); - comp.VerifyEmitDiagnostics( - // (7,13): error CS0518: Predefined type 'System.Byte' is not defined or imported - // _ = "hello"u8; - Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"""hello""u8").WithArguments("System.Byte").WithLocation(7, 13) - ); - } - - [ConditionalFact(typeof(CoreClrOnly))] - public void MissingHelpers_07() + [ConditionalTheory(typeof(CoreClrOnly))] + [InlineData("u8")] + [InlineData("U8")] + public void UTF8StringLiteral_01_InPlaceCtorCall(string suffix) { var source = @" using System; @@ -1832,100 +1628,160 @@ class C static void Main() { System.Console.WriteLine(); - Helpers.Print(Test1()); - Helpers.Print(Test2()); Helpers.Print(Test3()); } - static byte[] Test1() => ""hello""u8; - static Span Test2() => ""dog""u8; - static ReadOnlySpan Test3() => ""cat""u8; + static ReadOnlySpan Test3() + { + var x = ""cat""" + suffix + @"; + return x; + } } "; var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); - comp.MakeMemberMissing(WellKnownMember.System_Span_T__ctor_Array); - comp.MakeMemberMissing(WellKnownMember.System_Span_T__ctor_Pointer); - comp.MakeMemberMissing(WellKnownMember.System_ReadOnlySpan_T__ctor_Array); - var verifier = CompileAndVerify(comp, expectedOutput: @" -{ 0x68 0x65 0x6C 0x6C 0x6F } -{ 0x64 0x6F 0x67 } { 0x63 0x61 0x74 } ", verify: Verification.Fails).VerifyDiagnostics(); - verifier.VerifyIL("C.Test1()", @" -{ - // Code size 18 (0x12) - .maxstack 3 - IL_0000: ldc.i4.5 - IL_0001: newarr ""byte"" - IL_0006: dup - IL_0007: ldtoken "".__StaticArrayInitTypeSize=5 .2CF24DBA5FB0A30E26E83B2AC5B9E29E1B161E5C1FA7425E73043362938B9824"" - IL_000c: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0011: ret -} -"); - - verifier.VerifyIL("C.Test2()", @" -{ - // Code size 23 (0x17) - .maxstack 3 - IL_0000: ldc.i4.3 - IL_0001: newarr ""byte"" - IL_0006: dup - IL_0007: ldtoken "".__StaticArrayInitTypeSize=3 .CD6357EFDD966DE8C0CB2F876CC89EC74CE35F0968E11743987084BD42FB8944"" - IL_000c: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0011: call ""System.Span System.Span.op_Implicit(byte[])"" - IL_0016: ret -} -"); - verifier.VerifyIL("C.Test3()", @" { - // Code size 12 (0xc) - .maxstack 2 - IL_0000: ldsflda "".__StaticArrayInitTypeSize=3 .77AF778B51ABD4A3C51C5DDD97204A9C3AE614EBCCB75A606C3B6865AED6744E"" - IL_0005: ldc.i4.3 - IL_0006: newobj ""System.ReadOnlySpan..ctor(void*, int)"" - IL_000b: ret + // Code size 20 (0x14) + .maxstack 3 + .locals init (System.ReadOnlySpan V_0, //x + System.ReadOnlySpan V_1) + IL_0000: nop + IL_0001: ldloca.s V_0 + IL_0003: ldsflda ""int .F3D4280708A6C4BEA1BAEB5AD5A4B659E705A90BDD448840276EA20CB151BE57"" + IL_0008: ldc.i4.3 + IL_0009: call ""System.ReadOnlySpan..ctor(void*, int)"" + IL_000e: ldloc.0 + IL_000f: stloc.1 + IL_0010: br.s IL_0012 + IL_0012: ldloc.1 + IL_0013: ret } "); } - [ConditionalFact(typeof(CoreClrOnly))] - public void MissingHelpers_08() + [Fact] + public void MissingType_01() { var source = @" -using System; + class C { static void Main() { - Helpers.Print(Test2()); + _ = ""hello""u8; } - - static Span Test2() => ""dog""u8; } "; - var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); - comp.MakeMemberMissing(WellKnownMember.System_Span_T__ctor_Pointer); - var verifier = CompileAndVerify(comp, expectedOutput: "{ 0x64 0x6F 0x67 }", verify: Verification.Fails).VerifyDiagnostics(); - - verifier.VerifyIL("C.Test2()", @" -{ - // Code size 23 (0x17) - .maxstack 3 - IL_0000: ldc.i4.3 - IL_0001: newarr ""byte"" - IL_0006: dup - IL_0007: ldtoken "".__StaticArrayInitTypeSize=3 .CD6357EFDD966DE8C0CB2F876CC89EC74CE35F0968E11743987084BD42FB8944"" - IL_000c: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0011: call ""System.Span System.Span.op_Implicit(byte[])"" - IL_0016: ret -} -"); - } + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); + comp.MakeTypeMissing(SpecialType.System_Byte); + comp.VerifyDiagnostics( + // (7,13): error CS0518: Predefined type 'System.Byte' is not defined or imported + // _ = "hello"u8; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"""hello""u8").WithArguments("System.Byte").WithLocation(7, 13) + ); + comp.VerifyEmitDiagnostics( + // (7,13): error CS0518: Predefined type 'System.Byte' is not defined or imported + // _ = "hello"u8; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"""hello""u8").WithArguments("System.Byte").WithLocation(7, 13) + ); + } + + [Fact] + public void MissingType_02() + { + var source = @" + +class C +{ + static void Main() + { + _ = ""hello""u8; + } +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); + comp.MakeTypeMissing(SpecialType.System_Int32); + comp.VerifyDiagnostics(); + comp.VerifyEmitDiagnostics( + // (7,13): error CS0518: Predefined type 'System.Int32' is not defined or imported + // _ = "hello"u8; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"""hello""u8").WithArguments("System.Int32").WithLocation(7, 13), + // (7,13): error CS0518: Predefined type 'System.Int32' is not defined or imported + // _ = "hello"u8; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"""hello""u8").WithArguments("System.Int32").WithLocation(7, 13), + // (7,13): error CS0518: Predefined type 'System.Int32' is not defined or imported + // _ = "hello"u8; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"""hello""u8").WithArguments("System.Int32").WithLocation(7, 13) + ); + } + + [Fact] + public void MissingType_03() + { + var source = @" + +class C +{ + static void Main() + { + _ = ""hello""u8; + } +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); + comp.MakeTypeMissing(WellKnownType.System_ReadOnlySpan_T); + comp.VerifyDiagnostics( + // (7,13): error CS0518: Predefined type 'System.ReadOnlySpan`1' is not defined or imported + // _ = "hello"u8; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"""hello""u8").WithArguments("System.ReadOnlySpan`1").WithLocation(7, 13) + ); + comp.VerifyEmitDiagnostics( + // (7,13): error CS0518: Predefined type 'System.ReadOnlySpan`1' is not defined or imported + // _ = "hello"u8; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, @"""hello""u8").WithArguments("System.ReadOnlySpan`1").WithLocation(7, 13) + ); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void MissingHelpers_07() + { + var source = @" +using System; +class C +{ + static void Main() + { + System.Console.WriteLine(); + Helpers.Print(Test3()); + } + + static ReadOnlySpan Test3() => ""cat""u8; +} +"; + var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); + + comp.MakeMemberMissing(WellKnownMember.System_ReadOnlySpan_T__ctor_Array); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +{ 0x63 0x61 0x74 } +", verify: Verification.Fails).VerifyDiagnostics(); + + verifier.VerifyIL("C.Test3()", @" +{ + // Code size 12 (0xc) + .maxstack 2 + IL_0000: ldsflda ""int .F3D4280708A6C4BEA1BAEB5AD5A4B659E705A90BDD448840276EA20CB151BE57"" + IL_0005: ldc.i4.3 + IL_0006: newobj ""System.ReadOnlySpan..ctor(void*, int)"" + IL_000b: ret +} +"); + } [ConditionalFact(typeof(CoreClrOnly))] public void MissingHelpers_09() @@ -1948,21 +1804,23 @@ static void Main() verifier.VerifyIL("C.Test3()", @" { - // Code size 23 (0x17) + // Code size 25 (0x19) .maxstack 3 - IL_0000: ldc.i4.3 + IL_0000: ldc.i4.4 IL_0001: newarr ""byte"" IL_0006: dup - IL_0007: ldtoken "".__StaticArrayInitTypeSize=3 .77AF778B51ABD4A3C51C5DDD97204A9C3AE614EBCCB75A606C3B6865AED6744E"" + IL_0007: ldtoken ""int .F3D4280708A6C4BEA1BAEB5AD5A4B659E705A90BDD448840276EA20CB151BE57"" IL_000c: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0011: call ""System.ReadOnlySpan System.ReadOnlySpan.op_Implicit(byte[])"" - IL_0016: ret + IL_0011: ldc.i4.0 + IL_0012: ldc.i4.3 + IL_0013: newobj ""System.ReadOnlySpan..ctor(byte[], int, int)"" + IL_0018: ret } "); } - [ConditionalFact(typeof(CoreClrOnly))] - public void OverloadResolution_11() + [Fact] + public void MissingHelpers_10() { var source = @" using System; @@ -1970,19 +1828,27 @@ class C { static void Main() { - System.Console.WriteLine(Test(""s""u8)); + System.Console.WriteLine(); + Helpers.Print(Test3()); } - static string Test(ReadOnlySpan a) => ""ReadOnlySpan""; - static string Test(byte[] a) => ""array""; + static ReadOnlySpan Test3() => ""cat""u8; } "; - var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: @"array").VerifyDiagnostics(); + var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); + + comp.MakeMemberMissing(WellKnownMember.System_ReadOnlySpan_T__ctor_Array_Start_Length); + + comp.VerifyDiagnostics(); + comp.VerifyEmitDiagnostics( + // (11,42): error CS0656: Missing compiler required member 'System.ReadOnlySpan`1..ctor' + // static ReadOnlySpan Test3() => "cat"u8; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, @"""cat""u8").WithArguments("System.ReadOnlySpan`1", ".ctor").WithLocation(11, 42) + ); } [ConditionalFact(typeof(CoreClrOnly))] - public void OverloadResolution_12() + public void OverloadResolution_11() { var source = @" using System; @@ -1993,12 +1859,12 @@ static void Main() System.Console.WriteLine(Test(""s""u8)); } - static string Test(Span a) => ""Span""; + static string Test(ReadOnlySpan a) => ""ReadOnlySpan""; static string Test(byte[] a) => ""array""; } "; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: @"array").VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: @"ReadOnlySpan", verify: Verification.Fails).VerifyDiagnostics(); } [ConditionalFact(typeof(CoreClrOnly))] @@ -2018,7 +1884,7 @@ static void Main() } "; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: @"Span").VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: @"ReadOnlySpan", verify: Verification.Fails).VerifyDiagnostics(); } [ConditionalFact(typeof(CoreClrOnly))] @@ -2039,7 +1905,7 @@ static void Main() } "; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: @"array").VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: @"ReadOnlySpan", verify: Verification.Fails).VerifyDiagnostics(); } [ConditionalFact(typeof(CoreClrOnly))] @@ -2057,7 +1923,7 @@ static void Main() class C1 { - public static implicit operator C1(byte[] x) + public static implicit operator C1(ReadOnlySpan x) { Helpers.Print(x); return new C1(); @@ -2068,7 +1934,7 @@ public static implicit operator C1(byte[] x) CompileAndVerify(comp, expectedOutput: @" { 0x68 0x65 0x6C 0x6C 0x6F } -").VerifyDiagnostics(); +", verify: Verification.Fails).VerifyDiagnostics(); } [ConditionalFact(typeof(CoreClrOnly))] @@ -2086,7 +1952,7 @@ static void Main() class C1 { - public static implicit operator C1(byte[] x) + public static implicit operator C1(ReadOnlySpan x) { Helpers.Print(x); return new C1(); @@ -2097,10 +1963,10 @@ public static implicit operator C1(byte[] x) CompileAndVerify(comp, expectedOutput: @" { 0x68 0x65 0x6C 0x6C 0x6F } -").VerifyDiagnostics(); +", verify: Verification.Fails).VerifyDiagnostics(); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedImplicitConversions_05() { var source = @" @@ -2124,7 +1990,7 @@ public static implicit operator C2(Span x) class C3 { - public static implicit operator C3(ReadOnlySpan x) + public static implicit operator C3(byte[] x) { return new C3(); } @@ -2132,16 +1998,16 @@ public static implicit operator C3(ReadOnlySpan x) "; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); comp.VerifyDiagnostics( - // (7,16): error CS0029: Cannot implicitly convert type 'byte[]' to 'C2' + // (7,16): error CS0029: Cannot implicitly convert type 'System.ReadOnlySpan' to 'C2' // C2 y = "dog"u8; - Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""dog""u8").WithArguments("byte[]", "C2").WithLocation(7, 16), - // (8,16): error CS0029: Cannot implicitly convert type 'byte[]' to 'C3' + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""dog""u8").WithArguments("System.ReadOnlySpan", "C2").WithLocation(7, 16), + // (8,16): error CS0029: Cannot implicitly convert type 'System.ReadOnlySpan' to 'C3' // C3 z = "cat"u8; - Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""cat""u8").WithArguments("byte[]", "C3").WithLocation(8, 16) + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""cat""u8").WithArguments("System.ReadOnlySpan", "C3").WithLocation(8, 16) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedImplicitConversions_06() { var source = @" @@ -2165,7 +2031,7 @@ public static implicit operator C2(Span x) class C3 { - public static implicit operator C3(ReadOnlySpan x) + public static implicit operator C3(byte[] x) { return new C3(); } @@ -2173,16 +2039,16 @@ public static implicit operator C3(ReadOnlySpan x) "; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); comp.VerifyDiagnostics( - // (7,17): error CS0030: Cannot convert type 'byte[]' to 'C2' + // (7,17): error CS0030: Cannot convert type 'System.ReadOnlySpan' to 'C2' // var y = (C2)"dog"u8; - Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(C2)""dog""u8").WithArguments("byte[]", "C2").WithLocation(7, 17), - // (8,17): error CS0030: Cannot convert type 'byte[]' to 'C3' + Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(C2)""dog""u8").WithArguments("System.ReadOnlySpan", "C2").WithLocation(7, 17), + // (8,17): error CS0030: Cannot convert type 'System.ReadOnlySpan' to 'C3' // var z = (C3)"cat"u8; - Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(C3)""cat""u8").WithArguments("byte[]", "C3").WithLocation(8, 17) + Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(C3)""cat""u8").WithArguments("System.ReadOnlySpan", "C3").WithLocation(8, 17) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedExplicitConversions_03() { var source = @" @@ -2223,15 +2089,15 @@ public static explicit operator C3(ReadOnlySpan x) var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); comp.VerifyDiagnostics( - // (7,16): error CS0266: Cannot implicitly convert type 'byte[]' to 'C1'. An explicit conversion exists (are you missing a cast?) + // (7,16): error CS0029: Cannot implicitly convert type 'System.ReadOnlySpan' to 'C1' // C1 x = "hello"u8; - Diagnostic(ErrorCode.ERR_NoImplicitConvCast, @"""hello""u8").WithArguments("byte[]", "C1").WithLocation(7, 16), - // (8,16): error CS0029: Cannot implicitly convert type 'byte[]' to 'C2' + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""hello""u8").WithArguments("System.ReadOnlySpan", "C1").WithLocation(7, 16), + // (8,16): error CS0029: Cannot implicitly convert type 'System.ReadOnlySpan' to 'C2' // C2 y = "dog"u8; - Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""dog""u8").WithArguments("byte[]", "C2").WithLocation(8, 16), - // (9,16): error CS0029: Cannot implicitly convert type 'byte[]' to 'C3' + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""dog""u8").WithArguments("System.ReadOnlySpan", "C2").WithLocation(8, 16), + // (9,16): error CS0266: Cannot implicitly convert type 'System.ReadOnlySpan' to 'C3'. An explicit conversion exists (are you missing a cast?) // C3 z = "cat"u8; - Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""cat""u8").WithArguments("byte[]", "C3").WithLocation(9, 16) + Diagnostic(ErrorCode.ERR_NoImplicitConvCast, @"""cat""u8").WithArguments("System.ReadOnlySpan", "C3").WithLocation(9, 16) ); } @@ -2250,7 +2116,7 @@ static void Main() class C1 { - public static explicit operator C1(byte[] x) + public static explicit operator C1(ReadOnlySpan x) { Helpers.Print(x); return new C1(); @@ -2261,10 +2127,10 @@ public static explicit operator C1(byte[] x) CompileAndVerify(comp, expectedOutput: @" { 0x68 0x65 0x6C 0x6C 0x6F } -").VerifyDiagnostics(); +", verify: Verification.Fails).VerifyDiagnostics(); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void UserDefinedExplicitConversions_05() { var source = @" @@ -2288,7 +2154,7 @@ public static explicit operator C2(Span x) class C3 { - public static explicit operator C3(ReadOnlySpan x) + public static explicit operator C3(byte[] x) { return new C3(); } @@ -2296,12 +2162,12 @@ public static explicit operator C3(ReadOnlySpan x) "; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); comp.VerifyDiagnostics( - // (7,17): error CS0030: Cannot convert type 'byte[]' to 'C2' + // (7,17): error CS0030: Cannot convert type 'System.ReadOnlySpan' to 'C2' // var y = (C2)"dog"u8; - Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(C2)""dog""u8").WithArguments("byte[]", "C2").WithLocation(7, 17), - // (8,17): error CS0030: Cannot convert type 'byte[]' to 'C3' + Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(C2)""dog""u8").WithArguments("System.ReadOnlySpan", "C2").WithLocation(7, 17), + // (8,17): error CS0030: Cannot convert type 'System.ReadOnlySpan' to 'C3' // var z = (C3)"cat"u8; - Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(C3)""cat""u8").WithArguments("byte[]", "C3").WithLocation(8, 17) + Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(C3)""cat""u8").WithArguments("System.ReadOnlySpan", "C3").WithLocation(8, 17) ); } @@ -2319,13 +2185,22 @@ class C { static void Main() { - System.Console.WriteLine((" + literal + @"u8).GetType()); + PrintType(" + literal + @"u8); + } + + static void PrintType(T value) + { + System.Console.WriteLine(typeof(T)); } } "; - var comp = CreateCompilation(source, options: TestOptions.DebugExe); + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); - CompileAndVerify(comp, expectedOutput: @"System.Byte[]").VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (6,9): error CS0306: The type 'ReadOnlySpan' may not be used as a type argument + // PrintType(""" + Diagnostic(ErrorCode.ERR_BadTypeArgument, "PrintType").WithArguments("System.ReadOnlySpan").WithLocation(6, 9) + ); } [ConditionalFact(typeof(CoreClrOnly))] @@ -2348,10 +2223,10 @@ static void Main() CompileAndVerify(comp, expectedOutput: @"object").VerifyDiagnostics(); comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); - comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: @"object").VerifyDiagnostics(); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void NoConversionFromNonStringNull_01() { var source = @" @@ -2383,7 +2258,7 @@ static void Main() ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void VariableIsNotUsed() { var source = @" @@ -2395,23 +2270,7 @@ static void Main() var x1 = ""123""U8; - Span x2 = ""124""U8; ReadOnlySpan x3 = ""125""U8; - - - - - - - - - - - - - - - var x4 = (byte[])""123""U8; } } "; @@ -2421,13 +2280,13 @@ static void Main() // (9,13): warning CS0219: The variable 'x1' is assigned but its value is never used // var x1 = "123"U8; Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x1").WithArguments("x1").WithLocation(9, 13), - // (26,13): warning CS0219: The variable 'x4' is assigned but its value is never used - // var x4 = (byte[])"123"U8; - Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x4").WithArguments("x4").WithLocation(26, 13) + // (10,28): warning CS0219: The variable 'x3' is assigned but its value is never used + // ReadOnlySpan x3 = "125"U8; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x3").WithArguments("x3").WithLocation(10, 28) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void DefaultParameterValues_01() { var source = @" @@ -2460,7 +2319,7 @@ static void M07(ReadOnlySpan x = ""07""U8){} ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void DefaultParameterValues_02() { var source = @" @@ -2481,19 +2340,19 @@ static void M07(ReadOnlySpan x = (ReadOnlySpan)""07""U8){} var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugDll); comp.VerifyEmitDiagnostics( - // (11,32): error CS1736: Default parameter value for 'x' must be a compile-time constant + // (11,32): error CS0030: Cannot convert type 'System.ReadOnlySpan' to 'byte[]' // static void M05(byte[] x = (byte[])"05"u8){} - Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, @"(byte[])""05""u8").WithArguments("x").WithLocation(11, 32), - // (12,36): error CS1736: Default parameter value for 'x' must be a compile-time constant + Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(byte[])""05""u8").WithArguments("System.ReadOnlySpan", "byte[]").WithLocation(11, 32), + // (12,36): error CS0030: Cannot convert type 'System.ReadOnlySpan' to 'System.Span' // static void M06(Span x = (Span)"06"u8){} - Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, @"(Span)""06""u8").WithArguments("x").WithLocation(12, 36), + Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(Span)""06""u8").WithArguments("System.ReadOnlySpan", "System.Span").WithLocation(12, 36), // (13,44): error CS1736: Default parameter value for 'x' must be a compile-time constant // static void M07(ReadOnlySpan x = (ReadOnlySpan)"07"U8){} Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, @"(ReadOnlySpan)""07""U8").WithArguments("x").WithLocation(13, 44) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void CallerMemberName_01() { var source = @" @@ -2562,16 +2421,16 @@ public UTF8Attribute(byte[] x) {} var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugDll); comp.VerifyEmitDiagnostics( - // (13,11): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // (13,11): error CS1503: Argument 1: cannot convert from 'System.ReadOnlySpan' to 'byte[]' // [UTF8("3"U8)] - Diagnostic(ErrorCode.ERR_BadAttributeArgument, @"""3""U8").WithLocation(13, 11), - // (22,11): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + Diagnostic(ErrorCode.ERR_BadArgType, @"""3""U8").WithArguments("1", "System.ReadOnlySpan", "byte[]").WithLocation(13, 11), + // (22,11): error CS0030: Cannot convert type 'System.ReadOnlySpan' to 'byte[]' // [UTF8((byte[])"3"U8)] - Diagnostic(ErrorCode.ERR_BadAttributeArgument, @"(byte[])""3""U8").WithLocation(22, 11) + Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(byte[])""3""U8").WithArguments("System.ReadOnlySpan", "byte[]").WithLocation(22, 11) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void AttributeArgument_02() { var source = @" @@ -2607,16 +2466,19 @@ public UTF8Attribute(Span x) {} var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugDll); comp.VerifyEmitDiagnostics( - // (13,6): error CS0181: Attribute constructor parameter 'x' has type 'Span', which is not a valid attribute parameter type + // (13,11): error CS1503: Argument 1: cannot convert from 'System.ReadOnlySpan' to 'System.Span' // [UTF8("3"U8)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "UTF8").WithArguments("x", "System.Span").WithLocation(13, 6), + Diagnostic(ErrorCode.ERR_BadArgType, @"""3""U8").WithArguments("1", "System.ReadOnlySpan", "System.Span").WithLocation(13, 11), // (22,6): error CS0181: Attribute constructor parameter 'x' has type 'Span', which is not a valid attribute parameter type // [UTF8((Span)"3"U8)] - Diagnostic(ErrorCode.ERR_BadAttributeParamType, "UTF8").WithArguments("x", "System.Span").WithLocation(22, 6) + Diagnostic(ErrorCode.ERR_BadAttributeParamType, "UTF8").WithArguments("x", "System.Span").WithLocation(22, 6), + // (22,11): error CS0030: Cannot convert type 'System.ReadOnlySpan' to 'System.Span' + // [UTF8((Span)"3"U8)] + Diagnostic(ErrorCode.ERR_NoExplicitConv, @"(Span)""3""U8").WithArguments("System.ReadOnlySpan", "System.Span").WithLocation(22, 11) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void AttributeArgument_03() { var source = @" @@ -2661,7 +2523,7 @@ public UTF8Attribute(ReadOnlySpan x) {} ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void NoConversionFromNonConstant_01() { var source = @" @@ -2703,7 +2565,7 @@ void Test(string s) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void NoConversionFromNonConstant_02() { var source = @" @@ -2765,13 +2627,13 @@ void Test(byte[] s) // (7,18): error CS0029: Cannot implicitly convert type 'string' to 'byte[]' // _ = s is "1"; Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""1""").WithArguments("string", "byte[]").WithLocation(7, 18), - // (8,18): error CS0150: A constant value is expected + // (8,18): error CS0029: Cannot implicitly convert type 'System.ReadOnlySpan' to 'byte[]' // _ = s is "2"u8; - Diagnostic(ErrorCode.ERR_ConstantExpected, @"""2""u8").WithLocation(8, 18) + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""2""u8").WithArguments("System.ReadOnlySpan", "byte[]").WithLocation(8, 18) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void PatternMatching_02() { var source = @" @@ -2791,13 +2653,13 @@ void Test(Span s) // (7,18): error CS0029: Cannot implicitly convert type 'string' to 'System.Span' // _ = s is "1"; Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""1""").WithArguments("string", "System.Span").WithLocation(7, 18), - // (8,18): error CS0150: A constant value is expected + // (8,18): error CS0029: Cannot implicitly convert type 'System.ReadOnlySpan' to 'System.Span' // _ = s is "2"u8; - Diagnostic(ErrorCode.ERR_ConstantExpected, @"""2""u8").WithLocation(8, 18) + Diagnostic(ErrorCode.ERR_NoImplicitConv, @"""2""u8").WithArguments("System.ReadOnlySpan", "System.Span").WithLocation(8, 18) ); } - [ConditionalFact(typeof(CoreClrOnly))] + [Fact] public void PatternMatching_03() { var source = @" @@ -3013,10 +2875,10 @@ byte[] Test() Assert.Null(symbolInfo.Symbol); var typeInfo = model.GetTypeInfo(node); - Assert.Equal("System.Byte[]", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("System.ReadOnlySpan", typeInfo.Type.ToTestDisplayString()); Assert.Equal("System.Byte[]", typeInfo.ConvertedType.ToTestDisplayString()); - Assert.True(model.GetConversion(node).IsIdentity); + Assert.False(model.GetConversion(node).Exists); } [Fact] @@ -3066,41 +2928,13 @@ Span Test() var node = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single().Expression; var symbolInfo = model.GetSymbolInfo(node); - Assert.Equal("System.Span System.Span.op_Implicit(System.Byte[]? array)", symbolInfo.Symbol.ToTestDisplayString()); - - var typeInfo = model.GetTypeInfo(node); - Assert.Equal("System.Byte[]", typeInfo.Type.ToTestDisplayString()); - Assert.Equal("System.Span", typeInfo.ConvertedType.ToTestDisplayString()); - - Assert.True(model.GetConversion(node).IsUserDefined); - } - - [ConditionalFact(typeof(CoreClrOnly))] - public void SemanticModel_10() - { - var source = @" -using System; -class C -{ - Span Test() - { - return (Span)""1""u8; - } -} -"; - var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugDll); - var tree = comp.SyntaxTrees.Single(); - var model = comp.GetSemanticModel(tree); - var node = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single().Expression; - - var symbolInfo = model.GetSymbolInfo(node); - Assert.Equal("System.Span System.Span.op_Implicit(System.Byte[]? array)", symbolInfo.Symbol.ToTestDisplayString()); + Assert.Null(symbolInfo.Symbol); var typeInfo = model.GetTypeInfo(node); - Assert.Equal("System.Span", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("System.ReadOnlySpan", typeInfo.Type.ToTestDisplayString()); Assert.Equal("System.Span", typeInfo.ConvertedType.ToTestDisplayString()); - Assert.True(model.GetConversion(node).IsIdentity); + Assert.False(model.GetConversion(node).Exists); } [ConditionalFact(typeof(CoreClrOnly))] @@ -3122,13 +2956,13 @@ ReadOnlySpan Test() var node = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single().Expression; var symbolInfo = model.GetSymbolInfo(node); - Assert.Equal("System.ReadOnlySpan System.ReadOnlySpan.op_Implicit(System.Byte[]? array)", symbolInfo.Symbol.ToTestDisplayString()); + Assert.Null(symbolInfo.Symbol); var typeInfo = model.GetTypeInfo(node); - Assert.Equal("System.Byte[]", typeInfo.Type.ToTestDisplayString()); + Assert.Equal("System.ReadOnlySpan", typeInfo.Type.ToTestDisplayString()); Assert.Equal("System.ReadOnlySpan", typeInfo.ConvertedType.ToTestDisplayString()); - Assert.True(model.GetConversion(node).IsUserDefined); + Assert.True(model.GetConversion(node).IsIdentity); } [ConditionalFact(typeof(CoreClrOnly))] @@ -3150,7 +2984,7 @@ ReadOnlySpan Test() var node = tree.GetCompilationUnitRoot().DescendantNodes().OfType().Single().Expression; var symbolInfo = model.GetSymbolInfo(node); - Assert.Equal("System.ReadOnlySpan System.ReadOnlySpan.op_Implicit(System.Byte[]? array)", symbolInfo.Symbol.ToTestDisplayString()); + Assert.Null(symbolInfo.Symbol); var typeInfo = model.GetTypeInfo(node); Assert.Equal("System.ReadOnlySpan", typeInfo.Type.ToTestDisplayString()); @@ -3214,5 +3048,466 @@ ReadOnlySpan Test() Assert.True(model.GetConversion(node).IsIdentity); } + + [Fact] + public void NullTerminate_01() + { + var source = @" +using System; +class C +{ + static ReadOnlySpan Test3() => ""cat""u8; +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseDll); + var verifier = CompileAndVerify(comp, verify: Verification.Fails).VerifyDiagnostics(); + + string blobId = ExecutionConditionUtil.IsWindows ? "I_000025B8" : "I_00002600"; + + verifier.VerifyTypeIL("", @" +.class private auto ansi sealed '' + extends [System.Runtime]System.Object +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field assembly static initonly int32 F3D4280708A6C4BEA1BAEB5AD5A4B659E705A90BDD448840276EA20CB151BE57 at " + blobId + @" + .data cil " + blobId + @" = bytearray ( + 63 61 74 00 + ) +} // end of class +"); + } + + [Fact] + public void NullTerminate_02() + { + var source = @" +using System; +class C +{ + static ReadOnlySpan Test3() => """"u8; +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseDll); + var verifier = CompileAndVerify(comp, verify: Verification.Fails).VerifyDiagnostics(); + + verifier.VerifyIL("C.Test3()", @" +{ + // Code size 12 (0xc) + .maxstack 2 + IL_0000: ldsflda ""byte .6E340B9CFFB37A989CA544E6BB780A2C78901D3FB33738768511A30617AFA01D"" + IL_0005: ldc.i4.0 + IL_0006: newobj ""System.ReadOnlySpan..ctor(void*, int)"" + IL_000b: ret +} +"); + string blobId = ExecutionConditionUtil.IsWindows ? "I_000025B8" : "I_00002600"; + + verifier.VerifyTypeIL("", @" +.class private auto ansi sealed '' + extends [System.Runtime]System.Object +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field assembly static initonly uint8 '6E340B9CFFB37A989CA544E6BB780A2C78901D3FB33738768511A30617AFA01D' at " + blobId + @" + .data cil " + blobId + @" = bytearray ( 00 + ) +} // end of class +"); + } + + [ConditionalTheory(typeof(CoreClrOnly))] + [InlineData(0, -1, "ldc.i4.0", "ldc.i4.m1")] + [InlineData(0, 4, "ldc.i4.0", "ldc.i4.4")] + [InlineData(-1, -1, "ldc.i4.m1", "ldc.i4.m1")] + [InlineData(-1, 2, "ldc.i4.m1", "ldc.i4.2")] + [InlineData(-1, 4, "ldc.i4.m1", "ldc.i4.4")] + public void System_ReadOnlySpan_T__ctor_Array_Start_Length_ExplicitUsage_01(int start, int length, string startOpCode, string lengthOpCode) + { + var source = @" +using System; +class C +{ + static void Main() + { + try + { + Test3(); + } + catch (ArgumentOutOfRangeException) + { + Console.Write(""ArgumentOutOfRangeException""); + } + } + + static ReadOnlySpan Test3() + { + return new ReadOnlySpan(new byte[] { 1, 2, 3 }, " + start + ", " + length + @"); + } +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); + + var verifier = CompileAndVerify(comp, expectedOutput: @"ArgumentOutOfRangeException", verify: Verification.Fails).VerifyDiagnostics(); + + verifier.VerifyIL("C.Test3()", @" +{ + // Code size 30 (0x1e) + .maxstack 3 + .locals init (System.ReadOnlySpan V_0) + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: newarr ""byte"" + IL_0007: dup + IL_0008: ldtoken "".__StaticArrayInitTypeSize=3 .039058C6F2C0CB492C533B0A4D14EF77CC0F78ABCCCED5287D84A1A2011CFB81"" + IL_000d: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" + IL_0012: " + startOpCode + @" + IL_0013: " + lengthOpCode + @" + IL_0014: newobj ""System.ReadOnlySpan..ctor(byte[], int, int)"" + IL_0019: stloc.0 + IL_001a: br.s IL_001c + IL_001c: ldloc.0 + IL_001d: ret +} +"); + } + + [ConditionalTheory(typeof(CoreClrOnly))] + [InlineData(0, "{ }")] + [InlineData(1, "{ 0x1 }")] + [InlineData(2, "{ 0x1 0x2 }")] + public void System_ReadOnlySpan_T__ctor_Array_Start_Length_ExplicitUsage_02(int length, string expected) + { + var source = @" +using System; +class C +{ + static void Main() + { + System.Console.WriteLine(); + Helpers.Print(Test3()); + } + + static ReadOnlySpan Test3() + { + return new ReadOnlySpan(new byte[] { 1, 2 }, 0, " + length + @"); + } +} +"; + var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +" + expected + @" +", verify: Verification.Fails).VerifyDiagnostics(); + + verifier.VerifyIL("C.Test3()", @" +{ + // Code size 17 (0x11) + .maxstack 2 + .locals init (System.ReadOnlySpan V_0) + IL_0000: nop + IL_0001: ldsflda ""short .A12871FEE210FB8619291EAEA194581CBD2531E4B23759D225F6806923F63222"" + IL_0006: ldc.i4." + length + @" + IL_0007: newobj ""System.ReadOnlySpan..ctor(void*, int)"" + IL_000c: stloc.0 + IL_000d: br.s IL_000f + IL_000f: ldloc.0 + IL_0010: ret +} +"); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void System_ReadOnlySpan_T__ctor_Array_Start_Length_ExplicitUsage_03() + { + var source = @" +using System; +class C +{ + static void Main() + { + System.Console.WriteLine(); + Helpers.Print(Test3()); + } + + static ReadOnlySpan Test3() + { + return new ReadOnlySpan(new byte[] { 1, 2, 3 }, 1, 1); + } +} +"; + var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +{ 0x2 } +", verify: Verification.Fails).VerifyDiagnostics(); + + verifier.VerifyIL("C.Test3()", @" +{ + // Code size 30 (0x1e) + .maxstack 3 + .locals init (System.ReadOnlySpan V_0) + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: newarr ""byte"" + IL_0007: dup + IL_0008: ldtoken "".__StaticArrayInitTypeSize=3 .039058C6F2C0CB492C533B0A4D14EF77CC0F78ABCCCED5287D84A1A2011CFB81"" + IL_000d: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" + IL_0012: ldc.i4.1 + IL_0013: ldc.i4.1 + IL_0014: newobj ""System.ReadOnlySpan..ctor(byte[], int, int)"" + IL_0019: stloc.0 + IL_001a: br.s IL_001c + IL_001c: ldloc.0 + IL_001d: ret +} +"); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void System_ReadOnlySpan_T__ctor_Array_Start_Length_ExplicitUsage_04() + { + var source = @" +using System; +class C +{ + static void Main() + { + System.Console.WriteLine(); + Helpers.Print(Test3()); + } + + static ReadOnlySpan Test3() + { + return new ReadOnlySpan(new byte[] { 1, 2, 3 }, Start, 2); + } + + static int Start = 0; +} +"; + var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +{ 0x1 0x2 } +", verify: Verification.Fails).VerifyDiagnostics(); + + verifier.VerifyIL("C.Test3()", @" +{ + // Code size 34 (0x22) + .maxstack 3 + .locals init (System.ReadOnlySpan V_0) + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: newarr ""byte"" + IL_0007: dup + IL_0008: ldtoken "".__StaticArrayInitTypeSize=3 .039058C6F2C0CB492C533B0A4D14EF77CC0F78ABCCCED5287D84A1A2011CFB81"" + IL_000d: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" + IL_0012: ldsfld ""int C.Start"" + IL_0017: ldc.i4.2 + IL_0018: newobj ""System.ReadOnlySpan..ctor(byte[], int, int)"" + IL_001d: stloc.0 + IL_001e: br.s IL_0020 + IL_0020: ldloc.0 + IL_0021: ret +} +"); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void System_ReadOnlySpan_T__ctor_Array_Start_Length_ExplicitUsage_05() + { + var source = @" +using System; +class C +{ + static void Main() + { + System.Console.WriteLine(); + Helpers.Print(Test3()); + } + + static ReadOnlySpan Test3() + { + return new ReadOnlySpan(new byte[] { 1, 2, 3 }, 0, Length); + } + + static int Length = 3; +} +"; + var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +{ 0x1 0x2 0x3 } +", verify: Verification.Fails).VerifyDiagnostics(); + + verifier.VerifyIL("C.Test3()", @" +{ + // Code size 34 (0x22) + .maxstack 3 + .locals init (System.ReadOnlySpan V_0) + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: newarr ""byte"" + IL_0007: dup + IL_0008: ldtoken "".__StaticArrayInitTypeSize=3 .039058C6F2C0CB492C533B0A4D14EF77CC0F78ABCCCED5287D84A1A2011CFB81"" + IL_000d: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" + IL_0012: ldc.i4.0 + IL_0013: ldsfld ""int C.Length"" + IL_0018: newobj ""System.ReadOnlySpan..ctor(byte[], int, int)"" + IL_001d: stloc.0 + IL_001e: br.s IL_0020 + IL_0020: ldloc.0 + IL_0021: ret +} +"); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void System_ReadOnlySpan_T__ctor_Array_Start_Length_ExplicitUsage_06() + { + var source = @" +using System; +class C +{ + static void Main() + { + System.Console.WriteLine(); + Helpers.Print(Test3()); + } + + static ReadOnlySpan Test3() + { + return new ReadOnlySpan(new byte[] { 1, 2, 3 }, Start, Length); + } + + static int Start = 0; + static int Length = 1; +} +"; + var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +{ 0x1 } +", verify: Verification.Fails).VerifyDiagnostics(); + + verifier.VerifyIL("C.Test3()", @" +{ + // Code size 38 (0x26) + .maxstack 3 + .locals init (System.ReadOnlySpan V_0) + IL_0000: nop + IL_0001: ldc.i4.3 + IL_0002: newarr ""byte"" + IL_0007: dup + IL_0008: ldtoken "".__StaticArrayInitTypeSize=3 .039058C6F2C0CB492C533B0A4D14EF77CC0F78ABCCCED5287D84A1A2011CFB81"" + IL_000d: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" + IL_0012: ldsfld ""int C.Start"" + IL_0017: ldsfld ""int C.Length"" + IL_001c: newobj ""System.ReadOnlySpan..ctor(byte[], int, int)"" + IL_0021: stloc.0 + IL_0022: br.s IL_0024 + IL_0024: ldloc.0 + IL_0025: ret +} +"); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void System_ReadOnlySpan_T__ctor_Array_Start_Length_ExplicitUsage_07() + { + var source = @" +using System; +class C +{ + static void Main() + { + System.Console.WriteLine(); + Helpers.Print(Test3()); + } + + static ReadOnlySpan Test3() + { + return new ReadOnlySpan(new byte[] { }, 0, 0); + } +} +"; + var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +{ } +", verify: Verification.Fails).VerifyDiagnostics(); + + verifier.VerifyIL("C.Test3()", @" +{ + // Code size 15 (0xf) + .maxstack 1 + .locals init (System.ReadOnlySpan V_0, + System.ReadOnlySpan V_1) + IL_0000: nop + IL_0001: ldloca.s V_0 + IL_0003: initobj ""System.ReadOnlySpan"" + IL_0009: ldloc.0 + IL_000a: stloc.1 + IL_000b: br.s IL_000d + IL_000d: ldloc.1 + IL_000e: ret +} +"); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void PassAround_01() + { + var source = @" +using System; +class C +{ + static void Main() + { + Helpers.Print(Test2()); + } + + static ReadOnlySpan Test2() => Test3(""cat""u8); + + static ReadOnlySpan Test3(ReadOnlySpan x) => x; +} +"; + var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe); + + var verifier = CompileAndVerify(comp, expectedOutput: @" +{ 0x63 0x61 0x74 } +", verify: Verification.Fails).VerifyDiagnostics(); + } + + [ConditionalFact(typeof(CoreClrOnly))] + public void PassAround_02() + { + var source = @" +using System; +class C +{ + static ref readonly ReadOnlySpan Test2() + { + return ref Test3(""cat""u8); + } + + static ref readonly ReadOnlySpan Test3(in ReadOnlySpan x) => ref x; +} +"; + var comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugDll); + + comp.VerifyDiagnostics( + // (7,20): error CS8347: Cannot use a result of 'C.Test3(in ReadOnlySpan)' in this context because it may expose variables referenced by parameter 'x' outside of their declaration scope + // return ref Test3("cat"u8); + Diagnostic(ErrorCode.ERR_EscapeCall, @"Test3(""cat""u8)").WithArguments("C.Test3(in System.ReadOnlySpan)", "x").WithLocation(7, 20), + // (7,26): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // return ref Test3("cat"u8); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, @"""cat""u8").WithLocation(7, 26) + ); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs index 47c00c9b565f4..9c2d6db7b4322 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs @@ -925,6 +925,7 @@ public void AllWellKnownTypeMembers() case WellKnownMember.System_Span_T__get_Length: case WellKnownMember.System_ReadOnlySpan_T__ctor_Pointer: case WellKnownMember.System_ReadOnlySpan_T__ctor_Array: + case WellKnownMember.System_ReadOnlySpan_T__ctor_Array_Start_Length: case WellKnownMember.System_ReadOnlySpan_T__get_Item: case WellKnownMember.System_ReadOnlySpan_T__get_Length: case WellKnownMember.System_Index__ctor: diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/CrefParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/CrefParsingTests.cs index 0bc93b66d45ff..ffa57fbff8d15 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/CrefParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/CrefParsingTests.cs @@ -439,7 +439,7 @@ public void UnqualifiedOperatorMember1_Unchecked() // (1,16): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator unchecked +' // /// Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator unchecked +").WithArguments("operator unchecked +").WithLocation(1, 16), - // (1,25): error CS9028: Unexpected keyword 'unchecked' + // (1,25): error CS9027: Unexpected keyword 'unchecked' // /// Diagnostic(ErrorCode.ERR_MisplacedUnchecked, "unchecked").WithLocation(1, 25)); @@ -507,7 +507,7 @@ public void UnqualifiedOperatorMember2_Unchecked() // (1,16): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator unchecked +(A)' // /// Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator unchecked +(A)").WithArguments("operator unchecked +(A)").WithLocation(1, 16), - // (1,25): error CS9028: Unexpected keyword 'unchecked' + // (1,25): error CS9027: Unexpected keyword 'unchecked' // /// Diagnostic(ErrorCode.ERR_MisplacedUnchecked, "unchecked").WithLocation(1, 25)); @@ -583,7 +583,7 @@ public void QualifiedOperatorMember1_Unchecked() // (1,16): warning CS1584: XML comment has syntactically incorrect cref attribute 'T.operator unchecked +' // /// Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "T.operator unchecked +").WithArguments("T.operator unchecked +").WithLocation(1, 16), - // (1,27): error CS9028: Unexpected keyword 'unchecked' + // (1,27): error CS9027: Unexpected keyword 'unchecked' // /// Diagnostic(ErrorCode.ERR_MisplacedUnchecked, "unchecked").WithLocation(1, 27) ); @@ -768,7 +768,7 @@ public void GreaterThanGreaterThan_Unchecked() // (1,16): warning CS1584: XML comment has syntactically incorrect cref attribute 'operator unchecked }}(A{A{T}})' // /// Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "operator unchecked }}(A{A{T}})").WithArguments("operator unchecked }}(A{A{T}})").WithLocation(1, 16), - // (1,25): error CS9028: Unexpected keyword 'unchecked' + // (1,25): error CS9027: Unexpected keyword 'unchecked' // /// Diagnostic(ErrorCode.ERR_MisplacedUnchecked, "unchecked").WithLocation(1, 25) ); @@ -903,7 +903,7 @@ public void UnqualifiedConversionOperatorMember1_Unchecked() // (1,16): warning CS1584: XML comment has syntactically incorrect cref attribute 'implicit operator unchecked A' // /// Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "implicit operator unchecked A").WithArguments("implicit operator unchecked A").WithLocation(1, 16), - // (1,34): error CS9028: Unexpected keyword 'unchecked' + // (1,34): error CS9027: Unexpected keyword 'unchecked' // /// Diagnostic(ErrorCode.ERR_MisplacedUnchecked, "unchecked").WithLocation(1, 34) ); @@ -984,7 +984,7 @@ public void UnqualifiedConversionOperatorMember2_Unchecked() // (1,16): warning CS1584: XML comment has syntactically incorrect cref attribute 'explicit operator unchecked A(B)' // /// Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "explicit operator unchecked A(B)").WithArguments("explicit operator unchecked A(B)").WithLocation(1, 16), - // (1,34): error CS9028: Unexpected keyword 'unchecked' + // (1,34): error CS9027: Unexpected keyword 'unchecked' // /// Diagnostic(ErrorCode.ERR_MisplacedUnchecked, "unchecked").WithLocation(1, 34) ); @@ -1072,7 +1072,7 @@ public void QualifiedConversionOperatorMember1_Unchecked() // (1,16): warning CS1584: XML comment has syntactically incorrect cref attribute 'T.implicit operator unchecked A' // /// Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "T.implicit operator unchecked A").WithArguments("T.implicit operator unchecked A").WithLocation(1, 16), - // (1,36): error CS9028: Unexpected keyword 'unchecked' + // (1,36): error CS9027: Unexpected keyword 'unchecked' // /// Diagnostic(ErrorCode.ERR_MisplacedUnchecked, "unchecked").WithLocation(1, 36) ); @@ -1176,7 +1176,7 @@ public void QualifiedConversionOperatorMember2_Unchecked() // (1,16): warning CS1584: XML comment has syntactically incorrect cref attribute 'T.explicit operator unchecked A(B)' // /// Diagnostic(ErrorCode.WRN_BadXMLRefSyntax, "T.explicit operator unchecked A(B)").WithArguments("T.explicit operator unchecked A(B)").WithLocation(1, 16), - // (1,36): error CS9028: Unexpected keyword 'unchecked' + // (1,36): error CS9027: Unexpected keyword 'unchecked' // /// Diagnostic(ErrorCode.ERR_MisplacedUnchecked, "unchecked").WithLocation(1, 36) ); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs index ddf30e75fbe8a..2337ff563f551 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs @@ -8040,7 +8040,7 @@ public void CheckedOperatorDeclaration_06(string op, SyntaxKind opToken) public void UncheckedOperatorDeclaration_01(string op, SyntaxKind opToken) { UsingDeclaration("C operator unchecked " + op + "(C x) => x;", expectedErrors: - // (1,12): error CS9028: Unexpected keyword 'unchecked' + // (1,12): error CS9027: Unexpected keyword 'unchecked' // C operator unchecked op(C x) => x; Diagnostic(ErrorCode.ERR_MisplacedUnchecked, "unchecked").WithLocation(1, 12)); @@ -8099,7 +8099,7 @@ public void UncheckedOperatorDeclaration_01(string op, SyntaxKind opToken) public void UncheckedOperatorDeclaration_04(string op, SyntaxKind opToken) { UsingDeclaration("C I.operator unchecked " + op + "(C x, C y) => x;", options: TestOptions.RegularPreview, - // (1,14): error CS9028: Unexpected keyword 'unchecked' + // (1,14): error CS9027: Unexpected keyword 'unchecked' // C I.operator unchecked op(C x, C y) => x; Diagnostic(ErrorCode.ERR_MisplacedUnchecked, "unchecked").WithLocation(1, 14)); @@ -8160,7 +8160,7 @@ public void UncheckedOperatorDeclaration_04(string op, SyntaxKind opToken) public void UnheckedOperatorDeclaration_05(string op, SyntaxKind opToken) { UsingDeclaration(op + " operator unchecked D(C x) => x;", expectedErrors: - // (1,19): error CS9028: Unexpected keyword 'unchecked' + // (1,19): error CS9027: Unexpected keyword 'unchecked' // implicit operator unchecked op(C x) => x; Diagnostic(ErrorCode.ERR_MisplacedUnchecked, "unchecked").WithLocation(1, 19)); diff --git a/src/Compilers/Core/Portable/WellKnownMember.cs b/src/Compilers/Core/Portable/WellKnownMember.cs index a9e2796429218..03ac1ab640f21 100644 --- a/src/Compilers/Core/Portable/WellKnownMember.cs +++ b/src/Compilers/Core/Portable/WellKnownMember.cs @@ -442,6 +442,7 @@ internal enum WellKnownMember System_ReadOnlySpan_T__ctor_Pointer, System_ReadOnlySpan_T__ctor_Array, + System_ReadOnlySpan_T__ctor_Array_Start_Length, System_ReadOnlySpan_T__get_Item, System_ReadOnlySpan_T__get_Length, diff --git a/src/Compilers/Core/Portable/WellKnownMembers.cs b/src/Compilers/Core/Portable/WellKnownMembers.cs index 390cb2ab3281e..b912ab6405bae 100644 --- a/src/Compilers/Core/Portable/WellKnownMembers.cs +++ b/src/Compilers/Core/Portable/WellKnownMembers.cs @@ -3048,6 +3048,16 @@ static WellKnownMembers() (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type (byte)SignatureTypeCode.SZArray, (byte)SignatureTypeCode.GenericTypeParameter, 0, + // System_ReadOnlySpan_T__ctor_Array_Start_Length + (byte)(MemberFlags.Constructor), // Flags + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_ReadOnlySpan_T - WellKnownType.ExtSentinel), // DeclaringTypeId + 0, // Arity + 3, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type + (byte)SignatureTypeCode.SZArray, (byte)SignatureTypeCode.GenericTypeParameter, 0, + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, + // System_ReadOnlySpan_T__get_Item (byte)(MemberFlags.PropertyGet), // Flags (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_ReadOnlySpan_T - WellKnownType.ExtSentinel), // DeclaringTypeId @@ -3972,6 +3982,7 @@ static WellKnownMembers() "get_Length", // System_Span_T__get_Length ".ctor", // System_ReadOnlySpan_T__ctor_Pointer ".ctor", // System_ReadOnlySpan_T__ctor_Array + ".ctor", // System_ReadOnlySpan_T__ctor_Array_Start_Length "get_Item", // System_ReadOnlySpan_T__get_Item "get_Length", // System_ReadOnlySpan_T__get_Length ".ctor", // System_Runtime_CompilerServices_IsUnmanagedAttribute__ctor diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb index 88333f788a37a..1b772e94a64f0 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb @@ -669,6 +669,7 @@ End Namespace WellKnownMember.System_Span_T__get_Length, WellKnownMember.System_ReadOnlySpan_T__ctor_Pointer, WellKnownMember.System_ReadOnlySpan_T__ctor_Array, + WellKnownMember.System_ReadOnlySpan_T__ctor_Array_Start_Length, WellKnownMember.System_ReadOnlySpan_T__get_Item, WellKnownMember.System_ReadOnlySpan_T__get_Length, WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorStateMachineAttribute__ctor, @@ -816,6 +817,7 @@ End Namespace WellKnownMember.System_Span_T__get_Length, WellKnownMember.System_ReadOnlySpan_T__ctor_Pointer, WellKnownMember.System_ReadOnlySpan_T__ctor_Array, + WellKnownMember.System_ReadOnlySpan_T__ctor_Array_Start_Length, WellKnownMember.System_ReadOnlySpan_T__get_Item, WellKnownMember.System_ReadOnlySpan_T__get_Length, WellKnownMember.System_Runtime_CompilerServices_AsyncIteratorStateMachineAttribute__ctor, diff --git a/src/EditorFeatures/CSharpTest/ConvertNamespace/ConvertToFileScopedNamespaceAnalyzerTests.cs b/src/EditorFeatures/CSharpTest/ConvertNamespace/ConvertToFileScopedNamespaceAnalyzerTests.cs index 55e701b957214..4cf08c61767f2 100644 --- a/src/EditorFeatures/CSharpTest/ConvertNamespace/ConvertToFileScopedNamespaceAnalyzerTests.cs +++ b/src/EditorFeatures/CSharpTest/ConvertNamespace/ConvertToFileScopedNamespaceAnalyzerTests.cs @@ -737,7 +737,7 @@ class C { void M() { - System.Console.WriteLine("""""" + M2("""""" a b c @@ -745,6 +745,8 @@ void M() e """"""u8); } + + void M2(System.ReadOnlySpan x) {} } } ", @@ -755,7 +757,7 @@ class C { void M() { - System.Console.WriteLine("""""" + M2("""""" a b c @@ -763,9 +765,12 @@ void M() e """"""u8); } + + void M2(System.ReadOnlySpan x) {} } ", LanguageVersion = LanguageVersion.Preview, + ReferenceAssemblies = ReferenceAssemblies.Net.Net50, Options = { { CSharpCodeStyleOptions.NamespaceDeclarations, NamespaceDeclarationPreference.FileScoped } diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs index b3f5d30d790e6..57b2376589bf4 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs @@ -147,6 +147,12 @@ private Task TestInMethodAsync(string markup, params Action[] exp return TestWithUsingsAsync(markupInMethod, expectedResults); } + private Task TestInMethodAsync(string markup, string extraSource, params Action[] expectedResults) + { + var markupInMethod = "class C { void M() { " + markup + " } }" + extraSource; + return TestWithUsingsAsync(markupInMethod, expectedResults); + } + private static async Task TestWithReferenceAsync(string sourceCode, string referencedCode, string sourceLanguage, @@ -1823,14 +1829,18 @@ await TestInMethodAsync(@"string f = ""Goo""$$", public async Task TestStringLiteralUTF8_01() { await TestInMethodAsync(@"var f = ""Goo""u8$$", - MainDescription("byte[]")); + TestSources.Span, + MainDescription("readonly ref struct System.ReadOnlySpan"), + TypeParameterMap($"\r\nT {FeaturesResources.is_} byte")); } [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] public async Task TestStringLiteralUTF8_02() { await TestInMethodAsync(@"var f = ""Goo""U8$$", - MainDescription("byte[]")); + TestSources.Span, + MainDescription("readonly ref struct System.ReadOnlySpan"), + TypeParameterMap($"\r\nT {FeaturesResources.is_} byte")); } [WorkItem(1280, "https://github.com/dotnet/roslyn/issues/1280")] @@ -1845,14 +1855,18 @@ await TestInMethodAsync(@"string f = @""cat""$$", public async Task TestVerbatimStringLiteralUTF8_01() { await TestInMethodAsync(@"string f = @""cat""u8$$", - MainDescription("byte[]")); + TestSources.Span, + MainDescription("readonly ref struct System.ReadOnlySpan"), + TypeParameterMap($"\r\nT {FeaturesResources.is_} byte")); } [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] public async Task TestVerbatimStringLiteralUTF8_02() { await TestInMethodAsync(@"string f = @""cat""U8$$", - MainDescription("byte[]")); + TestSources.Span, + MainDescription("readonly ref struct System.ReadOnlySpan"), + TypeParameterMap($"\r\nT {FeaturesResources.is_} byte")); } [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] @@ -1866,14 +1880,18 @@ await TestInMethodAsync(@"string f = """"""Goo""""""$$", public async Task TestRawStringLiteralUTF8_01() { await TestInMethodAsync(@"string f = """"""Goo""""""u8$$", - MainDescription("byte[]")); + TestSources.Span, + MainDescription("readonly ref struct System.ReadOnlySpan"), + TypeParameterMap($"\r\nT {FeaturesResources.is_} byte")); } [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] public async Task TestRawStringLiteralUTF8_02() { await TestInMethodAsync(@"string f = """"""Goo""""""U8$$", - MainDescription("byte[]")); + TestSources.Span, + MainDescription("readonly ref struct System.ReadOnlySpan"), + TypeParameterMap($"\r\nT {FeaturesResources.is_} byte")); } [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] @@ -1891,7 +1909,9 @@ public async Task TestRawStringLiteralMultilineUTF8_01() await TestInMethodAsync(@"string f = """""" Goo """"""u8$$", - MainDescription("byte[]")); + TestSources.Span, + MainDescription("readonly ref struct System.ReadOnlySpan"), + TypeParameterMap($"\r\nT {FeaturesResources.is_} byte")); } [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] @@ -1900,7 +1920,9 @@ public async Task TestRawStringLiteralMultilineUTF8_02() await TestInMethodAsync(@"string f = """""" Goo """"""U8$$", - MainDescription("byte[]")); + TestSources.Span, + MainDescription("readonly ref struct System.ReadOnlySpan"), + TypeParameterMap($"\r\nT {FeaturesResources.is_} byte")); } [WorkItem(1280, "https://github.com/dotnet/roslyn/issues/1280")] diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs index a162ac0598d21..5ff6bbba58dce 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs @@ -1854,18 +1854,17 @@ static void F() source, OutputKind.DynamicallyLinkedLibrary, methodName: "C.F", - expr: @"""hello""u8"); + expr: @"""hello""u8", + targetFramework: TargetFramework.NetCoreApp); testData.GetMethodData("<>x.<>m0").VerifyIL( @" { - // Code size 18 (0x12) - .maxstack 3 - IL_0000: ldc.i4.5 - IL_0001: newarr ""byte"" - IL_0006: dup - IL_0007: ldtoken "".__StaticArrayInitTypeSize=5 .2CF24DBA5FB0A30E26E83B2AC5B9E29E1B161E5C1FA7425E73043362938B9824"" - IL_000c: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0011: ret + // Code size 12 (0xc) + .maxstack 2 + IL_0000: ldsflda "".__StaticArrayInitTypeSize=6 .F3AEFE62965A91903610F0E23CC8A69D5B87CEA6D28E75489B0D2CA02ED7993C"" + IL_0005: ldc.i4.5 + IL_0006: newobj ""System.ReadOnlySpan..ctor(void*, int)"" + IL_000b: ret } "); }