diff --git a/docs/Language Feature Status.md b/docs/Language Feature Status.md
index 768a966e61f4e..1685a00f7e9d7 100644
--- a/docs/Language Feature Status.md
+++ b/docs/Language Feature Status.md
@@ -10,11 +10,7 @@ efforts behind them.
| Feature | Branch | State | Developer | Reviewer | LDM Champ |
| ------- | ------ | ----- | --------- | -------- | --------- |
-| [Static Abstract Members In Interfaces](https://github.com/dotnet/csharplang/issues/4436) | [StaticAbstractMembersInInterfaces](https://github.com/dotnet/roslyn/tree/features/StaticAbstractMembersInInterfaces) | [In Progress](https://github.com/dotnet/roslyn/issues/52221) | [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | [MadsTorgersen](https://github.com/MadsTorgersen) |
-| [File-scoped namespace](https://github.com/dotnet/csharplang/issues/137) | [FileScopedNamespaces](https://github.com/dotnet/roslyn/tree/features/FileScopedNamespaces) | [In Progress](https://github.com/dotnet/roslyn/issues/49000) | [RikkiGibson](https://github.com/RikkiGibson) | [jcouv](https://github.com/jcouv), [chsienki](https://github.com/chsienki) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) |
-| [Interpolated string improvements](https://github.com/dotnet/csharplang/issues/4487) | [interpolated-string](https://github.com/dotnet/roslyn/tree/features/interpolated-string) | [In Progress](https://github.com/dotnet/roslyn/issues/51499) | [333fred](https://github.com/333fred) | [AlekseyTs](https://github.com/AlekseyTs), [chsienki](https://github.com/chsienki) | [jaredpar](https://github.com/jaredpar) |
| [Parameterless struct constructors](https://github.com/dotnet/csharplang/issues/99) | [struct-ctors](https://github.com/dotnet/roslyn/tree/features/struct-ctors) | [In Progress](https://github.com/dotnet/roslyn/issues/51698) | [cston](https://github.com/cston) | [jcouv](https://github.com/jcouv), [333fred](https://github.com/333fred) | [jcouv](https://github.com/jouv) |
-| [Lambda improvements](https://github.com/dotnet/csharplang/blob/main/proposals/lambda-improvements.md) | [lambdas](https://github.com/dotnet/roslyn/tree/features/lambdas) | [In Progress](https://github.com/dotnet/roslyn/issues/52192) | [cston](https://github.com/cston) | [333fred](https://github.com/333fred), [jcouv](https://github.com/jcouv) | [jaredpar](https://github.com/jaredpar) |
| [nameof(parameter)](https://github.com/dotnet/csharplang/issues/373) | main | [In Progress](https://github.com/dotnet/roslyn/issues/40524) | [jcouv](https://github.com/jcouv) | TBD | [jcouv](https://github.com/jcouv) |
| [Relax ordering of `ref` and `partial` modifiers](https://github.com/dotnet/csharplang/issues/946) | [ref-partial](https://github.com/dotnet/roslyn/tree/features/ref-partial) | In Progress | [alrz](https://github.com/alrz) | [gafter](https://github.com/gafter) | [jcouv](https://github.com/jcouv) |
| [Parameter null-checking](https://github.com/dotnet/csharplang/issues/2145) | [param-nullchecking](https://github.com/dotnet/roslyn/tree/features/param-nullchecking) | [In Progress](https://github.com/dotnet/roslyn/issues/36024) | [fayrose](https://github.com/fayrose) | [agocke](https://github.com/agocke) | [jaredpar](https://github.com/jaredpar) |
@@ -38,6 +34,10 @@ efforts behind them.
| [Mix declarations and variables in deconstruction](https://github.com/dotnet/csharplang/issues/125) | main | [Merged into 16.10](https://github.com/dotnet/roslyn/issues/47746) | [YairHalberstadt ](https://github.com/YairHalberstadt) | [jcouv](https://github.com/jcouv) | [MadsTorgersen](https://github.com/MadsTorgersen) |
| [Async method builder override](https://github.com/dotnet/csharplang/issues/1407) | main | [Merged into 17.0p2](https://github.com/dotnet/roslyn/issues/51999) | [jcouv](https://github.com/jcouv) | [cston](https://github.com/cston), [RikkiGibson](https://github.com/RikkiGibson) | [stephentoub](https://github.com/stephentoub) |
| [Enhanced `#line` directive](https://github.com/dotnet/csharplang/issues/4747) | main | [Merged into 17.0p2](https://github.com/dotnet/roslyn/issues/54509) | [cston](https://github.com/cston) | [jcouv](https://github.com/jcouv), [RikkiGibson](https://github.com/RikkiGibson) | [MadsTorgersen](https://github.com/MadsTorgersen) |
+| [Lambda improvements](https://github.com/dotnet/csharplang/blob/main/proposals/lambda-improvements.md) | main | [Merged into 17.0p2](https://github.com/dotnet/roslyn/issues/52192) | [cston](https://github.com/cston) | [333fred](https://github.com/333fred), [jcouv](https://github.com/jcouv) | [jaredpar](https://github.com/jaredpar) |
+| [Static Abstract Members In Interfaces C# 10 Preview](https://github.com/dotnet/csharplang/issues/4436) | main | [Merged into 17.0p2](https://github.com/dotnet/roslyn/issues/52221) | [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | [MadsTorgersen](https://github.com/MadsTorgersen) |
+| [Interpolated string improvements](https://github.com/dotnet/csharplang/issues/4487) | main | [Merged into 17.0p3](https://github.com/dotnet/roslyn/issues/51499) | [333fred](https://github.com/333fred) | [AlekseyTs](https://github.com/AlekseyTs), [chsienki](https://github.com/chsienki) | [jaredpar](https://github.com/jaredpar) |
+| [File-scoped namespace](https://github.com/dotnet/csharplang/issues/137) | main | [Merged into 17.0p3](https://github.com/dotnet/roslyn/issues/49000) | [RikkiGibson](https://github.com/RikkiGibson) | [jcouv](https://github.com/jcouv), [chsienki](https://github.com/chsienki) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) |
# VB 16.9
diff --git a/docs/features/source-generators.cookbook.md b/docs/features/source-generators.cookbook.md
index 499d585aaaa7a..5ef562d10b60b 100644
--- a/docs/features/source-generators.cookbook.md
+++ b/docs/features/source-generators.cookbook.md
@@ -693,10 +693,10 @@ await new VerifyCS.Test
TestState =
{
Sources = { code },
- },
- GeneratedSources =
- {
- (typeof(YourGenerator), "GeneratedFileName", SourceText.From(generated, Encoding.UTF8, SourceHashAlgorithm.Sha256)),
+ GeneratedSources =
+ {
+ (typeof(YourGenerator), "GeneratedFileName", SourceText.From(generated, Encoding.UTF8, SourceHashAlgorithm.Sha256)),
+ },
},
}.RunAsync();
```
diff --git a/docs/wiki/NuGet-packages.md b/docs/wiki/NuGet-packages.md
index d7e1a31b51f58..242a13d5919b8 100644
--- a/docs/wiki/NuGet-packages.md
+++ b/docs/wiki/NuGet-packages.md
@@ -33,6 +33,8 @@ Below are the versions of the language available in the NuGet packages. Remember
- Version `3.4` includes C# 8.0 (Visual Studio 2019 version 16.4, .NET Core 3.1)
- ...
- Version `3.8` includes C# 9.0 (Visual Studio 2019 version 16.8, .NET 5)
+- ...
+- Version `4.0` includes C# 10.0 (Visual Studio 2022 version 17.0, .NET 6)
See the [history of C# language features](https://github.com/dotnet/csharplang/blob/main/Language-Version-History.md) for more details.
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index e3d71b5799150..9e372390d4dfe 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -6,9 +6,9 @@
7e80445ee82adbf9a8e6ae601ac5e239d982afaa
-
+
https://github.com/dotnet/source-build
- bf8af9a5202d5016b4bcf3424fac6bac55ef7c8e
+ 80d41001c0b5a72651f5459b9b1fc3e1e9b1231d
@@ -18,9 +18,9 @@
78da7776965b428ff31da8f1ff2cb073506212b7
-
+
https://github.com/dotnet/roslyn
- ca27d128f3533dc41a46b010b8e878916328f2e4
+ ea623578b108856d3416af28af61060ed3d695e8
https://github.com/dotnet/arcade
diff --git a/eng/Versions.props b/eng/Versions.props
index 1a88275962197..f3bf6b0bc33e4 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -23,7 +23,7 @@
- 4.0.0-2.21359.14
+ 4.0.0-3.21369.1
diff --git a/eng/config/globalconfigs/Common.globalconfig b/eng/config/globalconfigs/Common.globalconfig
index 51441f5c46ad5..9be4ffd974176 100644
--- a/eng/config/globalconfigs/Common.globalconfig
+++ b/eng/config/globalconfigs/Common.globalconfig
@@ -5,6 +5,9 @@ dotnet_diagnostic.CA1068.severity = warning
dotnet_diagnostic.CA1200.severity = warning
dotnet_diagnostic.CA1821.severity = warning
+# CA2012: Use ValueTasks correctly
+dotnet_diagnostic.CA2012.severity = warning
+
dotnet_diagnostic.IDE0055.severity = warning
dotnet_diagnostic.RS1001.severity = none
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
index a4555b2a11018..560b5bf221e26 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
@@ -334,8 +334,16 @@ private BoundExpression ConvertConditionalExpression(
: GenerateConversionForAssignment(destination, source.Alternative, diagnostics);
var constantValue = FoldConditionalOperator(condition, trueExpr, falseExpr);
hasErrors |= constantValue?.IsBad == true;
- if (targetTyped && !destination.IsErrorType())
- MessageID.IDS_FeatureTargetTypedConditional.CheckFeatureAvailability(diagnostics, source.Syntax);
+ if (targetTyped && !destination.IsErrorType() && !Compilation.IsFeatureEnabled(MessageID.IDS_FeatureTargetTypedConditional))
+ {
+ diagnostics.Add(
+ ErrorCode.ERR_NoImplicitConvTargetTypedConditional,
+ source.Syntax.Location,
+ Compilation.LanguageVersion.ToDisplayString(),
+ source.Consequence.Display,
+ source.Alternative.Display,
+ new CSharpRequiredLanguageVersion(MessageID.IDS_FeatureTargetTypedConditional.RequiredVersion()));
+ }
return new BoundConditionalOperator(source.Syntax, isRef: false, condition, trueExpr, falseExpr, constantValue, source.Type, wasTargetTyped: targetTyped, destination, hasErrors)
.WithSuppression(source.IsSuppressed);
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx
index de133b845394d..ec8f847e7ce6d 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.resx
+++ b/src/Compilers/CSharp/Portable/CSharpResources.resx
@@ -6442,6 +6442,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
target-typed conditional expression
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
'{0}' does not override expected method from 'object'.
diff --git a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs
index 5e565391886b7..bddf333acf395 100644
--- a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs
+++ b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs
@@ -24,6 +24,7 @@ public class CSharpCommandLineParser : CommandLineParser
public static CSharpCommandLineParser Script { get; } = new CSharpCommandLineParser(isScriptCommandLineParser: true);
private static readonly char[] s_quoteOrEquals = new[] { '"', '=' };
+ private static readonly char[] s_warningSeparators = new char[] { ',', ';', ' ' };
internal CSharpCommandLineParser(bool isScriptCommandLineParser = false)
: base(CSharp.MessageProvider.Instance, isScriptCommandLineParser)
@@ -51,7 +52,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
Debug.Assert(baseDirectory == null || PathUtilities.IsAbsolute(baseDirectory));
List diagnostics = new List();
- List flattenedArgs = new List();
+ var flattenedArgs = ArrayBuilder.GetInstance();
List? scriptArgs = IsScriptCommandLineParser ? new List() : null;
List? responsePaths = IsScriptCommandLineParser ? new List() : null;
FlattenArgs(args, diagnostics, flattenedArgs, scriptArgs, baseDirectory, responsePaths);
@@ -142,14 +143,13 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
{
foreach (string arg in flattenedArgs)
{
- string? name, value;
- if (TryParseOption(arg, out name, out value) && (name == "ruleset"))
+ if (IsOption("ruleset", arg, out ReadOnlyMemory name, out ReadOnlyMemory? value))
{
var unquoted = RemoveQuotesAndSlashes(value);
if (RoslynString.IsNullOrEmpty(unquoted))
{
- AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "", name);
+ AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "", name.ToString());
}
else
{
@@ -164,13 +164,18 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
{
Debug.Assert(optionsEnded || !arg.StartsWith("@", StringComparison.Ordinal));
- string? name, value;
- if (optionsEnded || !TryParseOption(arg, out name, out value))
+ ArrayBuilder filePathBuilder;
+ ReadOnlyMemory nameMemory;
+ ReadOnlyMemory? valueMemory;
+ if (optionsEnded || !TryParseOption(arg, out nameMemory, out valueMemory))
{
- foreach (var path in ParseFileArgument(arg, baseDirectory, diagnostics))
+ filePathBuilder = ArrayBuilder.GetInstance();
+ ParseFileArgument(arg.AsMemory(), baseDirectory, filePathBuilder, diagnostics);
+ foreach (var path in filePathBuilder)
{
sourceFiles.Add(ToCommandLineSourceFile(path));
}
+ filePathBuilder.Free();
if (sourceFiles.Count > 0)
{
@@ -180,6 +185,68 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
}
+ string? value;
+ string? valueMemoryString() => valueMemory is { } m ? m.Span.ToString() : null;
+
+ // The main 'switch' for argument handling forces an allocation of the option name field. For the most
+ // common options we special case the handling below to avoid this allocation as it can contribute significantly
+ // to parsing allocations.
+ //
+ // When we allow for switching on Span this can be undone as the name 'switch' will be allocation free
+ // https://github.com/dotnet/roslyn/pull/44388
+ if (IsOptionName("r", "reference", nameMemory))
+ {
+ ParseAssemblyReferences(arg, valueMemory, diagnostics, embedInteropTypes: false, metadataReferences);
+ continue;
+ }
+ else if (IsOptionName("langversion", nameMemory))
+ {
+ value = RemoveQuotesAndSlashes(valueMemory);
+ if (RoslynString.IsNullOrEmpty(value))
+ {
+ AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_Text.Localize(), "/langversion:");
+ }
+ else if (value.StartsWith("0", StringComparison.Ordinal))
+ {
+ // This error was added in 7.1 to stop parsing versions as ints (behaviour in previous Roslyn compilers), and explicitly
+ // treat them as identifiers (behaviour in native compiler). This error helps users identify that breaking change.
+ AddDiagnostic(diagnostics, ErrorCode.ERR_LanguageVersionCannotHaveLeadingZeroes, value);
+ }
+ else if (value == "?")
+ {
+ displayLangVersions = true;
+ }
+ else if (!LanguageVersionFacts.TryParse(value, out languageVersion))
+ {
+ AddDiagnostic(diagnostics, ErrorCode.ERR_BadCompatMode, value);
+ }
+ continue;
+ }
+ else if (!IsScriptCommandLineParser && IsOptionName("a", "analyzer", nameMemory))
+ {
+ ParseAnalyzers(arg, valueMemory, analyzers, diagnostics);
+ continue;
+ }
+ else if (!IsScriptCommandLineParser && IsOptionName("nowarn", nameMemory))
+ {
+ if (valueMemory is null)
+ {
+ AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsNumber, nameMemory.ToString());
+ continue;
+ }
+
+ if (valueMemory.Value.Length == 0)
+ {
+ AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsNumber, nameMemory.ToString());
+ }
+ else
+ {
+ AddWarnings(noWarns, ReportDiagnostic.Suppress, valueMemory.Value);
+ }
+ continue;
+ }
+
+ string name = nameMemory.Span.ToString().ToLowerInvariant();
switch (name)
{
case "?":
@@ -191,34 +258,8 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
displayVersion = true;
continue;
- case "langversion":
- value = RemoveQuotesAndSlashes(value);
- if (RoslynString.IsNullOrEmpty(value))
- {
- AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_Text.Localize(), "/langversion:");
- }
- else if (value.StartsWith("0", StringComparison.Ordinal))
- {
- // This error was added in 7.1 to stop parsing versions as ints (behaviour in previous Roslyn compilers), and explicitly
- // treat them as identifiers (behaviour in native compiler). This error helps users identify that breaking change.
- AddDiagnostic(diagnostics, ErrorCode.ERR_LanguageVersionCannotHaveLeadingZeroes, value);
- }
- else if (value == "?")
- {
- displayLangVersions = true;
- }
- else if (!LanguageVersionFacts.TryParse(value, out languageVersion))
- {
- AddDiagnostic(diagnostics, ErrorCode.ERR_BadCompatMode, value);
- }
- continue;
-
- case "r":
- case "reference":
- metadataReferences.AddRange(ParseAssemblyReferences(arg, value, diagnostics, embedInteropTypes: false));
- continue;
-
case "features":
+ value = valueMemoryString();
if (value == null)
{
features.Clear();
@@ -232,7 +273,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "lib":
case "libpath":
case "libpaths":
- ParseAndResolveReferencePaths(name, value, baseDirectory, libPaths, MessageID.IDS_LIB_OPTION, diagnostics);
+ ParseAndResolveReferencePaths(name, valueMemory, baseDirectory, libPaths, MessageID.IDS_LIB_OPTION, diagnostics);
continue;
#if DEBUG
@@ -244,6 +285,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
if (IsScriptCommandLineParser)
{
+ value = valueMemoryString();
switch (name)
{
case "-": // csi -- script.csx
@@ -279,7 +321,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "loadpath":
case "loadpaths":
- ParseAndResolveReferencePaths(name, value, baseDirectory, sourcePaths, MessageID.IDS_REFERENCEPATH_OPTION, diagnostics);
+ ParseAndResolveReferencePaths(name, valueMemory, baseDirectory, sourcePaths, MessageID.IDS_REFERENCEPATH_OPTION, diagnostics);
continue;
case "u":
@@ -295,26 +337,21 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
{
switch (name)
{
- case "a":
- case "analyzer":
- analyzers.AddRange(ParseAnalyzers(arg, value, diagnostics));
- continue;
-
case "d":
case "define":
- if (RoslynString.IsNullOrEmpty(value))
+ if (valueMemory is not { Length: > 0 })
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "", arg);
continue;
}
IEnumerable defineDiagnostics;
- defines.AddRange(ParseConditionalCompilationSymbols(RemoveQuotesAndSlashes(value), out defineDiagnostics));
+ ParseConditionalCompilationSymbols(RemoveQuotesAndSlashesEx(valueMemory.Value), defines, out defineDiagnostics);
diagnostics.AddRange(defineDiagnostics);
continue;
case "codepage":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
if (value == null)
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "", name);
@@ -332,13 +369,14 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "checksumalgorithm":
- if (RoslynString.IsNullOrEmpty(value))
+ value = valueMemoryString();
+ if (string.IsNullOrEmpty(value))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "", name);
continue;
}
- var newChecksumAlgorithm = TryParseHashAlgorithmName(value);
+ var newChecksumAlgorithm = TryParseHashAlgorithmName(value!);
if (newChecksumAlgorithm == SourceHashAlgorithm.None)
{
AddDiagnostic(diagnostics, ErrorCode.FTL_BadChecksumAlgorithm, value);
@@ -350,7 +388,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "checked":
case "checked+":
- if (value != null)
+ if (valueMemory is not null)
{
break;
}
@@ -359,7 +397,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "checked-":
- if (value != null)
+ if (valueMemory is not null)
break;
checkOverflow = false;
@@ -367,7 +405,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "nullable":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
if (value != null)
{
if (value.IsEmpty())
@@ -408,7 +446,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "nullable+":
- if (value != null)
+ if (valueMemory is not null)
{
break;
}
@@ -417,14 +455,14 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "nullable-":
- if (value != null)
+ if (valueMemory is not null)
break;
nullableContextOptions = NullableContextOptions.Disable;
continue;
case "instrument":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
if (RoslynString.IsNullOrEmpty(value))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "", name);
@@ -448,7 +486,8 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "sqmsessionguid":
// The use of SQM is deprecated in the compiler but we still support the parsing of the option for
- // back compat reasons.
+ // back compat reason
+ value = valueMemoryString();
if (value == null)
{
AddDiagnostic(diagnostics, ErrorCode.ERR_MissingGuidForOption, "", name);
@@ -464,7 +503,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "preferreduilang":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
if (RoslynString.IsNullOrEmpty(value))
{
@@ -498,6 +537,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "out":
+ value = valueMemoryString();
if (RoslynString.IsNullOrWhiteSpace(value))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, arg);
@@ -510,7 +550,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "refout":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
if (RoslynString.IsNullOrEmpty(value))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, arg);
@@ -523,7 +563,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "refonly":
- if (value != null)
+ if (valueMemory is not null)
break;
refOnly = true;
@@ -531,6 +571,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "t":
case "target":
+ value = valueMemoryString();
if (value == null)
{
break; // force 'unrecognized option'
@@ -548,6 +589,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "moduleassemblyname":
+ value = valueMemoryString();
value = value != null ? value.Unquote() : null;
if (RoslynString.IsNullOrEmpty(value))
@@ -567,7 +609,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "modulename":
- var unquotedModuleName = RemoveQuotesAndSlashes(value);
+ var unquotedModuleName = RemoveQuotesAndSlashes(valueMemory);
if (string.IsNullOrEmpty(unquotedModuleName))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_Text.Localize(), "modulename");
@@ -581,7 +623,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "platform":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
if (RoslynString.IsNullOrEmpty(value))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "", arg);
@@ -593,7 +635,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "recurse":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
if (value == null)
{
@@ -615,7 +657,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "generatedfilesout":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
if (string.IsNullOrWhiteSpace(value))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_Text.Localize(), arg);
@@ -628,12 +670,13 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "doc":
parseDocumentationComments = true;
+ value = valueMemoryString();
if (RoslynString.IsNullOrEmpty(value))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_Text.Localize(), arg);
continue;
}
- string? unquoted = RemoveQuotesAndSlashes(value);
+ string? unquoted = RemoveQuotesAndSlashes(valueMemory);
if (RoslynString.IsNullOrEmpty(unquoted))
{
// CONSIDER: This diagnostic exactly matches dev11, but it would be simpler (and more consistent with /out)
@@ -647,11 +690,12 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "addmodule":
+ value = valueMemoryString();
if (value == null)
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_Text.Localize(), "/addmodule:");
}
- else if (string.IsNullOrEmpty(value))
+ else if (value.Length == 0)
{
AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, arg);
}
@@ -667,19 +711,19 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "l":
case "link":
- metadataReferences.AddRange(ParseAssemblyReferences(arg, value, diagnostics, embedInteropTypes: true));
+ ParseAssemblyReferences(arg, valueMemory, diagnostics, embedInteropTypes: true, metadataReferences);
continue;
case "win32res":
- win32ResourceFile = GetWin32Setting(arg, value, diagnostics);
+ win32ResourceFile = GetWin32Setting(arg, valueMemoryString(), diagnostics);
continue;
case "win32icon":
- win32IconFile = GetWin32Setting(arg, value, diagnostics);
+ win32IconFile = GetWin32Setting(arg, valueMemoryString(), diagnostics);
continue;
case "win32manifest":
- win32ManifestFile = GetWin32Setting(arg, value, diagnostics);
+ win32ManifestFile = GetWin32Setting(arg, valueMemoryString(), diagnostics);
noWin32Manifest = false;
continue;
@@ -690,12 +734,12 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "res":
case "resource":
- if (value == null)
+ if (valueMemory is null)
{
break; // Dev11 reports unrecognized option
}
- var embeddedResource = ParseResourceDescription(arg, value, baseDirectory, diagnostics, embedded: true);
+ var embeddedResource = ParseResourceDescription(arg, valueMemory.Value, baseDirectory, diagnostics, embedded: true);
if (embeddedResource != null)
{
managedResources.Add(embeddedResource);
@@ -706,12 +750,12 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "linkres":
case "linkresource":
- if (value == null)
+ if (valueMemory is null)
{
break; // Dev11 reports unrecognized option
}
- var linkedResource = ParseResourceDescription(arg, value, baseDirectory, diagnostics, embedded: false);
+ var linkedResource = ParseResourceDescription(arg, valueMemory.Value, baseDirectory, diagnostics, embedded: false);
if (linkedResource != null)
{
managedResources.Add(linkedResource);
@@ -721,7 +765,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "sourcelink":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
if (RoslynString.IsNullOrEmpty(value))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, arg);
@@ -736,7 +780,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
emitPdb = true;
// unused, parsed for backward compat only
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
if (value != null)
{
if (value.IsEmpty())
@@ -765,7 +809,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "debug+":
//guard against "debug+:xx"
- if (value != null)
+ if (valueMemory is not null)
break;
emitPdb = true;
@@ -773,7 +817,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "debug-":
- if (value != null)
+ if (valueMemory is not null)
break;
emitPdb = false;
@@ -784,7 +828,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "optimize":
case "o+":
case "optimize+":
- if (value != null)
+ if (valueMemory is not null)
break;
optimize = true;
@@ -792,7 +836,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "o-":
case "optimize-":
- if (value != null)
+ if (valueMemory is not null)
break;
optimize = false;
@@ -800,14 +844,14 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "deterministic":
case "deterministic+":
- if (value != null)
+ if (valueMemory is not null)
break;
deterministic = true;
continue;
case "deterministic-":
- if (value != null)
+ if (valueMemory is not null)
break;
deterministic = false;
continue;
@@ -816,7 +860,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "parallel":
case "p+":
case "parallel+":
- if (value != null)
+ if (valueMemory is not null)
break;
concurrentBuild = true;
@@ -824,7 +868,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "p-":
case "parallel-":
- if (value != null)
+ if (valueMemory is not null)
break;
concurrentBuild = false;
@@ -832,7 +876,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "warnaserror":
case "warnaserror+":
- if (value == null)
+ if (valueMemory is null)
{
generalDiagnosticOption = ReportDiagnostic.Error;
@@ -850,18 +894,18 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
}
- if (string.IsNullOrEmpty(value))
+ if (valueMemory.Value.Length == 0)
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsNumber, name);
}
else
{
- AddWarnings(warnAsErrors, ReportDiagnostic.Error, ParseWarnings(value));
+ AddWarnings(warnAsErrors, ReportDiagnostic.Error, valueMemory.Value);
}
continue;
case "warnaserror-":
- if (value == null)
+ if (valueMemory is null)
{
generalDiagnosticOption = ReportDiagnostic.Default;
@@ -871,13 +915,15 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
}
- if (string.IsNullOrEmpty(value))
+ if (valueMemory is not { Length: > 0 })
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsNumber, name);
}
else
{
- foreach (var id in ParseWarnings(value))
+ var builder = ArrayBuilder.GetInstance();
+ ParseWarnings(valueMemory.Value, builder);
+ foreach (var id in builder)
{
ReportDiagnostic ruleSetValue;
if (diagnosticOptions.TryGetValue(id, out ruleSetValue))
@@ -889,12 +935,13 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
warnAsErrors[id] = ReportDiagnostic.Default;
}
}
+ builder.Free();
}
continue;
case "w":
case "warn":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
if (value == null)
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsNumber, name);
@@ -917,33 +964,16 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
}
continue;
- case "nowarn":
- if (value == null)
- {
- AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsNumber, name);
- continue;
- }
-
- if (string.IsNullOrEmpty(value))
- {
- AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsNumber, name);
- }
- else
- {
- AddWarnings(noWarns, ReportDiagnostic.Suppress, ParseWarnings(value));
- }
- continue;
-
case "unsafe":
case "unsafe+":
- if (value != null)
+ if (valueMemory is not null)
break;
allowUnsafe = true;
continue;
case "unsafe-":
- if (value != null)
+ if (valueMemory is not null)
break;
allowUnsafe = false;
@@ -951,7 +981,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "delaysign":
case "delaysign+":
- if (value != null)
+ if (valueMemory is not null)
{
break;
}
@@ -960,7 +990,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "delaysign-":
- if (value != null)
+ if (valueMemory is not null)
{
break;
}
@@ -970,7 +1000,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "publicsign":
case "publicsign+":
- if (value != null)
+ if (valueMemory is not null)
{
break;
}
@@ -979,7 +1009,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "publicsign-":
- if (value != null)
+ if (valueMemory is not null)
{
break;
}
@@ -988,7 +1018,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "keyfile":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
if (string.IsNullOrEmpty(value))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, "keyfile");
@@ -1009,6 +1039,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "keycontainer":
+ value = valueMemoryString();
if (string.IsNullOrEmpty(value))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_Text.Localize(), "keycontainer");
@@ -1030,14 +1061,14 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "highentropyva":
case "highentropyva+":
- if (value != null)
+ if (valueMemory is not null)
break;
highEntropyVA = true;
continue;
case "highentropyva-":
- if (value != null)
+ if (valueMemory is not null)
break;
highEntropyVA = false;
@@ -1048,7 +1079,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "baseaddress":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
ulong newBaseAddress;
if (string.IsNullOrEmpty(value) || !TryParseUInt64(value, out newBaseAddress))
@@ -1070,6 +1101,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "subsystemversion":
+ value = valueMemoryString();
if (RoslynString.IsNullOrEmpty(value))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_Text.Localize(), "subsystemversion");
@@ -1090,7 +1122,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "touchedfiles":
- unquoted = RemoveQuotesAndSlashes(value);
+ unquoted = RemoveQuotesAndSlashes(valueMemory);
if (string.IsNullOrEmpty(unquoted))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_Text.Localize(), "touchedfiles");
@@ -1108,7 +1140,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "utf8output":
- if (value != null)
+ if (valueMemory is not null)
break;
utf8output = true;
@@ -1118,7 +1150,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "main":
// Remove any quotes for consistent behavior as MSBuild can return quoted or
// unquoted main.
- unquoted = RemoveQuotesAndSlashes(value);
+ unquoted = RemoveQuotesAndSlashes(valueMemory);
if (string.IsNullOrEmpty(unquoted))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "", name);
@@ -1129,7 +1161,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "fullpaths":
- if (value != null)
+ if (valueMemory is not null)
break;
printFullPaths = true;
@@ -1138,7 +1170,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "pathmap":
// "/pathmap:K1=V1,K2=V2..."
{
- unquoted = RemoveQuotesAndSlashes(value);
+ unquoted = RemoveQuotesAndSlashes(valueMemory);
if (unquoted == null)
{
@@ -1150,7 +1182,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "filealign":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
ushort newAlignment;
if (RoslynString.IsNullOrEmpty(value))
@@ -1172,7 +1204,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "pdb":
- value = RemoveQuotesAndSlashes(value);
+ value = RemoveQuotesAndSlashes(valueMemory);
if (RoslynString.IsNullOrEmpty(value))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, arg);
@@ -1193,14 +1225,14 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "skipanalyzers":
case "skipanalyzers+":
- if (value != null)
+ if (valueMemory is not null)
break;
skipAnalyzers = true;
continue;
case "skipanalyzers-":
- if (value != null)
+ if (valueMemory is not null)
break;
skipAnalyzers = false;
@@ -1208,14 +1240,14 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
case "nostdlib":
case "nostdlib+":
- if (value != null)
+ if (valueMemory is not null)
break;
noStdLib = true;
continue;
case "nostdlib-":
- if (value != null)
+ if (valueMemory is not null)
break;
noStdLib = false;
@@ -1225,23 +1257,23 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "errorlog":
- unquoted = RemoveQuotesAndSlashes(value);
- if (RoslynString.IsNullOrEmpty(unquoted))
+ valueMemory = RemoveQuotesAndSlashesEx(valueMemory);
+ if (valueMemory is not { Length: > 0 })
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, ErrorLogOptionFormat, RemoveQuotesAndSlashes(arg));
}
else
{
- errorLogOptions = ParseErrorLogOptions(unquoted, diagnostics, baseDirectory, out bool diagnosticAlreadyReported);
+ errorLogOptions = ParseErrorLogOptions(valueMemory.Value, diagnostics, baseDirectory, out bool diagnosticAlreadyReported);
if (errorLogOptions == null && !diagnosticAlreadyReported)
{
- AddDiagnostic(diagnostics, ErrorCode.ERR_BadSwitchValue, unquoted, "/errorlog:", ErrorLogOptionFormat);
+ AddDiagnostic(diagnostics, ErrorCode.ERR_BadSwitchValue, valueMemory.Value.ToString(), "/errorlog:", ErrorLogOptionFormat);
}
}
continue;
case "appconfig":
- unquoted = RemoveQuotesAndSlashes(value);
+ unquoted = RemoveQuotesAndSlashes(valueMemory);
if (RoslynString.IsNullOrEmpty(unquoted))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, ":", RemoveQuotesAndSlashes(arg));
@@ -1253,7 +1285,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "runtimemetadataversion":
- unquoted = RemoveQuotesAndSlashes(value);
+ unquoted = RemoveQuotesAndSlashes(valueMemory);
if (string.IsNullOrEmpty(unquoted))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "", name);
@@ -1268,39 +1300,48 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
continue;
case "additionalfile":
- if (RoslynString.IsNullOrEmpty(value))
+ if (valueMemory is not { Length: > 0 })
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "", name);
continue;
}
- foreach (var path in ParseSeparatedFileArgument(value, baseDirectory, diagnostics))
+ filePathBuilder = ArrayBuilder.GetInstance();
+ ParseSeparatedFileArgument(valueMemory.Value, baseDirectory, filePathBuilder, diagnostics);
+ foreach (var path in filePathBuilder)
{
additionalFiles.Add(ToCommandLineSourceFile(path));
}
+ filePathBuilder.Free();
continue;
-
case "analyzerconfig":
- if (RoslynString.IsNullOrEmpty(value))
+ if (valueMemory is not { Length: > 0 })
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, "", name);
continue;
}
- analyzerConfigPaths.AddRange(ParseSeparatedFileArgument(value, baseDirectory, diagnostics));
+ filePathBuilder = ArrayBuilder.GetInstance();
+ ParseSeparatedFileArgument(valueMemory.Value, baseDirectory, filePathBuilder, diagnostics);
+ analyzerConfigPaths.AddRange(filePathBuilder);
+ filePathBuilder.Free();
continue;
case "embed":
+ value = valueMemoryString();
if (RoslynString.IsNullOrEmpty(value))
{
embedAllSourceFiles = true;
continue;
}
- foreach (var path in ParseSeparatedFileArgument(value, baseDirectory, diagnostics))
+ filePathBuilder = ArrayBuilder.GetInstance();
+ ParseSeparatedFileArgument(value.AsMemory(), baseDirectory, filePathBuilder, diagnostics);
+ foreach (var path in filePathBuilder)
{
embeddedFiles.Add(ToCommandLineSourceFile(path));
}
+ filePathBuilder.Free();
continue;
case "-":
@@ -1363,7 +1404,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
// add additional reference paths if specified
if (!string.IsNullOrEmpty(additionalReferenceDirectories))
{
- ParseAndResolveReferencePaths(null, additionalReferenceDirectories, baseDirectory, libPaths, MessageID.IDS_LIB_ENV, diagnostics);
+ ParseAndResolveReferencePaths(null, additionalReferenceDirectories.AsMemory(), baseDirectory, libPaths, MessageID.IDS_LIB_ENV, diagnostics);
}
ImmutableArray referencePaths = BuildSearchPaths(sdkDirectory, libPaths, responsePaths);
@@ -1412,6 +1453,8 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
string? compilationName;
GetCompilationAndModuleNames(diagnostics, outputKind, sourceFiles, sourceFilesSpecified, moduleAssemblyName, ref outputFileName, ref moduleName, out compilationName);
+ flattenedArgs.Free();
+
var parseOptions = new CSharpParseOptions
(
languageVersion: languageVersion,
@@ -1538,16 +1581,16 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar
};
}
- private static void ParseAndResolveReferencePaths(string? switchName, string? switchValue, string? baseDirectory, List builder, MessageID origin, List diagnostics)
+ private static void ParseAndResolveReferencePaths(string? switchName, ReadOnlyMemory? switchValue, string? baseDirectory, List builder, MessageID origin, List diagnostics)
{
- if (string.IsNullOrEmpty(switchValue))
+ if (switchValue is not { Length: > 0 })
{
RoslynDebug.Assert(!RoslynString.IsNullOrEmpty(switchName));
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_PathList.Localize(), switchName);
return;
}
- foreach (string path in ParseSeparatedPaths(switchValue))
+ foreach (string path in ParseSeparatedPaths(switchValue.Value.ToString()))
{
string? resolvedPath = FileUtilities.ResolveRelativePath(path, baseDirectory);
if (resolvedPath == null)
@@ -1688,35 +1731,55 @@ private ImmutableArray BuildSearchPaths(string? sdkDirectoryOpt, List ParseConditionalCompilationSymbols(string value, out IEnumerable diagnostics)
+ {
+ var builder = ArrayBuilder.GetInstance();
+ ParseConditionalCompilationSymbols(value.AsMemory(), builder, out diagnostics);
+ return builder.ToArrayAndFree();
+ }
+
+ internal static void ParseConditionalCompilationSymbols(ReadOnlyMemory valueMemory, ArrayBuilder defines, out IEnumerable diagnostics)
{
DiagnosticBag outputDiagnostics = DiagnosticBag.GetInstance();
- value = value.TrimEnd(null);
- // Allow a trailing semicolon or comma in the options
- if (!value.IsEmpty() &&
- (value.Last() == ';' || value.Last() == ','))
+ if (valueMemory.IsWhiteSpace())
{
- value = value.Substring(0, value.Length - 1);
+ outputDiagnostics.Add(Diagnostic.Create(CSharp.MessageProvider.Instance, (int)ErrorCode.WRN_DefineIdentifierRequired, valueMemory.ToString()));
+ diagnostics = outputDiagnostics.ToReadOnlyAndFree();
+ return;
}
- string[] values = value.Split(new char[] { ';', ',' } /*, StringSplitOptions.RemoveEmptyEntries*/);
- var defines = new ArrayBuilder(values.Length);
+ var valueSpan = valueMemory.Span;
+ var nextIndex = 0;
+ var index = 0;
+ while (index < valueSpan.Length)
+ {
+ if (valueSpan[index] is ';' or ',')
+ {
+ add();
+ nextIndex = index + 1;
+ }
+ index++;
+ }
- foreach (string id in values)
+ if (nextIndex < valueSpan.Length)
{
- string trimmedId = id.Trim();
- if (SyntaxFacts.IsValidIdentifier(trimmedId))
+ add();
+ }
+
+ void add()
+ {
+ var id = valueMemory.Slice(nextIndex, index - nextIndex).Trim().ToString();
+ if (SyntaxFacts.IsValidIdentifier(id))
{
- defines.Add(trimmedId);
+ defines.Add(id);
}
else
{
- outputDiagnostics.Add(Diagnostic.Create(CSharp.MessageProvider.Instance, (int)ErrorCode.WRN_DefineIdentifierRequired, trimmedId));
+ outputDiagnostics.Add(Diagnostic.Create(CSharp.MessageProvider.Instance, (int)ErrorCode.WRN_DefineIdentifierRequired, id));
}
}
diagnostics = outputDiagnostics.ToReadOnlyAndFree();
- return defines.AsEnumerable();
}
private static Platform ParsePlatform(string value, IList diagnostics)
@@ -1785,38 +1848,46 @@ private static IEnumerable ParseUsings(string arg, string? value, IList<
}
}
- private static IEnumerable ParseAnalyzers(string arg, string? value, List diagnostics)
+ private static void ParseAnalyzers(string arg, ReadOnlyMemory? valueMemory, List analyzerReferences, List diagnostics)
{
- if (value == null)
+ if (valueMemory is not { } value)
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_Text.Localize(), arg);
- yield break;
+ return;
}
else if (value.Length == 0)
{
AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, arg);
- yield break;
+ return;
}
- List paths = ParseSeparatedPaths(value).Where((path) => !string.IsNullOrWhiteSpace(path)).ToList();
-
- foreach (string path in paths)
+ var builder = ArrayBuilder>.GetInstance();
+ ParseSeparatedPathsEx(value, builder);
+ foreach (var path in builder)
{
- yield return new CommandLineAnalyzerReference(path);
+ if (path.Length == 0)
+ {
+ continue;
+ }
+
+ analyzerReferences.Add(new CommandLineAnalyzerReference(path.ToString()));
}
+ builder.Free();
}
- private static IEnumerable ParseAssemblyReferences(string arg, string? value, IList diagnostics, bool embedInteropTypes)
+ private static void ParseAssemblyReferences(string arg, ReadOnlyMemory? valueMemory, IList diagnostics, bool embedInteropTypes, List commandLineReferences)
{
- if (value == null)
+ if (valueMemory is null)
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_Text.Localize(), arg);
- yield break;
+ return;
}
- else if (value.Length == 0)
+
+ var value = valueMemory.Value;
+ if (value.Length == 0)
{
AddDiagnostic(diagnostics, ErrorCode.ERR_NoFileSpec, arg);
- yield break;
+ return;
}
// /r:"reference"
@@ -1829,18 +1900,19 @@ private static IEnumerable ParseAssemblyReferences(string
// /r:alias=reference;reference ... error 2034
// /r:nonidf=reference ... error 1679
- int eqlOrQuote = value.IndexOfAny(s_quoteOrEquals);
+ var valueSpan = value.Span;
+ int eqlOrQuote = valueSpan.IndexOfAny(s_quoteOrEquals);
string? alias;
- if (eqlOrQuote >= 0 && value[eqlOrQuote] == '=')
+ if (eqlOrQuote >= 0 && valueSpan[eqlOrQuote] == '=')
{
- alias = value.Substring(0, eqlOrQuote);
- value = value.Substring(eqlOrQuote + 1);
+ alias = value.Slice(0, eqlOrQuote).ToString();
+ value = value.Slice(eqlOrQuote + 1);
if (!SyntaxFacts.IsValidIdentifier(alias))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_BadExternIdentifier, alias);
- yield break;
+ return;
}
}
else
@@ -1848,31 +1920,42 @@ private static IEnumerable ParseAssemblyReferences(string
alias = null;
}
- List paths = ParseSeparatedPaths(value).Where((path) => !string.IsNullOrWhiteSpace(path)).ToList();
- if (alias != null)
+ var builder = ArrayBuilder>.GetInstance();
+ ParseSeparatedPathsEx(value, builder);
+ var pathCount = 0;
+ foreach (var path in builder)
{
- if (paths.Count > 1)
+ if (path.IsWhiteSpace())
{
- AddDiagnostic(diagnostics, ErrorCode.ERR_OneAliasPerReference, value);
- yield break;
+ continue;
}
- if (paths.Count == 0)
- {
- AddDiagnostic(diagnostics, ErrorCode.ERR_AliasMissingFile, alias);
- yield break;
- }
- }
+ pathCount++;
- foreach (string path in paths)
- {
// NOTE(tomat): Dev10 used to report CS1541: ERR_CantIncludeDirectory if the path was a directory.
// Since we now support /referencePaths option we would need to search them to see if the resolved path is a directory.
var aliases = (alias != null) ? ImmutableArray.Create(alias) : ImmutableArray.Empty;
var properties = new MetadataReferenceProperties(MetadataImageKind.Assembly, aliases, embedInteropTypes);
- yield return new CommandLineReference(path, properties);
+ commandLineReferences.Add(new CommandLineReference(path.ToString(), properties));
+ }
+ builder.Free();
+
+ if (alias != null)
+ {
+ if (pathCount > 1)
+ {
+ commandLineReferences.RemoveRange(commandLineReferences.Count - pathCount, pathCount);
+ AddDiagnostic(diagnostics, ErrorCode.ERR_OneAliasPerReference, value.ToString());
+ return;
+ }
+
+ if (pathCount == 0)
+ {
+ AddDiagnostic(diagnostics, ErrorCode.ERR_AliasMissingFile, alias);
+ return;
+ }
}
}
@@ -1920,6 +2003,14 @@ private static IEnumerable ParseInstrumentationKinds(string
string resourceDescriptor,
string? baseDirectory,
IList diagnostics,
+ bool embedded) =>
+ ParseResourceDescription(arg, resourceDescriptor.AsMemory(), baseDirectory, diagnostics, embedded);
+
+ internal static ResourceDescription? ParseResourceDescription(
+ string arg,
+ ReadOnlyMemory resourceDescriptor,
+ string? baseDirectory,
+ IList diagnostics,
bool embedded)
{
string? filePath;
@@ -1981,27 +2072,33 @@ private static IEnumerable ParseInstrumentationKinds(string
return new ResourceDescription(resourceName, fileName, dataProvider, isPublic, embedded, checkArgs: false);
}
- private static IEnumerable ParseWarnings(string value)
+ private static void ParseWarnings(ReadOnlyMemory value, ArrayBuilder ids)
{
value = value.Unquote();
- string[] values = value.Split(new char[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries);
- foreach (string id in values)
+ var parts = ArrayBuilder>.GetInstance();
+
+ var nullableSpan = "nullable".AsSpan();
+ ParseSeparatedStrings(value, s_warningSeparators, removeEmptyEntries: true, parts);
+ foreach (ReadOnlyMemory part in parts)
{
- if (string.Equals(id, "nullable", StringComparison.OrdinalIgnoreCase))
+ if (part.Span.Equals(nullableSpan, StringComparison.OrdinalIgnoreCase))
{
foreach (var errorCode in ErrorFacts.NullableWarnings)
{
- yield return errorCode;
+ ids.Add(errorCode);
}
- yield return CSharp.MessageProvider.Instance.GetIdForErrorCode((int)ErrorCode.WRN_MissingNonNullTypesContextForAnnotation);
- yield return CSharp.MessageProvider.Instance.GetIdForErrorCode((int)ErrorCode.WRN_MissingNonNullTypesContextForAnnotationInGeneratedCode);
+ ids.Add(CSharp.MessageProvider.Instance.GetIdForErrorCode((int)ErrorCode.WRN_MissingNonNullTypesContextForAnnotation));
+ ids.Add(CSharp.MessageProvider.Instance.GetIdForErrorCode((int)ErrorCode.WRN_MissingNonNullTypesContextForAnnotationInGeneratedCode));
+ continue;
}
- else if (ushort.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out ushort number) &&
+
+ var id = part.ToString();
+ if (ushort.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out ushort number) &&
ErrorFacts.IsWarning((ErrorCode)number))
{
// The id refers to a compiler warning.
- yield return CSharp.MessageProvider.Instance.GetIdForErrorCode(number);
+ ids.Add(CSharp.MessageProvider.Instance.GetIdForErrorCode(number));
}
else
{
@@ -2009,14 +2106,18 @@ private static IEnumerable ParseWarnings(string value)
// whenever an unrecognized warning code was supplied in /nowarn or
// /warnaserror. We no longer generate a warning in such cases.
// Instead we assume that the unrecognized id refers to a custom diagnostic.
- yield return id;
+ ids.Add(id);
}
}
+
+ parts.Free();
}
- private static void AddWarnings(Dictionary d, ReportDiagnostic kind, IEnumerable items)
+ private static void AddWarnings(Dictionary d, ReportDiagnostic kind, ReadOnlyMemory warningArgument)
{
- foreach (var id in items)
+ var idsBuilder = ArrayBuilder.GetInstance();
+ ParseWarnings(warningArgument, idsBuilder);
+ foreach (var id in idsBuilder)
{
ReportDiagnostic existing;
if (d.TryGetValue(id, out existing))
@@ -2030,6 +2131,8 @@ private static void AddWarnings(Dictionary d, ReportDi
d.Add(id, kind);
}
}
+
+ idsBuilder.Free();
}
private static void UnimplementedSwitch(IList diagnostics, string switchName)
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
index 38d21fdfa5b58..edd35b8bcf802 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
@@ -1980,7 +1980,8 @@ internal enum ErrorCode
ERR_MultipleFileScopedNamespace = 8954,
ERR_FileScopedAndNormalNamespace = 8955,
ERR_FileScopedNamespaceNotBeforeAllMembers = 8956,
- ERR_AttrTypeArgCannotBeTypeVar = 8957,
+ ERR_NoImplicitConvTargetTypedConditional = 8957,
+ ERR_AttrTypeArgCannotBeTypeVar = 8958,
#endregion
diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
index b3273752e7006..000b5ebaddde1 100644
--- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs
+++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
@@ -229,7 +229,7 @@ internal enum MessageID
IDS_FeatureStaticAbstractMembersInInterfaces = MessageBase + 12803,
IDS_FeatureLambdaReturnType = MessageBase + 12804,
IDS_AsyncMethodBuilderOverride = MessageBase + 12805,
- IDS_FeatureImplicitImplementationOfNonPublicMemebers = MessageBase + 12806,
+ IDS_FeatureImplicitImplementationOfNonPublicMembers = MessageBase + 12806,
IDS_FeatureLineSpanDirective = MessageBase + 12807,
IDS_FeatureImprovedInterpolatedStrings = MessageBase + 12808,
IDS_FeatureFileScopedNamespace = MessageBase + 12809,
@@ -359,7 +359,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
case MessageID.IDS_FeatureLambdaReturnType: // semantic check
case MessageID.IDS_AsyncMethodBuilderOverride: // semantic check
case MessageID.IDS_FeatureConstantInterpolatedStrings: // semantic check
- case MessageID.IDS_FeatureImplicitImplementationOfNonPublicMemebers: // semantic check
+ case MessageID.IDS_FeatureImplicitImplementationOfNonPublicMembers: // semantic check
case MessageID.IDS_FeatureLineSpanDirective:
case MessageID.IDS_FeatureFileScopedNamespace: // syntax check
case MessageID.IDS_FeatureGenericAttributes: // semantic check
diff --git a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs
index f90f3fe486e9c..95c1c0d50f5f7 100644
--- a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs
@@ -1039,6 +1039,17 @@ public BoundLiteral StringLiteral(String stringValue)
return StringLiteral(ConstantValue.Create(stringValue));
}
+ public BoundLiteral CharLiteral(ConstantValue charConst)
+ {
+ Debug.Assert(charConst.IsChar || charConst.IsDefaultValue);
+ return new BoundLiteral(Syntax, charConst, SpecialType(Microsoft.CodeAnalysis.SpecialType.System_Char)) { WasCompilerGenerated = true };
+ }
+
+ public BoundLiteral CharLiteral(Char charValue)
+ {
+ return CharLiteral(ConstantValue.Create(charValue));
+ }
+
public BoundArrayLength ArrayLength(BoundExpression array)
{
Debug.Assert(array.Type is { TypeKind: TypeKind.Array });
diff --git a/src/Compilers/CSharp/Portable/Parser/Lexer.cs b/src/Compilers/CSharp/Portable/Parser/Lexer.cs
index 42af25f897c20..353f8ffda388b 100644
--- a/src/Compilers/CSharp/Portable/Parser/Lexer.cs
+++ b/src/Compilers/CSharp/Portable/Parser/Lexer.cs
@@ -440,7 +440,7 @@ private void ScanSyntaxToken(ref TokenInfo info)
{
case '\"':
case '\'':
- this.ScanStringLiteral(ref info);
+ this.ScanStringLiteral(ref info, inDirective: false);
break;
case '/':
@@ -2907,7 +2907,7 @@ private bool ScanDirectiveToken(ref TokenInfo info)
break;
case '\"':
- this.ScanStringLiteral(ref info, false);
+ this.ScanStringLiteral(ref info, inDirective: true);
break;
case '\\':
diff --git a/src/Compilers/CSharp/Portable/Parser/Lexer_StringLiteral.cs b/src/Compilers/CSharp/Portable/Parser/Lexer_StringLiteral.cs
index da04733e21f80..e7a04e322aaae 100644
--- a/src/Compilers/CSharp/Portable/Parser/Lexer_StringLiteral.cs
+++ b/src/Compilers/CSharp/Portable/Parser/Lexer_StringLiteral.cs
@@ -17,86 +17,82 @@ namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax
{
internal partial class Lexer
{
- private void ScanStringLiteral(ref TokenInfo info, bool allowEscapes = true)
+ private void ScanStringLiteral(ref TokenInfo info, bool inDirective)
{
var quoteCharacter = TextWindow.PeekChar();
- if (quoteCharacter == '\'' || quoteCharacter == '"')
+ Debug.Assert(quoteCharacter == '\'' || quoteCharacter == '"');
+
+ TextWindow.AdvanceChar();
+ _builder.Length = 0;
+
+ while (true)
{
- TextWindow.AdvanceChar();
- _builder.Length = 0;
- while (true)
+ char ch = TextWindow.PeekChar();
+
+ // Normal string & char constants can have escapes. Strings in directives cannot.
+ if (ch == '\\' && !inDirective)
{
- char ch = TextWindow.PeekChar();
- if (ch == '\\' && allowEscapes)
- {
- // normal string & char constants can have escapes
- char c2;
- ch = this.ScanEscapeSequence(out c2);
- _builder.Append(ch);
- if (c2 != SlidingTextWindow.InvalidCharacter)
- {
- _builder.Append(c2);
- }
- }
- else if (ch == quoteCharacter)
- {
- TextWindow.AdvanceChar();
- break;
- }
- else if (SyntaxFacts.IsNewLine(ch) ||
- (ch == SlidingTextWindow.InvalidCharacter && TextWindow.IsReallyAtEnd()))
- {
- //String and character literals can contain any Unicode character. They are not limited
- //to valid UTF-16 characters. So if we get the SlidingTextWindow's sentinel value,
- //double check that it was not real user-code contents. This will be rare.
- Debug.Assert(TextWindow.Width > 0);
- this.AddError(ErrorCode.ERR_NewlineInConst);
- break;
- }
- else
+ char c2;
+ ch = this.ScanEscapeSequence(out c2);
+ _builder.Append(ch);
+ if (c2 != SlidingTextWindow.InvalidCharacter)
{
- TextWindow.AdvanceChar();
- _builder.Append(ch);
+ _builder.Append(c2);
}
}
+ else if (ch == quoteCharacter)
+ {
+ TextWindow.AdvanceChar();
+ break;
+ }
+ else if (SyntaxFacts.IsNewLine(ch) ||
+ (ch == SlidingTextWindow.InvalidCharacter && TextWindow.IsReallyAtEnd()))
+ {
+ //String and character literals can contain any Unicode character. They are not limited
+ //to valid UTF-16 characters. So if we get the SlidingTextWindow's sentinel value,
+ //double check that it was not real user-code contents. This will be rare.
+ Debug.Assert(TextWindow.Width > 0);
+ this.AddError(ErrorCode.ERR_NewlineInConst);
+ break;
+ }
+ else
+ {
+ TextWindow.AdvanceChar();
+ _builder.Append(ch);
+ }
+ }
- info.Text = TextWindow.GetText(true);
- if (quoteCharacter == '\'')
+ info.Text = TextWindow.GetText(true);
+ if (quoteCharacter == '\'')
+ {
+ info.Kind = SyntaxKind.CharacterLiteralToken;
+ if (_builder.Length != 1)
{
- info.Kind = SyntaxKind.CharacterLiteralToken;
- if (_builder.Length != 1)
- {
- this.AddError((_builder.Length != 0) ? ErrorCode.ERR_TooManyCharsInConst : ErrorCode.ERR_EmptyCharConst);
- }
+ this.AddError((_builder.Length != 0) ? ErrorCode.ERR_TooManyCharsInConst : ErrorCode.ERR_EmptyCharConst);
+ }
- if (_builder.Length > 0)
- {
- info.StringValue = TextWindow.Intern(_builder);
- info.CharValue = info.StringValue[0];
- }
- else
- {
- info.StringValue = string.Empty;
- info.CharValue = SlidingTextWindow.InvalidCharacter;
- }
+ if (_builder.Length > 0)
+ {
+ info.StringValue = TextWindow.Intern(_builder);
+ info.CharValue = info.StringValue[0];
}
else
{
- info.Kind = SyntaxKind.StringLiteralToken;
- if (_builder.Length > 0)
- {
- info.StringValue = TextWindow.Intern(_builder);
- }
- else
- {
- info.StringValue = string.Empty;
- }
+ info.StringValue = string.Empty;
+ info.CharValue = SlidingTextWindow.InvalidCharacter;
}
}
else
{
- info.Kind = SyntaxKind.None;
- info.Text = null;
+ info.Kind = SyntaxKind.StringLiteralToken;
+ if (_builder.Length > 0)
+ {
+ info.StringValue = TextWindow.Intern(_builder);
+ }
+ else
+ {
+ info.StringValue = string.Empty;
+ }
}
}
@@ -294,60 +290,61 @@ internal static SyntaxToken RescanInterpolatedString(InterpolatedStringExpressio
private class InterpolatedStringScanner
{
- public readonly Lexer lexer;
- public bool isVerbatim;
- public bool allowNewlines;
+ private readonly Lexer _lexer;
+ private bool _isVerbatim;
+ private bool _allowNewlines;
public SyntaxDiagnosticInfo error;
+
public InterpolatedStringScanner(
Lexer lexer,
bool isVerbatim)
{
- this.lexer = lexer;
- this.isVerbatim = isVerbatim;
- this.allowNewlines = isVerbatim;
+ this._lexer = lexer;
+ this._isVerbatim = isVerbatim;
+ this._allowNewlines = isVerbatim;
}
private bool IsAtEnd()
{
- return IsAtEnd(isVerbatim && allowNewlines);
+ return IsAtEnd(_isVerbatim && _allowNewlines);
}
private bool IsAtEnd(bool allowNewline)
{
- char ch = lexer.TextWindow.PeekChar();
+ char ch = _lexer.TextWindow.PeekChar();
return
!allowNewline && SyntaxFacts.IsNewLine(ch) ||
- (ch == SlidingTextWindow.InvalidCharacter && lexer.TextWindow.IsReallyAtEnd());
+ (ch == SlidingTextWindow.InvalidCharacter && _lexer.TextWindow.IsReallyAtEnd());
}
internal void ScanInterpolatedStringLiteralTop(ArrayBuilder interpolations, ref TokenInfo info, out bool closeQuoteMissing)
{
- if (isVerbatim)
+ if (_isVerbatim)
{
Debug.Assert(
- (lexer.TextWindow.PeekChar() == '@' && lexer.TextWindow.PeekChar(1) == '$') ||
- (lexer.TextWindow.PeekChar() == '$' && lexer.TextWindow.PeekChar(1) == '@'));
+ (_lexer.TextWindow.PeekChar() == '@' && _lexer.TextWindow.PeekChar(1) == '$') ||
+ (_lexer.TextWindow.PeekChar() == '$' && _lexer.TextWindow.PeekChar(1) == '@'));
// @$ or $@
- lexer.TextWindow.AdvanceChar();
- lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
}
else
{
- Debug.Assert(lexer.TextWindow.PeekChar() == '$');
- lexer.TextWindow.AdvanceChar(); // $
+ Debug.Assert(_lexer.TextWindow.PeekChar() == '$');
+ _lexer.TextWindow.AdvanceChar(); // $
}
- Debug.Assert(lexer.TextWindow.PeekChar() == '"');
- lexer.TextWindow.AdvanceChar(); // "
+ Debug.Assert(_lexer.TextWindow.PeekChar() == '"');
+ _lexer.TextWindow.AdvanceChar(); // "
ScanInterpolatedStringLiteralContents(interpolations);
- if (lexer.TextWindow.PeekChar() != '"')
+ if (_lexer.TextWindow.PeekChar() != '"')
{
Debug.Assert(IsAtEnd());
if (error == null)
{
- int position = IsAtEnd(true) ? lexer.TextWindow.Position - 1 : lexer.TextWindow.Position;
- error = lexer.MakeError(position, 1, isVerbatim ? ErrorCode.ERR_UnterminatedStringLit : ErrorCode.ERR_NewlineInConst);
+ int position = IsAtEnd(true) ? _lexer.TextWindow.Position - 1 : _lexer.TextWindow.Position;
+ error = _lexer.MakeError(position, 1, _isVerbatim ? ErrorCode.ERR_UnterminatedStringLit : ErrorCode.ERR_NewlineInConst);
}
closeQuoteMissing = true;
@@ -355,7 +352,7 @@ internal void ScanInterpolatedStringLiteralTop(ArrayBuilder inter
else
{
// found the closing quote
- lexer.TextWindow.AdvanceChar(); // "
+ _lexer.TextWindow.AdvanceChar(); // "
closeQuoteMissing = false;
}
@@ -372,7 +369,7 @@ private void ScanInterpolatedStringLiteralContents(ArrayBuilder i
return;
}
- switch (lexer.TextWindow.PeekChar())
+ switch (_lexer.TextWindow.PeekChar())
{
case '"' when RecoveringFromRunawayLexing():
// When recovering from mismatched delimiters, we consume the next
@@ -381,51 +378,51 @@ private void ScanInterpolatedStringLiteralContents(ArrayBuilder i
// See, for example, https://github.com/dotnet/roslyn/issues/44789
return;
case '"':
- if (isVerbatim && lexer.TextWindow.PeekChar(1) == '"')
+ if (_isVerbatim && _lexer.TextWindow.PeekChar(1) == '"')
{
- lexer.TextWindow.AdvanceChar(); // "
- lexer.TextWindow.AdvanceChar(); // "
+ _lexer.TextWindow.AdvanceChar(); // "
+ _lexer.TextWindow.AdvanceChar(); // "
continue;
}
// found the end of the string
return;
case '}':
- var pos = lexer.TextWindow.Position;
- lexer.TextWindow.AdvanceChar(); // }
+ var pos = _lexer.TextWindow.Position;
+ _lexer.TextWindow.AdvanceChar(); // }
// ensure any } characters are doubled up
- if (lexer.TextWindow.PeekChar() == '}')
+ if (_lexer.TextWindow.PeekChar() == '}')
{
- lexer.TextWindow.AdvanceChar(); // }
+ _lexer.TextWindow.AdvanceChar(); // }
}
else if (error == null)
{
- error = lexer.MakeError(pos, 1, ErrorCode.ERR_UnescapedCurly, "}");
+ error = _lexer.MakeError(pos, 1, ErrorCode.ERR_UnescapedCurly, "}");
}
continue;
case '{':
- if (lexer.TextWindow.PeekChar(1) == '{')
+ if (_lexer.TextWindow.PeekChar(1) == '{')
{
- lexer.TextWindow.AdvanceChar();
- lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
}
else
{
- int openBracePosition = lexer.TextWindow.Position;
- lexer.TextWindow.AdvanceChar();
+ int openBracePosition = _lexer.TextWindow.Position;
+ _lexer.TextWindow.AdvanceChar();
int colonPosition = 0;
ScanInterpolatedStringLiteralHoleBalancedText('}', true, ref colonPosition);
- int closeBracePosition = lexer.TextWindow.Position;
+ int closeBracePosition = _lexer.TextWindow.Position;
bool closeBraceMissing = false;
- if (lexer.TextWindow.PeekChar() == '}')
+ if (_lexer.TextWindow.PeekChar() == '}')
{
- lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
}
else
{
closeBraceMissing = true;
if (error == null)
{
- error = lexer.MakeError(openBracePosition - 1, 2, ErrorCode.ERR_UnclosedExpressionHole);
+ error = _lexer.MakeError(openBracePosition - 1, 2, ErrorCode.ERR_UnclosedExpressionHole);
}
}
@@ -433,23 +430,23 @@ private void ScanInterpolatedStringLiteralContents(ArrayBuilder i
}
continue;
case '\\':
- if (isVerbatim)
+ if (_isVerbatim)
{
goto default;
}
- var escapeStart = lexer.TextWindow.Position;
+ var escapeStart = _lexer.TextWindow.Position;
char c2;
- char ch = lexer.ScanEscapeSequence(out c2);
+ char ch = _lexer.ScanEscapeSequence(out c2);
if ((ch == '{' || ch == '}') && error == null)
{
- error = lexer.MakeError(escapeStart, lexer.TextWindow.Position - escapeStart, ErrorCode.ERR_EscapedCurly, ch);
+ error = _lexer.MakeError(escapeStart, _lexer.TextWindow.Position - escapeStart, ErrorCode.ERR_EscapedCurly, ch);
}
continue;
default:
// found some other character in the string portion
- lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
continue;
}
}
@@ -457,28 +454,28 @@ private void ScanInterpolatedStringLiteralContents(ArrayBuilder i
private void ScanFormatSpecifier()
{
- Debug.Assert(lexer.TextWindow.PeekChar() == ':');
- lexer.TextWindow.AdvanceChar();
+ Debug.Assert(_lexer.TextWindow.PeekChar() == ':');
+ _lexer.TextWindow.AdvanceChar();
while (true)
{
- char ch = lexer.TextWindow.PeekChar();
- if (ch == '\\' && !isVerbatim)
+ char ch = _lexer.TextWindow.PeekChar();
+ if (ch == '\\' && !_isVerbatim)
{
// normal string & char constants can have escapes
- var pos = lexer.TextWindow.Position;
+ var pos = _lexer.TextWindow.Position;
char c2;
- ch = lexer.ScanEscapeSequence(out c2);
+ ch = _lexer.ScanEscapeSequence(out c2);
if ((ch == '{' || ch == '}') && error == null)
{
- error = lexer.MakeError(pos, 1, ErrorCode.ERR_EscapedCurly, ch);
+ error = _lexer.MakeError(pos, 1, ErrorCode.ERR_EscapedCurly, ch);
}
}
else if (ch == '"')
{
- if (isVerbatim && lexer.TextWindow.PeekChar(1) == '"')
+ if (_isVerbatim && _lexer.TextWindow.PeekChar(1) == '"')
{
- lexer.TextWindow.AdvanceChar();
- lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
}
else
{
@@ -487,24 +484,24 @@ private void ScanFormatSpecifier()
}
else if (ch == '{')
{
- var pos = lexer.TextWindow.Position;
- lexer.TextWindow.AdvanceChar();
+ var pos = _lexer.TextWindow.Position;
+ _lexer.TextWindow.AdvanceChar();
// ensure any { characters are doubled up
- if (lexer.TextWindow.PeekChar() == '{')
+ if (_lexer.TextWindow.PeekChar() == '{')
{
- lexer.TextWindow.AdvanceChar(); // {
+ _lexer.TextWindow.AdvanceChar(); // {
}
else if (error == null)
{
- error = lexer.MakeError(pos, 1, ErrorCode.ERR_UnescapedCurly, "{");
+ error = _lexer.MakeError(pos, 1, ErrorCode.ERR_UnescapedCurly, "{");
}
}
else if (ch == '}')
{
- if (lexer.TextWindow.PeekChar(1) == '}')
+ if (_lexer.TextWindow.PeekChar(1) == '}')
{
- lexer.TextWindow.AdvanceChar();
- lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
}
else
{
@@ -517,7 +514,7 @@ private void ScanFormatSpecifier()
}
else
{
- lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
}
}
}
@@ -535,37 +532,37 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool
return;
}
- char ch = lexer.TextWindow.PeekChar();
+ char ch = _lexer.TextWindow.PeekChar();
switch (ch)
{
case '#':
// preprocessor directives not allowed.
if (error == null)
{
- error = lexer.MakeError(lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString());
+ error = _lexer.MakeError(_lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString());
}
- lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
continue;
case '$':
- if (lexer.TextWindow.PeekChar(1) == '"' || lexer.TextWindow.PeekChar(1) == '@' && lexer.TextWindow.PeekChar(2) == '"')
+ if (_lexer.TextWindow.PeekChar(1) == '"' || _lexer.TextWindow.PeekChar(1) == '@' && _lexer.TextWindow.PeekChar(2) == '"')
{
- bool isVerbatimSubstring = lexer.TextWindow.PeekChar(1) == '@';
+ bool isVerbatimSubstring = _lexer.TextWindow.PeekChar(1) == '@';
var interpolations = (ArrayBuilder)null;
var info = default(TokenInfo);
- bool wasVerbatim = this.isVerbatim;
- bool wasAllowNewlines = this.allowNewlines;
+ bool wasVerbatim = this._isVerbatim;
+ bool wasAllowNewlines = this._allowNewlines;
try
{
- this.isVerbatim = isVerbatimSubstring;
- this.allowNewlines &= isVerbatim;
+ this._isVerbatim = isVerbatimSubstring;
+ this._allowNewlines &= _isVerbatim;
bool closeQuoteMissing;
ScanInterpolatedStringLiteralTop(interpolations, ref info, out closeQuoteMissing);
}
finally
{
- this.isVerbatim = wasVerbatim;
- this.allowNewlines = wasAllowNewlines;
+ this._isVerbatim = wasVerbatim;
+ this._allowNewlines = wasAllowNewlines;
}
continue;
}
@@ -576,7 +573,7 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool
if (isHole)
{
Debug.Assert(colonPosition == 0);
- colonPosition = lexer.TextWindow.Position;
+ colonPosition = _lexer.TextWindow.Position;
ScanFormatSpecifier();
return;
}
@@ -592,7 +589,7 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool
if (error == null)
{
- error = lexer.MakeError(lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString());
+ error = _lexer.MakeError(_lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString());
}
goto default;
@@ -608,46 +605,46 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool
ScanInterpolatedStringLiteralNestedString();
continue;
case '@':
- if (lexer.TextWindow.PeekChar(1) == '"' && !RecoveringFromRunawayLexing())
+ if (_lexer.TextWindow.PeekChar(1) == '"' && !RecoveringFromRunawayLexing())
{
// check for verbatim string inside an expression hole.
ScanInterpolatedStringLiteralNestedVerbatimString();
continue;
}
- else if (lexer.TextWindow.PeekChar(1) == '$' && lexer.TextWindow.PeekChar(2) == '"')
+ else if (_lexer.TextWindow.PeekChar(1) == '$' && _lexer.TextWindow.PeekChar(2) == '"')
{
- lexer.CheckFeatureAvailability(MessageID.IDS_FeatureAltInterpolatedVerbatimStrings);
+ _lexer.CheckFeatureAvailability(MessageID.IDS_FeatureAltInterpolatedVerbatimStrings);
var interpolations = (ArrayBuilder)null;
var info = default(TokenInfo);
- bool wasVerbatim = this.isVerbatim;
- bool wasAllowNewlines = this.allowNewlines;
+ bool wasVerbatim = this._isVerbatim;
+ bool wasAllowNewlines = this._allowNewlines;
try
{
- this.isVerbatim = true;
- this.allowNewlines = true;
+ this._isVerbatim = true;
+ this._allowNewlines = true;
bool closeQuoteMissing;
ScanInterpolatedStringLiteralTop(interpolations, ref info, out closeQuoteMissing);
}
finally
{
- this.isVerbatim = wasVerbatim;
- this.allowNewlines = wasAllowNewlines;
+ this._isVerbatim = wasVerbatim;
+ this._allowNewlines = wasAllowNewlines;
}
continue;
}
goto default;
case '/':
- switch (lexer.TextWindow.PeekChar(1))
+ switch (_lexer.TextWindow.PeekChar(1))
{
case '/':
- if (isVerbatim && allowNewlines)
+ if (_isVerbatim && _allowNewlines)
{
- lexer.TextWindow.AdvanceChar(); // skip /
- lexer.TextWindow.AdvanceChar(); // skip /
+ _lexer.TextWindow.AdvanceChar(); // skip /
+ _lexer.TextWindow.AdvanceChar(); // skip /
while (!IsAtEnd(false))
{
- lexer.TextWindow.AdvanceChar(); // skip // comment character
+ _lexer.TextWindow.AdvanceChar(); // skip // comment character
}
}
else
@@ -655,11 +652,11 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool
// error: single-line comment not allowed in an interpolated string
if (error == null)
{
- error = lexer.MakeError(lexer.TextWindow.Position, 2, ErrorCode.ERR_SingleLineCommentInExpressionHole);
+ error = _lexer.MakeError(_lexer.TextWindow.Position, 2, ErrorCode.ERR_SingleLineCommentInExpressionHole);
}
- lexer.TextWindow.AdvanceChar();
- lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
}
continue;
case '*':
@@ -667,7 +664,7 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool
ScanInterpolatedStringLiteralNestedComment();
continue;
default:
- lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
continue;
}
case '{':
@@ -684,7 +681,7 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool
continue;
default:
// part of code in the expression hole
- lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
continue;
}
}
@@ -698,10 +695,10 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool
private void ScanInterpolatedStringLiteralNestedComment()
{
- Debug.Assert(lexer.TextWindow.PeekChar() == '/');
- lexer.TextWindow.AdvanceChar();
- Debug.Assert(lexer.TextWindow.PeekChar() == '*');
- lexer.TextWindow.AdvanceChar();
+ Debug.Assert(_lexer.TextWindow.PeekChar() == '/');
+ _lexer.TextWindow.AdvanceChar();
+ Debug.Assert(_lexer.TextWindow.PeekChar() == '*');
+ _lexer.TextWindow.AdvanceChar();
while (true)
{
if (IsAtEnd())
@@ -709,11 +706,11 @@ private void ScanInterpolatedStringLiteralNestedComment()
return; // let the caller complain about the unterminated quote
}
- var ch = lexer.TextWindow.PeekChar();
- lexer.TextWindow.AdvanceChar();
- if (ch == '*' && lexer.TextWindow.PeekChar() == '/')
+ var ch = _lexer.TextWindow.PeekChar();
+ _lexer.TextWindow.AdvanceChar();
+ if (ch == '*' && _lexer.TextWindow.PeekChar() == '/')
{
- lexer.TextWindow.AdvanceChar(); // skip */
+ _lexer.TextWindow.AdvanceChar(); // skip */
return;
}
}
@@ -722,24 +719,24 @@ private void ScanInterpolatedStringLiteralNestedComment()
private void ScanInterpolatedStringLiteralNestedString()
{
var discarded = default(TokenInfo);
- lexer.ScanStringLiteral(ref discarded, true);
+ _lexer.ScanStringLiteral(ref discarded, inDirective: false);
}
private void ScanInterpolatedStringLiteralNestedVerbatimString()
{
var discarded = default(TokenInfo);
- lexer.ScanVerbatimStringLiteral(ref discarded, allowNewlines: allowNewlines);
+ _lexer.ScanVerbatimStringLiteral(ref discarded, _allowNewlines);
}
private void ScanInterpolatedStringLiteralHoleBracketed(char start, char end)
{
- Debug.Assert(start == lexer.TextWindow.PeekChar());
- lexer.TextWindow.AdvanceChar();
+ Debug.Assert(start == _lexer.TextWindow.PeekChar());
+ _lexer.TextWindow.AdvanceChar();
int colon = 0;
ScanInterpolatedStringLiteralHoleBalancedText(end, false, ref colon);
- if (lexer.TextWindow.PeekChar() == end)
+ if (_lexer.TextWindow.PeekChar() == end)
{
- lexer.TextWindow.AdvanceChar();
+ _lexer.TextWindow.AdvanceChar();
}
else
{
diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPrintMembers.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPrintMembers.cs
index 3f05883416741..5f5e6acfb6b1d 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPrintMembers.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPrintMembers.cs
@@ -162,14 +162,20 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
for (var i = 0; i < printableMembers.Length; i++)
{
- // builder.Append();
- // builder.Append(" = ");
- // builder.Append((object)); OR builder.Append(.ToString()); for value types
- // builder.Append(", "); // except for last member
+ // builder.Append(", = "); // if previous members exist
+ // builder.Append(" = "); // if it is the first member
+
+ // The only printable members are fields and properties,
+ // which cannot be generic so as to have variant names
var member = printableMembers[i];
- block.Add(makeAppendString(F, builder, member.Name));
- block.Add(makeAppendString(F, builder, " = "));
+ var memberHeader = $"{member.Name} = ";
+ if (i > 0)
+ {
+ memberHeader = ", " + memberHeader;
+ }
+
+ block.Add(makeAppendString(F, builder, memberHeader));
var value = member.Kind switch
{
@@ -178,6 +184,8 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
_ => throw ExceptionUtilities.UnexpectedValue(member.Kind)
};
+ // builder.Append((object)); OR builder.Append(.ToString()); for value types
+
Debug.Assert(value.Type is not null);
if (value.Type.IsValueType)
{
@@ -193,11 +201,6 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
F.WellKnownMethod(WellKnownMember.System_Text_StringBuilder__AppendObject),
F.Convert(F.SpecialType(SpecialType.System_Object), value))));
}
-
- if (i < printableMembers.Length - 1)
- {
- block.Add(makeAppendString(F, builder, ", "));
- }
}
block.Add(F.Return(F.Literal(true)));
diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordToString.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordToString.cs
index 17f70250dc4fe..28ff426445f4a 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordToString.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordToString.cs
@@ -66,11 +66,11 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
// builder.Append(" { ");
block.Add(makeAppendString(F, builderLocal, " { "));
- // if (this.PrintMembers(builder)) builder.Append(" ");
- block.Add(F.If(F.Call(F.This(), _printMethod, builderLocal), makeAppendString(F, builderLocal, " ")));
+ // if (this.PrintMembers(builder)) builder.Append(' ');
+ block.Add(F.If(F.Call(F.This(), _printMethod, builderLocal), makeAppendChar(F, builderLocal, ' ')));
- // builder.Append("}");
- block.Add(makeAppendString(F, builderLocal, "}"));
+ // builder.Append('}');
+ block.Add(makeAppendChar(F, builderLocal, '}'));
// return builder.ToString();
block.Add(F.Return(F.Call(builderLocal, F.SpecialMethod(SpecialMember.System_Object__ToString))));
@@ -87,6 +87,11 @@ static BoundStatement makeAppendString(SyntheticBoundNodeFactory F, BoundLocal b
{
return F.ExpressionStatement(F.Call(receiver: builder, F.WellKnownMethod(WellKnownMember.System_Text_StringBuilder__AppendString), F.StringLiteral(value)));
}
+
+ static BoundStatement makeAppendChar(SyntheticBoundNodeFactory F, BoundLocal builder, char value)
+ {
+ return F.ExpressionStatement(F.Call(receiver: builder, F.WellKnownMethod(WellKnownMember.System_Text_StringBuilder__AppendChar), F.CharLiteral(value)));
+ }
}
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs
index 755781e851806..3f8dae9399887 100644
--- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs
@@ -567,7 +567,7 @@ public virtual bool IsAnonymousType
/// Verify if the given type is a tuple of a given cardinality, or can be used to back a tuple type
/// with the given cardinality.
///
- public bool IsTupleTypeOfCardinality(int targetCardinality)
+ internal bool IsTupleTypeOfCardinality(int targetCardinality)
{
if (IsTupleType)
{
@@ -1007,7 +1007,7 @@ private static Symbol ComputeImplementationForInterfaceMember(Symbol interfaceMe
if (interfaceMember.Kind == SymbolKind.Method &&
(object)implementingBaseOpt == null) // Otherwise any approprite errors are going to be reported for the base.
{
- LanguageVersion requiredVersion = MessageID.IDS_FeatureImplicitImplementationOfNonPublicMemebers.RequiredVersion();
+ LanguageVersion requiredVersion = MessageID.IDS_FeatureImplicitImplementationOfNonPublicMembers.RequiredVersion();
LanguageVersion? availableVersion = implementingType.DeclaringCompilation?.LanguageVersion;
if (requiredVersion > availableVersion)
{
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
index 6dce0699bab19..dc7b51a2fadaa 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
@@ -827,6 +827,11 @@
V základním typu {0} se nenašel žádný přístupný kopírovací konstruktor.
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
+
Output directory could not be determined
Nepovedlo se určit výstupní adresář.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
index 394976f076936..58003a5db8cd5 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
@@ -827,6 +827,11 @@
Im Basistyp "{0}" wurde kein zugänglicher Kopierkonstruktor gefunden.
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
+
Output directory could not be determined
Das Ausgabeverzeichnis konnte nicht bestimmt werden.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
index b23615d2e4d2c..ede3e02613fe0 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
@@ -827,6 +827,11 @@
No se encontró ningún constructor de copia accesible en el tipo de base "{0}".
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
+
Output directory could not be determined
No se pudo determinar el directorio de salida.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
index e448ee074be50..a1af83dc73d33 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
@@ -827,6 +827,11 @@
Aucun constructeur de copie accessible n'a été trouvé dans le type de base '{0}'.
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
+
Output directory could not be determined
Impossible de déterminer le répertoire de sortie
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
index 158b6c38f6640..c36fc6623d863 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
@@ -827,6 +827,11 @@
Non è stato trovato alcun costruttore di copia accessibile nel tipo di base '{0}'.
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
+
Output directory could not be determined
Non è stato possibile individuare la directory di output
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
index f58205c7d66a7..9281c593f523b 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
@@ -827,6 +827,11 @@
基本型 '{0}' にアクセス可能なコピー コンストラクターが見つかりませんでした。
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
+
Output directory could not be determined
出力ディレクトリを特定できませんでした
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
index cac56c7b486ec..2601999542983 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
@@ -827,6 +827,11 @@
기본 형식 '{0}'에 액세스 가능한 복사 생성자가 없습니다.
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
+
Output directory could not be determined
출력 디렉터리를 확인할 수 없습니다.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
index c88af13137e65..834f1cbcd38de 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
@@ -827,6 +827,11 @@
W typie podstawowym „{0}” nie znaleziono dostępnego konstruktora kopiującego.
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
+
Output directory could not be determined
Nie można było określić katalogu wyjściowego
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
index c02b4151d8222..2b064a7ce0964 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
@@ -827,6 +827,11 @@
Não foi encontrado nenhum construtor de cópia acessível no tipo base '{0}'.
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
+
Output directory could not be determined
Não foi possível determinar o diretório de saída
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
index c2e68d13e07a3..e30bb79e6190d 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
@@ -827,6 +827,11 @@
Доступный конструктор копий не найден в базовом типе "{0}".
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
+
Output directory could not be determined
Не удалось определить выходной каталог
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
index 0a0cd4d39dd7d..20b1ae05dbcfe 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
@@ -827,6 +827,11 @@
'{0}' temel türünde erişilebilir kopya oluşturucu bulunamadı.
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
+
Output directory could not be determined
Çıkış dizini belirlenemedi
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
index e385fddc16c18..bfaaedc130264 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
@@ -827,6 +827,11 @@
在基类型“{0}”中找不到可访问的复制构造函数。
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
+
Output directory could not be determined
无法确定输出目录
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
index 9d6053fdcb056..ac1b5d2e5501b 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
@@ -827,6 +827,11 @@
在基底類型 '{0}' 中找不到可存取的複製建構函式。
+
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+ Conditional expression is not valid in language version {0} because a common type was not found between '{1}' and '{2}'. To use a target-typed conversion, upgrade to language version {3} or greater.
+
+
Output directory could not be determined
無法判斷輸出目錄
diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
index bc35ca5830830..05fa00db21656 100644
--- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
+++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
@@ -25,6 +25,7 @@
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Emit;
+using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Test.Resources.Proprietary;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
@@ -936,7 +937,7 @@ public void ParseResources()
Assert.Null(desc);
diags.Clear();
- desc = CSharpCommandLineParser.ParseResourceDescription("", null, WorkingDirectory, diags, embedded: false);
+ desc = CSharpCommandLineParser.ParseResourceDescription("", (string)null, WorkingDirectory, diags, embedded: false);
diags.Verify(Diagnostic(ErrorCode.ERR_NoFileSpec).WithArguments(""));
Assert.Null(desc);
diags.Clear();
@@ -6209,6 +6210,63 @@ static int Main()
CleanupAllGeneratedFiles(rsp);
}
+ [Fact]
+ public void ResponseFileOrdering()
+ {
+ var rspFilePath1 = Temp.CreateFile().WriteAllText(@"
+/b
+/c
+").Path;
+
+ assertOrder(
+ new[] { "/a", "/b", "/c", "/d" },
+ new[] { "/a", @$"@""{rspFilePath1}""", "/d" });
+
+ var rspFilePath2 = Temp.CreateFile().WriteAllText(@"
+/c
+/d
+").Path;
+
+ rspFilePath1 = Temp.CreateFile().WriteAllText(@$"
+/b
+@""{rspFilePath2}""
+").Path;
+
+ assertOrder(
+ new[] { "/a", "/b", "/c", "/d", "/e" },
+ new[] { "/a", @$"@""{rspFilePath1}""", "/e" });
+
+ rspFilePath1 = Temp.CreateFile().WriteAllText(@$"
+/b
+").Path;
+
+ rspFilePath2 = Temp.CreateFile().WriteAllText(@"
+# this will be ignored
+/c
+/d
+").Path;
+
+ assertOrder(
+ new[] { "/a", "/b", "/c", "/d", "/e" },
+ new[] { "/a", @$"@""{rspFilePath1}""", $@"@""{rspFilePath2}""", "/e" });
+
+ void assertOrder(string[] expected, string[] args)
+ {
+ var flattenedArgs = ArrayBuilder.GetInstance();
+ var diagnostics = new List();
+ CSharpCommandLineParser.Default.FlattenArgs(
+ args,
+ diagnostics,
+ flattenedArgs,
+ scriptArgsOpt: null,
+ baseDirectory: Path.DirectorySeparatorChar == '\\' ? @"c:\" : "/");
+
+ Assert.Empty(diagnostics);
+ Assert.Equal(expected, flattenedArgs);
+ flattenedArgs.Free();
+ }
+ }
+
[WorkItem(545832, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545832")]
[Fact]
public void ResponseFilesWithEmptyAliasReference2()
diff --git a/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs
index 78acdc77f3244..3aeed8be822f1 100644
--- a/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs
@@ -902,23 +902,23 @@ private static void CompareAssemblies(string sourceTemplate, string change1, str
string name = GetUniqueName();
string source1 = sourceTemplate.Replace("CHANGE", change1);
CSharpCompilation comp1 = CreateCompilation(Parse(source1), options: TestOptions.DebugDll.WithDeterministic(true), assemblyName: name);
- ImmutableArray image1 = comp1.EmitToArray(EmitOptions.Default.WithEmitMetadataOnly(true).WithIncludePrivateMembers(includePrivateMembers));
+ var image1 = comp1.EmitToStream(EmitOptions.Default.WithEmitMetadataOnly(true).WithIncludePrivateMembers(includePrivateMembers));
var source2 = sourceTemplate.Replace("CHANGE", change2);
Compilation comp2 = CreateCompilation(Parse(source2), options: TestOptions.DebugDll.WithDeterministic(true), assemblyName: name);
- ImmutableArray image2 = comp2.EmitToArray(EmitOptions.Default.WithEmitMetadataOnly(true).WithIncludePrivateMembers(includePrivateMembers));
+ var image2 = comp2.EmitToStream(EmitOptions.Default.WithEmitMetadataOnly(true).WithIncludePrivateMembers(includePrivateMembers));
if (expectMatch)
{
- AssertEx.Equal(image1, image2, message: $"Expecting match for includePrivateMembers={includePrivateMembers} case, but differences were found.");
+ AssertEx.Equal(image1.GetBuffer(), image2.GetBuffer(), message: $"Expecting match for includePrivateMembers={includePrivateMembers} case, but differences were found.");
}
else
{
- AssertEx.NotEqual(image1, image2, message: $"Expecting difference for includePrivateMembers={includePrivateMembers} case, but they matched.");
+ AssertEx.NotEqual(image1.GetBuffer(), image2.GetBuffer(), message: $"Expecting difference for includePrivateMembers={includePrivateMembers} case, but they matched.");
}
- var mvid1 = BuildTasks.MvidReader.ReadAssemblyMvidOrEmpty(new MemoryStream(image1.DangerousGetUnderlyingArray()));
- var mvid2 = BuildTasks.MvidReader.ReadAssemblyMvidOrEmpty(new MemoryStream(image2.DangerousGetUnderlyingArray()));
+ var mvid1 = BuildTasks.MvidReader.ReadAssemblyMvidOrEmpty(image1);
+ var mvid2 = BuildTasks.MvidReader.ReadAssemblyMvidOrEmpty(image2);
if (!includePrivateMembers)
{
diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IThrowOperation.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IThrowOperation.cs
index 06b66d0f38179..5b91f5e895754 100644
--- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IThrowOperation.cs
+++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IThrowOperation.cs
@@ -2171,9 +2171,9 @@ void F(bool x, bool y, System.Exception ex1, System.Exception ex2)
var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular8);
compilation.VerifyDiagnostics(
- // (6,13): error CS8400: Feature 'target-typed conditional expression' is not available in C# 8.0. Please use language version 9.0 or greater.
+ // (6,13): error CS8957: Conditional expression is not valid in language version 8.0 because a common type was not found between '' and ''. To use a target-typed conversion, upgrade to language version 9.0 or greater.
// x = y ? throw ex1 : throw ex2;
- Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "y ? throw ex1 : throw ex2").WithArguments("target-typed conditional expression", "9.0").WithLocation(6, 13)
+ Diagnostic(ErrorCode.ERR_NoImplicitConvTargetTypedConditional, "y ? throw ex1 : throw ex2").WithArguments("8.0", "", "", "9.0").WithLocation(6, 13)
);
string expectedOperationTree = @"
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs
index 75948efc9befc..54b8e0e62cd7d 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs
@@ -2054,6 +2054,7 @@ public class Attribute { }
public class String { }
public struct Void { }
public struct Boolean { }
+ public struct Char { }
public struct Int32 { }
public interface IEquatable { }
}
@@ -2070,7 +2071,8 @@ namespace System.Text
public class StringBuilder
{
public StringBuilder Append(string s) => null;
- public StringBuilder Append(object s) => null;
+ public StringBuilder Append(char c) => null;
+ public StringBuilder Append(object o) => null;
}
}
";
@@ -2146,6 +2148,7 @@ public class Attribute { }
public class String { }
public struct Void { }
public struct Boolean { }
+ public struct Char { }
public struct Int32 { }
public interface IEquatable { }
}
@@ -2162,7 +2165,8 @@ namespace System.Text
public class StringBuilder
{
public StringBuilder Append(string s) => null;
- public StringBuilder Append(object s) => null;
+ public StringBuilder Append(char c) => null;
+ public StringBuilder Append(object o) => null;
}
}
";
@@ -4069,6 +4073,7 @@ public class Attribute { }
public class String { }
public struct Void { }
public struct Boolean { }
+ public struct Char { }
public struct Int32 { }
public interface IEquatable { }
}
@@ -4085,7 +4090,8 @@ namespace System.Text
public class StringBuilder
{
public StringBuilder Append(string s) => null;
- public StringBuilder Append(object s) => null;
+ public StringBuilder Append(char c) => null;
+ public StringBuilder Append(object o) => null;
}
}
";
@@ -4320,6 +4326,7 @@ public class Attribute { }
public class String { }
public struct Void { }
public struct Boolean { }
+ public struct Char { }
public struct Int32 { }
public interface IEquatable { }
}
@@ -4336,7 +4343,8 @@ namespace System.Text
public class StringBuilder
{
public StringBuilder Append(string s) => null;
- public StringBuilder Append(object s) => null;
+ public StringBuilder Append(char c) => null;
+ public StringBuilder Append(object o) => null;
}
}
";
@@ -4707,7 +4715,7 @@ .maxstack 1
");
v.VerifyIL("C1." + WellKnownMemberNames.ObjectToString, @"
{
- // Code size 70 (0x46)
+ // Code size 64 (0x40)
.maxstack 2
.locals init (System.Text.StringBuilder V_0)
IL_0000: newobj ""System.Text.StringBuilder..ctor()""
@@ -4723,18 +4731,18 @@ .locals init (System.Text.StringBuilder V_0)
IL_001e: ldarg.0
IL_001f: ldloc.0
IL_0020: call ""bool C1.PrintMembers(System.Text.StringBuilder)""
- IL_0025: brfalse.s IL_0033
+ IL_0025: brfalse.s IL_0030
IL_0027: ldloc.0
- IL_0028: ldstr "" ""
- IL_002d: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0032: pop
- IL_0033: ldloc.0
- IL_0034: ldstr ""}""
- IL_0039: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_003e: pop
- IL_003f: ldloc.0
- IL_0040: callvirt ""string object.ToString()""
- IL_0045: ret
+ IL_0028: ldc.i4.s 32
+ IL_002a: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
+ IL_002f: pop
+ IL_0030: ldloc.0
+ IL_0031: ldc.i4.s 125
+ IL_0033: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
+ IL_0038: pop
+ IL_0039: ldloc.0
+ IL_003a: callvirt ""string object.ToString()""
+ IL_003f: ret
}
");
}
@@ -4903,25 +4911,21 @@ record struct C1
v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
- // Code size 50 (0x32)
+ // Code size 38 (0x26)
.maxstack 2
IL_0000: ldarg.1
- IL_0001: ldstr ""field""
+ IL_0001: ldstr ""field = ""
IL_0006: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_000b: pop
IL_000c: ldarg.1
- IL_000d: ldstr "" = ""
- IL_0012: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0017: pop
- IL_0018: ldarg.1
- IL_0019: ldarg.0
- IL_001a: ldflda ""int C1.field""
- IL_001f: constrained. ""int""
- IL_0025: callvirt ""string object.ToString()""
- IL_002a: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_002f: pop
- IL_0030: ldc.i4.1
- IL_0031: ret
+ IL_000d: ldarg.0
+ IL_000e: ldflda ""int C1.field""
+ IL_0013: constrained. ""int""
+ IL_0019: callvirt ""string object.ToString()""
+ IL_001e: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
+ IL_0023: pop
+ IL_0024: ldc.i4.1
+ IL_0025: ret
}
");
}
@@ -4945,25 +4949,21 @@ record struct C1 where T : struct
v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
- // Code size 50 (0x32)
+ // Code size 38 (0x26)
.maxstack 2
IL_0000: ldarg.1
- IL_0001: ldstr ""field""
+ IL_0001: ldstr ""field = ""
IL_0006: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_000b: pop
IL_000c: ldarg.1
- IL_000d: ldstr "" = ""
- IL_0012: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0017: pop
- IL_0018: ldarg.1
- IL_0019: ldarg.0
- IL_001a: ldflda ""T C1.field""
- IL_001f: constrained. ""T""
- IL_0025: callvirt ""string object.ToString()""
- IL_002a: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_002f: pop
- IL_0030: ldc.i4.1
- IL_0031: ret
+ IL_000d: ldarg.0
+ IL_000e: ldflda ""T C1.field""
+ IL_0013: constrained. ""T""
+ IL_0019: callvirt ""string object.ToString()""
+ IL_001e: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
+ IL_0023: pop
+ IL_0024: ldc.i4.1
+ IL_0025: ret
}
");
}
@@ -4987,23 +4987,19 @@ record struct C1
v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
- // Code size 39 (0x27)
+ // Code size 27 (0x1b)
.maxstack 2
IL_0000: ldarg.1
- IL_0001: ldstr ""field""
+ IL_0001: ldstr ""field = ""
IL_0006: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_000b: pop
IL_000c: ldarg.1
- IL_000d: ldstr "" = ""
- IL_0012: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0017: pop
- IL_0018: ldarg.1
- IL_0019: ldarg.0
- IL_001a: ldfld ""string C1.field""
- IL_001f: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
- IL_0024: pop
- IL_0025: ldc.i4.1
- IL_0026: ret
+ IL_000d: ldarg.0
+ IL_000e: ldfld ""string C1.field""
+ IL_0013: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
+ IL_0018: pop
+ IL_0019: ldc.i4.1
+ IL_001a: ret
}
");
}
@@ -5035,62 +5031,42 @@ record struct C1(int I)
v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
- // Code size 151 (0x97)
+ // Code size 91 (0x5b)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.1
- IL_0001: ldstr ""I""
+ IL_0001: ldstr ""I = ""
IL_0006: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_000b: pop
IL_000c: ldarg.1
- IL_000d: ldstr "" = ""
- IL_0012: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0017: pop
- IL_0018: ldarg.1
- IL_0019: ldarg.0
- IL_001a: call ""readonly int C1.I.get""
- IL_001f: stloc.0
- IL_0020: ldloca.s V_0
- IL_0022: constrained. ""int""
- IL_0028: callvirt ""string object.ToString()""
+ IL_000d: ldarg.0
+ IL_000e: call ""readonly int C1.I.get""
+ IL_0013: stloc.0
+ IL_0014: ldloca.s V_0
+ IL_0016: constrained. ""int""
+ IL_001c: callvirt ""string object.ToString()""
+ IL_0021: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
+ IL_0026: pop
+ IL_0027: ldarg.1
+ IL_0028: ldstr "", field1 = ""
IL_002d: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_0032: pop
IL_0033: ldarg.1
- IL_0034: ldstr "", ""
- IL_0039: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_003e: pop
- IL_003f: ldarg.1
- IL_0040: ldstr ""field1""
- IL_0045: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_004a: pop
- IL_004b: ldarg.1
- IL_004c: ldstr "" = ""
- IL_0051: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0056: pop
- IL_0057: ldarg.1
- IL_0058: ldarg.0
- IL_0059: ldfld ""string C1.field1""
- IL_005e: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
- IL_0063: pop
- IL_0064: ldarg.1
- IL_0065: ldstr "", ""
- IL_006a: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_006f: pop
- IL_0070: ldarg.1
- IL_0071: ldstr ""field2""
- IL_0076: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_007b: pop
- IL_007c: ldarg.1
- IL_007d: ldstr "" = ""
- IL_0082: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0087: pop
- IL_0088: ldarg.1
- IL_0089: ldarg.0
- IL_008a: ldfld ""string C1.field2""
- IL_008f: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
- IL_0094: pop
- IL_0095: ldc.i4.1
- IL_0096: ret
+ IL_0034: ldarg.0
+ IL_0035: ldfld ""string C1.field1""
+ IL_003a: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
+ IL_003f: pop
+ IL_0040: ldarg.1
+ IL_0041: ldstr "", field2 = ""
+ IL_0046: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
+ IL_004b: pop
+ IL_004c: ldarg.1
+ IL_004d: ldarg.0
+ IL_004e: ldfld ""string C1.field2""
+ IL_0053: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
+ IL_0058: pop
+ IL_0059: ldc.i4.1
+ IL_005a: ret
}
");
}
@@ -5111,33 +5087,29 @@ public void ToString_TopLevelRecord_Readonly()
v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
- // Code size 53 (0x35)
+ // Code size 41 (0x29)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.1
- IL_0001: ldstr ""I""
+ IL_0001: ldstr ""I = ""
IL_0006: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_000b: pop
IL_000c: ldarg.1
- IL_000d: ldstr "" = ""
- IL_0012: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0017: pop
- IL_0018: ldarg.1
- IL_0019: ldarg.0
- IL_001a: call ""int C1.I.get""
- IL_001f: stloc.0
- IL_0020: ldloca.s V_0
- IL_0022: constrained. ""int""
- IL_0028: callvirt ""string object.ToString()""
- IL_002d: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0032: pop
- IL_0033: ldc.i4.1
- IL_0034: ret
+ IL_000d: ldarg.0
+ IL_000e: call ""int C1.I.get""
+ IL_0013: stloc.0
+ IL_0014: ldloca.s V_0
+ IL_0016: constrained. ""int""
+ IL_001c: callvirt ""string object.ToString()""
+ IL_0021: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
+ IL_0026: pop
+ IL_0027: ldc.i4.1
+ IL_0028: ret
}
");
v.VerifyIL("C1." + WellKnownMemberNames.ObjectToString, @"
{
- // Code size 70 (0x46)
+ // Code size 64 (0x40)
.maxstack 2
.locals init (System.Text.StringBuilder V_0)
IL_0000: newobj ""System.Text.StringBuilder..ctor()""
@@ -5153,18 +5125,18 @@ .locals init (System.Text.StringBuilder V_0)
IL_001e: ldarg.0
IL_001f: ldloc.0
IL_0020: call ""bool C1.PrintMembers(System.Text.StringBuilder)""
- IL_0025: brfalse.s IL_0033
+ IL_0025: brfalse.s IL_0030
IL_0027: ldloc.0
- IL_0028: ldstr "" ""
- IL_002d: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0032: pop
- IL_0033: ldloc.0
- IL_0034: ldstr ""}""
- IL_0039: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_003e: pop
- IL_003f: ldloc.0
- IL_0040: callvirt ""string object.ToString()""
- IL_0045: ret
+ IL_0028: ldc.i4.s 32
+ IL_002a: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
+ IL_002f: pop
+ IL_0030: ldloc.0
+ IL_0031: ldc.i4.s 125
+ IL_0033: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
+ IL_0038: pop
+ IL_0039: ldloc.0
+ IL_003a: callvirt ""string object.ToString()""
+ IL_003f: ret
}
");
}
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs
index 61a4ebe97e08e..b07b691f06556 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs
@@ -5000,7 +5000,7 @@ .maxstack 1
");
v.VerifyIL("C1." + WellKnownMemberNames.ObjectToString, @"
{
- // Code size 70 (0x46)
+ // Code size 64 (0x40)
.maxstack 2
.locals init (System.Text.StringBuilder V_0)
IL_0000: newobj ""System.Text.StringBuilder..ctor()""
@@ -5016,18 +5016,18 @@ .locals init (System.Text.StringBuilder V_0)
IL_001e: ldarg.0
IL_001f: ldloc.0
IL_0020: callvirt ""bool C1.PrintMembers(System.Text.StringBuilder)""
- IL_0025: brfalse.s IL_0033
+ IL_0025: brfalse.s IL_0030
IL_0027: ldloc.0
- IL_0028: ldstr "" ""
- IL_002d: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0032: pop
- IL_0033: ldloc.0
- IL_0034: ldstr ""}""
- IL_0039: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_003e: pop
- IL_003f: ldloc.0
- IL_0040: callvirt ""string object.ToString()""
- IL_0045: ret
+ IL_0028: ldc.i4.s 32
+ IL_002a: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
+ IL_002f: pop
+ IL_0030: ldloc.0
+ IL_0031: ldc.i4.s 125
+ IL_0033: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
+ IL_0038: pop
+ IL_0039: ldloc.0
+ IL_003a: callvirt ""string object.ToString()""
+ IL_003f: ret
}
");
}
@@ -5075,7 +5075,7 @@ .maxstack 1
");
v.VerifyIL("C1." + WellKnownMemberNames.ObjectToString, @"
{
- // Code size 70 (0x46)
+ // Code size 64 (0x40)
.maxstack 2
.locals init (System.Text.StringBuilder V_0)
IL_0000: newobj ""System.Text.StringBuilder..ctor()""
@@ -5091,18 +5091,18 @@ .locals init (System.Text.StringBuilder V_0)
IL_001e: ldarg.0
IL_001f: ldloc.0
IL_0020: callvirt ""bool C1.PrintMembers(System.Text.StringBuilder)""
- IL_0025: brfalse.s IL_0033
+ IL_0025: brfalse.s IL_0030
IL_0027: ldloc.0
- IL_0028: ldstr "" ""
- IL_002d: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0032: pop
- IL_0033: ldloc.0
- IL_0034: ldstr ""}""
- IL_0039: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_003e: pop
- IL_003f: ldloc.0
- IL_0040: callvirt ""string object.ToString()""
- IL_0045: ret
+ IL_0028: ldc.i4.s 32
+ IL_002a: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
+ IL_002f: pop
+ IL_0030: ldloc.0
+ IL_0031: ldc.i4.s 125
+ IL_0033: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
+ IL_0038: pop
+ IL_0039: ldloc.0
+ IL_003a: callvirt ""string object.ToString()""
+ IL_003f: ret
}
");
}
@@ -5154,7 +5154,7 @@ .maxstack 2
");
v.VerifyIL("C1." + WellKnownMemberNames.ObjectToString, @"
{
- // Code size 70 (0x46)
+ // Code size 64 (0x40)
.maxstack 2
.locals init (System.Text.StringBuilder V_0)
IL_0000: newobj ""System.Text.StringBuilder..ctor()""
@@ -5170,18 +5170,18 @@ .locals init (System.Text.StringBuilder V_0)
IL_001e: ldarg.0
IL_001f: ldloc.0
IL_0020: callvirt ""bool Base.PrintMembers(System.Text.StringBuilder)""
- IL_0025: brfalse.s IL_0033
+ IL_0025: brfalse.s IL_0030
IL_0027: ldloc.0
- IL_0028: ldstr "" ""
- IL_002d: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0032: pop
- IL_0033: ldloc.0
- IL_0034: ldstr ""}""
- IL_0039: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_003e: pop
- IL_003f: ldloc.0
- IL_0040: callvirt ""string object.ToString()""
- IL_0045: ret
+ IL_0028: ldc.i4.s 32
+ IL_002a: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
+ IL_002f: pop
+ IL_0030: ldloc.0
+ IL_0031: ldc.i4.s 125
+ IL_0033: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(char)""
+ IL_0038: pop
+ IL_0039: ldloc.0
+ IL_003a: callvirt ""string object.ToString()""
+ IL_003f: ret
}
");
}
@@ -5259,6 +5259,26 @@ record C1(int P);
);
}
+ [Fact]
+ public void ToString_TopLevelRecord_OneProperty_MissingStringBuilderAppendStringAndChar()
+ {
+ var src = @"
+record C1(int P);
+";
+
+ var comp = CreateCompilation(src);
+ comp.MakeMemberMissing(WellKnownMember.System_Text_StringBuilder__AppendString);
+ comp.MakeMemberMissing(WellKnownMember.System_Text_StringBuilder__AppendChar);
+ comp.VerifyEmitDiagnostics(
+ // (2,1): error CS0656: Missing compiler required member 'System.Text.StringBuilder.Append'
+ // record C1(int P);
+ Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "record C1(int P);").WithArguments("System.Text.StringBuilder", "Append").WithLocation(2, 1),
+ // (2,1): error CS0656: Missing compiler required member 'System.Text.StringBuilder.Append'
+ // record C1(int P);
+ Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "record C1(int P);").WithArguments("System.Text.StringBuilder", "Append").WithLocation(2, 1)
+ );
+ }
+
[Fact]
public void ToString_TopLevelRecord_Empty_Sealed()
{
@@ -5539,25 +5559,21 @@ record C1
v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
- // Code size 50 (0x32)
+ // Code size 38 (0x26)
.maxstack 2
IL_0000: ldarg.1
- IL_0001: ldstr ""field""
+ IL_0001: ldstr ""field = ""
IL_0006: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_000b: pop
IL_000c: ldarg.1
- IL_000d: ldstr "" = ""
- IL_0012: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0017: pop
- IL_0018: ldarg.1
- IL_0019: ldarg.0
- IL_001a: ldflda ""int C1.field""
- IL_001f: constrained. ""int""
- IL_0025: callvirt ""string object.ToString()""
- IL_002a: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_002f: pop
- IL_0030: ldc.i4.1
- IL_0031: ret
+ IL_000d: ldarg.0
+ IL_000e: ldflda ""int C1.field""
+ IL_0013: constrained. ""int""
+ IL_0019: callvirt ""string object.ToString()""
+ IL_001e: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
+ IL_0023: pop
+ IL_0024: ldc.i4.1
+ IL_0025: ret
}
");
}
@@ -5581,25 +5597,21 @@ record C1 where T : struct
v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
- // Code size 50 (0x32)
+ // Code size 38 (0x26)
.maxstack 2
IL_0000: ldarg.1
- IL_0001: ldstr ""field""
+ IL_0001: ldstr ""field = ""
IL_0006: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_000b: pop
IL_000c: ldarg.1
- IL_000d: ldstr "" = ""
- IL_0012: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0017: pop
- IL_0018: ldarg.1
- IL_0019: ldarg.0
- IL_001a: ldflda ""T C1.field""
- IL_001f: constrained. ""T""
- IL_0025: callvirt ""string object.ToString()""
- IL_002a: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_002f: pop
- IL_0030: ldc.i4.1
- IL_0031: ret
+ IL_000d: ldarg.0
+ IL_000e: ldflda ""T C1.field""
+ IL_0013: constrained. ""T""
+ IL_0019: callvirt ""string object.ToString()""
+ IL_001e: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
+ IL_0023: pop
+ IL_0024: ldc.i4.1
+ IL_0025: ret
}
");
}
@@ -5623,23 +5635,19 @@ record C1
v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
- // Code size 39 (0x27)
+ // Code size 27 (0x1b)
.maxstack 2
IL_0000: ldarg.1
- IL_0001: ldstr ""field""
+ IL_0001: ldstr ""field = ""
IL_0006: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_000b: pop
IL_000c: ldarg.1
- IL_000d: ldstr "" = ""
- IL_0012: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0017: pop
- IL_0018: ldarg.1
- IL_0019: ldarg.0
- IL_001a: ldfld ""string C1.field""
- IL_001f: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
- IL_0024: pop
- IL_0025: ldc.i4.1
- IL_0026: ret
+ IL_000d: ldarg.0
+ IL_000e: ldfld ""string C1.field""
+ IL_0013: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
+ IL_0018: pop
+ IL_0019: ldc.i4.1
+ IL_001a: ret
}
");
}
@@ -5667,24 +5675,20 @@ record C1
v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
- // Code size 44 (0x2c)
+ // Code size 32 (0x20)
.maxstack 2
IL_0000: ldarg.1
- IL_0001: ldstr ""field""
+ IL_0001: ldstr ""field = ""
IL_0006: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_000b: pop
IL_000c: ldarg.1
- IL_000d: ldstr "" = ""
- IL_0012: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0017: pop
- IL_0018: ldarg.1
- IL_0019: ldarg.0
- IL_001a: ldfld ""T C1.field""
- IL_001f: box ""T""
- IL_0024: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
- IL_0029: pop
- IL_002a: ldc.i4.1
- IL_002b: ret
+ IL_000d: ldarg.0
+ IL_000e: ldfld ""T C1.field""
+ IL_0013: box ""T""
+ IL_0018: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
+ IL_001d: pop
+ IL_001e: ldc.i4.1
+ IL_001f: ret
}
");
}
@@ -5752,40 +5756,28 @@ record C1
v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
- // Code size 88 (0x58)
+ // Code size 52 (0x34)
.maxstack 2
IL_0000: ldarg.1
- IL_0001: ldstr ""field1""
+ IL_0001: ldstr ""field1 = ""
IL_0006: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_000b: pop
IL_000c: ldarg.1
- IL_000d: ldstr "" = ""
- IL_0012: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0017: pop
- IL_0018: ldarg.1
- IL_0019: ldarg.0
- IL_001a: ldfld ""string C1.field1""
- IL_001f: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
+ IL_000d: ldarg.0
+ IL_000e: ldfld ""string C1.field1""
+ IL_0013: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
+ IL_0018: pop
+ IL_0019: ldarg.1
+ IL_001a: ldstr "", field2 = ""
+ IL_001f: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_0024: pop
IL_0025: ldarg.1
- IL_0026: ldstr "", ""
- IL_002b: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0030: pop
- IL_0031: ldarg.1
- IL_0032: ldstr ""field2""
- IL_0037: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_003c: pop
- IL_003d: ldarg.1
- IL_003e: ldstr "" = ""
- IL_0043: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0048: pop
- IL_0049: ldarg.1
- IL_004a: ldarg.0
- IL_004b: ldfld ""string C1.field2""
- IL_0050: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
- IL_0055: pop
- IL_0056: ldc.i4.1
- IL_0057: ret
+ IL_0026: ldarg.0
+ IL_0027: ldfld ""string C1.field2""
+ IL_002c: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(object)""
+ IL_0031: pop
+ IL_0032: ldc.i4.1
+ IL_0033: ret
}
");
}
@@ -5817,28 +5809,24 @@ record C1(int Property)
v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
- // Code size 53 (0x35)
+ // Code size 41 (0x29)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.1
- IL_0001: ldstr ""Property""
+ IL_0001: ldstr ""Property = ""
IL_0006: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_000b: pop
IL_000c: ldarg.1
- IL_000d: ldstr "" = ""
- IL_0012: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0017: pop
- IL_0018: ldarg.1
- IL_0019: ldarg.0
- IL_001a: call ""int C1.Property.get""
- IL_001f: stloc.0
- IL_0020: ldloca.s V_0
- IL_0022: constrained. ""int""
- IL_0028: callvirt ""string object.ToString()""
- IL_002d: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0032: pop
- IL_0033: ldc.i4.1
- IL_0034: ret
+ IL_000d: ldarg.0
+ IL_000e: call ""int C1.Property.get""
+ IL_0013: stloc.0
+ IL_0014: ldloca.s V_0
+ IL_0016: constrained. ""int""
+ IL_001c: callvirt ""string object.ToString()""
+ IL_0021: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
+ IL_0026: pop
+ IL_0027: ldc.i4.1
+ IL_0028: ret
}
");
}
@@ -5883,9 +5871,9 @@ record C1(int A1, int B1) : Base(A1)
comp.VerifyEmitDiagnostics();
var v = CompileAndVerify(comp, expectedOutput: "C1 { A1 = 42, A2 = 100, B1 = 43, B2 = 101 }", verify: Verification.Skipped /* init-only */);
- v.VerifyIL("C1.PrintMembers", @"
+ v.VerifyIL("C1." + WellKnownMemberNames.PrintMembersMethodName, @"
{
- // Code size 134 (0x86)
+ // Code size 98 (0x62)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.0
@@ -5897,43 +5885,31 @@ .locals init (int V_0)
IL_000f: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_0014: pop
IL_0015: ldarg.1
- IL_0016: ldstr ""B1""
+ IL_0016: ldstr ""B1 = ""
IL_001b: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_0020: pop
IL_0021: ldarg.1
- IL_0022: ldstr "" = ""
- IL_0027: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_002c: pop
- IL_002d: ldarg.1
- IL_002e: ldarg.0
- IL_002f: call ""int C1.B1.get""
- IL_0034: stloc.0
- IL_0035: ldloca.s V_0
- IL_0037: constrained. ""int""
- IL_003d: callvirt ""string object.ToString()""
+ IL_0022: ldarg.0
+ IL_0023: call ""int C1.B1.get""
+ IL_0028: stloc.0
+ IL_0029: ldloca.s V_0
+ IL_002b: constrained. ""int""
+ IL_0031: callvirt ""string object.ToString()""
+ IL_0036: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
+ IL_003b: pop
+ IL_003c: ldarg.1
+ IL_003d: ldstr "", B2 = ""
IL_0042: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_0047: pop
IL_0048: ldarg.1
- IL_0049: ldstr "", ""
- IL_004e: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0053: pop
- IL_0054: ldarg.1
- IL_0055: ldstr ""B2""
+ IL_0049: ldarg.0
+ IL_004a: ldflda ""int C1.B2""
+ IL_004f: constrained. ""int""
+ IL_0055: callvirt ""string object.ToString()""
IL_005a: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
IL_005f: pop
- IL_0060: ldarg.1
- IL_0061: ldstr "" = ""
- IL_0066: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_006b: pop
- IL_006c: ldarg.1
- IL_006d: ldarg.0
- IL_006e: ldflda ""int C1.B2""
- IL_0073: constrained. ""int""
- IL_0079: callvirt ""string object.ToString()""
- IL_007e: callvirt ""System.Text.StringBuilder System.Text.StringBuilder.Append(string)""
- IL_0083: pop
- IL_0084: ldc.i4.1
- IL_0085: ret
+ IL_0060: ldc.i4.1
+ IL_0061: ret
}
");
}
@@ -16380,6 +16356,7 @@ public class String { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { }
+ public struct Char { }
public struct Int32 { }
public interface IEquatable
{
@@ -16391,7 +16368,8 @@ namespace System.Text
public class StringBuilder
{
public StringBuilder Append(string s) => null;
- public StringBuilder Append(object s) => null;
+ public StringBuilder Append(char c) => null;
+ public StringBuilder Append(object o) => null;
}
}
";
@@ -17323,6 +17301,7 @@ public class String { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { }
+ public struct Char { }
public struct Int32 { }
public interface IEquatable
{
@@ -17334,7 +17313,8 @@ namespace System.Text
public class StringBuilder
{
public StringBuilder Append(string s) => null;
- public StringBuilder Append(object s) => null;
+ public StringBuilder Append(char c) => null;
+ public StringBuilder Append(object o) => null;
}
}
@@ -17421,6 +17401,7 @@ public class String { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { }
+ public struct Char { }
public struct Int32 { }
public interface IEquatable
{
@@ -17432,7 +17413,8 @@ namespace System.Text
public class StringBuilder
{
public StringBuilder Append(string s) => null;
- public StringBuilder Append(object s) => null;
+ public StringBuilder Append(char c) => null;
+ public StringBuilder Append(object o) => null;
}
}
";
@@ -17515,6 +17497,7 @@ public class String { }
public abstract class ValueType { }
public struct Void { }
public struct Boolean { }
+ public struct Char { }
public struct Int32 { }
public interface IEquatable
{
@@ -17526,7 +17509,8 @@ namespace System.Text
public class StringBuilder
{
public StringBuilder Append(string s) => null;
- public StringBuilder Append(object s) => null;
+ public StringBuilder Append(char c) => null;
+ public StringBuilder Append(object o) => null;
}
}
";
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs
index 42cd3670adbfe..8d4f8ac776b1e 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs
@@ -6531,9 +6531,9 @@ public static void Main()
// (21,16): error CS0172: Type of conditional expression cannot be determined because 'Square.Circle' and 'Square' implicitly convert to one another
// var o1 = (1 == 1) ? aa : ii; // CS0172
Diagnostic(ErrorCode.ERR_AmbigQM, "(1 == 1) ? aa : ii").WithArguments("Square.Circle", "Square").WithLocation(21, 16),
- // (22,19): error CS8400: Feature 'target-typed conditional expression' is not available in C# 8.0. Please use language version 9.0 or greater.
+ // (22,19): error CS8957: Conditional expression is not valid in language version 8.0 because a common type was not found between 'Square.Circle' and 'Square'. To use a target-typed conversion, upgrade to language version 9.0 or greater.
// object o2 = (1 == 1) ? aa : ii; // CS8652
- Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "(1 == 1) ? aa : ii").WithArguments("target-typed conditional expression", "9.0").WithLocation(22, 19)
+ Diagnostic(ErrorCode.ERR_NoImplicitConvTargetTypedConditional, "(1 == 1) ? aa : ii").WithArguments("8.0", "Square.Circle", "Square", "9.0").WithLocation(22, 19)
);
}
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedConditionalOperatorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedConditionalOperatorTests.cs
index 4966e95dab2a7..8144e3d6c4487 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedConditionalOperatorTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedConditionalOperatorTests.cs
@@ -640,9 +640,10 @@ static B F(bool b, A a)
// (15,16): error CS0029: Cannot implicitly convert type 'A' to 'B'
// return (b ? a : 0) + a;
Diagnostic(ErrorCode.ERR_NoImplicitConv, "(b ? a : 0) + a").WithArguments("A", "B").WithLocation(15, 16),
- // (15,17): error CS8370: Feature 'target-typed conditional expression' is not available in C# 7.3. Please use language version 9.0 or greater.
+ // (15,17): error CS8957: Conditional expression is not valid in language version 7.3 because a common type was not found between 'A' and 'int'. To use a target-typed conversion, upgrade to language version 9.0 or greater.
// return (b ? a : 0) + a;
- Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "b ? a : 0").WithArguments("target-typed conditional expression", "9.0").WithLocation(15, 17));
+ Diagnostic(ErrorCode.ERR_NoImplicitConvTargetTypedConditional, "b ? a : 0").WithArguments("7.3", "A", "int", "9.0").WithLocation(15, 17));
+
CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(MessageID.IDS_FeatureTargetTypedConditional.RequiredVersion())).VerifyDiagnostics(
// (15,16): error CS0029: Cannot implicitly convert type 'A' to 'B'
// return (b ? a : 0) + a;
@@ -690,5 +691,27 @@ static void F(bool b, int x)
Assert.Null(typeInfo.Type);
Assert.Equal("System.Int32?", typeInfo.ConvertedType.ToTestDisplayString());
}
+
+ [Fact]
+ public void DiagnosticClarity_LangVersion8()
+ {
+ var source = @"
+class C
+{
+ void M(bool b)
+ {
+ int? i = b ? 1 : null;
+ }
+}
+";
+ var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
+ comp.VerifyDiagnostics(
+ // (6,18): error CS8957: Conditional expression is not valid in language version 8.0 because a common type was not found between 'int' and ''. To use a target-typed conversion, upgrade to language version 9.0 or greater.
+ // int? i = b ? 1 : null;
+ Diagnostic(ErrorCode.ERR_NoImplicitConvTargetTypedConditional, "b ? 1 : null").WithArguments("8.0", "int", "", "9.0").WithLocation(6, 18));
+
+ comp = CreateCompilation(source);
+ comp.VerifyDiagnostics();
+ }
}
}
diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs
index 2a86998678c58..df401904ed1d9 100644
--- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/StateTableTests.cs
@@ -177,6 +177,31 @@ public void Node_Builder_Handles_Modification_When_Both_Tables_Have_Empty_Entrie
AssertTableEntries(newTable, expected);
}
+ [Fact]
+ public void Node_Table_Doesnt_Modify_Single_Item_Multiple_Times_When_Same()
+ {
+ var builder = NodeStateTable.Empty.ToBuilder();
+ builder.AddEntries(ImmutableArray.Create(1), EntryState.Added);
+ builder.AddEntries(ImmutableArray.Create(2), EntryState.Added);
+ builder.AddEntries(ImmutableArray.Create(3), EntryState.Added);
+ builder.AddEntries(ImmutableArray.Create(4), EntryState.Added);
+ var previousTable = builder.ToImmutableAndFree();
+
+ var expected = ImmutableArray.Create((1, EntryState.Added), (2, EntryState.Added), (3, EntryState.Added), (4, EntryState.Added));
+ AssertTableEntries(previousTable, expected);
+
+ builder = previousTable.ToBuilder();
+ Assert.True(builder.TryModifyEntry(1, EqualityComparer.Default)); // ((1, EntryState.Cached))
+ Assert.True(builder.TryModifyEntry(2, EqualityComparer.Default)); // ((2, EntryState.Cached))
+ Assert.True(builder.TryModifyEntry(5, EqualityComparer.Default)); // ((5, EntryState.Modified))
+ Assert.True(builder.TryModifyEntry(4, EqualityComparer.Default)); // ((4, EntryState.Cached))
+
+ var newTable = builder.ToImmutableAndFree();
+
+ expected = ImmutableArray.Create((1, EntryState.Cached), (2, EntryState.Cached), (5, EntryState.Modified), (4, EntryState.Cached));
+ AssertTableEntries(newTable, expected);
+ }
+
[Fact]
public void Driver_Table_Calls_Into_Node_With_Self()
{
diff --git a/src/Compilers/Core/CodeAnalysisTest/Collections/ImmutableArrayExtensionsTests.cs b/src/Compilers/Core/CodeAnalysisTest/Collections/ImmutableArrayExtensionsTests.cs
index 0672c3fbc5229..be6724db373c3 100644
--- a/src/Compilers/Core/CodeAnalysisTest/Collections/ImmutableArrayExtensionsTests.cs
+++ b/src/Compilers/Core/CodeAnalysisTest/Collections/ImmutableArrayExtensionsTests.cs
@@ -380,17 +380,6 @@ public void SelectAsArrayWithPredicate()
Assert.Empty(array.SelectAsArray(item => item < 0, item => throw null));
}
- [Fact]
- public void DangerousCreateFromUnderlyingArray()
- {
- var array = new[] { 1, 2, 3, 4 };
- var copy = array;
- var immutable = ImmutableArrayExtensions.DangerousCreateFromUnderlyingArray(ref copy);
- Assert.Null(copy);
- AssertEx.Equal(array, immutable);
- Assert.Same(array, ImmutableArrayExtensions.DangerousGetUnderlyingArray(immutable));
- }
-
[Fact]
public void ZipAsArray()
{
diff --git a/src/Compilers/Core/CodeAnalysisTest/CommonCommandLineParserTests.cs b/src/Compilers/Core/CodeAnalysisTest/CommonCommandLineParserTests.cs
index f80799b530052..ab436d334ce56 100644
--- a/src/Compilers/Core/CodeAnalysisTest/CommonCommandLineParserTests.cs
+++ b/src/Compilers/Core/CodeAnalysisTest/CommonCommandLineParserTests.cs
@@ -7,7 +7,9 @@
using System;
using System.Globalization;
using System.Linq;
+using System.Runtime.InteropServices;
using System.Threading;
+using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Test.Utilities;
using Xunit;
@@ -1106,20 +1108,23 @@ public void GetEffectiveIncludes_TwoLevels()
Assert.Equal(expected: include2.Path, actual: includePaths[2]);
}
+ private string[] ParseSeparatedStrings(string arg, char[] separators, bool removeEmptyEntries = true)
+ {
+ var builder = ArrayBuilder>.GetInstance();
+ CommandLineParser.ParseSeparatedStrings(arg.AsMemory(), separators, removeEmptyEntries, builder);
+ return builder.Select(x => x.ToString()).ToArray();
+ }
+
[Fact]
public void ParseSeparatedStrings_ExcludeSeparatorChar()
{
Assert.Equal(
- CommandLineParser.ParseSeparatedStrings(@"a,b", new[] { ',' }, StringSplitOptions.RemoveEmptyEntries),
+ ParseSeparatedStrings(@"a,b", new[] { ',' }),
new[] { "a", "b" });
Assert.Equal(
- CommandLineParser.ParseSeparatedStrings(@"a,,b", new[] { ',' }, StringSplitOptions.RemoveEmptyEntries),
+ ParseSeparatedStrings(@"a,,b", new[] { ',' }),
new[] { "a", "b" });
-
- Assert.Equal(
- CommandLineParser.ParseSeparatedStrings(@"a,,b", new[] { ',' }, StringSplitOptions.None),
- new[] { "a", "", "b" });
}
///
@@ -1130,15 +1135,15 @@ public void ParseSeparatedStrings_ExcludeSeparatorChar()
public void ParseSeparatedStrings_IncludeQuotes()
{
Assert.Equal(
- CommandLineParser.ParseSeparatedStrings(@"""a"",b", new[] { ',' }, StringSplitOptions.RemoveEmptyEntries),
+ ParseSeparatedStrings(@"""a"",b", new[] { ',' }),
new[] { @"""a""", "b" });
Assert.Equal(
- CommandLineParser.ParseSeparatedStrings(@"""a,b""", new[] { ',' }, StringSplitOptions.RemoveEmptyEntries),
+ ParseSeparatedStrings(@"""a,b""", new[] { ',' }),
new[] { @"""a,b""" });
Assert.Equal(
- CommandLineParser.ParseSeparatedStrings(@"""a"",""b", new[] { ',' }, StringSplitOptions.RemoveEmptyEntries),
+ ParseSeparatedStrings(@"""a"",""b", new[] { ',' }),
new[] { @"""a""", @"""b" });
}
@@ -1228,7 +1233,7 @@ public void SplitCommandLineIntoArguments_Quotes()
/// as \"\\test.cs\".
///
[Fact]
- public void RemoveQuotes()
+ public void RemoveQuotesAndSlashes()
{
Assert.Equal(@"\\test.cs", CommandLineParser.RemoveQuotesAndSlashes(@"\\test.cs"));
Assert.Equal(@"\\test.cs", CommandLineParser.RemoveQuotesAndSlashes(@"""\\test.cs"""));
@@ -1240,6 +1245,27 @@ public void RemoveQuotes()
Assert.Equal(@"a"" mid ""b.cs", CommandLineParser.RemoveQuotesAndSlashes(@"a\"" mid \""b.cs"));
Assert.Equal(@"a mid b.cs", CommandLineParser.RemoveQuotesAndSlashes(@"a"" mid ""b.cs"));
Assert.Equal(@"a.cs", CommandLineParser.RemoveQuotesAndSlashes(@"""a.cs"""));
+ Assert.Equal(@"C:""My Folder\MyBinary.xml", CommandLineParser.RemoveQuotesAndSlashes(@"C:\""My Folder""\MyBinary.xml"));
+ }
+
+ ///
+ /// Verify that for the standard cases we do not allocate new memory but instead
+ /// return a to the existing string
+ ///
+ [Fact]
+ public void RemoveQuotesAndSlashes_NoAllocation()
+ {
+ assertSame(@"c:\test.cs");
+ assertSame(@"""c:\test.cs""");
+ assertSame(@"""c:\\\\\\\\\test.cs""");
+ assertSame(@"""c:\\\\\\\\\test.cs""");
+
+ void assertSame(string arg)
+ {
+ var memory = CommandLineParser.RemoveQuotesAndSlashesEx(arg.AsMemory());
+ Assert.True(MemoryMarshal.TryGetString(memory, out var memoryString, out _, out _));
+ Assert.Same(arg, memoryString);
+ }
}
}
}
diff --git a/src/Compilers/Core/CodeAnalysisTest/Emit/EmitBaselineTests.cs b/src/Compilers/Core/CodeAnalysisTest/Emit/EmitBaselineTests.cs
index 139140eda3899..d9201a9a07e41 100644
--- a/src/Compilers/Core/CodeAnalysisTest/Emit/EmitBaselineTests.cs
+++ b/src/Compilers/Core/CodeAnalysisTest/Emit/EmitBaselineTests.cs
@@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.UnitTests.Emit
public class EmitBaselineTests
{
[Fact]
- public void CreateInitialBaseline_Errors()
+ public unsafe void CreateInitialBaseline_Errors()
{
var debugInfoProvider = new Func(_ => default);
var localSigProvider = new Func(_ => default);
@@ -24,17 +24,19 @@ public void CreateInitialBaseline_Errors()
var peReader = peModule.Module.PEReaderOpt;
var mdBytes = peReader.GetMetadata().GetContent();
- var mdBytesHandle = GCHandle.Alloc(mdBytes.DangerousGetUnderlyingArray(), GCHandleType.Pinned);
- var mdModule = ModuleMetadata.CreateFromMetadata(mdBytesHandle.AddrOfPinnedObject(), mdBytes.Length);
+ fixed (byte* mdBytesPointer = mdBytes.AsSpan())
+ {
+ var mdModule = ModuleMetadata.CreateFromMetadata((IntPtr)mdBytesPointer, mdBytes.Length);
- Assert.Throws(() => EmitBaseline.CreateInitialBaseline(null, debugInfoProvider));
- Assert.Throws(() => EmitBaseline.CreateInitialBaseline(peModule, null));
- Assert.Throws(() => EmitBaseline.CreateInitialBaseline(mdModule, debugInfoProvider));
+ Assert.Throws(() => EmitBaseline.CreateInitialBaseline(null, debugInfoProvider));
+ Assert.Throws(() => EmitBaseline.CreateInitialBaseline(peModule, null));
+ Assert.Throws(() => EmitBaseline.CreateInitialBaseline(mdModule, debugInfoProvider));
- Assert.Throws(() => EmitBaseline.CreateInitialBaseline(null, debugInfoProvider, localSigProvider, true));
- Assert.Throws(() => EmitBaseline.CreateInitialBaseline(peModule, null, localSigProvider, true));
- Assert.Throws(() => EmitBaseline.CreateInitialBaseline(mdModule, debugInfoProvider, null, true));
- Assert.NotNull(EmitBaseline.CreateInitialBaseline(mdModule, debugInfoProvider, localSigProvider, true));
+ Assert.Throws(() => EmitBaseline.CreateInitialBaseline(null, debugInfoProvider, localSigProvider, true));
+ Assert.Throws(() => EmitBaseline.CreateInitialBaseline(peModule, null, localSigProvider, true));
+ Assert.Throws(() => EmitBaseline.CreateInitialBaseline(mdModule, debugInfoProvider, null, true));
+ Assert.NotNull(EmitBaseline.CreateInitialBaseline(mdModule, debugInfoProvider, localSigProvider, true));
+ }
}
}
}
diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj b/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj
index 8e18c9cd89601..46f844e7edc5c 100644
--- a/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj
+++ b/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj
@@ -54,6 +54,8 @@
+
+
diff --git a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs
index b2f8948f09f10..66d29b193e4f2 100644
--- a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs
+++ b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs
@@ -737,27 +737,6 @@ public static int Count(this ImmutableArray items, Func predicate
return count;
}
- [StructLayout(LayoutKind.Sequential)]
- private struct ImmutableArrayProxy
- {
- internal T[] MutableArray;
- }
-
- // TODO(https://github.com/dotnet/corefx/issues/34126): Remove when System.Collections.Immutable
- // provides a Span API
- internal static T[] DangerousGetUnderlyingArray(this ImmutableArray array)
- => Unsafe.As, ImmutableArrayProxy>(ref array).MutableArray;
-
- internal static ReadOnlySpan AsSpan(this ImmutableArray array)
- => array.DangerousGetUnderlyingArray();
-
- internal static ImmutableArray DangerousCreateFromUnderlyingArray([MaybeNull] ref T[] array)
- {
- var proxy = new ImmutableArrayProxy { MutableArray = array };
- array = null!;
- return Unsafe.As, ImmutableArray>(ref proxy);
- }
-
internal static Dictionary> ToDictionary(this ImmutableArray items, Func keySelector, IEqualityComparer? comparer = null)
where K : notnull
{
diff --git a/src/Compilers/Core/Portable/CommandLine/CommandLineParser.cs b/src/Compilers/Core/Portable/CommandLine/CommandLineParser.cs
index 30660b895886a..9c6219b762728 100644
--- a/src/Compilers/Core/Portable/CommandLine/CommandLineParser.cs
+++ b/src/Compilers/Core/Portable/CommandLine/CommandLineParser.cs
@@ -80,16 +80,81 @@ public CommandLineArguments Parse(IEnumerable args, string baseDirectory
return CommonParse(args, baseDirectory, sdkDirectory, additionalReferenceDirectories);
}
- private static bool IsOption(string arg)
+ internal static bool IsOptionName(string optionName, ReadOnlyMemory value) =>
+ IsOptionName(optionName, value.Span);
+
+ internal static bool IsOptionName(string shortOptionName, string longOptionName, ReadOnlyMemory value) =>
+ IsOptionName(shortOptionName, value) || IsOptionName(longOptionName, value);
+
+ ///
+ /// Determines if a is equal to the provided option name
+ ///
+ ///
+ /// Prefer this over the Equals methods on . The
+ /// implementation allocates a .
+ /// The 99% case here is that we are dealing with an ASCII string that matches the input hence
+ /// it's worth special casing that here and falling back to the more complicated comparison
+ /// when dealing with non-ASCII input
+ ///
+ internal static bool IsOptionName(string optionName, ReadOnlySpan value)
{
- return !string.IsNullOrEmpty(arg) && (arg[0] == '/' || arg[0] == '-');
+ Debug.Assert(isAllAscii(optionName.AsSpan()));
+ if (isAllAscii(value))
+ {
+ if (optionName.Length != value.Length)
+ return false;
+
+ for (int i = 0; i < optionName.Length; i++)
+ {
+ if (optionName[i] != char.ToLowerInvariant(value[i]))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return optionName.AsSpan().Equals(value, StringComparison.InvariantCultureIgnoreCase);
+
+ static bool isAllAscii(ReadOnlySpan span)
+ {
+ foreach (char ch in span)
+ {
+ if (ch > 127)
+ return false;
+ }
+ return true;
+ }
}
+ internal static bool IsOption(string arg) => IsOption(arg.AsSpan());
+
+ internal static bool IsOption(ReadOnlySpan arg) =>
+ arg.Length > 0 && (arg[0] == '/' || arg[0] == '-');
+
+ internal static bool IsOption(string optionName, string arg, out ReadOnlyMemory name, out ReadOnlyMemory