-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
added CSharpOperationFactory #18825
Conversation
otherwise, it throws all over the places.
retest windows_release_vs-integration_prtest please |
@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); |
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.
not understanding why it's the case that we have a discard if we don't have a local symbol.
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.
@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>(); |
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.
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.
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.
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.
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.
@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.
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.
Ok great. Maybe today at our design meeting you can talk us through yoru next steps.
{ | ||
switch (boundNode) | ||
{ | ||
case BoundDeconstructValuePlaceholder boundDeconstructValuePlaceholder: |
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.
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.
- is there a visitor for bound nodes we can use to do this work?
- 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.
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.
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) |
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.
are these handwritten, or generated? If handwritten, add newline.
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.
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)); |
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.
the cast to IOperation feels like it shoudn't be necessary.
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.
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 |
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.
Sync with Gen to make sure this isn't a problem with teh work he's doing.
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.
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 |
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.
why is this typed to 'object'?
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.
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 |
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.
I think we use the pattern BaseXXX, not XXX base. i.e. BaseTypeDeclarationSyntax
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.
sure
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.
done
@AlekseyTs can you take a look? tagging @dotnet/roslyn-compiler since I need 2 compiler dev sign off. |
@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); |
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.
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
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.
Also, restore the constructor that is, apparently, deleted in this PR. Place it into Constructors.cs
In reply to: 112778009 [](ancestors = 112778009)
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.
sure will do.
protected override OperationKind ExpressionKind => OperationKind.None; | ||
} | ||
|
||
internal partial class BoundDeclarationPattern |
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 partial class BoundDeclarationPattern [](start = 4, length = 46)
This partial declaration should be moved to Constructors.cs rather than deleted. #Closed
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.
sure.
@@ -1542,7 +1542,7 @@ private static Binder GetQueryEnclosingBinder(int position, CSharpSyntaxNode sta | |||
} | |||
while (node != null); | |||
|
|||
done: | |||
done: | |||
return GetEnclosingBinderInternalWithinRoot(AdjustStartingNodeAccordingToNewRoot(startingNode, queryClause.Syntax), |
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.
Please revert formatting change for this line. #Closed
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.
sure
Done with review pass. #Closed |
|
||
public override TResult Accept<TArgument, TResult>(OperationVisitor<TArgument, TResult> visitor, TArgument argument) | ||
{ | ||
return visitor.VisitNoneOperation(this, argument); |
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.
Why not move this to CSharpOperationFactory
and delete this file?
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.
sure. I can do that.
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.
deleted
@AlekseyTs this shouldn't contain any behavior change. |
LGTM besides changes @AlekseyTs requested. |
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 |
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.
// Since the input was
dynamic
, which is equivalent toobject
, there must also [](start = 20, length = 82)
Please revert this file to its original state. #Closed
Done with review pass. Please revert src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs to its original state. |
@AlekseyTs can you take a look? I did what you asked. this is HeeJae. |
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
@@ -867,6 +866,7 @@ | |||
<InternalsVisibleToTest Include="Roslyn.Services.Editor.CSharp.UnitTests" /> | |||
<InternalsVisibleToTest Include="Roslyn.Services.Editor2.UnitTests" /> | |||
</ItemGroup> | |||
<ItemGroup /> |
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.
Empty group?
Optional<object> constantValue = default(Optional<object>); | ||
return new LazyVariableDeclarationStatement(declarations, isInvalid, syntax, type, constantValue); | ||
} | ||
private static IVariableDeclarationStatement C |
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.
return blockStatement.Statements.SelectAsArray(s => Create(s)).WhereAsArray(s => s.Kind != OperationKind.None);
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.
@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?
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.
@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. |
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.
Typo: statement
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; |
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 you be checking if binaryOperationKind is BinaryOperationKind.Invalid here?
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.
@333fred you might be correct but for now, I am keeping code exactly same as before.
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.
Can we file a bug to keep track?
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.
we just decide to remove isInvalid from IOperation. so that solves this issue :)
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