-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Enable basic end-to-end scenarios of extension method invocation. #77320
Enable basic end-to-end scenarios of extension method invocation. #77320
Conversation
|
||
return rewrittenCall; | ||
|
||
BoundExpression visitArgumentsAndFinishRewrite(BoundCall node, BoundExpression? rewrittenReceiver) |
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.
nit: consider passing rewriter
explicitly and marking local function as static
to avoid capture #Resolved
} | ||
else | ||
{ | ||
argumentRefKinds = argumentRefKinds.Insert(0, SyntheticBoundNodeFactory.ArgumentRefKindFromParameterRefKind(receiverRefKind, useStrictArgumentRefKinds: 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.
Consider adding a test for this value
Testing for ref receivers is to be done, I added a couple of tests with prototype comment. I am not planning to test more in this PR.
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.
BTW, the added tests break for true
, but quite possibly they take the other branch that has the same logic.
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.
Yes, the added tests take the other branch
|
||
return uncommon.LazyExtensionParameter.Value; | ||
|
||
ParameterSymbol makeExtensionParameter() |
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.
nit: consider making static
to avoid captures, or limiting capture to this
. Same for getMarkerMethodSymbol
below #Resolved
{ | ||
foreach (var member in @this.ContainingType.GetMembers(SourceExtensionImplementationMethodSymbol.GetImplementationName(method))) | ||
{ | ||
if (member is not MethodSymbol { HasSpecialName: true, IsStatic: true } candidate) |
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 we check the accessibility of the implementation method (should match the skeleton method's)? #Resolved
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 we check the accessibility of the implementation method (should match the skeleton method's)?
I'll add a PROTOTYPE comment.
|
||
return uncommon.LazyImplementationMap.GetOrAdd( | ||
method, | ||
static (method, @this) => |
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.
nit: consider making this a local function #Resolved
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.
consider making this a local function
What would be the motivation?
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.
Code with long embedded lambdas is not as readable. The last argument of GetOrAdd
would not be lost after the long lambda
/// <summary> | ||
/// The name of marker method for an extension type. | ||
/// </summary> | ||
internal const string ExtensionMarkerMethodName = "<Extension>$"; // PROTOTYPE confirm name with WG |
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.
LGTM Thanks (iteration 4)
// Code size 1 (0x1) | ||
.maxstack 8 | ||
IL_0000: ret | ||
} // end of method '<>E__0'::'<Extension>$' |
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.
Consider adding a LangVer test (you can consume extension methods from metadata from any language version) #Resolved
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.
Consider adding a LangVer test (you can consume extension methods from metadata from any language version)
- I think the behavior should be different, the suggested behavior goes against the spirit of the language version feature, I think.
- This level of testing is outside of scope of the PR. It is not about binding call-sites. While the language check should be performed for a call-site during binding.
@jjonescz, @dotnet/roslyn-compiler For the second review |
else | ||
{ | ||
loweredBody = ExtensionMethodReferenceRewriter.Rewrite(loweredBody); | ||
} |
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 we add if (loweredBody.HasErrors) { return loweredBody; }
after this "rewriting stage" similarly to the other stages around here? #Resolved
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.
These visitors have no way of reporting errors and are not expected to produce bad nodes.
@@ -366,8 +377,174 @@ public override ExtendedSpecialType ExtendedSpecialType | |||
} | |||
} | |||
|
|||
// PROTOTYPE metadata is undone | |||
internal sealed override ParameterSymbol ExtensionParameter => throw new NotImplementedException(); | |||
internal sealed override ParameterSymbol ExtensionParameter |
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.
Consider wrapping this bulk of new code in #nullable enable
#Resolved
} | ||
} | ||
|
||
public override MethodSymbol TryGetCorrespondingExtensionImplementationMethod(MethodSymbol method) |
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.
public override MethodSymbol TryGetCorrespondingExtensionImplementationMethod(MethodSymbol method) | |
public sealed override MethodSymbol TryGetCorrespondingExtensionImplementationMethod(MethodSymbol method) | |
``` #Resolved |
@@ -84,5 +103,49 @@ internal sealed override ParameterSymbol? ExtensionParameter | |||
} | |||
} | |||
} | |||
|
|||
public override MethodSymbol? TryGetCorrespondingExtensionImplementationMethod(MethodSymbol method) |
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.
public override MethodSymbol? TryGetCorrespondingExtensionImplementationMethod(MethodSymbol method) | |
public sealed override MethodSymbol? TryGetCorrespondingExtensionImplementationMethod(MethodSymbol method) | |
``` #Resolved |
/// <summary> | ||
/// Replaces references to extension methods with references to their implementation methods | ||
/// </summary> | ||
internal class ExtensionMethodReferenceRewriter : BoundTreeRewriterWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator |
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.
internal class ExtensionMethodReferenceRewriter : BoundTreeRewriterWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator | |
internal sealed class ExtensionMethodReferenceRewriter : BoundTreeRewriterWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator | |
``` #Resolved |
No description provided.