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 IOperation APIs for Dynamic invocations and indexer access #21711

Merged
merged 12 commits into from
Sep 15, 2017

Conversation

mavasani
Copy link
Contributor

Fixes #20114 and #20122

";
string expectedOperationTree = @"
IDynamicInvocationExpression (OperationKind.DynamicInvocationExpression, Type: dynamic) (Syntax: 'c.M2(d)')
Expression: IOperation: (OperationKind.None) (Syntax: 'c.M2')
Copy link
Contributor Author

@mavasani mavasani Aug 23, 2017

Choose a reason for hiding this comment

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

OperationKind.None here seems to be due to a BoundMethodGroup node in the tree - we seem to be losing the IOperation tree for the receiver here ('c' for this example). @heejaechang is going to bring it up for discussion in tomorrow's design meeting. #Pending

boundLateInvocation.ArgumentsOpt.SelectAsArray(Function(n) Create(n)))
End Function)
Dim argumentNames As ImmutableArray(Of String) = boundLateInvocation.ArgumentNamesOpt.NullToEmpty()
Dim argumentRefKinds As ImmutableArray(Of RefKind) = ImmutableArray(Of RefKind).Empty
Copy link
Contributor Author

Choose a reason for hiding this comment

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

BoundLateInvocation node in VB doesn't seem to be storing the array of RefKinds for each argument. @AlekseyTs, is this expected or should I open a compiler bug?

Copy link
Contributor

@AlekseyTs AlekseyTs Aug 24, 2017

Choose a reason for hiding this comment

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

BoundLateInvocation node in VB doesn't seem to be storing the array of RefKinds for each argument.

I believe ref kinds in C# are coming from syntax, VB doesn't have syntax like that. #Closed

Copy link
Contributor

@AlekseyTs AlekseyTs Aug 24, 2017

Choose a reason for hiding this comment

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

That said, if we are using language-agnostic IOperation nodes, we should probably be able to distinguish situations when

  • ref kinds are specified - C#, and
  • ref kinds are not specified - VB #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@AlekseyTs - We can do so by returning a default array for VB. Does that sound fine?

@mavasani
Copy link
Contributor Author

mavasani commented Aug 25, 2017

@dotnet retest ubuntu_14_debug_prtest please #Closed

@@ -12,6 +12,11 @@ namespace Microsoft.CodeAnalysis.Semantics
public interface IDynamicObjectCreationExpression : IHasDynamicArgumentsExpression
{
/// <summary>
/// Name of the dynamically invoked member.
/// </summary>
string MemberName { get; }
Copy link
Contributor

@AlekseyTs AlekseyTs Aug 28, 2017

Choose a reason for hiding this comment

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

string MemberName { get; } [](start = 8, length = 26)

I am not sure if this property belongs in IDynamicObjectCreationExpression. Isn't the member is always an instance constructor, which has predefined name? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The doc comment is actually misleading, it should be name of the dynamically created type, and the field name should be "Name".

Copy link
Contributor

@AlekseyTs AlekseyTs Aug 29, 2017

Choose a reason for hiding this comment

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

it should be name of the dynamically created type

Why is the name of the type interesting? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, users can derive this name from syntax or the child dynamic member reference expression. Let me remove this property.

Copy link
Contributor

@AlekseyTs AlekseyTs Aug 29, 2017

Choose a reason for hiding this comment

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

users can derive this name from syntax or the child dynamic member reference expression.

I assume the type symbol is available as the Type property of the node itself. Correct? #Closed

/// This interface is reserved for implementation by its associated APIs. We reserve the right to
/// change it in the future.
/// </remarks>
public interface IDynamicInvocationExpression : IHasDynamicArgumentsExpression
Copy link
Contributor

@AlekseyTs AlekseyTs Aug 29, 2017

Choose a reason for hiding this comment

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

IDynamicInvocationExpression [](start = 21, length = 28)

Should we expose information about type arguments? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Type arguments are stored neither on BoundDynamicInvocation node in C# nor on BoundLateInvocation node in VB. A dynamic invocation generally has the dynamic member reference as it's Expression child, which already exposes the type arguments.

Private Function CreateBoundLateInvocationOperation(boundLateInvocation As BoundLateInvocation) As IOperation
Dim expression As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(boundLateInvocation.Member))

Dim isDynamicPropertyReference = boundLateInvocation.MethodOrPropertyGroupOpt?.Kind = BoundKind.PropertyGroup
Copy link
Contributor

@AlekseyTs AlekseyTs Aug 29, 2017

Choose a reason for hiding this comment

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

isDynamicPropertyReference [](start = 16, length = 26)

I believe It is not always possible to accurately calculate this value for VB. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@AlekseyTs do you have an example where this could likely be wrong? I was able to write unit tests where this value is correctly computed to true for property reference and false for method reference.

Copy link
Contributor

@AlekseyTs AlekseyTs Aug 29, 2017

Choose a reason for hiding this comment

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

do you have an example where this could likely be wrong?

Aren't there cases when we simply don't know whether the name refers to a property, or to a method? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I get your point, lets discuss the correct way to represent this in the next design meeting.

Copy link
Contributor

@AlekseyTs AlekseyTs Aug 29, 2017

Choose a reason for hiding this comment

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

I believe that from VB point of view there is no (o very little) difference between late bound method invocation or late bound property indexing. At the same time, it looks like there is no such thing as dynamic property indexing on C# side. #Closed

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Aug 29, 2017

Would it make sense to have distinct nodes for VB and C#? #Closed

@mavasani
Copy link
Contributor Author

mavasani commented Aug 29, 2017

Would it make sense to have distinct nodes for VB and C#?

@AlekseyTs Are you suggesting this because of differences in the language specs? I am not very clear on why we need the distinction, but we can bring this up at the next design meeting. #Resolved

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Aug 29, 2017

Are you suggesting this because of differences in the language specs?

Yes, because the difference in the languages. VB late binding is very different from C# dynamic. Semantics is different. #Closed

1) Use IDynamicInvocationExpression for VB late bound invocation and C# dynamic invocation.
2) Use IDynamicIndexerAccessExpression for C# dynamic indexer access; not used in VB.
3) Remove IDynamicObjectCreationExpression.MemberName property.
4) Add extension methods on IHasDynamicArgumentExpression to get optional argument name and ref kind for an argument at a given index.
@mavasani
Copy link
Contributor Author

mavasani commented Sep 5, 2017

This PR has been updated as per last week's design decisions and is ready for review. #Closed

@mavasani
Copy link
Contributor Author

mavasani commented Sep 6, 2017

Ping for reviews. #Closed

{
Lazy<IOperation> expression = new Lazy<IOperation>(() => Create(boundDynamicInvocation.Expression));
ImmutableArray<ISymbol> applicableSymbols = StaticCast<ISymbol>.From(boundDynamicInvocation.ApplicableMethods);
Lazy<ImmutableArray<IOperation>> arguments = new Lazy<ImmutableArray<IOperation>>(() => boundDynamicInvocation.Arguments.SelectAsArray(n => Create(n)));
Copy link
Member

@cston cston Sep 6, 2017

Choose a reason for hiding this comment

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

Consider extracting a helper method for creating a Lazy<ImmutableArray<IOperation>> from ImmutableArray<BoundExpression> since there appear to be many instances of this. #Pending

Copy link
Contributor Author

@mavasani mavasani Sep 11, 2017

Choose a reason for hiding this comment

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

Good idea, but there are large number of instances of this and I would prefer it to be a separate cleanup change, especially given we want to write an operation generator. I have added this suggestion to the issue tracking implementation of the operation generator: #20204 (comment) #Pending

var x = /*<bind>*/d[i]/*</bind>*/;
}

public int this[int i] => 0;
Copy link
Member

Choose a reason for hiding this comment

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

Property is not needed here nor in the test below.

{
var x = /*<bind>*/c.M2[i]/*</bind>*/;
}
}
Copy link
Member

@cston cston Sep 6, 2017

Choose a reason for hiding this comment

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

Is this test different from the test above? #Resolved

Copy link
Contributor Author

@mavasani mavasani Sep 11, 2017

Choose a reason for hiding this comment

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

Good catch, I intended the parameter to be C c not dynamic c. I have fixed it now. #Resolved


static void M(dynamic d, C c)
{
// This could be either of the one-parameter overloads so we allow it.
c.Goo(d);

// Doesn't constraints of generic overloads.
c.Goo<short>(d, d);
/*<bind>*/c.Goo<short>(d, d)/*</bind>*/; // Doesn't constraints of generic overloads.
Copy link
Member

Choose a reason for hiding this comment

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

What does the comment mean?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not sure - I have just retained the existing comment. I had to move it outside the /*<bind>*/ annotation as otherwise the test framework was unable to find the correct syntax node to fetch operation.

}

var expression = (HasDynamicArgumentsExpression)dynamicExpression;
if (expression.ArgumentNames.IsDefaultOrEmpty)
Copy link
Member

@cston cston Sep 6, 2017

Choose a reason for hiding this comment

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

Please extract a local for expression.ArgumentNames. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

}

var expression = (HasDynamicArgumentsExpression)dynamicExpression;
if (expression.ArgumentRefKinds.IsDefault)
Copy link
Member

@cston cston Sep 6, 2017

Choose a reason for hiding this comment

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

Please extract a local for expression.ArgumentRefKinds.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

if (index < 0 || index >= expression.ArgumentNames.Length)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
Copy link
Member

@cston cston Sep 6, 2017

Choose a reason for hiding this comment

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

This check is unnecessary, ArgumentNames[index] will throw the same exception. Same comment for GetArgumentRefKind. #Resolved


/// <summary>
/// List of applicable symbols that are dynamically bound to the <see cref="Name"/>.
/// List of applicable symbols that are dynamically bound.
/// </summary>
ImmutableArray<ISymbol> ApplicableSymbols { get; }
Copy link
Contributor

@AlekseyTs AlekseyTs Sep 8, 2017

Choose a reason for hiding this comment

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

ImmutableArray ApplicableSymbols { get; } [](start = 8, length = 50)

I believe we decided to not expose any applicable symbols. In any case, given the name of the interface, it feels like this property doesn't belong in it. #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

If we remove the property, is there a value in having this interface at all?


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

Copy link
Contributor Author

@mavasani mavasani Sep 11, 2017

Choose a reason for hiding this comment

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

I have removed the interface and moved the Arguments property to each IDynamicXXXExpression interface. #Closed

@mavasani
Copy link
Contributor Author

@AlekseyTs - addressed your feedback. One more round of review please.

@mavasani
Copy link
Contributor Author

@dotnet-bot retest windows_debug_unit32_prtest please

… expression for a bound method group that is a child of dynamic invocation
@AlekseyTs
Copy link
Contributor

AlekseyTs commented Sep 13, 2017

@mavasani Could you please confirm that build failures aren't caused by the changes in this PR? #Closed

@mavasani
Copy link
Contributor Author

Thanks @AlekseyTs - some failures are irrelevant and some seem to be from tests not marked with IOperation compiler trait attribute. Let me fix this up.

@mavasani
Copy link
Contributor Author

@dotnet-bot retest windows_debug_unit64_prtest please

@mavasani
Copy link
Contributor Author

@dotnet-bot retest windows_debug_vs-integration_prtest please

@mavasani
Copy link
Contributor Author

@dotnet-bot retest windows_release_vs-integration_prtest please

@mavasani
Copy link
Contributor Author

@dotnet/roslyn-infrastructure All the VSI runs seems to be failing with the following:

 	Microsoft.VisualStudio.Shell.15.0.dll!Microsoft.Internal.VisualStudio.PlatformUI.WindowHelper.ShowModal(System.Windows.Window window, System.IntPtr parent)	Unknown
 	Microsoft.VisualStudio.CommonIDE.dll!Microsoft.VisualStudio.CommonIDE.ProductKeyDialogLauncher.LaunchProductKeyDialogHelper(Microsoft.VisualStudio.LicenseManagement.Interop.IVsLicensingState licensingState, Microsoft.Internal.VisualStudio.Shell.Interop.IVsProductKeyDialogLauncherCallback callback, System.IDisposable telemetryActivity)	Unknown
 	Microsoft.VisualStudio.CommonIDE.dll!Microsoft.VisualStudio.CommonIDE.ProductKeyDialogLauncher.LaunchProductKeyDialog(Microsoft.Internal.VisualStudio.Shell.Interop.IVsProductKeyDialogLauncherCallback callback)	Unknown

Can someone please update the product key on the machines?

/// </summary>
/// <param name="dynamicExpression">Dynamic or late bound expression.</param>
/// <param name="index">Argument index.</param>
internal static string GetArgumentName(this HasDynamicArgumentsExpression dynamicExpression, int index)
Copy link
Contributor

@AlekseyTs AlekseyTs Sep 14, 2017

Choose a reason for hiding this comment

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

int index [](start = 101, length = 9)

Index should be checked for range even when argumentNames.IsDefaultOrEmpty. #Closed

return GetArgumentRefKind((HasDynamicArgumentsExpression)dynamicExpression, index);
}

internal static RefKind? GetArgumentRefKind(this HasDynamicArgumentsExpression dynamicExpression, int index)
Copy link
Contributor

@AlekseyTs AlekseyTs Sep 14, 2017

Choose a reason for hiding this comment

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

index [](start = 110, length = 5)

Index should be checked for range even when argumentRefKinds.IsDefaultOrEmpty #Closed

";
string expectedOperationTree = @"
IInvocationExpression ( ? A.B.()) (OperationKind.InvocationExpression, Type: ?, IsInvalid) (Syntax: 'M(d)')
Instance Receiver: IOperation: (OperationKind.None, IsInvalid) (Syntax: 'M')
Copy link
Contributor

@AlekseyTs AlekseyTs Sep 14, 2017

Choose a reason for hiding this comment

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

Instance Receiver: IOperation: (OperationKind.None, IsInvalid) (Syntax: 'M') [](start = 2, length = 77)

Why are we getting None here? Please open an issue to follow up. #Closed

Copy link
Contributor Author

@mavasani mavasani Sep 14, 2017

Choose a reason for hiding this comment

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

Filed #22121 #Resolved

Instance Receiver: IOperation: (OperationKind.None, IsInvalid) (Syntax: 'M')
Arguments(1):
IArgument (ArgumentKind.Explicit, Matching Parameter: null) (OperationKind.Argument, IsInvalid) (Syntax: 'd')
ILocalReferenceExpression: d (OperationKind.LocalReferenceExpression, Type: dynamic, IsInvalid) (Syntax: 'd')
Copy link
Contributor

@AlekseyTs AlekseyTs Sep 14, 2017

Choose a reason for hiding this comment

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

ILocalReferenceExpression: d (OperationKind.LocalReferenceExpression, Type: dynamic, IsInvalid) (Syntax: 'd') [](start = 8, length = 109)

I am not sure why this node is marked as invalid. Please open an issue to follow up. #Closed

Copy link
Contributor Author

@mavasani mavasani Sep 14, 2017

Choose a reason for hiding this comment

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

#22122 #Resolved

/// </summary>
/// <param name="dynamicExpression">Dynamic or late bound expression.</param>
/// <param name="index">Argument index.</param>
public static string GetArgumentName(this IDynamicInvocationExpression dynamicExpression, int index)
Copy link
Contributor

@AlekseyTs AlekseyTs Sep 14, 2017

Choose a reason for hiding this comment

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

GetArgumentName [](start = 29, length = 15)

For all new public methods, please add targeted tests to cover scenarios with an invalid input, i.e. when validation fails and we throw. #Closed

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Sep 14, 2017

Done with review pass (iteration 10) #Closed

@mavasani
Copy link
Contributor Author

@AlekseyTs - addressed your feedback.

@mavasani
Copy link
Contributor Author

@dotnet-bot retest ubuntu_16_debug_prtest please

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

@mavasani
Copy link
Contributor Author

Integration tests queues are failing due to an unrelated expired product key issue.

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.

4 participants