diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs index c405c81bbb7d00d544c5496b6839ed96f0e59a36..843b7a2ca26bced583edc9581246803666f77e21 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs @@ -941,7 +941,7 @@ private static bool DoesInputTypeContain(BoundExpression argument, TypeSymbol fo } var delegateParameters = delegateType.DelegateParameters(); - if (delegateParameters.IsEmpty) + if (delegateParameters.IsDefaultOrEmpty) { return false; } diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs index bd1f0d7fcc2c569c937a7fac05339a713f848b12..f4bdd24a951799231b01a923ab0aa8bc0f1074fb 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodBuilderMemberCollection.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Roslyn.Utilities; @@ -102,6 +103,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, if (method.IsVoidReturningAsync()) { var builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncVoidMethodBuilder); + Debug.Assert((object)builderType != null); MethodSymbol createBuilderMethod; bool customBuilder = false; TryGetBuilderMember( @@ -110,8 +112,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, builderType, customBuilder, out createBuilderMethod); - if ((object)builderType == null || - (object)createBuilderMethod == null) + if ((object)createBuilderMethod == null) { collection = default(AsyncMethodBuilderMemberCollection); return false; @@ -146,6 +147,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, else { builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder); + Debug.Assert((object)builderType != null); TryGetBuilderMember( F, WellKnownMember.System_Runtime_CompilerServices_AsyncTaskMethodBuilder__Create, @@ -159,8 +161,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, customBuilder, out taskProperty); } - if ((object)builderType == null || - (object)createBuilderMethod == null || + if ((object)createBuilderMethod == null || (object)taskProperty == null) { collection = default(AsyncMethodBuilderMemberCollection); @@ -202,11 +203,7 @@ internal static bool TryCreate(SyntheticBoundNodeFactory F, MethodSymbol method, if (!customBuilder) { builderType = F.WellKnownType(WellKnownType.System_Runtime_CompilerServices_AsyncTaskMethodBuilder_T); - if ((object)builderType == null) - { - collection = default(AsyncMethodBuilderMemberCollection); - return false; - } + Debug.Assert((object)builderType != null); builderType = builderType.Construct(resultType); } if (customBuilder) diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index b1b67462ddfa61c57a470c740801c5ce6db9d2d8..bce6baa227300a031c9ea22f8617f2aa066d89bf 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -355,9 +355,12 @@ public static bool IsDelegateType(this TypeSymbol type) public static ImmutableArray DelegateParameters(this TypeSymbol type) { - Debug.Assert((object)type.DelegateInvokeMethod() != null && !type.DelegateInvokeMethod().HasUseSiteError, - "This method should only be called on valid delegate types."); - return type.DelegateInvokeMethod().Parameters; + var invokeMethod = type.DelegateInvokeMethod(); + if ((object)invokeMethod == null) + { + return default(ImmutableArray); + } + return invokeMethod.Parameters; } public static bool TryGetElementTypesIfTupleOrCompatible(this TypeSymbol type, out ImmutableArray elementTypes) @@ -1339,28 +1342,30 @@ internal static bool IsCustomTaskType(this NamedTypeSymbol type, out NamedTypeSy /// internal static TypeSymbol NormalizeTaskTypes(this TypeSymbol type, CSharpCompilation compilation) { - NormalizeTaskTypesCore(compilation, ref type); + NormalizeTaskTypesInType(compilation, ref type); return type; } /// /// Replace Task-like types with Task types. Returns true if there were changes. /// - private static bool NormalizeTaskTypesCore(CSharpCompilation compilation, ref TypeSymbol type) + private static bool NormalizeTaskTypesInType(CSharpCompilation compilation, ref TypeSymbol type) { switch (type.Kind) { case SymbolKind.NamedType: { var namedType = (NamedTypeSymbol)type; - var changed = NormalizeTaskTypesCore(compilation, ref namedType); + var changed = type.IsTupleType ? + NormalizeTaskTypesInTuple(compilation, ref namedType) : + NormalizeTaskTypesInNamedType(compilation, ref namedType); type = namedType; return changed; } case SymbolKind.ArrayType: { var arrayType = (ArrayTypeSymbol)type; - var changed = NormalizeTaskTypesCore(compilation, ref arrayType); + var changed = NormalizeTaskTypesInArray(compilation, ref arrayType); type = arrayType; return changed; } @@ -1368,7 +1373,7 @@ private static bool NormalizeTaskTypesCore(CSharpCompilation compilation, ref Ty return false; } - private static bool NormalizeTaskTypesCore(CSharpCompilation compilation, ref NamedTypeSymbol type) + private static bool NormalizeTaskTypesInNamedType(CSharpCompilation compilation, ref NamedTypeSymbol type) { bool hasChanged = false; @@ -1380,12 +1385,13 @@ private static bool NormalizeTaskTypesCore(CSharpCompilation compilation, ref Na type.GetAllTypeArguments(typeArgumentsBuilder, ref useSiteDiagnostics); for (int i = 0; i < typeArgumentsBuilder.Count; i++) { - var typeArgNormalized = typeArgumentsBuilder[i].Type; - if (NormalizeTaskTypesCore(compilation, ref typeArgNormalized)) + var typeWithModifier = typeArgumentsBuilder[i]; + var typeArgNormalized = typeWithModifier.Type; + if (NormalizeTaskTypesInType(compilation, ref typeArgNormalized)) { hasChanged = true; - // Should preserve custom modifiers (see https://github.com/dotnet/roslyn/issues/12615). - typeArgumentsBuilder[i] = new TypeWithModifiers(typeArgNormalized); + // Preserve custom modifiers but without normalizing those types. + typeArgumentsBuilder[i] = new TypeWithModifiers(typeArgNormalized, typeWithModifier.CustomModifiers); } } if (hasChanged) @@ -1415,17 +1421,34 @@ private static bool NormalizeTaskTypesCore(CSharpCompilation compilation, ref Na } type = arity == 0 ? taskType : - taskType.Construct(type.TypeArgumentsNoUseSiteDiagnostics); + taskType.Construct( + ImmutableArray.Create( + new TypeWithModifiers( + type.TypeArgumentsNoUseSiteDiagnostics[0], + type.HasTypeArgumentsCustomModifiers ? type.TypeArgumentsCustomModifiers[0] : default(ImmutableArray))), + unbound: false); hasChanged = true; } return hasChanged; } - private static bool NormalizeTaskTypesCore(CSharpCompilation compilation, ref ArrayTypeSymbol arrayType) + private static bool NormalizeTaskTypesInTuple(CSharpCompilation compilation, ref NamedTypeSymbol type) + { + Debug.Assert(type.IsTupleType); + var underlyingType = type.TupleUnderlyingType; + if (!NormalizeTaskTypesInNamedType(compilation, ref underlyingType)) + { + return false; + } + type = TupleTypeSymbol.Create(underlyingType, type.TupleElementNames); + return true; + } + + private static bool NormalizeTaskTypesInArray(CSharpCompilation compilation, ref ArrayTypeSymbol arrayType) { var elementType = arrayType.ElementType; - if (!NormalizeTaskTypesCore(compilation, ref elementType)) + if (!NormalizeTaskTypesInType(compilation, ref elementType)) { return false; } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index 628f0d469d0ef784429c6cb26e8f739486820256..b7cf7cfbee54ab0fd942f80c5dfd8e1f3f550613 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -3124,13 +3124,13 @@ public static void Main() [WorkItem(840843, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/840843")] [Fact] - public void MissingAsyncMethodBuilder() + public void MissingAsyncVoidMethodBuilder() { var source = @" class C { async void M() {} - } +} "; var comp = CSharpTestBaseBase.CreateCompilation(source, new[] { MscorlibRef }, TestOptions.ReleaseDll); // NOTE: 4.0, not 4.5, so it's missing the async helpers. @@ -3154,6 +3154,68 @@ class C Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{}").WithArguments("System.Runtime.CompilerServices.IAsyncStateMachine", "SetStateMachine").WithLocation(4, 20)); } + [Fact] + public void MissingAsyncTaskMethodBuilder() + { + var source = +@"using System.Threading.Tasks; +class C +{ + async Task M() {} +}"; + var comp = CSharpTestBaseBase.CreateCompilation(source, new[] { MscorlibRef }, TestOptions.ReleaseDll); // NOTE: 4.0, not 4.5, so it's missing the async helpers. + comp.VerifyEmitDiagnostics( + // (4,16): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. + // async Task M() {} + Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "M").WithLocation(4, 16), + // (4,20): error CS0518: Predefined type 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder' is not defined or imported + // async Task M() {} + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "{}").WithArguments("System.Runtime.CompilerServices.AsyncTaskMethodBuilder").WithLocation(4, 20), + // (4,20): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Create' + // async Task M() {} + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{}").WithArguments("System.Runtime.CompilerServices.AsyncTaskMethodBuilder", "Create").WithLocation(4, 20), + // (4,20): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Task' + // async Task M() {} + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{}").WithArguments("System.Runtime.CompilerServices.AsyncTaskMethodBuilder", "Task").WithLocation(4, 20), + // (4,20): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext' + // async Task M() {} + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{}").WithArguments("System.Runtime.CompilerServices.IAsyncStateMachine", "MoveNext").WithLocation(4, 20), + // (4,20): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.IAsyncStateMachine.SetStateMachine' + // async Task M() {} + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "{}").WithArguments("System.Runtime.CompilerServices.IAsyncStateMachine", "SetStateMachine").WithLocation(4, 20)); + } + + [Fact] + public void MissingAsyncTaskMethodBuilder_T() + { + var source = +@"using System.Threading.Tasks; +class C +{ + async Task F() => 3; +}"; + var comp = CSharpTestBaseBase.CreateCompilation(source, new[] { MscorlibRef }, TestOptions.ReleaseDll); // NOTE: 4.0, not 4.5, so it's missing the async helpers. + comp.VerifyEmitDiagnostics( + // (4,21): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. + // async Task F() => 3; + Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "F").WithLocation(4, 21), + // (4,25): error CS0518: Predefined type 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1' is not defined or imported + // async Task F() => 3; + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "=> 3").WithArguments("System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1").WithLocation(4, 25), + // (4,25): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Create' + // async Task F() => 3; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> 3").WithArguments("System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1", "Create").WithLocation(4, 25), + // (4,25): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Task' + // async Task F() => 3; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> 3").WithArguments("System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1", "Task").WithLocation(4, 25), + // (4,25): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext' + // async Task F() => 3; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> 3").WithArguments("System.Runtime.CompilerServices.IAsyncStateMachine", "MoveNext").WithLocation(4, 25), + // (4,25): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.IAsyncStateMachine.SetStateMachine' + // async Task F() => 3; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> 3").WithArguments("System.Runtime.CompilerServices.IAsyncStateMachine", "SetStateMachine").WithLocation(4, 25)); + } + [Fact] public void PresentAsyncTasklikeBuilderMethod() { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs index 8c6563f29c3d8f003818c9d5d1a7988176eec70e..f9629b82328c84a5b16e170e046b420ecc3fcf20 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs @@ -406,6 +406,67 @@ class MyTaskMethodBuilder Assert.Equal("MyTask", method.ReturnType.ToDisplayString()); } + [Fact] + public void Dynamic() + { + var source = +@"using System; +using System.Runtime.CompilerServices; +class C +{ + static void F(Func> f) { } + static void G(Func> f) { } + static void M(object o) + { +#pragma warning disable CS1998 + F(async () => (dynamic)o); + F(async () => new[] { (dynamic)o }); + G(async () => o); +#pragma warning restore CS1998 + } +} +class MyTask +{ + public static MyTaskMethodBuilder CreateAsyncMethodBuilder() => null; + internal Awaiter GetAwaiter() => null; + internal class Awaiter : INotifyCompletion + { + public void OnCompleted(Action a) { } + internal bool IsCompleted => true; + internal T GetResult() => default(T); + } +} +class MyTaskMethodBuilder +{ + public void SetStateMachine(IAsyncStateMachine stateMachine) { } + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { } + public void SetException(Exception e) { } + public void SetResult(T t) { } + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { } + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { } + public MyTask Task => default(MyTask); +}"; + var compilation = CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }); + var verifier = CompileAndVerify( + compilation, + expectedSignatures: new[] + { + Signature( + "C+<>c__DisplayClass2_0", + "b__0", + ".method [System.Runtime.CompilerServices.AsyncStateMachineAttribute(C+<>c__DisplayClass2_0+<b__0>d)] assembly hidebysig instance [System.Runtime.CompilerServices.DynamicAttribute(System.Collections.ObjectModel.ReadOnlyCollection`1[System.Reflection.CustomAttributeTypedArgument])] MyTask`1[System.Object] b__0() cil managed"), + Signature( + "C+<>c__DisplayClass2_0", + "b__1", + ".method [System.Runtime.CompilerServices.AsyncStateMachineAttribute(C+<>c__DisplayClass2_0+<b__1>d)] assembly hidebysig instance [System.Runtime.CompilerServices.DynamicAttribute(System.Collections.ObjectModel.ReadOnlyCollection`1[System.Reflection.CustomAttributeTypedArgument])] MyTask`1[System.Object[]] b__1() cil managed"), + Signature( + "C+<>c__DisplayClass2_0", + "b__2", + ".method [System.Runtime.CompilerServices.AsyncStateMachineAttribute(C+<>c__DisplayClass2_0+<b__2>d)] assembly hidebysig instance [System.Runtime.CompilerServices.DynamicAttribute(System.Collections.ObjectModel.ReadOnlyCollection`1[System.Reflection.CustomAttributeTypedArgument])] MyTask`1[System.Object] b__2() cil managed"), + }); + verifier.VerifyDiagnostics(); + } + [Fact] public void NonTaskBuilder() { @@ -473,5 +534,42 @@ internal class Awaiter : INotifyCompletion // async MyTask F(T t) => t; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "=> t").WithArguments("System.IEquatable", "Task").WithLocation(8, 35)); } + + [Fact] + public void NonTaskBuilder_Array() + { + var source = +@"using System; +using System.Runtime.CompilerServices; +class C +{ + static async void M() + { +#pragma warning disable CS1998 + async MyTask F() { }; + await F(); +#pragma warning restore CS1998 + } +} +struct MyTask +{ + public static object[] CreateAsyncMethodBuilder() => null; + internal Awaiter GetAwaiter() => null; + internal class Awaiter : INotifyCompletion + { + public void OnCompleted(Action a) { } + internal bool IsCompleted => true; + internal void GetResult() { } + } +}"; + var compilation = CreateCompilationWithMscorlib45(source); + compilation.VerifyEmitDiagnostics( + // (8,22): error CS0161: 'F()': not all code paths return a value + // async MyTask F() { }; + Diagnostic(ErrorCode.ERR_ReturnExpected, "F").WithArguments("F()").WithLocation(8, 22), + // (8,22): error CS1983: The return type of an async method must be void, Task or Task + // async MyTask F() { }; + Diagnostic(ErrorCode.ERR_BadAsyncReturn, "F").WithLocation(8, 22)); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeTests.cs index 985b525b9c7e238c317782c9cc324ec488b11ab7..6d113440120a042b9a80949eb7420c00d17fbade 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeTests.cs @@ -22,8 +22,8 @@ struct ValueTask { public static Task CreateAsyncMethodBuilder() => null; "; var compilation = CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); - var methodf = (SourceMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("f").Single(); - var methodg = (SourceMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("g").Single(); + var methodf = compilation.GetMember("C.f"); + var methodg = compilation.GetMember("C.g"); Assert.True(methodf.IsAsync); Assert.True(methodg.IsAsync); } @@ -313,8 +313,8 @@ class ValueTaskMethodBuilder {} class ValueTaskMethodBuilder {} "; var compilation = CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); - var methodf = (SourceMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("f").Single(); - var methodg = (SourceMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("g").Single(); + var methodf = compilation.GetMember("C.f"); + var methodg = compilation.GetMember("C.g"); Assert.True(methodf.IsAsync); Assert.True(methodg.IsAsync); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs index 755ad21c875bc3f14fc3c31713f675d7ab944140..3970c4683cc135b4b01b3309e6a1d6acb354968a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs @@ -3821,5 +3821,41 @@ Task YAsync() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "async () => YAsync()").WithLocation(15, 21) ); } + + [Fact()] + public void DelegateTypeWithNoInvokeMethod() + { + // Delegate type with no Invoke method. + var ilSource = +@".class public auto ansi sealed D`1 + extends [mscorlib]System.MulticastDelegate +{ + .method public hidebysig specialname rtspecialname + instance void .ctor(object 'object', + native int 'method') runtime managed + { + } +}"; + var source = +@"using System; +using System.Threading.Tasks; +class C +{ + static void F(D d) { } + static void F(D> d) { } + static void F(Func f) { } + static void F(Func> f) { } + static void M() + { +#pragma warning disable CS1998 + F(async () => { }); + F(async () => { return 3; }); +#pragma warning restore CS1998 + } +}"; + var reference = CompileIL(ilSource); + var compilation = CreateCompilationWithMscorlib45(source, references: new[] { reference }); + compilation.VerifyEmitDiagnostics(); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs index 001a4c390a9bd73689b881ba103baddfb297b5a3..7321fbd1fba661d9d412b7f01824a82091e69bad 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs @@ -585,24 +585,163 @@ struct MyTaskMethodBuilder compilation.VerifyDiagnostics(); var type = compilation.GetMember("C.F0").Type; + var normalized = type.NormalizeTaskTypes(compilation); Assert.Equal("MyTask", type.ToTestDisplayString()); - Assert.Equal("System.Threading.Tasks.Task", type.NormalizeTaskTypes(compilation).ToTestDisplayString()); + Assert.Equal("System.Threading.Tasks.Task", normalized.ToTestDisplayString()); type = compilation.GetMember("C.F1").Type; + normalized = type.NormalizeTaskTypes(compilation); Assert.Equal("MyTask", type.ToTestDisplayString()); - Assert.Equal("System.Threading.Tasks.Task", type.NormalizeTaskTypes(compilation).ToTestDisplayString()); + Assert.Equal("System.Threading.Tasks.Task", normalized.ToTestDisplayString()); type = compilation.GetMember("C.F2").Type; + normalized = type.NormalizeTaskTypes(compilation); Assert.Equal("C[,]", type.ToTestDisplayString()); - Assert.Equal("C[,]", type.NormalizeTaskTypes(compilation).ToTestDisplayString()); + Assert.Equal("C[,]", normalized.ToTestDisplayString()); type = compilation.GetMember("C.F3").Type; + normalized = type.NormalizeTaskTypes(compilation); Assert.Equal("A>.B>", type.ToTestDisplayString()); - Assert.Equal("A>.B>", type.NormalizeTaskTypes(compilation).ToTestDisplayString()); + Assert.Equal("A>.B>", normalized.ToTestDisplayString()); type = compilation.GetMember("C.F4").Type; + normalized = type.NormalizeTaskTypes(compilation); Assert.Equal("System.Int32*", type.ToTestDisplayString()); - Assert.Equal("System.Int32*", type.NormalizeTaskTypes(compilation).ToTestDisplayString()); + Assert.Equal("System.Int32*", normalized.ToTestDisplayString()); + } + + [Fact] + public void NormalizeTaskTypes_Tuples() + { + string source = +@"using System; +using System.Threading.Tasks; +class C +{ +#pragma warning disable CS0169 + static MyTask> F0; + static ((MyTask a, T b) c, MyTask<(U, MyTask)[]> d) F1; + static Task<(Task, object)[]> F2; + static (MyTask, char, byte, short, ushort, int, uint, long, ulong, char, byte, short, ushort, int, uint, long, MyTask) F3; +#pragma warning restore CS0169 +} +struct MyTask +{ + public static MyTaskMethodBuilder CreateAsyncMethodBuilder() => new MyTaskMethodBuilder(); +} +struct MyTask +{ + public static MyTaskMethodBuilder CreateAsyncMethodBuilder() => new MyTaskMethodBuilder(); +} +struct MyTaskMethodBuilder +{ +} +struct MyTaskMethodBuilder +{ +} +namespace System +{ + struct ValueTuple + { + } + struct ValueTuple + { + } + struct ValueTuple + { + } +} +namespace System.Runtime.CompilerServices +{ + class TupleElementNamesAttribute : Attribute + { + public TupleElementNamesAttribute(string[] names) { } + } +}"; + var compilation = CreateCompilationWithMscorlib45(source); + compilation.VerifyDiagnostics(); + + var type = compilation.GetMember("C.F0").Type; + var normalized = type.NormalizeTaskTypes(compilation); + Assert.Equal("MyTask<(MyTask, T)>", type.ToTestDisplayString()); + Assert.Equal("System.Threading.Tasks.Task<(System.Threading.Tasks.Task, T)>", normalized.ToTestDisplayString()); + + type = compilation.GetMember("C.F1").Type; + normalized = type.NormalizeTaskTypes(compilation); + Assert.Equal("((MyTask a, T b) c, MyTask<(U, MyTask)[]> d)", type.ToTestDisplayString()); + Assert.Equal("((System.Threading.Tasks.Task a, T b) c, System.Threading.Tasks.Task<(U, System.Threading.Tasks.Task)[]> d)", normalized.ToTestDisplayString()); + + // No changes. + type = compilation.GetMember("C.F2").Type; + normalized = type.NormalizeTaskTypes(compilation); + Assert.Equal("System.Threading.Tasks.Task<(System.Threading.Tasks.Task, System.Object)[]>", type.ToTestDisplayString()); + Assert.Same(type, normalized); + + // Nested System.ValueTuple<>. + type = compilation.GetMember("C.F3").Type; + normalized = type.NormalizeTaskTypes(compilation); + Assert.Equal("(MyTask, System.Char, System.Byte, System.Int16, System.UInt16, System.Int32, System.UInt32, System.Int64, System.UInt64, System.Char, System.Byte, System.Int16, System.UInt16, System.Int32, System.UInt32, System.Int64, MyTask)", type.ToTestDisplayString()); + Assert.Equal("(System.Threading.Tasks.Task, System.Char, System.Byte, System.Int16, System.UInt16, System.Int32, System.UInt32, System.Int64, System.UInt64, System.Char, System.Byte, System.Int16, System.UInt16, System.Int32, System.UInt32, System.Int64, System.Threading.Tasks.Task)", normalized.ToTestDisplayString()); + Assert.Equal("System.ValueTuple>", GetUnderlyingTupleTypeRest(type).ToTestDisplayString()); + Assert.Equal("System.ValueTuple>", GetUnderlyingTupleTypeRest(normalized).ToTestDisplayString()); + } + + // Return the underlying type of the most-nested part of the TupleTypeSymbol. + private static NamedTypeSymbol GetUnderlyingTupleTypeRest(TypeSymbol type) + { + while (type.IsTupleType) + { + var underlyingType = type.TupleUnderlyingType; + var typeArgs = underlyingType.TypeArguments; + if (typeArgs.Length < 8) + { + return underlyingType; + } + type = typeArgs[7]; + } + return null; + } + + // Preserve type argument custom modifiers. + [WorkItem(592, "https://github.com/dotnet/roslyn/issues/12615")] + [Fact] + public void NormalizeTaskTypes_TypeArgumentCustomModifiers() + { + var ilSource = +@".class public C +{ + .field public static class MyTask`1)> F0 + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } +} +.class public MyTask +{ + .method public hidebysig static class MyTaskMethodBuilder CreateAsyncMethodBuilder() cil managed { ldnull ret } + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } +} +.class public MyTask`1 +{ + .method public hidebysig static class MyTaskMethodBuilder`1 CreateAsyncMethodBuilder() cil managed { ldnull ret } + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } +} +.class public MyTaskMethodBuilder +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } +} +.class public MyTaskMethodBuilder`1 +{ + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ret } +} +"; + var source = +@""; + var reference = CompileIL(ilSource); + var compilation = CreateCompilationWithMscorlib45(source, references: new[] { reference }); + compilation.VerifyDiagnostics(); + + var type = compilation.GetMember("C.F0").Type; + var normalized = type.NormalizeTaskTypes(compilation); + Assert.Equal("MyTask)>", type.ToTestDisplayString()); + Assert.Equal("System.Threading.Tasks.Task)>", normalized.ToTestDisplayString()); } [Fact] @@ -638,16 +777,19 @@ class MyTaskMethodBuilder compilation.VerifyDiagnostics(); var type = compilation.GetMember("C.F0").Type; + var normalized = type.NormalizeTaskTypes(compilation); Assert.Equal("C.MyTask", type.ToTestDisplayString()); - Assert.Equal("System.Threading.Tasks.Task", type.NormalizeTaskTypes(compilation).ToTestDisplayString()); + Assert.Equal("System.Threading.Tasks.Task", normalized.ToTestDisplayString()); type = compilation.GetMember("C.F1").Type; + normalized = type.NormalizeTaskTypes(compilation); Assert.Equal("C.MyTask>.MyTask", type.ToTestDisplayString()); - Assert.Equal("System.Threading.Tasks.Task", type.NormalizeTaskTypes(compilation).ToTestDisplayString()); + Assert.Equal("System.Threading.Tasks.Task", normalized.ToTestDisplayString()); type = compilation.GetMember("C.F2").Type; + normalized = type.NormalizeTaskTypes(compilation); Assert.Equal("C.MyTask>.Inner", type.ToTestDisplayString()); - Assert.Equal("C>.Inner", type.NormalizeTaskTypes(compilation).ToTestDisplayString()); + Assert.Equal("C>.Inner", normalized.ToTestDisplayString()); } [Fact] @@ -681,12 +823,14 @@ class MyTaskMethodBuilder compilation.VerifyDiagnostics(); var type = compilation.GetMember("C.F0").Type; + var normalized = type.NormalizeTaskTypes(compilation); Assert.Equal("MyTask", type.ToTestDisplayString()); - Assert.Equal("System.Threading.Tasks.Task", type.NormalizeTaskTypes(compilation).ToTestDisplayString()); + Assert.Equal("System.Threading.Tasks.Task", normalized.ToTestDisplayString()); type = compilation.GetMember("C.F1").Type; + normalized = type.NormalizeTaskTypes(compilation); Assert.Equal("MyTask>.B", type.ToTestDisplayString()); - Assert.Equal("MyTask>.B", type.NormalizeTaskTypes(compilation).ToTestDisplayString()); + Assert.Equal("MyTask>.B", normalized.ToTestDisplayString()); } /// @@ -720,8 +864,9 @@ struct MyTaskMethodBuilder var compilation = CreateCompilation(source, references: new[] { MscorlibRef_v20 }); compilation.VerifyDiagnostics(); var type = compilation.GetMember("C.F").Type; + var normalized = type.NormalizeTaskTypes(compilation); Assert.Equal("MyTask", type.ToTestDisplayString()); - Assert.Equal("MyTask", type.NormalizeTaskTypes(compilation).ToTestDisplayString()); + Assert.Equal("MyTask", normalized.ToTestDisplayString()); } [Fact] diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb index 09f42377032f297d8d6f9b52769e6dfa57d31d68..882588fd05cdfd5872d7bb73a6af77d224919f51 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb @@ -8405,27 +8405,26 @@ End Class - Public Sub MissingAsyncMethodBuilder() - Dim source = - + Public Sub MissingAsyncVoidMethodBuilder() + Dim source = + + Public Class TestCase Async Sub M() End Sub End Class - - + Dim comp = CreateCompilationWithReferences(source, {MscorlibRef}, TestOptions.ReleaseDll) ' NOTE: 4.0, Not 4.5, so it's missing the async helpers. - - Using stream As New MemoryStream() - AssertTheseDiagnostics(comp.Emit(stream).Diagnostics, -BC31091: Import of type 'AsyncVoidMethodBuilder' from assembly or module 'Async.dll' failed. + comp.AssertTheseEmitDiagnostics( + +BC31091: Import of type 'AsyncVoidMethodBuilder' from assembly or module 'AsyncVoid.dll' failed. Async Sub M() ~~~~~~~~~~~~~~ -BC31091: Import of type 'AsyncVoidMethodBuilder' from assembly or module 'Async.dll' failed. +BC31091: Import of type 'AsyncVoidMethodBuilder' from assembly or module 'AsyncVoid.dll' failed. Async Sub M() ~~~~~~~~~~~~~~ -BC31091: Import of type 'IAsyncStateMachine' from assembly or module 'Async.dll' failed. +BC31091: Import of type 'IAsyncStateMachine' from assembly or module 'AsyncVoid.dll' failed. Async Sub M() ~~~~~~~~~~~~~~ BC35000: Requested operation is not available because the runtime library function 'System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext' is not defined. @@ -8437,8 +8436,80 @@ BC35000: Requested operation is not available because the runtime library functi BC42356: This async method lacks 'Await' operators and so will run synchronously. Consider using the 'Await' operator to await non-blocking API calls, or 'Await Task.Run(...)' to do CPU-bound work on a background thread. Async Sub M() ~ - ) - End Using +) + End Sub + + + Public Sub MissingAsyncTaskMethodBuilder() + Dim source = + + +Imports System.Threading.Tasks +Public Class TestCase + Async Function M() As Task + End Function +End Class + + + Dim comp = CreateCompilationWithReferences(source, {MscorlibRef}, TestOptions.ReleaseDll) ' NOTE: 4.0, Not 4.5, so it's missing the async helpers. + comp.AssertTheseEmitDiagnostics( + +BC31091: Import of type 'AsyncTaskMethodBuilder' from assembly or module 'AsyncTask.dll' failed. + Async Function M() As Task + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC31091: Import of type 'AsyncTaskMethodBuilder' from assembly or module 'AsyncTask.dll' failed. + Async Function M() As Task + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC31091: Import of type 'IAsyncStateMachine' from assembly or module 'AsyncTask.dll' failed. + Async Function M() As Task + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC35000: Requested operation is not available because the runtime library function 'System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext' is not defined. + Async Function M() As Task + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC35000: Requested operation is not available because the runtime library function 'System.Runtime.CompilerServices.IAsyncStateMachine.SetStateMachine' is not defined. + Async Function M() As Task + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC42356: This async method lacks 'Await' operators and so will run synchronously. Consider using the 'Await' operator to await non-blocking API calls, or 'Await Task.Run(...)' to do CPU-bound work on a background thread. + Async Function M() As Task + ~ +) + End Sub + + + Public Sub MissingAsyncTaskMethodBuilder_T() + Dim source = + + +Imports System.Threading.Tasks +Public Class TestCase + Async Function M() As Task(Of Integer) + Return 3 + End Function +End Class + + + Dim comp = CreateCompilationWithReferences(source, {MscorlibRef}, TestOptions.ReleaseDll) ' NOTE: 4.0, Not 4.5, so it's missing the async helpers. + comp.AssertTheseEmitDiagnostics( + +BC31091: Import of type 'AsyncTaskMethodBuilder(Of )' from assembly or module 'AsyncTask_T.dll' failed. + Async Function M() As Task(Of Integer) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC31091: Import of type 'AsyncTaskMethodBuilder(Of )' from assembly or module 'AsyncTask_T.dll' failed. + Async Function M() As Task(Of Integer) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC31091: Import of type 'IAsyncStateMachine' from assembly or module 'AsyncTask_T.dll' failed. + Async Function M() As Task(Of Integer) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC35000: Requested operation is not available because the runtime library function 'System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext' is not defined. + Async Function M() As Task(Of Integer) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC35000: Requested operation is not available because the runtime library function 'System.Runtime.CompilerServices.IAsyncStateMachine.SetStateMachine' is not defined. + Async Function M() As Task(Of Integer) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC42356: This async method lacks 'Await' operators and so will run synchronously. Consider using the 'Await' operator to await non-blocking API calls, or 'Await Task.Run(...)' to do CPU-bound work on a background thread. + Async Function M() As Task(Of Integer) + ~ +) End Sub