-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Explainer for list-patterns #57210
Explainer for list-patterns #57210
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -177,6 +177,7 @@ private static string SamplePatternForTemp( | |
tryHandleTuplePattern(ref unnamedEnumValue) ?? | ||
tryHandleNumericLimits(ref unnamedEnumValue) ?? | ||
tryHandleRecursivePattern(ref unnamedEnumValue) ?? | ||
tryHandleListPattern(ref unnamedEnumValue) ?? | ||
produceFallbackPattern(); | ||
|
||
static ImmutableArray<T> getArray<T>(Dictionary<BoundDagTemp, ArrayBuilder<T>> map, BoundDagTemp temp) | ||
|
@@ -319,6 +320,95 @@ void addRelation(BinaryOperatorKind relation, ConstantValue value) | |
return null; | ||
} | ||
|
||
// Handle the special case of a list pattern | ||
string tryHandleListPattern(ref bool unnamedEnumValue) | ||
{ | ||
if (constraints.IsEmpty && evaluations.IsEmpty) | ||
return null; | ||
|
||
if (!constraints.All(c => c switch | ||
{ | ||
// not-null tests are implicitly incorporated into a recursive pattern | ||
(test: BoundDagNonNullTest _, sense: true) => true, | ||
(test: BoundDagExplicitNullTest _, sense: false) => true, | ||
_ => false, | ||
})) | ||
{ | ||
return null; | ||
} | ||
|
||
var indexes = new Dictionary<int, string>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did not know you were working on this. I took a different approach to handle trailing patterns. Updated #55327 just in case. We should def go with your change since this is closer to completion. :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I got a bit excited this weekend and gave it a try. Thanks |
||
int length = -1; | ||
|
||
foreach (var eval in evaluations) | ||
{ | ||
switch (eval) | ||
{ | ||
case BoundDagPropertyEvaluation e when e.IsLengthOrCount: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's unlikely to have multiple length tests in the shortest path. I suspect this doesn't need to be in the loop. |
||
{ | ||
Debug.Assert(length == -1); | ||
var subInput = new BoundDagTemp(e.Syntax, e.Property.Type, e); | ||
var lengthValue = SamplePatternForTemp(subInput, constraintMap, evaluationMap, false, ref unnamedEnumValue); | ||
if (int.TryParse(lengthValue, out var parsedLength)) | ||
{ | ||
Debug.Assert(parsedLength >= 0); | ||
length = parsedLength; | ||
} | ||
} | ||
break; | ||
case BoundDagIndexerEvaluation e: | ||
{ | ||
var subInput = new BoundDagTemp(e.Syntax, e.IndexerType, e); | ||
var subPattern = SamplePatternForTemp(subInput, constraintMap, evaluationMap, false, ref unnamedEnumValue); | ||
indexes.Add(e.Index, subPattern); | ||
} | ||
break; | ||
case BoundDagSliceEvaluation e: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This may produce multiple slice patterns in the list but since we won't construct a dag for invalid patterns that probably won't happen. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, we don't get here when multiple slices. Added test |
||
{ | ||
if (e.StartIndex < length + e.EndIndex) | ||
{ | ||
var subInput = new BoundDagTemp(e.Syntax, e.SliceType, e); | ||
var subPattern = SamplePatternForTemp(subInput, constraintMap, evaluationMap, false, ref unnamedEnumValue); | ||
indexes.Add(e.StartIndex, ".. " + subPattern); | ||
} | ||
} | ||
break; | ||
default: | ||
return null; | ||
} | ||
} | ||
|
||
if (length < 0) | ||
{ | ||
Debug.Assert(false); | ||
return null; | ||
} | ||
|
||
var pooledBuilder = PooledStringBuilder.GetInstance(); | ||
var builder = pooledBuilder.Builder; | ||
|
||
builder.Append("["); | ||
for (int i = 0; i < length; i++) | ||
{ | ||
string sample = (indexes.TryGetValue(i, out var sampleFromStart), indexes.TryGetValue(i - length, out var sampleFromEnd)) switch | ||
{ | ||
(true, false) => sampleFromStart, | ||
(false, true) => sampleFromEnd, | ||
_ => "_" | ||
}; | ||
|
||
if (builder.Length > 1) | ||
{ | ||
builder.Append(", "); | ||
} | ||
|
||
builder.Append(sample); | ||
} | ||
builder.Append("]"); | ||
|
||
return pooledBuilder.ToStringAndFree(); | ||
} | ||
|
||
// Handle the special case of a recursive pattern | ||
string tryHandleRecursivePattern(ref bool unnamedEnumValue) | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doing this after recursive patterns will make it unnecessary to worry about
[]
or[..]
but we may choose to generate those instead.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that something I've been debating. Should we say
{ Length: 0 }
or[]
?