Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
18bb0438
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,发现更多精彩内容 >>
提交
18bb0438
编写于
8月 09, 2017
作者:
V
vsadov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
GetValEscape introduced
上级
76892a74
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
156 addition
and
115 deletion
+156
-115
src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
+154
-109
src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
+1
-5
src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs
...ilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs
+1
-1
未找到文件。
src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
浏览文件 @
18bb0438
...
...
@@ -907,7 +907,7 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV
return
true
;
}
private
bool
CheckInvocation
Ref
Escape
(
private
bool
CheckInvocationEscape
(
SyntaxNode
syntax
,
Symbol
symbol
,
ImmutableArray
<
ParameterSymbol
>
parameters
,
...
...
@@ -918,143 +918,89 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV
uint
escapeTo
,
DiagnosticBag
diagnostics
)
{
// check all arguments that are not passed by value
if
(!
argRefKinds
.
IsDefault
)
{
for
(
var
argIndex
=
0
;
argIndex
<
args
.
Length
;
argIndex
++)
{
if
(
argRefKinds
[
argIndex
]
!=
RefKind
.
None
&&
!
CheckRefEscape
(
args
[
argIndex
].
Syntax
,
args
[
argIndex
],
escapeTo
,
false
,
diagnostics
))
{
var
errorCode
=
checkingReceiver
?
ErrorCode
.
ERR_RefReturnCall2
:
ErrorCode
.
ERR_RefReturnCall
;
var
parameterIndex
=
argToParamsOpt
.
IsDefault
?
argIndex
:
argToParamsOpt
[
argIndex
];
var
parameterName
=
parameters
[
parameterIndex
].
Name
;
Error
(
diagnostics
,
errorCode
,
syntax
,
symbol
,
parameterName
);
return
false
;
}
}
//TODO: VS optional "in" arguments - scopeOfTheContainingExpression
return
true
;
}
//TODO: VS ref-like receiver
// check all
"in" parameters
if
(!
parameter
s
.
IsDefault
)
// check all
arguments that are not passed by value
if
(!
arg
s
.
IsDefault
)
{
for
(
var
paramIndex
=
0
;
paramIndex
<
parameters
.
Length
;
param
Index
++)
for
(
var
argIndex
=
0
;
argIndex
<
args
.
Length
;
arg
Index
++)
{
var
parameter
=
parameters
[
paramIndex
];
if
(
parameter
.
RefKind
!=
RefKind
.
RefReadOnly
)
var
effectiveRefKind
=
argRefKinds
.
IsDefault
?
RefKind
.
None
:
argRefKinds
[
argIndex
];
if
(
effectiveRefKind
==
RefKind
.
None
&&
argIndex
<
parameters
.
Length
)
{
continue
;
}
if
(
parameter
.
IsParams
)
{
break
;
}
BoundExpression
argument
=
null
;
if
(
argToParamsOpt
.
IsDefault
)
{
if
(
paramIndex
<
args
.
Length
)
{
argument
=
args
[
paramIndex
];
}
}
else
{
for
(
int
argIndex
=
0
;
argIndex
<
args
.
Length
;
argIndex
++)
var
paramIndex
=
argToParamsOpt
.
IsDefault
?
argIndex
:
argToParamsOpt
[
argIndex
];
if
(
parameters
[
paramIndex
].
RefKind
==
RefKind
.
RefReadOnly
)
{
if
(
argToParamsOpt
[
argIndex
]
==
paramIndex
)
{
argument
=
args
[
argIndex
];
break
;
}
effectiveRefKind
=
RefKind
.
RefReadOnly
;
}
}
if
(
argument
==
null
||
!
CheckRefEscape
(
argument
.
Syntax
,
argument
,
escapeTo
,
false
,
diagnostics
))
// if ref is passed, check ref escape, since it is the same or narrower than val escape
var
argument
=
args
[
argIndex
];
var
valid
=
effectiveRefKind
!=
RefKind
.
None
?
CheckRefEscape
(
argument
.
Syntax
,
argument
,
escapeTo
,
false
,
diagnostics
)
:
true
;
// CheckRefEscape(argument.Syntax, argument, escapeTo, false, diagnostics); //TODO: VS should be CheckVal
if
(!
valid
)
{
var
errorCode
=
checkingReceiver
?
ErrorCode
.
ERR_RefReturnCall2
:
ErrorCode
.
ERR_RefReturnCall
;
Error
(
diagnostics
,
errorCode
,
syntax
,
symbol
,
parameter
.
Name
);
var
paramIndex
=
argToParamsOpt
.
IsDefault
?
argIndex
:
argToParamsOpt
[
argIndex
];
var
parameterName
=
parameters
[
paramIndex
].
Name
;
Error
(
diagnostics
,
errorCode
,
syntax
,
symbol
,
parameterName
);
return
false
;
}
}
}
return
true
;
}
private
uint
GetInvocation
Ref
Escape
(
private
uint
GetInvocationEscape
(
ImmutableArray
<
ParameterSymbol
>
parameters
,
ImmutableArray
<
BoundExpression
>
args
,
ImmutableArray
<
RefKind
>
argRefKinds
,
ImmutableArray
<
int
>
argToParamsOpt
,
uint
scopeOfTheContainingExpression
)
{
//by default it is safe to return
uint
refEscape
=
Binder
.
ExternalScope
;
//TODO: VS optional "in" arguments - scopeOfTheContainingExpression
// check all arguments that are not passed by value
if
(!
argRefKinds
.
IsDefault
)
{
for
(
var
argIndex
=
0
;
argIndex
<
args
.
Length
;
argIndex
++)
{
if
(
argRefKinds
[
argIndex
]
!=
RefKind
.
None
)
{
var
argRefEscape
=
GetRefEscape
(
args
[
argIndex
],
scopeOfTheContainingExpression
);
refEscape
=
Math
.
Max
(
refEscape
,
argRefEscape
);
}
}
}
//TODO: VS ref-like receiver
// check all "in" parameters
if
(!
parameters
.
IsDefault
)
//by default it is safe to escape
uint
escapeScope
=
Binder
.
ExternalScope
;
if
(!
args
.
IsDefault
)
{
for
(
var
paramIndex
=
0
;
paramIndex
<
parameters
.
Length
;
param
Index
++)
for
(
var
argIndex
=
0
;
argIndex
<
args
.
Length
;
arg
Index
++)
{
var
parameter
=
parameters
[
paramIndex
];
if
(
parameter
.
RefKind
!=
RefKind
.
RefReadOnly
)
var
effectiveRefKind
=
argRefKinds
.
IsDefault
?
RefKind
.
None
:
argRefKinds
[
argIndex
];
if
(
effectiveRefKind
==
RefKind
.
None
&&
argIndex
<
parameters
.
Length
)
{
continue
;
}
if
(
parameter
.
IsParams
)
{
break
;
}
BoundExpression
argument
=
null
;
if
(
argToParamsOpt
.
IsDefault
)
{
if
(
paramIndex
<
args
.
Length
)
var
paramIndex
=
argToParamsOpt
.
IsDefault
?
argIndex
:
argToParamsOpt
[
argIndex
];
if
(
parameters
[
paramIndex
].
RefKind
==
RefKind
.
RefReadOnly
)
{
argument
=
args
[
paramIndex
];
}
}
else
{
for
(
int
argIndex
=
0
;
argIndex
<
args
.
Length
;
argIndex
++)
{
if
(
argToParamsOpt
[
argIndex
]
==
paramIndex
)
{
argument
=
args
[
argIndex
];
break
;
}
effectiveRefKind
=
RefKind
.
RefReadOnly
;
}
}
if
(
argument
!=
null
)
// if ref is passed, check ref escape, since it is the same or narrower than val escape
var
argEscape
=
effectiveRefKind
!=
RefKind
.
None
?
GetRefEscape
(
args
[
argIndex
],
scopeOfTheContainingExpression
)
:
GetValEscape
(
args
[
argIndex
],
scopeOfTheContainingExpression
);
escapeScope
=
Math
.
Max
(
escapeScope
,
argEscape
);
if
(
escapeScope
>=
scopeOfTheContainingExpression
)
{
var
argRefEscape
=
GetRefEscape
(
argument
,
scopeOfTheContainingExpression
);
re
fEscape
=
Math
.
Max
(
refEscape
,
argRefEscape
)
;
// can't get any worse
re
turn
escapeScope
;
}
}
}
return
refEsca
pe
;
return
escapeSco
pe
;
}
private
static
void
ReportReadonlyLocalError
(
SyntaxNode
node
,
LocalSymbol
local
,
BindValueKind
kind
,
bool
checkingReceiver
,
DiagnosticBag
diagnostics
)
...
...
@@ -1389,7 +1335,7 @@ internal bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint escapeT
break
;
}
return
CheckInvocation
Ref
Escape
(
return
CheckInvocationEscape
(
call
.
Syntax
,
methodSymbol
,
methodSymbol
.
Parameters
,
...
...
@@ -1404,7 +1350,7 @@ internal bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint escapeT
var
indexerAccess
=
(
BoundIndexerAccess
)
expr
;
var
indexerSymbol
=
indexerAccess
.
Indexer
;
return
CheckInvocation
Ref
Escape
(
return
CheckInvocationEscape
(
indexerAccess
.
Syntax
,
indexerSymbol
,
indexerSymbol
.
Parameters
,
...
...
@@ -1420,7 +1366,7 @@ internal bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint escapeT
var
propertySymbol
=
propertyAccess
.
PropertySymbol
;
// not passing any arguments/parameters
return
CheckInvocation
Ref
Escape
(
return
CheckInvocationEscape
(
propertyAccess
.
Syntax
,
propertySymbol
,
default
,
...
...
@@ -1443,19 +1389,26 @@ internal bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint escapeT
/// </summary>
internal
uint
GetRefEscape
(
BoundExpression
expr
,
uint
scopeOfTheContainingExpression
)
{
// cannot infer anything from errors
if
(
expr
.
HasAnyErrors
)
{
// cannot infer anything from errors
return
Binder
.
ExternalScope
;
}
Debug
.
Assert
(
expr
.
Type
.
GetSpecialTypeSafe
()
!=
SpecialType
.
System_Void
);
// cannot infer anything from Void (broken code)
if
(
expr
.
Type
?.
GetSpecialTypeSafe
()
==
SpecialType
.
System_Void
)
{
return
Binder
.
ExternalScope
;
}
if
(
expr
.
ConstantValue
!=
null
)
// constants/literals cannot ref-escape current scope
if
(
expr
.
ConstantValue
!=
null
)
{
return
scopeOfTheContainingExpression
;
}
// cover case that cannot refer to local state
// otherwise default to current scope (RValues, etc)
switch
(
expr
.
Kind
)
{
case
BoundKind
.
ArrayAccess
:
...
...
@@ -1557,7 +1510,96 @@ internal uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainingExpres
break
;
}
return
GetInvocationRefEscape
(
return
GetInvocationEscape
(
methodSymbol
.
Parameters
,
call
.
Arguments
,
call
.
ArgumentRefKindsOpt
,
call
.
ArgsToParamsOpt
,
scopeOfTheContainingExpression
);
case
BoundKind
.
IndexerAccess
:
var
indexerAccess
=
(
BoundIndexerAccess
)
expr
;
var
indexerSymbol
=
indexerAccess
.
Indexer
;
return
GetInvocationEscape
(
indexerSymbol
.
Parameters
,
indexerAccess
.
Arguments
,
indexerAccess
.
ArgumentRefKindsOpt
,
indexerAccess
.
ArgsToParamsOpt
,
scopeOfTheContainingExpression
);
case
BoundKind
.
PropertyAccess
:
var
propertyAccess
=
(
BoundPropertyAccess
)
expr
;
var
propertySymbol
=
propertyAccess
.
PropertySymbol
;
// not passing any arguments/parameters
return
GetInvocationEscape
(
default
,
default
,
default
,
default
,
scopeOfTheContainingExpression
);
}
// At this point we should have covered all the possible cases for anything that is not a strict RValue.
return
scopeOfTheContainingExpression
;
}
internal
uint
GetValEscape
(
BoundExpression
expr
,
uint
scopeOfTheContainingExpression
)
{
// cannot infer anything from errors
if
(
expr
.
HasAnyErrors
)
{
return
Binder
.
ExternalScope
;
}
// constants/literals cannot refer to local state
if
(
expr
.
ConstantValue
!=
null
)
{
return
Binder
.
ExternalScope
;
;
}
// to have local-referring values an expression must have a ref-like type
if
(
expr
.
Type
?.
IsByRefLikeType
!=
true
)
{
return
Binder
.
ExternalScope
;
;
}
// cover case that can refer to local state
// otherwise default to ExternalScope (ordinary values)
switch
(
expr
.
Kind
)
{
case
BoundKind
.
RefValueOperator
:
// The undocumented __refvalue(tr, T) expression results in a variable of type T.
// it is a readwrite variable, but could refer to unknown local data
// we will constrain it to the current scope
// TODO: VS is this right?
return
scopeOfTheContainingExpression
;
case
BoundKind
.
Local
:
return
((
BoundLocal
)
expr
).
LocalSymbol
.
ValEscapeScope
;
case
BoundKind
.
ConditionalOperator
:
var
conditional
=
(
BoundConditionalOperator
)
expr
;
// conditional defers to its operands
return
Math
.
Max
(
GetValEscape
(
conditional
.
Consequence
,
scopeOfTheContainingExpression
),
GetValEscape
(
conditional
.
Alternative
,
scopeOfTheContainingExpression
));
case
BoundKind
.
FieldAccess
:
var
fieldAccess
=
(
BoundFieldAccess
)
expr
;
var
fieldSymbol
=
fieldAccess
.
FieldSymbol
;
Debug
.
Assert
(!
fieldSymbol
.
IsStatic
&&
fieldSymbol
.
ContainingType
.
IsByRefLikeType
);
// for ref-like fields defer to the receiver.
return
GetRefEscape
(
fieldAccess
.
ReceiverOpt
,
scopeOfTheContainingExpression
);
case
BoundKind
.
Call
:
var
call
=
(
BoundCall
)
expr
;
var
methodSymbol
=
call
.
Method
;
return
GetInvocationEscape
(
methodSymbol
.
Parameters
,
call
.
Arguments
,
call
.
ArgumentRefKindsOpt
,
...
...
@@ -1568,7 +1610,7 @@ internal uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainingExpres
var
indexerAccess
=
(
BoundIndexerAccess
)
expr
;
var
indexerSymbol
=
indexerAccess
.
Indexer
;
return
GetInvocation
Ref
Escape
(
return
GetInvocationEscape
(
indexerSymbol
.
Parameters
,
indexerAccess
.
Arguments
,
indexerAccess
.
ArgumentRefKindsOpt
,
...
...
@@ -1580,12 +1622,15 @@ internal uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainingExpres
var
propertySymbol
=
propertyAccess
.
PropertySymbol
;
// not passing any arguments/parameters
return
GetInvocation
Ref
Escape
(
return
GetInvocationEscape
(
default
,
default
,
default
,
default
,
scopeOfTheContainingExpression
);
//TODO: VS other exprs with operands - Obj creations, binary, unary, parenthesized?, etc...
}
// At this point we should have covered all the possible cases for anything that is not a strict RValue.
...
...
src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
浏览文件 @
18bb0438
...
...
@@ -951,11 +951,7 @@ private TypeSymbol BindVariableType(CSharpSyntaxNode declarationNode, Diagnostic
{
var
currentScope
=
LocalScopeDepth
;
var
valEscape
=
localSymbol
.
Type
.
IsByRefLikeType
?
currentScope
:
// default to the current scope
Binder
.
ExternalScope
;
// no need to compute, it is safe to return by value
localSymbol
.
SetValEscape
(
valEscape
);
localSymbol
.
SetValEscape
(
GetValEscape
(
initializerOpt
,
currentScope
));
if
(
localSymbol
.
RefKind
!=
RefKind
.
None
)
{
...
...
src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs
浏览文件 @
18bb0438
...
...
@@ -379,7 +379,7 @@ internal void SetType(TypeSymbol newType)
Interlocked
.
CompareExchange
(
ref
_type
,
newType
,
null
);
}
// to handle error self-referential cases we will default to current scope
// to handle error self-referential cases we will default to
the
current scope
_valEscapeScope
=
_type
.
IsByRefLikeType
?
_scopeBinder
.
LocalScopeDepth
:
Binder
.
ExternalScope
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录