Skip to content

Commit b279a80

Browse files
committed
Adjust nullability analysis for extension operators.
Related to #29605. Related to #29961. Related to #79011.
1 parent b34e734 commit b279a80

File tree

8 files changed

+11005
-7216
lines changed

8 files changed

+11005
-7216
lines changed

src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,13 @@ internal partial class BoundBinaryOperator
418418

419419
internal partial class BoundUserDefinedConditionalLogicalOperator
420420
{
421+
private partial void Validate()
422+
{
423+
Debug.Assert(LogicalOperator.ParameterCount == 2);
424+
Debug.Assert(TrueOperator.ParameterCount == 1);
425+
Debug.Assert(FalseOperator.ParameterCount == 1);
426+
}
427+
421428
public override Symbol ExpressionSymbol
422429
{
423430
get { return this.LogicalOperator; }

src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@
496496
<Field Name="Operators" Type="TupleBinaryOperatorInfo.Multiple"/>
497497
</Node>
498498

499-
<Node Name="BoundUserDefinedConditionalLogicalOperator" Base="BoundBinaryOperatorBase" SkipInNullabilityRewriter="true">
499+
<Node Name="BoundUserDefinedConditionalLogicalOperator" Base="BoundBinaryOperatorBase" SkipInNullabilityRewriter="true" HasValidate="true">
500500
<Field Name="OperatorKind" Type="BinaryOperatorKind"/>
501501
<Field Name="LogicalOperator" Type="MethodSymbol"/>
502502
<Field Name="TrueOperator" Type="MethodSymbol"/>

src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ protected void VisitCondition(BoundExpression node)
628628
AdjustConditionalState(node);
629629
}
630630

631-
private void AdjustConditionalState(BoundExpression node)
631+
protected void AdjustConditionalState(BoundExpression node)
632632
{
633633
if (IsConstantTrue(node))
634634
{
@@ -2450,14 +2450,36 @@ private void VisitBinaryLogicalOperatorChildren(BoundExpression node)
24502450
stack.Push(binary);
24512451
}
24522452

2453+
VisitBinaryLogicalOperatorChildren(stack);
2454+
stack.Free();
2455+
}
2456+
2457+
protected virtual void VisitBinaryLogicalOperatorChildren(ArrayBuilder<BoundExpression> stack)
2458+
{
2459+
BoundExpression binary;
24532460
Debug.Assert(stack.Count > 0);
24542461

2462+
binary = stack.Pop();
2463+
2464+
BoundExpression child;
2465+
switch (binary.Kind)
2466+
{
2467+
case BoundKind.BinaryOperator:
2468+
var binOp = (BoundBinaryOperator)binary;
2469+
child = binOp.Left;
2470+
break;
2471+
case BoundKind.UserDefinedConditionalLogicalOperator:
2472+
var udBinOp = (BoundUserDefinedConditionalLogicalOperator)binary;
2473+
child = udBinOp.Left;
2474+
break;
2475+
default:
2476+
throw ExceptionUtilities.UnexpectedValue(binary.Kind);
2477+
}
2478+
24552479
VisitCondition(child);
24562480

24572481
while (true)
24582482
{
2459-
binary = stack.Pop();
2460-
24612483
BinaryOperatorKind kind;
24622484
BoundExpression right;
24632485
switch (binary.Kind)
@@ -2479,6 +2501,7 @@ private void VisitBinaryLogicalOperatorChildren(BoundExpression node)
24792501
var op = kind.Operator();
24802502
var isAnd = op == BinaryOperatorKind.And;
24812503
var isBool = kind.OperandTypes() == BinaryOperatorKind.Bool;
2504+
Debug.Assert(!isBool || binary.Kind != BoundKind.UserDefinedConditionalLogicalOperator);
24822505

24832506
Debug.Assert(isAnd || op == BinaryOperatorKind.Or);
24842507

@@ -2494,10 +2517,8 @@ private void VisitBinaryLogicalOperatorChildren(BoundExpression node)
24942517
}
24952518

24962519
AdjustConditionalState(binary);
2520+
binary = stack.Pop();
24972521
}
2498-
2499-
Debug.Assert((object)binary == node);
2500-
stack.Free();
25012522
}
25022523

25032524
protected virtual void AfterLeftChildOfBinaryLogicalOperatorHasBeenVisited(BoundExpression binary, BoundExpression right, bool isAnd, bool isBool, ref TLocalState leftTrue, ref TLocalState leftFalse)

src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,8 @@ private void VisitForEachEnumeratorInfo(ForEachEnumeratorInfo enumeratorInfo)
276276

277277
public override BoundNode? VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node)
278278
{
279-
if (node.LeftConversion is BoundConversion leftConversion)
279+
if (node.LeftConversion is BoundConversion leftConversion &&
280+
!(node.Operator.Method is { IsStatic: false } method && method.GetIsNewExtensionMember()))
280281
{
281282
VerifyExpression(leftConversion);
282283
}

0 commit comments

Comments
 (0)