Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
33d76271
R
roslyn
项目概览
lwm1986
/
roslyn
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
roslyn
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
33d76271
编写于
10月 25, 2015
作者:
N
Neal Gafter
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Binding pattern-matching switch. Not passing all tests. Lowering still needed.
上级
d4f3f34d
变更
14
隐藏空白更改
内联
并排
Showing
14 changed file
with
291 addition
and
134 deletion
+291
-134
src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
+1
-1
src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
+1
-1
src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs
src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs
+3
-1
src/Compilers/CSharp/Portable/Binder/PatternVariableBinder.cs
...Compilers/CSharp/Portable/Binder/PatternVariableBinder.cs
+39
-2
src/Compilers/CSharp/Portable/Binder/SwitchBinder.cs
src/Compilers/CSharp/Portable/Binder/SwitchBinder.cs
+5
-3
src/Compilers/CSharp/Portable/Binder/SwitchBinder_BindPatternSwitch.cs
.../CSharp/Portable/Binder/SwitchBinder_BindPatternSwitch.cs
+14
-13
src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
+1
-0
src/Compilers/CSharp/Portable/CSharpCodeAnalysis.csproj
src/Compilers/CSharp/Portable/CSharpCodeAnalysis.csproj
+2
-1
src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
...pilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
+18
-0
src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs
...s/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs
+0
-108
src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass_Switch.cs
...p/Portable/FlowAnalysis/PreciseAbstractFlowPass_Switch.cs
+192
-0
src/Compilers/CSharp/Portable/Syntax/LookupPosition.cs
src/Compilers/CSharp/Portable/Syntax/LookupPosition.cs
+10
-0
src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs
src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs
+2
-1
src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs
...rs/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs
+3
-3
未找到文件。
src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
浏览文件 @
33d76271
...
...
@@ -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
())
{
...
...
src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
浏览文件 @
33d76271
...
...
@@ -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;
...
...
src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs
浏览文件 @
33d76271
...
...
@@ -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
);
}
}
...
...
src/Compilers/CSharp/Portable/Binder/PatternVariableBinder.cs
浏览文件 @
33d76271
...
...
@@ -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
);
...
...
src/Compilers/CSharp/Portable/Binder/SwitchBinder.cs
浏览文件 @
33d76271
...
...
@@ -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
(
original
Binder
.
BindStatement
(
statement
,
diagnostics
));
boundStatementsBuilder
.
Add
(
section
Binder
.
BindStatement
(
statement
,
diagnostics
));
}
return
new
BoundSwitchSection
(
node
,
boundLabelsBuilder
.
ToImmutableAndFree
(),
boundStatementsBuilder
.
ToImmutableAndFree
());
...
...
src/Compilers/CSharp/Portable/Binder/SwitchBinder_BindPatternSwitch.cs
浏览文件 @
33d76271
...
...
@@ -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
,
o
riginalBinder
,
o
ut
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
(
original
Binder
.
BindStatement
(
statement
,
diagnostics
));
boundStatementsBuilder
.
Add
(
section
Binder
.
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
);
...
...
src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
浏览文件 @
33d76271
...
...
@@ -689,6 +689,7 @@
</Node>
<Node
Name=
"BoundMatchSection"
Base=
"BoundStatementList"
>
<Field
Name=
"Locals"
Type=
"ImmutableArray<LocalSymbol>"
/>
<Field
Name=
"BoundMatchLabels"
Type=
"ImmutableArray<BoundMatchLabel>"
/>
</Node>
...
...
src/Compilers/CSharp/Portable/CSharpCodeAnalysis.csproj
浏览文件 @
33d76271
...
...
@@ -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
src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
浏览文件 @
33d76271
...
...
@@ -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
...
...
src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs
浏览文件 @
33d76271
...
...
@@ -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
);
...
...
src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass_Switch.cs
0 → 100644
浏览文件 @
33d76271
// 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
);
}
}
}
src/Compilers/CSharp/Portable/Syntax/LookupPosition.cs
浏览文件 @
33d76271
...
...
@@ -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.
...
...
src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs
浏览文件 @
33d76271
...
...
@@ -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>
...
...
src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs
浏览文件 @
33d76271
...
...
@@ -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 ye
t implemented"
)]
[
Fact
(
Skip
=
"
Lowering no
t 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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录