Browse Source

Added a separate AwaitResolveResult

newNRvisualizers
Erik Källén 13 years ago
parent
commit
66f51bff3a
  1. 1
      ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  2. 80
      ICSharpCode.NRefactory.CSharp/Resolver/AwaitResolveResult.cs
  3. 44
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  4. 366
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnaryOperatorTests.cs

1
ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -337,6 +337,7 @@
<Compile Include="Refactoring\TypeSystemAstBuilder.cs" /> <Compile Include="Refactoring\TypeSystemAstBuilder.cs" />
<Compile Include="Refactoring\VariableReferenceGraph.cs" /> <Compile Include="Refactoring\VariableReferenceGraph.cs" />
<Compile Include="Resolver\CompositeResolveVisitorNavigator.cs" /> <Compile Include="Resolver\CompositeResolveVisitorNavigator.cs" />
<Compile Include="Resolver\AwaitResolveResult.cs" />
<Compile Include="Resolver\DynamicInvocationResolveResult.cs" /> <Compile Include="Resolver\DynamicInvocationResolveResult.cs" />
<Compile Include="Resolver\DynamicMemberResolveResult.cs" /> <Compile Include="Resolver\DynamicMemberResolveResult.cs" />
<Compile Include="Resolver\CSharpConversions.cs" /> <Compile Include="Resolver\CSharpConversions.cs" />

80
ICSharpCode.NRefactory.CSharp/Resolver/AwaitResolveResult.cs

@ -0,0 +1,80 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Represents the result of an await expression.
/// </summary>
public class AwaitResolveResult : ResolveResult
{
/// <summary>
/// The method representing the GetAwaiter() call. Can be null if the GetAwaiter method was not found.
/// </summary>
public readonly ResolveResult GetAwaiterInvocation;
/// <summary>
/// Awaiter type. Will not be null (but can be UnknownType).
/// </summary>
public readonly IType AwaiterType;
/// <summary>
/// Property representing the IsCompleted property on the awaiter type. Can be null if the awaiter type or the property was not found, or when awaiting a dynamic expression.
/// </summary>
public readonly IProperty IsCompletedProperty;
/// <summary>
/// Method representing the OnCompleted method on the awaiter type. Can be null if the awaiter type or the method was not found, or when awaiting a dynamic expression.
/// </summary>
public readonly IMethod OnCompletedMethod;
/// <summary>
/// Method representing the GetResult method on the awaiter type. Can be null if the awaiter type or the method was not found, or when awaiting a dynamic expression.
/// </summary>
public readonly IMethod GetResultMethod;
public AwaitResolveResult(IType resultType, ResolveResult getAwaiterInvocation, IType awaiterType, IProperty isCompletedProperty, IMethod onCompletedMethod, IMethod getResultMethod)
: base(resultType)
{
if (awaiterType == null)
throw new ArgumentNullException("awaiterType");
if (getAwaiterInvocation == null)
throw new ArgumentNullException("getAwaiterInvocation");
this.GetAwaiterInvocation = getAwaiterInvocation;
this.AwaiterType = awaiterType;
this.IsCompletedProperty = isCompletedProperty;
this.OnCompletedMethod = onCompletedMethod;
this.GetResultMethod = getResultMethod;
}
public override bool IsError {
get { return this.GetAwaiterInvocation.IsError || (AwaiterType.Kind != TypeKind.Dynamic && (this.IsCompletedProperty == null || this.OnCompletedMethod == null || this.GetResultMethod == null)); }
}
public override IEnumerable<ResolveResult> GetChildResults() {
return new[] { GetAwaiterInvocation };
}
}
}

44
ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs

@ -360,8 +360,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region ResolveUnaryOperator method #region ResolveUnaryOperator method
public ResolveResult ResolveUnaryOperator(UnaryOperatorType op, ResolveResult expression) public ResolveResult ResolveUnaryOperator(UnaryOperatorType op, ResolveResult expression)
{ {
if (expression.Type.Kind == TypeKind.Dynamic) if (expression.Type.Kind == TypeKind.Dynamic) {
return UnaryOperatorResolveResult(SpecialType.Dynamic, op, expression); if (op == UnaryOperatorType.Await) {
return new AwaitResolveResult(SpecialType.Dynamic, new DynamicInvocationResolveResult(new DynamicMemberResolveResult(expression, "GetAwaiter"), DynamicInvocationType.Invocation, EmptyList<ResolveResult>.Instance), SpecialType.Dynamic, null, null, null);
}
else {
return UnaryOperatorResolveResult(SpecialType.Dynamic, op, expression);
}
}
// C# 4.0 spec: §7.3.3 Unary operator overload resolution // C# 4.0 spec: §7.3.3 Unary operator overload resolution
string overloadableOperatorName = GetOverloadableOperatorName(op); string overloadableOperatorName = GetOverloadableOperatorName(op);
@ -375,17 +381,37 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return ErrorResult; return ErrorResult;
case UnaryOperatorType.AddressOf: case UnaryOperatorType.AddressOf:
return UnaryOperatorResolveResult(new PointerType(expression.Type), op, expression); return UnaryOperatorResolveResult(new PointerType(expression.Type), op, expression);
case UnaryOperatorType.Await: case UnaryOperatorType.Await: {
ResolveResult getAwaiterMethodGroup = ResolveMemberAccess(expression, "GetAwaiter", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget); ResolveResult getAwaiterMethodGroup = ResolveMemberAccess(expression, "GetAwaiter", EmptyList<IType>.Instance, NameLookupMode.InvocationTarget);
ResolveResult getAwaiterInvocation = ResolveInvocation(getAwaiterMethodGroup, new ResolveResult[0]); ResolveResult getAwaiterInvocation = ResolveInvocation(getAwaiterMethodGroup, new ResolveResult[0]);
var getResultMethodGroup = CreateMemberLookup().Lookup(getAwaiterInvocation, "GetResult", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
var lookup = CreateMemberLookup();
IMethod getResultMethod;
IType awaitResultType;
var getResultMethodGroup = lookup.Lookup(getAwaiterInvocation, "GetResult", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
if (getResultMethodGroup != null) { if (getResultMethodGroup != null) {
var or = getResultMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0], allowExtensionMethods: false, conversions: conversions); var getResultOR = getResultMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0], allowExtensionMethods: false, conversions: conversions);
IType awaitResultType = or.GetBestCandidateWithSubstitutedTypeArguments().ReturnType; getResultMethod = getResultOR.FoundApplicableCandidate ? getResultOR.GetBestCandidateWithSubstitutedTypeArguments() as IMethod : null;
return UnaryOperatorResolveResult(awaitResultType, UnaryOperatorType.Await, expression); awaitResultType = getResultMethod != null ? getResultMethod.ReturnType : SpecialType.UnknownType;
} else { }
return UnaryOperatorResolveResult(SpecialType.UnknownType, UnaryOperatorType.Await, expression); else {
getResultMethod = null;
awaitResultType = SpecialType.UnknownType;
} }
var isCompletedRR = lookup.Lookup(getAwaiterInvocation, "IsCompleted", EmptyList<IType>.Instance, false);
var isCompletedProperty = (isCompletedRR is MemberResolveResult ? ((MemberResolveResult)isCompletedRR).Member as IProperty : null);
var onCompletedMethodGroup = lookup.Lookup(getAwaiterInvocation, "OnCompleted", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
IMethod onCompletedMethod = null;
if (onCompletedMethodGroup != null) {
var onCompletedOR = onCompletedMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[] { new TypeResolveResult(compilation.FindType(new FullTypeName("System.Action"))) }, allowExtensionMethods: false, conversions: conversions);
onCompletedMethod = (onCompletedOR.FoundApplicableCandidate ? onCompletedOR.GetBestCandidateWithSubstitutedTypeArguments() as IMethod : null);
}
return new AwaitResolveResult(awaitResultType, getAwaiterInvocation, getAwaiterInvocation.Type, isCompletedProperty, onCompletedMethod, getResultMethod);
}
default: default:
throw new ArgumentException("Invalid value for UnaryOperatorType", "op"); throw new ArgumentException("Invalid value for UnaryOperatorType", "op");
} }

366
ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnaryOperatorTests.cs

@ -274,5 +274,371 @@ class Test {
Assert.IsFalse(rr.IsError); Assert.IsFalse(rr.IsError);
Assert.AreEqual(unchecked( (ushort)~3 ), rr.ConstantValue); Assert.AreEqual(unchecked( (ushort)~3 ), rr.ConstantValue);
} }
[Test]
public void Await() {
string program = @"
using System;
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public MyAwaiter GetAwaiter() { return null; }
public MyAwaiter GetAwaiter(int i) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32));
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(0, getAwaiterInvocation.Arguments.Count);
Assert.AreEqual("MyAwaitable.GetAwaiter", getAwaiterInvocation.Member.FullName);
Assert.AreEqual(0, getAwaiterInvocation.Member.Parameters.Count);
Assert.AreEqual("MyAwaiter", rr.AwaiterType.FullName);
Assert.IsNotNull(rr.IsCompletedProperty);
Assert.AreEqual("MyAwaiter.IsCompleted", rr.IsCompletedProperty.FullName);
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("MyAwaiter.OnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNotNull(rr.GetResultMethod);
Assert.AreEqual("MyAwaiter.GetResult", rr.GetResultMethod.FullName);
}
[Test]
public void AwaitWhenGetAwaiterIsAnExtensionMethod() {
string program = @"
using System;
namespace N {
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
}
static class MyAwaitableExtensions {
public static MyAwaiter GetAwaiter(this MyAwaitable x) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32));
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(1, getAwaiterInvocation.Arguments.Count);
Assert.AreEqual("N.MyAwaitableExtensions.GetAwaiter", getAwaiterInvocation.Member.FullName);
Assert.AreEqual(1, getAwaiterInvocation.Member.Parameters.Count);
Assert.IsTrue(getAwaiterInvocation.Arguments[0] is LocalResolveResult && ((LocalResolveResult)getAwaiterInvocation.Arguments[0]).Variable.Name == "x");
Assert.AreEqual("N.MyAwaiter", rr.AwaiterType.FullName);
Assert.IsNotNull(rr.IsCompletedProperty);
Assert.AreEqual("N.MyAwaiter.IsCompleted", rr.IsCompletedProperty.FullName);
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("N.MyAwaiter.OnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNotNull(rr.GetResultMethod);
Assert.AreEqual("N.MyAwaiter.GetResult", rr.GetResultMethod.FullName);
}
[Test, Ignore("TODO: MS C# (at least the RC version) refuses to use default values in GetAwaiter(). I do not know, however, if this is by design, and I could not find a simple, nice way to do the implementation")]
public void GetAwaiterMethodWithDefaultArgumentCannotBeUsed() {
string program = @"
using System;
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public MyAwaiter GetAwaiter(int i = 0) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.AreEqual(SpecialType.UnknownType, rr.Type);
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
Assert.IsTrue(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(rr.AwaiterType, SpecialType.UnknownType);
Assert.IsNull(rr.IsCompletedProperty);
Assert.IsNull(rr.OnCompletedMethod);
Assert.IsNull(rr.GetResultMethod);
}
[Test, Ignore("TODO: MS C# (at least the RC version) refuses to use default values in GetAwaiter(). I do not know, however, if this is by design, and I could not find a simple, nice way to do the implementation")]
public void GetAwaiterMethodWithDefaultArgumentHidesExtensionMethodAndResultsInError() {
string program = @"
using System;
namespace N {
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public MyAwaiter GetAwaiter(int i = 0) { return null; }
}
static class MyAwaitableExtensions {
public static MyAwaiter GetAwaiter(this MyAwaitable x) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.AreEqual(SpecialType.UnknownType, rr.Type);
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
Assert.IsTrue(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(rr.AwaiterType, SpecialType.UnknownType);
Assert.IsNull(rr.IsCompletedProperty);
Assert.IsNull(rr.OnCompletedMethod);
Assert.IsNull(rr.GetResultMethod);
}
[Test]
public void GetAwaiterMethodWithArgumentDoesNotHideExtensionMethod() {
string program = @"
using System;
namespace N {
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public static MyAwaiter GetAwaiter(int i) { return null; }
}
static class MyAwaitableExtensions {
public static MyAwaiter GetAwaiter(this MyAwaitable x) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32));
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(1, getAwaiterInvocation.Arguments.Count);
Assert.AreEqual("N.MyAwaitableExtensions.GetAwaiter", getAwaiterInvocation.Member.FullName);
Assert.AreEqual(1, getAwaiterInvocation.Member.Parameters.Count);
Assert.IsTrue(getAwaiterInvocation.Arguments[0] is LocalResolveResult && ((LocalResolveResult)getAwaiterInvocation.Arguments[0]).Variable.Name == "x");
Assert.AreEqual("N.MyAwaiter", rr.AwaiterType.FullName);
Assert.IsNotNull(rr.IsCompletedProperty);
Assert.AreEqual("N.MyAwaiter.IsCompleted", rr.IsCompletedProperty.FullName);
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("N.MyAwaiter.OnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNotNull(rr.GetResultMethod);
Assert.AreEqual("N.MyAwaiter.GetResult", rr.GetResultMethod.FullName);
}
[Test]
public void AwaiterWithNoSuitableGetResult() {
string program = @"
using System;
namespace N {
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult(int i) { return 0; }
}
class MyAwaitable {
public static MyAwaiter GetAwaiter(int i) { return null; }
}
static class MyAwaitableExtensions {
public static MyAwaiter GetAwaiter(this MyAwaitable x) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsTrue(rr.IsError);
Assert.AreEqual(SpecialType.UnknownType, rr.Type);
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(1, getAwaiterInvocation.Arguments.Count);
Assert.AreEqual("N.MyAwaitableExtensions.GetAwaiter", getAwaiterInvocation.Member.FullName);
Assert.AreEqual(1, getAwaiterInvocation.Member.Parameters.Count);
Assert.IsTrue(getAwaiterInvocation.Arguments[0] is LocalResolveResult && ((LocalResolveResult)getAwaiterInvocation.Arguments[0]).Variable.Name == "x");
Assert.AreEqual("N.MyAwaiter", rr.AwaiterType.FullName);
Assert.IsNotNull(rr.IsCompletedProperty);
Assert.AreEqual("N.MyAwaiter.IsCompleted", rr.IsCompletedProperty.FullName);
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("N.MyAwaiter.OnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNull(rr.GetResultMethod);
}
[Test]
public void AwaiterWithNoIsCompletedProperty() {
string program = @"
using System;
namespace N {
class MyAwaiter {
public bool IsCompleted() { return false; }
public void OnCompleted(Action continuation) {}
public int GetResult(int i) { return 0; }
}
class MyAwaitable {
public static MyAwaiter GetAwaiter(int i) { return null; }
}
static class MyAwaitableExtensions {
public static MyAwaiter GetAwaiter(this MyAwaitable x) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsTrue(rr.IsError);
Assert.AreEqual(SpecialType.UnknownType, rr.Type);
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(1, getAwaiterInvocation.Arguments.Count);
Assert.AreEqual("N.MyAwaitableExtensions.GetAwaiter", getAwaiterInvocation.Member.FullName);
Assert.AreEqual(1, getAwaiterInvocation.Member.Parameters.Count);
Assert.IsTrue(getAwaiterInvocation.Arguments[0] is LocalResolveResult && ((LocalResolveResult)getAwaiterInvocation.Arguments[0]).Variable.Name == "x");
Assert.AreEqual("N.MyAwaiter", rr.AwaiterType.FullName);
Assert.IsNull(rr.IsCompletedProperty);
Assert.IsNotNull(rr.OnCompletedMethod);
Assert.AreEqual("N.MyAwaiter.OnCompleted", rr.OnCompletedMethod.FullName);
Assert.IsNull(rr.GetResultMethod);
}
[Test]
public void AwaiterWithNoOnCompletedMethodWithSuitableSignature() {
string program = @"
using System;
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Func<int> continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public MyAwaiter GetAwaiter() { return null; }
public MyAwaiter GetAwaiter(int i) { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = $await x$;
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsTrue(rr.IsError);
Assert.IsTrue(rr.Type.IsKnownType(KnownTypeCode.Int32));
Assert.IsInstanceOf<CSharpInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (CSharpInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(0, getAwaiterInvocation.Arguments.Count);
Assert.AreEqual("MyAwaitable.GetAwaiter", getAwaiterInvocation.Member.FullName);
Assert.AreEqual(0, getAwaiterInvocation.Member.Parameters.Count);
Assert.AreEqual("MyAwaiter", rr.AwaiterType.FullName);
Assert.IsNotNull(rr.IsCompletedProperty);
Assert.AreEqual("MyAwaiter.IsCompleted", rr.IsCompletedProperty.FullName);
Assert.IsNull(rr.OnCompletedMethod);
Assert.IsNotNull(rr.GetResultMethod);
Assert.AreEqual("MyAwaiter.GetResult", rr.GetResultMethod.FullName);
}
[Test]
public void AwaitDynamic() {
string program = @"
public class C {
public async void M() {
dynamic x = null;
int i = $await x$;
}
}";
var rr = Resolve<AwaitResolveResult>(program);
Assert.IsFalse(rr.IsError);
Assert.AreEqual(SpecialType.Dynamic, rr.Type);
Assert.IsInstanceOf<DynamicInvocationResolveResult>(rr.GetAwaiterInvocation);
var getAwaiterInvocation = (DynamicInvocationResolveResult)rr.GetAwaiterInvocation;
Assert.IsFalse(rr.GetAwaiterInvocation.IsError);
Assert.AreEqual(DynamicInvocationType.Invocation, getAwaiterInvocation.InvocationType);
Assert.AreEqual(0, getAwaiterInvocation.Arguments.Count);
Assert.IsInstanceOf<DynamicMemberResolveResult>(getAwaiterInvocation.Target);
var target = (DynamicMemberResolveResult)getAwaiterInvocation.Target;
Assert.IsInstanceOf<LocalResolveResult>(target.Target);
Assert.AreEqual("GetAwaiter", target.Member);
Assert.AreEqual(SpecialType.Dynamic, rr.AwaiterType);
Assert.IsNull(rr.IsCompletedProperty);
Assert.IsNull(rr.OnCompletedMethod);
Assert.IsNull(rr.GetResultMethod);
}
} }
} }

Loading…
Cancel
Save