Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
81b8888d
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,发现更多精彩内容 >>
提交
81b8888d
编写于
4月 14, 2015
作者:
V
VSadov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Code review feedback. More tests.
上级
0c69ef23
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
485 addition
and
60 deletion
+485
-60
src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs
src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs
+30
-0
src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
+3
-3
src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs
src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs
+2
-2
src/Compilers/CSharp/Portable/CodeGen/EmitConversion.cs
src/Compilers/CSharp/Portable/CodeGen/EmitConversion.cs
+1
-1
src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
+6
-2
src/Compilers/CSharp/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs
...p/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs
+2
-2
src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AwaitExpressionSpiller.cs
...Portable/Lowering/AsyncRewriter/AwaitExpressionSpiller.cs
+10
-12
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
...le/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
+11
-8
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs
...LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs
+2
-26
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs
...Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs
+5
-3
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullCoalescingOperator.cs
...ing/LocalRewriter/LocalRewriter_NullCoalescingOperator.cs
+1
-1
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs
...arp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs
+412
-0
未找到文件。
src/Compilers/CSharp/Portable/BoundTree/BoundExpression.cs
浏览文件 @
81b8888d
...
...
@@ -332,6 +332,36 @@ public override bool SuppressVirtualCalls
{
get
{
return
this
.
IsBaseConversion
;
}
}
/// <summary>
/// Returns true when conversion itself (not the operand) may have sideeffects
/// A typical sideeffect of a conversion is an exception when conversion is unsuccessful.
/// </summary>
/// <returns></returns>
internal
bool
ConversionHasSideEffects
()
{
// only some intrinsic conversions are side effect free
// the only side effect of an intrinsic conversion is a throw when we fail to convert.
// and some intrinsic conversion always succeed
switch
(
this
.
ConversionKind
)
{
case
ConversionKind
.
Identity
:
// NOTE: even explicit float/double identity conversion does not have side
// effects since it does not throw
case
ConversionKind
.
ImplicitNumeric
:
case
ConversionKind
.
ImplicitEnumeration
:
// implicit ref cast does not throw ...
case
ConversionKind
.
ImplicitReference
:
case
ConversionKind
.
Boxing
:
return
false
;
// unchecked numeric conversion does not throw
case
ConversionKind
.
ExplicitNumeric
:
return
this
.
Checked
;
}
return
true
;
}
}
internal
partial
class
BoundObjectCreationExpression
...
...
src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
浏览文件 @
81b8888d
...
...
@@ -979,16 +979,16 @@
expressions.
To be able to do that, during lowering, we will assign
BoundLoweredConditionalAccess and corresponding BoundConditionalReceiver
matching I
D
that are integers unique for the containing method body.
matching I
d
that are integers unique for the containing method body.
-->
<Field
Name=
"I
D
"
Type=
"int"
/>
<Field
Name=
"I
d
"
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=
"I
D
"
Type=
"int"
/>
<Field
Name=
"I
d
"
Type=
"int"
/>
</Node>
<!-- This node represents a complex receiver for a conditional access.
...
...
src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs
浏览文件 @
81b8888d
...
...
@@ -49,7 +49,7 @@ private LocalDefinition EmitAddress(BoundExpression expression, AddressKind addr
break
;
case
BoundKind
.
ComplexConditionalReceiver
:
EmitComplexConditionalReceiver
((
BoundComplexConditionalReceiver
)
expression
);
EmitComplexConditionalReceiver
Address
((
BoundComplexConditionalReceiver
)
expression
);
break
;
case
BoundKind
.
Parameter
:
...
...
@@ -100,7 +100,7 @@ private LocalDefinition EmitAddress(BoundExpression expression, AddressKind addr
return
null
;
}
private
void
EmitComplexConditionalReceiver
(
BoundComplexConditionalReceiver
expression
)
private
void
EmitComplexConditionalReceiver
Address
(
BoundComplexConditionalReceiver
expression
)
{
Debug
.
Assert
(!
expression
.
Type
.
IsReferenceType
);
Debug
.
Assert
(!
expression
.
Type
.
IsValueType
);
...
...
src/Compilers/CSharp/Portable/CodeGen/EmitConversion.cs
浏览文件 @
81b8888d
...
...
@@ -26,7 +26,7 @@ private void EmitConversionExpression(BoundConversion conversion, bool used)
return
;
}
if
(!
used
&&
!
LocalRewriter
.
ConversionHasSideEffects
(
conversion
))
if
(!
used
&&
!
conversion
.
ConversionHasSideEffects
(
))
{
EmitExpression
(
conversion
.
Operand
,
false
);
// just do expr side effects
return
;
...
...
src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
浏览文件 @
81b8888d
...
...
@@ -1231,8 +1231,12 @@ public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalA
whenNull
=
(
BoundExpression
)
this
.
Visit
(
whenNull
);
EnsureStackState
(
cookie
);
// implicit label here
}
else
{
_counter
+=
1
;
}
return
node
.
Update
(
receiver
,
whenNotNull
,
whenNull
,
node
.
I
D
,
node
.
Type
);
return
node
.
Update
(
receiver
,
whenNotNull
,
whenNull
,
node
.
I
d
,
node
.
Type
);
}
public
override
BoundNode
VisitComplexConditionalReceiver
(
BoundComplexConditionalReceiver
node
)
...
...
@@ -1251,7 +1255,7 @@ public override BoundNode VisitComplexConditionalReceiver(BoundComplexConditiona
EnsureStackState
(
cookie
);
// implicit label here
this
.
_evalStack
=
origStack
;
// alternative is evaluated with original stack
var
referenceTypeReceiver
=
(
BoundExpression
)
this
.
Visit
(
node
.
ReferenceTypeReceiver
);
var
referenceTypeReceiver
=
(
BoundExpression
)
this
.
Visit
(
node
.
ReferenceTypeReceiver
);
EnsureStackState
(
cookie
);
// implicit label here
...
...
src/Compilers/CSharp/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs
浏览文件 @
81b8888d
...
...
@@ -276,10 +276,10 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,
F
.
Field
(
F
.
This
(),
property
.
BackingField
),
F
.
Call
(
new
BoundConditionalReceiver
(
F
.
Syntax
,
i
D
:
i
,
i
d
:
i
,
type
:
property
.
BackingField
.
Type
),
manager
.
System_Object__ToString
),
null
,
i
D
:
i
,
i
d
:
i
,
type
:
manager
.
System_String
),
ConversionKind
.
ImplicitReference
);
}
...
...
src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AwaitExpressionSpiller.cs
浏览文件 @
81b8888d
...
...
@@ -901,7 +901,7 @@ public override BoundNode VisitLoweredConditionalAccess(BoundLoweredConditionalA
if
(
whenNotNullBuilder
==
null
&&
whenNullBuilder
==
null
)
{
return
UpdateExpression
(
receiverBuilder
,
node
.
Update
(
receiver
,
whenNotNull
,
whenNullOpt
,
node
.
I
D
,
node
.
Type
));
return
UpdateExpression
(
receiverBuilder
,
node
.
Update
(
receiver
,
whenNotNull
,
whenNullOpt
,
node
.
I
d
,
node
.
Type
));
}
if
(
receiverBuilder
==
null
)
receiverBuilder
=
new
BoundSpillSequenceBuilder
();
...
...
@@ -942,19 +942,15 @@ 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
,
node
.
I
D
);
wnenNotNullStatement
=
ConditionalReceiverReplacer
.
Replace
(
wnenNotNullStatement
,
receiver
,
node
.
I
d
);
receiverBuilder
.
AddStatement
(
_F
.
If
(
condition
,
wnenNotNullStatement
,
UpdateStatement
(
whenNullBuilder
,
_F
.
ExpressionStatement
(
whenNullOpt
),
substituteTemps
:
false
)));
Debug
.
Assert
(
whenNullOpt
==
null
||
!
LocalRewriter
.
ReadIsSideeffecting
(
whenNullOpt
));
receiverBuilder
.
AddStatement
(
_F
.
If
(
condition
,
wnenNotNullStatement
));
return
receiverBuilder
.
Update
(
_F
.
Default
(
node
.
Type
));
}
...
...
@@ -963,7 +959,9 @@ 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
,
node
.
ID
);
wnenNotNullStatement
=
ConditionalReceiverReplacer
.
Replace
(
wnenNotNullStatement
,
receiver
,
node
.
Id
);
whenNullOpt
=
whenNullOpt
??
_F
.
Default
(
node
.
Type
);
receiverBuilder
.
AddLocal
(
tmp
,
_F
.
Diagnostics
);
receiverBuilder
.
AddStatement
(
...
...
@@ -1004,7 +1002,7 @@ public static BoundStatement Replace(BoundNode node, BoundExpression receiver, i
public
override
BoundNode
VisitConditionalReceiver
(
BoundConditionalReceiver
node
)
{
if
(
node
.
I
D
==
this
.
_receiverID
)
if
(
node
.
I
d
==
this
.
_receiverID
)
{
#if DEBUG
_replaced
++;
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
浏览文件 @
81b8888d
...
...
@@ -271,7 +271,7 @@ public BoundExpression VisitBinaryOperator(BoundBinaryOperator node, BoundUnaryO
if
(
operatorKind
.
IsLifted
())
{
return
RewriteLiftedBinaryOperator
(
syntax
,
operatorKind
,
ref
loweredLeft
,
loweredRight
,
type
,
method
);
return
RewriteLiftedBinaryOperator
(
syntax
,
operatorKind
,
loweredLeft
,
loweredRight
,
type
,
method
);
}
if
(
operatorKind
.
IsUserDefined
())
...
...
@@ -475,7 +475,7 @@ public BoundExpression VisitBinaryOperator(BoundBinaryOperator node, BoundUnaryO
new
BoundBinaryOperator
(
syntax
,
operatorKind
,
loweredLeft
,
loweredRight
,
null
,
null
,
LookupResultKind
.
Viable
,
type
);
}
private
BoundExpression
RewriteLiftedBinaryOperator
(
CSharpSyntaxNode
syntax
,
BinaryOperatorKind
operatorKind
,
ref
BoundExpression
loweredLeft
,
BoundExpression
loweredRight
,
TypeSymbol
type
,
MethodSymbol
method
)
private
BoundExpression
RewriteLiftedBinaryOperator
(
CSharpSyntaxNode
syntax
,
BinaryOperatorKind
operatorKind
,
BoundExpression
loweredLeft
,
BoundExpression
loweredRight
,
TypeSymbol
type
,
MethodSymbol
method
)
{
var
conditionalLeft
=
loweredLeft
as
BoundLoweredConditionalAccess
;
...
...
@@ -501,16 +501,19 @@ private BoundExpression RewriteLiftedBinaryOperator(CSharpSyntaxNode syntax, Bin
{
BoundExpression
whenNullOpt
=
null
;
if
(
operatorKind
.
Operator
()
==
BinaryOperatorKind
.
NotEqual
)
// for all operators null-in means null-out
// except for the Equal/NotEqual since null == null ==> true
if
(
operatorKind
.
Operator
()
==
BinaryOperatorKind
.
NotEqual
||
operatorKind
.
Operator
()
==
BinaryOperatorKind
.
Equal
)
{
whenNullOpt
=
MakeBooleanConstant
(
syntax
,
true
);
whenNullOpt
=
RewriteLiftedBinaryOperator
(
syntax
,
operatorKind
,
_factory
.
Default
(
loweredLeft
.
Type
),
loweredRight
,
type
,
method
);
}
result
=
conditionalLeft
.
Update
(
conditionalLeft
.
Receiver
,
whenNotNull
:
result
,
whenNullOpt
:
whenNullOpt
,
i
D
:
conditionalLeft
.
ID
,
i
d
:
conditionalLeft
.
Id
,
type
:
result
.
Type
);
}
...
...
@@ -704,7 +707,7 @@ private BoundExpression MakeTruthTestForDynamicLogicalOperator(CSharpSyntaxNode
if
(
operatorKind
.
IsLifted
())
{
return
RewriteLiftedBinaryOperator
(
syntax
,
operatorKind
,
ref
loweredLeft
,
loweredRight
,
type
,
method
);
return
RewriteLiftedBinaryOperator
(
syntax
,
operatorKind
,
loweredLeft
,
loweredRight
,
type
,
method
);
}
// Otherwise, nothing special here.
...
...
@@ -1736,7 +1739,7 @@ private MethodSymbol GetNullableMethod(CSharpSyntaxNode syntax, TypeSymbol nulla
type
:
returnType
);
}
// arr?.Le
gh
th == null
// arr?.Le
ng
th == null
var
conditionalAccess
=
nullable
as
BoundLoweredConditionalAccess
;
if
(
conditionalAccess
!=
null
&&
(
conditionalAccess
.
WhenNullOpt
==
null
||
conditionalAccess
.
WhenNullOpt
.
IsDefaultValue
()))
...
...
@@ -1750,7 +1753,7 @@ private MethodSymbol GetNullableMethod(CSharpSyntaxNode syntax, TypeSymbol nulla
var
whenNull
=
kind
==
BinaryOperatorKind
.
NullableNullEqual
?
MakeBooleanConstant
(
syntax
,
true
)
:
null
;
return
conditionalAccess
.
Update
(
conditionalAccess
.
Receiver
,
whenNotNull
,
whenNull
,
conditionalAccess
.
I
D
,
whenNotNull
.
Type
);
return
conditionalAccess
.
Update
(
conditionalAccess
.
Receiver
,
whenNotNull
,
whenNull
,
conditionalAccess
.
I
d
,
whenNotNull
.
Type
);
}
MethodSymbol
get_HasValue
=
GetNullableMethod
(
syntax
,
nullable
.
Type
,
SpecialMember
.
System_Nullable_T_get_HasValue
);
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs
浏览文件 @
81b8888d
...
...
@@ -620,7 +620,7 @@ private BoundExpression BoxReceiver(BoundExpression rewrittenReceiver, NamedType
}
// a simple check for common nonsideeffecting expressions
private
static
bool
ReadIsSideeffecting
(
internal
static
bool
ReadIsSideeffecting
(
BoundExpression
expression
)
{
if
(
expression
.
ConstantValue
!=
null
)
...
...
@@ -645,7 +645,7 @@ private BoundExpression BoxReceiver(BoundExpression rewrittenReceiver, NamedType
case
BoundKind
.
Conversion
:
var
conv
=
(
BoundConversion
)
expression
;
return
ConversionHasSideEffects
(
conv
)
||
return
conv
.
ConversionHasSideEffects
(
)
||
ReadIsSideeffecting
(
conv
.
Operand
);
case
BoundKind
.
ObjectCreationExpression
:
...
...
@@ -664,30 +664,6 @@ private BoundExpression BoxReceiver(BoundExpression rewrittenReceiver, NamedType
}
}
internal
static
bool
ConversionHasSideEffects
(
BoundConversion
conversion
)
{
// only some intrinsic conversions are side effect free the only side effect of an
// intrinsic conversion is a throw when we fail to convert.
switch
(
conversion
.
ConversionKind
)
{
case
ConversionKind
.
Identity
:
// NOTE: even explicit float/double identity conversion does not have side
// effects since it does not throw
case
ConversionKind
.
ImplicitNumeric
:
case
ConversionKind
.
ImplicitEnumeration
:
// implicit ref cast does not throw ...
case
ConversionKind
.
ImplicitReference
:
case
ConversionKind
.
Boxing
:
return
false
;
// unchecked numeric conversion does not throw
case
ConversionKind
.
ExplicitNumeric
:
return
conversion
.
Checked
;
}
return
true
;
}
// nontrivial literals do not change between reads
// but may require re-constructing, so it is better
// to treat them as potentially changing.
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs
浏览文件 @
81b8888d
...
...
@@ -39,6 +39,10 @@ internal BoundExpression RewriteConditionalAccess(BoundConditionalAccess node, b
var
receiverType
=
loweredReceiver
.
Type
;
ConditionalAccessLoweringKind
loweringKind
;
// nullable and dynamic receivers are not directly supported in codegen and need to be lowered
// in particular nullable receiver implies that the condition of the
// conditional and the access receiver are actually different expressions
// (HasValue and GetValueOrDefault respectively)
var
lowerToTernary
=
receiverType
.
IsNullableType
()
||
node
.
AccessExpression
.
Type
.
IsDynamic
();
if
(!
lowerToTernary
)
...
...
@@ -127,8 +131,6 @@ internal BoundExpression RewriteConditionalAccess(BoundConditionalAccess node, b
BoundExpression
result
;
var
objectType
=
_compilation
.
GetSpecialType
(
SpecialType
.
System_Object
);
rewrittenWhenNull
=
rewrittenWhenNull
??
_factory
.
Default
(
nodeType
);
switch
(
loweringKind
)
{
case
ConditionalAccessLoweringKind
.
LoweredConditionalAccess
:
...
...
@@ -165,7 +167,7 @@ internal BoundExpression RewriteConditionalAccess(BoundConditionalAccess node, b
result
=
RewriteConditionalOperator
(
node
.
Syntax
,
condition
,
consequence
,
rewrittenWhenNull
,
rewrittenWhenNull
??
_factory
.
Default
(
nodeType
)
,
null
,
nodeType
);
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullCoalescingOperator.cs
浏览文件 @
81b8888d
...
...
@@ -130,7 +130,7 @@ private bool TryGetOptimizableNullableConditionalAccess(BoundExpression operand,
conditionalAccess
.
Receiver
,
whenNotNull
:
notNullAccess
,
whenNullOpt
:
whenNullOpt
,
i
D
:
conditionalAccess
.
ID
,
i
d
:
conditionalAccess
.
Id
,
type
:
rewrittenResultType
);
}
...
...
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs
浏览文件 @
81b8888d
...
...
@@ -5948,6 +5948,100 @@ .maxstack 2
}"
);
}
[
Fact
]
public
void
ConditionalBoolExpr02a
()
{
var
source
=
@"
class C
{
public static void Main()
{
System.Console.Write(NotHasLength(null, 0));
System.Console.Write(NotHasLength(null, 3));
System.Console.Write(NotHasLength(""q"", 2));
}
static bool NotHasLength(string s, int len)
{
return s?.Length + 1 != len;
}
}
"
;
var
verifier
=
CompileAndVerify
(
source
,
expectedOutput
:
@"TrueTrueFalse"
);
verifier
.
VerifyIL
(
"C.NotHasLength"
,
@"
{
// Code size 20 (0x14)
.maxstack 2
IL_0000: ldarg.0
IL_0001: brtrue.s IL_0005
IL_0003: ldc.i4.1
IL_0004: ret
IL_0005: ldarg.0
IL_0006: call ""int string.Length.get""
IL_000b: ldc.i4.1
IL_000c: add
IL_000d: ldarg.1
IL_000e: ceq
IL_0010: ldc.i4.0
IL_0011: ceq
IL_0013: ret
}"
);
}
[
Fact
]
public
void
ConditionalBoolExpr02b
()
{
var
source
=
@"
class C
{
public static void Main()
{
System.Console.Write(NotHasLength(null, 0));
System.Console.Write(NotHasLength(null, 3));
System.Console.Write(NotHasLength(""q"", 2));
System.Console.Write(NotHasLength(null, null));
}
static bool NotHasLength(string s, int? len)
{
return s?.Length + 1 != len;
}
}
"
;
var
verifier
=
CompileAndVerify
(
source
,
expectedOutput
:
@"TrueTrueFalseFalse"
);
verifier
.
VerifyIL
(
"C.NotHasLength"
,
@"
{
// Code size 43 (0x2b)
.maxstack 2
.locals init (int? V_0)
IL_0000: ldarg.0
IL_0001: brtrue.s IL_000b
IL_0003: ldarga.s V_1
IL_0005: call ""bool int?.HasValue.get""
IL_000a: ret
IL_000b: ldarg.0
IL_000c: call ""int string.Length.get""
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: ldarg.1
IL_0014: stloc.0
IL_0015: ldloca.s V_0
IL_0017: call ""int int?.GetValueOrDefault()""
IL_001c: beq.s IL_0020
IL_001e: ldc.i4.1
IL_001f: ret
IL_0020: ldloca.s V_0
IL_0022: call ""bool int?.HasValue.get""
IL_0027: ldc.i4.0
IL_0028: ceq
IL_002a: ret
}"
);
}
[
Fact
]
public
void
ConditionalBoolExpr03
()
{
...
...
@@ -6181,5 +6275,323 @@ static async Task<dynamic> Bar(string arg)
True"
);
}
[
Fact
]
public
void
ConditionalUserDef01
()
{
var
source
=
@"
class C
{
struct S1
{
public static bool operator ==(S1? x, S1?y)
{
System.Console.Write(""=="");
return true;
}
public static bool operator !=(S1? x, S1? y)
{
System.Console.Write(""!="");
return false;
}
}
class C1
{
public S1 Foo()
{
return new S1();
}
}
public static void Main()
{
System.Console.WriteLine(TestEq(null, new S1()));
System.Console.WriteLine(TestEq(new C1(), new S1()));
System.Console.WriteLine(TestNeq(null, new S1()));
System.Console.WriteLine(TestNeq(new C1(), new S1()));
}
static bool TestEq(C1 c, S1 arg)
{
return c?.Foo() == arg;
}
static bool TestNeq(C1 c, S1 arg)
{
return c?.Foo() != arg;
}
}
"
;
var
verifier
=
CompileAndVerify
(
source
,
expectedOutput
:
@"==True
==True
!=False
!=False"
);
verifier
.
VerifyIL
(
"C.TestNeq"
,
@"
{
// Code size 37 (0x25)
.maxstack 2
.locals init (C.S1? V_0)
IL_0000: ldarg.0
IL_0001: brtrue.s IL_000e
IL_0003: ldloca.s V_0
IL_0005: initobj ""C.S1?""
IL_000b: ldloc.0
IL_000c: br.s IL_0019
IL_000e: ldarg.0
IL_000f: call ""C.S1 C.C1.Foo()""
IL_0014: newobj ""C.S1?..ctor(C.S1)""
IL_0019: ldarg.1
IL_001a: newobj ""C.S1?..ctor(C.S1)""
IL_001f: call ""bool C.S1.op_Inequality(C.S1?, C.S1?)""
IL_0024: ret
}"
);
}
[
Fact
]
public
void
ConditionalUserDef01n
()
{
var
source
=
@"
class C
{
struct S1
{
public static bool operator ==(S1? x, S1?y)
{
System.Console.Write(""=="");
return true;
}
public static bool operator !=(S1? x, S1? y)
{
System.Console.Write(""!="");
return false;
}
}
class C1
{
public S1 Foo()
{
return new S1();
}
}
public static void Main()
{
System.Console.WriteLine(TestEq(null, new S1()));
System.Console.WriteLine(TestEq(new C1(), new S1()));
System.Console.WriteLine(TestEq(new C1(), null));
System.Console.WriteLine(TestNeq(null, new S1()));
System.Console.WriteLine(TestNeq(new C1(), new S1()));
System.Console.WriteLine(TestNeq(new C1(), null));
}
static bool TestEq(C1 c, S1? arg)
{
return c?.Foo() == arg;
}
static bool TestNeq(C1 c, S1? arg)
{
return c?.Foo() != arg;
}
}
"
;
var
verifier
=
CompileAndVerify
(
source
,
expectedOutput
:
@"==True
==True
==True
!=False
!=False
!=False"
);
verifier
.
VerifyIL
(
"C.TestNeq"
,
@"
{
// Code size 32 (0x20)
.maxstack 2
.locals init (C.S1? V_0)
IL_0000: ldarg.0
IL_0001: brtrue.s IL_000e
IL_0003: ldloca.s V_0
IL_0005: initobj ""C.S1?""
IL_000b: ldloc.0
IL_000c: br.s IL_0019
IL_000e: ldarg.0
IL_000f: call ""C.S1 C.C1.Foo()""
IL_0014: newobj ""C.S1?..ctor(C.S1)""
IL_0019: ldarg.1
IL_001a: call ""bool C.S1.op_Inequality(C.S1?, C.S1?)""
IL_001f: ret
}"
);
}
[
Fact
]
public
void
ConditionalUserDef02
()
{
var
source
=
@"
class C
{
struct S1
{
public static bool operator ==(S1 x, S1 y)
{
System.Console.Write(""=="");
return true;
}
public static bool operator !=(S1 x, S1 y)
{
System.Console.Write(""!="");
return false;
}
}
class C1
{
public S1 Foo()
{
return new S1();
}
}
public static void Main()
{
System.Console.WriteLine(TestEq(null, new S1()));
System.Console.WriteLine(TestEq(new C1(), new S1()));
System.Console.WriteLine(TestNeq(null, new S1()));
System.Console.WriteLine(TestNeq(new C1(), new S1()));
}
static bool TestEq(C1 c, S1 arg)
{
return c?.Foo() == arg;
}
static bool TestNeq(C1 c, S1 arg)
{
return c?.Foo() != arg;
}
}
"
;
var
verifier
=
CompileAndVerify
(
source
,
expectedOutput
:
@"False
==True
True
!=False"
);
verifier
.
VerifyIL
(
"C.TestNeq"
,
@"
{
// Code size 18 (0x12)
.maxstack 2
IL_0000: ldarg.0
IL_0001: brtrue.s IL_0005
IL_0003: ldc.i4.1
IL_0004: ret
IL_0005: ldarg.0
IL_0006: call ""C.S1 C.C1.Foo()""
IL_000b: ldarg.1
IL_000c: call ""bool C.S1.op_Inequality(C.S1, C.S1)""
IL_0011: ret
}"
);
}
[
Fact
]
public
void
ConditionalUserDef02n
()
{
var
source
=
@"
class C
{
struct S1
{
public static bool operator ==(S1 x, S1 y)
{
System.Console.Write(""=="");
return true;
}
public static bool operator !=(S1 x, S1 y)
{
System.Console.Write(""!="");
return false;
}
}
class C1
{
public S1 Foo()
{
return new S1();
}
}
public static void Main()
{
System.Console.WriteLine(TestEq(null, new S1()));
System.Console.WriteLine(TestEq(new C1(), new S1()));
System.Console.WriteLine(TestEq(new C1(), null));
System.Console.WriteLine(TestNeq(null, new S1()));
System.Console.WriteLine(TestNeq(new C1(), new S1()));
System.Console.WriteLine(TestNeq(new C1(), null));
}
static bool TestEq(C1 c, S1? arg)
{
return c?.Foo() == arg;
}
static bool TestNeq(C1 c, S1? arg)
{
return c?.Foo() != arg;
}
}
"
;
var
verifier
=
CompileAndVerify
(
source
,
expectedOutput
:
@"False
==True
False
True
!=False
True"
);
verifier
.
VerifyIL
(
"C.TestNeq"
,
@"
{
// Code size 45 (0x2d)
.maxstack 2
.locals init (C.S1 V_0,
C.S1? V_1)
IL_0000: ldarg.0
IL_0001: brtrue.s IL_000b
IL_0003: ldarga.s V_1
IL_0005: call ""bool C.S1?.HasValue.get""
IL_000a: ret
IL_000b: ldarg.0
IL_000c: call ""C.S1 C.C1.Foo()""
IL_0011: stloc.0
IL_0012: ldarg.1
IL_0013: stloc.1
IL_0014: ldloca.s V_1
IL_0016: call ""bool C.S1?.HasValue.get""
IL_001b: brtrue.s IL_001f
IL_001d: ldc.i4.1
IL_001e: ret
IL_001f: ldloc.0
IL_0020: ldloca.s V_1
IL_0022: call ""C.S1 C.S1?.GetValueOrDefault()""
IL_0027: call ""bool C.S1.op_Inequality(C.S1, C.S1)""
IL_002c: ret
}"
);
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录