-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Add support for interpolated string handler conversions #53602
Add support for interpolated string handler conversions #53602
Conversation
This PR allows interpolated strings to convert to types marked with InterpolatedStringBuilderAttribute, allows the RefKind to mismatch, and implements support for the better conversion rules.
35a62af
to
8f52216
Compare
objectType = GetSpecialType(SpecialType.System_Object, diagnostics, unconvertedInterpolatedString.Syntax); | ||
conversionDiagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics: true, withDependencies: false); | ||
} | ||
else if (isHandlerConversion) |
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.
Most of this function is unchanged, just extracted to be called from multiple places. The new bit is the addition of isHandlerConversion
as a parameter, this feature check, and the addition of a prototype comment around dynamic below.
@@ -2105,19 +2105,19 @@ private static ParameterSymbol GetParameter(int argIndex, MemberAnalysisResult r | |||
return (m1ModifierCount < m2ModifierCount) ? BetterResult.Left : BetterResult.Right; | |||
} | |||
|
|||
// Otherwise, prefer methods with 'val' parameters over 'in' parameters. | |||
return PreferValOverInParameters(arguments, m1, m1LeastOverriddenParameters, m2, m2LeastOverriddenParameters); | |||
// Otherwise, prefer methods with 'val' parameters over 'in' parameters and over 'ref' parameters when the argument is an interpolated string handler. |
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.
This needs to be documented in the spec, but I'd propose we do so. #Pending
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.
@chsienki @AlekseyTs there's a couple of globalization issues I have to fix up in the tests around windows vs unix/linux and PEVerify, but this is otherwise ready for review. Please take a look. |
@333fred Apologies I got sidetracked by a bunch of different stuff today, but I'll take a look at this first thing tomorrow. |
syntax, | ||
BindUnconvertedInterpolatedStringToHandlerType(unconvertedSource, (NamedTypeSymbol)destination, diagnostics, isHandlerConversion: true), | ||
conversion, | ||
@checked: false, |
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.
Does this conversion cover the whole expression? If I have arithmetic in the interpolation holes for example? #Pending
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.
Any expression is valid in the interpolation holes, we don't treat anything special.
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.
Oh, I see what you're saying. It doesn't apply to anything inside interpolations, but we should probably use the value of CheckOverflowAtRuntime
anyway.
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs
Show resolved
Hide resolved
Done with review pass (commit 7) |
@AlekseyTs for second review. |
@@ -1002,6 +1002,11 @@ internal bool HasCodeAnalysisEmbeddedAttribute(EntityHandle token) | |||
return FindTargetAttribute(token, AttributeDescription.CodeAnalysisEmbeddedAttribute).HasValue; | |||
} | |||
|
|||
internal bool HasInterpolatedStringBuilderAttribute(EntityHandle token) |
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.
|
||
#region InterpolatedStringHandlerAttribute | ||
private bool _hasInterpolatedStringHandlerAttribute; | ||
public bool HasInterpolatedStringHandlerAttribute |
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.
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.
This is covered in the actual decode code, and has a corresponding test to make sure we bind to the correct attribute constructor.
|
||
#region InterpolatedStringHandlerAttribute | ||
private bool _hasInterpolatedStringHandlerAttribute; | ||
public bool HasInterpolatedStringHandlerAttribute |
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.
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.
I'll have to add one as we don't have one for C# currently, but that's doable.
BindUnconvertedInterpolatedStringToHandlerType(unconvertedSource, (NamedTypeSymbol)destination, diagnostics, isHandlerConversion: true), | ||
conversion, | ||
@checked: false, | ||
explicitCastInCode: false, |
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.
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.
Chris mentioned this earlier. I'm planning on addressing in the next PR, unless you think this needs to be addressed now.
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.
Oh, sorry, that was on a different line. Yes, this is incorrect and I'll add a test.
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.
Chris mentioned this earlier.
This is not about checked/unchecked, which has no impact on this conversion. This is about explicitCastInCode, which is likely to be significant.
} | ||
private BoundInterpolatedString BindUnconvertedInterpolatedStringToHandlerType(BoundUnconvertedInterpolatedString unconvertedInterpolatedString, NamedTypeSymbol interpolatedStringHandlerType, BindingDiagnosticBag diagnostics, bool isHandlerConversion) | ||
{ | ||
diagnostics.Add(interpolatedStringHandlerType.GetUseSiteInfo(), unconvertedInterpolatedString.Syntax.Location); |
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.
objectType = GetSpecialType(SpecialType.System_Object, diagnostics, unconvertedInterpolatedString.Syntax); | ||
conversionDiagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics: true, withDependencies: false); | ||
} | ||
else if (isHandlerConversion) |
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.
@@ -510,6 +510,7 @@ internal static bool PreventsSuccessfulDelegateConversion(ErrorCode code) | |||
case ErrorCode.ERR_QueryRangeVariableSameAsTypeParam: | |||
case ErrorCode.ERR_DeprecatedCollectionInitAddStr: | |||
case ErrorCode.ERR_DeprecatedSymbolStr: | |||
case ErrorCode.ERR_FeatureInPreview: // LangVersion should never change how we bind things |
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.
Isn't there a chance to change existing behavior if we modify this list? The motivation feels reasonable though. Another thing to consider is what happens when the particular feature is moved to its final language version. Also, I believe there are many other language specific errors, including the custom ones. And we will be adding them in the future. Does this mean this function requires special maintanense long term? #Closed
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.
Does this mean this function requires special maintanense long term?
Yes, I think it does. In particular, the way this manifests is that, when you use an interpolated string conversion, overload resolution can potentially pick a different overload that doesn't use the conversion (even if that conversion wasn't used in the return type, just somewhere in the body). /cc @cston.
Perhaps the thing to do is make this change in dev16.11 (and include the other FeatureIn error codes as well) and do a smoke test on VS to see whether it's a big breaking change?
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.
Does this mean this function requires special maintanense long term?
Yes, I think it does.
I think it will be hard to keep track. We should consider the following:
- Adjusting the code so that it can intersept all current and future language version errors. I think they are already specially recognizable, since the required language version is supplied in a special way fo IDE to recognize.
- Adding a dedicated method in this class that returns true for a language version error and using that helper here. Adding relevant comments and asserts in some strategic places to guide devs into the direction of this new helper.
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.
I filed #53761 to follow up on this. I'll revert the change in this PR for now, as we discussed offline, and I've added a specific test to cover the difference in behavior.
@@ -141,6 +141,7 @@ private class UncommonProperties | |||
internal string lazyDefaultMemberName; | |||
internal NamedTypeSymbol lazyComImportCoClassType = ErrorTypeSymbol.UnknownResultType; | |||
internal ThreeState lazyHasEmbeddedAttribute = ThreeState.Unknown; | |||
internal ThreeState lazyHasInterpolatedStringBuilderAttribute = ThreeState.Unknown; |
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.
Should the doc comment be adjusted? In reply to: 850668203 #Closed Refers to: src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs:506 in ff3c946. [](commit_id = ff3c946, deletion_comment = False) |
|
||
case BoundKind.Conversion: | ||
var conversion = ((BoundConversion)expr); | ||
return expr is BoundConversion { Conversion: { IsInterpolatedStringHandler: true }, Type: { IsValueType: true } }; |
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.
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.
I mean the local that is passed by ref at the end. I just realized that it is probably the builder local that we are always creating. So we are just pretending that there is a ref modifier for the corresponding argument. Correct?
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.
So we are just pretending that there is a ref modifier for the corresponding argument
That is correct.
Done with review pass (commit 7) In reply to: 850675628 |
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.
LGTM (commit 8)
This PR allows interpolated strings to convert to types marked with InterpolatedStringBuilderAttribute, allows the RefKind to mismatch, and implements support for the better conversion rules.
Test plan: #51499