Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
ed4bab80
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,发现更多精彩内容 >>
提交
ed4bab80
编写于
8月 17, 2016
作者:
V
VSadov
提交者:
GitHub
8月 17, 2016
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #13107 from VSadov/tupleDataFlow
Implement definite assignment analysis for tuples
上级
faf30160
9d18615d
变更
6
展开全部
隐藏空白更改
内联
并排
Showing
6 changed file
with
1018 addition
and
52 deletion
+1018
-52
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs
+53
-0
src/Compilers/CSharp/Portable/FlowAnalysis/EmptyStructTypeCache.cs
...lers/CSharp/Portable/FlowAnalysis/EmptyStructTypeCache.cs
+11
-2
src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs
src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs
+11
-0
src/Compilers/CSharp/Portable/Symbols/Tuples/TupleFieldSymbol.cs
...pilers/CSharp/Portable/Symbols/Tuples/TupleFieldSymbol.cs
+42
-13
src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs
...mpilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs
+20
-16
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
+881
-21
未找到文件。
src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs
浏览文件 @
ed4bab80
...
...
@@ -664,6 +664,8 @@ private void NoteWrite(BoundExpression n, BoundExpression value, bool read)
/// </summary>
protected
int
VariableSlot
(
Symbol
symbol
,
int
containingSlot
=
0
)
{
containingSlot
=
DescendThroughTupleRestFields
(
ref
symbol
,
containingSlot
,
forceContainingSlotsToExist
:
false
);
int
slot
;
return
(
_variableSlot
.
TryGetValue
(
new
VariableIdentifier
(
symbol
,
containingSlot
),
out
slot
))
?
slot
:
-
1
;
}
...
...
@@ -674,6 +676,9 @@ protected int VariableSlot(Symbol symbol, int containingSlot = 0)
protected
int
GetOrCreateSlot
(
Symbol
symbol
,
int
containingSlot
=
0
)
{
if
(
symbol
is
RangeVariableSymbol
)
return
-
1
;
containingSlot
=
DescendThroughTupleRestFields
(
ref
symbol
,
containingSlot
,
forceContainingSlotsToExist
:
true
);
VariableIdentifier
identifier
=
new
VariableIdentifier
(
symbol
,
containingSlot
);
int
slot
;
...
...
@@ -700,6 +705,54 @@ protected int GetOrCreateSlot(Symbol symbol, int containingSlot = 0)
return
slot
;
}
/// <summary>
/// Descends through Rest fields of a tuple if "symbol" is an extended field
/// As a result the "symbol" will be adjusted to be the field of the innermost tuple
/// and a corresponding containingSlot is returned.
/// Return value -1 indicates a failure which could happen for the following reasons
/// a) Rest field does not exist, which could happen in rare error scenarios involving broken ValueTuple types
/// b) Rest is not tracked already and forceSlotsToExist is false (otherwise we create slots on demand)
/// </summary>
private
int
DescendThroughTupleRestFields
(
ref
Symbol
symbol
,
int
containingSlot
,
bool
forceContainingSlotsToExist
)
{
var
fieldSymbol
=
symbol
as
TupleFieldSymbol
;
if
((
object
)
fieldSymbol
!=
null
)
{
TypeSymbol
containingType
=
((
TupleTypeSymbol
)
symbol
.
ContainingType
).
UnderlyingNamedType
;
// for tuple fields the variable identifier represents the underlying field
symbol
=
fieldSymbol
.
TupleUnderlyingField
;
// descend through Rest fields
// force corresponding slots if do not exist
while
(
containingType
!=
symbol
.
ContainingType
)
{
var
restField
=
containingType
.
GetMembers
(
TupleTypeSymbol
.
RestFieldName
).
FirstOrDefault
()
as
FieldSymbol
;
if
((
object
)
restField
==
null
)
{
return
-
1
;
}
if
(
forceContainingSlotsToExist
)
{
containingSlot
=
GetOrCreateSlot
(
restField
,
containingSlot
);
}
else
{
if
(!
_variableSlot
.
TryGetValue
(
new
VariableIdentifier
(
restField
,
containingSlot
),
out
containingSlot
))
{
return
-
1
;
}
}
containingType
=
restField
.
Type
.
TupleUnderlyingTypeOrSelf
();
}
}
return
containingSlot
;
}
private
void
Normalize
(
ref
LocalState
state
)
{
int
oldNext
=
state
.
Assigned
.
Capacity
;
...
...
src/Compilers/CSharp/Portable/FlowAnalysis/EmptyStructTypeCache.cs
浏览文件 @
ed4bab80
...
...
@@ -118,8 +118,8 @@ private bool CheckStructInstanceFields(ConsList<NamedTypeSymbol> typesWithMember
if
((
object
)
field
!=
null
)
{
var
actualFi
le
dType
=
field
.
Type
;
if
(!
IsEmptyStructType
(
actualFi
le
dType
,
typesWithMembersOfThisType
))
var
actualFi
el
dType
=
field
.
Type
;
if
(!
IsEmptyStructType
(
actualFi
el
dType
,
typesWithMembersOfThisType
))
{
return
false
;
}
...
...
@@ -167,6 +167,15 @@ private FieldSymbol GetActualInstanceField(Symbol member, NamedTypeSymbol type)
{
case
SymbolKind
.
Field
:
var
field
=
(
FieldSymbol
)
member
;
// Do not report virtual tuple fields.
// They are additional aliases to the fields of the underlying struct or nested extensions.
// and as such are already accounted for via the nonvirtual fields.
if
(
field
.
IsVirtualTupleField
)
{
return
null
;
}
return
(
field
.
IsFixed
||
ShouldIgnoreStructField
(
field
,
field
.
Type
))
?
null
:
field
.
AsMember
(
type
);
case
SymbolKind
.
Event
:
...
...
src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs
浏览文件 @
ed4bab80
...
...
@@ -384,6 +384,17 @@ public virtual bool IsTupleField
}
}
/// <summary>
/// Returns True when field symbol is not mapped directly to a field in the underlying tuple struct.
/// </summary>
internal
virtual
bool
IsVirtualTupleField
{
get
{
return
false
;
}
}
/// <summary>
/// If this is a field of a tuple type, return corresponding underlying field from the
/// tuple underlying type. Otherwise, null. In case of a malformed underlying type
...
...
src/Compilers/CSharp/Portable/Symbols/Tuples/TupleFieldSymbol.cs
浏览文件 @
ed4bab80
...
...
@@ -15,7 +15,7 @@ internal class TupleFieldSymbol : WrappedFieldSymbol
protected
readonly
TupleTypeSymbol
_containingTuple
;
/// <summary>
/// If this field represents a tuple element
(including the name match)
,
/// If this field represents a tuple element,
/// id is an index of the element (zero-based).
/// Otherwise, (-1 - [index in members array]);
/// </summary>
...
...
@@ -24,6 +24,9 @@ internal class TupleFieldSymbol : WrappedFieldSymbol
public
TupleFieldSymbol
(
TupleTypeSymbol
container
,
FieldSymbol
underlyingField
,
int
tupleFieldId
)
:
base
(
underlyingField
)
{
Debug
.
Assert
(
container
.
UnderlyingNamedType
.
Equals
(
underlyingField
.
ContainingType
,
TypeCompareKind
.
IgnoreDynamicAndTupleNames
)
||
this
is
TupleVirtualElementFieldSymbol
,
"virtual fields should be represented by "
+
nameof
(
TupleVirtualElementFieldSymbol
));
_containingTuple
=
container
;
_tupleFieldId
=
tupleFieldId
;
}
...
...
@@ -37,7 +40,7 @@ public override bool IsTupleField
}
/// <summary>
/// If this field represents a tuple element
(including the name match)
,
/// If this field represents a tuple element,
/// id is an index of the element (zero-based).
/// Otherwise, (-1 - [index in members array]);
/// </summary>i
...
...
@@ -100,22 +103,27 @@ internal override DiagnosticInfo GetUseSiteDiagnostic()
public
override
sealed
int
GetHashCode
()
{
return
Hash
.
Combine
(
_containingTuple
.
GetHashCode
(),
_tupleFieldId
.
GetHashCode
());
return
Hash
.
Combine
(
Hash
.
Combine
(
_containingTuple
.
GetHashCode
(),
_tupleFieldId
.
GetHashCode
()),
this
.
Name
.
GetHashCode
());
}
public
override
sealed
bool
Equals
(
object
obj
)
{
return
Equals
(
obj
as
TupleFieldSymbol
);
}
var
other
=
obj
as
TupleFieldSymbol
;
public
bool
Equals
(
TupleFieldSymbol
other
)
{
if
((
object
)
other
==
this
)
{
return
true
;
}
return
(
object
)
other
!=
null
&&
_tupleFieldId
==
other
.
_tupleFieldId
&&
_containingTuple
==
other
.
_containingTuple
;
// note we have to compare both index and name because
// in nameless tuple there could be fields that differ only by index
// and in named tupoles there could be fields that differ only by name
return
(
object
)
other
!=
null
&&
_tupleFieldId
==
other
.
TupleElementIndex
&&
_containingTuple
==
other
.
_containingTuple
&&
this
.
Name
==
other
.
Name
;
}
}
...
...
@@ -185,18 +193,31 @@ public override Symbol AssociatedSymbol
}
/// <summary>
/// Represents an element field of a tuple type (such as (int a, byte b).a, or (int a, byte b).b)
/// that is backed by a real field with a different name within the tuple underlying type.
/// Represents an element field of a tuple type that is not backed by a real field
/// with the same name within the tuple underlying type.
///
/// Examples
/// // alias to Item1 with a different name
/// (int a, byte b).a
///
/// // not backed directly by the underlying type
/// (int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8).i8
///
/// NOTE: For any virtual element, there is a nonvirtual way to access the same underlying field.
/// In scenarios where we need to enumerate actual fields of a struct,
/// virtual fields should be ignored.
/// </summary>
internal
sealed
class
Tuple
Renamed
ElementFieldSymbol
:
TupleElementFieldSymbol
internal
sealed
class
Tuple
Virtual
ElementFieldSymbol
:
TupleElementFieldSymbol
{
private
readonly
string
_name
;
public
Tuple
Renamed
ElementFieldSymbol
(
TupleTypeSymbol
container
,
FieldSymbol
underlyingField
,
string
name
,
int
tupleElementOrdinal
,
Location
location
)
public
Tuple
Virtual
ElementFieldSymbol
(
TupleTypeSymbol
container
,
FieldSymbol
underlyingField
,
string
name
,
int
tupleElementOrdinal
,
Location
location
)
:
base
(
container
,
underlyingField
,
tupleElementOrdinal
,
location
)
{
Debug
.
Assert
(
name
!=
null
);
Debug
.
Assert
(
name
!=
underlyingField
.
Name
);
Debug
.
Assert
(
name
!=
underlyingField
.
Name
||
!
container
.
UnderlyingNamedType
.
Equals
(
underlyingField
.
ContainingType
,
TypeCompareKind
.
IgnoreDynamicAndTupleNames
),
"fields that map directly to underlying should not be represented by "
+
nameof
(
TupleVirtualElementFieldSymbol
));
_name
=
name
;
}
...
...
@@ -223,5 +244,13 @@ public override Symbol AssociatedSymbol
return
null
;
}
}
internal
override
bool
IsVirtualTupleField
{
get
{
return
true
;
}
}
}
}
src/Compilers/CSharp/Portable/Symbols/Tuples/TupleTypeSymbol.cs
浏览文件 @
ed4bab80
...
...
@@ -44,6 +44,7 @@ internal sealed class TupleTypeSymbol : WrappedNamedTypeSymbol
internal
const
int
RestPosition
=
8
;
// The Rest field is in 8th position
internal
const
string
TupleTypeName
=
"ValueTuple"
;
internal
const
string
RestFieldName
=
"Rest"
;
private
TupleTypeSymbol
(
Location
locationOpt
,
NamedTypeSymbol
underlyingType
,
ImmutableArray
<
Location
>
elementLocations
,
ImmutableArray
<
string
>
elementNames
,
ImmutableArray
<
TypeSymbol
>
elementTypes
)
:
this
(
locationOpt
==
null
?
ImmutableArray
<
Location
>.
Empty
:
ImmutableArray
.
Create
(
locationOpt
),
...
...
@@ -555,6 +556,15 @@ internal static int IsElementNameReserved(string name)
return
0
;
}
return
MatchesCanonicalElementName
(
name
);
}
/// <summary>
/// Returns 3 for "Item3".
/// Returns -1 otherwise.
/// </summary>
private
static
int
MatchesCanonicalElementName
(
string
name
)
{
if
(
name
.
StartsWith
(
"Item"
,
StringComparison
.
Ordinal
))
{
string
tail
=
name
.
Substring
(
4
);
...
...
@@ -723,13 +733,13 @@ private ImmutableArray<FieldSymbol> CollectTupleElementFields()
continue
;
}
int
index
=
(
member
as
TupleFieldSymbol
)?.
TupleElementIndex
??
((
TupleErrorFieldSymbol
)
member
)
.
TupleElementIndex
;
var
field
=
(
FieldSymbol
)
member
;
var
index
=
field
.
TupleElementIndex
;
if
(
index
>=
0
)
if
(
index
>=
0
&&
index
==
MatchesCanonicalElementName
(
field
.
Name
)
-
1
)
{
Debug
.
Assert
((
object
)
builder
[
index
]
==
null
);
builder
[
index
]
=
(
FieldSymbol
)
member
;
builder
[
index
]
=
field
;
}
}
...
...
@@ -813,21 +823,15 @@ private ImmutableArray<Symbol> CreateMembers()
if
(
namesOfVirtualFields
[
tupleFieldIndex
]
!=
defaultName
)
{
// The name given doesn't match default name Item8, etc.
members
.
Add
(
new
TupleRenamedElementFieldSymbol
(
this
,
fieldSymbol
,
defaultName
,
-
members
.
Count
-
1
,
null
));
// Add a field with default name and make it virtual since we are not at the top level
members
.
Add
(
new
TupleVirtualElementFieldSymbol
(
this
,
fieldSymbol
,
defaultName
,
tupleFieldIndex
,
null
));
}
// Add a field with the given name
var
location
=
_elementLocations
.
IsDefault
?
null
:
_elementLocations
[
tupleFieldIndex
];
members
.
Add
(
new
TupleVirtualElementFieldSymbol
(
this
,
fieldSymbol
,
namesOfVirtualFields
[
tupleFieldIndex
],
tupleFieldIndex
,
location
));
if
(
field
.
Name
==
namesOfVirtualFields
[
tupleFieldIndex
])
{
members
.
Add
(
new
TupleElementFieldSymbol
(
this
,
fieldSymbol
,
tupleFieldIndex
,
location
));
}
else
{
members
.
Add
(
new
TupleRenamedElementFieldSymbol
(
this
,
fieldSymbol
,
namesOfVirtualFields
[
tupleFieldIndex
],
tupleFieldIndex
,
location
));
}
}
else
if
(
field
.
Name
==
namesOfVirtualFields
[
tupleFieldIndex
])
{
...
...
@@ -837,12 +841,12 @@ private ImmutableArray<Symbol> CreateMembers()
else
{
// Add a field with default name
members
.
Add
(
new
TupleFieldSymbol
(
this
,
fieldSymbol
,
-
members
.
Count
-
1
));
members
.
Add
(
new
TupleFieldSymbol
(
this
,
fieldSymbol
,
tupleFieldIndex
));
// Add a field with the given name
if
(
namesOfVirtualFields
[
tupleFieldIndex
]
!=
null
)
{
members
.
Add
(
new
Tuple
Renamed
ElementFieldSymbol
(
this
,
fieldSymbol
,
namesOfVirtualFields
[
tupleFieldIndex
],
tupleFieldIndex
,
members
.
Add
(
new
Tuple
Virtual
ElementFieldSymbol
(
this
,
fieldSymbol
,
namesOfVirtualFields
[
tupleFieldIndex
],
tupleFieldIndex
,
_elementLocations
.
IsDefault
?
null
:
_elementLocations
[
tupleFieldIndex
]));
}
}
...
...
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
浏览文件 @
ed4bab80
此差异已折叠。
点击以展开。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录