Closed 333fred closed 3 years ago
We discussed this in depth today, and some members are worried that we're over-specifying the API here. We'll dig into this again in a future API review session with more concrete tree examples.
I've added some examples of the trees to the original comment. Note that some of the properties will be a bit off (such as syntax) as I've bodged together a bunch of different examples, but it should at least be the correct general shape.
We've generally agreed that the interface should expose the Append calls as children directly, rather than trying to add the information to IInterpolatedTextOperation
or IInterpolatedContentOperation
. We don't want to expose the data on IBinaryOperation
directly: we feel it's surprising and a violation of layering, and that the IInterpolatedStringOperation
should be the top node. We have a few options we're considering:
IInterpolatedStringOperation
. While this is the most faithful to the semantics of the language, we're concerned about the ergonomics of not having IOperation
nodes that correspond to nested BinaryExpressionSyntax
es or InterpolatedStringExpressionSyntax
es, which this approach would necessitate.IBinaryContentOperation
or similar nodes that represent the binary operations themselves, and are part of the Parts
array on the root IInterpolatedStringOperation
node. While this is more complex and more of a "syntactic" view, it will alleviate the concerns about missing explicit syntax nodes.A smaller team will explore this space and update the design.
One other note is that we should have a flag on IInterpolatedStringAppendOperation
that indicates whether the content is a literal or an interpolation placeholder.
We'll use IInvalidOperation
for bad arguments in the handler creation, rather than IInterpolatedStringHandlerArgumentPlaceholderOperation
. For the receiver node, IInterpolatedStringHandlerArgumentPlaceholderOperation.ArgumentIndex
will be -1, and IsContainingMethodReceiver
will be removed. Otherwise, the API looks good as currently defined.
The update is generally approved, with the following names for the enum:
public enum InterpolatedStringArgumentPlaceholderKind
{
CallsiteArgument,
CallsiteReceiver,
TrailingValidityArgument,
}
Background and Motivation
C# 10 adds interpolated string handler conversions. These conversions have a number of new components that don't map to existing interpolated string nodes, so we need to add public API support for them.
Proposed API
Alternative Designs
We could potentially introduce an
IPlaceholderOperation
instead ofIInterpolatedStringHandlerArgumentPlaceholder
, with an additionalPlaceholderKind
enum to differentiate the variants. However, that a) doesn't follow existing patterns, such asIInstanceReferenceOperation
, and b) I don't believe that it's actually useful to operate on all placeholders regardless of what type of placeholder it is.I debated for a while on whether we should have
HandlerAppendCallsReturnBool
andHandlerCreationHasSuccessParameter
. The latter can be figured out by examining the call by hand, and the former could just be a single boolean that's true if there's any conditional evaluation of the holes. However, after implementing the BoundTree I foundHandlerCreationHasSuccessParameter
to be very valuable, and the single bool version is lossy. For full fidelity of the runtime semantics here, we do need both.We could potentially add a flag to
IInterpolatedStringAppendOperation
to say whether it'sAppendFormatted
orAppendLiteral
, but I think that's fine to grab the call and examine the type symbol for.Examples of IOperation Trees
Followup Questions
In our original design, we did not approve a way to distinguish between placeholders for the receiver of the containing method, and the optional trailing out parameter placeholder.