diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index f341f74432161..203362cc6e92e 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -10321,6 +10321,72 @@ partial class C Assert.False(comp.HasLocalsInit("C.M")); } + [Fact] + public void SkipLocalsInitAttributeOnExtendedPartialMethod_01() + { + var source = @" +namespace System.Runtime.CompilerServices +{ + class SkipLocalsInitAttribute : System.Attribute + { + } +} + +partial class C +{ + public partial int M() + { + int x = 1; + x = x + x + x; + return x; + } +} + +partial class C +{ + [System.Runtime.CompilerServices.SkipLocalsInitAttribute] + public partial int M(); +} +"; + + var comp = CompileAndVerify(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularWithExtendedPartialMethods, verify: Verification.Fails); + + Assert.False(comp.HasLocalsInit("C.M")); + } + + [Fact] + public void SkipLocalsInitAttributeOnExtendedPartialMethod_02() + { + var source = @" +namespace System.Runtime.CompilerServices +{ + class SkipLocalsInitAttribute : System.Attribute + { + } +} + +partial class C +{ + [System.Runtime.CompilerServices.SkipLocalsInitAttribute] + public partial int M() + { + int x = 1; + x = x + x + x; + return x; + } +} + +partial class C +{ + public partial int M(); +} +"; + + var comp = CompileAndVerify(source, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularWithExtendedPartialMethods, verify: Verification.Fails); + + Assert.False(comp.HasLocalsInit("C.M")); + } + [Fact] public unsafe void StackallocWithSkipLocalsInit() { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs index 05567255d9951..2c8d4f1ed7a95 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs @@ -3125,6 +3125,268 @@ .locals init (int V_0, }", sequencePoints: "C+d__0.MoveNext", source: source); } + [ConditionalTheory(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.NativePdbRequiresDesktop)] + [InlineData("[EnumeratorCancellation] ", "")] + [InlineData("", "[EnumeratorCancellation] ")] + public void AsyncIteratorWithAwaitCompletedAndYield_WithEnumeratorCancellation_ExtendedPartialMethod(string definitionAttributes, string implementationAttributes) + { + string source = @" +using System.Runtime.CompilerServices; +using System.Threading; +partial class C +{ + public static partial System.Collections.Generic.IAsyncEnumerable M(" + definitionAttributes + @"CancellationToken token); + public static async partial System.Collections.Generic.IAsyncEnumerable M(" + implementationAttributes + @"CancellationToken token) + { + _ = token; + await System.Threading.Tasks.Task.CompletedTask; + yield return 3; + } +}"; + var comp = CreateCompilationWithAsyncIterator(new[] { source, EnumeratorCancellationAttributeType }, options: TestOptions.ReleaseDll, parseOptions: TestOptions.RegularWithExtendedPartialMethods); + comp.VerifyDiagnostics(); + var verifier = CompileAndVerify(comp); + + var expectedFields = new[] { + "FieldDefinition:Int32 <>1__state", + "FieldDefinition:System.Runtime.CompilerServices.AsyncIteratorMethodBuilder <>t__builder", + "FieldDefinition:System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore`1{Boolean} <>v__promiseOfValueOrEnd", + "FieldDefinition:Int32 <>2__current", + "FieldDefinition:Boolean <>w__disposeMode", + "FieldDefinition:System.Threading.CancellationTokenSource <>x__combinedTokens", + "FieldDefinition:Int32 <>l__initialThreadId", + "FieldDefinition:System.Threading.CancellationToken token", + "FieldDefinition:System.Threading.CancellationToken <>3__token", + "FieldDefinition:System.Runtime.CompilerServices.TaskAwaiter <>u__1" + }; + VerifyStateMachineFields(comp, "d__0", expectedFields); + + // we generate initialization logic for the token parameter + verifier.VerifyIL("C.d__0.System.Collections.Generic.IAsyncEnumerable.GetAsyncEnumerator(System.Threading.CancellationToken)", @" +{ + // Code size 176 (0xb0) + .maxstack 3 + .locals init (C.d__0 V_0, + System.Threading.CancellationToken V_1) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: ldc.i4.s -2 + IL_0008: bne.un.s IL_0035 + IL_000a: ldarg.0 + IL_000b: ldfld ""int C.d__0.<>l__initialThreadId"" + IL_0010: call ""int System.Environment.CurrentManagedThreadId.get"" + IL_0015: bne.un.s IL_0035 + IL_0017: ldarg.0 + IL_0018: ldc.i4.s -3 + IL_001a: stfld ""int C.d__0.<>1__state"" + IL_001f: ldarg.0 + IL_0020: call ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Create()"" + IL_0025: stfld ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_002a: ldarg.0 + IL_002b: ldc.i4.0 + IL_002c: stfld ""bool C.d__0.<>w__disposeMode"" + IL_0031: ldarg.0 + IL_0032: stloc.0 + IL_0033: br.s IL_003d + IL_0035: ldc.i4.s -3 + IL_0037: newobj ""C.d__0..ctor(int)"" + IL_003c: stloc.0 + IL_003d: ldarg.0 + IL_003e: ldflda ""System.Threading.CancellationToken C.d__0.<>3__token"" + IL_0043: ldloca.s V_1 + IL_0045: initobj ""System.Threading.CancellationToken"" + IL_004b: ldloc.1 + IL_004c: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" + IL_0051: brfalse.s IL_005c + IL_0053: ldloc.0 + IL_0054: ldarg.1 + IL_0055: stfld ""System.Threading.CancellationToken C.d__0.token"" + IL_005a: br.s IL_00ae + IL_005c: ldarga.s V_1 + IL_005e: ldarg.0 + IL_005f: ldfld ""System.Threading.CancellationToken C.d__0.<>3__token"" + IL_0064: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" + IL_0069: brtrue.s IL_007d + IL_006b: ldarga.s V_1 + IL_006d: ldloca.s V_1 + IL_006f: initobj ""System.Threading.CancellationToken"" + IL_0075: ldloc.1 + IL_0076: call ""bool System.Threading.CancellationToken.Equals(System.Threading.CancellationToken)"" + IL_007b: brfalse.s IL_008b + IL_007d: ldloc.0 + IL_007e: ldarg.0 + IL_007f: ldfld ""System.Threading.CancellationToken C.d__0.<>3__token"" + IL_0084: stfld ""System.Threading.CancellationToken C.d__0.token"" + IL_0089: br.s IL_00ae + IL_008b: ldarg.0 + IL_008c: ldarg.0 + IL_008d: ldfld ""System.Threading.CancellationToken C.d__0.<>3__token"" + IL_0092: ldarg.1 + IL_0093: call ""System.Threading.CancellationTokenSource System.Threading.CancellationTokenSource.CreateLinkedTokenSource(System.Threading.CancellationToken, System.Threading.CancellationToken)"" + IL_0098: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_009d: ldloc.0 + IL_009e: ldarg.0 + IL_009f: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_00a4: callvirt ""System.Threading.CancellationToken System.Threading.CancellationTokenSource.Token.get"" + IL_00a9: stfld ""System.Threading.CancellationToken C.d__0.token"" + IL_00ae: ldloc.0 + IL_00af: ret +}"); + + // we generate disposal logic for the combinedTokens field + verifier.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @" +{ + // Code size 329 (0x149) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__0 V_2, + System.Exception V_3) + // sequence point: + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.0 + .try + { + // sequence point: + IL_0007: ldloc.0 + IL_0008: ldc.i4.s -4 + IL_000a: sub + IL_000b: switch ( + IL_00b4, + IL_0024, + IL_0024, + IL_0024, + IL_007b) + IL_0024: ldarg.0 + IL_0025: ldfld ""bool C.d__0.<>w__disposeMode"" + IL_002a: brfalse.s IL_0031 + IL_002c: leave IL_0102 + IL_0031: ldarg.0 + IL_0032: ldc.i4.m1 + IL_0033: dup + IL_0034: stloc.0 + IL_0035: stfld ""int C.d__0.<>1__state"" + // sequence point: _ = token; + IL_003a: ldarg.0 + IL_003b: ldfld ""System.Threading.CancellationToken C.d__0.token"" + IL_0040: pop + // sequence point: await System.Threading.Tasks.Task.CompletedTask; + IL_0041: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.CompletedTask.get"" + IL_0046: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_004b: stloc.1 + // sequence point: + IL_004c: ldloca.s V_1 + IL_004e: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0053: brtrue.s IL_0097 + IL_0055: ldarg.0 + IL_0056: ldc.i4.0 + IL_0057: dup + IL_0058: stloc.0 + IL_0059: stfld ""int C.d__0.<>1__state"" + // async: yield + IL_005e: ldarg.0 + IL_005f: ldloc.1 + IL_0060: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_0065: ldarg.0 + IL_0066: stloc.2 + IL_0067: ldarg.0 + IL_0068: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_006d: ldloca.s V_1 + IL_006f: ldloca.s V_2 + IL_0071: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" + IL_0076: leave IL_0148 + // async: resume + IL_007b: ldarg.0 + IL_007c: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_0081: stloc.1 + IL_0082: ldarg.0 + IL_0083: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_0088: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_008e: ldarg.0 + IL_008f: ldc.i4.m1 + IL_0090: dup + IL_0091: stloc.0 + IL_0092: stfld ""int C.d__0.<>1__state"" + IL_0097: ldloca.s V_1 + IL_0099: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + // sequence point: yield return 3; + IL_009e: ldarg.0 + IL_009f: ldc.i4.3 + IL_00a0: stfld ""int C.d__0.<>2__current"" + IL_00a5: ldarg.0 + IL_00a6: ldc.i4.s -4 + IL_00a8: dup + IL_00a9: stloc.0 + IL_00aa: stfld ""int C.d__0.<>1__state"" + IL_00af: leave IL_013c + // sequence point: + IL_00b4: ldarg.0 + IL_00b5: ldc.i4.m1 + IL_00b6: dup + IL_00b7: stloc.0 + IL_00b8: stfld ""int C.d__0.<>1__state"" + IL_00bd: ldarg.0 + IL_00be: ldfld ""bool C.d__0.<>w__disposeMode"" + IL_00c3: pop + // sequence point: + IL_00c4: leave.s IL_0102 + } + catch System.Exception + { + // sequence point: + IL_00c6: stloc.3 + IL_00c7: ldarg.0 + IL_00c8: ldc.i4.s -2 + IL_00ca: stfld ""int C.d__0.<>1__state"" + IL_00cf: ldarg.0 + IL_00d0: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_00d5: brfalse.s IL_00e9 + IL_00d7: ldarg.0 + IL_00d8: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_00dd: callvirt ""void System.Threading.CancellationTokenSource.Dispose()"" + IL_00e2: ldarg.0 + IL_00e3: ldnull + IL_00e4: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_00e9: ldarg.0 + IL_00ea: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_00ef: ldloc.3 + IL_00f0: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_00f5: ldarg.0 + IL_00f6: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_00fb: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_0100: leave.s IL_0148 + } + // sequence point: } + IL_0102: ldarg.0 + IL_0103: ldc.i4.s -2 + IL_0105: stfld ""int C.d__0.<>1__state"" + // sequence point: + IL_010a: ldarg.0 + IL_010b: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_0110: brfalse.s IL_0124 + IL_0112: ldarg.0 + IL_0113: ldfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_0118: callvirt ""void System.Threading.CancellationTokenSource.Dispose()"" + IL_011d: ldarg.0 + IL_011e: ldnull + IL_011f: stfld ""System.Threading.CancellationTokenSource C.d__0.<>x__combinedTokens"" + IL_0124: ldarg.0 + IL_0125: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_012a: ldc.i4.0 + IL_012b: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0130: ldarg.0 + IL_0131: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0136: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_013b: ret + IL_013c: ldarg.0 + IL_013d: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0142: ldc.i4.1 + IL_0143: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0148: ret +}", sequencePoints: "C+d__0.MoveNext", source: source); + } + [ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.NativePdbRequiresDesktop)] public void AsyncIteratorWithAwaitCompletedAndYield_WithEnumeratorCancellation_LocalFunction() { diff --git a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs index 84fa8b738786a..9494e1f645059 100644 --- a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/DocumentationCommentCompilerTests.cs @@ -922,6 +922,65 @@ partial class C Assert.Equal(expectedB, actualB); } + [Fact] + public void ExtendedPartialMethods_MultipleFiles() + { + var source1 = @" +partial class C +{ + /** Summary 1*/ + public partial int M() => 42; +} +"; + + var source2 = @" +partial class C +{ + /** Summary 2*/ + public partial int M(); +} +"; + + var tree1 = SyntaxFactory.ParseSyntaxTree(source1, options: TestOptions.RegularWithDocumentationComments); + var tree2 = SyntaxFactory.ParseSyntaxTree(source2, options: TestOptions.RegularWithDocumentationComments); + + // Files passed in order. + var compA = CreateCompilation(new[] { tree1, tree2 }, assemblyName: "Test"); + var actualA = GetDocumentationCommentText(compA); + var expectedA = @" + + + + Test + + + + Summary 1 + + + +".Trim(); + Assert.Equal(expectedA, actualA); + + // Files passed in reverse order. + var compB = CreateCompilation(new[] { tree2, tree1 }, assemblyName: "Test"); + var actualB = GetDocumentationCommentText(compB); + var expectedB = @" + + + + Test + + + + Summary 1 + + + +".Trim(); + Assert.Equal(expectedB, actualB); + } + #endregion Partial methods #region Crefs diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtendedPartialMethodsTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtendedPartialMethodsTests.cs index 9842f5a811c23..f64f10564af2d 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtendedPartialMethodsTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtendedPartialMethodsTests.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Runtime.InteropServices; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; @@ -2398,5 +2399,244 @@ public static partial async Task Main() // public static partial async Task Main() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Main").WithLocation(8, 43)); } + + [ConditionalFact(typeof(CoreClrOnly))] + public void Override_CustomModifiers() + { + var source1 = @" +public class C +{ + public virtual void M(in object x) { } +}"; + var comp1 = CreateCompilation(source1, assemblyName: "C"); + comp1.VerifyDiagnostics(); + verify(comp1.ToMetadataReference()); + verify(comp1.EmitToImageReference()); + + void verify(MetadataReference reference) + { + + var source2 = @" +public partial class D : C +{ + public override partial void M(in object x); + public override partial void M(in object x) { x.ToString(); } +} +"; + var verifier = CompileAndVerify(source2, references: new[] { reference }, parseOptions: TestOptions.RegularWithExtendedPartialMethods); + verifier.VerifyTypeIL("D", @" +.class public auto ansi beforefieldinit D + extends [C]C +{ + // Methods + .method public hidebysig virtual + instance void M ( + [in] object& modreq([netstandard]System.Runtime.InteropServices.InAttribute) x + ) cil managed + { + .param [1] + .custom instance void System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2058 + // Code size 9 (0x9) + .maxstack 8 + IL_0000: ldarg.1 + IL_0001: ldind.ref + IL_0002: callvirt instance string [netstandard]System.Object::ToString() + IL_0007: pop + IL_0008: ret + } // end of method D::M + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2062 + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [C]C::.ctor() + IL_0006: ret + } // end of method D::.ctor +} // end of class D"); + } + } + + [Fact] + public void InterfaceImpl_InThunk() + { + var source = @" +public interface I +{ + void M(in object obj); +} + +public partial class C : I +{ + public partial void M(in object obj); + public partial void M(in object obj) { } +} +"; + var verifier = CompileAndVerify( + source, + options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), + parseOptions: TestOptions.RegularWithExtendedPartialMethods, + symbolValidator: verify); + verifier.VerifyDiagnostics(); + + void verify(ModuleSymbol module) + { + Assert.Equal(MetadataImportOptions.All, ((PEModuleSymbol)module).ImportOptions); + var cType = module.ContainingAssembly.GetTypeByMetadataName("C"); + Assert.NotNull(cType.GetMethod("M")); + Assert.NotNull(cType.GetMethod("I.M")); + } + } + + [Fact] + public void ConsumeExtendedPartialFromVB() + { + var csharp = @" +public partial class C +{ + public virtual partial int M1(); + public virtual partial int M1() => 42; +}"; + var comp = CreateCompilation(csharp, parseOptions: TestOptions.RegularWithExtendedPartialMethods); + comp.VerifyDiagnostics(); + + var vb = @" +Public Class D + Inherits C + + Public Overrides Function M1() As Integer + Return 123 + End Function +End Class +"; + + var vbComp = CreateVisualBasicCompilation(vb, referencedAssemblies: TargetFrameworkUtil.GetReferences(TargetFramework.Standard).Add(comp.EmitToImageReference())); + vbComp.VerifyDiagnostics(); + } + + [Fact] + public void Override_SingleDimensionArraySizesInMetadata() + { + + var il = @" +.class public auto ansi abstract beforefieldinit Base + extends [mscorlib]System.Object +{ + // Methods + .method public hidebysig newslot abstract virtual + void M1 (int32[0...] param) cil managed + { + } + .method public hidebysig newslot abstract virtual + int32[0...] M2 () cil managed + { + } + .method family hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +}"; + + var source = @" +public partial class Derived : Base +{ + public override partial void M1(int[] param); + public override partial void M1(int[] param) { } + + public override partial int[] M2(); + public override partial int[] M2() => new int[0]; +}"; + + var comp = CreateCompilationWithIL(source, il, parseOptions: TestOptions.RegularWithExtendedPartialMethods); + comp.VerifyDiagnostics( + // (2,22): error CS0534: 'Derived' does not implement inherited abstract member 'Base.M1(int[*])' + // public partial class Derived : Base + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Derived").WithArguments("Derived", "Base.M1(int[*])").WithLocation(2, 22), + // (4,34): error CS0115: 'Derived.M1(int[])': no suitable method found to override + // public override partial void M1(int[] param); + Diagnostic(ErrorCode.ERR_OverrideNotExpected, "M1").WithArguments("Derived.M1(int[])").WithLocation(4, 34), + // (7,35): error CS0508: 'Derived.M2()': return type must be 'int[*]' to match overridden member 'Base.M2()' + // public override partial int[] M2(); + Diagnostic(ErrorCode.ERR_CantChangeReturnTypeOnOverride, "M2").WithArguments("Derived.M2()", "Base.M2()", "int[*]").WithLocation(7, 35) + ); + } + + [Fact] + public void Override_ArraySizesInMetadata() + { + var il = @" +.class public auto ansi abstract beforefieldinit Base + extends [mscorlib]System.Object +{ + // Methods + .method public hidebysig newslot abstract virtual + void M1 (int32[5...5,2...4] param) cil managed + { + } + .method public hidebysig newslot abstract virtual + int32[5...5,2...4] M2 () cil managed + { + } + .method family hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +}"; + + var source = @" +using System; +partial class Derived : Base +{ + public override partial void M1(int[,] param); + public override partial int[,] M2(); + + public override partial void M1(int[,] param) + { + Console.Write(1); + } + public override partial int[,] M2() + { + Console.Write(2); + return null; + } + + public static void Main() + { + var d = new Derived(); + d.M1(null); + _ = d.M2(); + } +}"; + + var comp = CreateCompilationWithIL(source, il, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularWithExtendedPartialMethods); + CompileAndVerify(comp, expectedOutput: "12"); + + var m1 = comp.GetMember("Derived.M1"); + verifyArray(m1.Parameters[0].Type); + + var m2 = comp.GetMember("Derived.M2"); + verifyArray(m2.ReturnType); + + static void verifyArray(TypeSymbol type) + { + var array = (ArrayTypeSymbol)type; + Assert.False(array.IsSZArray); + Assert.Equal(2, array.Rank); + Assert.Equal(5, array.LowerBounds[0]); + Assert.Equal(1, array.Sizes[0]); + Assert.Equal(2, array.LowerBounds[1]); + Assert.Equal(3, array.Sizes[1]); + } + } } }