Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
f3f5cd30
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,发现更多精彩内容 >>
提交
f3f5cd30
编写于
3月 13, 2017
作者:
V
Vladimir Sadov
提交者:
GitHub
3月 13, 2017
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #17436 from VSadov/refTernaryRebased
Implemented ref conditional operator (aka: ternary ref)
上级
3408f6a6
a9c0a840
变更
24
展开全部
隐藏空白更改
内联
并排
Showing
24 changed file
with
1187 addition
and
48 deletion
+1187
-48
src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
+39
-3
src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
+22
-0
src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
+1
-1
src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
+27
-0
src/Compilers/CSharp/Portable/CSharpResources.resx
src/Compilers/CSharp/Portable/CSharpResources.resx
+9
-0
src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs
src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs
+46
-0
src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs
src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs
+17
-0
src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
+10
-4
src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+7
-0
src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs
...s/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs
+24
-13
src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AwaitExpressionSpiller.cs
...Portable/Lowering/AsyncRewriter/AwaitExpressionSpiller.cs
+11
-1
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
...le/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
+20
-10
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs
...LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs
+4
-0
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs
...Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs
+2
-1
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalOperator.cs
...wering/LocalRewriter/LocalRewriter_ConditionalOperator.cs
+6
-3
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs
...rtable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs
+6
-3
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_FixedStatement.cs
...le/Lowering/LocalRewriter/LocalRewriter_FixedStatement.cs
+1
-1
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullCoalescingOperator.cs
...ing/LocalRewriter/LocalRewriter_NullCoalescingOperator.cs
+2
-1
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs
...ble/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs
+7
-4
src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs
...ring/StateMachineRewriter/MethodToStateMachineRewriter.cs
+20
-0
src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs
...ers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs
+1
-1
src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
+2
-2
src/Compilers/CSharp/Test/Emit/CSharpCompilerEmitTest.csproj
src/Compilers/CSharp/Test/Emit/CSharpCompilerEmitTest.csproj
+1
-0
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs
...p/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs
+902
-0
未找到文件。
src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
浏览文件 @
f3f5cd30
...
...
@@ -3419,9 +3419,30 @@ private BoundExpression BindNullCoalescingOperator(BinaryExpressionSyntax node,
/// </remarks>
private
BoundExpression
BindConditionalOperator
(
ConditionalExpressionSyntax
node
,
DiagnosticBag
diagnostics
)
{
var
whenTrue
=
node
.
WhenTrue
.
SkipRef
(
out
var
whenTrueRefKind
);
var
whenFalse
=
node
.
WhenFalse
.
SkipRef
(
out
var
whenFalseRefKind
);
var
isRef
=
whenTrueRefKind
==
RefKind
.
Ref
&&
whenFalseRefKind
==
RefKind
.
Ref
;
if
(!
isRef
)
{
if
(
whenFalseRefKind
==
RefKind
.
Ref
)
{
diagnostics
.
Add
(
ErrorCode
.
ERR_RefConditionalNeedsTwoRefs
,
whenFalse
.
GetFirstToken
().
GetLocation
());
}
if
(
whenTrueRefKind
==
RefKind
.
Ref
)
{
diagnostics
.
Add
(
ErrorCode
.
ERR_RefConditionalNeedsTwoRefs
,
whenTrue
.
GetFirstToken
().
GetLocation
());
}
}
BoundExpression
condition
=
BindBooleanExpression
(
node
.
Condition
,
diagnostics
);
BoundExpression
trueExpr
=
BindValue
(
node
.
WhenTrue
,
diagnostics
,
BindValueKind
.
RValue
);
BoundExpression
falseExpr
=
BindValue
(
node
.
WhenFalse
,
diagnostics
,
BindValueKind
.
RValue
);
var
valKind
=
isRef
?
BindValueKind
.
RefOrOut
:
BindValueKind
.
RValue
;
BoundExpression
trueExpr
=
BindValue
(
whenTrue
,
diagnostics
,
valKind
);
BoundExpression
falseExpr
=
BindValue
(
whenFalse
,
diagnostics
,
valKind
);
TypeSymbol
trueType
=
trueExpr
.
Type
;
TypeSymbol
falseType
=
falseExpr
.
Type
;
...
...
@@ -3488,6 +3509,21 @@ private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node
type
=
bestType
;
hasErrors
=
true
;
}
else
if
(
isRef
)
{
if
(!
Conversions
.
HasIdentityConversion
(
trueType
,
falseType
))
{
diagnostics
.
Add
(
ErrorCode
.
ERR_RefConditionalDifferentTypes
,
falseExpr
.
Syntax
.
Location
,
trueType
);
type
=
CreateErrorType
();
hasErrors
=
true
;
}
else
{
Debug
.
Assert
(
Conversions
.
HasIdentityConversion
(
trueType
,
bestType
));
Debug
.
Assert
(
Conversions
.
HasIdentityConversion
(
falseType
,
bestType
));
type
=
bestType
;
}
}
else
{
trueExpr
=
GenerateConversionForAssignment
(
bestType
,
trueExpr
,
diagnostics
);
...
...
@@ -3515,7 +3551,7 @@ private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node
hasErrors
=
constantValue
!=
null
&&
constantValue
.
IsBad
;
}
return
new
BoundConditionalOperator
(
node
,
condition
,
trueExpr
,
falseExpr
,
constantValue
,
type
,
hasErrors
);
return
new
BoundConditionalOperator
(
node
,
isRef
,
condition
,
trueExpr
,
falseExpr
,
constantValue
,
type
,
hasErrors
);
}
/// <summary>
...
...
src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
浏览文件 @
f3f5cd30
...
...
@@ -1521,6 +1521,28 @@ private bool CheckIsVariable(SyntaxNode node, BoundExpression expr, BindValueKin
return
true
;
}
var
conditional
=
expr
as
BoundConditionalOperator
;
if
(
conditional
!=
null
)
{
if
(
kind
==
BindValueKind
.
RefReturn
)
{
var
returnable
=
CheckIsVariable
(
conditional
.
Consequence
.
Syntax
,
conditional
.
Consequence
,
kind
,
checkingReceiver
:
false
,
diagnostics
:
diagnostics
)
&
CheckIsVariable
(
conditional
.
Alternative
.
Syntax
,
conditional
.
Alternative
,
kind
,
checkingReceiver
:
false
,
diagnostics
:
diagnostics
);
return
returnable
;
}
else
if
(
conditional
.
IsByRef
)
{
return
true
;
}
else
{
Error
(
diagnostics
,
GetStandardLvalueError
(
kind
),
node
);
}
return
false
;
}
// Local constants are never variables. Local variables are sometimes
// not to be treated as variables, if they are fixed, declared in a using,
// or declared in a foreach.
...
...
src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
浏览文件 @
f3f5cd30
...
...
@@ -426,7 +426,7 @@
<Node
Name=
"BoundConditionalOperator"
Base=
"BoundExpression"
>
<!-- Non-null type is required for this node kind -->
<Field
Name=
"Type"
Type=
"TypeSymbol"
Override=
"true"
Null=
"disallow"
/>
<Field
Name=
"IsByRef"
Type=
"bool"
/>
<Field
Name=
"Condition"
Type=
"BoundExpression"
/>
<Field
Name=
"Consequence"
Type=
"BoundExpression"
/>
<Field
Name=
"Alternative"
Type=
"BoundExpression"
/>
...
...
src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
浏览文件 @
f3f5cd30
...
...
@@ -2257,6 +2257,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to 'await' cannot be used in an expression containing a ref conditional operator.
/// </summary>
internal static string ERR_RefConditionalAndAwait {
get {
return ResourceManager.GetString("ERR_RefConditionalAndAwait", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A declaration of a by-reference variable must have an initializer.
/// </summary>
...
...
@@ -7900,6 +7909,24 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to The expression must be of type '{0}' to match the alternative ref value.
/// </summary>
internal static string ERR_RefConditionalDifferentTypes {
get {
return ResourceManager.GetString("ERR_RefConditionalDifferentTypes", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Both conditional operator values must be ref values or neither may be a ref value.
/// </summary>
internal static string ERR_RefConditionalNeedsTwoRefs {
get {
return ResourceManager.GetString("ERR_RefConditionalNeedsTwoRefs", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The type '{2}' must be a reference type in order to use it as parameter '{1}' in the generic type or method '{0}'.
/// </summary>
...
...
src/Compilers/CSharp/Portable/CSharpResources.resx
浏览文件 @
f3f5cd30
...
...
@@ -4834,6 +4834,15 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data
name=
"ERR_RefReturningCallAndAwait"
xml:space=
"preserve"
>
<value>
'await' cannot be used in an expression containing a call to '{0}' because it returns by reference
</value>
</data>
<data
name=
"ERR_RefConditionalAndAwait"
xml:space=
"preserve"
>
<value>
'await' cannot be used in an expression containing a ref conditional operator
</value>
</data>
<data
name=
"ERR_RefConditionalNeedsTwoRefs"
xml:space=
"preserve"
>
<value>
Both conditional operator values must be ref values or neither may be a ref value
</value>
</data>
<data
name=
"ERR_RefConditionalDifferentTypes"
xml:space=
"preserve"
>
<value>
The expression must be of type '{0}' to match the alternative ref value
</value>
</data>
<data
name=
"ERR_ExpressionTreeContainsLocalFunction"
xml:space=
"preserve"
>
<value>
An expression tree may not contain a reference to a local function
</value>
</data>
...
...
src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs
浏览文件 @
f3f5cd30
...
...
@@ -103,6 +103,16 @@ private LocalDefinition EmitAddress(BoundExpression expression, AddressKind addr
EmitCallExpression
(
call
,
UseKind
.
UsedAsAddress
);
break
;
case
BoundKind
.
ConditionalOperator
:
var
conditional
=
(
BoundConditionalOperator
)
expression
;
if
(!
conditional
.
IsByRef
)
{
goto
default
;
}
EmitConditionalOperatorAddress
(
conditional
);
break
;
case
BoundKind
.
AssignmentOperator
:
var
assignment
=
(
BoundAssignmentOperator
)
expression
;
if
(
assignment
.
RefKind
==
RefKind
.
None
)
...
...
@@ -120,6 +130,42 @@ private LocalDefinition EmitAddress(BoundExpression expression, AddressKind addr
return
null
;
}
/// <summary>
/// Emit code for a conditional (aka ternary) operator.
/// </summary>
/// <remarks>
/// (b ? x : y) becomes
/// push b
/// if pop then goto CONSEQUENCE
/// push y
/// goto DONE
/// CONSEQUENCE:
/// push x
/// DONE:
/// </remarks>
private
void
EmitConditionalOperatorAddress
(
BoundConditionalOperator
expr
)
{
Debug
.
Assert
(
expr
.
ConstantValue
==
null
,
"Constant value should have been emitted directly"
);
object
consequenceLabel
=
new
object
();
object
doneLabel
=
new
object
();
EmitCondBranch
(
expr
.
Condition
,
ref
consequenceLabel
,
sense
:
true
);
var
temp
=
EmitAddress
(
expr
.
Alternative
,
AddressKind
.
Writeable
);
Debug
.
Assert
(
temp
==
null
);
_builder
.
EmitBranch
(
ILOpCode
.
Br
,
doneLabel
);
// If we get to consequenceLabel, we should not have Alternative on stack, adjust for that.
_builder
.
AdjustStack
(-
1
);
_builder
.
MarkLabel
(
consequenceLabel
);
EmitAddress
(
expr
.
Consequence
,
AddressKind
.
Writeable
);
_builder
.
MarkLabel
(
doneLabel
);
}
private
void
EmitComplexConditionalReceiverAddress
(
BoundComplexConditionalReceiver
expression
)
{
Debug
.
Assert
(!
expression
.
Type
.
IsReferenceType
);
...
...
src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs
浏览文件 @
f3f5cd30
...
...
@@ -2162,6 +2162,18 @@ private bool EmitAssignmentPreamble(BoundAssignmentOperator assignmentOperator)
}
break
;
case
BoundKind
.
ConditionalOperator
:
{
var
left
=
(
BoundConditionalOperator
)
assignmentTarget
;
Debug
.
Assert
(
left
.
IsByRef
);
var
temp
=
EmitAddress
(
left
,
AddressKind
.
Writeable
);
Debug
.
Assert
(
temp
==
null
,
"taking ref of this should not create a temp"
);
lhsUsesStack
=
true
;
}
break
;
case
BoundKind
.
PointerIndirectionOperator
:
{
var
left
=
(
BoundPointerIndirectionOperator
)
assignmentTarget
;
...
...
@@ -2337,6 +2349,11 @@ private void EmitStore(BoundAssignmentOperator assignment)
EmitIndirectStore
(
expression
.
Type
,
expression
.
Syntax
);
break
;
case
BoundKind
.
ConditionalOperator
:
Debug
.
Assert
(((
BoundConditionalOperator
)
expression
).
IsByRef
);
EmitIndirectStore
(
expression
.
Type
,
expression
.
Syntax
);
break
;
case
BoundKind
.
RefValueOperator
:
case
BoundKind
.
PointerIndirectionOperator
:
case
BoundKind
.
PseudoVariable
:
...
...
src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
浏览文件 @
f3f5cd30
...
...
@@ -1001,6 +1001,10 @@ private static bool IsIndirectAssignment(BoundAssignmentOperator node)
Debug
.
Assert
(((
BoundCall
)
lhs
).
Method
.
RefKind
==
RefKind
.
Ref
,
"only ref returning methods are assignable"
);
return
true
;
case
BoundKind
.
ConditionalOperator
:
Debug
.
Assert
(((
BoundConditionalOperator
)
lhs
).
IsByRef
,
"only ref ternaries are assignable"
);
return
true
;
case
BoundKind
.
AssignmentOperator
:
Debug
.
Assert
(((
BoundAssignmentOperator
)
lhs
).
RefKind
==
RefKind
.
Ref
,
"only ref assignments are assignable"
);
return
true
;
...
...
@@ -1239,21 +1243,23 @@ public override BoundNode VisitConditionalGoto(BoundConditionalGoto node)
public
override
BoundNode
VisitConditionalOperator
(
BoundConditionalOperator
node
)
{
var
origStack
=
StackDepth
();
BoundExpression
condition
=
(
BoundExpression
)
this
.
Visit
(
node
.
Condition
);
BoundExpression
condition
=
this
.
VisitExpression
(
node
.
Condition
,
ExprContext
.
Value
);
var
cookie
=
GetStackStateCookie
();
// implicit goto here
var
context
=
node
.
IsByRef
?
ExprContext
.
Address
:
ExprContext
.
Value
;
SetStackDepth
(
origStack
);
// consequence is evaluated with original stack
BoundExpression
consequence
=
(
BoundExpression
)
this
.
Visit
(
node
.
Consequence
);
BoundExpression
consequence
=
this
.
VisitExpression
(
node
.
Consequence
,
context
);
EnsureStackState
(
cookie
);
// implicit label here
SetStackDepth
(
origStack
);
// alternative is evaluated with original stack
BoundExpression
alternative
=
(
BoundExpression
)
this
.
Visit
(
node
.
Alternative
);
BoundExpression
alternative
=
this
.
VisitExpression
(
node
.
Alternative
,
context
);
EnsureStackState
(
cookie
);
// implicit label here
return
node
.
Update
(
condition
,
consequence
,
alternative
,
node
.
ConstantValueOpt
,
node
.
Type
);
return
node
.
Update
(
node
.
IsByRef
,
condition
,
consequence
,
alternative
,
node
.
ConstantValueOpt
,
node
.
Type
);
}
public
override
BoundNode
VisitBinaryOperator
(
BoundBinaryOperator
node
)
...
...
src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
浏览文件 @
f3f5cd30
...
...
@@ -1457,5 +1457,12 @@ internal enum ErrorCode
#
endregion
more
stragglers
for
C
#
7
ERR_BadParameterModifiers
=
8205
,
//PROTOTYPE(ReadonlyRefs): make err IDs contiguous before merging to master.
// For now it is more convenient to have a gap to avoid conflicts with other added errors
ERR_RefConditionalAndAwait
=
8301
,
ERR_RefConditionalNeedsTwoRefs
=
8302
,
ERR_RefConditionalDifferentTypes
=
8332
,
}
}
src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs
浏览文件 @
f3f5cd30
...
...
@@ -2329,35 +2329,31 @@ public override BoundNode VisitContinueStatement(BoundContinueStatement node)
return
null
;
}
public
override
BoundNode
VisitConditionalOperator
(
BoundConditionalOperator
node
)
public
sealed
override
BoundNode
VisitConditionalOperator
(
BoundConditionalOperator
node
)
{
var
isByRef
=
node
.
IsByRef
;
VisitCondition
(
node
.
Condition
);
var
consequenceState
=
this
.
StateWhenTrue
;
var
alternativeState
=
this
.
StateWhenFalse
;
if
(
IsConstantTrue
(
node
.
Condition
))
{
SetState
(
alternativeState
);
Visit
(
node
.
Alternative
);
SetState
(
consequenceState
);
Visit
(
node
.
Consequence
);
VisitConditionalOperand
(
alternativeState
,
node
.
Alternative
,
isByRef
);
VisitConditionalOperand
(
consequenceState
,
node
.
Consequence
,
isByRef
);
// it may be a boolean state at this point.
}
else
if
(
IsConstantFalse
(
node
.
Condition
))
{
SetState
(
consequenceState
);
Visit
(
node
.
Consequence
);
SetState
(
alternativeState
);
Visit
(
node
.
Alternative
);
VisitConditionalOperand
(
consequenceState
,
node
.
Consequence
,
isByRef
);
VisitConditionalOperand
(
alternativeState
,
node
.
Alternative
,
isByRef
);
// it may be a boolean state at this point.
}
else
{
SetState
(
consequenceState
);
Visit
(
node
.
Consequence
);
VisitConditionalOperand
(
consequenceState
,
node
.
Consequence
,
isByRef
);
Unsplit
();
consequenceState
=
this
.
State
;
SetState
(
alternativeState
);
Visit
(
node
.
Alternative
);
VisitConditionalOperand
(
alternativeState
,
node
.
Alternative
,
isByRef
);
Unsplit
();
IntersectWith
(
ref
this
.
State
,
ref
consequenceState
);
// it may not be a boolean state at this point (5.3.3.28)
...
...
@@ -2366,6 +2362,21 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
return
null
;
}
private
void
VisitConditionalOperand
(
LocalState
state
,
BoundExpression
operand
,
bool
isByRef
)
{
SetState
(
state
);
if
(
isByRef
)
{
VisitLvalue
(
operand
);
// exposing ref is a potential write
WriteArgument
(
operand
,
RefKind
.
Ref
,
method
:
null
);
}
else
{
Visit
(
operand
);
}
}
public
override
BoundNode
VisitBaseReference
(
BoundBaseReference
node
)
{
// TODO: in a struct constructor, "this" is not initially assigned.
...
...
src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AwaitExpressionSpiller.cs
浏览文件 @
f3f5cd30
...
...
@@ -404,6 +404,16 @@ private BoundStatement UpdateStatement(BoundSpillSequenceBuilder builder, BoundS
}
goto
default
;
case
BoundKind
.
ConditionalOperator
:
var
conditional
=
(
BoundConditionalOperator
)
expression
;
if
(
refKind
!=
RefKind
.
None
)
{
Debug
.
Assert
(
conditional
.
IsByRef
);
_F
.
Diagnostics
.
Add
(
ErrorCode
.
ERR_RefConditionalAndAwait
,
_F
.
Syntax
.
Location
);
refKind
=
RefKind
.
None
;
// Switch the RefKind to avoid asserting later in the pipeline
}
goto
default
;
case
BoundKind
.
Literal
:
case
BoundKind
.
TypeExpression
:
return
expression
;
...
...
@@ -807,7 +817,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
if
(
consequenceBuilder
==
null
&&
alternativeBuilder
==
null
)
{
return
UpdateExpression
(
conditionBuilder
,
node
.
Update
(
condition
,
consequence
,
alternative
,
node
.
ConstantValueOpt
,
node
.
Type
));
return
UpdateExpression
(
conditionBuilder
,
node
.
Update
(
node
.
IsByRef
,
condition
,
consequence
,
alternative
,
node
.
ConstantValueOpt
,
node
.
Type
));
}
if
(
conditionBuilder
==
null
)
conditionBuilder
=
new
BoundSpillSequenceBuilder
();
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
浏览文件 @
f3f5cd30
...
...
@@ -97,7 +97,8 @@ public override BoundNode VisitUserDefinedConditionalLogicalOperator(BoundUserDe
rewrittenConsequence
:
boundTemp
,
rewrittenAlternative
:
andOperatorCall
,
constantValueOpt
:
null
,
rewrittenType
:
type
);
rewrittenType
:
type
,
isRef
:
false
);
// temp = x; T.false(temp) ? temp : T.&(temp, y)
return
new
BoundSequence
(
...
...
@@ -966,7 +967,8 @@ private BoundExpression MakeNullableHasValue(SyntaxNode syntax, BoundExpression
rewrittenConsequence
:
consequence
,
rewrittenAlternative
:
alternative
,
constantValueOpt
:
null
,
rewrittenType
:
boolType
);
rewrittenType
:
boolType
,
isRef
:
false
);
// tempx = x;
// tempy = y;
...
...
@@ -1108,7 +1110,8 @@ private BoundExpression MakeNullableHasValue(SyntaxNode syntax, BoundExpression
rewrittenConsequence
:
unliftedOp
,
rewrittenAlternative
:
MakeLiteral
(
syntax
,
ConstantValue
.
Create
(
operatorKind
==
BinaryOperatorKind
.
Equal
),
boolType
),
constantValueOpt
:
null
,
rewrittenType
:
boolType
);
rewrittenType
:
boolType
,
isRef
:
false
);
}
else
{
...
...
@@ -1125,7 +1128,8 @@ private BoundExpression MakeNullableHasValue(SyntaxNode syntax, BoundExpression
rewrittenConsequence
:
consequence
,
rewrittenAlternative
:
alternative
,
constantValueOpt
:
null
,
rewrittenType
:
boolType
);
rewrittenType
:
boolType
,
isRef
:
false
);
return
new
BoundSequence
(
syntax
:
syntax
,
...
...
@@ -1313,7 +1317,8 @@ private BoundExpression MakeNullableHasValue(SyntaxNode syntax, BoundExpression
rewrittenConsequence
:
consequence
,
rewrittenAlternative
:
alternative
,
constantValueOpt
:
null
,
rewrittenType
:
type
);
rewrittenType
:
type
,
isRef
:
false
);
return
new
BoundSequence
(
syntax
:
syntax
,
...
...
@@ -1462,7 +1467,8 @@ private BoundExpression CaptureNullableOperandInTempIfNeeded(BoundExpression ope
MakeBinaryOperator
(
syntax
,
kind
,
conditional
.
Consequence
,
right
,
type
,
method
),
MakeBinaryOperator
(
syntax
,
kind
,
conditional
.
Alternative
,
right
,
type
,
method
),
ConstantValue
.
NotAvailable
,
type
),
type
,
isRef
:
false
),
type
);
}
}
...
...
@@ -1532,7 +1538,8 @@ private BoundExpression MakeNewNullableBoolean(SyntaxNode syntax, bool? value)
rewrittenConsequence
:
kind
==
BinaryOperatorKind
.
LiftedBoolAnd
?
nullBool
:
newNullBool
,
rewrittenAlternative
:
kind
==
BinaryOperatorKind
.
LiftedBoolAnd
?
newNullBool
:
nullBool
,
constantValueOpt
:
null
,
rewrittenType
:
alwaysNull
.
Type
);
rewrittenType
:
alwaysNull
.
Type
,
isRef
:
false
);
}
// Now we optimize the case where one operand is null and the other is not. We generate
...
...
@@ -1558,7 +1565,8 @@ private BoundExpression MakeNewNullableBoolean(SyntaxNode syntax, bool? value)
rewrittenConsequence
:
consequence
,
rewrittenAlternative
:
alternative
,
constantValueOpt
:
null
,
rewrittenType
:
alwaysNull
.
Type
);
rewrittenType
:
alwaysNull
.
Type
,
isRef
:
false
);
return
new
BoundSequence
(
syntax
:
syntax
,
locals
:
ImmutableArray
.
Create
<
LocalSymbol
>(
boundTemp
.
LocalSymbol
),
...
...
@@ -1618,7 +1626,8 @@ private BoundExpression MakeNewNullableBoolean(SyntaxNode syntax, bool? value)
rewrittenConsequence
:
consequence
,
rewrittenAlternative
:
alternative
,
constantValueOpt
:
null
,
rewrittenType
:
newNullBool
.
Type
);
rewrittenType
:
newNullBool
.
Type
,
isRef
:
false
);
return
new
BoundSequence
(
syntax
:
syntax
,
locals
:
ImmutableArray
.
Create
<
LocalSymbol
>(
boundTempX
.
LocalSymbol
,
boundTempY
.
LocalSymbol
),
...
...
@@ -1702,7 +1711,8 @@ private BoundExpression MakeNewNullableBoolean(SyntaxNode syntax, bool? value)
rewrittenConsequence
:
consequence
,
rewrittenAlternative
:
alternative
,
constantValueOpt
:
null
,
rewrittenType
:
alternative
.
Type
);
rewrittenType
:
alternative
.
Type
,
isRef
:
false
);
return
new
BoundSequence
(
syntax
:
syntax
,
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs
浏览文件 @
f3f5cd30
...
...
@@ -535,6 +535,10 @@ private BoundExpression TransformCompoundAssignmentLHS(BoundExpression originalL
Debug
.
Assert
(((
BoundCall
)
originalLHS
).
Method
.
RefKind
!=
RefKind
.
None
);
break
;
case
BoundKind
.
ConditionalOperator
:
Debug
.
Assert
(((
BoundConditionalOperator
)
originalLHS
).
IsByRef
);
break
;
case
BoundKind
.
AssignmentOperator
:
Debug
.
Assert
(((
BoundAssignmentOperator
)
originalLHS
).
RefKind
!=
RefKind
.
None
);
break
;
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalAccess.cs
浏览文件 @
f3f5cd30
...
...
@@ -178,7 +178,8 @@ internal BoundExpression RewriteConditionalAccess(BoundConditionalAccess node, b
consequence
,
_factory
.
Default
(
nodeType
),
null
,
nodeType
);
nodeType
,
isRef
:
false
);
if
(
temp
!=
null
)
{
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ConditionalOperator.cs
浏览文件 @
f3f5cd30
...
...
@@ -24,7 +24,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
if
(
rewrittenCondition
.
ConstantValue
==
null
)
{
return
node
.
Update
(
rewrittenCondition
,
rewrittenConsequence
,
rewrittenAlternative
,
node
.
ConstantValueOpt
,
node
.
Type
);
return
node
.
Update
(
node
.
IsByRef
,
rewrittenCondition
,
rewrittenConsequence
,
rewrittenAlternative
,
node
.
ConstantValueOpt
,
node
.
Type
);
}
return
RewriteConditionalOperator
(
...
...
@@ -33,7 +33,8 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
rewrittenConsequence
,
rewrittenAlternative
,
node
.
ConstantValueOpt
,
node
.
Type
);
node
.
Type
,
node
.
IsByRef
);
}
private
static
BoundExpression
RewriteConditionalOperator
(
...
...
@@ -42,7 +43,8 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
BoundExpression
rewrittenConsequence
,
BoundExpression
rewrittenAlternative
,
ConstantValue
constantValueOpt
,
TypeSymbol
rewrittenType
)
TypeSymbol
rewrittenType
,
bool
isRef
)
{
// NOTE: This optimization assumes that a constant has no side effects. In the future we
// might wish to represent nodes that are known to the optimizer as having constant
...
...
@@ -62,6 +64,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
{
return
new
BoundConditionalOperator
(
syntax
,
isRef
,
rewrittenCondition
,
rewrittenConsequence
,
rewrittenAlternative
,
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs
浏览文件 @
f3f5cd30
...
...
@@ -841,7 +841,8 @@ private static BoundExpression NullableAlwaysHasValue(BoundExpression expression
rewrittenConsequence
:
consequence
,
rewrittenAlternative
:
alternative
,
constantValueOpt
:
null
,
rewrittenType
:
type
);
rewrittenType
:
type
,
isRef
:
false
);
return
new
BoundSequence
(
syntax
:
syntax
,
...
...
@@ -967,7 +968,8 @@ private static BoundExpression NullableAlwaysHasValue(BoundExpression expression
MakeConversionNode
(
null
,
syntax
,
conditional
.
Consequence
,
conversion
,
@checked
,
explicitCastInCode
:
false
,
constantValueOpt
:
ConstantValue
.
NotAvailable
,
rewrittenType
:
type
),
MakeConversionNode
(
null
,
syntax
,
conditional
.
Alternative
,
conversion
,
@checked
,
explicitCastInCode
:
false
,
constantValueOpt
:
ConstantValue
.
NotAvailable
,
rewrittenType
:
type
),
ConstantValue
.
NotAvailable
,
type
),
type
,
isRef
:
false
),
type
);
}
}
...
...
@@ -1080,7 +1082,8 @@ private BoundExpression MakeLiftedUserDefinedConversionConsequence(BoundCall cal
rewrittenConsequence
:
consequence
,
rewrittenAlternative
:
alternative
,
constantValueOpt
:
null
,
rewrittenType
:
rewrittenType
);
rewrittenType
:
rewrittenType
,
isRef
:
false
);
// temp = operand
// temp.HasValue ? new R?(op_Whatever(temp.GetValueOrDefault())) : default(R?)
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_FixedStatement.cs
浏览文件 @
f3f5cd30
...
...
@@ -348,7 +348,7 @@ public override BoundNode VisitFixedLocalCollectionInitializer(BoundFixedLocalCo
//(((temp = array) != null && temp.Length != 0) ? loc = &temp[0] : loc = null)
BoundStatement
localInit
=
factory
.
ExpressionStatement
(
new
BoundConditionalOperator
(
factory
.
Syntax
,
condition
,
consequenceAssignment
,
alternativeAssignment
,
ConstantValue
.
NotAvailable
,
localType
));
new
BoundConditionalOperator
(
factory
.
Syntax
,
false
,
condition
,
consequenceAssignment
,
alternativeAssignment
,
ConstantValue
.
NotAvailable
,
localType
));
return
InstrumentLocalDeclarationIfNecessary
(
localDecl
,
localSymbol
,
localInit
);
}
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_NullCoalescingOperator.cs
浏览文件 @
f3f5cd30
...
...
@@ -125,7 +125,8 @@ public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperato
rewrittenConsequence
:
convertedLeft
,
rewrittenAlternative
:
rewrittenRight
,
constantValueOpt
:
null
,
rewrittenType
:
rewrittenResultType
);
rewrittenType
:
rewrittenResultType
,
isRef
:
false
);
Debug
.
Assert
(
conditionalExpression
.
ConstantValue
==
null
);
// we shouldn't have hit this else case otherwise
Debug
.
Assert
(
conditionalExpression
.
Type
.
Equals
(
rewrittenResultType
,
TypeCompareKind
.
IgnoreDynamicAndTupleNames
));
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs
浏览文件 @
f3f5cd30
...
...
@@ -210,7 +210,8 @@ public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
rewrittenConsequence
:
consequence
,
rewrittenAlternative
:
alternative
,
constantValueOpt
:
null
,
rewrittenType
:
type
);
rewrittenType
:
type
,
isRef
:
false
);
// temp = operand;
// temp.HasValue ?
...
...
@@ -322,7 +323,8 @@ public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
MakeUnaryOperator
(
operatorKind
,
syntax
,
method
,
conditional
.
Consequence
,
type
),
MakeUnaryOperator
(
operatorKind
,
syntax
,
method
,
conditional
.
Alternative
,
type
),
ConstantValue
.
NotAvailable
,
type
),
type
,
isRef
:
false
),
type
);
}
}
...
...
@@ -647,7 +649,8 @@ private BoundExpression MakeUserDefinedIncrementOperator(BoundIncrementOperator
rewrittenConsequence
:
consequence
,
rewrittenAlternative
:
alternative
,
constantValueOpt
:
null
,
rewrittenType
:
type
);
rewrittenType
:
type
,
isRef
:
false
);
// temp = operand;
// temp.HasValue ?
...
...
@@ -805,7 +808,7 @@ private BoundExpression MakeLiftedDecimalIncDecOperator(SyntaxNode syntax, Binar
BoundExpression
alternative
=
new
BoundDefaultOperator
(
syntax
,
null
,
operand
.
Type
);
// x.HasValue ? new decimal?(op_Inc(x.GetValueOrDefault())) : default(decimal?)
return
RewriteConditionalOperator
(
syntax
,
condition
,
consequence
,
alternative
,
ConstantValue
.
NotAvailable
,
operand
.
Type
);
return
RewriteConditionalOperator
(
syntax
,
condition
,
consequence
,
alternative
,
ConstantValue
.
NotAvailable
,
operand
.
Type
,
isRef
:
false
);
}
/// <summary>
...
...
src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs
浏览文件 @
f3f5cd30
...
...
@@ -552,6 +552,26 @@ private BoundExpression HoistRefInitialization(SynthesizedLocal local, BoundAssi
case
BoundKind
.
DefaultOperator
:
return
expr
;
case
BoundKind
.
Call
:
var
call
=
(
BoundCall
)
expr
;
if
(
isRef
)
{
Debug
.
Assert
(
call
.
Method
.
RefKind
!=
RefKind
.
None
);
F
.
Diagnostics
.
Add
(
ErrorCode
.
ERR_RefReturningCallAndAwait
,
F
.
Syntax
.
Location
,
call
.
Method
);
isRef
=
false
;
// Switch to ByVal to avoid asserting later in the pipeline
}
goto
default
;
case
BoundKind
.
ConditionalOperator
:
var
conditional
=
(
BoundConditionalOperator
)
expr
;
if
(
isRef
)
{
Debug
.
Assert
(
conditional
.
IsByRef
);
F
.
Diagnostics
.
Add
(
ErrorCode
.
ERR_RefConditionalAndAwait
,
F
.
Syntax
.
Location
);
isRef
=
false
;
// Switch to ByVal to avoid asserting later in the pipeline
}
goto
default
;
default
:
if
(
expr
.
ConstantValue
!=
null
)
{
...
...
src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs
浏览文件 @
f3f5cd30
...
...
@@ -653,7 +653,7 @@ public BoundCall Call(BoundExpression receiver, MethodSymbol method, ImmutableAr
public
BoundExpression
Conditional
(
BoundExpression
condition
,
BoundExpression
consequence
,
BoundExpression
alternative
,
TypeSymbol
type
)
{
return
new
BoundConditionalOperator
(
Syntax
,
condition
,
consequence
,
alternative
,
default
(
ConstantValue
),
type
)
{
WasCompilerGenerated
=
true
};
return
new
BoundConditionalOperator
(
Syntax
,
false
,
condition
,
consequence
,
alternative
,
default
(
ConstantValue
),
type
)
{
WasCompilerGenerated
=
true
};
}
public
BoundExpression
ComplexConditionalReceiver
(
BoundExpression
valueTypeReceiver
,
BoundExpression
referenceTypeReceiver
)
...
...
src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
浏览文件 @
f3f5cd30
...
...
@@ -9507,9 +9507,9 @@ private ExpressionSyntax ParseSubExpressionCore(Precedence precedence)
if
(
tk
==
SyntaxKind
.
QuestionToken
&&
precedence
<=
Precedence
.
Ternary
)
{
var
questionToken
=
this
.
EatToken
();
var
colonLeft
=
this
.
Parse
ExpressionCore
();
var
colonLeft
=
this
.
Parse
PossibleRefExpression
();
var
colon
=
this
.
EatToken
(
SyntaxKind
.
ColonToken
);
var
colonRight
=
this
.
Parse
ExpressionCore
();
var
colonRight
=
this
.
Parse
PossibleRefExpression
();
leftOperand
=
_syntaxFactory
.
ConditionalExpression
(
leftOperand
,
questionToken
,
colonLeft
,
colon
,
colonRight
);
}
...
...
src/Compilers/CSharp/Test/Emit/CSharpCompilerEmitTest.csproj
浏览文件 @
f3f5cd30
...
...
@@ -74,6 +74,7 @@
<Compile
Include=
"CodeGen\CodeGenInParametersTests.cs"
/>
<Compile
Include=
"CodeGen\CodeGenCapturing.cs"
/>
<Compile
Include=
"CodeGen\CodeGenRefReadonlyReturnTests.cs"
/>
<Compile
Include=
"CodeGen\CodeGenRefConditionalOperatorTests.cs"
/>
<Compile
Include=
"Emit\BinaryCompatibility.cs"
/>
<Compile
Include=
"Emit\DesktopStrongNameProviderTests.cs"
/>
<Compile
Include=
"Attributes\InternalsVisibleToAndStrongNameTests.cs"
/>
...
...
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs
0 → 100644
浏览文件 @
f3f5cd30
此差异已折叠。
点击以展开。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录