Interpolated string handlers in the CFG#57483
Conversation
Support for arguments from context is not in this commit, it will be in the next one.
|
@AlekseyTs @chsienki for review of this PR. |
|
#57484 covers the API proposal for |
* Fix a few bugs revealed by the IOperation hook. * Substitute `IInstanceReferenceOperation`s for the handler capture where appropriate.
* upstream/main: (51 commits) Disable sql when built from source Fix Reduce indirections Reduce indirections Rename files Fix nullability warning Update cloud cache in the same way Ensure only one storage service factory gets created per workspace. Remove processed typename check Simplify Equals method Build CodeAction description into table and only generate Dev17 hash Avoid recomputing expensive persistence location data that does not change. Options Refactoring - Round 3 (dotnet#57254) Merge pull request dotnet#57509 from dotnet/dev/rigibson/fix-publishdata Classify method group assignments as methods (dotnet#57410) Simplify NRT Simplify Remove unnecessary workaround code. Simplify ...
|
@AlekseyTs @chsienki please take another look. |
| { | ||
| return args.Any( | ||
| static (arg, unwrapper) => unwrapper(arg) switch | ||
| { |
| IInterpolatedStringHandlerArgumentPlaceholderOperation { PlaceholderKind: not InterpolatedStringArgumentPlaceholderKind.TrailingValidityArgument } => true, | ||
| IConversionOperation | ||
| { | ||
| Operand: IInterpolatedStringHandlerArgumentPlaceholderOperation { PlaceholderKind: not InterpolatedStringArgumentPlaceholderKind.TrailingValidityArgument } |
| IInterpolatedStringHandlerArgumentPlaceholderOperation { PlaceholderKind: not InterpolatedStringArgumentPlaceholderKind.TrailingValidityArgument } => true, | ||
| IConversionOperation | ||
| { | ||
| Operand: IInterpolatedStringHandlerArgumentPlaceholderOperation { PlaceholderKind: not InterpolatedStringArgumentPlaceholderKind.TrailingValidityArgument } |
| return arguments.Any( | ||
| static arg => arg.Value switch | ||
| { | ||
| IInterpolatedStringHandlerCreationOperation { HandlerCreation: IObjectCreationOperation { Arguments: { } creationArgs } } => |
| PushOperand(VisitRequired(UnwrapArgumentDoNotCaptureDirectly(arguments[i]))); | ||
| } | ||
|
|
||
| bool visitArgument<T>(IOperation originalArgument, ImmutableArray<T> nestedArguments, Func<T, IOperation> unwrapper) where T : IOperation |
| return _placeholderDictionary[key]; | ||
| } | ||
|
|
||
| private void AddPlaceholder(IOperation key, IOperation value) |
| } | ||
| } | ||
|
|
||
| private IOperation GetPlaceholder(IOperation key) |
There was a problem hiding this comment.
These are no longer present.
| (_placeholderDictionary ??= PooledDictionary<IOperation, IOperation>.GetInstance()).Add(key, value); | ||
| } | ||
|
|
||
| private void RemovePlaceholder(IOperation key) |
|
|
||
| IOperation visitedArgument = VisitRequired(originalArgument); | ||
| Debug.Assert(visitedArgument is IFlowCaptureReferenceOperation); | ||
| visitedArguments.Add(visitedArgument); |
There was a problem hiding this comment.
| if (method != null) | ||
| { | ||
| var args = disposeMethod is object ? VisitArguments(disposeArguments) : ImmutableArray<IArgumentOperation>.Empty; | ||
| var args = VisitArray(disposeArguments, UnwrapArgument, RewriteArgumentFromArray); |
There was a problem hiding this comment.
I think that in the long term it would be better to keep calling VisitArguments with appropriate value for the second parameter.
| if (arguments != null) | ||
| { | ||
| return VisitArguments(arguments); | ||
| return VisitArray(arguments, UnwrapArgument, RewriteArgumentFromArray); |
| { | ||
| EvalStackFrame frame = PushStackFrame(); | ||
| EvalStackFrame argumentsFrame = PushStackFrame(); | ||
| ImmutableArray<IArgumentOperation> visitedArgs = VisitArguments(operation.Arguments); |
There was a problem hiding this comment.
Because the first approach needed this version of the call, and I didn't fully revert this bit when I took the new approach.
| int outParameterFlowCapture = -1; | ||
| IOperation? outParameterPlaceholder = null; | ||
|
|
||
| if (operation.HandlerCreationHasSuccessParameter) |
There was a problem hiding this comment.
We can call collectAppendCalls before this if and, if the set is empty, not enter the if, leaving outParameterFlowCapture == -1. Then we suppress creation of conditional branch in the if below when outParameterFlowCapture == -1. Then we can adjust VisitInterpolatedStringHandlerArgumentPlaceholder to create IDiscardOperation in this case. This way we can eliminate an unnecessary branch, see InterpolatedStringHandlerConversionFlow_16 for example. This work doesn't look prohibiteviley complex or expensive to me. #Closed
There was a problem hiding this comment.
I filed #57611 to track doing this work at some point in the future.
|
Done with review pass (commit 8) |
|
@AlekseyTs addressed feedback. In reply to: 962158460 |
|
It looks like the build is broken |
We probably want to pass In reply to: 963303268 In reply to: 963303268 Refers to: src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs:5721 in 3ecd8ad. [](commit_id = 3ecd8ad, deletion_comment = False) |
|
|
||
| #if DEBUG | ||
| Debug.Assert(_evalStack[maxStackDepth + 1].frameOpt != null); | ||
| if (_currentInterpolatedStringHandlerArgumentContext?.ApplicableCreationOperations.Contains(operation) ?? false) |
|
|
||
| #if DEBUG | ||
| Debug.Assert(_evalStack[maxStackDepth + 1].frameOpt != null); | ||
| if (_currentInterpolatedStringHandlerArgumentContext?.ApplicableCreationOperations.Contains(operation) ?? false) |
|
Done with review pass (commit 10) |
| { | ||
| internal static class SpanExtensions | ||
| { | ||
| public static bool Any<T>(this ReadOnlySpan<T> span, Func<T, bool> predicate) |
AlekseyTs
left a comment
There was a problem hiding this comment.
LGTM (commit 12), assuming CI is passing.
|
/azp run |
|
Azure Pipelines successfully started running 4 pipeline(s). |
Closes #54718. Implements support for interpolated string handlers in the CFG. For ease of review, I recommend reviewing commits 1 and 2 separately: commit 1 implements lowering for interpolated string handlers without supporting containing context. Commit 2 adds the machinery to set up the containing context and uses it everywhere we have arguments in the IOperation machinery.