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

Skip user-defined conversions when checking extension method 'this' argument #19511

Merged
merged 1 commit into from
May 19, 2017

Conversation

cston
Copy link
Member

@cston cston commented May 15, 2017

Customer scenario

Invoke extension methods where the receiver type has user-defined conversion operators. This change affects performance only, not correctness.

Bugs this fixes:

434957

Workarounds, if any

None

Risk

Medium. The change avoids looking for user-defined conversion operators that were already being ignored by the caller for the this argument, although that argument conversion is now handled by a new specific method.

Performance impact

Improves performance

Is this a regression from a previous update?

Yes, a regression from VS2013.

How was the bug found?

Customer reported

Copy link
Member

@gafter gafter left a comment

Choose a reason for hiding this comment

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

LGTM

@gafter gafter added Area-Compilers Tenet-Performance Regression in measured performance of the product from goals. labels May 15, 2017
@gafter gafter added this to the 15.3 milestone May 15, 2017
@cston cston force-pushed the skip-udc branch 3 times, most recently from da9be0a to 567f3a0 Compare May 17, 2017 06:15
@@ -54,67 +52,6 @@ public override Conversion GetMethodGroupConversion(BoundMethodGroup source, Typ
return conversion;
}

protected override Conversion GetImplicitTupleLiteralConversion(BoundTupleLiteral source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
Copy link
Member Author

Choose a reason for hiding this comment

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

Methods have moved to ConversionsBase since the implementation did not depend on the derived class.

@@ -1340,14 +1391,15 @@ public static bool HasIdentityConversionToAny<T>(T type, ArrayBuilder<T> targetT
public Conversion ConvertExtensionMethodThisArg(TypeSymbol parameterType, TypeSymbol thisType, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
Debug.Assert((object)thisType != null);
var conversion = this.ClassifyImplicitConversionFromType(thisType, parameterType, ref useSiteDiagnostics);
var conversion = this.ClassifyImplicitExtensionMethodThisArgConversion(null, thisType, parameterType, ref useSiteDiagnostics);
return IsValidExtensionMethodThisArgConversion(conversion) ? conversion : Conversion.NoConversion;
}

// Spec 7.6.5.2: "An extension method ... is eligible if ... [an] implicit identity, reference,
// or boxing conversion exists from expr to the type of the first parameter"
public static bool IsValidExtensionMethodThisArgConversion(Conversion conversion)
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 method should be replaced by an assert.

Copy link
Member

Choose a reason for hiding this comment

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

Yes. I did not notice your comment and was puzzled at why IsValidExtensionMethodThisArgConversion still needs to be called.


if (conversion.IsImplicit)
Copy link
Member Author

Choose a reason for hiding this comment

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

Implicit conversions are no longer generated for this argument.

@cston
Copy link
Member Author

cston commented May 17, 2017

@dotnet/roslyn, @AlekseyTs please review.

Copy link
Member

@VSadov VSadov left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@gafter gafter left a comment

Choose a reason for hiding this comment

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

LGTM

@cston
Copy link
Member Author

cston commented May 18, 2017

@MeiChin-Tsai for approval

@cston
Copy link
Member Author

cston commented May 18, 2017

@dotnet-bot test windows_release_vs-integration_prtest please

return Conversion.NoConversion;
}

// It should be possible to remove IsValidExtensionMethodThisArgConversion
Copy link
Member

Choose a reason for hiding this comment

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

File follow-up issue?

Copy link
Member Author

Choose a reason for hiding this comment

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

Logged #19622


if ((object)sourceType != null)
{
var tupleConversion = ClassifyTupleConversion(
Copy link
Member

Choose a reason for hiding this comment

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

I didn't quite follow. How do we know that we're looking at a tuple at this point?

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 don't know we have a tuple at this point but ClassifyTupleConversion returns NoConversion if either the source or destination is not a tuple. This follows the pattern used elsewhere in ConversionsBase. See the call to ClassifyImplicitTupleConversion in ClassifyStandardImplicitConversion for instance.

TypeSymbol destination,
ref HashSet<DiagnosticInfo> useSiteDiagnostics,
ConversionKind kind,
ClassifyConversionFromExpressionDelegate classifyConversion,
Copy link
Member

Choose a reason for hiding this comment

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

Would it be simpler to pass options, rather than a delegate? Seems like there are three cases: implicit, explicit and implicit-for-this-in-extension. Maybe two bools, or a small enum?

Copy link
Member Author

@cston cston May 18, 2017

Choose a reason for hiding this comment

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

Unfortunately the code didn't seem any clearer since it added a switch in each method and meant each method took two enum values, one for ConversionKind and one for new enum.

I have changed the delegates to take an additional ConversionsBase argument though, so that the delegate instances are static and cached.

TypeSymbol destination,
ref HashSet<DiagnosticInfo> useSiteDiagnostics,
ConversionKind kind,
ClassifyConversionFromTypeDelegate classifyConversion,
Copy link
Member

Choose a reason for hiding this comment

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

Same question here.
Thanks for the factoring of common code, btw.

@@ -1986,6 +1986,138 @@ static void Main()
Diagnostic(ErrorCode.ERR_NoImplicitConv, "0").WithArguments("int", "R"));
}

[Fact]
[WorkItem(434957, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?id=434957")]
public void SkipUserDefinedConversionsForThisArgument()
Copy link
Member

Choose a reason for hiding this comment

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

Just to confirm: this test (and the following 2 or three) already produced errors (just different error code) before your change?

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, these tests also (correctly) produced errors before this change. The tests made more sense with an earlier iteration of this change and are now likely redundant, and I considered removing them.

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM

@MeiChin-Tsai
Copy link

Please make sure all checks are successful. Do we want to add more tests given that the risk is medium? Approved since it is a regression. thx.

@jasonmalinowski
Copy link
Member

@dotnet-bot retest windows_release_vs-integration_prtest please.

@cston
Copy link
Member Author

cston commented May 19, 2017

@dotnet-bot retest windows_release_vs-integration_prtest please

@cston
Copy link
Member Author

cston commented May 19, 2017

@MeiChin-Tsai, added tests for more conversion cases.

@cston
Copy link
Member Author

cston commented May 19, 2017

@dotnet-bot retest Ubuntu_16_debug_prtest please

@cston cston merged commit 41cdec1 into dotnet:master May 19, 2017
@cston cston deleted the skip-udc branch May 19, 2017 04:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers cla-already-signed Tenet-Performance Regression in measured performance of the product from goals.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants