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

added CSharpOperationFactory #18825

Merged
merged 20 commits into from
Apr 27, 2017

Conversation

heejaechang
Copy link
Contributor

@heejaechang heejaechang commented Apr 19, 2017

made BoundNode to not implement IOperation and replaced GetOperationInternal to return Operation type.

currently, it uses Lazy for laziness and ConditionalWeakTable for identity

this only contains common and csharp side change. vb side change will follow.

Part of #18246

@heejaechang heejaechang added the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Apr 19, 2017
@heejaechang
Copy link
Contributor Author

retest windows_release_vs-integration_prtest please

@heejaechang heejaechang changed the title Operation factory added CSharpOperationFactory Apr 20, 2017
@heejaechang
Copy link
Contributor Author

@dotnet/analyzer-ioperation can you take a look?

@@ -272,7 +272,8 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
hasErrors = CheckRestrictedTypeInAsync(this.ContainingMemberOrLambda, declType, diagnostics, typeSyntax);
}

return new BoundDeclarationPattern(node, localSymbol, boundDeclType, isVar, hasErrors);
var expression = localSymbol == null ? new BoundDiscardExpression(node, boundDeclType.Type) : (BoundExpression)new BoundLocal(node, localSymbol, null, boundDeclType.Type);
Copy link
Member

Choose a reason for hiding this comment

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

not understanding why it's the case that we have a discard if we don't have a local symbol.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@CyrusNajmabadi I dont know I didn't change the logic. @genlu do you know?

{
internal static partial class CSharpOperationFactory
{
private static readonly ConditionalWeakTable<BoundNode, IOperation> s_cache = new ConditionalWeakTable<BoundNode, IOperation>();
Copy link
Member

Choose a reason for hiding this comment

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

i feel like a cache on SemanticModel might be more appropriate, with Operations having a pointer back to the semantic model that was used to create them.

Copy link
Member

Choose a reason for hiding this comment

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

CWT's are ok when you really have no appropritae entity on which to associate data ownership. In this case, it feels like the SemanticModel is the right owner.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@CyrusNajmabadi my next work is adding parent pointer and doing better identity mechanism.

current thinking is making factory an instance owned by semantic model that have explicit cache tied to semantic model.

only thing I am not sure is whether the cache will be tied to bound node or not.

Copy link
Member

Choose a reason for hiding this comment

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

Ok great. Maybe today at our design meeting you can talk us through yoru next steps.

{
switch (boundNode)
{
case BoundDeconstructValuePlaceholder boundDeconstructValuePlaceholder:
Copy link
Member

Choose a reason for hiding this comment

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

while this pattern matching is attractive because it doesn't require test+cast, it's also really expensive as every node may require dozens of type checks.

  1. is there a visitor for bound nodes we can use to do this work?
  2. if not, i think we should just use a regular Kind switch so that we don't do tons of type checks for every operation we create.

--

Note: this isn't a hypothetical concern. I've run into i several time in throughput oriented domains. type-switchs are great when small, or when you need to them rarely. However, if we're converting tons of nodes over to operations, this isn't desirable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure, I can change it to different pattern.

Optional<object> constantValue = ConvertToOptional(boundDeconstructValuePlaceholder.ConstantValue);
return new PlaceholderExpression(isInvalid, syntax, type, constantValue);
}
private static IInvocationExpression CreateBoundCallOperation(BoundCall boundCall)
Copy link
Member

Choose a reason for hiding this comment

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

are these handwritten, or generated? If handwritten, add newline.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

generated. styling. let me do once I am done vb side and done with all other code reviews.

private static ICompoundAssignmentExpression CreateBoundCompoundAssignmentOperatorOperation(BoundCompoundAssignmentOperator boundCompoundAssignmentOperator)
{
BinaryOperationKind binaryOperationKind = CSharp.Expression.DeriveBinaryOperationKind(boundCompoundAssignmentOperator.Operator.Kind);
Lazy<IOperation> target = new Lazy<IOperation>(() => (IOperation)Create(boundCompoundAssignmentOperator.Left));
Copy link
Member

Choose a reason for hiding this comment

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

the cast to IOperation feels like it shoudn't be necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yep. its there since it is generated. I will clean those up.

private static IVariableDeclarationStatement CreateBoundLocalDeclarationOperation(BoundLocalDeclaration boundLocalDeclaration)
{
Lazy<ImmutableArray<IVariableDeclaration>> declarations = new Lazy<ImmutableArray<IVariableDeclaration>>(() => GetVariableDeclarationStatementVariables(boundLocalDeclaration));
bool isInvalid = boundLocalDe
Copy link
Member

Choose a reason for hiding this comment

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

Sync with Gen to make sure this isn't a problem with teh work he's doing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@genlu @mavasani @333fred do you guys have pending work on IOperation? this includes the Evaluation order and IVariableDecl changes.

Copy link
Member

Choose a reason for hiding this comment

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

I'm not working on this.

private static IVariableDeclarationStatement CreateBoundLocalDeclarationOperation(BoundLocalDeclaration boundLocalDeclaration)
{
Lazy<ImmutableArray<IVariableDeclaration>> declarations = new Lazy<ImmutableArray<IVariableDeclaration>>(() => GetVariableDeclarationStatementVariables(boundLocalDeclaration));
bool isInvalid = boundLocalDe
Copy link
Member

Choose a reason for hiding this comment

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

why is this typed to 'object'?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

which one are you talking about?

/// <summary>
/// Represents an expression that creates a pointer value by taking the address of a reference.
/// </summary>
internal sealed partial class AddressOfExpression : AddressOfExpressionBase, IAddressOfExpression
Copy link
Member

Choose a reason for hiding this comment

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

I think we use the pattern BaseXXX, not XXX base. i.e. BaseTypeDeclarationSyntax

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure

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

@heejaechang heejaechang removed the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Apr 21, 2017
@heejaechang
Copy link
Contributor Author

@AlekseyTs can you take a look? tagging @dotnet/roslyn-compiler since I need 2 compiler dev sign off.

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Apr 21, 2017

@heejaechang Are there any behavior changes in this PR? #Closed

@@ -246,7 +246,7 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
case SyntaxKind.SingleVariableDesignation:
break;
case SyntaxKind.DiscardDesignation:
return new BoundDeclarationPattern(node, null, boundDeclType, isVar, hasErrors);
return new BoundDeclarationPattern(node, null, new BoundDiscardExpression(node, boundDeclType.Type), boundDeclType, isVar, hasErrors);
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 21, 2017

Choose a reason for hiding this comment

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

return new BoundDeclarationPattern(node, null, new BoundDiscardExpression(node, boundDeclType.Type), boundDeclType, isVar, hasErrors); [](start = 20, length = 134)

Please revert this file to the original state. #Closed

Copy link
Contributor

@AlekseyTs AlekseyTs Apr 21, 2017

Choose a reason for hiding this comment

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

Also, restore the constructor that is, apparently, deleted in this PR. Place it into Constructors.cs


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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure will do.

protected override OperationKind ExpressionKind => OperationKind.None;
}

internal partial class BoundDeclarationPattern
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 21, 2017

Choose a reason for hiding this comment

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

internal partial class BoundDeclarationPattern [](start = 4, length = 46)

This partial declaration should be moved to Constructors.cs rather than deleted. #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.

sure.

@@ -1542,7 +1542,7 @@ private static Binder GetQueryEnclosingBinder(int position, CSharpSyntaxNode sta
}
while (node != null);

done:
done:
return GetEnclosingBinderInternalWithinRoot(AdjustStartingNodeAccordingToNewRoot(startingNode, queryClause.Syntax),
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 21, 2017

Choose a reason for hiding this comment

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

Please revert formatting change for this line. #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.

sure

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Apr 21, 2017

Done with review pass. #Closed


public override TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument)
{
return visitor.VisitNoneOperation(this, argument);
Copy link
Member

Choose a reason for hiding this comment

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

Why not move this to CSharpOperationFactory and delete this file?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure. I can do that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

deleted

@heejaechang
Copy link
Contributor Author

@AlekseyTs this shouldn't contain any behavior change.

@genlu
Copy link
Member

genlu commented Apr 21, 2017

LGTM besides changes @AlekseyTs requested.

@heejaechang
Copy link
Contributor Author

retest windows_eta_open_prtest please

@@ -180,8 +180,8 @@ internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSy
{
case ConversionKind.ExplicitDynamic:
case ConversionKind.ImplicitDynamic:
// Since the input was `dynamic`, which is equivalent to `object`, there must also
// exist some unboxing, identity, or reference conversion as well, making the conversion legal.
// Since the input was `dynamic`, which is equivalent to `object`, there must also
Copy link
Contributor

@AlekseyTs AlekseyTs Apr 24, 2017

Choose a reason for hiding this comment

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

// Since the input was dynamic, which is equivalent to object, there must also [](start = 20, length = 82)

Please revert this file to its original state. #Closed

@AlekseyTs
Copy link
Contributor

Done with review pass. Please revert src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs to its original state.

@mavasani
Copy link
Contributor

@AlekseyTs can you take a look? I did what you asked. this is HeeJae.

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

@heejaechang
Copy link
Contributor Author

@cston @jaredpar @VSadov @jcouv can you take a look?

@@ -867,6 +866,7 @@
<InternalsVisibleToTest Include="Roslyn.Services.Editor.CSharp.UnitTests" />
<InternalsVisibleToTest Include="Roslyn.Services.Editor2.UnitTests" />
</ItemGroup>
<ItemGroup />
Copy link
Member

Choose a reason for hiding this comment

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

Empty group?

Optional<object> constantValue = default(Optional<object>);
return new LazyVariableDeclarationStatement(declarations, isInvalid, syntax, type, constantValue);
}
private static IVariableDeclarationStatement C
Copy link
Member

Choose a reason for hiding this comment

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

return blockStatement.Statements.SelectAsArray(s => Create(s)).WhereAsArray(s => s.Kind != OperationKind.None);

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 I think the current form is less allocation since SelectAs or WhereAs create new immutablearray. if there is only one SelectAs or WhereAsArray then they are better but in this case, there are 2 linq attached. so I think what I have is less allocation?

Copy link
Member

@cston cston Apr 27, 2017

Choose a reason for hiding this comment

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

@heejaechang You may be right that LINQ may be cheaper than the combination of SelectAs and WhereAs. For LINQ, I suspect there are 4 allocations: boxing the Statements struct, the Select result, the Where result, and the ToImmutableArray() result. The alternative should be at most two allocations: one for SelectAs, and zero or one for WhereAs depending on whether WhereAs returns a non-empty subset, That said, if there are two allocations, the total bytes allocated may be larger than the LINQ approach. Feel free to keep as is.

@@ -901,119 +1600,304 @@ public override void Accept(OperationVisitor visitor)
}

/// <summary>
/// Represents a C# foreach statement or a VB For Each staement.
Copy link
Member

Choose a reason for hiding this comment

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

Typo: statement

@cston
Copy link
Member

cston commented Apr 26, 2017

LGTM

public static IExpressionStatement CreateCompoundAssignmentExpressionStatement(
IOperation target, IOperation value, BinaryOperationKind binaryOperationKind, IMethodSymbol operatorMethod, SyntaxNode syntax)
{
var isInvalid = target == null || target.IsInvalid || value == null || value.IsInvalid;
Copy link
Member

Choose a reason for hiding this comment

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

Should you be checking if binaryOperationKind is BinaryOperationKind.Invalid here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@333fred you might be correct but for now, I am keeping code exactly same as before.

Copy link
Member

Choose a reason for hiding this comment

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

Can we file a bug to keep track?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we just decide to remove isInvalid from IOperation. so that solves this issue :)

@heejaechang heejaechang changed the base branch from master to features/ioperation April 27, 2017 22:58
@heejaechang heejaechang merged commit 29c7b6e into dotnet:features/ioperation Apr 27, 2017
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.

9 participants