Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
9d6aef71
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,发现更多精彩内容 >>
提交
9d6aef71
编写于
8月 26, 2015
作者:
C
CyrusNajmabadi
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #4800 from CyrusNajmabadi/flowInferenceAcrossReturnTypes
Flow inference values across generic method return types.
上级
47e6da37
c6304af9
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
161 addition
and
0 deletion
+161
-0
src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.cs
...itorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.cs
+38
-0
src/Workspaces/CSharp/Portable/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs
...nguageServices/CSharpTypeInferenceService.TypeInferrer.cs
+123
-0
未找到文件。
src/EditorFeatures/CSharpTest/TypeInferrer/TypeInferrerTests.cs
浏览文件 @
9d6aef71
...
...
@@ -1600,5 +1600,43 @@ static async void T()
}"
;
Test
(
text
,
"global::System.Threading.Tasks.Task<System.Boolean>"
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
TypeInferenceService
)]
[
WorkItem
(
4233
,
"https://github.com/dotnet/roslyn/issues/4233"
)]
public
void
TestAwaitExpressionWithGenericMethod1
()
{
var
text
=
@"using System.Threading.Tasks;
public class C
{
private async void M()
{
bool merged = await X([|Test()|]);
}
private async Task<T> X<T>(T t) { return t; }
}"
;
Test
(
text
,
"System.Boolean"
,
testPosition
:
false
);
}
[
Fact
,
Trait
(
Traits
.
Feature
,
Traits
.
Features
.
TypeInferenceService
)]
[
WorkItem
(
4233
,
"https://github.com/dotnet/roslyn/issues/4233"
)]
public
void
TestAwaitExpressionWithGenericMethod2
()
{
var
text
=
@"using System.Threading.Tasks;
public class C
{
private async void M()
{
bool merged = await Task.Run(() => [|Test()|]);;
}
private async Task<T> X<T>(T t) { return t; }
}"
;
Test
(
text
,
"System.Boolean"
);
}
}
}
src/Workspaces/CSharp/Portable/LanguageServices/CSharpTypeInferenceService.TypeInferrer.cs
浏览文件 @
9d6aef71
...
...
@@ -606,9 +606,132 @@ private IEnumerable<ITypeSymbol> InferTypeInAttributeArgument(int index, IEnumer
private
IEnumerable
<
ITypeSymbol
>
InferTypeInArgument
(
int
index
,
IEnumerable
<
IMethodSymbol
>
methods
,
ArgumentSyntax
argumentOpt
)
{
if
(
argumentOpt
!=
null
)
{
var
invocation
=
argumentOpt
?.
Parent
?.
Parent
as
InvocationExpressionSyntax
;
if
(
invocation
!=
null
)
{
// We're trying to figure out the signature of a method we're an argument to.
// That method may be generic, and we might end up using one of its generic
// type parameters in the type we infer. First, let's see if we can instantiate
// the methods so that the type can be inferred better.
var
invocationTypes
=
this
.
InferTypes
(
invocation
).
WhereNotNull
().
ToList
();
var
instantiatedMethods
=
methods
.
Select
(
m
=>
Instantiate
(
m
,
invocationTypes
)).
ToList
();
// Now that we've instantiated the methods, filter down to the ones that
// will actually return a viable type given where this invocation expression
// is.
var
filteredMethods
=
instantiatedMethods
.
Where
(
m
=>
invocationTypes
.
Any
(
t
=>
Compilation
.
ClassifyConversion
(
m
.
ReturnType
,
t
).
IsImplicit
)).
ToList
();
// If we filtered down to nothing, then just fall back to the instantiated list.
// this is a best effort after all.
methods
=
filteredMethods
.
Any
()
?
filteredMethods
:
instantiatedMethods
;
}
}
return
InferTypeInArgument
(
index
,
methods
.
Select
(
m
=>
m
.
Parameters
),
argumentOpt
);
}
private
IMethodSymbol
Instantiate
(
IMethodSymbol
method
,
IList
<
ITypeSymbol
>
invocationTypes
)
{
// No need to instantiate if this isn't a generic method.
if
(
method
.
TypeArguments
.
Length
==
0
)
{
return
method
;
}
// Can't infer the type parameters if this method doesn't have a return type.
// Note: this is because this code path is specifically flowing type information
// backward through the return type. Type information is already flowed forward
// through arguments by the compiler when we get the initial set of methods.
if
(
method
.
ReturnsVoid
)
{
return
method
;
}
// If the method has already been constructed poorly (i.e. with error types for type
// arguments), then unconstruct it.
if
(
method
.
TypeArguments
.
All
(
t
=>
t
.
Kind
==
SymbolKind
.
ErrorType
))
{
method
=
method
.
ConstructedFrom
;
}
IDictionary
<
ITypeParameterSymbol
,
ITypeSymbol
>
bestMap
=
null
;
foreach
(
var
type
in
invocationTypes
)
{
// Ok. We inferred a type for this location, and we have the return type of this
// method. See if we can then assign any values for type parameters.
var
map
=
DetermineTypeParameterMapping
(
type
,
method
.
ReturnType
);
if
(
map
.
Count
>
0
&&
(
bestMap
==
null
||
map
.
Count
>
bestMap
.
Count
))
{
bestMap
=
map
;
}
}
if
(
bestMap
==
null
)
{
return
method
;
}
var
typeArguments
=
method
.
ConstructedFrom
.
TypeParameters
.
Select
(
tp
=>
bestMap
.
GetValueOrDefault
(
tp
)
??
tp
).
ToArray
();
return
method
.
Construct
(
typeArguments
);
}
private
Dictionary
<
ITypeParameterSymbol
,
ITypeSymbol
>
DetermineTypeParameterMapping
(
ITypeSymbol
inferredType
,
ITypeSymbol
returnType
)
{
var
result
=
new
Dictionary
<
ITypeParameterSymbol
,
ITypeSymbol
>();
DetermineTypeParameterMapping
(
inferredType
,
returnType
,
result
);
return
result
;
}
private
void
DetermineTypeParameterMapping
(
ITypeSymbol
inferredType
,
ITypeSymbol
returnType
,
Dictionary
<
ITypeParameterSymbol
,
ITypeSymbol
>
result
)
{
if
(
inferredType
==
null
||
returnType
==
null
)
{
return
;
}
if
(
returnType
.
Kind
==
SymbolKind
.
TypeParameter
)
{
if
(
inferredType
.
Kind
!=
SymbolKind
.
TypeParameter
)
{
var
returnTypeParameter
=
(
ITypeParameterSymbol
)
returnType
;
if
(!
result
.
ContainsKey
(
returnTypeParameter
))
{
result
[
returnTypeParameter
]
=
inferredType
;
}
return
;
}
}
if
(
inferredType
.
Kind
!=
returnType
.
Kind
)
{
return
;
}
switch
(
inferredType
.
Kind
)
{
case
SymbolKind
.
ArrayType
:
DetermineTypeParameterMapping
(((
IArrayTypeSymbol
)
inferredType
).
ElementType
,
((
IArrayTypeSymbol
)
returnType
).
ElementType
,
result
);
return
;
case
SymbolKind
.
PointerType
:
DetermineTypeParameterMapping
(((
IPointerTypeSymbol
)
inferredType
).
PointedAtType
,
((
IPointerTypeSymbol
)
returnType
).
PointedAtType
,
result
);
return
;
case
SymbolKind
.
NamedType
:
var
inferredNamedType
=
(
INamedTypeSymbol
)
inferredType
;
var
returnNamedType
=
(
INamedTypeSymbol
)
returnType
;
if
(
inferredNamedType
.
TypeArguments
.
Length
==
returnNamedType
.
TypeArguments
.
Length
)
{
for
(
int
i
=
0
,
n
=
inferredNamedType
.
TypeArguments
.
Length
;
i
<
n
;
i
++)
{
DetermineTypeParameterMapping
(
inferredNamedType
.
TypeArguments
[
i
],
returnNamedType
.
TypeArguments
[
i
],
result
);
}
}
return
;
}
}
private
IEnumerable
<
ITypeSymbol
>
InferTypeInAttributeArgument
(
int
index
,
IEnumerable
<
ImmutableArray
<
IParameterSymbol
>>
parameterizedSymbols
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录