Skip to content

Commit 147ebc0

Browse files
authored
Merge latest bits from main into features/extensions (#81534)
2 parents 97aea17 + dc267b9 commit 147ebc0

File tree

159 files changed

+2205
-325
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

159 files changed

+2205
-325
lines changed

Compilers.slnf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"src\\Compilers\\CSharp\\CSharpAnalyzerDriver\\CSharpAnalyzerDriver.shproj",
66
"src\\Compilers\\CSharp\\Portable\\Microsoft.CodeAnalysis.CSharp.csproj",
77
"src\\Compilers\\CSharp\\Test\\CommandLine\\Microsoft.CodeAnalysis.CSharp.CommandLine.UnitTests.csproj",
8+
"src\\Compilers\\CSharp\\Test\\CSharp15\\Microsoft.CodeAnalysis.CSharp.CSharp15.UnitTests.csproj",
89
"src\\Compilers\\CSharp\\Test\\Emit3\\Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests.csproj",
910
"src\\Compilers\\CSharp\\Test\\Emit2\\Microsoft.CodeAnalysis.CSharp.Emit2.UnitTests.csproj",
1011
"src\\Compilers\\CSharp\\Test\\Emit\\Microsoft.CodeAnalysis.CSharp.Emit.UnitTests.csproj",

Ide.slnf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"src\\Compilers\\CSharp\\Test\\CommandLine\\Microsoft.CodeAnalysis.CSharp.CommandLine.UnitTests.csproj",
2727
"src\\Compilers\\CSharp\\Test\\Emit2\\Microsoft.CodeAnalysis.CSharp.Emit2.UnitTests.csproj",
2828
"src\\Compilers\\CSharp\\Test\\Emit3\\Microsoft.CodeAnalysis.CSharp.Emit3.UnitTests.csproj",
29+
"src\\Compilers\\CSharp\\Test\\CSharp15\\Microsoft.CodeAnalysis.CSharp.CSharp15.UnitTests.csproj",
2930
"src\\Compilers\\CSharp\\Test\\Emit\\Microsoft.CodeAnalysis.CSharp.Emit.UnitTests.csproj",
3031
"src\\Compilers\\CSharp\\Test\\EndToEnd\\Microsoft.CodeAnalysis.CSharp.EndToEnd.UnitTests.csproj",
3132
"src\\Compilers\\CSharp\\Test\\IOperation\\Microsoft.CodeAnalysis.CSharp.IOperation.UnitTests.csproj",

Roslyn.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
<Project Path="src/Compilers/CSharp/Test/Semantic/Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.csproj" />
109109
<Project Path="src/Compilers/CSharp/Test/Symbol/Microsoft.CodeAnalysis.CSharp.Symbol.UnitTests.csproj" />
110110
<Project Path="src/Compilers/CSharp/Test/Syntax/Microsoft.CodeAnalysis.CSharp.Syntax.UnitTests.csproj" />
111+
<Project Path="src/Compilers/CSharp/Test/CSharp15/Microsoft.CodeAnalysis.CSharp.CSharp15.UnitTests.csproj" />
111112
<Project Path="src/Compilers/CSharp/Test/WinRT/Microsoft.CodeAnalysis.CSharp.WinRT.UnitTests.csproj" />
112113
<Project Path="src/Compilers/Test/Utilities/CSharp/Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj" />
113114
</Folder>

docs/Language Feature Status.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ When a feature is merged to the `main` branch, its entry should be moved to the
2121
| [Unions](https://github.com/dotnet/csharplang/issues/9662) | [Unions](https://github.com/dotnet/roslyn/tree/features/Unions) | [In Progress](https://github.com/dotnet/roslyn/issues/81074) | [AlekseyTs](https://github.com/AlekseyTs) | [RikkiGibson](https://github.com/RikkiGibson), [333fred](https://github.com/333fred) | TBD | [MadsTorgersen](https://github.com/MadsTorgersen) |
2222
| [Closed class hierarchies](https://github.com/dotnet/csharplang/issues/9499) | [closed-class](https://github.com/dotnet/roslyn/tree/features/closed-class) | [In progress](https://github.com/dotnet/roslyn/issues/81039) | [RikkiGibson](https://github.com/RikkiGibson) | [AlekseyTs](https://github.com/AlekseyTs), [jjonescz](https://github.com/jjonescz) | TBD | [mattwar](https://github.com/mattwar) |
2323
| [Unsafe evolution](https://github.com/dotnet/csharplang/issues/9704) | [UnsafeEvolution](https://github.com/dotnet/roslyn/tree/features/UnsafeEvolution) | [In progress](https://github.com/dotnet/roslyn/issues/81207) | [jjonescz](https://github.com/jjonescz) | [333fred](https://github.com/333fred), [jcouv](https://github.com/jcouv) | TBD | [agocke](https://github.com/agocke) |
24+
| [Extension indexers](https://github.com/dotnet/csharplang/issues/9856) | [extensions](https://github.com/dotnet/roslyn/tree/features/extensions) | [In progress](https://github.com/dotnet/roslyn/issues/81505) | [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs), [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jcouv](https://github.com/jcouv) |
2425
| Runtime Async | [runtime-async](https://github.com/dotnet/roslyn/tree/features/runtime-async) | [Merged into main in preview](https://github.com/dotnet/roslyn/issues/75960) | [333fred](https://github.com/333fred) | [jcouv](https://github.com/jcouv), [RikkiGibson](https://github.com/RikkiGibson) | | |
2526

2627
# Working Set VB

docs/features/file-based-programs-vscode.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,8 @@ Any of the above is met, and, the file is not included in an ordinary `.csproj`
5757
### Opt-out
5858

5959
We added an opt-out flag with option name `dotnet.projects.enableFileBasedPrograms`. If issues arise with the file-based program experience, then VS Code users should set the corresponding setting `"dotnet.projects.enableFileBasedPrograms": false` to revert back to the old miscellaneous files experience.
60+
61+
We also have a second, finer-grained opt-out flag `dotnet.projects.enableFileBasedProgramsWhenAmbiguous`. This flag is conditional on the previous flag (i.e. it is ignored when `enableFileBasedPrograms` is `false`). This is used to allow opting out only in cases where it is unclear from the single file itself, whether it should be treated as a file-based program. Presence of `#:` or `#!` directives in a `.cs` file strongly indicates that the file is a file-based program, and editor functionality will continue to light up for such files, even when `enableFileBasedProgramsWhenAmbiguous` is `false`.
62+
63+
> [!NOTE]
64+
> The second flag is being used on a short-term basis while we work out the set of heuristics and cross-component APIs needed to efficiently and satisfactorily resolve whether a file with top-level statements but no directives is a file-based program in the context of a complex workspace.

eng/build.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ function GetCompilerTestAssembliesIncludePaths() {
357357
$assemblies += " --include '^Microsoft\.CodeAnalysis\.CSharp\.Emit\.UnitTests$'"
358358
$assemblies += " --include '^Microsoft\.CodeAnalysis\.CSharp\.Emit2\.UnitTests$'"
359359
$assemblies += " --include '^Microsoft\.CodeAnalysis\.CSharp\.Emit3\.UnitTests$'"
360+
$assemblies += " --include '^Microsoft\.CodeAnalysis\.CSharp\.CSharp15\.UnitTests$'"
360361
$assemblies += " --include '^Microsoft\.CodeAnalysis\.CSharp\.IOperation\.UnitTests$'"
361362
$assemblies += " --include '^Microsoft\.CodeAnalysis\.CSharp\.CommandLine\.UnitTests$'"
362363
$assemblies += " --include '^Microsoft\.CodeAnalysis\.VisualBasic\.Syntax\.UnitTests$'"

eng/build.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ function GetCompilerTestAssembliesIncludePaths {
347347
assemblies+=" --include '^Microsoft\.CodeAnalysis\.CSharp\.Emit\.UnitTests$'"
348348
assemblies+=" --include '^Microsoft\.CodeAnalysis\.CSharp\.Emit2\.UnitTests$'"
349349
assemblies+=" --include '^Microsoft\.CodeAnalysis\.CSharp\.Emit3\.UnitTests$'"
350+
assemblies+=" --include '^Microsoft\.CodeAnalysis\.CSharp\.CSharp15\.UnitTests$'"
350351
assemblies+=" --include '^Microsoft\.CodeAnalysis\.CSharp\.IOperation\.UnitTests$'"
351352
assemblies+=" --include '^Microsoft\.CodeAnalysis\.CSharp\.CommandLine\.UnitTests$'"
352353
assemblies+=" --include '^Microsoft\.CodeAnalysis\.VisualBasic\.Syntax\.UnitTests$'"

src/Analyzers/CSharp/Analyzers/AddRequiredParentheses/CSharpAddRequiredExpressionParenthesesDiagnosticAnalyzer.cs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,28 +51,31 @@ protected override int GetPrecedence(ExpressionSyntax binaryLike)
5151

5252
protected override bool IsBinaryLike(ExpressionSyntax node)
5353
=> node is BinaryExpressionSyntax ||
54-
node is IsPatternExpressionSyntax { Pattern: ConstantPatternSyntax };
54+
// Support `x is const` pattern as binary-like for precedence purposes.
55+
node is IsPatternExpressionSyntax { Pattern: ConstantPatternSyntax } ||
56+
// Support `x is not const` pattern as binary-like for precedence purposes.
57+
node is IsPatternExpressionSyntax { Pattern: UnaryPatternSyntax { Pattern: ConstantPatternSyntax } };
5558

5659
protected override (ExpressionSyntax, SyntaxToken, ExpressionSyntax) GetPartsOfBinaryLike(ExpressionSyntax binaryLike)
5760
{
5861
Debug.Assert(IsBinaryLike(binaryLike));
59-
switch (binaryLike)
62+
return binaryLike switch
6063
{
61-
case BinaryExpressionSyntax binaryExpression:
62-
return (binaryExpression.Left, binaryExpression.OperatorToken, binaryExpression.Right);
63-
64-
case IsPatternExpressionSyntax { Pattern: ConstantPatternSyntax constantPattern } isPatternExpression:
65-
return (isPatternExpression.Expression, isPatternExpression.IsKeyword, constantPattern.Expression);
66-
67-
default:
68-
throw ExceptionUtilities.UnexpectedValue(binaryLike);
69-
}
64+
BinaryExpressionSyntax binaryExpression => (binaryExpression.Left, binaryExpression.OperatorToken, binaryExpression.Right),
65+
IsPatternExpressionSyntax { Pattern: ConstantPatternSyntax constantPattern } isPatternExpression => (isPatternExpression.Expression, isPatternExpression.IsKeyword, constantPattern.Expression),
66+
IsPatternExpressionSyntax { Pattern: UnaryPatternSyntax { Pattern: ConstantPatternSyntax constantPattern } } isPatternExpression => (isPatternExpression.Expression, isPatternExpression.IsKeyword, constantPattern.Expression),
67+
_ => throw ExceptionUtilities.UnexpectedValue(binaryLike),
68+
};
7069
}
7170

7271
protected override ExpressionSyntax? TryGetAppropriateParent(ExpressionSyntax binaryLike)
73-
=> binaryLike.Parent is ConstantPatternSyntax
74-
? binaryLike.Parent.Parent as ExpressionSyntax
75-
: binaryLike.Parent as ExpressionSyntax;
72+
=> binaryLike.Parent switch
73+
{
74+
ExpressionSyntax expression => expression,
75+
ConstantPatternSyntax { Parent: ExpressionSyntax expression } => expression,
76+
ConstantPatternSyntax { Parent: UnaryPatternSyntax { Parent: ExpressionSyntax expression } } => expression,
77+
_ => null,
78+
};
7679

7780
protected override bool IsAsExpression(ExpressionSyntax node)
7881
=> node.Kind() == SyntaxKind.AsExpression;

src/Analyzers/CSharp/Tests/AddRequiredParentheses/AddRequiredExpressionParenthesesTests.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,38 @@ void M()
439439
}
440440
""", RequireAllParenthesesForClarity);
441441

442+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/81488")]
443+
public Task TestCoalescePrecedence_IsNull()
444+
=> TestAsync(
445+
"""
446+
class C
447+
{
448+
bool M(object x, object y) => x?.Equals(y) ?? y $$is null;
449+
}
450+
""",
451+
"""
452+
class C
453+
{
454+
bool M(object x, object y) => x?.Equals(y) ?? (y is null);
455+
}
456+
""", RequireAllParenthesesForClarity);
457+
458+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/81488")]
459+
public Task TestCoalescePrecedence_IsNotNull()
460+
=> TestAsync(
461+
"""
462+
class C
463+
{
464+
bool M(object x, object y) => x?.Equals(y) ?? y $$is not null;
465+
}
466+
""",
467+
"""
468+
class C
469+
{
470+
bool M(object x, object y) => x?.Equals(y) ?? (y is not null);
471+
}
472+
""", RequireAllParenthesesForClarity);
473+
442474
[Fact]
443475
public Task TestBitwisePrecedence1()
444476
=> TestAsync(

src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Diagnostics.CodeAnalysis;
99
using System.Linq;
1010
using Microsoft.CodeAnalysis.CSharp.Symbols;
11+
using Microsoft.CodeAnalysis.CSharp.Syntax;
1112
using Microsoft.CodeAnalysis.PooledObjects;
1213
using Roslyn.Utilities;
1314

@@ -1245,13 +1246,40 @@ private static bool CheckNotNamespaceOrType(BoundExpression expr, BindingDiagnos
12451246
Error(diagnostics, ErrorCode.ERR_BadSKknown, expr.Syntax, ((BoundNamespaceExpression)expr).NamespaceSymbol, MessageID.IDS_SK_NAMESPACE.Localize(), MessageID.IDS_SK_VARIABLE.Localize());
12461247
return false;
12471248
case BoundKind.TypeExpression:
1248-
Error(diagnostics, ErrorCode.ERR_BadSKunknown, expr.Syntax, expr.Type, MessageID.IDS_SK_TYPE.Localize());
1249+
// Don't report ERR_BadSKunknown if we're in a (T)-X pattern, as we'll report
1250+
// ERR_PossibleBadNegCast instead which is more specific and helpful.
1251+
// Note: This check must be kept in sync with BindSimpleBinaryOperator where ERR_PossibleBadNegCast is reported.
1252+
if (!IsInPossibleBadNegCastContext(expr.Syntax))
1253+
{
1254+
Error(diagnostics, ErrorCode.ERR_BadSKunknown, expr.Syntax, expr.Type, MessageID.IDS_SK_TYPE.Localize());
1255+
}
12491256
return false;
12501257
default:
12511258
return true;
12521259
}
12531260
}
12541261

1262+
private static bool IsInPossibleBadNegCastContext(SyntaxNode syntax)
1263+
{
1264+
// Check if the syntax is a type name inside (T)-X pattern:
1265+
// The syntax could be inside a ParenthesizedExpression which is the left side of a SubtractExpression
1266+
// Additionally, the parenthesized expression should not itself be parenthesized (i.e., we want (T)-X, not ((T))-X)
1267+
return syntax.Parent is ParenthesizedExpressionSyntax parenthesized &&
1268+
!parenthesized.Expression.IsKind(SyntaxKind.ParenthesizedExpression) &&
1269+
IsParenthesizedExpressionInPossibleBadNegCastContext(parenthesized);
1270+
}
1271+
1272+
/// <summary>
1273+
/// Checks if a parenthesized expression is the left operand of a subtraction (the <c>(T)</c> part of <c>(T)-X</c>).
1274+
/// This method is shared between CheckNotNamespaceOrType and BindSimpleBinaryOperator to ensure they
1275+
/// check for the same pattern consistently.
1276+
/// </summary>
1277+
private static bool IsParenthesizedExpressionInPossibleBadNegCastContext(ParenthesizedExpressionSyntax parenthesized)
1278+
{
1279+
return parenthesized.Parent is BinaryExpressionSyntax { RawKind: (int)SyntaxKind.SubtractExpression } binary &&
1280+
binary.Left == parenthesized;
1281+
}
1282+
12551283
private void CheckAddressOfInAsyncOrIteratorMethod(SyntaxNode node, BindValueKind valueKind, BindingDiagnosticBag diagnostics)
12561284
{
12571285
if (valueKind == BindValueKind.AddressOf)

0 commit comments

Comments
 (0)