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

Add support for interpolated string handler conversions #53602

Merged

Conversation

333fred
Copy link
Member

@333fred 333fred commented May 21, 2021

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

@333fred 333fred changed the title interpolated conversion Add support for interpolated string handler conversions May 21, 2021
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.
objectType = GetSpecialType(SpecialType.System_Object, diagnostics, unconvertedInterpolatedString.Syntax);
conversionDiagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics: true, withDependencies: false);
}
else if (isHandlerConversion)
Copy link
Member Author

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.
Copy link
Member Author

@333fred 333fred May 24, 2021

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

Copy link
Contributor

Choose a reason for hiding this comment

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

//PROTOTYPE to track?


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

@333fred 333fred marked this pull request as ready for review May 25, 2021 17:54
@333fred 333fred requested a review from a team as a code owner May 25, 2021 17:54
@333fred
Copy link
Member Author

333fred commented May 25, 2021

@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.

@chsienki
Copy link
Contributor

@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,
Copy link
Contributor

@chsienki chsienki May 26, 2021

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

Copy link
Member Author

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.

Copy link
Member Author

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.

@chsienki
Copy link
Contributor

Done with review pass (commit 7)

@333fred
Copy link
Member Author

333fred commented May 26, 2021

@chsienki did you have any more comments? I don't think there's anything I can't address in the next PR.


In reply to: 849090010

@333fred
Copy link
Member Author

333fred commented May 26, 2021

@AlekseyTs for second review.

@@ -1002,6 +1002,11 @@ internal bool HasCodeAnalysisEmbeddedAttribute(EntityHandle token)
return FindTargetAttribute(token, AttributeDescription.CodeAnalysisEmbeddedAttribute).HasValue;
}

internal bool HasInterpolatedStringBuilderAttribute(EntityHandle token)
Copy link
Contributor

@AlekseyTs AlekseyTs May 28, 2021

Choose a reason for hiding this comment

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

HasInterpolatedStringBuilderAttribute

HasInterpolatedStringHandlerAttribute? #Closed


#region InterpolatedStringHandlerAttribute
private bool _hasInterpolatedStringHandlerAttribute;
public bool HasInterpolatedStringHandlerAttribute
Copy link
Contributor

@AlekseyTs AlekseyTs May 28, 2021

Choose a reason for hiding this comment

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

HasInterpolatedStringHandlerAttribute

What is the reason for putting this into EarlyWellKnownAttributeData? #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.

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

@AlekseyTs AlekseyTs May 28, 2021

Choose a reason for hiding this comment

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

HasInterpolatedStringHandlerAttribute

Should this be moved to C# specific type? #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 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,
Copy link
Contributor

@AlekseyTs AlekseyTs May 28, 2021

Choose a reason for hiding this comment

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

explicitCastInCode: false

This looks suspicious. #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.

Chris mentioned this earlier. I'm planning on addressing in the next PR, unless you think this needs to be addressed now.

Copy link
Member Author

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.

Copy link
Contributor

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

@AlekseyTs AlekseyTs May 28, 2021

Choose a reason for hiding this comment

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

Add

I think we have a ReportUseSite helper that takes a symbol and a syntax node #Closed

objectType = GetSpecialType(SpecialType.System_Object, diagnostics, unconvertedInterpolatedString.Syntax);
conversionDiagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics: true, withDependencies: false);
}
else if (isHandlerConversion)
Copy link
Contributor

@AlekseyTs AlekseyTs May 28, 2021

Choose a reason for hiding this comment

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

else if (isHandlerConversion)

Consider making this a separate if rather than an else if. This will avoid dependency on value of needToCheckConversionToObject and any future changes for it. needToCheckConversionToObject depends on isHandlerConversion, not the other way around. #Closed

@@ -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
Copy link
Contributor

@AlekseyTs AlekseyTs May 28, 2021

Choose a reason for hiding this comment

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

case ErrorCode.ERR_FeatureInPreview:

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

Copy link
Member Author

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?

Copy link
Contributor

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.

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

@AlekseyTs AlekseyTs May 28, 2021

Choose a reason for hiding this comment

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

lazyHasInterpolatedStringBuilderAttribute

Builder vs.Handler #Closed

@AlekseyTs
Copy link
Contributor

AlekseyTs commented May 28, 2021

    /// Patch refKinds for arguments that match 'In' parameters to have effective RefKind.

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

@AlekseyTs AlekseyTs May 28, 2021

Choose a reason for hiding this comment

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

return expr is BoundConversion { Conversion: { IsInterpolatedStringHandler: true }, Type: { IsValueType: true } };

Is the actual local introduced by ILGen layer or elswhere in the LocalRewriter? #Closed

Copy link
Contributor

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?

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 are just pretending that there is a ref modifier for the corresponding argument

That is correct.

@AlekseyTs
Copy link
Contributor

AlekseyTs commented May 28, 2021

Done with review pass (commit 7)


In reply to: 850675628

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 8)

@333fred 333fred enabled auto-merge (squash) June 1, 2021 17:48
@333fred 333fred merged commit 66267da into dotnet:features/interpolated-string Jun 1, 2021
@333fred 333fred deleted the interpolated-conversion branch June 1, 2021 18:41
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