Skip to content

Interpolated string handlers in the CFG#57483

Merged
333fred merged 14 commits intodotnet:mainfrom
333fred:interpolated-cfg
Nov 9, 2021
Merged

Interpolated string handlers in the CFG#57483
333fred merged 14 commits intodotnet:mainfrom
333fred:interpolated-cfg

Conversation

@333fred
Copy link
Copy Markdown
Member

@333fred 333fred commented Oct 30, 2021

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.

Support for arguments from context is not in this commit, it will be in the next one.
@333fred 333fred requested a review from a team as a code owner October 30, 2021 00:26
@ghost ghost added the Area-Compilers label Oct 30, 2021
@333fred
Copy link
Copy Markdown
Member Author

333fred commented Oct 30, 2021

@AlekseyTs @chsienki for review of this PR.

@333fred 333fred requested review from AlekseyTs and chsienki October 30, 2021 00:47
@333fred
Copy link
Copy Markdown
Member Author

333fred commented Oct 30, 2021

#57484 covers the API proposal for IsInitialized.

Comment thread src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs
Comment thread src/Compilers/Core/Portable/Operations/OperationNodes.cs Outdated
Comment thread src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs Outdated
Comment thread src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs Outdated
* 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
  ...
@333fred
Copy link
Copy Markdown
Member Author

333fred commented Nov 2, 2021

@AlekseyTs @chsienki please take another look.

{
return args.Any(
static (arg, unwrapper) => unwrapper(arg) switch
{
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{

The alignment looks wrong. #Closed

IInterpolatedStringHandlerArgumentPlaceholderOperation { PlaceholderKind: not InterpolatedStringArgumentPlaceholderKind.TrailingValidityArgument } => true,
IConversionOperation
{
Operand: IInterpolatedStringHandlerArgumentPlaceholderOperation { PlaceholderKind: not InterpolatedStringArgumentPlaceholderKind.TrailingValidityArgument }
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IInterpolatedStringHandlerArgumentPlaceholderOperation

This looks fragile. I think when user-defined conversions are involved, the original operand might not be the immediate operand of a top level conversion. #Closed

IInterpolatedStringHandlerArgumentPlaceholderOperation { PlaceholderKind: not InterpolatedStringArgumentPlaceholderKind.TrailingValidityArgument } => true,
IConversionOperation
{
Operand: IInterpolatedStringHandlerArgumentPlaceholderOperation { PlaceholderKind: not InterpolatedStringArgumentPlaceholderKind.TrailingValidityArgument }
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not InterpolatedStringArgumentPlaceholderKind.TrailingValidityArgument

Can this check ever fail? #Closed

return arguments.Any(
static arg => arg.Value switch
{
IInterpolatedStringHandlerCreationOperation { HandlerCreation: IObjectCreationOperation { Arguments: { } creationArgs } } =>
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IInterpolatedStringHandlerCreationOperation

I do not see any benefit from repeating this type check for every case within the switch. It feels like the code will be easier to follow when the type check is moved outside and performed once. #Closed

PushOperand(VisitRequired(UnwrapArgumentDoNotCaptureDirectly(arguments[i])));
}

bool visitArgument<T>(IOperation originalArgument, ImmutableArray<T> nestedArguments, Func<T, IOperation> unwrapper) where T : IOperation
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IOperation

IInterpolatedStringHandlerCreationOperation? #Closed

return _placeholderDictionary[key];
}

private void AddPlaceholder(IOperation key, IOperation value)
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AddPlaceholder

AddPlaceholderReplacement? #Closed

}
}

private IOperation GetPlaceholder(IOperation key)
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetPlaceholder

GetPlaceholderReplacement? #Closed

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are no longer present.

(_placeholderDictionary ??= PooledDictionary<IOperation, IOperation>.GetInstance()).Add(key, value);
}

private void RemovePlaceholder(IOperation key)
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RemovePlaceholder

RemovePlaceholderReplacement? #Closed


IOperation visitedArgument = VisitRequired(originalArgument);
Debug.Assert(visitedArgument is IFlowCaptureReferenceOperation);
visitedArguments.Add(visitedArgument);
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

visitedArguments.Add(visitedArgument);

I think the logic would be simpler to follow if we were to limit the purpose of this method to visiting IInterpolatedStringHandlerCreationOperation argument and returning it. The caller can handle adition of the result to the list. #Closed

if (method != null)
{
var args = disposeMethod is object ? VisitArguments(disposeArguments) : ImmutableArray<IArgumentOperation>.Empty;
var args = VisitArray(disposeArguments, UnwrapArgument, RewriteArgumentFromArray);
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var args = VisitArray(disposeArguments, UnwrapArgument, RewriteArgumentFromArray);

It is not obvious why we need to make changes here, especially removal of the conditional logic looks suspicious #Closed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VisitArray

I think that in the long term it would be better to keep calling VisitArguments with appropriate value for the second parameter. #Closed

{
EvalStackFrame frame = PushStackFrame();
EvalStackFrame argumentsFrame = PushStackFrame();
ImmutableArray<IArgumentOperation> visitedArgs = VisitArguments(operation.Arguments);
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VisitArguments

It is not clear why we simply didn't pass false as the second argument. #Closed

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (operation.HandlerCreationHasSuccessParameter)

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I filed #57611 to track doing this work at some point in the future.

@AlekseyTs
Copy link
Copy Markdown
Contributor

Done with review pass (commit 8)

@333fred
Copy link
Copy Markdown
Member Author

333fred commented Nov 5, 2021

@AlekseyTs addressed feedback.


In reply to: 962158460

@AlekseyTs
Copy link
Copy Markdown
Contributor

It looks like the build is broken

@AlekseyTs
Copy link
Copy Markdown
Contributor

AlekseyTs commented Nov 8, 2021

            ImmutableArray<IArgumentOperation> visitedArguments = VisitArguments(arguments);

We probably want to pass false as the second parameter here.


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)
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tentiall

== true? #Closed


#if DEBUG
Debug.Assert(_evalStack[maxStackDepth + 1].frameOpt != null);
if (_currentInterpolatedStringHandlerArgumentContext?.ApplicableCreationOperations.Contains(operation) ?? false)
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

of appe

It looks like we are leaving the room for the Contains to not find the match. I.e. we will not assert here, at the same time, it looks like we will use _currentInterpolatedStringHandlerArgumentContext regardless. #Closed

@AlekseyTs
Copy link
Copy Markdown
Contributor

Done with review pass (commit 10)

{
internal static class SpanExtensions
{
public static bool Any<T>(this ReadOnlySpan<T> span, Func<T, bool> predicate)
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Nov 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any

Do we still use this helper? #Resolved

Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (commit 12), assuming CI is passing.

@333fred
Copy link
Copy Markdown
Member Author

333fred commented Nov 9, 2021

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 4 pipeline(s).

@333fred 333fred enabled auto-merge (squash) November 9, 2021 01:39
@333fred 333fred merged commit 573f06d into dotnet:main Nov 9, 2021
@ghost ghost added this to the Next milestone Nov 9, 2021
@333fred 333fred deleted the interpolated-cfg branch November 9, 2021 03:29
@allisonchou allisonchou modified the milestones: Next, 17.1.P2 Nov 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IOperation support for interpolated string handler conversions

5 participants