Skip to content

Commit e154e00

Browse files
authored
Add initial support for Union matching (#81188)
Relates to test plan #81074
1 parent 702f0fe commit e154e00

30 files changed

+3680
-358
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1978,7 +1978,7 @@ private BoundExpression ConvertSwitchExpression(BoundUnconvertedSwitchExpression
19781978
? CreateConversion(oldValue.Syntax, oldValue, underlyingConversions[i], isCast: false, conversionGroupOpt: null, destination, diagnostics)
19791979
: GenerateConversionForAssignment(destination, oldValue, diagnostics);
19801980
var newCase = (oldValue == newValue) ? oldCase :
1981-
new BoundSwitchExpressionArm(oldCase.Syntax, oldCase.Locals, oldCase.Pattern, oldCase.WhenClause, newValue, oldCase.Label, oldCase.HasErrors);
1981+
new BoundSwitchExpressionArm(oldCase.Syntax, oldCase.Locals, oldCase.Pattern, oldCase.HasUnionMatching, oldCase.WhenClause, newValue, oldCase.Label, oldCase.HasErrors);
19821982
builder.Add(newCase);
19831983
}
19841984
conversion.MarkUnderlyingConversionsChecked();

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4865,19 +4865,23 @@ private BoundExpression BindIsOperator(BinaryExpressionSyntax node, BindingDiagn
48654865
operand = ToBadExpression(operand);
48664866
}
48674867

4868+
TypeSymbol inputType = operand.Type;
4869+
NamedTypeSymbol unionType = PrepareForUnionMatchingIfAppropriateAndReturnUnionType(node, ref inputType, isPatternDiagnostics);
4870+
48684871
bool hasErrors = node.Right.HasErrors;
4869-
var convertedExpression = BindExpressionForPattern(operand.Type, node.Right, ref hasErrors, isPatternDiagnostics, out var constantValueOpt, out var wasExpression, out _);
4872+
var convertedExpression = BindExpressionForPattern(inputType, node.Right, ref hasErrors, isPatternDiagnostics, out var constantValueOpt, out var wasExpression, out _);
48704873
if (wasExpression)
48714874
{
48724875
hasErrors |= constantValueOpt is null;
48734876
isTypeDiagnostics.Free();
48744877
diagnostics.AddRangeAndFree(isPatternDiagnostics);
4878+
48754879
var boundConstantPattern = new BoundConstantPattern(
4876-
node.Right, convertedExpression, constantValueOpt ?? ConstantValue.Bad, operand.Type, convertedExpression.Type ?? operand.Type, hasErrors)
4880+
node.Right, convertedExpression, constantValueOpt ?? ConstantValue.Bad, isUnionMatching: unionType is not null, inputType: unionType ?? inputType, convertedExpression.Type ?? inputType, hasErrors)
48774881
#pragma warning disable format
48784882
{ WasCompilerGenerated = true };
48794883
#pragma warning restore format
4880-
return MakeIsPatternExpression(node, operand, boundConstantPattern, resultType, operandHasErrors, diagnostics);
4884+
return MakeIsPatternExpression(node, operand, boundConstantPattern, boundConstantPattern.IsUnionMatching, resultType, operandHasErrors, diagnostics);
48814885
}
48824886

48834887
isPatternDiagnostics.Free();

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

Lines changed: 422 additions & 225 deletions
Large diffs are not rendered by default.

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,25 +115,27 @@ public static BoundDecisionDag CreateDecisionDagForIsPattern(
115115
SyntaxNode syntax,
116116
BoundExpression inputExpression,
117117
BoundPattern pattern,
118+
bool hasUnionMatching,
118119
LabelSymbol whenTrueLabel,
119120
LabelSymbol whenFalseLabel,
120121
BindingDiagnosticBag diagnostics,
121122
bool forLowering = false)
122123
{
123124
var builder = new DecisionDagBuilder(compilation, defaultLabel: whenFalseLabel, forLowering, diagnostics);
124-
return builder.CreateDecisionDagForIsPattern(syntax, inputExpression, pattern, whenTrueLabel);
125+
return builder.CreateDecisionDagForIsPattern(syntax, inputExpression, pattern, hasUnionMatching, whenTrueLabel);
125126
}
126127

127128
private BoundDecisionDag CreateDecisionDagForIsPattern(
128129
SyntaxNode syntax,
129130
BoundExpression inputExpression,
130131
BoundPattern pattern,
132+
bool hasUnionMatching,
131133
LabelSymbol whenTrueLabel)
132134
{
133135
var rootIdentifier = BoundDagTemp.ForOriginalInput(inputExpression);
134136

135137
using var builder = TemporaryArray<StateForCase>.Empty;
136-
builder.Add(MakeTestsForPattern(index: 1, pattern.Syntax, rootIdentifier, pattern, whenClause: null, whenTrueLabel));
138+
builder.Add(MakeTestsForPattern(index: 1, pattern.Syntax, rootIdentifier, pattern, hasUnionMatching, whenClause: null, whenTrueLabel));
137139

138140
return MakeBoundDecisionDag(syntax, ref builder.AsRef());
139141
}
@@ -152,7 +154,7 @@ private BoundDecisionDag CreateDecisionDagForSwitchStatement(
152154
{
153155
if (label.Syntax.Kind() != SyntaxKind.DefaultSwitchLabel)
154156
{
155-
builder.Add(MakeTestsForPattern(++i, label.Syntax, rootIdentifier, label.Pattern, label.WhenClause, label.Label));
157+
builder.Add(MakeTestsForPattern(++i, label.Syntax, rootIdentifier, label.Pattern, label.HasUnionMatching, label.WhenClause, label.Label));
156158
}
157159
}
158160
}
@@ -172,7 +174,7 @@ private BoundDecisionDag CreateDecisionDagForSwitchExpression(
172174
int i = 0;
173175
using var builder = TemporaryArray<StateForCase>.GetInstance(switchArms.Length);
174176
foreach (BoundSwitchExpressionArm arm in switchArms)
175-
builder.Add(MakeTestsForPattern(++i, arm.Syntax, rootIdentifier, arm.Pattern, arm.WhenClause, arm.Label));
177+
builder.Add(MakeTestsForPattern(++i, arm.Syntax, rootIdentifier, arm.Pattern, arm.HasUnionMatching, arm.WhenClause, arm.Label));
176178

177179
return MakeBoundDecisionDag(syntax, ref builder.AsRef());
178180
}
@@ -185,9 +187,15 @@ private StateForCase MakeTestsForPattern(
185187
SyntaxNode syntax,
186188
BoundDagTemp input,
187189
BoundPattern pattern,
190+
bool hasUnionMatching,
188191
BoundExpression? whenClause,
189192
LabelSymbol label)
190193
{
194+
if (hasUnionMatching)
195+
{
196+
pattern = UnionMatchingRewriter.Rewrite(_compilation, pattern);
197+
}
198+
191199
Tests tests = MakeAndSimplifyTestsAndBindings(input, pattern, out ImmutableArray<BoundPatternBinding> bindings);
192200
return new StateForCase(index, syntax, tests, bindings, whenClause, label);
193201
}
@@ -330,6 +338,7 @@ private Tests MakeTestsAndBindings(
330338
out BoundDagTemp output,
331339
ArrayBuilder<BoundPatternBinding> bindings)
332340
{
341+
Debug.Assert(!pattern.IsUnionMatching);
333342
Debug.Assert(pattern.HasErrors || pattern.InputType.Equals(input.Type, TypeCompareKind.AllIgnoreOptions) || pattern.InputType.IsErrorType());
334343
switch (pattern)
335344
{

0 commit comments

Comments
 (0)