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

Ensure that we get a well formed child IOperation tree even for bound… #18976

Merged
merged 8 commits into from
May 4, 2017

Conversation

mavasani
Copy link
Contributor

@mavasani mavasani commented Apr 25, 2017

… nodes for whom IOperation support is not yet implemented

Customer scenario

Due to large number of unimplemented IOperation APIs for new language and existing features, all the IOperation analyzers (such as FXCop analyzers) do not receive any operation callbacks for code containing these features (tuples, string interpolation, query expressions, object and collection initializers, etc.). This causes lot of false positives in the analyzer diagnostics as it doesn't see parameter or field references within such code. Additionally, the analyzers do not report true issues in expressions within this language features. This is one of the biggest blocker towards dogfooding the FXCop analyzers.

Bugs this fixes:

Fixes #8884

Workarounds, if any

Disable the rule or suppress all the false positives. All our three repos consuming the FXCop analyzers (Roslyn, Project system and Roslyn-analyzers) were forced to disable these rules due to extremely large number of false positives.

Risk

Low. Proposed fix is to introduce a temporary internal interface IOperationWithChildren for bound nodes for which we haven't designed the IOperation APIs or they have missing pieces. This will allow the OperationWalker to walk the descendants of such nodes and make analyzer callbacks and drastically reduce the false positives. This change doesn't modify the publically available IOperation tree or the API, so we should be able to remove it once we have fully designed and implemented IOperation (tracked by #19060)

Performance impact

Low. We will now walk additional IOperation nodes and make callbacks, but this is a functional requirement.

Is this a regression from a previous update?

No.

Root cause analysis:

IOperation based analyzers are still being developed and tested.

How was the bug found?

Lots of customer reports about false positives.

… nodes for whom IOperation support is not yet implemented

This ensures that the analyzer driver/operation walker is able to find all the descendant IOperation nodes within these not yet implemented features. We should remove the IOperationWithChildren interface once we have designed all the IOperation APIs.

TODO: Implement the VB part.

Fixes dotnet#8884
@mavasani
Copy link
Contributor Author

Tagging @dotnet/analyzer-ioperation for review.

@mavasani
Copy link
Contributor Author

Added the VB support and tests.

Tagging @AlekseyTs @cston as well.

var collectionInitializerExpresion = objectOrCollectionInitializer as BoundCollectionInitializerExpression;
if (collectionInitializerExpresion != null)
{
return collectionInitializerExpresion.Initializers;
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

return collectionInitializerExpresion.Initializers; [](start = 16, length = 51)

Is this new code path covered by tests? #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 have added a skipped test for this. It still doesn't work as expected due to the fact that IObjectCreationExpression.Initializers is still returning ImmutableArray of ISymbolInitializers.

Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

I am not comfortable with changes that affect behavior of existing APIs and are not covered by active tests. I think we should either revert changes to IObjectCreationExpression.MemberInitializers implementation, or cover the changes in tests. #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.

Makes sense, let me revert the changes to IObjectCreationExpression.MemberInitializers implementation.

@@ -1001,6 +1016,8 @@ internal sealed partial class BoundDeconstructionAssignmentOperator : BoundExpre
// TODO: implement IOperation for pattern-matching constructs (https://github.com/dotnet/roslyn/issues/8699)
protected override OperationKind ExpressionKind => OperationKind.None;

protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Left, this.Right);
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

this.Right [](start = 111, length = 10)

We might not want to expose the right node as is. For example, I believe it can contain special conversions that probably shouldn't be exposed to the outside world in that form. I think we might want to expose only the nodes that aren't special for deconstruction. CC @jcouv #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.

Note that the IOperationWithChildren API is just internal, which only the OperationWalker understands so we can walk down it's children when computing all operations to analyze in a method block. Public clients will still not be able to access any children nodes, we don't need to worry about exposing unwanted nodes here.

@@ -1413,6 +1420,8 @@ internal partial class BoundDynamicIndexerAccess
{
protected override OperationKind ExpressionKind => OperationKind.None;

protected override ImmutableArray<IOperation> Children => this.Arguments.Add(this.ReceiverOpt).As<IOperation>();
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

this.ReceiverOpt [](start = 85, length = 16)

Receiver should probably be the first. We also probably don't want to add nulls to the list. #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.

Given that the API is only internal, and the OperationWalker handles null child nodes inside Children, I felt it is better to add all nodes and the client handle null cases.

Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

I felt it is better to add all nodes and the client handle null cases.

Then we should clearly document this on the API in the BoundNode and in the interface. #Closed

@@ -1488,6 +1503,8 @@ internal partial class BoundRangeVariable
{
protected override OperationKind ExpressionKind => OperationKind.None;

protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Value);
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

protected override ImmutableArray Children => ImmutableArray.Create(this.Value); [](start = 8, length = 104)

This doesn't feel right. It looks like the value doesn't correspond to anything explicitly present in source. #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.

Okay, I will revert this.

@@ -1533,6 +1550,8 @@ internal partial class BoundQueryClause
{
protected override OperationKind ExpressionKind => OperationKind.None;

protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Value);
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

protected override ImmutableArray Children => ImmutableArray.Create(this.Value); [](start = 8, length = 104)

I am not sure if we want to expose the entire value here. I think it will include calls to the query operators, but at the design meeting I didn't get an impression that we would want to expose them right now. #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.

How do we ensure that we make callbacks for any operation nodes for user code within query? I think the fact that we are returning compiler generated nodes is irrelevant to this approach or the IOperationWithChildren API.


internal partial class BoundDeclarationPattern
{
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.VariableAccess, this.DeclaredType);
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

protected override ImmutableArray Children => ImmutableArray.Create(this.VariableAccess, this.DeclaredType); [](start = 7, length = 133)

Should be an empty set, I think. #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.

Okay, I can revert

@@ -1818,6 +1873,8 @@ internal partial class BoundDynamicInvocation
{
protected override OperationKind ExpressionKind => OperationKind.None;

protected override ImmutableArray<IOperation> Children => this.Arguments.As<IOperation>().Add(this.Expression);
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

this.Arguments.As().Add(this.Expression); [](start = 66, length = 53)

Expression should probably be first. #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.

Order doesn't really matter as we are not exposing this publically.

@@ -1833,6 +1890,8 @@ internal partial class BoundArrayLength
{
protected override OperationKind ExpressionKind => OperationKind.None;

protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Expression);
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

protected override ImmutableArray Children => ImmutableArray.Create(this.Expression); [](start = 8, length = 109)

I think we can skip this node, it is created only at lowering. #Closed

@@ -767,6 +795,8 @@ internal partial class BoundConditionalGoto
{
protected override OperationKind StatementKind => OperationKind.None;

protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Condition);
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

protected override ImmutableArray Children => ImmutableArray.Create(this.Condition); [](start = 8, length = 108)

This is a lower level node. #Closed

{
builder.Add(section);
}
builder.Add(this.DefaultLabel);
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

builder.Add(this.DefaultLabel); [](start = 16, length = 31)

It feels like one of the sections refers to this node and this member is just for compiler's convenience. #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.

Okay, in that case I can remove this statement.

Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

Should be verified with a test. #Closed

@@ -58,6 +58,8 @@ public bool HasLocals

protected override OperationKind ExpressionKind => OperationKind.None;

protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.Value);
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

protected override ImmutableArray Children => ImmutableArray.Create(this.Value); [](start = 12, length = 104)

This is a lower node, I think we shouldn't touch it. #Closed

Children(2): IOperation: (OperationKind.None) (Syntax: 'var (x, y)')
Children(2): ILocalReferenceExpression: x (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'x')
ILocalReferenceExpression: y (OperationKind.LocalReferenceExpression, Type: System.Int32) (Syntax: 'y')
IConversionExpression (ConversionKind.Invalid, Implicit) (OperationKind.ConversionExpression, Type: (System.Int32, System.Int32)) (Syntax: 'point')
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

IConversionExpression (ConversionKind.Invalid, Implicit) (OperationKind.ConversionExpression, Type: (System.Int32, System.Int32)) (Syntax: 'point') [](start = 4, length = 147)

This looks like a conversion that we might not want to expose. #Closed

}

[Fact, WorkItem(8884, "https://github.com/dotnet/roslyn/issues/8884")]
public void ParameterReference_PatternSwitchStatement()
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

ParameterReference_PatternSwitchStatement [](start = 20, length = 41)

It looks like we are missing a test with default label. #Closed

Protected Overrides Function ExpressionKind() As OperationKind
Return OperationKind.None
End Function

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation) [](start = 8, length = 79)

BoundArrayLength is lower node, there is no need to modify it. #Closed

Protected Overrides Function ExpressionKind() As OperationKind
Return OperationKind.None
End Function

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation) [](start = 8, length = 79)

It looks like BoundReferenceAssignment is a lower node, we don't need to modify it. #Closed

Protected Overrides Function ExpressionKind() As OperationKind
Return OperationKind.None
End Function

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Get
Return ImmutableArray.Create(Of IOperation)(Me.OriginalArgument, Me.InConversion, Me.InPlaceholder, Me.OutConversion, Me.OutPlaceholder)
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

Me.InConversion, Me.InPlaceholder, Me.OutConversion, Me.OutPlaceholder [](start = 81, length = 70)

I think we shouldn't expose these nodes for now. Placeholders are going to be duplicated in conversions. #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

OriginalArgument is fine.


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

Protected Overrides Function ExpressionKind() As OperationKind
Return OperationKind.None
End Function

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation) [](start = 8, length = 79)

BoundLateBoundArgumentSupportingAssignmentWithCapture looks like a lower node, no need to modify it. #Closed

Protected Overrides Function ExpressionKind() As OperationKind
Return OperationKind.None
End Function

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Get
Return ImmutableArray.Create(Of IOperation)(Me.CapturedGroupOpt, Me.GroupPlaceholderOpt, Me.UnderlyingExpression)
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 27, 2017

Choose a reason for hiding this comment

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

Me.GroupPlaceholderOpt [](start = 81, length = 22)

I think GroupPlaceholderOpt should be excluded from the list, it simply provides identity. #Closed

Protected Overrides Function ExpressionKind() As OperationKind
Return OperationKind.None
End Function

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 28, 2017

Choose a reason for hiding this comment

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

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation) [](start = 8, length = 79)

BoundComplexConditionalAccessReceiver looks like a lower node, there is no need to modify it. #Closed

/// </summary>
protected virtual ImmutableArray<IOperation> Children => ImmutableArray<IOperation>.Empty;

public virtual void Accept(OperationVisitor visitor)
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 28, 2017

Choose a reason for hiding this comment

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

public virtual void Accept(OperationVisitor visitor) [](start = 8, length = 52)

Should this be abstract instead? #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

Never mind, looks fine.


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

visitor.VisitNoneOperation(this);
}

public virtual TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument)
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 28, 2017

Choose a reason for hiding this comment

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

public virtual TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument) [](start = 8, length = 115)

Should this be abstract instead? #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

Never mind, looks fine.


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

@@ -1714,6 +1794,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return OperationKind.None
End Function

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 28, 2017

Choose a reason for hiding this comment

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

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation) [](start = 8, length = 79)

BoundConditionalGoto is a lower level node, no need to modify it. #Closed

@@ -1806,6 +1910,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return OperationKind.None
End Function

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 28, 2017

Choose a reason for hiding this comment

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

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation) [](start = 8, length = 79)

BoundUnstructuredExceptionOnErrorSwitch is a lower level node, no need to modify it. #Closed

@AlekseyTs
Copy link
Contributor

AlekseyTs commented May 1, 2017

Done with review pass. #Closed

@mavasani
Copy link
Contributor Author

mavasani commented May 3, 2017

@AlekseyTs The PR is ready for another review. Thanks!


internal partial class BoundDeclarationPattern
{
protected override ImmutableArray<IOperation> Children => ImmutableArray.Create<IOperation>(this.VariableAccess);
Copy link
Contributor

@AlekseyTs AlekseyTs May 3, 2017

Choose a reason for hiding this comment

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

protected override ImmutableArray Children => ImmutableArray.Create(this.VariableAccess); [](start = 8, length = 113)

I do not understand why is this changed back? #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.

Aleksey, this was breaking a test where we do not get an ILocalReferenceExpression for the variable access.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

@AlekseyTs AlekseyTs May 3, 2017

Choose a reason for hiding this comment

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

I guess, it is fine to expose that node until we figure out how declaration pattern is supposed to be represented. #Closed

@AlekseyTs
Copy link
Contributor

AlekseyTs commented May 3, 2017

    protected override ImmutableArray<IOperation> Children => this.Arguments.As<IOperation>();

Not sure why this code is removed. #Closed


Refers to: src/Compilers/CSharp/Portable/BoundTree/Expression.cs:1587 in 5f6e036. [](commit_id = 5f6e036, deletion_comment = True)

@mavasani
Copy link
Contributor Author

mavasani commented May 3, 2017

Not sure why this code is removed.

I deleted it accidentally in one of the previous commits, and I have added it back in the latest commit.

@AlekseyTs
Copy link
Contributor

AlekseyTs commented May 3, 2017

I deleted it accidentally in one of the previous commits, and I have added it back in the latest commit.

It looks like it wasn't added back, at least I don't see it. #Closed

references: new[] { MscorlibRef, SystemRef, compilation0.EmitToImageReference(embedInteropTypes: true) });

string expectedOperationTree = @"
IOperation: (OperationKind.None) (Syntax: 'new I(x)')
Copy link
Contributor

@AlekseyTs AlekseyTs May 3, 2017

Choose a reason for hiding this comment

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

It feels like we should have a node for x. #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.

Yes, but the generated bound node doesn't seem to have it. I will file an issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Filed #19219

@@ -2375,6 +2426,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return OperationKind.None
End Function

Protected Overrides ReadOnly Property Children As ImmutableArray(Of IOperation)
Get
Return ImmutableArray.Create(Of IOperation)(Me.OriginalArgument)
Copy link
Contributor

@AlekseyTs AlekseyTs May 3, 2017

Choose a reason for hiding this comment

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

Return ImmutableArray.Create(Of IOperation)(Me.OriginalArgument) [](start = 16, length = 64)

Is this code path covered by tests? #Closed

@AlekseyTs
Copy link
Contributor

AlekseyTs commented May 3, 2017

Done with review pass. #Closed

… as it is never exposed in the operation tree
@mavasani
Copy link
Contributor Author

mavasani commented May 3, 2017

Also tagging @cston for review.

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

mavasani commented May 3, 2017

@ManishJayaswal @Pilchie for ask mode approval.

@@ -9,23 +9,52 @@

namespace Microsoft.CodeAnalysis.CSharp
{
internal partial class BoundStatement : IOperation
internal partial class BoundNode : IOperation, IOperationWithChildren
Copy link
Member

Choose a reason for hiding this comment

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

Is there an advantage to having a separate interface for IOperationWithChildren? Aren't callers forced to check for an implementation of IOperationWithChildren, then check .Children.IsEmpty or perhaps even .IsDefault?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cston This is supposed to be a temporary internal interface that will exist until will we finish IOperation API design and implementation. Only the OperationWalker is aware about this interface to enable the analyzer driver to walk the descendants under unimplemented bound nodes. Having a special interface allows us to then just delete the interface and verify/fix up bound nodes still relying on it.

{
get
{
var builder = ImmutableArray.CreateBuilder<IOperation>(this.SwitchSections.Length + 2);
Copy link
Member

Choose a reason for hiding this comment

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

this.SwitchSections.Length + 1?


partial class BoundPatternSwitchSection
{
protected override ImmutableArray<IOperation> Children => this.SwitchLabels.As<IOperation>().AddRange(this.Statements).ToImmutableArray();
Copy link
Member

Choose a reason for hiding this comment

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

AddRange() returns an ImmutableArray<T>. No need for .ToImmutableArray().

@cston
Copy link
Member

cston commented May 4, 2017

LGTM

@mavasani
Copy link
Contributor Author

mavasani commented May 4, 2017

FYI @heejaechang - once this PR is merged, it will cause merge conflicts in the IOperation feature branch due to your OperationFactory work. We can sit together and resolve these conflicts.

@mavasani
Copy link
Contributor Author

mavasani commented May 4, 2017

@dotnet-bot retest windows_debug_unit32_prtest please

@heejaechang
Copy link
Contributor

@mavasani sure.

@mavasani
Copy link
Contributor Author

mavasani commented May 4, 2017

@dotnet-bot retest windows_debug_unit32_prtest please

@mavasani
Copy link
Contributor Author

mavasani commented May 4, 2017

@dotnet-bot retest windows_release_vs-integration_prtest please

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.

IParameterReferenceExpression operation not generated for parameter access in a certain cases
6 participants