From bb657329402ed585721c68a5865a8524039e1d0c Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Fri, 8 Mar 2024 00:42:04 +0330 Subject: [PATCH 01/13] Reapply "Avoid creating a result temp for is-expressions (#68694)" (#69582) This reverts commit b4a9c622fb60700459f0e828e6f168d6adeff17c. --- .../BoundLoweredIsPatternExpression.cs | 16 + .../CSharp/Portable/BoundTree/BoundNodes.xml | 8 + .../CSharp/Portable/CodeGen/EmitExpression.cs | 51 +- .../CSharp/Portable/CodeGen/EmitOperators.cs | 21 +- .../CSharp/Portable/CodeGen/EmitStatement.cs | 28 +- .../CSharp/Portable/CodeGen/Optimizer.cs | 33 +- .../Portable/FlowAnalysis/AbstractFlowPass.cs | 6 + .../Generated/BoundNodes.xml.Generated.cs | 91 +- .../LocalRewriter_IsPatternOperator.cs | 39 +- .../Portable/Lowering/SpillSequenceSpiller.cs | 10 + .../CSharp/Test/Emit/CodeGen/PatternTests.cs | 240 ++--- .../CSharp/Test/Emit/CodeGen/SwitchTests.cs | 2 +- .../Emit2/Semantics/PatternMatchingTests.cs | 832 +++++++++--------- .../Emit2/Semantics/PatternMatchingTests3.cs | 70 +- .../Emit2/Semantics/PatternMatchingTests5.cs | 199 ++++- .../Core/Portable/CodeGen/ILBuilder.cs | 10 + 16 files changed, 993 insertions(+), 663 deletions(-) create mode 100644 src/Compilers/CSharp/Portable/BoundTree/BoundLoweredIsPatternExpression.cs diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundLoweredIsPatternExpression.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundLoweredIsPatternExpression.cs new file mode 100644 index 0000000000000..68fed229791af --- /dev/null +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundLoweredIsPatternExpression.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +namespace Microsoft.CodeAnalysis.CSharp; + +partial class BoundLoweredIsPatternExpression +{ + private partial void Validate() + { + // Ensure fall-through is unreachable + Debug.Assert(this.Statements is [.., BoundGotoStatement or BoundSwitchDispatch]); + } +} diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index f4d0d9b9db29c..86389cd858f15 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -2340,6 +2340,7 @@ 'is not Type t') will need to compensate for negated patterns. IsNegated is set if Pattern is the negated form of the inner pattern represented by DecisionDag. --> + @@ -2348,6 +2349,13 @@ + + + + + + + diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index f188d21d0876a..7dbb5a507197f 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -315,6 +315,10 @@ private void EmitExpressionCore(BoundExpression expression, bool used) EmitRefValueOperator((BoundRefValueOperator)expression, used); break; + case BoundKind.LoweredIsPatternExpression: + EmitLoweredIsPatternExpression((BoundLoweredIsPatternExpression)expression, used); + break; + case BoundKind.LoweredConditionalAccess: EmitLoweredConditionalAccessExpression((BoundLoweredConditionalAccess)expression, used); break; @@ -352,6 +356,42 @@ private void EmitExpressionCore(BoundExpression expression, bool used) } } + private void EmitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node, bool used, bool sense = true) + { + EmitSideEffects(node.Statements); + + if (!used) + { + _builder.MarkLabel(node.WhenTrueLabel); + _builder.MarkLabel(node.WhenFalseLabel); + } + else + { + var doneLabel = new object(); + _builder.MarkLabel(node.WhenTrueLabel); + _builder.EmitBoolConstant(sense); + _builder.EmitBranch(ILOpCode.Br, doneLabel); + _builder.AdjustStack(-1); + _builder.MarkLabel(node.WhenFalseLabel); + _builder.EmitBoolConstant(!sense); + _builder.MarkLabel(doneLabel); + } + } + + private void EmitSideEffects(ImmutableArray statements) + { +#if DEBUG + int prevStack = _expectedStackDepth; + int origStack = _builder.GetStackDepth(); + _expectedStackDepth = origStack; +#endif + EmitStatements(statements); +#if DEBUG + Debug.Assert(_expectedStackDepth == origStack); + _expectedStackDepth = prevStack; +#endif + } + private void EmitThrowExpression(BoundThrowExpression node, bool used) { this.EmitThrow(node.Expression); @@ -830,7 +870,7 @@ private void EmitSequencePoint(BoundSequencePointExpression node) } } - private void EmitSequenceExpression(BoundSequence sequence, bool used) + private void EmitSequenceExpression(BoundSequence sequence, bool used, bool sense = true) { DefineLocals(sequence); EmitSideEffects(sequence); @@ -844,7 +884,14 @@ private void EmitSequenceExpression(BoundSequence sequence, bool used) Debug.Assert(sequence.Value.Kind != BoundKind.TypeExpression || !used); if (sequence.Value.Kind != BoundKind.TypeExpression) { - EmitExpression(sequence.Value, used); + if (used && sequence.Type.SpecialType == SpecialType.System_Boolean) + { + EmitCondExpr(sequence.Value, sense: sense); + } + else + { + EmitExpression(sequence.Value, used: used); + } } // sequence is used as a value, can release all locals diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs index 80ca057d83076..ee3f158d49eca 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs @@ -484,14 +484,25 @@ private void EmitCondExpr(BoundExpression condition, bool sense) return; } - if (condition.Kind == BoundKind.BinaryOperator) + switch (condition.Kind) { - var binOp = (BoundBinaryOperator)condition; - if (IsConditional(binOp.OperatorKind)) - { + case BoundKind.BinaryOperator: + var binOp = (BoundBinaryOperator)condition; + if (!IsConditional(binOp.OperatorKind)) + { + break; + } + EmitBinaryCondOperator(binOp, sense); return; - } + + case BoundKind.Sequence: + EmitSequenceExpression((BoundSequence)condition, used: true, sense); + return; + + case BoundKind.LoweredIsPatternExpression: + EmitLoweredIsPatternExpression((BoundLoweredIsPatternExpression)condition, used: true, sense); + return; } EmitExpression(condition, true); diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs index c336e8c170a1c..284eee1e0b5d1 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs @@ -24,6 +24,10 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeGen { internal partial class CodeGenerator { +#if DEBUG + private int _expectedStackDepth = 0; +#endif + private void EmitStatement(BoundStatement statement) { switch (statement.Kind) @@ -108,7 +112,7 @@ private void EmitStatement(BoundStatement statement) #if DEBUG if (_stackLocals == null || _stackLocals.Count == 0) { - _builder.AssertStackEmpty(); + _builder.AssertStackDepth(_expectedStackDepth); } #endif @@ -572,6 +576,28 @@ top.condition is BoundBinaryOperator binary && } return; + case BoundKind.LoweredIsPatternExpression: + { + var loweredIs = (BoundLoweredIsPatternExpression)condition; + dest ??= new object(); + + EmitSideEffects(loweredIs.Statements); + + if (sense) + { + _builder.MarkLabel(loweredIs.WhenTrueLabel); + _builder.EmitBranch(ILOpCode.Br, dest); + _builder.MarkLabel(loweredIs.WhenFalseLabel); + } + else + { + _builder.MarkLabel(loweredIs.WhenFalseLabel); + _builder.EmitBranch(ILOpCode.Br, dest); + _builder.MarkLabel(loweredIs.WhenTrueLabel); + } + } + return; + case BoundKind.UnaryOperator: var unOp = (BoundUnaryOperator)condition; if (unOp.OperatorKind == UnaryOperatorKind.BoolLogicalNegation) diff --git a/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs b/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs index 99e004078d094..16cd977a393c3 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs @@ -415,6 +415,10 @@ internal sealed class StackOptimizerPass1 : BoundTreeRewriter private int _recursionDepth; +#if DEBUG + private int _expectedStackDepth = 0; +#endif + private StackOptimizerPass1(Dictionary locals, ArrayBuilder> evalStack, bool debugFriendly) @@ -565,10 +569,27 @@ private void PopEvalStack() public BoundNode VisitStatement(BoundNode node) { - Debug.Assert(node == null || EvalStackIsEmpty()); +#if DEBUG + Debug.Assert(node == null || StackDepth() == _expectedStackDepth); +#endif return VisitSideEffect(node); } + public ImmutableArray VisitSideEffects(ImmutableArray statements) + { +#if DEBUG + int prevStack = _expectedStackDepth; + int origStack = StackDepth(); + _expectedStackDepth = origStack; +#endif + var result = this.VisitList(statements); +#if DEBUG + Debug.Assert(_expectedStackDepth == origStack); + _expectedStackDepth = prevStack; +#endif + return result; + } + public BoundNode VisitSideEffect(BoundNode node) { var origStack = StackDepth(); @@ -1416,8 +1437,6 @@ public override BoundNode VisitConditionalGoto(BoundConditionalGoto node) public override BoundNode VisitSwitchDispatch(BoundSwitchDispatch node) { - Debug.Assert(EvalStackIsEmpty()); - // switch dispatch needs a byval local or a parameter as a key. // if this is already a fitting local, let's keep it that way BoundExpression boundExpression = node.Expression; @@ -1447,6 +1466,14 @@ public override BoundNode VisitSwitchDispatch(BoundSwitchDispatch node) return node.Update(boundExpression, node.Cases, node.DefaultLabel, node.LengthBasedStringSwitchDataOpt); } + public override BoundNode VisitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node) + { + var statements = VisitSideEffects(node.Statements); + RecordBranch(node.WhenTrueLabel); + RecordBranch(node.WhenFalseLabel); + return node.Update(statements, node.WhenTrueLabel, node.WhenFalseLabel, VisitType(node.Type)); + } + public override BoundNode VisitConditionalOperator(BoundConditionalOperator node) { var origStack = StackDepth(); diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index f7a16cc4bbae0..f92de3ecb0b2f 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -3039,6 +3039,12 @@ public override BoundNode VisitConditionalReceiver(BoundConditionalReceiver node return null; } + public override BoundNode VisitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node) + { + VisitStatements(node.Statements); + return null; + } + public override BoundNode VisitComplexConditionalReceiver(BoundComplexConditionalReceiver node) { var savedState = this.State.Clone(); diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs index 34f286a111b2d..a7a963c4da834 100644 --- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs @@ -226,6 +226,7 @@ internal enum BoundKind : byte InterpolatedStringArgumentPlaceholder, StringInsert, IsPatternExpression, + LoweredIsPatternExpression, ConstantPattern, DiscardPattern, DeclarationPattern, @@ -7834,7 +7835,7 @@ public BoundStringInsert Update(BoundExpression value, BoundExpression? alignmen internal sealed partial class BoundIsPatternExpression : BoundExpression { - public BoundIsPatternExpression(SyntaxNode syntax, BoundExpression expression, BoundPattern pattern, bool isNegated, BoundDecisionDag reachabilityDecisionDag, LabelSymbol whenTrueLabel, LabelSymbol whenFalseLabel, TypeSymbol? type, bool hasErrors = false) + public BoundIsPatternExpression(SyntaxNode syntax, BoundExpression expression, BoundPattern pattern, bool isNegated, BoundDecisionDag reachabilityDecisionDag, LabelSymbol whenTrueLabel, LabelSymbol whenFalseLabel, TypeSymbol type, bool hasErrors = false) : base(BoundKind.IsPatternExpression, syntax, type, hasErrors || expression.HasErrors() || pattern.HasErrors() || reachabilityDecisionDag.HasErrors()) { @@ -7843,6 +7844,7 @@ public BoundIsPatternExpression(SyntaxNode syntax, BoundExpression expression, B RoslynDebug.Assert(reachabilityDecisionDag is object, "Field 'reachabilityDecisionDag' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(whenTrueLabel is object, "Field 'whenTrueLabel' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); RoslynDebug.Assert(whenFalseLabel is object, "Field 'whenFalseLabel' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); + RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); this.Expression = expression; this.Pattern = pattern; @@ -7852,6 +7854,7 @@ public BoundIsPatternExpression(SyntaxNode syntax, BoundExpression expression, B this.WhenFalseLabel = whenFalseLabel; } + public new TypeSymbol Type => base.Type!; public BoundExpression Expression { get; } public BoundPattern Pattern { get; } public bool IsNegated { get; } @@ -7862,7 +7865,7 @@ public BoundIsPatternExpression(SyntaxNode syntax, BoundExpression expression, B [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitIsPatternExpression(this); - public BoundIsPatternExpression Update(BoundExpression expression, BoundPattern pattern, bool isNegated, BoundDecisionDag reachabilityDecisionDag, LabelSymbol whenTrueLabel, LabelSymbol whenFalseLabel, TypeSymbol? type) + public BoundIsPatternExpression Update(BoundExpression expression, BoundPattern pattern, bool isNegated, BoundDecisionDag reachabilityDecisionDag, LabelSymbol whenTrueLabel, LabelSymbol whenFalseLabel, TypeSymbol type) { if (expression != this.Expression || pattern != this.Pattern || isNegated != this.IsNegated || reachabilityDecisionDag != this.ReachabilityDecisionDag || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(whenTrueLabel, this.WhenTrueLabel) || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(whenFalseLabel, this.WhenFalseLabel) || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { @@ -7874,6 +7877,46 @@ public BoundIsPatternExpression Update(BoundExpression expression, BoundPattern } } + internal sealed partial class BoundLoweredIsPatternExpression : BoundExpression + { + public BoundLoweredIsPatternExpression(SyntaxNode syntax, ImmutableArray statements, LabelSymbol whenTrueLabel, LabelSymbol whenFalseLabel, TypeSymbol type, bool hasErrors = false) + : base(BoundKind.LoweredIsPatternExpression, syntax, type, hasErrors || statements.HasErrors()) + { + + RoslynDebug.Assert(!statements.IsDefault, "Field 'statements' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); + RoslynDebug.Assert(whenTrueLabel is object, "Field 'whenTrueLabel' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); + RoslynDebug.Assert(whenFalseLabel is object, "Field 'whenFalseLabel' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); + RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)"); + + this.Statements = statements; + this.WhenTrueLabel = whenTrueLabel; + this.WhenFalseLabel = whenFalseLabel; + Validate(); + } + + [Conditional("DEBUG")] + private partial void Validate(); + + public new TypeSymbol Type => base.Type!; + public ImmutableArray Statements { get; } + public LabelSymbol WhenTrueLabel { get; } + public LabelSymbol WhenFalseLabel { get; } + + [DebuggerStepThrough] + public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitLoweredIsPatternExpression(this); + + public BoundLoweredIsPatternExpression Update(ImmutableArray statements, LabelSymbol whenTrueLabel, LabelSymbol whenFalseLabel, TypeSymbol type) + { + if (statements != this.Statements || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(whenTrueLabel, this.WhenTrueLabel) || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(whenFalseLabel, this.WhenFalseLabel) || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + { + var result = new BoundLoweredIsPatternExpression(this.Syntax, statements, whenTrueLabel, whenFalseLabel, type, this.HasErrors); + result.CopyAttributes(this); + return result; + } + return this; + } + } + internal abstract partial class BoundPattern : BoundNode { protected BoundPattern(BoundKind kind, SyntaxNode syntax, TypeSymbol inputType, TypeSymbol narrowedType, bool hasErrors) @@ -9131,6 +9174,8 @@ internal R VisitInternal(BoundNode node, A arg) return VisitStringInsert((BoundStringInsert)node, arg); case BoundKind.IsPatternExpression: return VisitIsPatternExpression((BoundIsPatternExpression)node, arg); + case BoundKind.LoweredIsPatternExpression: + return VisitLoweredIsPatternExpression((BoundLoweredIsPatternExpression)node, arg); case BoundKind.ConstantPattern: return VisitConstantPattern((BoundConstantPattern)node, arg); case BoundKind.DiscardPattern: @@ -9391,6 +9436,7 @@ internal abstract partial class BoundTreeVisitor public virtual R VisitInterpolatedStringArgumentPlaceholder(BoundInterpolatedStringArgumentPlaceholder node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitStringInsert(BoundStringInsert node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitIsPatternExpression(BoundIsPatternExpression node, A arg) => this.DefaultVisit(node, arg); + public virtual R VisitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitConstantPattern(BoundConstantPattern node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitDiscardPattern(BoundDiscardPattern node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitDeclarationPattern(BoundDeclarationPattern node, A arg) => this.DefaultVisit(node, arg); @@ -9624,6 +9670,7 @@ internal abstract partial class BoundTreeVisitor public virtual BoundNode? VisitInterpolatedStringArgumentPlaceholder(BoundInterpolatedStringArgumentPlaceholder node) => this.DefaultVisit(node); public virtual BoundNode? VisitStringInsert(BoundStringInsert node) => this.DefaultVisit(node); public virtual BoundNode? VisitIsPatternExpression(BoundIsPatternExpression node) => this.DefaultVisit(node); + public virtual BoundNode? VisitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node) => this.DefaultVisit(node); public virtual BoundNode? VisitConstantPattern(BoundConstantPattern node) => this.DefaultVisit(node); public virtual BoundNode? VisitDiscardPattern(BoundDiscardPattern node) => this.DefaultVisit(node); public virtual BoundNode? VisitDeclarationPattern(BoundDeclarationPattern node) => this.DefaultVisit(node); @@ -10549,6 +10596,11 @@ internal abstract partial class BoundTreeWalker : BoundTreeVisitor this.Visit(node.Pattern); return null; } + public override BoundNode? VisitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node) + { + this.VisitList(node.Statements); + return null; + } public override BoundNode? VisitConstantPattern(BoundConstantPattern node) { this.Visit(node.Value); @@ -11904,6 +11956,12 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor TypeSymbol? type = this.VisitType(node.Type); return node.Update(expression, pattern, node.IsNegated, reachabilityDecisionDag, node.WhenTrueLabel, node.WhenFalseLabel, type); } + public override BoundNode? VisitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node) + { + ImmutableArray statements = this.VisitList(node.Statements); + TypeSymbol? type = this.VisitType(node.Type); + return node.Update(statements, node.WhenTrueLabel, node.WhenFalseLabel, type); + } public override BoundNode? VisitConstantPattern(BoundConstantPattern node) { BoundExpression value = (BoundExpression)this.Visit(node.Value); @@ -14517,7 +14575,7 @@ public NullabilityRewriter(ImmutableDictionary statements = this.VisitList(node.Statements); + BoundLoweredIsPatternExpression updatedNode; + + if (_updatedNullabilities.TryGetValue(node, out (NullabilityInfo Info, TypeSymbol? Type) infoAndType)) + { + updatedNode = node.Update(statements, node.WhenTrueLabel, node.WhenFalseLabel, infoAndType.Type!); + updatedNode.TopLevelNullability = infoAndType.Info; + } + else + { + updatedNode = node.Update(statements, node.WhenTrueLabel, node.WhenFalseLabel, node.Type); + } + return updatedNode; + } + public override BoundNode? VisitConstantPattern(BoundConstantPattern node) { TypeSymbol inputType = GetUpdatedSymbol(node, node.InputType); @@ -16698,6 +16773,16 @@ private BoundTreeDumperNodeProducer() new TreeDumperNode("hasErrors", node.HasErrors, null) } ); + public override TreeDumperNode VisitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node, object? arg) => new TreeDumperNode("loweredIsPatternExpression", null, new TreeDumperNode[] + { + new TreeDumperNode("statements", null, from x in node.Statements select Visit(x, null)), + new TreeDumperNode("whenTrueLabel", node.WhenTrueLabel, null), + new TreeDumperNode("whenFalseLabel", node.WhenFalseLabel, null), + new TreeDumperNode("type", node.Type, null), + new TreeDumperNode("isSuppressed", node.IsSuppressed, null), + new TreeDumperNode("hasErrors", node.HasErrors, null) + } + ); public override TreeDumperNode VisitConstantPattern(BoundConstantPattern node, object? arg) => new TreeDumperNode("constantPattern", null, new TreeDumperNode[] { new TreeDumperNode("value", null, new TreeDumperNode[] { Visit(node.Value, null) }), diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs index 753a242ab44fc..00cbbd7362677 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs @@ -108,29 +108,32 @@ public IsPatternExpressionGeneralLocalRewriter( internal BoundExpression LowerGeneralIsPattern(BoundIsPatternExpression node, BoundDecisionDag decisionDag) { + Debug.Assert(node.Type is { SpecialType: SpecialType.System_Boolean }); + _factory.Syntax = node.Syntax; - var resultBuilder = ArrayBuilder.GetInstance(); var inputExpression = _localRewriter.VisitExpression(node.Expression); - decisionDag = ShareTempsIfPossibleAndEvaluateInput(decisionDag, inputExpression, resultBuilder, out _); + var sideEffectsBuilder = ArrayBuilder.GetInstance(); + + // The optimization of sharing pattern-matching temps with user variables can always apply to + // an is-pattern expression because there is no when clause that could possibly intervene during + // the execution of the pattern-matching automaton and change one of those variables. + decisionDag = ShareTempsAndEvaluateInput(inputExpression, decisionDag, sideEffectsBuilder.Add, out _); // lower the decision dag. ImmutableArray loweredDag = LowerDecisionDagCore(decisionDag); - resultBuilder.Add(_factory.Block(loweredDag)); - Debug.Assert(node.Type is { SpecialType: SpecialType.System_Boolean }); - LocalSymbol resultTemp = _factory.SynthesizedLocal(node.Type, node.Syntax, kind: SynthesizedLocalKind.LoweringTemp); - LabelSymbol afterIsPatternExpression = _factory.GenerateLabel("afterIsPatternExpression"); - LabelSymbol trueLabel = node.WhenTrueLabel; - LabelSymbol falseLabel = node.WhenFalseLabel; - if (_statements.Count != 0) - resultBuilder.Add(_factory.Block(_statements.ToArray())); - resultBuilder.Add(_factory.Label(trueLabel)); - resultBuilder.Add(_factory.Assignment(_factory.Local(resultTemp), _factory.Literal(true))); - resultBuilder.Add(_factory.Goto(afterIsPatternExpression)); - resultBuilder.Add(_factory.Label(falseLabel)); - resultBuilder.Add(_factory.Assignment(_factory.Local(resultTemp), _factory.Literal(false))); - resultBuilder.Add(_factory.Label(afterIsPatternExpression)); - _localRewriter._needsSpilling = true; - return _factory.SpillSequence(_tempAllocator.AllTemps().Add(resultTemp), resultBuilder.ToImmutableAndFree(), _factory.Local(resultTemp)); + var resultBuilder = ArrayBuilder.GetInstance(loweredDag.Length + _statements.Count); + resultBuilder.AddRange(loweredDag); + resultBuilder.AddRange(_statements); + return _factory.Sequence( + _tempAllocator.AllTemps(), + sideEffectsBuilder.ToImmutableAndFree(), + new BoundLoweredIsPatternExpression( + node.Syntax, + // Note: it is not expected for this node to trigger spilling + resultBuilder.ToImmutableAndFree(), + node.WhenTrueLabel, + node.WhenFalseLabel, + node.Type)); } } diff --git a/src/Compilers/CSharp/Portable/Lowering/SpillSequenceSpiller.cs b/src/Compilers/CSharp/Portable/Lowering/SpillSequenceSpiller.cs index 9bfb3a387e2f3..909e135ec5126 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SpillSequenceSpiller.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SpillSequenceSpiller.cs @@ -716,6 +716,16 @@ public override BoundNode DefaultVisit(BoundNode node) #region Expression Visitors +#if DEBUG + public override BoundNode VisitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node) + { + // Ensure this node won't trigger spilling + var result = base.VisitLoweredIsPatternExpression(node); + Debug.Assert(result == node); + return result; + } +#endif + public override BoundNode VisitAwaitExpression(BoundAwaitExpression node) { // An await expression has already been wrapped in a BoundSpillSequence if not at the top level, so diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/PatternTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/PatternTests.cs index 86e1ed704dbc7..a6085f5fdb588 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/PatternTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/PatternTests.cs @@ -3003,7 +3003,7 @@ public class NotPossibleException : System.Exception { } var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput); compVerifier.VerifyIL("ConsoleApp1.TestHelper.IsValueTypeT(ConsoleApp1.Result)", @"{ - // Code size 31 (0x1f) + // Code size 28 (0x1c) .maxstack 2 .locals init (T V_0, //v bool V_1) @@ -3014,15 +3014,13 @@ .locals init (T V_0, //v IL_0008: ldloc.0 IL_0009: box ""T"" IL_000e: ldnull - IL_000f: cgt.un - IL_0011: ldc.i4.0 - IL_0012: ceq - IL_0014: stloc.1 - IL_0015: ldloc.1 - IL_0016: brfalse.s IL_001e - IL_0018: newobj ""ConsoleApp1.NotPossibleException..ctor()"" - IL_001d: throw - IL_001e: ret + IL_000f: ceq + IL_0011: stloc.1 + IL_0012: ldloc.1 + IL_0013: brfalse.s IL_001b + IL_0015: newobj ""ConsoleApp1.NotPossibleException..ctor()"" + IL_001a: throw + IL_001b: ret }"); } @@ -5510,23 +5508,19 @@ public static void Main() var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput); compVerifier.VerifyIL("C.M1", """ { - // Code size 26 (0x1a) + // Code size 23 (0x17) .maxstack 1 - .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: isinst "int" IL_0006: brtrue.s IL_0012 IL_0008: ldarg.0 IL_0009: isinst "long" IL_000e: brtrue.s IL_0012 - IL_0010: br.s IL_0016 + IL_0010: br.s IL_0015 IL_0012: ldc.i4.1 - IL_0013: stloc.0 - IL_0014: br.s IL_0018 - IL_0016: ldc.i4.0 - IL_0017: stloc.0 - IL_0018: ldloc.0 - IL_0019: ret + IL_0013: br.s IL_0016 + IL_0015: ldc.i4.0 + IL_0016: ret } """); compVerifier.VerifyIL("C.M2", """ @@ -5551,22 +5545,18 @@ .maxstack 2 compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput); compVerifier.VerifyIL("C.M1", """ { - // Code size 24 (0x18) + // Code size 20 (0x14) .maxstack 1 - .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: isinst "int" IL_0006: brtrue.s IL_0010 IL_0008: ldarg.0 IL_0009: isinst "long" - IL_000e: brfalse.s IL_0014 + IL_000e: brfalse.s IL_0012 IL_0010: ldc.i4.1 - IL_0011: stloc.0 - IL_0012: br.s IL_0016 - IL_0014: ldc.i4.0 - IL_0015: stloc.0 - IL_0016: ldloc.0 - IL_0017: ret + IL_0011: ret + IL_0012: ldc.i4.0 + IL_0013: ret } """); compVerifier.VerifyIL("C.M2", @" @@ -5610,27 +5600,20 @@ public static void Main() var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput); compVerifier.VerifyIL("C.M1", """ { - // Code size 40 (0x28) + // Code size 33 (0x21) .maxstack 1 - .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: isinst "int" IL_0006: brtrue.s IL_0012 IL_0008: ldarg.0 IL_0009: isinst "long" IL_000e: brtrue.s IL_0012 - IL_0010: br.s IL_0016 - IL_0012: ldc.i4.1 - IL_0013: stloc.0 - IL_0014: br.s IL_0018 - IL_0016: ldc.i4.0 - IL_0017: stloc.0 - IL_0018: ldloc.0 - IL_0019: brtrue.s IL_0022 - IL_001b: ldstr "False" - IL_0020: br.s IL_0027 - IL_0022: ldstr "True" - IL_0027: ret + IL_0010: br.s IL_0014 + IL_0012: br.s IL_001b + IL_0014: ldstr "False" + IL_0019: br.s IL_0020 + IL_001b: ldstr "True" + IL_0020: ret } """); compVerifier.VerifyIL("C.M2", """ @@ -5655,26 +5638,18 @@ .maxstack 1 compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput); compVerifier.VerifyIL("C.M1", """ { - // Code size 37 (0x25) + // Code size 28 (0x1c) .maxstack 1 - .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: isinst "int" - IL_0006: brtrue.s IL_0010 + IL_0006: brtrue.s IL_0016 IL_0008: ldarg.0 IL_0009: isinst "long" - IL_000e: brfalse.s IL_0014 - IL_0010: ldc.i4.1 - IL_0011: stloc.0 - IL_0012: br.s IL_0016 - IL_0014: ldc.i4.0 - IL_0015: stloc.0 - IL_0016: ldloc.0 - IL_0017: brtrue.s IL_001f - IL_0019: ldstr "False" - IL_001e: ret - IL_001f: ldstr "True" - IL_0024: ret + IL_000e: brtrue.s IL_0016 + IL_0010: ldstr "False" + IL_0015: ret + IL_0016: ldstr "True" + IL_001b: ret } """); compVerifier.VerifyIL("C.M2", @" @@ -5718,13 +5693,12 @@ public static void Main() var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput); compVerifier.VerifyIL("C.M1", @" { - // Code size 47 (0x2f) + // Code size 44 (0x2c) .maxstack 2 - .locals init (char V_0, - bool V_1) + .locals init (char V_0) IL_0000: ldarg.0 IL_0001: isinst ""char"" - IL_0006: brfalse.s IL_002b + IL_0006: brfalse.s IL_002a IL_0008: ldarg.0 IL_0009: unbox.any ""char"" IL_000e: stloc.0 @@ -5734,21 +5708,18 @@ .locals init (char V_0, IL_0014: ldloc.0 IL_0015: ldc.i4.s 122 IL_0017: ble.s IL_0027 - IL_0019: br.s IL_002b + IL_0019: br.s IL_002a IL_001b: ldloc.0 IL_001c: ldc.i4.s 65 - IL_001e: blt.s IL_002b + IL_001e: blt.s IL_002a IL_0020: ldloc.0 IL_0021: ldc.i4.s 90 IL_0023: ble.s IL_0027 - IL_0025: br.s IL_002b + IL_0025: br.s IL_002a IL_0027: ldc.i4.1 - IL_0028: stloc.1 - IL_0029: br.s IL_002d - IL_002b: ldc.i4.0 - IL_002c: stloc.1 - IL_002d: ldloc.1 - IL_002e: ret + IL_0028: br.s IL_002b + IL_002a: ldc.i4.0 + IL_002b: ret } "); compVerifier.VerifyIL("C.M2", @" @@ -5791,13 +5762,12 @@ .locals init (char V_0) //c compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput); compVerifier.VerifyIL("C.M1", @" { - // Code size 45 (0x2d) + // Code size 41 (0x29) .maxstack 2 - .locals init (char V_0, - bool V_1) + .locals init (char V_0) IL_0000: ldarg.0 IL_0001: isinst ""char"" - IL_0006: brfalse.s IL_0029 + IL_0006: brfalse.s IL_0027 IL_0008: ldarg.0 IL_0009: unbox.any ""char"" IL_000e: stloc.0 @@ -5807,20 +5777,17 @@ .locals init (char V_0, IL_0014: ldloc.0 IL_0015: ldc.i4.s 122 IL_0017: ble.s IL_0025 - IL_0019: br.s IL_0029 + IL_0019: br.s IL_0027 IL_001b: ldloc.0 IL_001c: ldc.i4.s 65 - IL_001e: blt.s IL_0029 + IL_001e: blt.s IL_0027 IL_0020: ldloc.0 IL_0021: ldc.i4.s 90 - IL_0023: bgt.s IL_0029 + IL_0023: bgt.s IL_0027 IL_0025: ldc.i4.1 - IL_0026: stloc.1 - IL_0027: br.s IL_002b - IL_0029: ldc.i4.0 - IL_002a: stloc.1 - IL_002b: ldloc.1 - IL_002c: ret + IL_0026: ret + IL_0027: ldc.i4.0 + IL_0028: ret } "); compVerifier.VerifyIL("C.M2", @" @@ -5882,34 +5849,27 @@ public static void Main() var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput); compVerifier.VerifyIL("C.M1", @" { - // Code size 38 (0x26) + // Code size 31 (0x1f) .maxstack 2 - .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: ldc.i4.s 97 IL_0003: blt.s IL_000c IL_0005: ldarg.0 IL_0006: ldc.i4.s 122 IL_0008: ble.s IL_0018 - IL_000a: br.s IL_001c + IL_000a: br.s IL_001a IL_000c: ldarg.0 IL_000d: ldc.i4.s 65 - IL_000f: blt.s IL_001c + IL_000f: blt.s IL_001a IL_0011: ldarg.0 IL_0012: ldc.i4.s 90 IL_0014: ble.s IL_0018 - IL_0016: br.s IL_001c - IL_0018: ldc.i4.1 - IL_0019: stloc.0 - IL_001a: br.s IL_001e - IL_001c: ldc.i4.0 - IL_001d: stloc.0 - IL_001e: ldloc.0 - IL_001f: brtrue.s IL_0024 - IL_0021: ldc.i4.0 - IL_0022: br.s IL_0025 - IL_0024: ldc.i4.1 - IL_0025: ret + IL_0016: br.s IL_001a + IL_0018: br.s IL_001d + IL_001a: ldc.i4.0 + IL_001b: br.s IL_001e + IL_001d: ldc.i4.1 + IL_001e: ret } "); compVerifier.VerifyIL("C.M2", @" @@ -5940,31 +5900,27 @@ .maxstack 2 compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput); compVerifier.VerifyIL("C.M1", @" { - // Code size 33 (0x21) + // Code size 30 (0x1e) .maxstack 2 - .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: ldc.i4.s 97 IL_0003: blt.s IL_000c IL_0005: ldarg.0 IL_0006: ldc.i4.s 122 IL_0008: ble.s IL_0016 - IL_000a: br.s IL_001a + IL_000a: br.s IL_0019 IL_000c: ldarg.0 IL_000d: ldc.i4.s 65 - IL_000f: blt.s IL_001a + IL_000f: blt.s IL_0019 IL_0011: ldarg.0 IL_0012: ldc.i4.s 90 - IL_0014: bgt.s IL_001a + IL_0014: bgt.s IL_0019 IL_0016: ldc.i4.1 - IL_0017: stloc.0 - IL_0018: br.s IL_001c + IL_0017: br.s IL_001a + IL_0019: ldc.i4.0 IL_001a: ldc.i4.0 - IL_001b: stloc.0 - IL_001c: ldloc.0 - IL_001d: ldc.i4.0 - IL_001e: cgt.un - IL_0020: ret + IL_001b: cgt.un + IL_001d: ret } "); compVerifier.VerifyIL("C.M2", @" @@ -6026,11 +5982,10 @@ public static void Main() var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput); compVerifier.VerifyIL("C.M1", @" { - // Code size 46 (0x2e) + // Code size 43 (0x2b) .maxstack 2 .locals init (bool V_0, - bool V_1, - int V_2) + int V_1) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldc.i4.s 97 @@ -6038,31 +5993,28 @@ .locals init (bool V_0, IL_0006: ldarg.0 IL_0007: ldc.i4.s 122 IL_0009: ble.s IL_0019 - IL_000b: br.s IL_001d + IL_000b: br.s IL_001c IL_000d: ldarg.0 IL_000e: ldc.i4.s 65 - IL_0010: blt.s IL_001d + IL_0010: blt.s IL_001c IL_0012: ldarg.0 IL_0013: ldc.i4.s 90 IL_0015: ble.s IL_0019 - IL_0017: br.s IL_001d + IL_0017: br.s IL_001c IL_0019: ldc.i4.1 - IL_001a: stloc.0 - IL_001b: br.s IL_001f - IL_001d: ldc.i4.0 - IL_001e: stloc.0 - IL_001f: ldloc.0 - IL_0020: stloc.1 - IL_0021: ldloc.1 - IL_0022: brfalse.s IL_0028 - IL_0024: ldc.i4.1 - IL_0025: stloc.2 - IL_0026: br.s IL_002c - IL_0028: ldc.i4.0 - IL_0029: stloc.2 - IL_002a: br.s IL_002c - IL_002c: ldloc.2 - IL_002d: ret + IL_001a: br.s IL_001d + IL_001c: ldc.i4.0 + IL_001d: stloc.0 + IL_001e: ldloc.0 + IL_001f: brfalse.s IL_0025 + IL_0021: ldc.i4.1 + IL_0022: stloc.1 + IL_0023: br.s IL_0029 + IL_0025: ldc.i4.0 + IL_0026: stloc.1 + IL_0027: br.s IL_0029 + IL_0029: ldloc.1 + IL_002a: ret } "); compVerifier.VerifyIL("C.M2", @" @@ -6109,33 +6061,25 @@ .locals init (bool V_0, compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput); compVerifier.VerifyIL("C.M1", @" { - // Code size 35 (0x23) + // Code size 26 (0x1a) .maxstack 2 - .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: ldc.i4.s 97 IL_0003: blt.s IL_000c IL_0005: ldarg.0 IL_0006: ldc.i4.s 122 IL_0008: ble.s IL_0016 - IL_000a: br.s IL_001a + IL_000a: br.s IL_0018 IL_000c: ldarg.0 IL_000d: ldc.i4.s 65 - IL_000f: blt.s IL_001a + IL_000f: blt.s IL_0018 IL_0011: ldarg.0 IL_0012: ldc.i4.s 90 - IL_0014: bgt.s IL_001a + IL_0014: bgt.s IL_0018 IL_0016: ldc.i4.1 - IL_0017: stloc.0 - IL_0018: br.s IL_001c - IL_001a: ldc.i4.0 - IL_001b: stloc.0 - IL_001c: ldloc.0 - IL_001d: brfalse.s IL_0021 - IL_001f: ldc.i4.1 - IL_0020: ret - IL_0021: ldc.i4.0 - IL_0022: ret + IL_0017: ret + IL_0018: ldc.i4.0 + IL_0019: ret } "); compVerifier.VerifyIL("C.M2", @" diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs index 319a46fefc276..1bf9c823ed51a 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/SwitchTests.cs @@ -7125,7 +7125,7 @@ .maxstack 2 IL_0760: ret }"; compVerifier.VerifyIL("ConsoleApplication24.Program.IsWarning", codeForSwitchStatement); - compVerifier.VerifyIL("ConsoleApplication24.Program.IsWarning_IsExpression", codeForExpression); + compVerifier.VerifyIL("ConsoleApplication24.Program.IsWarning_IsExpression", codeForSwitchStatement); compVerifier.VerifyIL("ConsoleApplication24.Program.IsWarning_SwitchExpression", codeForExpression); } diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests.cs index ac537827d6664..8102fe7157794 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests.cs @@ -8354,64 +8354,63 @@ static void Test(ReadOnlySpan chars) not: True") .VerifyIL("C.Test", """ { - // Code size 167 (0xa7) + // Code size 166 (0xa6) .maxstack 3 .locals init (bool V_0) IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldstr "string 1" - IL_0007: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" - IL_000c: call "bool System.MemoryExtensions.SequenceEqual(System.ReadOnlySpan, System.ReadOnlySpan)" - IL_0011: brtrue.s IL_0027 - IL_0013: ldarg.0 - IL_0014: ldstr "string 2" - IL_0019: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" - IL_001e: call "bool System.MemoryExtensions.SequenceEqual(System.ReadOnlySpan, System.ReadOnlySpan)" - IL_0023: brtrue.s IL_0027 - IL_0025: br.s IL_002b - IL_0027: ldc.i4.1 - IL_0028: stloc.0 - IL_0029: br.s IL_002d - IL_002b: ldc.i4.0 - IL_002c: stloc.0 - IL_002d: ldstr "or: " - IL_0032: ldloca.s V_0 - IL_0034: call "string bool.ToString()" - IL_0039: call "string string.Concat(string, string)" - IL_003e: call "void System.Console.WriteLine(string)" - IL_0043: nop - IL_0044: ldstr "and: " - IL_0049: ldarg.0 - IL_004a: ldstr "string 1" - IL_004f: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" - IL_0054: call "bool System.MemoryExtensions.SequenceEqual(System.ReadOnlySpan, System.ReadOnlySpan)" - IL_0059: brfalse.s IL_0067 - IL_005b: ldarga.s V_0 - IL_005d: call "int System.ReadOnlySpan.Length.get" - IL_0062: ldc.i4.7 - IL_0063: ceq - IL_0065: br.s IL_0068 - IL_0067: ldc.i4.0 - IL_0068: stloc.0 - IL_0069: ldloca.s V_0 - IL_006b: call "string bool.ToString()" - IL_0070: call "string string.Concat(string, string)" - IL_0075: call "void System.Console.WriteLine(string)" - IL_007a: nop - IL_007b: ldstr "not: " - IL_0080: ldarg.0 - IL_0081: ldstr "string 1" - IL_0086: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" - IL_008b: call "bool System.MemoryExtensions.SequenceEqual(System.ReadOnlySpan, System.ReadOnlySpan)" - IL_0090: ldc.i4.0 - IL_0091: ceq - IL_0093: stloc.0 - IL_0094: ldloca.s V_0 - IL_0096: call "string bool.ToString()" - IL_009b: call "string string.Concat(string, string)" - IL_00a0: call "void System.Console.WriteLine(string)" - IL_00a5: nop - IL_00a6: ret + IL_0001: ldstr "or: " + IL_0006: ldarg.0 + IL_0007: ldstr "string 1" + IL_000c: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" + IL_0011: call "bool System.MemoryExtensions.SequenceEqual(System.ReadOnlySpan, System.ReadOnlySpan)" + IL_0016: brtrue.s IL_002c + IL_0018: ldarg.0 + IL_0019: ldstr "string 2" + IL_001e: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" + IL_0023: call "bool System.MemoryExtensions.SequenceEqual(System.ReadOnlySpan, System.ReadOnlySpan)" + IL_0028: brtrue.s IL_002c + IL_002a: br.s IL_002f + IL_002c: ldc.i4.1 + IL_002d: br.s IL_0030 + IL_002f: ldc.i4.0 + IL_0030: stloc.0 + IL_0031: ldloca.s V_0 + IL_0033: call "string bool.ToString()" + IL_0038: call "string string.Concat(string, string)" + IL_003d: call "void System.Console.WriteLine(string)" + IL_0042: nop + IL_0043: ldstr "and: " + IL_0048: ldarg.0 + IL_0049: ldstr "string 1" + IL_004e: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" + IL_0053: call "bool System.MemoryExtensions.SequenceEqual(System.ReadOnlySpan, System.ReadOnlySpan)" + IL_0058: brfalse.s IL_0066 + IL_005a: ldarga.s V_0 + IL_005c: call "int System.ReadOnlySpan.Length.get" + IL_0061: ldc.i4.7 + IL_0062: ceq + IL_0064: br.s IL_0067 + IL_0066: ldc.i4.0 + IL_0067: stloc.0 + IL_0068: ldloca.s V_0 + IL_006a: call "string bool.ToString()" + IL_006f: call "string string.Concat(string, string)" + IL_0074: call "void System.Console.WriteLine(string)" + IL_0079: nop + IL_007a: ldstr "not: " + IL_007f: ldarg.0 + IL_0080: ldstr "string 1" + IL_0085: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" + IL_008a: call "bool System.MemoryExtensions.SequenceEqual(System.ReadOnlySpan, System.ReadOnlySpan)" + IL_008f: ldc.i4.0 + IL_0090: ceq + IL_0092: stloc.0 + IL_0093: ldloca.s V_0 + IL_0095: call "string bool.ToString()" + IL_009a: call "string string.Concat(string, string)" + IL_009f: call "void System.Console.WriteLine(string)" + IL_00a4: nop + IL_00a5: ret } """); } @@ -8920,14 +8919,14 @@ .locals init (bool V_0) IL_0066: call ""string bool.ToString()"" IL_006b: call ""string string.Concat(string, string)"" IL_0070: call ""void System.Console.WriteLine(string)"" - IL_0075: ldarg.0 - IL_0076: ldstr """" - IL_007b: call ""System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)"" - IL_0080: call ""bool System.MemoryExtensions.SequenceEqual(System.ReadOnlySpan, System.ReadOnlySpan)"" - IL_0085: pop - IL_0086: ldc.i4.1 - IL_0087: stloc.0 - IL_0088: ldstr ""4."" + IL_0075: ldstr ""4."" + IL_007a: ldarg.0 + IL_007b: ldstr """" + IL_0080: call ""System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)"" + IL_0085: call ""bool System.MemoryExtensions.SequenceEqual(System.ReadOnlySpan, System.ReadOnlySpan)"" + IL_008a: pop + IL_008b: ldc.i4.1 + IL_008c: stloc.0 IL_008d: ldloca.s V_0 IL_008f: call ""string bool.ToString()"" IL_0094: call ""string string.Concat(string, string)"" @@ -9952,64 +9951,63 @@ static void Test(Span chars) not: True") .VerifyIL("C.Test", """ { - // Code size 167 (0xa7) + // Code size 166 (0xa6) .maxstack 3 .locals init (bool V_0) IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldstr "string 1" - IL_0007: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" - IL_000c: call "bool System.MemoryExtensions.SequenceEqual(System.Span, System.ReadOnlySpan)" - IL_0011: brtrue.s IL_0027 - IL_0013: ldarg.0 - IL_0014: ldstr "string 2" - IL_0019: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" - IL_001e: call "bool System.MemoryExtensions.SequenceEqual(System.Span, System.ReadOnlySpan)" - IL_0023: brtrue.s IL_0027 - IL_0025: br.s IL_002b - IL_0027: ldc.i4.1 - IL_0028: stloc.0 - IL_0029: br.s IL_002d - IL_002b: ldc.i4.0 - IL_002c: stloc.0 - IL_002d: ldstr "or: " - IL_0032: ldloca.s V_0 - IL_0034: call "string bool.ToString()" - IL_0039: call "string string.Concat(string, string)" - IL_003e: call "void System.Console.WriteLine(string)" - IL_0043: nop - IL_0044: ldstr "and: " - IL_0049: ldarg.0 - IL_004a: ldstr "string 1" - IL_004f: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" - IL_0054: call "bool System.MemoryExtensions.SequenceEqual(System.Span, System.ReadOnlySpan)" - IL_0059: brfalse.s IL_0067 - IL_005b: ldarga.s V_0 - IL_005d: call "int System.Span.Length.get" - IL_0062: ldc.i4.7 - IL_0063: ceq - IL_0065: br.s IL_0068 - IL_0067: ldc.i4.0 - IL_0068: stloc.0 - IL_0069: ldloca.s V_0 - IL_006b: call "string bool.ToString()" - IL_0070: call "string string.Concat(string, string)" - IL_0075: call "void System.Console.WriteLine(string)" - IL_007a: nop - IL_007b: ldstr "not: " - IL_0080: ldarg.0 - IL_0081: ldstr "string 1" - IL_0086: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" - IL_008b: call "bool System.MemoryExtensions.SequenceEqual(System.Span, System.ReadOnlySpan)" - IL_0090: ldc.i4.0 - IL_0091: ceq - IL_0093: stloc.0 - IL_0094: ldloca.s V_0 - IL_0096: call "string bool.ToString()" - IL_009b: call "string string.Concat(string, string)" - IL_00a0: call "void System.Console.WriteLine(string)" - IL_00a5: nop - IL_00a6: ret + IL_0001: ldstr "or: " + IL_0006: ldarg.0 + IL_0007: ldstr "string 1" + IL_000c: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" + IL_0011: call "bool System.MemoryExtensions.SequenceEqual(System.Span, System.ReadOnlySpan)" + IL_0016: brtrue.s IL_002c + IL_0018: ldarg.0 + IL_0019: ldstr "string 2" + IL_001e: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" + IL_0023: call "bool System.MemoryExtensions.SequenceEqual(System.Span, System.ReadOnlySpan)" + IL_0028: brtrue.s IL_002c + IL_002a: br.s IL_002f + IL_002c: ldc.i4.1 + IL_002d: br.s IL_0030 + IL_002f: ldc.i4.0 + IL_0030: stloc.0 + IL_0031: ldloca.s V_0 + IL_0033: call "string bool.ToString()" + IL_0038: call "string string.Concat(string, string)" + IL_003d: call "void System.Console.WriteLine(string)" + IL_0042: nop + IL_0043: ldstr "and: " + IL_0048: ldarg.0 + IL_0049: ldstr "string 1" + IL_004e: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" + IL_0053: call "bool System.MemoryExtensions.SequenceEqual(System.Span, System.ReadOnlySpan)" + IL_0058: brfalse.s IL_0066 + IL_005a: ldarga.s V_0 + IL_005c: call "int System.Span.Length.get" + IL_0061: ldc.i4.7 + IL_0062: ceq + IL_0064: br.s IL_0067 + IL_0066: ldc.i4.0 + IL_0067: stloc.0 + IL_0068: ldloca.s V_0 + IL_006a: call "string bool.ToString()" + IL_006f: call "string string.Concat(string, string)" + IL_0074: call "void System.Console.WriteLine(string)" + IL_0079: nop + IL_007a: ldstr "not: " + IL_007f: ldarg.0 + IL_0080: ldstr "string 1" + IL_0085: call "System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)" + IL_008a: call "bool System.MemoryExtensions.SequenceEqual(System.Span, System.ReadOnlySpan)" + IL_008f: ldc.i4.0 + IL_0090: ceq + IL_0092: stloc.0 + IL_0093: ldloca.s V_0 + IL_0095: call "string bool.ToString()" + IL_009a: call "string string.Concat(string, string)" + IL_009f: call "void System.Console.WriteLine(string)" + IL_00a4: nop + IL_00a5: ret } """); } @@ -10523,14 +10521,14 @@ .locals init (bool V_0) IL_0066: call ""string bool.ToString()"" IL_006b: call ""string string.Concat(string, string)"" IL_0070: call ""void System.Console.WriteLine(string)"" - IL_0075: ldarg.0 - IL_0076: ldstr """" - IL_007b: call ""System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)"" - IL_0080: call ""bool System.MemoryExtensions.SequenceEqual(System.Span, System.ReadOnlySpan)"" - IL_0085: pop - IL_0086: ldc.i4.1 - IL_0087: stloc.0 - IL_0088: ldstr ""4."" + IL_0075: ldstr ""4."" + IL_007a: ldarg.0 + IL_007b: ldstr """" + IL_0080: call ""System.ReadOnlySpan System.MemoryExtensions.AsSpan(string)"" + IL_0085: call ""bool System.MemoryExtensions.SequenceEqual(System.Span, System.ReadOnlySpan)"" + IL_008a: pop + IL_008b: ldc.i4.1 + IL_008c: stloc.0 IL_008d: ldloca.s V_0 IL_008f: call ""string bool.ToString()"" IL_0094: call ""string string.Concat(string, string)"" @@ -11591,16 +11589,16 @@ public static async Task ExceptionFilterBroken() // in the exception filter (at IL_00b6) before accessing `.InnerException` on it. verifier.VerifyIL("C.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" { - // Code size 471 (0x1d7) + // Code size 460 (0x1cc) .maxstack 3 .locals init (int V_0, bool V_1, - System.Exception V_2, - string V_3, - bool V_4, - System.Runtime.CompilerServices.TaskAwaiter V_5, - C.d__1 V_6, - System.Exception V_7, + System.Runtime.CompilerServices.TaskAwaiter V_2, + C.d__1 V_3, + System.Exception V_4, + bool V_5, + System.Exception V_6, + string V_7, int V_8, System.Runtime.CompilerServices.TaskAwaiter V_9) IL_0000: ldarg.0 @@ -11616,7 +11614,7 @@ .locals init (int V_0, IL_000e: beq.s IL_0014 IL_0010: br.s IL_0019 IL_0012: br.s IL_0021 - IL_0014: br IL_0166 + IL_0014: br IL_0159 IL_0019: nop IL_001a: ldarg.0 IL_001b: ldc.i4.0 @@ -11627,193 +11625,188 @@ .locals init (int V_0, IL_0022: ldloc.0 IL_0023: brfalse.s IL_0027 IL_0025: br.s IL_0029 - IL_0027: br.s IL_0068 + IL_0027: br.s IL_0065 IL_0029: nop IL_002a: call ""System.Threading.Tasks.Task C.ThrowException()"" IL_002f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0034: stloc.s V_5 - IL_0036: ldloca.s V_5 - IL_0038: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_003d: brtrue.s IL_0085 - IL_003f: ldarg.0 - IL_0040: ldc.i4.0 - IL_0041: dup - IL_0042: stloc.0 - IL_0043: stfld ""int C.d__1.<>1__state"" - IL_0048: ldarg.0 - IL_0049: ldloc.s V_5 - IL_004b: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" + IL_0034: stloc.2 + IL_0035: ldloca.s V_2 + IL_0037: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_003c: brtrue.s IL_0081 + IL_003e: ldarg.0 + IL_003f: ldc.i4.0 + IL_0040: dup + IL_0041: stloc.0 + IL_0042: stfld ""int C.d__1.<>1__state"" + IL_0047: ldarg.0 + IL_0048: ldloc.2 + IL_0049: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" + IL_004e: ldarg.0 + IL_004f: stloc.3 IL_0050: ldarg.0 - IL_0051: stloc.s V_6 - IL_0053: ldarg.0 - IL_0054: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" - IL_0059: ldloca.s V_5 - IL_005b: ldloca.s V_6 - IL_005d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__1)"" - IL_0062: nop - IL_0063: leave IL_01d6 - IL_0068: ldarg.0 - IL_0069: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" - IL_006e: stloc.s V_5 - IL_0070: ldarg.0 - IL_0071: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" - IL_0076: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_007c: ldarg.0 - IL_007d: ldc.i4.m1 - IL_007e: dup - IL_007f: stloc.0 - IL_0080: stfld ""int C.d__1.<>1__state"" - IL_0085: ldloca.s V_5 - IL_0087: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_008c: nop - IL_008d: ldc.i4.1 - IL_008e: stloc.1 - IL_008f: leave IL_01c1 + IL_0051: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" + IL_0056: ldloca.s V_2 + IL_0058: ldloca.s V_3 + IL_005a: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__1)"" + IL_005f: nop + IL_0060: leave IL_01cb + IL_0065: ldarg.0 + IL_0066: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" + IL_006b: stloc.2 + IL_006c: ldarg.0 + IL_006d: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" + IL_0072: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0078: ldarg.0 + IL_0079: ldc.i4.m1 + IL_007a: dup + IL_007b: stloc.0 + IL_007c: stfld ""int C.d__1.<>1__state"" + IL_0081: ldloca.s V_2 + IL_0083: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0088: nop + IL_0089: ldc.i4.1 + IL_008a: stloc.1 + IL_008b: leave IL_01b6 } filter { - IL_0094: isinst ""System.Exception"" - IL_0099: dup - IL_009a: brtrue.s IL_00a0 - IL_009c: pop - IL_009d: ldc.i4.0 - IL_009e: br.s IL_0106 - IL_00a0: stloc.s V_7 - IL_00a2: ldarg.0 - IL_00a3: ldloc.s V_7 - IL_00a5: stfld ""object C.d__1.<>s__1"" - IL_00aa: ldarg.0 - IL_00ab: ldarg.0 - IL_00ac: ldfld ""object C.d__1.<>s__1"" - IL_00b1: castclass ""System.Exception"" - IL_00b6: stfld ""System.Exception C.d__1.5__3"" - IL_00bb: ldarg.0 - IL_00bc: ldfld ""System.Exception C.d__1.5__3"" - IL_00c1: callvirt ""System.Exception System.Exception.InnerException.get"" - IL_00c6: stloc.2 - IL_00c7: ldloc.2 - IL_00c8: brfalse.s IL_00f2 - IL_00ca: ldloc.2 - IL_00cb: callvirt ""string System.Exception.Message.get"" - IL_00d0: stloc.3 - IL_00d1: ldloc.3 - IL_00d2: ldstr ""bad dog"" - IL_00d7: call ""bool string.op_Equality(string, string)"" - IL_00dc: brtrue.s IL_00ed - IL_00de: ldloc.3 - IL_00df: ldstr ""dog bad"" - IL_00e4: call ""bool string.op_Equality(string, string)"" - IL_00e9: brtrue.s IL_00ed - IL_00eb: br.s IL_00f2 - IL_00ed: ldc.i4.1 - IL_00ee: stloc.s V_4 - IL_00f0: br.s IL_00f5 + IL_0090: isinst ""System.Exception"" + IL_0095: dup + IL_0096: brtrue.s IL_009c + IL_0098: pop + IL_0099: ldc.i4.0 + IL_009a: br.s IL_00fa + IL_009c: stloc.s V_4 + IL_009e: ldarg.0 + IL_009f: ldloc.s V_4 + IL_00a1: stfld ""object C.d__1.<>s__1"" + IL_00a6: ldarg.0 + IL_00a7: ldarg.0 + IL_00a8: ldfld ""object C.d__1.<>s__1"" + IL_00ad: castclass ""System.Exception"" + IL_00b2: stfld ""System.Exception C.d__1.5__3"" + IL_00b7: ldarg.0 + IL_00b8: ldfld ""System.Exception C.d__1.5__3"" + IL_00bd: callvirt ""System.Exception System.Exception.InnerException.get"" + IL_00c2: stloc.s V_6 + IL_00c4: ldloc.s V_6 + IL_00c6: brfalse.s IL_00f2 + IL_00c8: ldloc.s V_6 + IL_00ca: callvirt ""string System.Exception.Message.get"" + IL_00cf: stloc.s V_7 + IL_00d1: ldloc.s V_7 + IL_00d3: ldstr ""bad dog"" + IL_00d8: call ""bool string.op_Equality(string, string)"" + IL_00dd: brtrue.s IL_00ef + IL_00df: ldloc.s V_7 + IL_00e1: ldstr ""dog bad"" + IL_00e6: call ""bool string.op_Equality(string, string)"" + IL_00eb: brtrue.s IL_00ef + IL_00ed: br.s IL_00f2 + IL_00ef: ldc.i4.1 + IL_00f0: br.s IL_00f3 IL_00f2: ldc.i4.0 - IL_00f3: stloc.s V_4 - IL_00f5: ldarg.0 - IL_00f6: ldloc.s V_4 - IL_00f8: stfld ""bool C.d__1.<>s__4"" - IL_00fd: ldarg.0 - IL_00fe: ldfld ""bool C.d__1.<>s__4"" - IL_0103: ldc.i4.0 - IL_0104: cgt.un - IL_0106: endfilter + IL_00f3: stloc.s V_5 + IL_00f5: ldloc.s V_5 + IL_00f7: ldc.i4.0 + IL_00f8: cgt.un + IL_00fa: endfilter } // end filter { // handler - IL_0108: pop - IL_0109: ldarg.0 - IL_010a: ldc.i4.1 - IL_010b: stfld ""int C.d__1.<>s__2"" - IL_0110: leave.s IL_011b + IL_00fc: pop + IL_00fd: ldarg.0 + IL_00fe: ldc.i4.1 + IL_00ff: stfld ""int C.d__1.<>s__2"" + IL_0104: leave.s IL_010f } catch object { - IL_0112: pop - IL_0113: nop - IL_0114: ldc.i4.0 - IL_0115: stloc.1 - IL_0116: leave IL_01c1 - } - IL_011b: ldarg.0 - IL_011c: ldfld ""int C.d__1.<>s__2"" - IL_0121: stloc.s V_8 - IL_0123: ldloc.s V_8 - IL_0125: ldc.i4.1 - IL_0126: beq.s IL_012a - IL_0128: br.s IL_0199 - IL_012a: nop - IL_012b: call ""System.Threading.Tasks.Task C.TrueAsync()"" - IL_0130: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0135: stloc.s V_9 - IL_0137: ldloca.s V_9 - IL_0139: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_013e: brtrue.s IL_0183 - IL_0140: ldarg.0 - IL_0141: ldc.i4.1 - IL_0142: dup - IL_0143: stloc.0 - IL_0144: stfld ""int C.d__1.<>1__state"" - IL_0149: ldarg.0 - IL_014a: ldloc.s V_9 - IL_014c: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__2"" - IL_0151: ldarg.0 - IL_0152: stloc.s V_6 - IL_0154: ldarg.0 - IL_0155: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" - IL_015a: ldloca.s V_9 - IL_015c: ldloca.s V_6 - IL_015e: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, C.d__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__1)"" - IL_0163: nop - IL_0164: leave.s IL_01d6 - IL_0166: ldarg.0 - IL_0167: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__2"" - IL_016c: stloc.s V_9 - IL_016e: ldarg.0 - IL_016f: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__2"" - IL_0174: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_017a: ldarg.0 - IL_017b: ldc.i4.m1 - IL_017c: dup - IL_017d: stloc.0 - IL_017e: stfld ""int C.d__1.<>1__state"" + IL_0106: pop + IL_0107: nop + IL_0108: ldc.i4.0 + IL_0109: stloc.1 + IL_010a: leave IL_01b6 + } + IL_010f: ldarg.0 + IL_0110: ldfld ""int C.d__1.<>s__2"" + IL_0115: stloc.s V_8 + IL_0117: ldloc.s V_8 + IL_0119: ldc.i4.1 + IL_011a: beq.s IL_011e + IL_011c: br.s IL_018c + IL_011e: nop + IL_011f: call ""System.Threading.Tasks.Task C.TrueAsync()"" + IL_0124: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0129: stloc.s V_9 + IL_012b: ldloca.s V_9 + IL_012d: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0132: brtrue.s IL_0176 + IL_0134: ldarg.0 + IL_0135: ldc.i4.1 + IL_0136: dup + IL_0137: stloc.0 + IL_0138: stfld ""int C.d__1.<>1__state"" + IL_013d: ldarg.0 + IL_013e: ldloc.s V_9 + IL_0140: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__2"" + IL_0145: ldarg.0 + IL_0146: stloc.3 + IL_0147: ldarg.0 + IL_0148: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" + IL_014d: ldloca.s V_9 + IL_014f: ldloca.s V_3 + IL_0151: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, C.d__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__1)"" + IL_0156: nop + IL_0157: leave.s IL_01cb + IL_0159: ldarg.0 + IL_015a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__2"" + IL_015f: stloc.s V_9 + IL_0161: ldarg.0 + IL_0162: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__2"" + IL_0167: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_016d: ldarg.0 + IL_016e: ldc.i4.m1 + IL_016f: dup + IL_0170: stloc.0 + IL_0171: stfld ""int C.d__1.<>1__state"" + IL_0176: ldarg.0 + IL_0177: ldloca.s V_9 + IL_0179: call ""bool System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_017e: stfld ""bool C.d__1.<>s__4"" IL_0183: ldarg.0 - IL_0184: ldloca.s V_9 - IL_0186: call ""bool System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_018b: stfld ""bool C.d__1.<>s__5"" - IL_0190: ldarg.0 - IL_0191: ldfld ""bool C.d__1.<>s__5"" - IL_0196: stloc.1 - IL_0197: leave.s IL_01c1 - IL_0199: ldarg.0 - IL_019a: ldnull - IL_019b: stfld ""object C.d__1.<>s__1"" - IL_01a0: ldarg.0 - IL_01a1: ldnull - IL_01a2: stfld ""System.Exception C.d__1.5__3"" - IL_01a7: leave.s IL_01c1 + IL_0184: ldfld ""bool C.d__1.<>s__4"" + IL_0189: stloc.1 + IL_018a: leave.s IL_01b6 + IL_018c: ldarg.0 + IL_018d: ldnull + IL_018e: stfld ""object C.d__1.<>s__1"" + IL_0193: ldarg.0 + IL_0194: ldnull + IL_0195: stfld ""System.Exception C.d__1.5__3"" + IL_019a: leave.s IL_01b6 } catch System.Exception { - IL_01a9: stloc.2 - IL_01aa: ldarg.0 - IL_01ab: ldc.i4.s -2 - IL_01ad: stfld ""int C.d__1.<>1__state"" - IL_01b2: ldarg.0 - IL_01b3: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" - IL_01b8: ldloc.2 - IL_01b9: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_01be: nop - IL_01bf: leave.s IL_01d6 + IL_019c: stloc.s V_6 + IL_019e: ldarg.0 + IL_019f: ldc.i4.s -2 + IL_01a1: stfld ""int C.d__1.<>1__state"" + IL_01a6: ldarg.0 + IL_01a7: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" + IL_01ac: ldloc.s V_6 + IL_01ae: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_01b3: nop + IL_01b4: leave.s IL_01cb } - IL_01c1: ldarg.0 - IL_01c2: ldc.i4.s -2 - IL_01c4: stfld ""int C.d__1.<>1__state"" - IL_01c9: ldarg.0 - IL_01ca: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" - IL_01cf: ldloc.1 - IL_01d0: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(bool)"" - IL_01d5: nop - IL_01d6: ret + IL_01b6: ldarg.0 + IL_01b7: ldc.i4.s -2 + IL_01b9: stfld ""int C.d__1.<>1__state"" + IL_01be: ldarg.0 + IL_01bf: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" + IL_01c4: ldloc.1 + IL_01c5: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(bool)"" + IL_01ca: nop + IL_01cb: ret } "); } @@ -11940,8 +11933,8 @@ public static async Task ExceptionFilterBroken() comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: "True"); verifier.VerifyIL("C.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" - { - // Code size 527 (0x20f) +{ + // Code size 513 (0x201) .maxstack 3 .locals init (int V_0, bool V_1, @@ -11950,9 +11943,9 @@ .locals init (int V_0, System.Exception V_4, int V_5, System.Exception V_6, - string V_7, - bool V_8, - System.Exception V_9, + bool V_7, + System.Exception V_8, + string V_9, System.Runtime.CompilerServices.TaskAwaiter V_10) IL_0000: ldarg.0 IL_0001: ldfld ""int C.d__1.<>1__state"" @@ -11967,7 +11960,7 @@ .locals init (int V_0, IL_000e: beq.s IL_0014 IL_0010: br.s IL_0019 IL_0012: br.s IL_0021 - IL_0014: br IL_0192 + IL_0014: br IL_0184 IL_0019: nop IL_001a: ldarg.0 IL_001b: ldc.i4.0 @@ -12002,7 +11995,7 @@ .locals init (int V_0, IL_0058: ldloca.s V_3 IL_005a: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__1)"" IL_005f: nop - IL_0060: leave IL_020e + IL_0060: leave IL_0200 IL_0065: ldarg.0 IL_0066: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__1"" IL_006b: stloc.2 @@ -12019,7 +12012,7 @@ .locals init (int V_0, IL_0088: nop IL_0089: ldc.i4.1 IL_008a: stloc.1 - IL_008b: leave IL_01f9 + IL_008b: leave IL_01eb } catch System.Exception { @@ -12038,7 +12031,7 @@ .locals init (int V_0, IL_00ab: ldloc.s V_5 IL_00ad: ldc.i4.1 IL_00ae: beq.s IL_00b5 - IL_00b0: br IL_01d6 + IL_00b0: br IL_01c8 IL_00b5: ldarg.0 IL_00b6: ldarg.0 IL_00b7: ldfld ""object C.d__1.<>s__1"" @@ -12061,135 +12054,130 @@ .locals init (int V_0, IL_00db: brtrue.s IL_00e1 IL_00dd: pop IL_00de: ldc.i4.0 - IL_00df: br.s IL_013c - IL_00e1: stloc.s V_9 + IL_00df: br.s IL_012e + IL_00e1: stloc.s V_6 IL_00e3: ldarg.0 - IL_00e4: ldloc.s V_9 + IL_00e4: ldloc.s V_6 IL_00e6: stfld ""object C.d__1.<>s__4"" IL_00eb: ldarg.0 IL_00ec: ldfld ""System.Exception C.d__1.5__3"" IL_00f1: callvirt ""System.Exception System.Exception.InnerException.get"" - IL_00f6: stloc.s V_6 - IL_00f8: ldloc.s V_6 - IL_00fa: brfalse.s IL_0128 - IL_00fc: ldloc.s V_6 + IL_00f6: stloc.s V_8 + IL_00f8: ldloc.s V_8 + IL_00fa: brfalse.s IL_0126 + IL_00fc: ldloc.s V_8 IL_00fe: callvirt ""string System.Exception.Message.get"" - IL_0103: stloc.s V_7 - IL_0105: ldloc.s V_7 + IL_0103: stloc.s V_9 + IL_0105: ldloc.s V_9 IL_0107: ldstr ""bad dog"" IL_010c: call ""bool string.op_Equality(string, string)"" IL_0111: brtrue.s IL_0123 - IL_0113: ldloc.s V_7 + IL_0113: ldloc.s V_9 IL_0115: ldstr ""dog bad"" IL_011a: call ""bool string.op_Equality(string, string)"" IL_011f: brtrue.s IL_0123 - IL_0121: br.s IL_0128 + IL_0121: br.s IL_0126 IL_0123: ldc.i4.1 - IL_0124: stloc.s V_8 - IL_0126: br.s IL_012b - IL_0128: ldc.i4.0 - IL_0129: stloc.s V_8 - IL_012b: ldarg.0 - IL_012c: ldloc.s V_8 - IL_012e: stfld ""bool C.d__1.<>s__6"" - IL_0133: ldarg.0 - IL_0134: ldfld ""bool C.d__1.<>s__6"" - IL_0139: ldc.i4.0 - IL_013a: cgt.un - IL_013c: endfilter + IL_0124: br.s IL_0127 + IL_0126: ldc.i4.0 + IL_0127: stloc.s V_7 + IL_0129: ldloc.s V_7 + IL_012b: ldc.i4.0 + IL_012c: cgt.un + IL_012e: endfilter } // end filter { // handler - IL_013e: pop - IL_013f: ldarg.0 - IL_0140: ldc.i4.1 - IL_0141: stfld ""int C.d__1.<>s__5"" - IL_0146: leave.s IL_0148 - } - IL_0148: ldarg.0 - IL_0149: ldfld ""int C.d__1.<>s__5"" - IL_014e: stloc.s V_5 - IL_0150: ldloc.s V_5 - IL_0152: ldc.i4.1 - IL_0153: beq.s IL_0157 - IL_0155: br.s IL_01c5 - IL_0157: nop - IL_0158: call ""System.Threading.Tasks.Task C.TrueAsync()"" - IL_015d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0162: stloc.s V_10 - IL_0164: ldloca.s V_10 - IL_0166: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_016b: brtrue.s IL_01af - IL_016d: ldarg.0 - IL_016e: ldc.i4.1 - IL_016f: dup - IL_0170: stloc.0 - IL_0171: stfld ""int C.d__1.<>1__state"" - IL_0176: ldarg.0 - IL_0177: ldloc.s V_10 - IL_0179: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__2"" - IL_017e: ldarg.0 - IL_017f: stloc.3 - IL_0180: ldarg.0 - IL_0181: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" - IL_0186: ldloca.s V_10 - IL_0188: ldloca.s V_3 - IL_018a: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, C.d__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__1)"" - IL_018f: nop - IL_0190: leave.s IL_020e - IL_0192: ldarg.0 - IL_0193: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__2"" - IL_0198: stloc.s V_10 - IL_019a: ldarg.0 - IL_019b: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__2"" - IL_01a0: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_01a6: ldarg.0 - IL_01a7: ldc.i4.m1 - IL_01a8: dup - IL_01a9: stloc.0 - IL_01aa: stfld ""int C.d__1.<>1__state"" - IL_01af: ldarg.0 - IL_01b0: ldloca.s V_10 - IL_01b2: call ""bool System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_01b7: stfld ""bool C.d__1.<>s__7"" - IL_01bc: ldarg.0 - IL_01bd: ldfld ""bool C.d__1.<>s__7"" - IL_01c2: stloc.1 - IL_01c3: leave.s IL_01f9 - IL_01c5: ldarg.0 - IL_01c6: ldnull - IL_01c7: stfld ""object C.d__1.<>s__4"" - IL_01cc: nop - IL_01cd: ldarg.0 - IL_01ce: ldnull - IL_01cf: stfld ""System.Exception C.d__1.5__3"" - IL_01d4: br.s IL_01d6 - IL_01d6: ldarg.0 - IL_01d7: ldnull - IL_01d8: stfld ""object C.d__1.<>s__1"" - IL_01dd: leave.s IL_01f9 + IL_0130: pop + IL_0131: ldarg.0 + IL_0132: ldc.i4.1 + IL_0133: stfld ""int C.d__1.<>s__5"" + IL_0138: leave.s IL_013a + } + IL_013a: ldarg.0 + IL_013b: ldfld ""int C.d__1.<>s__5"" + IL_0140: stloc.s V_5 + IL_0142: ldloc.s V_5 + IL_0144: ldc.i4.1 + IL_0145: beq.s IL_0149 + IL_0147: br.s IL_01b7 + IL_0149: nop + IL_014a: call ""System.Threading.Tasks.Task C.TrueAsync()"" + IL_014f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0154: stloc.s V_10 + IL_0156: ldloca.s V_10 + IL_0158: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_015d: brtrue.s IL_01a1 + IL_015f: ldarg.0 + IL_0160: ldc.i4.1 + IL_0161: dup + IL_0162: stloc.0 + IL_0163: stfld ""int C.d__1.<>1__state"" + IL_0168: ldarg.0 + IL_0169: ldloc.s V_10 + IL_016b: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__2"" + IL_0170: ldarg.0 + IL_0171: stloc.3 + IL_0172: ldarg.0 + IL_0173: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" + IL_0178: ldloca.s V_10 + IL_017a: ldloca.s V_3 + IL_017c: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, C.d__1>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__1)"" + IL_0181: nop + IL_0182: leave.s IL_0200 + IL_0184: ldarg.0 + IL_0185: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__2"" + IL_018a: stloc.s V_10 + IL_018c: ldarg.0 + IL_018d: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__1.<>u__2"" + IL_0192: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0198: ldarg.0 + IL_0199: ldc.i4.m1 + IL_019a: dup + IL_019b: stloc.0 + IL_019c: stfld ""int C.d__1.<>1__state"" + IL_01a1: ldarg.0 + IL_01a2: ldloca.s V_10 + IL_01a4: call ""bool System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_01a9: stfld ""bool C.d__1.<>s__6"" + IL_01ae: ldarg.0 + IL_01af: ldfld ""bool C.d__1.<>s__6"" + IL_01b4: stloc.1 + IL_01b5: leave.s IL_01eb + IL_01b7: ldarg.0 + IL_01b8: ldnull + IL_01b9: stfld ""object C.d__1.<>s__4"" + IL_01be: nop + IL_01bf: ldarg.0 + IL_01c0: ldnull + IL_01c1: stfld ""System.Exception C.d__1.5__3"" + IL_01c6: br.s IL_01c8 + IL_01c8: ldarg.0 + IL_01c9: ldnull + IL_01ca: stfld ""object C.d__1.<>s__1"" + IL_01cf: leave.s IL_01eb } catch System.Exception { - IL_01df: stloc.s V_6 - IL_01e1: ldarg.0 - IL_01e2: ldc.i4.s -2 - IL_01e4: stfld ""int C.d__1.<>1__state"" - IL_01e9: ldarg.0 - IL_01ea: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" - IL_01ef: ldloc.s V_6 - IL_01f1: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_01f6: nop - IL_01f7: leave.s IL_020e + IL_01d1: stloc.s V_8 + IL_01d3: ldarg.0 + IL_01d4: ldc.i4.s -2 + IL_01d6: stfld ""int C.d__1.<>1__state"" + IL_01db: ldarg.0 + IL_01dc: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" + IL_01e1: ldloc.s V_8 + IL_01e3: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_01e8: nop + IL_01e9: leave.s IL_0200 } - IL_01f9: ldarg.0 - IL_01fa: ldc.i4.s -2 - IL_01fc: stfld ""int C.d__1.<>1__state"" - IL_0201: ldarg.0 - IL_0202: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" - IL_0207: ldloc.1 - IL_0208: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(bool)"" - IL_020d: nop - IL_020e: ret + IL_01eb: ldarg.0 + IL_01ec: ldc.i4.s -2 + IL_01ee: stfld ""int C.d__1.<>1__state"" + IL_01f3: ldarg.0 + IL_01f4: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__1.<>t__builder"" + IL_01f9: ldloc.1 + IL_01fa: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(bool)"" + IL_01ff: nop + IL_0200: ret } "); } diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests3.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests3.cs index 27bd784d69384..1be33c211fbeb 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests3.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests3.cs @@ -6420,25 +6420,60 @@ class C {{ static void Main() {{ - object o = 42; - M(o); + M1(41); + M1(42); + M1(43); + WriteLine(M2(41)); + WriteLine(M2(42)); + WriteLine(M2(43)); }} - static void M(object o) + static void M1(object o) {{ if ({pattern}) return; WriteLine(o); }} + static bool M2(object o) + {{ + return ({pattern}); + }} }}"; - var verifier = CompileAndVerify(source, expectedOutput: "42"); - verifier.VerifyIL("C.M", + string expectedOutput = """ +41 +42 +False +False +True +"""; + var verifier = CompileAndVerify(source, expectedOutput: expectedOutput); + verifier.VerifyIL("C.M1", @"{ - // Code size 39 (0x27) + // Code size 30 (0x1e) .maxstack 2 - .locals init (int V_0, - bool V_1) + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: isinst ""int"" + IL_0006: brfalse.s IL_0016 + IL_0008: ldarg.0 + IL_0009: unbox.any ""int"" + IL_000e: stloc.0 + IL_000f: ldloc.0 + IL_0010: ldc.i4.s 41 + IL_0012: sub + IL_0013: ldc.i4.1 + IL_0014: ble.un.s IL_0017 + IL_0016: ret + IL_0017: ldarg.0 + IL_0018: call ""void System.Console.WriteLine(object)"" + IL_001d: ret +}"); + verifier.VerifyIL("C.M2", +@"{ + // Code size 26 (0x1a) + .maxstack 2 + .locals init (int V_0) IL_0000: ldarg.0 IL_0001: isinst ""int"" - IL_0006: brfalse.s IL_001a + IL_0006: brfalse.s IL_0018 IL_0008: ldarg.0 IL_0009: unbox.any ""int"" IL_000e: stloc.0 @@ -6446,18 +6481,11 @@ .locals init (int V_0, IL_0010: ldc.i4.s 41 IL_0012: sub IL_0013: ldc.i4.1 - IL_0014: bgt.un.s IL_001a - IL_0016: ldc.i4.1 - IL_0017: stloc.1 - IL_0018: br.s IL_001c - IL_001a: ldc.i4.0 - IL_001b: stloc.1 - IL_001c: ldloc.1 - IL_001d: brtrue.s IL_0020 - IL_001f: ret - IL_0020: ldarg.0 - IL_0021: call ""void System.Console.WriteLine(object)"" - IL_0026: ret + IL_0014: bgt.un.s IL_0018 + IL_0016: ldc.i4.0 + IL_0017: ret + IL_0018: ldc.i4.1 + IL_0019: ret }"); } diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests5.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests5.cs index 0120dc6e33d29..cd99ca9ea6484 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests5.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests5.cs @@ -3178,21 +3178,17 @@ public static bool Test(int a) var compilation = CompileAndVerify(source, expectedOutput: "True"); compilation.VerifyIL("C.Test", """ { - // Code size 14 (0xe) + // Code size 10 (0xa) .maxstack 2 - .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: ldc.i4.1 IL_0002: sub IL_0003: ldc.i4.7 - IL_0004: bgt.un.s IL_000a + IL_0004: bgt.un.s IL_0008 IL_0006: ldc.i4.1 - IL_0007: stloc.0 - IL_0008: br.s IL_000c - IL_000a: ldc.i4.0 - IL_000b: stloc.0 - IL_000c: ldloc.0 - IL_000d: ret + IL_0007: ret + IL_0008: ldc.i4.0 + IL_0009: ret } """); } @@ -3227,9 +3223,8 @@ public static bool Test(int a, object b) var compilation = CompileAndVerify(source, expectedOutput: "True"); compilation.VerifyIL("C.Test", """ { - // Code size 72 (0x48) + // Code size 68 (0x44) .maxstack 2 - .locals init (bool V_0) IL_0000: ldarg.0 IL_0001: ldc.i4.1 IL_0002: sub @@ -3238,29 +3233,26 @@ .locals init (bool V_0) IL_0024, IL_002e, IL_0038) - IL_0018: br.s IL_0044 + IL_0018: br.s IL_0042 IL_001a: ldarg.1 IL_001b: isinst "int" IL_0020: brtrue.s IL_0040 - IL_0022: br.s IL_0044 + IL_0022: br.s IL_0042 IL_0024: ldarg.1 IL_0025: isinst "bool" IL_002a: brtrue.s IL_0040 - IL_002c: br.s IL_0044 + IL_002c: br.s IL_0042 IL_002e: ldarg.1 IL_002f: isinst "double" IL_0034: brtrue.s IL_0040 - IL_0036: br.s IL_0044 + IL_0036: br.s IL_0042 IL_0038: ldarg.1 IL_0039: isinst "long" - IL_003e: brfalse.s IL_0044 + IL_003e: brfalse.s IL_0042 IL_0040: ldc.i4.1 - IL_0041: stloc.0 - IL_0042: br.s IL_0046 - IL_0044: ldc.i4.0 - IL_0045: stloc.0 - IL_0046: ldloc.0 - IL_0047: ret + IL_0041: ret + IL_0042: ldc.i4.0 + IL_0043: ret } """); } @@ -3294,24 +3286,23 @@ public static bool Test(string a) var compilation = CompileAndVerify(source, expectedOutput: "True"); compilation.VerifyIL("C.Test", """ { - // Code size 73 (0x49) + // Code size 69 (0x45) .maxstack 2 - .locals init (bool V_0, - int V_1, - char V_2) + .locals init (int V_0, + char V_1) IL_0000: ldarg.0 - IL_0001: brfalse.s IL_0045 + IL_0001: brfalse.s IL_0043 IL_0003: ldarg.0 IL_0004: call "int string.Length.get" - IL_0009: stloc.1 - IL_000a: ldloc.1 + IL_0009: stloc.0 + IL_000a: ldloc.0 IL_000b: ldc.i4.1 - IL_000c: bne.un.s IL_0045 + IL_000c: bne.un.s IL_0043 IL_000e: ldarg.0 IL_000f: ldc.i4.0 IL_0010: call "char string.this[int].get" - IL_0015: stloc.2 - IL_0016: ldloc.2 + IL_0015: stloc.1 + IL_0016: ldloc.1 IL_0017: ldc.i4.s 49 IL_0019: sub IL_001a: switch ( @@ -3323,14 +3314,11 @@ .locals init (bool V_0, IL_0041, IL_0041, IL_0041) - IL_003f: br.s IL_0045 + IL_003f: br.s IL_0043 IL_0041: ldc.i4.1 - IL_0042: stloc.0 - IL_0043: br.s IL_0047 - IL_0045: ldc.i4.0 - IL_0046: stloc.0 - IL_0047: ldloc.0 - IL_0048: ret + IL_0042: ret + IL_0043: ldc.i4.0 + IL_0044: ret } """); } @@ -3356,5 +3344,138 @@ bool M0({type} x0) Diagnostic(ErrorCode.ERR_ConstantExpected, expression).WithLocation(6, 22) ); } + + [Fact] + public void IsPatternExpressionWithAwait() + { + var source = """ +using System; +using System.Threading.Tasks; + +Console.WriteLine(await Async1(30)); +Console.WriteLine(await Async1(40)); +Console.WriteLine(await Async1(50)); + +Console.WriteLine(await Async2(30)); +Console.WriteLine(await Async2(40)); +Console.WriteLine(await Async2(50)); + +Console.WriteLine(await Async3(30)); +Console.WriteLine(await Async3(40)); +Console.WriteLine(await Async3(50)); + +static async Task Async1(int i) { + // sub-expression + return await Task.FromResult(false) || i is 30 or 40; +} +static async Task Async2(int i) { + // input-expression + return await Task.FromResult(i) is 30 or 40; +} +static async Task Async3(int i) { + // expression-list + return (await Task.FromResult(0), i is 30 or 40).Item2; +} +"""; + var expectedOutput = """ +True +True +False +True +True +False +True +True +False +"""; + var verifier = CompileAndVerify(source, expectedOutput: expectedOutput); + // await in input-expression + verifier.VerifyIL("Program.<<
$>g__Async2|0_1>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", """ +{ + // Code size 167 (0xa7) + .maxstack 3 + .locals init (int V_0, + bool V_1, + int V_2, + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld "int Program.<<
$>g__Async2|0_1>d.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0044 + IL_000a: ldarg.0 + IL_000b: ldfld "int Program.<<
$>g__Async2|0_1>d.i" + IL_0010: call "System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(int)" + IL_0015: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_001a: stloc.3 + IL_001b: ldloca.s V_3 + IL_001d: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_0022: brtrue.s IL_0060 + IL_0024: ldarg.0 + IL_0025: ldc.i4.0 + IL_0026: dup + IL_0027: stloc.0 + IL_0028: stfld "int Program.<<
$>g__Async2|0_1>d.<>1__state" + IL_002d: ldarg.0 + IL_002e: ldloc.3 + IL_002f: stfld "System.Runtime.CompilerServices.TaskAwaiter Program.<<
$>g__Async2|0_1>d.<>u__1" + IL_0034: ldarg.0 + IL_0035: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<
$>g__Async2|0_1>d.<>t__builder" + IL_003a: ldloca.s V_3 + IL_003c: ldarg.0 + IL_003d: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted, Program.<<
$>g__Async2|0_1>d>(ref System.Runtime.CompilerServices.TaskAwaiter, ref Program.<<
$>g__Async2|0_1>d)" + IL_0042: leave.s IL_00a6 + IL_0044: ldarg.0 + IL_0045: ldfld "System.Runtime.CompilerServices.TaskAwaiter Program.<<
$>g__Async2|0_1>d.<>u__1" + IL_004a: stloc.3 + IL_004b: ldarg.0 + IL_004c: ldflda "System.Runtime.CompilerServices.TaskAwaiter Program.<<
$>g__Async2|0_1>d.<>u__1" + IL_0051: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_0057: ldarg.0 + IL_0058: ldc.i4.m1 + IL_0059: dup + IL_005a: stloc.0 + IL_005b: stfld "int Program.<<
$>g__Async2|0_1>d.<>1__state" + IL_0060: ldloca.s V_3 + IL_0062: call "int System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_0067: stloc.2 + IL_0068: ldloc.2 + IL_0069: ldc.i4.s 30 + IL_006b: beq.s IL_0072 + IL_006d: ldloc.2 + IL_006e: ldc.i4.s 40 + IL_0070: bne.un.s IL_0075 + IL_0072: ldc.i4.1 + IL_0073: br.s IL_0076 + IL_0075: ldc.i4.0 + IL_0076: stloc.1 + IL_0077: leave.s IL_0092 + } + catch System.Exception + { + IL_0079: stloc.s V_4 + IL_007b: ldarg.0 + IL_007c: ldc.i4.s -2 + IL_007e: stfld "int Program.<<
$>g__Async2|0_1>d.<>1__state" + IL_0083: ldarg.0 + IL_0084: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<
$>g__Async2|0_1>d.<>t__builder" + IL_0089: ldloc.s V_4 + IL_008b: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_0090: leave.s IL_00a6 + } + IL_0092: ldarg.0 + IL_0093: ldc.i4.s -2 + IL_0095: stfld "int Program.<<
$>g__Async2|0_1>d.<>1__state" + IL_009a: ldarg.0 + IL_009b: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder Program.<<
$>g__Async2|0_1>d.<>t__builder" + IL_00a0: ldloc.1 + IL_00a1: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult(bool)" + IL_00a6: ret +} +"""); + } } } diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs index 6c07a0e211d7b..b06c36e7e4e34 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs @@ -1096,6 +1096,16 @@ internal void AssertStackEmpty() Debug.Assert(_emitState.CurStack == 0); } + [Conditional("DEBUG")] + internal void AssertStackDepth(int stack) + { + Debug.Assert(_emitState.CurStack == stack); + } + +#if DEBUG + internal int GetStackDepth() => _emitState.CurStack; +#endif + // true if there may have been a label generated with no subsequent code internal bool IsJustPastLabel() { From b080e4ab8b32d4f0903f0019a4a8a94353892c73 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Fri, 18 Aug 2023 13:50:07 -0700 Subject: [PATCH 02/13] Add repro --- .../Test/Emit/CodeGen/CodeGenAsyncTests.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index fa39f561f1e8b..33cf9893651ff 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -6053,5 +6053,36 @@ public async Task M(object o) var comp = CSharpTestBase.CreateCompilation(source); comp.VerifyEmitDiagnostics(); } + + [ConditionalFact(typeof(CoreClrOnly))] + public void Repro() + { + var source = """ + using System; + using System.Threading.Tasks; + using System.Collections.Immutable; + + await M(ImmutableArray.Create("a")); + Console.Write(1); + + public partial class Program + { + public static void M1(bool b) { } + + public static async Task M(ImmutableArray a) + { + foreach (var i in a) + { + M1(i.Length is 10 or 20 or 30); + await Task.Delay(1).ConfigureAwait(false); + } + } + } + """; + + // TODO2: ImmutableArray is only available when we specify a targetFramework + var comp = CompileAndVerify(source, expectedOutput: "1", options: TestOptions.ReleaseExe, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } } } From 3c690ffece450a536e961c11da819780c0ea77f5 Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Mon, 26 Feb 2024 20:43:37 +0330 Subject: [PATCH 03/13] Reset state --- src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index f92de3ecb0b2f..cb5d99d4602b3 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -3041,7 +3041,9 @@ public override BoundNode VisitConditionalReceiver(BoundConditionalReceiver node public override BoundNode VisitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node) { + var savedState = this.State.Clone(); VisitStatements(node.Statements); + this.State = savedState; return null; } From 49e5434f504a44438bedb907c1a79384ffc693da Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Wed, 6 Mar 2024 01:12:29 +0330 Subject: [PATCH 04/13] Cherry-pick relevant changes from other PR --- .../CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs | 2 +- .../LocalRewriter/LocalRewriter_IsPatternOperator.cs | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index cb5d99d4602b3..1786887ab08cc 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -3043,7 +3043,7 @@ public override BoundNode VisitLoweredIsPatternExpression(BoundLoweredIsPatternE { var savedState = this.State.Clone(); VisitStatements(node.Statements); - this.State = savedState; + SetState(savedState); return null; } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs index 00cbbd7362677..ad9a07be340bc 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs @@ -121,16 +121,13 @@ internal BoundExpression LowerGeneralIsPattern(BoundIsPatternExpression node, Bo // lower the decision dag. ImmutableArray loweredDag = LowerDecisionDagCore(decisionDag); - var resultBuilder = ArrayBuilder.GetInstance(loweredDag.Length + _statements.Count); - resultBuilder.AddRange(loweredDag); - resultBuilder.AddRange(_statements); return _factory.Sequence( _tempAllocator.AllTemps(), sideEffectsBuilder.ToImmutableAndFree(), new BoundLoweredIsPatternExpression( node.Syntax, // Note: it is not expected for this node to trigger spilling - resultBuilder.ToImmutableAndFree(), + loweredDag.AddRange(_statements), node.WhenTrueLabel, node.WhenFalseLabel, node.Type)); From b304997377716f4cfcc34e1dc763f58376625a66 Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Wed, 6 Mar 2024 01:15:56 +0330 Subject: [PATCH 05/13] Remove TODO marker --- src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index 33cf9893651ff..e028a267fad9b 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -6080,7 +6080,7 @@ public static async Task M(ImmutableArray a) } """; - // TODO2: ImmutableArray is only available when we specify a targetFramework + // ImmutableArray is only available when we specify a targetFramework var comp = CompileAndVerify(source, expectedOutput: "1", options: TestOptions.ReleaseExe, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics(); } From 6a342a32ccdf9544514d2c10dde91974c38e4f8e Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Wed, 6 Mar 2024 11:46:03 +0330 Subject: [PATCH 06/13] Use RecordLabel --- src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs b/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs index 16cd977a393c3..9d9d26016574f 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs @@ -1469,8 +1469,8 @@ public override BoundNode VisitSwitchDispatch(BoundSwitchDispatch node) public override BoundNode VisitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node) { var statements = VisitSideEffects(node.Statements); - RecordBranch(node.WhenTrueLabel); - RecordBranch(node.WhenFalseLabel); + RecordLabel(node.WhenTrueLabel); + RecordLabel(node.WhenFalseLabel); return node.Update(statements, node.WhenTrueLabel, node.WhenFalseLabel, VisitType(node.Type)); } From 283061a27a5994d90190bb98e501f992399da4c0 Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Fri, 8 Mar 2024 00:11:56 +0330 Subject: [PATCH 07/13] PR feedback --- .../Test/Emit/CodeGen/CodeGenAsyncTests.cs | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index e028a267fad9b..af26ea33be967 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -6055,22 +6055,26 @@ public async Task M(object o) } [ConditionalFact(typeof(CoreClrOnly))] - public void Repro() + public void IsPatternExpressionInAsyncMethodShouldNotAffectHoistedLocals() { var source = """ using System; using System.Threading.Tasks; using System.Collections.Immutable; - await M(ImmutableArray.Create("a")); - Console.Write(1); + await M(ImmutableArray.Create("", new('a', 10), new('a', 20), new('a', 30))); + Console.WriteLine("done"); public partial class Program { - public static void M1(bool b) { } + public static void M1(bool b) + { + Console.WriteLine(b); + } public static async Task M(ImmutableArray a) { + await Task.Yield(); foreach (var i in a) { M1(i.Length is 10 or 20 or 30); @@ -6081,7 +6085,14 @@ public static async Task M(ImmutableArray a) """; // ImmutableArray is only available when we specify a targetFramework - var comp = CompileAndVerify(source, expectedOutput: "1", options: TestOptions.ReleaseExe, targetFramework: TargetFramework.NetCoreApp); + string expectedOutput = """ + False + True + True + True + done + """; + var comp = CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics(); } } From 0294a0935d491f4e24a33bd43abb965948478893 Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Fri, 8 Mar 2024 20:24:19 +0330 Subject: [PATCH 08/13] Apply suggestion --- .../Portable/FlowAnalysis/AbstractFlowPass.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index 1786887ab08cc..661a57b78dc8b 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -3041,10 +3041,20 @@ public override BoundNode VisitConditionalReceiver(BoundConditionalReceiver node public override BoundNode VisitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node) { - var savedState = this.State.Clone(); - VisitStatements(node.Statements); - SetState(savedState); + visitLabel(node.WhenTrueLabel); + var stateWhenTrue = this.State.Clone(); + SetUnreachable(); + visitLabel(node.WhenFalseLabel); + Join(ref this.State, ref stateWhenTrue); return null; + + void visitLabel(LabelSymbol label) + { + ResolveBranches(label, null); + var state = LabelState(label); + Join(ref this.State, ref state); + _labels[label] = this.State.Clone(); + } } public override BoundNode VisitComplexConditionalReceiver(BoundComplexConditionalReceiver node) From 4f6310534952df354b3074a6e6770fac25dbba8d Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Fri, 8 Mar 2024 20:37:04 +0330 Subject: [PATCH 09/13] Revert --- src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index 661a57b78dc8b..1399688045400 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -3041,6 +3041,7 @@ public override BoundNode VisitConditionalReceiver(BoundConditionalReceiver node public override BoundNode VisitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node) { + VisitStatements(node.Statements); visitLabel(node.WhenTrueLabel); var stateWhenTrue = this.State.Clone(); SetUnreachable(); From 3fc3fbab7e7017d948534515945e0ffac1843cdb Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Thu, 21 Mar 2024 12:01:04 +0330 Subject: [PATCH 10/13] Add assert --- src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs | 2 ++ .../Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs | 1 + 2 files changed, 3 insertions(+) diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index 7dbb5a507197f..2e73432f6457e 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -882,6 +882,8 @@ private void EmitSequenceExpression(BoundSequence sequence, bool used, bool sens // CONSIDER: This will allow us to remove the below check before emitting the value. Debug.Assert(sequence.Value.Kind != BoundKind.TypeExpression || !used); + Debug.Assert(sequence.Type.SpecialType == SpecialType.System_Boolean || sense); + if (sequence.Value.Kind != BoundKind.TypeExpression) { if (used && sequence.Type.SpecialType == SpecialType.System_Boolean) diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs index ad9a07be340bc..22976a079b0f9 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IsPatternOperator.cs @@ -121,6 +121,7 @@ internal BoundExpression LowerGeneralIsPattern(BoundIsPatternExpression node, Bo // lower the decision dag. ImmutableArray loweredDag = LowerDecisionDagCore(decisionDag); + return _factory.Sequence( _tempAllocator.AllTemps(), sideEffectsBuilder.ToImmutableAndFree(), From e9ab35efb10ef7ad315490202c4c28b9dc1cf4f1 Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Thu, 21 Mar 2024 17:01:46 +0330 Subject: [PATCH 11/13] Share code --- .../Portable/FlowAnalysis/AbstractFlowPass.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index 1399688045400..b5f3e7db714c6 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -3042,20 +3042,12 @@ public override BoundNode VisitConditionalReceiver(BoundConditionalReceiver node public override BoundNode VisitLoweredIsPatternExpression(BoundLoweredIsPatternExpression node) { VisitStatements(node.Statements); - visitLabel(node.WhenTrueLabel); + VisitLabelCore(node.WhenTrueLabel); var stateWhenTrue = this.State.Clone(); SetUnreachable(); - visitLabel(node.WhenFalseLabel); + VisitLabelCore(node.WhenFalseLabel); Join(ref this.State, ref stateWhenTrue); return null; - - void visitLabel(LabelSymbol label) - { - ResolveBranches(label, null); - var state = LabelState(label); - Join(ref this.State, ref state); - _labels[label] = this.State.Clone(); - } } public override BoundNode VisitComplexConditionalReceiver(BoundComplexConditionalReceiver node) @@ -3258,13 +3250,18 @@ public override BoundNode VisitGotoStatement(BoundGotoStatement node) return null; } - protected void VisitLabel(LabelSymbol label, BoundStatement node) + private void VisitLabelCore(LabelSymbol label, BoundStatement? node = null) { - node.AssertIsLabeledStatementWithLabel(label); ResolveBranches(label, node); var state = LabelState(label); Join(ref this.State, ref state); _labels[label] = this.State.Clone(); + } + + protected void VisitLabel(LabelSymbol label, BoundStatement node) + { + node.AssertIsLabeledStatementWithLabel(label); + VisitLabelCore(label, node); _labelsSeen.Add(node); } From 37e660bdee578bf5b93348771aee53e46f31a5fc Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Thu, 21 Mar 2024 17:18:58 +0330 Subject: [PATCH 12/13] Fixup --- src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index b5f3e7db714c6..d624b90b1988f 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -3250,7 +3250,7 @@ public override BoundNode VisitGotoStatement(BoundGotoStatement node) return null; } - private void VisitLabelCore(LabelSymbol label, BoundStatement? node = null) + private void VisitLabelCore(LabelSymbol label, BoundStatement node = null) { ResolveBranches(label, node); var state = LabelState(label); From 093995dda771c74f0e871b64d3b1279f724e8f07 Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Fri, 22 Mar 2024 01:51:30 +0330 Subject: [PATCH 13/13] PR feedback --- src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index 2e73432f6457e..b5aa06a4b0d4c 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -882,8 +882,6 @@ private void EmitSequenceExpression(BoundSequence sequence, bool used, bool sens // CONSIDER: This will allow us to remove the below check before emitting the value. Debug.Assert(sequence.Value.Kind != BoundKind.TypeExpression || !used); - Debug.Assert(sequence.Type.SpecialType == SpecialType.System_Boolean || sense); - if (sequence.Value.Kind != BoundKind.TypeExpression) { if (used && sequence.Type.SpecialType == SpecialType.System_Boolean) @@ -892,6 +890,7 @@ private void EmitSequenceExpression(BoundSequence sequence, bool used, bool sens } else { + Debug.Assert(sense); EmitExpression(sequence.Value, used: used); } }