Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
81166360
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,发现更多精彩内容 >>
提交
81166360
编写于
4月 08, 2015
作者:
V
VSadov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Added more tests for ?. codegen and fixed some issues that were uncovered.
上级
8f49b0ed
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
330 addition
and
23 deletion
+330
-23
src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
+1
-1
src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
+11
-0
src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
+1
-1
src/Compilers/CSharp/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs
...p/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs
+6
-2
src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AwaitExpressionSpiller.cs
...Portable/Lowering/AsyncRewriter/AwaitExpressionSpiller.cs
+21
-11
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
...le/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
+2
-1
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs
...Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs
+13
-7
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullCoalescingOperator.cs
...ing/LocalRewriter/LocalRewriter_NullCoalescingOperator.cs
+1
-0
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs
...arp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs
+274
-0
未找到文件。
src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
浏览文件 @
81166360
...
...
@@ -6437,7 +6437,7 @@ private BoundExpression GetReceiverForConditionalBinding(ExpressionSyntax bindin
receiverType
=
receiverType
.
GetNullableUnderlyingType
();
}
receiver
=
new
BoundConditionalReceiver
(
receiver
.
Syntax
,
receiverType
)
{
WasCompilerGenerated
=
true
};
receiver
=
new
BoundConditionalReceiver
(
receiver
.
Syntax
,
0
,
receiverType
)
{
WasCompilerGenerated
=
true
};
return
receiver
;
}
...
...
src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
浏览文件 @
81166360
...
...
@@ -973,11 +973,22 @@
<Field
Name=
"Receiver"
Type=
"BoundExpression"
/>
<Field
Name=
"WhenNotNull"
Type=
"BoundExpression"
/>
<Field
Name=
"WhenNullOpt"
Type=
"BoundExpression"
Null=
"allow"
/>
<!--
Async rewriter needs to replace receivers with their spilled values
and for that it needs to match receivers and the containing conditional
expressions.
To be able to do that, during lowering, we will assign
BoundLoweredConditionalAccess and corresponding BoundConditionalReceiver
matching ID that are integers unique for the containing method body.
-->
<Field
Name=
"ID"
Type=
"int"
/>
</Node>
<!-- represents the receiver of a conditional access expression -->
<Node
Name=
"BoundConditionalReceiver"
Base=
"BoundExpression"
>
<Field
Name=
"Type"
Type=
"TypeSymbol"
Override=
"true"
Null=
"disallow"
/>
<!-- See the comment in BoundLoweredConditionalAccess -->
<Field
Name=
"ID"
Type=
"int"
/>
</Node>
<!-- This node represents a complex receiver for a conditional access.
...
...
src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
浏览文件 @
81166360
...
...
@@ -1232,7 +1232,7 @@ public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalA
EnsureStackState
(
cookie
);
// implicit label here
}
return
node
.
Update
(
receiver
,
whenNotNull
,
whenNull
,
node
.
Type
);
return
node
.
Update
(
receiver
,
whenNotNull
,
whenNull
,
node
.
ID
,
node
.
Type
);
}
public
override
BoundNode
VisitComplexConditionalReceiver
(
BoundComplexConditionalReceiver
node
)
...
...
src/Compilers/CSharp/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs
浏览文件 @
81166360
...
...
@@ -274,9 +274,13 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
arguments
[
i
]
=
F
.
Convert
(
manager
.
System_Object
,
new
BoundLoweredConditionalAccess
(
F
.
Syntax
,
F
.
Field
(
F
.
This
(),
property
.
BackingField
),
F
.
Call
(
new
BoundConditionalReceiver
(
F
.
Syntax
,
property
.
BackingField
.
Type
),
manager
.
System_Object__ToString
),
F
.
Call
(
new
BoundConditionalReceiver
(
F
.
Syntax
,
iD
:
i
,
type
:
property
.
BackingField
.
Type
),
manager
.
System_Object__ToString
),
null
,
manager
.
System_String
),
iD
:
i
,
type
:
manager
.
System_String
),
ConversionKind
.
ImplicitReference
);
}
formatString
.
Builder
.
Append
(
" }}"
);
...
...
src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AwaitExpressionSpiller.cs
浏览文件 @
81166360
...
...
@@ -897,11 +897,11 @@ public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalA
var
whenNotNull
=
VisitExpression
(
ref
whenNotNullBuilder
,
node
.
WhenNotNull
);
BoundSpillSequenceBuilder
whenNullBuilder
=
null
;
var
whenNull
=
VisitExpression
(
ref
whenNullBuilder
,
node
.
WhenNullOpt
);
var
whenNull
Opt
=
VisitExpression
(
ref
whenNullBuilder
,
node
.
WhenNullOpt
);
if
(
whenNotNullBuilder
==
null
&&
whenNullBuilder
==
null
)
{
return
UpdateExpression
(
receiverBuilder
,
node
.
Update
(
receiver
,
whenNotNull
,
whenNull
,
node
.
Type
));
return
UpdateExpression
(
receiverBuilder
,
node
.
Update
(
receiver
,
whenNotNull
,
whenNull
Opt
,
node
.
ID
,
node
.
Type
));
}
if
(
receiverBuilder
==
null
)
receiverBuilder
=
new
BoundSpillSequenceBuilder
();
...
...
@@ -943,15 +943,18 @@ public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalA
receiver
=
_F
.
ComplexConditionalReceiver
(
receiver
,
_F
.
Local
(
clone
));
}
whenNullOpt
=
whenNullOpt
??
_F
.
Default
(
node
.
Type
);
if
(
node
.
Type
.
SpecialType
==
SpecialType
.
System_Void
)
{
var
wnenNotNullStatement
=
UpdateStatement
(
whenNotNullBuilder
,
_F
.
ExpressionStatement
(
whenNotNull
),
substituteTemps
:
false
);
wnenNotNullStatement
=
ConditionalReceiverReplacer
.
Replace
(
wnenNotNullStatement
,
receiver
);
wnenNotNullStatement
=
ConditionalReceiverReplacer
.
Replace
(
wnenNotNullStatement
,
receiver
,
node
.
ID
);
receiverBuilder
.
AddStatement
(
_F
.
If
(
condition
,
wnenNotNullStatement
,
UpdateStatement
(
whenNullBuilder
,
_F
.
ExpressionStatement
(
whenNull
),
substituteTemps
:
false
)));
UpdateStatement
(
whenNullBuilder
,
_F
.
ExpressionStatement
(
whenNull
Opt
),
substituteTemps
:
false
)));
return
receiverBuilder
.
Update
(
_F
.
Default
(
node
.
Type
));
}
...
...
@@ -960,13 +963,13 @@ public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalA
Debug
.
Assert
(
_F
.
Syntax
.
IsKind
(
SyntaxKind
.
AwaitExpression
));
var
tmp
=
_F
.
SynthesizedLocal
(
node
.
Type
,
kind
:
SynthesizedLocalKind
.
AwaitSpill
,
syntax
:
_F
.
Syntax
);
var
wnenNotNullStatement
=
UpdateStatement
(
whenNotNullBuilder
,
_F
.
Assignment
(
_F
.
Local
(
tmp
),
whenNotNull
),
substituteTemps
:
false
);
wnenNotNullStatement
=
ConditionalReceiverReplacer
.
Replace
(
wnenNotNullStatement
,
receiver
);
wnenNotNullStatement
=
ConditionalReceiverReplacer
.
Replace
(
wnenNotNullStatement
,
receiver
,
node
.
ID
);
receiverBuilder
.
AddLocal
(
tmp
,
_F
.
Diagnostics
);
receiverBuilder
.
AddStatement
(
_F
.
If
(
condition
,
wnenNotNullStatement
,
UpdateStatement
(
whenNullBuilder
,
_F
.
Assignment
(
_F
.
Local
(
tmp
),
whenNull
),
substituteTemps
:
false
)));
UpdateStatement
(
whenNullBuilder
,
_F
.
Assignment
(
_F
.
Local
(
tmp
),
whenNull
Opt
),
substituteTemps
:
false
)));
return
receiverBuilder
.
Update
(
_F
.
Local
(
tmp
));
}
...
...
@@ -975,20 +978,22 @@ public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalA
private
class
ConditionalReceiverReplacer
:
BoundTreeRewriter
{
private
readonly
BoundExpression
_receiver
;
private
readonly
int
_receiverID
;
#if DEBUG
// we must replace exatly one node
private
int
_replaced
;
#endif
private
ConditionalReceiverReplacer
(
BoundExpression
receiver
)
private
ConditionalReceiverReplacer
(
BoundExpression
receiver
,
int
receiverID
)
{
this
.
_receiver
=
receiver
;
this
.
_receiverID
=
receiverID
;
}
public
static
BoundStatement
Replace
(
BoundNode
node
,
BoundExpression
receiver
)
public
static
BoundStatement
Replace
(
BoundNode
node
,
BoundExpression
receiver
,
int
receiverID
)
{
var
replacer
=
new
ConditionalReceiverReplacer
(
receiver
);
var
replacer
=
new
ConditionalReceiverReplacer
(
receiver
,
receiverID
);
var
result
=
(
BoundStatement
)
replacer
.
Visit
(
node
);
#if DEBUG
Debug
.
Assert
(
replacer
.
_replaced
==
1
,
"should have replaced exactly one node"
);
...
...
@@ -999,10 +1004,15 @@ public static BoundStatement Replace(BoundNode node, BoundExpression receiver)
public
override
BoundNode
VisitConditionalReceiver
(
BoundConditionalReceiver
node
)
{
if
(
node
.
ID
==
this
.
_receiverID
)
{
#if DEBUG
_replaced
++;
_replaced
++;
#endif
return
_receiver
;
return
_receiver
;
}
return
node
;
}
}
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
浏览文件 @
81166360
...
...
@@ -510,6 +510,7 @@ private BoundExpression RewriteLiftedBinaryOperator(CSharpSyntaxNode syntax, Bin
conditionalLeft
.
Receiver
,
whenNotNull
:
result
,
whenNullOpt
:
whenNullOpt
,
iD
:
conditionalLeft
.
ID
,
type
:
result
.
Type
);
}
...
...
@@ -1749,7 +1750,7 @@ private MethodSymbol GetNullableMethod(CSharpSyntaxNode syntax, TypeSymbol nulla
var
whenNull
=
kind
==
BinaryOperatorKind
.
NullableNullEqual
?
MakeBooleanConstant
(
syntax
,
true
)
:
null
;
return
conditionalAccess
.
Update
(
conditionalAccess
.
Receiver
,
whenNotNull
,
whenNull
,
whenNotNull
.
Type
);
return
conditionalAccess
.
Update
(
conditionalAccess
.
Receiver
,
whenNotNull
,
whenNull
,
conditionalAccess
.
ID
,
whenNotNull
.
Type
);
}
MethodSymbol
get_HasValue
=
GetNullableMethod
(
syntax
,
nullable
.
Type
,
SpecialMember
.
System_Nullable_T_get_HasValue
);
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs
浏览文件 @
81166360
...
...
@@ -20,6 +20,7 @@ public override BoundNode VisitConditionalAccess(BoundConditionalAccess node)
// null when currently enclosing conditional access node
// is not supposed to be lowered.
private
BoundExpression
_currentConditionalAccessTarget
=
null
;
private
int
_currentConditionalAccessID
=
0
;
private
enum
ConditionalAccessLoweringKind
{
...
...
@@ -63,13 +64,19 @@ internal BoundExpression RewriteConditionalAccess(BoundConditionalAccess node, b
var
previousConditionalAccesTarget
=
_currentConditionalAccessTarget
;
var
currentConditionalAccessID
=
++
this
.
_currentConditionalAccessID
;
LocalSymbol
temp
=
null
;
BoundExpression
unconditionalAccess
=
null
;
switch
(
loweringKind
)
{
case
ConditionalAccessLoweringKind
.
LoweredConditionalAccess
:
_currentConditionalAccessTarget
=
null
;
_currentConditionalAccessTarget
=
new
BoundConditionalReceiver
(
loweredReceiver
.
Syntax
,
currentConditionalAccessID
,
receiverType
);
break
;
case
ConditionalAccessLoweringKind
.
Ternary
:
...
...
@@ -130,7 +137,9 @@ internal BoundExpression RewriteConditionalAccess(BoundConditionalAccess node, b
node
.
Syntax
,
loweredReceiver
,
loweredAccessExpression
,
rewrittenWhenNull
,
type
);
rewrittenWhenNull
,
currentConditionalAccessID
,
type
);
break
;
...
...
@@ -176,14 +185,11 @@ internal BoundExpression RewriteConditionalAccess(BoundConditionalAccess node, b
public
override
BoundNode
VisitConditionalReceiver
(
BoundConditionalReceiver
node
)
{
if
(
_currentConditionalAccessTarget
==
null
)
{
return
node
;
}
var
newtarget
=
_currentConditionalAccessTarget
;
if
(
newtarget
.
Type
.
IsNullableType
())
{
Debug
.
Assert
(
newtarget
.
Kind
!=
BoundKind
.
ConditionalReceiver
);
newtarget
=
MakeOptimizedGetValueOrDefault
(
node
.
Syntax
,
newtarget
);
}
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullCoalescingOperator.cs
浏览文件 @
81166360
...
...
@@ -130,6 +130,7 @@ private bool TryGetOptimizableNullableConditionalAccess(BoundExpression operand,
conditionalAccess
.
Receiver
,
whenNotNull
:
notNullAccess
,
whenNullOpt
:
whenNullOpt
,
iD
:
conditionalAccess
.
ID
,
type
:
rewrittenResultType
);
}
...
...
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs
浏览文件 @
81166360
...
...
@@ -5786,5 +5786,279 @@ .maxstack 2
IL_000e: ret
}"
);
}
[
Fact
]
public
void
ConditionalBoolExpr02
()
{
var
source
=
@"
class C
{
public static void Main()
{
System.Console.Write(HasLength(null, 0));
System.Console.Write(HasLength(null, 3));
System.Console.Write(HasLength(""q"", 2));
}
static bool HasLength(string s, int len)
{
return (s?.Length ?? 2) + 1 == len;
}
}
"
;
var
verifier
=
CompileAndVerify
(
source
,
expectedOutput
:
@"FalseTrueTrue"
);
verifier
.
VerifyIL
(
"C.HasLength"
,
@"
{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: brtrue.s IL_0006
IL_0003: ldc.i4.2
IL_0004: br.s IL_000c
IL_0006: ldarg.0
IL_0007: call ""int string.Length.get""
IL_000c: ldc.i4.1
IL_000d: add
IL_000e: ldarg.1
IL_000f: ceq
IL_0011: ret
}"
);
}
[
Fact
]
public
void
ConditionalBoolExpr03
()
{
var
source
=
@"
using System.Threading.Tasks;
static class C
{
public static void Main()
{
System.Console.Write(HasLength(null, 0).Result);
System.Console.Write(HasLength(null, 3).Result);
System.Console.Write(HasLength(""q"", 2).Result);
}
static async Task<bool> HasLength(string s, int len)
{
return (s?.Foo(await Bar()) ?? await Bar() + await Bar()) + 1 == len;
}
static int Foo(this string s, int arg)
{
return s.Length;
}
static async Task<int> Bar()
{
await Task.Yield();
return 1;
}
}
"
;
var
c
=
CreateCompilationWithMscorlib45
(
source
,
new
[]
{
SystemRef_v4_0_30319_17929
,
SystemCoreRef_v4_0_30319_17929
,
CSharpRef
},
TestOptions
.
ReleaseExe
);
var
comp
=
CompileAndVerify
(
c
,
expectedOutput
:
@"FalseTrueTrue"
);
}
[
Fact
]
public
void
ConditionalBoolExpr04
()
{
var
source
=
@"
using System.Threading.Tasks;
static class C
{
public static void Main()
{
System.Console.Write(HasLength((string)null, 0).Result);
System.Console.Write(HasLength((string)null, 3).Result);
System.Console.Write(HasLength(""q"", 2).Result);
}
static async Task<bool> HasLength<T>(T s, int len)
{
return (s?.Foo(await Bar()) ?? 2) + 1 == len;
}
static int Foo<T>(this T s, int arg)
{
return ((string)(object)s).Length;
}
static async Task<int> Bar()
{
await Task.Yield();
return 1;
}
}
"
;
var
c
=
CreateCompilationWithMscorlib45
(
source
,
new
[]
{
SystemRef_v4_0_30319_17929
,
SystemCoreRef_v4_0_30319_17929
,
CSharpRef
},
TestOptions
.
ReleaseExe
);
var
comp
=
CompileAndVerify
(
c
,
expectedOutput
:
@"FalseTrueTrue"
);
}
[
Fact
]
public
void
ConditionalBoolExpr05
()
{
var
source
=
@"
using System.Threading.Tasks;
static class C
{
public static void Main()
{
System.Console.Write(HasLength((string)null, 0).Result);
System.Console.Write(HasLength((string)null, 3).Result);
System.Console.Write(HasLength(""q"", 2).Result);
}
static async Task<bool> HasLength<T>(T s, int len)
{
return (s?.Foo(await Bar(await Bar())) ?? 2) + 1 == len;
}
static int Foo<T>(this T s, int arg)
{
return ((string)(object)s).Length;
}
static async Task<int> Bar()
{
await Task.Yield();
return 1;
}
static async Task<int> Bar(int arg)
{
await Task.Yield();
return arg;
}
}
"
;
var
c
=
CreateCompilationWithMscorlib45
(
source
,
new
[]
{
SystemRef_v4_0_30319_17929
,
SystemCoreRef_v4_0_30319_17929
,
CSharpRef
},
TestOptions
.
ReleaseExe
);
var
comp
=
CompileAndVerify
(
c
,
expectedOutput
:
@"FalseTrueTrue"
);
}
[
Fact
]
public
void
ConditionalBoolExpr06
()
{
var
source
=
@"
using System.Threading.Tasks;
static class C
{
public static void Main()
{
System.Console.Write(HasLength(null, 0).Result);
System.Console.Write(HasLength(null, 7).Result);
System.Console.Write(HasLength(""q"", 7).Result);
}
static async Task<bool> HasLength(string s, int len)
{
System.Console.WriteLine(s?.Foo(await Bar())?.Foo(await Bar()) + ""#"");
return s?.Foo(await Bar())?.Foo(await Bar()).Length == len;
}
static string Foo(this string s, string arg)
{
return s + arg;
}
static async Task<string> Bar()
{
await Task.Yield();
return ""Bar"";
}
}
"
;
var
c
=
CreateCompilationWithMscorlib45
(
source
,
new
[]
{
SystemRef_v4_0_30319_17929
,
SystemCoreRef_v4_0_30319_17929
,
CSharpRef
},
TestOptions
.
ReleaseExe
);
var
comp
=
CompileAndVerify
(
c
,
expectedOutput
:
@"#
False#
FalseqBarBar#
True"
);
}
[
Fact
]
public
void
ConditionalBoolExpr07
()
{
var
source
=
@"
using System.Threading.Tasks;
static class C
{
public static void Main()
{
System.Console.WriteLine(Test(null).Result);
System.Console.WriteLine(Test(""q"").Result);
}
static async Task<bool> Test(string s)
{
return (await Bar(s))?.Foo(await Bar())?.ToString()?.Length > 1;
}
static string Foo(this string s, string arg1)
{
return s + arg1;
}
static async Task<string> Bar()
{
await Task.Yield();
return ""Bar"";
}
static async Task<string> Bar(string arg)
{
await Task.Yield();
return arg;
}
}
"
;
var
c
=
CreateCompilationWithMscorlib45
(
source
,
new
[]
{
SystemRef_v4_0_30319_17929
,
SystemCoreRef_v4_0_30319_17929
,
CSharpRef
},
TestOptions
.
ReleaseExe
);
var
comp
=
CompileAndVerify
(
c
,
expectedOutput
:
@"False
True"
);
}
[
Fact
]
public
void
ConditionalBoolExpr08
()
{
var
source
=
@"
using System.Threading.Tasks;
static class C
{
public static void Main()
{
System.Console.WriteLine(Test(null).Result);
System.Console.WriteLine(Test(""q"").Result);
}
static async Task<bool> Test(string s)
{
return (await Bar(s))?.Insert(0, await Bar())?.ToString()?.Length > 1;
}
static async Task<string> Bar()
{
await Task.Yield();
return ""Bar"";
}
static async Task<dynamic> Bar(string arg)
{
await Task.Yield();
return arg;
}
}"
;
var
c
=
CreateCompilationWithMscorlib45
(
source
,
new
[]
{
SystemRef_v4_0_30319_17929
,
SystemCoreRef_v4_0_30319_17929
,
CSharpRef
},
TestOptions
.
ReleaseExe
);
var
comp
=
CompileAndVerify
(
c
,
expectedOutput
:
@"False
True"
);
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录