diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index bce6baa227300a031c9ea22f8617f2aa066d89bf..55b636f7448ed32f3c30d3fc6e575918a4c620ca 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -1354,6 +1354,7 @@ private static bool NormalizeTaskTypesInType(CSharpCompilation compilation, ref switch (type.Kind) { case SymbolKind.NamedType: + case SymbolKind.ErrorType: { var namedType = (NamedTypeSymbol)type; var changed = type.IsTupleType ? @@ -1369,6 +1370,13 @@ private static bool NormalizeTaskTypesInType(CSharpCompilation compilation, ref type = arrayType; return changed; } + case SymbolKind.PointerType: + { + var pointerType = (PointerTypeSymbol)type; + var changed = NormalizeTaskTypesInPointer(compilation, ref pointerType); + type = pointerType; + return changed; + } } return false; } @@ -1456,6 +1464,18 @@ private static bool NormalizeTaskTypesInArray(CSharpCompilation compilation, ref return true; } + private static bool NormalizeTaskTypesInPointer(CSharpCompilation compilation, ref PointerTypeSymbol pointerType) + { + var pointedAtType = pointerType.PointedAtType; + if (!NormalizeTaskTypesInType(compilation, ref pointedAtType)) + { + return false; + } + // Preserve custom modifiers but without normalizing those types. + pointerType = new PointerTypeSymbol(pointedAtType, pointerType.CustomModifiers); + return true; + } + internal static Cci.TypeReferenceWithAttributes GetTypeRefWithAttributes( this TypeSymbol type, CSharpCompilation declaringCompilation, diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs index 7321fbd1fba661d9d412b7f01824a82091e69bad..d0b7eef02ac4d83fd80b0945a81fadc654b1850d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs @@ -744,6 +744,113 @@ public void NormalizeTaskTypes_TypeArgumentCustomModifiers() Assert.Equal("System.Threading.Tasks.Task)>", normalized.ToTestDisplayString()); } + [Fact] + public void NormalizeTaskTypes_Pointers() + { + string source = +@"unsafe class C +{ +#pragma warning disable CS0169 + static C>* F0; +#pragma warning restore CS0169 +} +struct MyTask +{ + public static MyTaskMethodBuilder CreateAsyncMethodBuilder() => new MyTaskMethodBuilder(); +} +struct MyTaskMethodBuilder +{ +}"; + var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.UnsafeDebugDll); + compilation.VerifyDiagnostics( + // (4,12): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('C>') + // static C>* F0; + Diagnostic(ErrorCode.ERR_ManagedAddr, "C>*").WithArguments("C>").WithLocation(4, 12)); + + var type = compilation.GetMember("C.F0").Type; + var normalized = type.NormalizeTaskTypes(compilation); + Assert.Equal("C>*", type.ToTestDisplayString()); + Assert.Equal("C>*", normalized.ToTestDisplayString()); + } + + [Fact] + public void NormalizeTaskTypes_PointersCustomModifiers() + { + var ilSource = +@".class public C +{ + .field public static class MyTask modopt(class MyTask) *[] 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 MyTaskMethodBuilder +{ + .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 modopt(MyTask) *[]", type.ToTestDisplayString()); + Assert.Equal("System.Threading.Tasks.Task modopt(MyTask) *[]", normalized.ToTestDisplayString()); + } + + [Fact] + public void NormalizeTaskTypes_Errors() + { + string source = +@"class C +{ +#pragma warning disable CS0169 + static A F0; + static MyTask F1; +#pragma warning restore CS0169 +} +struct MyTask +{ + public static MyTaskMethodBuilder CreateAsyncMethodBuilder() => new MyTaskMethodBuilder(); +} +struct MyTask +{ + public static MyTaskMethodBuilder CreateAsyncMethodBuilder() => new MyTaskMethodBuilder(); +} +struct MyTaskMethodBuilder +{ +} +struct MyTaskMethodBuilder +{ +}"; + var compilation = CreateCompilationWithMscorlib45(source); + compilation.VerifyDiagnostics( + // (5,19): error CS0246: The type or namespace name 'B' could not be found (are you missing a using directive or an assembly reference?) + // static MyTask F1; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "B").WithArguments("B").WithLocation(5, 19), + // (4,12): error CS0246: The type or namespace name 'A<,>' could not be found (are you missing a using directive or an assembly reference?) + // static A F0; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("A<,>").WithLocation(4, 12)); + + var type = compilation.GetMember("C.F0").Type; + Assert.Equal(TypeKind.Error, type.TypeKind); + var normalized = type.NormalizeTaskTypes(compilation); + Assert.Equal("A", type.ToTestDisplayString()); + Assert.Equal("A", normalized.ToTestDisplayString()); + + type = compilation.GetMember("C.F1").Type; + Assert.Equal(TypeKind.Error, ((NamedTypeSymbol)type).TypeArguments[0].TypeKind); + normalized = type.NormalizeTaskTypes(compilation); + Assert.Equal("MyTask", type.ToTestDisplayString()); + Assert.Equal("System.Threading.Tasks.Task", normalized.ToTestDisplayString()); + } + [Fact] public void NormalizeTaskTypes_Inner() {