Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
7c5e8fdf
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,发现更多精彩内容 >>
未验证
提交
7c5e8fdf
编写于
8月 20, 2019
作者:
N
Neal Gafter
提交者:
GitHub
8月 20, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Handle hoisted temporary variables of the switch expression pattern-matching machinery. (#37818)
Fixes #37713
上级
6a7de5a7
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
130 addition
and
48 deletion
+130
-48
src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs
...ing/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs
+17
-43
src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs
...ring/StateMachineRewriter/MethodToStateMachineRewriter.cs
+0
-5
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncSpillTests.cs
...pilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncSpillTests.cs
+113
-0
未找到文件。
src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/IteratorAndAsyncCaptureWalker.cs
浏览文件 @
7c5e8fdf
...
...
@@ -62,7 +62,6 @@ public static OrderedSet<Symbol> Analyze(CSharpCompilation compilation, MethodSy
walker
.
CaptureVariable
(
method
.
ThisParameter
,
node
.
Syntax
);
}
var
variablesToHoist
=
walker
.
_variablesToHoist
;
var
lazyDisallowedCaptures
=
walker
.
_lazyDisallowedCaptures
;
var
allVariables
=
walker
.
variableBySlot
;
...
...
@@ -91,11 +90,10 @@ public static OrderedSet<Symbol> Analyze(CSharpCompilation compilation, MethodSy
}
}
var
variablesToHoist
=
new
OrderedSet
<
Symbol
>();
if
(
compilation
.
Options
.
OptimizationLevel
!=
OptimizationLevel
.
Release
)
{
Debug
.
Assert
(
variablesToHoist
.
Count
==
0
);
// In debug build we hoist all locals and parameters:
// In debug build we hoist long-lived locals and parameters
foreach
(
var
v
in
allVariables
)
{
var
symbol
=
v
.
Symbol
;
...
...
@@ -106,38 +104,25 @@ public static OrderedSet<Symbol> Analyze(CSharpCompilation compilation, MethodSy
}
}
// Hoist anything determined to be live across an await or yield
variablesToHoist
.
AddRange
(
walker
.
_variablesToHoist
);
return
variablesToHoist
;
}
private
static
bool
HoistInDebugBuild
(
Symbol
symbol
)
{
// in Debug build hoist all parameters that can be hoisted:
if
(
symbol
.
Kind
==
SymbolKind
.
Parameter
)
{
var
parameter
=
(
ParameterSymbol
)
symbol
;
return
!
parameter
.
TypeWithAnnotations
.
IsRestrictedType
();
}
if
(
symbol
.
Kind
==
SymbolKind
.
Local
)
return
(
symbol
)
switch
{
LocalSymbol
local
=
(
LocalSymbol
)
symbol
;
if
(
local
.
IsConst
||
local
.
IsPinned
)
{
return
false
;
}
// hoist all user-defined locals that can be hoisted:
if
(
local
.
SynthesizedKind
==
SynthesizedLocalKind
.
UserDefined
)
{
return
!
local
.
TypeWithAnnotations
.
IsRestrictedType
();
}
// hoist all synthesized variables that have to survive state machine suspension:
return
local
.
SynthesizedKind
.
MustSurviveStateMachineSuspension
();
}
return
false
;
ParameterSymbol
parameter
=>
// in Debug build hoist all parameters that can be hoisted:
!
parameter
.
Type
.
IsRestrictedType
(),
LocalSymbol
{
IsConst
:
false
,
IsPinned
:
false
}
local
=>
// hoist all user-defined locals and long-lived temps that can be hoisted:
local
.
SynthesizedKind
.
MustSurviveStateMachineSuspension
()
&&
!
local
.
Type
.
IsRestrictedType
(),
_
=>
false
};
}
private
void
MarkLocalsUnassigned
()
...
...
@@ -203,20 +188,9 @@ private void CaptureVariable(Symbol variable, SyntaxNode syntax)
var
type
=
(
variable
.
Kind
==
SymbolKind
.
Local
)
?
((
LocalSymbol
)
variable
).
Type
:
((
ParameterSymbol
)
variable
).
Type
;
if
(
type
.
IsRestrictedType
())
{
// error has already been reported.
if
(
variable
is
SynthesizedLocal
local
&&
local
.
SynthesizedKind
!=
SynthesizedLocalKind
.
Spill
)
{
return
;
}
if
(
_lazyDisallowedCaptures
==
null
)
{
_lazyDisallowedCaptures
=
new
MultiDictionary
<
Symbol
,
SyntaxNode
>();
}
_lazyDisallowedCaptures
.
Add
(
variable
,
syntax
);
(
_lazyDisallowedCaptures
??=
new
MultiDictionary
<
Symbol
,
SyntaxNode
>()).
Add
(
variable
,
syntax
);
}
else
if
(
compilation
.
Options
.
OptimizationLevel
==
OptimizationLevel
.
Release
)
else
{
_variablesToHoist
.
Add
(
variable
);
}
...
...
src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs
浏览文件 @
7c5e8fdf
...
...
@@ -273,8 +273,6 @@ private BoundStatement PossibleIteratorScope(ImmutableArray<LocalSymbol> locals,
continue
;
}
Debug
.
Assert
(
local
.
SynthesizedKind
.
IsLongLived
());
CapturedSymbolReplacement
proxy
;
bool
reused
=
false
;
if
(!
proxies
.
TryGetValue
(
local
,
out
proxy
))
...
...
@@ -414,9 +412,6 @@ private bool MightContainReferences(TypeSymbol type)
private
StateMachineFieldSymbol
GetOrAllocateReusableHoistedField
(
TypeSymbol
type
,
out
bool
reused
,
LocalSymbol
local
=
null
)
{
// In debug builds we don't reuse any hoisted variable.
Debug
.
Assert
(
F
.
Compilation
.
Options
.
OptimizationLevel
==
OptimizationLevel
.
Release
);
ArrayBuilder
<
StateMachineFieldSymbol
>
fields
;
if
(
_lazyAvailableReusableHoistedFields
!=
null
&&
_lazyAvailableReusableHoistedFields
.
TryGetValue
(
type
,
out
fields
)
&&
fields
.
Count
>
0
)
{
...
...
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncSpillTests.cs
浏览文件 @
7c5e8fdf
...
...
@@ -3596,5 +3596,118 @@ static async Task Main()
);
}
}
[
Fact
]
public
void
SpillStateMachineTemps
()
{
var
source
=
@"using System;
using System.Threading.Tasks;
public class C {
public static void Main()
{
Console.WriteLine(M1(new Q(), SF()).Result);
}
public static async Task<int> M1(object o, Task<bool> c)
{
return o switch
{
Q { F: { P1: true } } when await c => 1, // cached Q.F is alive
Q { F: { P2: true } } => 2,
_ => 3,
};
}
public static async Task<bool> SF()
{
await Task.Delay(10);
return false;
}
}
class Q
{
public F F => new F(true);
}
struct F
{
bool _result;
public F(bool result)
{
_result = result;
}
public bool P1 => _result;
public bool P2 => _result;
}
"
;
CompileAndVerify
(
source
,
options
:
TestOptions
.
ReleaseExe
,
expectedOutput
:
"2"
);
CompileAndVerify
(
source
,
options
:
TestOptions
.
DebugExe
,
expectedOutput
:
"2"
);
}
[
Fact
]
[
WorkItem
(
37713
,
"https://github.com/dotnet/roslyn/issues/37713"
)]
public
void
RefStructInAsyncStateMachineWithWhenClause
()
{
var
source
=
@"
using System.Threading.Tasks;
class Program
{
async Task<int> M1(object o, Task<bool> c, int r)
{
return o switch
{
Q { F: { P1: true } } when await c => r, // error: cached Q.F is alive
Q { F: { P2: true } } => 2,
_ => 3,
};
}
async Task<int> M2(object o, Task<bool> c, int r)
{
return o switch
{
Q { F: { P1: true } } when await c => r, // ok: only Q.P1 is live
Q { F: { P1: true } } => 2,
_ => 3,
};
}
async Task<int> M3(object o, bool c, Task<int> r)
{
return o switch
{
Q { F: { P1: true } } when c => await r, // ok: nothing alive at await
Q { F: { P2: true } } => 2,
_ => 3,
};
}
async Task<int> M4(object o, Task<bool> c, int r)
{
return o switch
{
Q { F: { P1: true } } when await c => r, // ok: no switch state is alive
_ => 3,
};
}
}
public class Q
{
public S F => throw null!;
}
public ref struct S
{
public bool P1 => true;
public bool P2 => true;
}
"
;
CreateCompilation
(
source
,
options
:
TestOptions
.
DebugDll
).
VerifyDiagnostics
().
VerifyEmitDiagnostics
(
// (9,20): error CS4013: Instance of type 'S' cannot be used inside a nested function, query expression, iterator block or async method
// Q { F: { P1: true } } when await c => r, // error: cached Q.F is alive
Diagnostic
(
ErrorCode
.
ERR_SpecialByRefInLambda
,
"{ P1: true }"
).
WithArguments
(
"S"
).
WithLocation
(
9
,
20
)
);
CreateCompilation
(
source
,
options
:
TestOptions
.
ReleaseDll
).
VerifyDiagnostics
().
VerifyEmitDiagnostics
(
// (9,20): error CS4013: Instance of type 'S' cannot be used inside a nested function, query expression, iterator block or async method
// Q { F: { P1: true } } when await c => r, // error: cached Q.F is alive
Diagnostic
(
ErrorCode
.
ERR_SpecialByRefInLambda
,
"{ P1: true }"
).
WithArguments
(
"S"
).
WithLocation
(
9
,
20
)
);
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录