Skip to content
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

InterpolatedStringHandlerArgumentAttribute Decoding #53932

Conversation

333fred
Copy link
Member

@333fred 333fred commented Jun 8, 2021

Validate and decode InterpolatedStringHandlerArgumentAttribute from source and from metadata. This doesn't implement call-site validation, just errors on attribute usage and metadata decoding.

Test plan: #51499

@333fred 333fred requested a review from a team as a code owner June 8, 2021 00:00
@333fred
Copy link
Member Author

333fred commented Jun 8, 2021

@chsienki @AlekseyTs for review.

if (PEModule.CrackStringArrayInAttributeValue(out additionalLanguageNames, ref argsReader))
{
if (additionalLanguageNames.Length == 0)
{
return SpecializedCollections.SingletonEnumerable(firstLanguageName);
return firstLanguageName == null ? SpecializedCollections.EmptyEnumerable<string>() : SpecializedCollections.SingletonEnumerable(firstLanguageName);
}
Copy link
Contributor

@chsienki chsienki Jun 8, 2021

Choose a reason for hiding this comment

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

Previously this would return an array of one null string in the case it read null from the language, or the additional languages with null at the end. I suspect it makes no difference, but want to check that behavior change doesn't break anything. #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

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

Users already had to deal with the empty list as a possible return. I don't think this really introduces anything new.

break;

default:
var param = parameters.FirstOrDefault(static (p, name) => string.Equals(p.Name, name, StringComparison.Ordinal), name);
Copy link
Contributor

@chsienki chsienki Jun 8, 2021

Choose a reason for hiding this comment

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

Given that this is the only place we're using FirstOrDefault, is it worth just putting the implementation here, avoiding the lambda, and probably isnt any more lines of code as you don't need the below checks? #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think so. I prefer it the way I wrote it.

ArrayBuilder<ParameterSymbol?> parameters;
if (constructorArgument.Kind == TypedConstantKind.Primitive)
{
if (decodeName(constructorArgument, ref arguments) is (int ordinal, var parameter))
Copy link
Contributor

@chsienki chsienki Jun 8, 2021

Choose a reason for hiding this comment

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

Consider using is not and inverting the conditional.

if (decodeName(constructorArgument, ref arguments) is not (int ordinal, var parameter))
{
    return;
}
parameterOrdinals = ImmutableArray.Create(ordinal);
parameters = ArrayBuilder<ParameterSymbol?>.GetInstance(1);
parameters.Add(parameter);
``` #Resolved

return (-1, null);
}

ImmutableArray<ParameterSymbol> parameters = ContainingSymbol switch
Copy link
Contributor

@chsienki chsienki Jun 8, 2021

Choose a reason for hiding this comment

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

Could do this once, outside the function #Resolved

@@ -1048,6 +1057,199 @@ bool needsReporting()
}
}

#nullable enable
private void DecodeInterpolatedStringHandlerArgumentAttribute(ref DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation> arguments, Binder binder, BindingDiagnosticBag diagnostics)
Copy link
Contributor

@chsienki chsienki Jun 8, 2021

Choose a reason for hiding this comment

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

I guess i'm suprised that we would need the binder in order to decode the attribute. I see below that we're doing overload resolution to determine if its valid or not. Would an alternative be to just decode the raw strings here? Then wherever we actually use them in the binder, do the actual resolution etc? We can always get back to them from the containing symbol I think? (they always apply to other parameters in the same list as the one the attribute is on?) #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

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

Would an alternative be to just decode the raw strings here?

We could, yes, but then you don't get validation of the attribute at the attribute definition location. This seems suboptimal to me.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, yeah thats a bummer. Just seems like we're doing a lot of work here that as a caller I woulnd't expect to happen. Do we have anywhere else where the attribute itself can error based on semantics of other code?


In reply to: 647835991 [](ancestors = 647835991)

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm. Could we not just store the location along with the cracked data? So we can report on it if it fails later on?

Copy link
Member Author

Choose a reason for hiding this comment

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

So we can report on it if it fails later on?

This doesn't help if you never use it in this project (as I would expect many to do, since these will mostly be used in libraries). Unless Aleksey has a different opinion or suggestion for how to approach this, I believe this is the right way to go.

Copy link
Member Author

Choose a reason for hiding this comment

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

After discussion with Aleksey, we've decided that there's too much potential for issue with missing references, retargeting, and langversion changes to move forward with this for now. I'll remove the binder code.

@chsienki
Copy link
Contributor

chsienki commented Jun 8, 2021

Done with review pass (iteration 4)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jun 9, 2021

    private static IEnumerable<string> ReadLanguagesFromAttribute(ref BlobReader argsReader)

How changes in this function are related to the goal of the PR?


In reply to: 857917744


In reply to: 857917744


In reply to: 857917744


In reply to: 857917744


Refers to: src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs:296 in b8ea696. [](commit_id = b8ea696, deletion_comment = False)

}
else if (TryExtractStringArrayValueFromAttribute(targetAttribute.Handle, out var paramNames))
{
Debug.Assert(targetAttribute.SignatureIndex == 1);
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

Debug.Assert(targetAttribute.SignatureIndex == 1);

It feels like the Assert is somewhat misplaced. Should we move it before we TryExtractStringArrayValueFromAttribute? #Closed

else if (TryExtractStringArrayValueFromAttribute(targetAttribute.Handle, out var paramNames))
{
Debug.Assert(targetAttribute.SignatureIndex == 1);
return paramNames.NullToEmpty();
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

paramNames.NullToEmpty()

Is an attribute with an empty array a valid form? If so, I think we should not represent invalid/broken forms with an empty array. This is applicable to other places in this function. Basically I think we should be able to judge from the result of GetInterpolatedStringHandlerArgumentAttributeValues if the attribute was missing or malformed. #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

Basically I think we should be able to judge from the result of GetInterpolatedStringHandlerArgumentAttributeValues if the attribute was missing or malformed.

I originally had it as default if missing/malformed, but thinking about it more I realized I didn't have a reason to need to understand the difference. Unless we want to actually error at the use site when we encounter a malformed attribute from metadata (which I didn't see the need to do), it feels like having the distinction really doesn't buy us much of anything.

Copy link
Contributor

Choose a reason for hiding this comment

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

Unless we want to actually error at the use site when we encounter a malformed attribute from metadata (which I didn't see the need to do), it feels like having the distinction really doesn't buy us much of anything.

My initial thinking is that we should fail to create a handler at the call site if there is a maformed InterpolatedStringHandlerArgumentAttribute attribute on the corresponding parameter.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll record whether the data has errors in a separate bit in the packed flags.

<value>Parameter to interpolated string handler conversion occurs after handler parameter</value>
</data>
<data name="ERR_CannotUseSelfAsInterpolatedStringHandlerArgument" xml:space="preserve">
<value>Interpolated string handler arguments cannot refer to themselves.</value>
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

Is this error about referring to the parameter in the attribute applied to the same parameter? Perhaps it would be clearer to say something like: "cannot be used to create a handler for this parameter"? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

I tried to make it a bit more clear. Let me know if you think it still needs work.

@@ -2020,6 +2020,13 @@

<Node Name="BoundInterpolatedStringHandlerPlaceholder" Base="BoundValuePlaceholderBase"/>

<!-- Type expression placeholder for the arguments to the constructor call for an interpolated string handler
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

Type expression

"Type expression" sounds a lot like BoundTypeExpression, but I believe this node doesn't represent a type reference. Because of that the comment feels confusing to me. I suggest saying "An expression" or "A typed expression" instead. #Closed

@333fred
Copy link
Member Author

333fred commented Jun 9, 2021

    private static IEnumerable<string> ReadLanguagesFromAttribute(ref BlobReader argsReader)

They resulted from me nullable enabling the decoding functions (which I did because I had missed a case in the attribute decoding and was suprised I didn't get a warning about it).


In reply to: 857917744


Refers to: src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs:296 in b8ea696. [](commit_id = b8ea696, deletion_comment = False)

@AlekseyTs
Copy link
Contributor

    private static IEnumerable<string> ReadLanguagesFromAttribute(ref BlobReader argsReader)

They resulted from me nullable enabling the decoding functions (which I did because I had missed a case in the attribute decoding and was suprised I didn't get a warning about it).

Since the change goes beyond just adding/adjusting annotations. I think the change should be taken out of this PR and out of this feature branch. If we need to suppress nulable warnings in this function to do this, that is what we should do, I think.


In reply to: 857971951


Refers to: src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs:296 in b8ea696. [](commit_id = b8ea696, deletion_comment = False)

MethodSymbol { Parameters: var p } => p,
PropertySymbol { Parameters: var p } => p,
_ => throw ExceptionUtilities.UnexpectedValue(ContainingSymbol)
};
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

It looks like we already have internal static ImmutableArray<ParameterSymbol> GetParameters(this Symbol member) helper that can be used here. #Closed

Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

BTW, are we going to crash on an event accessor parameter here?

case { Length: 0 } when ContainingSymbol.IsStatic:
// Invalid data, bail
builder.Free();
return ImmutableArray<int>.Empty;
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

return ImmutableArray.Empty;

As I mentioned elsewhere, I think we should not silently ignore malformed applications of the attribute at the call site of the method. #Closed

switch (name)
{
case null:
case { Length: 0 } when ContainingSymbol.IsStatic:
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

when ContainingSymbol.IsStatic:

I guess I am missing what static-ness of a container has to do with validity of the data? Is there a relevant spec? #Closed

Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

Perhaps the Length check confused me as I thought we are dealing with an array. Consider comparing with an empty string instead, for clarity. Below as well.

@@ -164,6 +164,8 @@ internal override ImmutableHashSet<string> NotNullIfParameterNotNull
get { return ImmutableHashSet<string>.Empty; }
}

internal override ImmutableArray<int> InterpolatedStringHandlerArgumentIndexes => _originalParam.InterpolatedStringHandlerArgumentIndexes;
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

_originalParam.InterpolatedStringHandlerArgumentIndexes;

Why is this needed? And why do we assume inxes won't change? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

Cloned parameter symbols share attribute data, so they shouldn't change.

Copy link
Contributor

Choose a reason for hiding this comment

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

Cloned parameter symbols share attribute data, so they shouldn't change.

Perhaps attribute applications shouldn't change, but the meaning of attributes can. It is quite possible that for other well-known attributes it isn't an issue because they are self-contained. However for this attribute, surrounding parameters and parameter ordinals are significant, etc. So, I would say we should reinterpret the attribute application rather than take it as is. But the question is whether there is a scenario where this particular symbol is required to expose this information at all. If not, then why return anything but a value indicating - fail creating a handler at the call site. Anything other than an "error" value would require thorough testing for this code path.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll make these throw for now and mark with a prototype, and we'll see if the indexes are needed during lowering in the next PR. I have a hunch they might be.

@@ -169,6 +169,8 @@ public override string GetDocumentationCommentXml(CultureInfo preferredCulture =
return _underlyingParameter.GetDocumentationCommentXml(preferredCulture, expandIncludes, cancellationToken);
}

internal override ImmutableArray<int> InterpolatedStringHandlerArgumentIndexes => _underlyingParameter.InterpolatedStringHandlerArgumentIndexes;
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

internal override ImmutableArray InterpolatedStringHandlerArgumentIndexes => _underlyingParameter.InterpolatedStringHandlerArgumentIndexes;

I would prefer overriding this property only in leaf classes. Otherwise, it is hard to predict whether this implementation is appropriate for all derived types now and in the future. #Closed

@@ -746,6 +751,10 @@ internal override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArgu
arguments.GetOrCreateData<ParameterWellKnownAttributeData>().HasEnumeratorCancellationAttribute = true;
ValidateCancellationTokenAttribute(arguments.AttributeSyntaxOpt, (BindingDiagnosticBag)arguments.Diagnostics);
}
else if (attribute.IsTargetAttribute(this, AttributeDescription.InterpolatedStringHandlerArgumentAttribute))
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

IsTargetAttribute

Since we need to deal with two different signatures here, I think we should use GetTargetAttributeSignatureIndex directly rather than trying to infer what signature we are dealing with based on values. #Closed

{
if (parameter.Name.Equals(name, StringComparison.Ordinal))
{
if ((object)parameter == this)
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

if ((object)parameter == this)

Are we checking this error condition for PE? #Closed

_ => throw ExceptionUtilities.UnexpectedValue(ContainingType)
};

foreach (var parameter in parameters)
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

foreach (var parameter in parameters)

It looks like for similar task for PEParameterSymbol we are using FirstOrDefault helper #Closed

foreach (var parameter in parameters)
{
var argumentType = parameter?.Type ?? ContainingType;
analyzedArguments.Arguments.Add(new BoundInterpolatedStringArgumentPlaceholder(arguments.AttributeSyntaxOpt!, argumentType, hasErrors: argumentType.IsErrorType()));
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

BoundInterpolatedStringArgumentPlaceholder

I am curious how BoundInterpolatedStringArgumentPlaceholder behaves as a target for a ref/out parameter. It is not a variable by default. Are we testing this? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

We have tests for this side in this PR, but we're also ignoring any diagnostics that come up from this. Regardless, since I'm removing this code it'll be tested in more depth in the next PR.

else
{
// Could not find a constructor on '{0}' that matches the parameters specified in the InterpolatedStringHandlerArgumentAttribute.
diagnostics.Add(ErrorCode.ERR_CouldNotFindApplicableInterpolatedStringHandlerConstructor, errorLocation, handlerType);
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

diagnostics.Add(ErrorCode.ERR_CouldNotFindApplicableInterpolatedStringHandlerConstructor, errorLocation, handlerType);

I think we should worry whether there are things that are specific to this particular location that could cause a failure that might not occur at a different location (missing references, language version, etc.)
#Closed

errorName: handlerType.Name,
errorLocation,
suppressResultDiagnostics: true,
BindingDiagnosticBag.Discarded,
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

BindingDiagnosticBag.Discarded

When I see us binding with BindingDiagnosticBag.Discarded and then reporting a diagnostics based on the result, that is a red flag for me. Used asembly references are not tracked and it is quite possible that things break after they are removed because compiler says they are not used. #Closed

var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Sub M(i As Integer, <InterpolatedStringHandlerArgument({ Nothing })> c As CustomHandler)
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

{ Nothing }

Did you mean to use a single element array here? Or CStr()Nothing)? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, this is intentionally an array with 1 element, that element being Nothing.

}

[Fact]
public void InterpolatedStringHandlerArgumentAttributeError_ReferenceSelf()
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

InterpolatedStringHandlerArgumentAttributeError_ReferenceSelf

Are we testing this scenario from metadata? #Closed

var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Shared Sub M(<InterpolatedStringHandlerArgument({ """" })> c As CustomHandler)
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

{ """" }

Are we testing single value overload? #Closed

}

[Fact]
public void InterpolatedStringHandlerArgumentAttributeWarn_ParameterAfterHandler()
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

InterpolatedStringHandlerArgumentAttributeWarn_ParameterAfterHandler

Consider adding a metadata test too. #Closed


public partial struct CustomHandler
{
private CustomHandler(int literalLength, int formattedCount, int i) : this() {}
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

private CustomHandler(int literalLength, int formattedCount, int i) : this() {}

Accessibility is another aspect that is location specific. For example, internal/protected constrcutor might be accessible from where M will be called. #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll test location more fully in the next PR. We're removing the error for this scenario.

var handler = GetCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: true);

var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(comp, sourceSymbolValidator: verifier, symbolValidator: verifier);
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 9, 2021

Choose a reason for hiding this comment

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

CompileAndVerify

Consider VerifyDiagnostics on result of CompileAndVerify calls. This helps catch unexpected warnings, etc. #Closed

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 5).

@333fred
Copy link
Member Author

333fred commented Jun 10, 2021

    private static IEnumerable<string> ReadLanguagesFromAttribute(ref BlobReader argsReader)

Filed #53994 to track.


In reply to: 857980418


Refers to: src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs:296 in b8ea696. [](commit_id = b8ea696, deletion_comment = False)

* Remove attribute constructor resolution during source binding
* More tests
* Small refactorings.
@333fred
Copy link
Member Author

333fred commented Jun 10, 2021

@AlekseyTs @chsienki addressed your feedback.


In reply to: 858138258

@@ -621,6 +621,10 @@ public override ImmutableArray<CustomModifier> RefCustomModifiers
}
}

internal override ImmutableArray<int> InterpolatedStringHandlerArgumentIndexes => _underlyingParameter.InterpolatedStringHandlerArgumentIndexes;
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 10, 2021

Choose a reason for hiding this comment

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

_underlyingParameter.InterpolatedStringHandlerArgumentIndexes

Should these be adjusted? I think reduced extension methods remove the first parameter, it becomes the receiver. If we never bind against a reduced method symbol (it used to be that C# only used them for SemanticModel, this is likely still the case), consider simply throwing from both new APIs. #Closed

}

private struct PackedFlags
{
// Layout:
// |...|fffffffff|n|rr|cccccccc|vvvvvvvv|
// |..|fffffffff|n|rr|ccccccccc|vvvvvvvvv|
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 10, 2021

Choose a reason for hiding this comment

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

// |..|fffffffff|n|rr|ccccccccc|vvvvvvvvv|

We are running out of bits here really fast. I believe CallerArgumentEx[pression is going to add at least couple of bits here. Automatic merge isn't goint to work as well.
As an alternative, can we use default value in _lazyInterpolatedStringHandlerAttributeIndexes to indicate an error and use another sentinel value to represent an unitilized state, like a shared array with a single int.MinValue in it? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

Rather than creating a new structure, I think the appropriate thing to do will be to move _bits to a long at that point. It'll take a bit of effort when merging, but I'd much rather do that than try and create a separate side-structure for just this bit.

Copy link
Member Author

Choose a reason for hiding this comment

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

Talked with Aleksey offline, I misread his comment. I'll do this.

var vbCode = @"
Imports System.Runtime.CompilerServices
Public Class C
Public Sub M(i As Integer, <InterpolatedStringHandlerArgument({ Nothing })> c As CustomHandler)
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 10, 2021

Choose a reason for hiding this comment

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

{ Nothing }

Are we testing single value overload? #Closed

}
}

private bool _hasInterpolatedStringHandlerArgumentAttributeError = false;
Copy link
Contributor

@AlekseyTs AlekseyTs Jun 10, 2021

Choose a reason for hiding this comment

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

private bool _hasInterpolatedStringHandlerArgumentAttributeError = false;

Consider if we can get rid of this separate flag similar to the suggestion for PEParameterSymbol. #Closed

@AlekseyTs
Copy link
Contributor

@333fred It looks like there are some related test failures.

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jun 10, 2021

Done with review pass (commit 7)


In reply to: 859088157

@333fred
Copy link
Member Author

333fred commented Jun 10, 2021

@AlekseyTs addressed feedback.


In reply to: 859088157

Copy link
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 9), assuming CI is passing

@333fred
Copy link
Member Author

333fred commented Jun 10, 2021

@chsienki can you please take another look?

@333fred 333fred merged commit e0a2cd6 into dotnet:features/interpolated-string Jun 10, 2021
@333fred 333fred deleted the interpolated-arguments-decode branch June 10, 2021 23:16
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.

3 participants