提交 33d76271 编写于 作者: N Neal Gafter

Binding pattern-matching switch. Not passing all tests. Lowering still needed.

上级 d4f3f34d
......@@ -20,7 +20,7 @@ private BoundExpression BindIsPatternExpression(IsPatternExpressionSyntax node,
return new BoundIsPatternExpression(node, expression, pattern, GetSpecialType(SpecialType.System_Boolean, diagnostics, node), hasErrors);
}
protected BoundPattern BindPattern(PatternSyntax node, BoundExpression operand, TypeSymbol operandType, bool hasErrors, DiagnosticBag diagnostics)
internal BoundPattern BindPattern(PatternSyntax node, BoundExpression operand, TypeSymbol operandType, bool hasErrors, DiagnosticBag diagnostics)
{
switch (node.Kind())
{
......
......@@ -2545,7 +2545,7 @@ private BoundStatement BindIfStatement(IfStatementSyntax node, DiagnosticBag dia
return result;
}
protected BoundExpression BindBooleanExpression(ExpressionSyntax node, DiagnosticBag diagnostics)
internal BoundExpression BindBooleanExpression(ExpressionSyntax node, DiagnosticBag diagnostics)
{
// SPEC:
// A boolean-expression is an expression that yields a result of type bool;
......
......@@ -324,9 +324,11 @@ public override void VisitSwitchStatement(SwitchStatementSyntax node)
public override void VisitSwitchSection(SwitchSectionSyntax node)
{
var patternBinder = new PatternVariableBinder(node, _enclosing);
AddToMap(node, patternBinder);
foreach (StatementSyntax statement in node.Statements)
{
Visit(statement, _enclosing);
Visit(statement, patternBinder);
}
}
......
......@@ -13,6 +13,7 @@ internal sealed class PatternVariableBinder : LocalScopeBinder
{
private readonly ExpressionSyntax expression;
private readonly ImmutableArray<ExpressionSyntax> expressions;
private readonly ImmutableArray<PatternSyntax> patterns;
public readonly SyntaxNode Syntax;
internal PatternVariableBinder(SyntaxNode syntax, ImmutableArray<ExpressionSyntax> expressions, Binder next) : base(next)
......@@ -45,6 +46,28 @@ internal PatternVariableBinder(SyntaxNode syntax, IEnumerable<ArgumentSyntax> ar
this.expressions = expressions.ToImmutableAndFree();
}
internal PatternVariableBinder(SwitchSectionSyntax syntax, Binder next) : base(next)
{
this.Syntax = syntax;
var expressions = ArrayBuilder<ExpressionSyntax>.GetInstance();
var patterns = ArrayBuilder<PatternSyntax>.GetInstance();
foreach (var label in syntax.Labels)
{
var match = label as CaseMatchLabelSyntax;
if (match != null)
{
patterns.Add(match.Pattern);
if (match.Condition != null)
{
expressions.Add(match.Condition);
}
}
}
this.expressions = expressions.ToImmutableAndFree();
this.patterns = patterns.ToImmutableAndFree();
}
internal PatternVariableBinder(ForStatementSyntax syntax, Binder next) : base(next)
{
this.Syntax = syntax;
......@@ -68,7 +91,7 @@ internal PatternVariableBinder(SyntaxNode syntax, ExpressionSyntax expression, B
protected override ImmutableArray<LocalSymbol> BuildLocals()
{
var patterns = PatternVariableFinder.FindPatternVariables(expression, expressions);
var patterns = PatternVariableFinder.FindPatternVariables(expression, expressions, this.patterns);
var builder = ArrayBuilder<LocalSymbol>.GetInstance();
foreach (var pattern in patterns)
{
......@@ -88,7 +111,10 @@ internal BoundExpression WrapWithPatternVariables(BoundExpression expression)
class PatternVariableFinder : CSharpSyntaxWalker
{
ArrayBuilder<DeclarationPatternSyntax> declarationPatterns = ArrayBuilder<DeclarationPatternSyntax>.GetInstance();
internal static ArrayBuilder<DeclarationPatternSyntax> FindPatternVariables(ExpressionSyntax expression, ImmutableArray<ExpressionSyntax> expressions)
internal static ArrayBuilder<DeclarationPatternSyntax> FindPatternVariables(
ExpressionSyntax expression,
ImmutableArray<ExpressionSyntax> expressions,
ImmutableArray<PatternSyntax> patterns)
{
var finder = s_poolInstance.Allocate();
finder.declarationPatterns = ArrayBuilder<DeclarationPatternSyntax>.GetInstance();
......@@ -97,11 +123,22 @@ internal static ArrayBuilder<DeclarationPatternSyntax> FindPatternVariables(Expr
{
finder.Visit(subExpression);
}
var result = finder.declarationPatterns;
if (patterns != null)
{
foreach (var pattern in patterns)
{
var declarationPattern = pattern as DeclarationPatternSyntax;
if (declarationPattern != null) result.Add(declarationPattern);
}
}
finder.declarationPatterns = null;
s_poolInstance.Free(finder);
return result;
}
public override void VisitDeclarationPattern(DeclarationPatternSyntax node)
{
declarationPatterns.Add(node);
......
......@@ -298,7 +298,7 @@ internal override BoundStatement BindSwitchExpressionAndSections(SwitchStatement
{
_isPatternSwitch = true;
return (Compilation.Feature("patterns") != null)
? (BoundStatement)BindPatternSwitch(node, originalBinder, diagnostics)
? (BoundStatement)BindPatternSwitch(node, diagnostics)
: new BoundBlock(node, ImmutableArray<LocalSymbol>.Empty, ImmutableArray<LocalFunctionSymbol>.Empty, ImmutableArray<BoundStatement>.Empty, true);
}
......@@ -309,7 +309,7 @@ internal override BoundStatement BindSwitchExpressionAndSections(SwitchStatement
if (localDiagnostics.HasAnyResolvedErrors() && Compilation.Feature("patterns") != null)
{
_isPatternSwitch = true;
return BindPatternSwitch(node, originalBinder, diagnostics);
return BindPatternSwitch(node, diagnostics);
}
_isPatternSwitch = false;
diagnostics.AddRangeAndFree(localDiagnostics);
......@@ -470,6 +470,8 @@ private ImmutableArray<BoundSwitchSection> BindSwitchSections(SyntaxList<SwitchS
private BoundSwitchSection BindSwitchSection(SwitchSectionSyntax node, Binder originalBinder, DiagnosticBag diagnostics)
{
var sectionBinder = GetBinder(node);
// Bind switch section labels
var boundLabelsBuilder = ArrayBuilder<BoundSwitchLabel>.GetInstance();
foreach (var labelSyntax in node.Labels)
......@@ -482,7 +484,7 @@ private BoundSwitchSection BindSwitchSection(SwitchSectionSyntax node, Binder or
var boundStatementsBuilder = ArrayBuilder<BoundStatement>.GetInstance();
foreach (var statement in node.Statements)
{
boundStatementsBuilder.Add(originalBinder.BindStatement(statement, diagnostics));
boundStatementsBuilder.Add(sectionBinder.BindStatement(statement, diagnostics));
}
return new BoundSwitchSection(node, boundLabelsBuilder.ToImmutableAndFree(), boundStatementsBuilder.ToImmutableAndFree());
......
......@@ -14,20 +14,20 @@ namespace Microsoft.CodeAnalysis.CSharp
{
internal partial class SwitchBinder
{
private BoundMatchStatement BindPatternSwitch(SwitchStatementSyntax node, Binder originalBinder, DiagnosticBag diagnostics)
private BoundMatchStatement BindPatternSwitch(SwitchStatementSyntax node, DiagnosticBag diagnostics)
{
var boundSwitchExpression = BindValue(node.Expression, diagnostics, BindValueKind.RValue);
// TODO: any constraints on a switch expression must be enforced here. For example,
// it must have a type (not be target-typed, lambda, null, etc)
GeneratedLabelSymbol defaultLabelSymbol;
ImmutableArray<BoundMatchSection> boundMatchSections = BindMatchSections(boundSwitchExpression, node.Sections, originalBinder, out defaultLabelSymbol, diagnostics);
ImmutableArray<BoundMatchSection> boundMatchSections = BindMatchSections(boundSwitchExpression, node.Sections, out defaultLabelSymbol, diagnostics);
return new BoundMatchStatement(node, boundSwitchExpression, Locals, LocalFunctions, boundMatchSections, this.BreakLabel, defaultLabelSymbol);
throw new NotImplementedException("switch binder for pattern matching");
}
private ImmutableArray<BoundMatchSection> BindMatchSections(BoundExpression boundSwitchExpression, SyntaxList<SwitchSectionSyntax> sections, Binder originalBinder, out GeneratedLabelSymbol defaultLabelSymbol, DiagnosticBag diagnostics)
private ImmutableArray<BoundMatchSection> BindMatchSections(BoundExpression boundSwitchExpression, SyntaxList<SwitchSectionSyntax> sections, out GeneratedLabelSymbol defaultLabelSymbol, DiagnosticBag diagnostics)
{
defaultLabelSymbol = null;
......@@ -35,20 +35,21 @@ private ImmutableArray<BoundMatchSection> BindMatchSections(BoundExpression boun
var boundMatchSectionsBuilder = ArrayBuilder<BoundMatchSection>.GetInstance();
foreach (var sectionSyntax in sections)
{
boundMatchSectionsBuilder.Add(BindMatchSection(boundSwitchExpression, sectionSyntax, originalBinder, ref defaultLabelSymbol, diagnostics));
boundMatchSectionsBuilder.Add(BindMatchSection(boundSwitchExpression, sectionSyntax, ref defaultLabelSymbol, diagnostics));
}
return boundMatchSectionsBuilder.ToImmutableAndFree();
}
private BoundMatchSection BindMatchSection(BoundExpression boundSwitchExpression, SwitchSectionSyntax node, Binder originalBinder, ref GeneratedLabelSymbol defaultLabelSymbol, DiagnosticBag diagnostics)
private BoundMatchSection BindMatchSection(BoundExpression boundSwitchExpression, SwitchSectionSyntax node, ref GeneratedLabelSymbol defaultLabelSymbol, DiagnosticBag diagnostics)
{
// Bind match section labels
var boundLabelsBuilder = ArrayBuilder<BoundMatchLabel>.GetInstance();
var labelSymbol = new GeneratedLabelSymbol("case");
var sectionBinder = (PatternVariableBinder)this.GetBinder(node); // this binder can bind pattern variables from the section.
foreach (var labelSyntax in node.Labels)
{
BoundMatchLabel boundLabel = BindMatchSectionLabel(boundSwitchExpression, labelSymbol, labelSyntax, ref defaultLabelSymbol, diagnostics);
BoundMatchLabel boundLabel = BindMatchSectionLabel(sectionBinder, boundSwitchExpression, labelSymbol, labelSyntax, ref defaultLabelSymbol, diagnostics);
boundLabelsBuilder.Add(boundLabel);
}
......@@ -56,28 +57,28 @@ private BoundMatchSection BindMatchSection(BoundExpression boundSwitchExpression
var boundStatementsBuilder = ArrayBuilder<BoundStatement>.GetInstance();
foreach (var statement in node.Statements)
{
boundStatementsBuilder.Add(originalBinder.BindStatement(statement, diagnostics));
boundStatementsBuilder.Add(sectionBinder.BindStatement(statement, diagnostics));
}
return new BoundMatchSection(node, boundLabelsBuilder.ToImmutableAndFree(), boundStatementsBuilder.ToImmutableAndFree());
return new BoundMatchSection(node, sectionBinder.Locals, boundLabelsBuilder.ToImmutableAndFree(), boundStatementsBuilder.ToImmutableAndFree());
}
private BoundMatchLabel BindMatchSectionLabel(BoundExpression boundSwitchExpression, GeneratedLabelSymbol labelSym, SwitchLabelSyntax node, ref GeneratedLabelSymbol defaultLabelSymbol, DiagnosticBag diagnostics)
private static BoundMatchLabel BindMatchSectionLabel(Binder sectionBinder, BoundExpression boundSwitchExpression, GeneratedLabelSymbol labelSym, SwitchLabelSyntax node, ref GeneratedLabelSymbol defaultLabelSymbol, DiagnosticBag diagnostics)
{
switch (node.Kind())
{
case SyntaxKind.CaseMatchLabel:
{
var matchLabelSyntax = (CaseMatchLabelSyntax)node;
return new BoundMatchLabel(node, labelSym,
BindPattern(matchLabelSyntax.Pattern, boundSwitchExpression, boundSwitchExpression.Type, node.HasErrors, diagnostics),
matchLabelSyntax.Condition != null ? BindBooleanExpression(matchLabelSyntax.Condition, diagnostics) : null, node.HasErrors);
return new BoundMatchLabel(node, labelSym,
sectionBinder.BindPattern(matchLabelSyntax.Pattern, boundSwitchExpression, boundSwitchExpression.Type, node.HasErrors, diagnostics),
matchLabelSyntax.Condition != null ? sectionBinder.BindBooleanExpression(matchLabelSyntax.Condition, diagnostics) : null, node.HasErrors);
}
case SyntaxKind.CaseSwitchLabel:
{
var caseLabelSyntax = (CaseSwitchLabelSyntax)node;
var boundLabelExpression = BindValue(caseLabelSyntax.Value, diagnostics, BindValueKind.RValue);
var boundLabelExpression = sectionBinder.BindValue(caseLabelSyntax.Value, diagnostics, BindValueKind.RValue);
// TODO: check compatibility of the bound switch expression with the label
// TODO: check that it is a constant.
var pattern = new BoundConstantPattern(node, boundLabelExpression, node.HasErrors);
......
......@@ -689,6 +689,7 @@
</Node>
<Node Name="BoundMatchSection" Base="BoundStatementList">
<Field Name="Locals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<Field Name="BoundMatchLabels" Type="ImmutableArray&lt;BoundMatchLabel&gt;"/>
</Node>
......
......@@ -371,6 +371,7 @@
<Compile Include="FlowAnalysis\FlowAnalysisPass.cs" />
<Compile Include="FlowAnalysis\PreciseAbstractFlowPass.AbstractLocalState.cs" />
<Compile Include="FlowAnalysis\PreciseAbstractFlowPass.cs" />
<Compile Include="FlowAnalysis\PreciseAbstractFlowPass_Switch.cs" />
<Compile Include="FlowAnalysis\ReadWriteWalker.cs" />
<Compile Include="FlowAnalysis\RegionAnalysisContext.cs" />
<Compile Include="FlowAnalysis\RegionReachableWalker.cs" />
......@@ -905,4 +906,4 @@
<ImportGroup Label="Targets">
<Import Project="..\..\..\..\build\Targets\VSL.Imports.targets" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
......@@ -208,6 +208,13 @@ private Binder GetEnclosingBinder(CSharpSyntaxNode node, int position)
typeOfArgument = typeOfExpression.Type;
typeOfEncounteredBeforeUnexpectedAnonymousFunction = unexpectedAnonymousFunction == null;
}
else if (current.Kind() == SyntaxKind.SwitchSection)
{
if (LookupPosition.IsInSwitchSectionScope(position, (SwitchSectionSyntax)current))
{
binder = RootBinder.GetBinder(current);
}
}
else
{
// If this ever breaks, make sure that all callers of
......@@ -1371,6 +1378,17 @@ private static Binder GetLambdaEnclosingBinder(int position, CSharpSyntaxNode st
}
}
}
else if (current.Kind() == SyntaxKind.SwitchSection)
{
if (LookupPosition.IsInSwitchSectionScope(position, (SwitchSectionSyntax)current))
{
Binder binder = lambdaBinder.GetBinder(current);
if (binder != null)
{
return binder;
}
}
}
else
{
// If this ever breaks, make sure that all callers of
......
......@@ -1633,109 +1633,6 @@ public override BoundNode VisitWhileStatement(BoundWhileStatement node)
return null;
}
public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
{
// visit switch header
LocalState breakState = VisitSwitchHeader(node);
SetUnreachable();
// visit switch block
VisitSwitchBlock(node);
IntersectWith(ref breakState, ref this.State);
ResolveBreaks(breakState, node.BreakLabel);
return null;
}
private LocalState VisitSwitchHeader(BoundSwitchStatement node)
{
// Initial value for the Break state for a switch statement is established as follows:
// Break state = UnreachableState if either of the following is true:
// (1) there is a default label, or
// (2) the switch expression is constant and there is a matching case label.
// Otherwise, the Break state = current state.
// visit switch expression
VisitRvalue(node.BoundExpression);
LocalState breakState = this.State;
// For a switch statement, we simulate a possible jump to the switch labels to ensure that
// the label is not treated as an unused label and a pending branch to the label is noted.
// However, if switch expression is a constant, we must have determined the single target label
// at bind time, i.e. node.ConstantTargetOpt, and we must simulate a jump only to this label.
var constantTargetOpt = node.ConstantTargetOpt;
if ((object)constantTargetOpt == null)
{
bool hasDefaultLabel = false;
foreach (var section in node.SwitchSections)
{
foreach (var boundSwitchLabel in section.BoundSwitchLabels)
{
var label = boundSwitchLabel.Label;
hasDefaultLabel = hasDefaultLabel || label.IdentifierNodeOrToken.Kind() == SyntaxKind.DefaultSwitchLabel;
SetState(breakState.Clone());
var simulatedGoto = new BoundGotoStatement(node.Syntax, label);
VisitGotoStatement(simulatedGoto);
}
}
if (hasDefaultLabel)
{
// Condition (1) for an unreachable break state is satisfied
breakState = UnreachableState();
}
}
else if (!node.BreakLabel.Equals(constantTargetOpt))
{
SetState(breakState.Clone());
var simulatedGoto = new BoundGotoStatement(node.Syntax, constantTargetOpt);
VisitGotoStatement(simulatedGoto);
// Condition (1) or (2) for an unreachable break state is satisfied
breakState = UnreachableState();
}
return breakState;
}
private void VisitSwitchBlock(BoundSwitchStatement node)
{
var afterSwitchState = UnreachableState();
var switchSections = node.SwitchSections;
var iLastSection = (switchSections.Length - 1);
// visit switch sections
for (var iSection = 0; iSection <= iLastSection; iSection++)
{
VisitSwitchSection(switchSections[iSection], iSection == iLastSection);
// Even though it is illegal for the end of a switch section to be reachable, in erroneous
// code it may be reachable. We treat that as an implicit break (branch to afterSwitchState).
IntersectWith(ref afterSwitchState, ref this.State);
}
SetState(afterSwitchState);
}
public virtual BoundNode VisitSwitchSection(BoundSwitchSection node, bool lastSection)
{
return VisitSwitchSection(node);
}
public override BoundNode VisitSwitchSection(BoundSwitchSection node)
{
// visit switch section labels
foreach (var boundSwitchLabel in node.BoundSwitchLabels)
{
VisitRvalue(boundSwitchLabel.ExpressionOpt);
VisitSwitchSectionLabel(boundSwitchLabel.Label, node);
}
// visit switch section body
VisitStatementList(node);
return null;
}
public override BoundNode VisitArrayAccess(BoundArrayAccess node)
{
VisitRvalue(node.Expression);
......@@ -2306,11 +2203,6 @@ protected virtual void VisitLabel(BoundLabeledStatement node)
VisitLabel(node.Label, node);
}
protected virtual void VisitSwitchSectionLabel(LabelSymbol label, BoundSwitchSection node)
{
VisitLabel(label, node);
}
public override BoundNode VisitLabelStatement(BoundLabelStatement node)
{
VisitLabel(node.Label, node);
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
internal abstract partial class PreciseAbstractFlowPass<LocalState>
{
public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
{
// visit switch header
LocalState breakState = VisitSwitchHeader(node);
SetUnreachable();
// visit switch block
VisitSwitchBlock(node);
IntersectWith(ref breakState, ref this.State);
ResolveBreaks(breakState, node.BreakLabel);
return null;
}
private LocalState VisitSwitchHeader(BoundSwitchStatement node)
{
// Initial value for the Break state for a switch statement is established as follows:
// Break state = UnreachableState if either of the following is true:
// (1) there is a default label, or
// (2) the switch expression is constant and there is a matching case label.
// Otherwise, the Break state = current state.
// visit switch expression
VisitRvalue(node.BoundExpression);
LocalState breakState = this.State;
// For a switch statement, we simulate a possible jump to the switch labels to ensure that
// the label is not treated as an unused label and a pending branch to the label is noted.
// However, if switch expression is a constant, we must have determined the single target label
// at bind time, i.e. node.ConstantTargetOpt, and we must simulate a jump only to this label.
var constantTargetOpt = node.ConstantTargetOpt;
if ((object)constantTargetOpt == null)
{
bool hasDefaultLabel = false;
foreach (var section in node.SwitchSections)
{
foreach (var boundSwitchLabel in section.BoundSwitchLabels)
{
var label = boundSwitchLabel.Label;
hasDefaultLabel = hasDefaultLabel || label.IdentifierNodeOrToken.Kind() == SyntaxKind.DefaultSwitchLabel;
SetState(breakState.Clone());
var simulatedGoto = new BoundGotoStatement(node.Syntax, label);
VisitGotoStatement(simulatedGoto);
}
}
if (hasDefaultLabel)
{
// Condition (1) for an unreachable break state is satisfied
breakState = UnreachableState();
}
}
else if (!node.BreakLabel.Equals(constantTargetOpt))
{
SetState(breakState.Clone());
var simulatedGoto = new BoundGotoStatement(node.Syntax, constantTargetOpt);
VisitGotoStatement(simulatedGoto);
// Condition (1) or (2) for an unreachable break state is satisfied
breakState = UnreachableState();
}
return breakState;
}
private void VisitSwitchBlock(BoundSwitchStatement node)
{
var afterSwitchState = UnreachableState();
var switchSections = node.SwitchSections;
var iLastSection = (switchSections.Length - 1);
// visit switch sections
for (var iSection = 0; iSection <= iLastSection; iSection++)
{
VisitSwitchSection(switchSections[iSection], iSection == iLastSection);
// Even though it is illegal for the end of a switch section to be reachable, in erroneous
// code it may be reachable. We treat that as an implicit break (branch to afterSwitchState).
IntersectWith(ref afterSwitchState, ref this.State);
}
SetState(afterSwitchState);
}
public virtual BoundNode VisitSwitchSection(BoundSwitchSection node, bool lastSection)
{
return VisitSwitchSection(node);
}
public override BoundNode VisitSwitchSection(BoundSwitchSection node)
{
// visit switch section labels
foreach (var boundSwitchLabel in node.BoundSwitchLabels)
{
VisitRvalue(boundSwitchLabel.ExpressionOpt);
VisitSwitchSectionLabel(boundSwitchLabel.Label, node);
}
// visit switch section body
VisitStatementList(node);
return null;
}
protected virtual void VisitSwitchSectionLabel(LabelSymbol label, BoundSwitchSection node)
{
VisitLabel(label, node);
}
// ===========================
// Below here is the implementation for the pattern-matching variation of the switch statement.
// ===========================
public override BoundNode VisitMatchStatement(BoundMatchStatement node)
{
// visit switch header
LocalState breakState = VisitMatchHeader(node);
// visit switch block
VisitMatchBlock(node);
IntersectWith(ref breakState, ref this.State);
ResolveBreaks(breakState, node.BreakLabel);
return null;
}
private void VisitMatchBlock(BoundMatchStatement node)
{
var afterSwitchState = UnreachableState();
var switchSections = node.MatchSections;
var iLastSection = (switchSections.Length - 1);
var dispatchState = State.Clone();
// visit switch sections
for (var iSection = 0; iSection <= iLastSection; iSection++)
{
SetState(dispatchState);
VisitMatchSection(switchSections[iSection], iSection == iLastSection);
// Even though it is illegal for the end of a switch section to be reachable, in erroneous
// code it may be reachable. We treat that as an implicit break (branch to afterSwitchState).
IntersectWith(ref afterSwitchState, ref this.State);
}
SetState(afterSwitchState);
}
private LocalState VisitMatchHeader(BoundMatchStatement node)
{
// Initial value for the Break state for a switch statement is established as follows:
// Break state = UnreachableState if either of the following is true:
// (1) there is a default label, or
// (2) the switch expression is constant and there is a matching case label.
// Otherwise, the Break state = current state.
// visit switch expression
VisitRvalue(node.BoundExpression);
LocalState breakState = this.State;
// TODO: handle the switch expression being a constant.
return breakState;
}
private void VisitMatchSection(BoundMatchSection node, bool v)
{
// visit switch section labels
foreach (var label in node.BoundMatchLabels)
{
// VisitPattern(label.Pattern); // TODO: implement this
VisitRvalue(label.Guard);
}
// visit switch section body
VisitStatementList(node);
}
}
}
......@@ -233,6 +233,16 @@ internal static bool IsInStatementScope(int position, StatementSyntax statement)
IsBetweenTokens(position, firstIncludedToken, GetFirstExcludedToken(statement));
}
/// <remarks>
/// Used to determine whether it would be appropriate to use the binder for the switch section (if any).
/// Not used to determine whether the position is syntactically within the statement.
/// </remarks>
internal static bool IsInSwitchSectionScope(int position, SwitchSectionSyntax section)
{
Debug.Assert(section != null);
return section.Span.Contains(position);
}
/// <remarks>
/// Used to determine whether it would be appropriate to use the binder for the statement (if any).
/// Not used to determine whether the position is syntactically within the statement.
......
......@@ -61,9 +61,10 @@ public static bool IsQuery(this CSharpSyntaxNode syntax)
internal static bool CanHaveAssociatedLocalBinder(this CSharpSyntaxNode syntax)
{
return syntax.IsAnonymousFunction() ||
syntax is StatementSyntax ||
syntax.Kind() == SyntaxKind.CatchClause ||
syntax.Kind() == SyntaxKind.CatchFilterClause ||
syntax is StatementSyntax;
syntax.Kind() == SyntaxKind.SwitchSection;
}
/// <summary>
......
......@@ -495,7 +495,7 @@ private static bool M(object o, bool result)
var comp = CompileAndVerify(compilation, expectedOutput: expectedOutput);
}
[Fact(Skip = "pattern-based switch is not yet implemented")]
[Fact(Skip = "Lowering not implemented")]
public void GeneralizedSwitchStatement()
{
var source =
......@@ -524,8 +524,8 @@ public static void Main()
case null:
Console.WriteLine($""null"");
break;
case object o:
Console.WriteLine($""object {typeof(o).Name} {s}"");
case object z:
Console.WriteLine($""object {z.GetType().Name} {z}"");
break;
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册