提交 e82ef8f2 编写于 作者: C CyrusNajmabadi

Merge pull request #5564 from CyrusNajmabadi/returnInAsyncLambda

Property support inference in async lambda/delegates

Fixes #4486
......@@ -1719,5 +1719,43 @@ void M(IEnumerable<string> args)
}";
Test(text, "System.Object", testPosition: false);
}
[Fact, Trait(Traits.Feature, Traits.Features.TypeInferenceService)]
[WorkItem(4486, "https://github.com/dotnet/roslyn/issues/4486")]
public void TestReturnInAsyncLambda1()
{
var text =
@"using System;
using System.IO;
using System.Threading.Tasks;
public class C
{
public async void M()
{
Func<Task<int>> t2 = async () => { return [|a|]; };
}
}";
Test(text, "System.Int32");
}
[Fact, Trait(Traits.Feature, Traits.Features.TypeInferenceService)]
[WorkItem(4486, "https://github.com/dotnet/roslyn/issues/4486")]
public void TestReturnInAsyncLambda2()
{
var text =
@"using System;
using System.IO;
using System.Threading.Tasks;
public class C
{
public async void M()
{
Func<Task<int>> t2 = async delegate () { return [|a|]; };
}
}";
Test(text, "System.Int32");
}
}
}
\ No newline at end of file
......@@ -1523,10 +1523,39 @@ private IEnumerable<ITypeSymbol> InferTypeInYieldStatement(YieldStatementSyntax
private IEnumerable<ITypeSymbol> InferTypeForReturnStatement(ReturnStatementSyntax returnStatement, SyntaxToken? previousToken = null)
{
bool isAsync;
IEnumerable<ITypeSymbol> types;
InferTypeForReturnStatement(returnStatement, previousToken, out isAsync, out types);
if (!isAsync)
{
return types;
}
var taskOfT = this.Compilation.TaskOfTType();
if (taskOfT == null || types == null)
{
return SpecializedCollections.EmptyEnumerable<ITypeSymbol>();
}
return from t in types
where t != null && t.OriginalDefinition.Equals(taskOfT)
let nt = (INamedTypeSymbol)t
where nt.TypeArguments.Length == 1
select nt.TypeArguments[0];
}
private void InferTypeForReturnStatement(
ReturnStatementSyntax returnStatement, SyntaxToken? previousToken, out bool isAsync, out IEnumerable<ITypeSymbol> types)
{
isAsync = false;
types = SpecializedCollections.EmptyEnumerable<ITypeSymbol>();
// If we are position based, then we have to be after the return statement.
if (previousToken.HasValue && previousToken.Value != returnStatement.ReturnKeyword)
{
return SpecializedCollections.EmptyEnumerable<ITypeSymbol>();
return;
}
var ancestorExpressions = returnStatement.GetAncestorsOrThis<ExpressionSyntax>();
......@@ -1536,11 +1565,13 @@ private IEnumerable<ITypeSymbol> InferTypeForReturnStatement(ReturnStatementSynt
var lambda = ancestorExpressions.FirstOrDefault(e => e.IsKind(SyntaxKind.ParenthesizedLambdaExpression, SyntaxKind.SimpleLambdaExpression));
if (lambda != null)
{
return InferTypeInLambdaExpression(lambda);
types= InferTypeInLambdaExpression(lambda);
isAsync = lambda is ParenthesizedLambdaExpressionSyntax && ((ParenthesizedLambdaExpressionSyntax)lambda).AsyncKeyword.Kind() != SyntaxKind.None;
return;
}
// If we are inside a delegate then use the return type of the Invoke Method of the delegate type
var delegateExpression = ancestorExpressions.FirstOrDefault(e => e.IsKind(SyntaxKind.AnonymousMethodExpression));
var delegateExpression = (AnonymousMethodExpressionSyntax)ancestorExpressions.FirstOrDefault(e => e.IsKind(SyntaxKind.AnonymousMethodExpression));
if (delegateExpression != null)
{
var delegateType = InferTypes(delegateExpression).FirstOrDefault();
......@@ -1549,7 +1580,9 @@ private IEnumerable<ITypeSymbol> InferTypeForReturnStatement(ReturnStatementSynt
var delegateInvokeMethod = delegateType.GetDelegateType(this.Compilation).DelegateInvokeMethod;
if (delegateInvokeMethod != null)
{
return SpecializedCollections.SingletonEnumerable(delegateInvokeMethod.ReturnType);
types = SpecializedCollections.SingletonEnumerable(delegateInvokeMethod.ReturnType);
isAsync = delegateExpression.AsyncKeyword.Kind() != SyntaxKind.None;
return;
}
}
}
......@@ -1559,30 +1592,21 @@ private IEnumerable<ITypeSymbol> InferTypeForReturnStatement(ReturnStatementSynt
if (memberSymbol.IsKind(SymbolKind.Method))
{
var method = memberSymbol as IMethodSymbol;
if (method.IsAsync)
{
var typeArguments = method.ReturnType.GetTypeArguments();
var taskOfT = this.Compilation.TaskOfTType();
return taskOfT != null && method.ReturnType.OriginalDefinition == taskOfT && typeArguments.Any()
? SpecializedCollections.SingletonEnumerable(typeArguments.First())
: SpecializedCollections.EmptyEnumerable<ITypeSymbol>();
}
else
{
return SpecializedCollections.SingletonEnumerable(method.ReturnType);
}
isAsync = method.IsAsync;
types = SpecializedCollections.SingletonEnumerable(method.ReturnType);
return;
}
else if (memberSymbol.IsKind(SymbolKind.Property))
{
return SpecializedCollections.SingletonEnumerable((memberSymbol as IPropertySymbol).Type);
types = SpecializedCollections.SingletonEnumerable((memberSymbol as IPropertySymbol).Type);
return;
}
else if (memberSymbol.IsKind(SymbolKind.Field))
{
return SpecializedCollections.SingletonEnumerable((memberSymbol as IFieldSymbol).Type);
types = SpecializedCollections.SingletonEnumerable((memberSymbol as IFieldSymbol).Type);
return;
}
return SpecializedCollections.EmptyEnumerable<ITypeSymbol>();
}
private ISymbol GetDeclaredMemberSymbolFromOriginalSemanticModel(SemanticModel currentSemanticModel, MemberDeclarationSyntax declarationInCurrentTree)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册