Skip to content

Commit e001c59

Browse files
authored
Report ERR_PatternWrongType for Union matching scenarios (#81352)
Relates to test plan: #81074
1 parent e154e00 commit e001c59

File tree

7 files changed

+1493
-84
lines changed

7 files changed

+1493
-84
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4869,7 +4869,7 @@ private BoundExpression BindIsOperator(BinaryExpressionSyntax node, BindingDiagn
48694869
NamedTypeSymbol unionType = PrepareForUnionMatchingIfAppropriateAndReturnUnionType(node, ref inputType, isPatternDiagnostics);
48704870

48714871
bool hasErrors = node.Right.HasErrors;
4872-
var convertedExpression = BindExpressionForPattern(inputType, node.Right, ref hasErrors, isPatternDiagnostics, out var constantValueOpt, out var wasExpression, out _);
4872+
var convertedExpression = BindExpressionForPattern(unionType, inputType, node.Right, ref hasErrors, isPatternDiagnostics, out var constantValueOpt, out var wasExpression, out _);
48734873
if (wasExpression)
48744874
{
48754875
hasErrors |= constantValueOpt is null;

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

Lines changed: 241 additions & 73 deletions
Large diffs are not rendered by default.

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,9 @@ private void BuildSwitchLabels(SyntaxList<SwitchLabelSyntax> labelsSyntax, Binde
223223
case SyntaxKind.CasePatternSwitchLabel:
224224
// bind the pattern, to cause its pattern variables to be inferred if necessary
225225
var matchLabel = (CasePatternSwitchLabelSyntax)labelSyntax;
226+
NamedTypeSymbol unionType = null;
226227
_ = sectionBinder.BindPattern(
227-
matchLabel.Pattern, SwitchGoverningType, permitDesignations: true, labelSyntax.HasErrors, tempDiagnosticBag, hasUnionMatching: out _);
228+
matchLabel.Pattern, ref unionType, SwitchGoverningType, permitDesignations: true, labelSyntax.HasErrors, tempDiagnosticBag, hasUnionMatching: out _);
228229
break;
229230

230231
default:
@@ -270,7 +271,10 @@ protected BoundExpression ConvertCaseExpression(CSharpSyntaxNode node, BoundExpr
270271
caseExpression = CreateConversion(caseExpression, conversion, SwitchGoverningType, diagnostics);
271272
}
272273

273-
return ConvertPatternExpression(SwitchGoverningType, node, caseExpression, out constantValueOpt, hasErrors, diagnostics, out _);
274+
// PROTOTYPE: Test that consumer actually does the right thing when a union matching is involved. Cover error scenarios as well.
275+
var inputType = SwitchGoverningType;
276+
NamedTypeSymbol unionType = PrepareForUnionMatchingIfAppropriateAndReturnUnionType(node, ref inputType, diagnostics);
277+
return ConvertPatternExpression(unionType, inputType, node, caseExpression, out constantValueOpt, hasErrors, diagnostics, out _);
274278
}
275279

276280
private static readonly object s_nullKey = new object();

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,9 @@ private BoundSwitchLabel BindSwitchSectionLabel(
247247
{
248248
var caseLabelSyntax = (CaseSwitchLabelSyntax)node;
249249
bool hasErrors = node.HasErrors;
250+
NamedTypeSymbol unionType = null;
250251
BoundPattern pattern = sectionBinder.BindConstantPatternWithFallbackToTypePattern(
251-
caseLabelSyntax.Value, caseLabelSyntax.Value, SwitchGoverningType, hasErrors, diagnostics, out bool hasUnionMatching);
252+
caseLabelSyntax.Value, caseLabelSyntax.Value, ref unionType, SwitchGoverningType, hasErrors, diagnostics, out bool hasUnionMatching);
252253
pattern.WasCompilerGenerated = true; // we don't have a pattern syntax here
253254
reportIfConstantNamedUnderscore(pattern, caseLabelSyntax.Value);
254255

@@ -279,8 +280,9 @@ private BoundSwitchLabel BindSwitchSectionLabel(
279280

280281
MessageID.IDS_FeaturePatternMatching.CheckFeatureAvailability(diagnostics, node.Keyword);
281282

283+
NamedTypeSymbol unionType = null;
282284
BoundPattern pattern = sectionBinder.BindPattern(
283-
matchLabelSyntax.Pattern, SwitchGoverningType, permitDesignations: true, node.HasErrors, diagnostics, out bool hasUnionMatching);
285+
matchLabelSyntax.Pattern, ref unionType, SwitchGoverningType, permitDesignations: true, node.HasErrors, diagnostics, out bool hasUnionMatching);
284286
if (matchLabelSyntax.Pattern is ConstantPatternSyntax p)
285287
reportIfConstantNamedUnderscore(pattern, p.Expression);
286288

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ internal override BoundSwitchExpressionArm BindSwitchExpressionArm(SwitchExpress
3939
Binder armBinder = this.GetRequiredBinder(node);
4040
bool hasErrors = switchGoverningType.IsErrorType();
4141
ImmutableArray<LocalSymbol> locals = _armScopeBinder.Locals;
42-
BoundPattern pattern = armBinder.BindPattern(node.Pattern, switchGoverningType, permitDesignations: true, hasErrors, diagnostics, out bool hasUnionMatching);
42+
NamedTypeSymbol? unionType = null;
43+
BoundPattern pattern = armBinder.BindPattern(node.Pattern, ref unionType, switchGoverningType, permitDesignations: true, hasErrors, diagnostics, out bool hasUnionMatching);
4344
BoundExpression? whenClause = node.WhenClause != null
4445
? armBinder.BindBooleanExpression(node.WhenClause.Condition, diagnostics)
4546
: null;

src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,9 +2139,8 @@ internal static bool IsWellKnownTypeUnmanagedType(this TypeSymbol typeSymbol)
21392139
internal static bool IsWellKnownTypeIsExternalInit(this TypeSymbol typeSymbol)
21402140
=> typeSymbol.IsWellKnownCompilerServicesTopLevelType("IsExternalInit");
21412141

2142-
internal static bool IsWellKnownTypeIUnion(this NamedTypeSymbol typeSymbol)
2143-
=> typeSymbol.DeclaredAccessibility == Accessibility.Public &&
2144-
typeSymbol.IsInterface &&
2142+
internal static bool IsWellKnownTypeIUnion(this NamedTypeSymbol typeSymbol) // PROTOTYPE: Test individual conditions
2143+
=> typeSymbol is { DeclaredAccessibility: Accessibility.Public, IsInterface: true, IsGenericType: false } &&
21452144
typeSymbol.IsWellKnownCompilerServicesTopLevelType(WellKnownMemberNames.IUnionInterfaceName); // PROTOTYPE: Confirm namespace, the spec doesn't specify it at the moment.
21462145

21472146
internal static bool IsWellKnownTypeOutAttribute(this TypeSymbol typeSymbol) => typeSymbol.IsWellKnownInteropServicesTopLevelType("OutAttribute");

0 commit comments

Comments
 (0)