-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Support delegate or function pointer creation based on a static abstract method. #52685
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2076,8 +2076,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) | |
|
||
// do actual assignment | ||
|
||
// PROTOTYPE(StaticAbstractMembersInInterfaces): This assert fires for a user-defined prefix increment/decrement. Open an issue. | ||
//Debug.Assert(locInfo.LocalDefs.Any((d) => _nodeCounter == d.Start && _nodeCounter <= d.End)); | ||
Debug.Assert(locInfo.LocalDefs.Any((d) => _nodeCounter == d.Start && _nodeCounter <= d.End)); | ||
var isLast = IsLastAccess(locInfo, _nodeCounter); | ||
|
||
if (isLast) | ||
|
@@ -2093,6 +2092,36 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) | |
} | ||
} | ||
|
||
#nullable enable | ||
public override BoundNode VisitCall(BoundCall node) | ||
{ | ||
BoundExpression? receiverOpt = node.ReceiverOpt; | ||
|
||
if (node.Method.RequiresInstanceReceiver) | ||
{ | ||
receiverOpt = (BoundExpression?)this.Visit(receiverOpt); | ||
} | ||
else | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like this is necessary because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In genera it can do that. However, since the first pass specially visits BoundCall, we have to mirror that here as well in order to make sure that the count of nodes is in sync across passes. |
||
_nodeCounter++; | ||
|
||
if (receiverOpt is BoundTypeExpression { AliasOpt: null, BoundContainingTypeOpt: null, BoundDimensionsOpt: { IsEmpty: true }, Type: { TypeKind: TypeKind.TypeParameter } } typeExpression) | ||
{ | ||
receiverOpt = typeExpression.Update(aliasOpt: null, boundContainingTypeOpt: null, boundDimensionsOpt: ImmutableArray<BoundExpression>.Empty, | ||
typeWithAnnotations: typeExpression.TypeWithAnnotations, type: this.VisitType(typeExpression.Type)); | ||
} | ||
else if (receiverOpt is not null) | ||
{ | ||
throw ExceptionUtilities.Unreachable; | ||
} | ||
} | ||
|
||
ImmutableArray<BoundExpression> arguments = this.VisitList(node.Arguments); | ||
TypeSymbol? type = this.VisitType(node.Type); | ||
return node.Update(receiverOpt, node.Method, arguments, node.ArgumentNamesOpt, node.ArgumentRefKindsOpt, node.IsDelegateCall, node.Expanded, node.InvokedAsExtensionMethod, node.ArgsToParamsOpt, node.DefaultArguments, node.ResultKind, node.OriginalMethodsOpt, type); | ||
} | ||
#nullable disable | ||
|
||
public override BoundNode VisitCatchBlock(BoundCatchBlock node) | ||
{ | ||
var exceptionSource = node.ExceptionSourceOpt; | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -379,7 +379,9 @@ private BoundExpression MakeConversionNodeCore( | |
{ | ||
var mg = (BoundMethodGroup)rewrittenOperand; | ||
Debug.Assert(oldNodeOpt.SymbolOpt is { }); | ||
return new BoundFunctionPointerLoad(oldNodeOpt.Syntax, oldNodeOpt.SymbolOpt, type: funcPtrType, hasErrors: false); | ||
return new BoundFunctionPointerLoad(oldNodeOpt.Syntax, oldNodeOpt.SymbolOpt, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we made it to lowering with a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Pretty much. |
||
constrainedToTypeOpt: oldNodeOpt.SymbolOpt.IsStatic && oldNodeOpt.SymbolOpt.IsAbstract ? mg.ReceiverOpt?.Type : null, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more.
I prefer to not surface this as a NullReference exception There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An exception in the emit layer is sufficient to deal with this unexpected situation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's fine, but we're seriously busted at this point, right? Should we consider throwing an unreachable or something? In reply to: 616239428 [](ancestors = 616239428) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
An emit layer takes care of this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I would say consider at least leaving a comment. Explicitly "dealing" with the potential null by doing a conditional access here feels to me like an expression of intent, but I don't read the intent as "let the emit layer throw". I read it as "this should have some meaning", which is not what is meant. In reply to: 616240220 [](ancestors = 616240220) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My intent is to not perform any validation here. Null reference is not the only thing we should worry about. The code matches the intent. |
||
type: funcPtrType, hasErrors: false); | ||
} | ||
|
||
case ConversionKind.MethodGroup: | ||
|
@@ -391,7 +393,7 @@ private BoundExpression MakeConversionNodeCore( | |
Debug.Assert(method is { }); | ||
var oldSyntax = _factory.Syntax; | ||
_factory.Syntax = (mg.ReceiverOpt ?? mg).Syntax; | ||
var receiver = (!method.RequiresInstanceReceiver && !oldNodeOpt.IsExtensionMethod) ? _factory.Type(method.ContainingType) : mg.ReceiverOpt; | ||
var receiver = (!method.RequiresInstanceReceiver && !oldNodeOpt.IsExtensionMethod && !method.IsAbstract) ? _factory.Type(method.ContainingType) : mg.ReceiverOpt; | ||
Debug.Assert(receiver is { }); | ||
_factory.Syntax = oldSyntax; | ||
return new BoundDelegateCreationExpression(syntax, argument: receiver, methodOpt: 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.
To make sure I understand the change: it looks like this lets us use 'call' instruction when calling a method that implements a static abstract method. Is that correct? #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.
At the moment, this chnage is not observable in any way, but static methods can be invoked only by 'call' instruction.