/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Emit/CodeGen/IndexerTests.cs
1 374 строки
39 KB
AlekseyTs
Fix receiver capturing for various extension scenarios (#79472)
25 июл 2025, 22:45
Не верифицирован
25 июл 2025, 22:45
1d9820f
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.CSharp.UnitTests.Emit; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen { public class IndexerTests : CSharpTestBase { #region Declarations [Fact] public void ReadWriteIndexer() { var text = @" class C { public int this[int x] { get { return x; } set { } } } "; var compVerifier = CompileAndVerify(text, symbolValidator: module => ValidateIndexer(module, "System.Int32 C.this[System.Int32 x].get", "void C.this[System.Int32 x].set"), expectedSignatures: new[] { Signature("C", "Item", ".property readwrite instance System.Int32 Item(System.Int32 x)"), Signature("C", "get_Item", ".method public hidebysig specialname instance System.Int32 get_Item(System.Int32 x) cil managed"), Signature("C", "set_Item", ".method public hidebysig specialname instance System.Void set_Item(System.Int32 x, System.Int32 value) cil managed") }); } [Fact] public void ReadOnlyIndexer() { var text = @" class C { public int this[int x, int y] { get { return x; } } } "; var compVerifier = CompileAndVerify(text, symbolValidator: module => ValidateIndexer(module, "System.Int32 C.this[System.Int32 x, System.Int32 y].get", null), expectedSignatures: new[] { Signature("C", "Item", ".property readonly instance System.Int32 Item(System.Int32 x, System.Int32 y)"), Signature("C", "get_Item", ".method public hidebysig specialname instance System.Int32 get_Item(System.Int32 x, System.Int32 y) cil managed") }); } [Fact] public void WriteOnlyIndexer() { var text = @" class C { public int this[int x, int y, int z] { set { } } } "; var compVerifier = CompileAndVerify(text, symbolValidator: module => ValidateIndexer(module, null, "void C.this[System.Int32 x, System.Int32 y, System.Int32 z].set"), expectedSignatures: new[] { Signature("C", "Item", ".property writeonly instance System.Int32 Item(System.Int32 x, System.Int32 y, System.Int32 z)"), Signature("C", "set_Item", ".method public hidebysig specialname instance System.Void set_Item(System.Int32 x, System.Int32 y, System.Int32 z, System.Int32 value) cil managed") }); } [Fact] public void GenericIndexer() { var text = @" class C<T> { public T this[T x] { get { return x; } set { } } } "; var compVerifier = CompileAndVerify(text, symbolValidator: module => ValidateIndexer(module, "T C<T>.this[T x].get", "void C<T>.this[T x].set"), expectedSignatures: new[] { Signature("C`1", "Item", ".property readwrite instance T Item(T x)"), Signature("C`1", "get_Item", ".method public hidebysig specialname instance T get_Item(T x) cil managed"), Signature("C`1", "set_Item", ".method public hidebysig specialname instance System.Void set_Item(T x, T value) cil managed") }); } [Fact] public void IndexerWithOptionalParameters() { var text = @" class C { public int this[int x = 1, int y = 2] { get { return x; } set { } } } "; var compVerifier = CompileAndVerify(text, symbolValidator: module => ValidateIndexer(module, "System.Int32 C.this[[System.Int32 x = 1], [System.Int32 y = 2]].get", "void C.this[[System.Int32 x = 1], [System.Int32 y = 2]].set"), expectedSignatures: new[] { Signature("C", "Item", ".property readwrite instance System.Int32 Item([opt] System.Int32 x = 1, [opt] System.Int32 y = 2)"), Signature("C", "get_Item", ".method public hidebysig specialname instance System.Int32 get_Item([opt] System.Int32 x = 1, [opt] System.Int32 y = 2) cil managed"), Signature("C", "set_Item", ".method public hidebysig specialname instance System.Void set_Item([opt] System.Int32 x = 1, [opt] System.Int32 y = 2, System.Int32 value) cil managed") }); } [Fact] public void IndexerWithParameterArray() { var text = @" class C { public int this[params int[] x] { get { return 0; } set { } } } "; var compVerifier = CompileAndVerify(text, symbolValidator: module => ValidateIndexer(module, "System.Int32 C.this[params System.Int32[] x].get", "void C.this[params System.Int32[] x].set"), expectedSignatures: new[] { Signature("C", "Item", ".property readwrite instance System.Int32 Item([System.ParamArrayAttribute()] System.Int32[] x)"), Signature("C", "get_Item", ".method public hidebysig specialname instance System.Int32 get_Item([System.ParamArrayAttribute()] System.Int32[] x) cil managed"), Signature("C", "set_Item", ".method public hidebysig specialname instance System.Void set_Item([System.ParamArrayAttribute()] System.Int32[] x, System.Int32 value) cil managed") }); } [Fact] public void ExplicitInterfaceImplementation() { var text = @" interface I { int this[int x] { get; set; } } class C : I { int I.this[int x] { get { return 0; } set { } } } "; System.Action<ModuleSymbol> validator = module => { // Can't use ValidateIndexer because explicit implementations aren't indexers in metadata. var @class = module.GlobalNamespace.GetMember<NamedTypeSymbol>("C"); var indexer = @class.GetMembers().Where(member => member.Kind == SymbolKind.Property).Cast<PropertySymbol>().Single(); Assert.False(indexer.IsIndexer); Assert.True(indexer.MustCallMethodsDirectly); //since has parameters, but isn't an indexer Assert.Equal(Accessibility.Private, indexer.DeclaredAccessibility); Assert.False(indexer.IsStatic); var getMethod = indexer.GetMethod; Assert.Equal(MethodKind.ExplicitInterfaceImplementation, getMethod.MethodKind); //since CallMethodsDirectly Assert.Equal("System.Int32 C.I.get_Item(System.Int32 x)", getMethod.ToTestDisplayString()); getMethod.CheckAccessorModifiers(indexer); var setMethod = indexer.SetMethod; Assert.Equal(MethodKind.ExplicitInterfaceImplementation, setMethod.MethodKind); //since CallMethodsDirectly Assert.Equal("void C.I.set_Item(System.Int32 x, System.Int32 value)", setMethod.ToTestDisplayString()); setMethod.CheckAccessorModifiers(indexer); }; var compVerifier = CompileAndVerify(text, symbolValidator: validator, expectedSignatures: new[] { Signature("C", "I.Item", ".property readwrite System.Int32 I.Item(System.Int32 x)"), Signature("C", "I.get_Item", ".method private hidebysig newslot specialname virtual final instance System.Int32 I.get_Item(System.Int32 x) cil managed"), Signature("C", "I.set_Item", ".method private hidebysig newslot specialname virtual final instance System.Void I.set_Item(System.Int32 x, System.Int32 value) cil managed") }); } [Fact] public void ImplicitInterfaceImplementation() { var text = @" interface I { int this[int x] { get; set; } } class C : I { public int this[int x] { get { return 0; } set { } } } "; var compVerifier = CompileAndVerify(text, symbolValidator: module => ValidateIndexer(module, "System.Int32 C.this[System.Int32 x].get", "void C.this[System.Int32 x].set"), expectedSignatures: new[] { Signature("C", "Item", ".property readwrite instance System.Int32 Item(System.Int32 x)"), Signature("C", "get_Item", ".method public hidebysig newslot specialname virtual final instance System.Int32 get_Item(System.Int32 x) cil managed"), Signature("C", "set_Item", ".method public hidebysig newslot specialname virtual final instance System.Void set_Item(System.Int32 x, System.Int32 value) cil managed") }); } [Fact] public void Overriding() { var text = @" class B { public virtual int this[int x] { get { return 0; } set { } } } class C : B { public override sealed int this[int x] { get { return 0; } set { } } } "; var compVerifier = CompileAndVerify(text, symbolValidator: module => ValidateIndexer(module, "System.Int32 C.this[System.Int32 x].get", "void C.this[System.Int32 x].set"), expectedSignatures: new[] { Signature("C", "Item", ".property readwrite instance System.Int32 Item(System.Int32 x)"), Signature("C", "get_Item", ".method public hidebysig specialname virtual final instance System.Int32 get_Item(System.Int32 x) cil managed"), Signature("C", "set_Item", ".method public hidebysig specialname virtual final instance System.Void set_Item(System.Int32 x, System.Int32 value) cil managed") }); } [Fact] public void Hiding() { var text = @" class B { public virtual int this[int x] { get { return 0; } set { } } } class C : B { public new virtual int this[int x] { get { return 0; } set { } } } "; var compVerifier = CompileAndVerify(text, symbolValidator: module => ValidateIndexer(module, "System.Int32 C.this[System.Int32 x].get", "void C.this[System.Int32 x].set"), expectedSignatures: new[] { Signature("C", "Item", ".property readwrite instance System.Int32 Item(System.Int32 x)"), Signature("C", "get_Item", ".method public hidebysig newslot specialname virtual instance System.Int32 get_Item(System.Int32 x) cil managed"), Signature("C", "set_Item", ".method public hidebysig newslot specialname virtual instance System.Void set_Item(System.Int32 x, System.Int32 value) cil managed") }); } // NOTE: assumes there's a single indexer (type = int) in a type C. private static void ValidateIndexer(ModuleSymbol module, string getterDisplayString, string setterDisplayString) { var @class = module.GlobalNamespace.GetMember<NamedTypeSymbol>("C"); var indexer = @class.Indexers.Single(); Assert.Equal(SymbolKind.Property, indexer.Kind); Assert.True(indexer.IsIndexer); Assert.False(indexer.MustCallMethodsDirectly); Assert.Equal(Accessibility.Public, indexer.DeclaredAccessibility); Assert.False(indexer.IsStatic); var getMethod = indexer.GetMethod; if (getterDisplayString == null) { Assert.Null(getMethod); } else { Assert.Equal(MethodKind.PropertyGet, getMethod.MethodKind); Assert.Equal(getterDisplayString, getMethod.ToTestDisplayString()); getMethod.CheckAccessorShape(indexer); } var setMethod = indexer.SetMethod; if (setterDisplayString == null) { Assert.Null(setMethod); } else { Assert.Equal(MethodKind.PropertySet, setMethod.MethodKind); Assert.Equal(setterDisplayString, setMethod.ToTestDisplayString()); setMethod.CheckAccessorShape(indexer); } } #endregion Declarations #region Lowering private const string TypeWithIndexers = @" public class C { public static int Goo(int x) { System.Console.Write(x + "",""); return x * 10; } public int this[int x, int y = 9] { get { System.Console.Write(x + "",""); System.Console.Write(y + "",""); return -(x + y); } set { System.Console.Write(x + "",""); System.Console.Write(y + "",""); System.Console.Write(value + "",""); } } public int this[params int[] x] { get { foreach (var i in x) System.Console.Write(i + "",""); return -(x.Length); } set { foreach (var i in x) System.Console.Write(i + "",""); System.Console.Write(value + "",""); } } } "; [Fact] public void LoweringRead() { var text = TypeWithIndexers + @" class Test { static void Main() { C c = new C(); int x; //// Normal x = c[C.Goo(1), C.Goo(2)]; System.Console.WriteLine(); //// Named parameters x = c[C.Goo(1), y: C.Goo(2)]; //NB: Dev10 gets this wrong (2,1,10,20) System.Console.WriteLine(); x = c[x: C.Goo(1), y: C.Goo(2)]; System.Console.WriteLine(); x = c[y: C.Goo(2), x: C.Goo(1)]; System.Console.WriteLine(); //// Optional parameters x = c[C.Goo(1)]; System.Console.WriteLine(); x = c[x: C.Goo(1)]; System.Console.WriteLine(); //// Parameter arrays x = c[C.Goo(1), C.Goo(2), C.Goo(3)]; System.Console.WriteLine(); x = c[new int[] { C.Goo(1), C.Goo(2), C.Goo(3) }]; System.Console.WriteLine(); } } "; CompileAndVerify(text, expectedOutput: @" 1,2,10,20, 1,2,10,20, 1,2,10,20, 2,1,10,20, 1,10,9, 1,10,9, 1,2,3,10,20,30, 1,2,3,10,20,30, "); } [Fact] public void LoweringReadIL() { var text = TypeWithIndexers + @" class Test { static void Main() { C c = new C(); int x; //// Normal x = c[1, 2]; //// Named parameters x = c[1, y: 2]; x = c[x: 1, y: 2]; x = c[y: 2, x: 1]; //// Optional parameters x = c[1]; x = c[x: 1]; //// Parameter arrays x = c[1, 2, 3]; x = c[new int[] { 1, 2, 3 }]; } } "; var compVerifier = CompileAndVerify(text, options: TestOptions.ReleaseExe.WithModuleName("MODULE")); compVerifier.VerifyIL("Test.Main", @" { // Code size 111 (0x6f) .maxstack 4 .locals init (C V_0) //c IL_0000: newobj ""C..ctor()"" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldc.i4.1 IL_0008: ldc.i4.2 IL_0009: callvirt ""int C.this[int, int].get"" IL_000e: pop IL_000f: ldloc.0 IL_0010: ldc.i4.1 IL_0011: ldc.i4.2 IL_0012: callvirt ""int C.this[int, int].get"" IL_0017: pop IL_0018: ldloc.0 IL_0019: ldc.i4.1 IL_001a: ldc.i4.2 IL_001b: callvirt ""int C.this[int, int].get"" IL_0020: pop IL_0021: ldloc.0 IL_0022: ldc.i4.1 IL_0023: ldc.i4.2 IL_0024: callvirt ""int C.this[int, int].get"" IL_0029: pop IL_002a: ldloc.0 IL_002b: ldc.i4.1 IL_002c: ldc.i4.s 9 IL_002e: callvirt ""int C.this[int, int].get"" IL_0033: pop IL_0034: ldloc.0 IL_0035: ldc.i4.1 IL_0036: ldc.i4.s 9 IL_0038: callvirt ""int C.this[int, int].get"" IL_003d: pop IL_003e: ldloc.0 IL_003f: ldc.i4.3 IL_0040: newarr ""int"" IL_0045: dup IL_0046: ldtoken ""<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 <PrivateImplementationDetails>.4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D"" IL_004b: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_0050: callvirt ""int C.this[params int[]].get"" IL_0055: pop IL_0056: ldloc.0 IL_0057: ldc.i4.3 IL_0058: newarr ""int"" IL_005d: dup IL_005e: ldtoken ""<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 <PrivateImplementationDetails>.4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D"" IL_0063: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_0068: callvirt ""int C.this[params int[]].get"" IL_006d: pop IL_006e: ret } "); } [Fact] public void LoweringAssignment() { var text = TypeWithIndexers + @" class Test { static void Main() { C c = new C(); //// Normal c[C.Goo(1), C.Goo(2)] = C.Goo(3); System.Console.WriteLine(); //// Named parameters c[C.Goo(1), y: C.Goo(2)] = C.Goo(3); System.Console.WriteLine(); c[x: C.Goo(1), y: C.Goo(2)] = C.Goo(3); //NB: dev10 gets this wrong (2,1,3,10,20,30,) System.Console.WriteLine(); c[y: C.Goo(2), x: C.Goo(1)] = C.Goo(3); System.Console.WriteLine(); //// Optional parameters c[C.Goo(1)] = C.Goo(3); System.Console.WriteLine(); c[x: C.Goo(1)] = C.Goo(3); System.Console.WriteLine(); //// Parameter arrays c[C.Goo(1), C.Goo(2), C.Goo(3)] = C.Goo(4); System.Console.WriteLine(); c[new int[] { C.Goo(1), C.Goo(2), C.Goo(3) }] = C.Goo(4); System.Console.WriteLine(); } } "; CompileAndVerify(text, expectedOutput: @" 1,2,3,10,20,30, 1,2,3,10,20,30, 1,2,3,10,20,30, 2,1,3,10,20,30, 1,3,10,9,30, 1,3,10,9,30, 1,2,3,4,10,20,30,40, 1,2,3,4,10,20,30,40, "); } [Fact] public void LoweringAssignmentIL() { var text = TypeWithIndexers + @" class Test { static void Main() { C c = new C(); //// Normal c[1, 2] = 3; //// Named parameters c[1, y: 2] = 3; c[x: 1, y: 2] = 3; c[y: 2, x: 1] = 3; //// Optional parameters c[1] = 3; c[x: 1] = 3; //// Parameter arrays c[1, 2, 3] = 4; c[new int[] { 1, 2, 3 }] = 4; } } "; var compVerifier = CompileAndVerify(text, options: TestOptions.ReleaseExe.WithModuleName("MODULE")); compVerifier.VerifyIL("Test.Main", @" { // Code size 111 (0x6f) .maxstack 4 .locals init (C V_0) //c IL_0000: newobj ""C..ctor()"" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldc.i4.1 IL_0008: ldc.i4.2 IL_0009: ldc.i4.3 IL_000a: callvirt ""void C.this[int, int].set"" IL_000f: ldloc.0 IL_0010: ldc.i4.1 IL_0011: ldc.i4.2 IL_0012: ldc.i4.3 IL_0013: callvirt ""void C.this[int, int].set"" IL_0018: ldloc.0 IL_0019: ldc.i4.1 IL_001a: ldc.i4.2 IL_001b: ldc.i4.3 IL_001c: callvirt ""void C.this[int, int].set"" IL_0021: ldloc.0 IL_0022: ldc.i4.1 IL_0023: ldc.i4.2 IL_0024: ldc.i4.3 IL_0025: callvirt ""void C.this[int, int].set"" IL_002a: ldloc.0 IL_002b: ldc.i4.1 IL_002c: ldc.i4.s 9 IL_002e: ldc.i4.3 IL_002f: callvirt ""void C.this[int, int].set"" IL_0034: ldloc.0 IL_0035: ldc.i4.1 IL_0036: ldc.i4.s 9 IL_0038: ldc.i4.3 IL_0039: callvirt ""void C.this[int, int].set"" IL_003e: ldloc.0 IL_003f: ldc.i4.3 IL_0040: newarr ""int"" IL_0045: dup IL_0046: ldtoken ""<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 <PrivateImplementationDetails>.4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D"" IL_004b: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_0050: ldc.i4.4 IL_0051: callvirt ""void C.this[params int[]].set"" IL_0056: ldloc.0 IL_0057: ldc.i4.3 IL_0058: newarr ""int"" IL_005d: dup IL_005e: ldtoken ""<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 <PrivateImplementationDetails>.4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D"" IL_0063: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_0068: ldc.i4.4 IL_0069: callvirt ""void C.this[params int[]].set"" IL_006e: ret } "); } [Fact] public void LoweringIncrement() { var text = TypeWithIndexers + @" class Test { static void Main() { C c = new C(); //// Normal c[C.Goo(1), C.Goo(2)]++; System.Console.WriteLine(); //// Named parameters c[C.Goo(1), y: C.Goo(2)]++; System.Console.WriteLine(); c[x: C.Goo(1), y: C.Goo(2)]++; //NB: dev10 gets this wrong (2,1,10,20,10,20,-29,) System.Console.WriteLine(); c[y: C.Goo(2), x: C.Goo(1)]++; System.Console.WriteLine(); //// Optional parameters c[C.Goo(1)]++; System.Console.WriteLine(); c[x: C.Goo(1)]++; System.Console.WriteLine(); //// Parameter arrays c[C.Goo(1), C.Goo(2), C.Goo(3)]++; System.Console.WriteLine(); c[new int[] { C.Goo(1), C.Goo(2), C.Goo(3) }]++; System.Console.WriteLine(); } } "; var compVerifier = CompileAndVerify(text, expectedOutput: @" 1,2,10,20,10,20,-29, 1,2,10,20,10,20,-29, 1,2,10,20,10,20,-29, 2,1,10,20,10,20,-29, 1,10,9,10,9,-18, 1,10,9,10,9,-18, 1,2,3,10,20,30,10,20,30,-2, 1,2,3,10,20,30,10,20,30,-2, "); } [Fact] public void LoweringIncrementIL() { var text = TypeWithIndexers + @" class Test { static void Main() { C c = new C(); //// Normal c[1, 2]++; //// Named parameters c[1, y: 2]++; c[x: 1, y: 2]++; c[y: 2, x: 1]++; //// Optional parameters c[1]++; c[x: 1]++; //// Parameter arrays c[1, 2, 3]++; c[new int[] { 1, 2, 3 }]++; } } "; var compVerifier = CompileAndVerify(text, options: TestOptions.ReleaseExe.WithModuleName("MODULE")); compVerifier.VerifyIL("Test.Main", @" { // Code size 207 (0xcf) .maxstack 5 .locals init (C V_0, //c int V_1, C V_2, int[] V_3) IL_0000: newobj ""C..ctor()"" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: dup IL_0008: ldc.i4.1 IL_0009: ldc.i4.2 IL_000a: callvirt ""int C.this[int, int].get"" IL_000f: stloc.1 IL_0010: ldc.i4.1 IL_0011: ldc.i4.2 IL_0012: ldloc.1 IL_0013: ldc.i4.1 IL_0014: add IL_0015: callvirt ""void C.this[int, int].set"" IL_001a: ldloc.0 IL_001b: dup IL_001c: ldc.i4.1 IL_001d: ldc.i4.2 IL_001e: callvirt ""int C.this[int, int].get"" IL_0023: stloc.1 IL_0024: ldc.i4.1 IL_0025: ldc.i4.2 IL_0026: ldloc.1 IL_0027: ldc.i4.1 IL_0028: add IL_0029: callvirt ""void C.this[int, int].set"" IL_002e: ldloc.0 IL_002f: dup IL_0030: ldc.i4.1 IL_0031: ldc.i4.2 IL_0032: callvirt ""int C.this[int, int].get"" IL_0037: stloc.1 IL_0038: ldc.i4.1 IL_0039: ldc.i4.2 IL_003a: ldloc.1 IL_003b: ldc.i4.1 IL_003c: add IL_003d: callvirt ""void C.this[int, int].set"" IL_0042: ldloc.0 IL_0043: dup IL_0044: ldc.i4.1 IL_0045: ldc.i4.2 IL_0046: callvirt ""int C.this[int, int].get"" IL_004b: stloc.1 IL_004c: ldc.i4.1 IL_004d: ldc.i4.2 IL_004e: ldloc.1 IL_004f: ldc.i4.1 IL_0050: add IL_0051: callvirt ""void C.this[int, int].set"" IL_0056: ldloc.0 IL_0057: dup IL_0058: ldc.i4.1 IL_0059: ldc.i4.s 9 IL_005b: callvirt ""int C.this[int, int].get"" IL_0060: stloc.1 IL_0061: ldc.i4.1 IL_0062: ldc.i4.s 9 IL_0064: ldloc.1 IL_0065: ldc.i4.1 IL_0066: add IL_0067: callvirt ""void C.this[int, int].set"" IL_006c: ldloc.0 IL_006d: dup IL_006e: ldc.i4.1 IL_006f: ldc.i4.s 9 IL_0071: callvirt ""int C.this[int, int].get"" IL_0076: stloc.1 IL_0077: ldc.i4.1 IL_0078: ldc.i4.s 9 IL_007a: ldloc.1 IL_007b: ldc.i4.1 IL_007c: add IL_007d: callvirt ""void C.this[int, int].set"" IL_0082: ldloc.0 IL_0083: stloc.2 IL_0084: ldc.i4.3 IL_0085: newarr ""int"" IL_008a: dup IL_008b: ldtoken ""<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 <PrivateImplementationDetails>.4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D"" IL_0090: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_0095: stloc.3 IL_0096: ldloc.2 IL_0097: ldloc.3 IL_0098: callvirt ""int C.this[params int[]].get"" IL_009d: stloc.1 IL_009e: ldloc.2 IL_009f: ldloc.3 IL_00a0: ldloc.1 IL_00a1: ldc.i4.1 IL_00a2: add IL_00a3: callvirt ""void C.this[params int[]].set"" IL_00a8: ldloc.0 IL_00a9: stloc.2 IL_00aa: ldc.i4.3 IL_00ab: newarr ""int"" IL_00b0: dup IL_00b1: ldtoken ""<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 <PrivateImplementationDetails>.4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D"" IL_00b6: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_00bb: stloc.3 IL_00bc: ldloc.2 IL_00bd: ldloc.3 IL_00be: callvirt ""int C.this[params int[]].get"" IL_00c3: stloc.1 IL_00c4: ldloc.2 IL_00c5: ldloc.3 IL_00c6: ldloc.1 IL_00c7: ldc.i4.1 IL_00c8: add IL_00c9: callvirt ""void C.this[params int[]].set"" IL_00ce: ret } "); } [Fact] public void LoweringCompoundAssignment() { var text = TypeWithIndexers + @" class Test { static void Main() { C c = new C(); //// Normal c[C.Goo(1), C.Goo(2)] += C.Goo(3); System.Console.WriteLine(); //// Named parameters c[C.Goo(1), y: C.Goo(2)] += C.Goo(3); System.Console.WriteLine(); c[x: C.Goo(1), y: C.Goo(2)] += C.Goo(3); //NB: dev10 gets this wrong (2,1,10,20,3,10,20,0,) System.Console.WriteLine(); c[y: C.Goo(2), x: C.Goo(1)] += C.Goo(3); System.Console.WriteLine(); //// Optional parameters c[C.Goo(1)] += C.Goo(3); System.Console.WriteLine(); c[x: C.Goo(1)] += C.Goo(3); System.Console.WriteLine(); //// Parameter arrays c[C.Goo(1), C.Goo(2), C.Goo(3)] += C.Goo(4); System.Console.WriteLine(); c[new int[] { C.Goo(1), C.Goo(2), C.Goo(3) }] += C.Goo(4); System.Console.WriteLine(); } } "; CompileAndVerify(text, expectedOutput: @" 1,2,10,20,3,10,20,0, 1,2,10,20,3,10,20,0, 1,2,10,20,3,10,20,0, 2,1,10,20,3,10,20,0, 1,10,9,3,10,9,11, 1,10,9,3,10,9,11, 1,2,3,10,20,30,4,10,20,30,37, 1,2,3,10,20,30,4,10,20,30,37, "); } [Fact] public void LoweringCompoundAssignmentIL() { var text = TypeWithIndexers + @" class Test { static void Main() { C c = new C(); //// Normal c[1, 2] += 3; System.Console.WriteLine(); //// Named parameters c[1, y: 2] += 3; System.Console.WriteLine(); c[x: 1, y: 2] += 3; //NB: dev10 gets this wrong (2,1,10,20,3,10,20,0,) System.Console.WriteLine(); c[y: 2, x: 1] += 3; System.Console.WriteLine(); //// Optional parameters c[1] += 3; System.Console.WriteLine(); c[x: 1] += 3; System.Console.WriteLine(); //// Parameter arrays c[1, 2, 3] += 4; System.Console.WriteLine(); c[new int[] { 1, 2, 3 }] += 4; System.Console.WriteLine(); } } "; var compVerifier = CompileAndVerify(text, options: TestOptions.ReleaseExe.WithModuleName("MODULE")); compVerifier.VerifyIL("Test.Main", @" { // Code size 243 (0xf3) .maxstack 6 .locals init (C V_0, //c C V_1, int[] V_2) IL_0000: newobj ""C..ctor()"" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: stloc.1 IL_0008: ldloc.1 IL_0009: ldc.i4.1 IL_000a: ldc.i4.2 IL_000b: ldloc.1 IL_000c: ldc.i4.1 IL_000d: ldc.i4.2 IL_000e: callvirt ""int C.this[int, int].get"" IL_0013: ldc.i4.3 IL_0014: add IL_0015: callvirt ""void C.this[int, int].set"" IL_001a: call ""void System.Console.WriteLine()"" IL_001f: ldloc.0 IL_0020: stloc.1 IL_0021: ldloc.1 IL_0022: ldc.i4.1 IL_0023: ldc.i4.2 IL_0024: ldloc.1 IL_0025: ldc.i4.1 IL_0026: ldc.i4.2 IL_0027: callvirt ""int C.this[int, int].get"" IL_002c: ldc.i4.3 IL_002d: add IL_002e: callvirt ""void C.this[int, int].set"" IL_0033: call ""void System.Console.WriteLine()"" IL_0038: ldloc.0 IL_0039: stloc.1 IL_003a: ldloc.1 IL_003b: ldc.i4.1 IL_003c: ldc.i4.2 IL_003d: ldloc.1 IL_003e: ldc.i4.1 IL_003f: ldc.i4.2 IL_0040: callvirt ""int C.this[int, int].get"" IL_0045: ldc.i4.3 IL_0046: add IL_0047: callvirt ""void C.this[int, int].set"" IL_004c: call ""void System.Console.WriteLine()"" IL_0051: ldloc.0 IL_0052: stloc.1 IL_0053: ldloc.1 IL_0054: ldc.i4.1 IL_0055: ldc.i4.2 IL_0056: ldloc.1 IL_0057: ldc.i4.1 IL_0058: ldc.i4.2 IL_0059: callvirt ""int C.this[int, int].get"" IL_005e: ldc.i4.3 IL_005f: add IL_0060: callvirt ""void C.this[int, int].set"" IL_0065: call ""void System.Console.WriteLine()"" IL_006a: ldloc.0 IL_006b: stloc.1 IL_006c: ldloc.1 IL_006d: ldc.i4.1 IL_006e: ldc.i4.s 9 IL_0070: ldloc.1 IL_0071: ldc.i4.1 IL_0072: ldc.i4.s 9 IL_0074: callvirt ""int C.this[int, int].get"" IL_0079: ldc.i4.3 IL_007a: add IL_007b: callvirt ""void C.this[int, int].set"" IL_0080: call ""void System.Console.WriteLine()"" IL_0085: ldloc.0 IL_0086: stloc.1 IL_0087: ldloc.1 IL_0088: ldc.i4.1 IL_0089: ldc.i4.s 9 IL_008b: ldloc.1 IL_008c: ldc.i4.1 IL_008d: ldc.i4.s 9 IL_008f: callvirt ""int C.this[int, int].get"" IL_0094: ldc.i4.3 IL_0095: add IL_0096: callvirt ""void C.this[int, int].set"" IL_009b: call ""void System.Console.WriteLine()"" IL_00a0: ldloc.0 IL_00a1: stloc.1 IL_00a2: ldc.i4.3 IL_00a3: newarr ""int"" IL_00a8: dup IL_00a9: ldtoken ""<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 <PrivateImplementationDetails>.4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D"" IL_00ae: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_00b3: stloc.2 IL_00b4: ldloc.1 IL_00b5: ldloc.2 IL_00b6: ldloc.1 IL_00b7: ldloc.2 IL_00b8: callvirt ""int C.this[params int[]].get"" IL_00bd: ldc.i4.4 IL_00be: add IL_00bf: callvirt ""void C.this[params int[]].set"" IL_00c4: call ""void System.Console.WriteLine()"" IL_00c9: ldloc.0 IL_00ca: stloc.1 IL_00cb: ldc.i4.3 IL_00cc: newarr ""int"" IL_00d1: dup IL_00d2: ldtoken ""<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 <PrivateImplementationDetails>.4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D"" IL_00d7: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_00dc: stloc.2 IL_00dd: ldloc.1 IL_00de: ldloc.2 IL_00df: ldloc.1 IL_00e0: ldloc.2 IL_00e1: callvirt ""int C.this[params int[]].get"" IL_00e6: ldc.i4.4 IL_00e7: add IL_00e8: callvirt ""void C.this[params int[]].set"" IL_00ed: call ""void System.Console.WriteLine()"" IL_00f2: ret } "); } [Fact] public void LoweringComplex() { var text = TypeWithIndexers + @" class Test { static C NewC() { System.Console.Write(""N,""); return new C(); } static void Main() { NewC()[y: C.Goo(1), x: NewC()[C.Goo(2)]] = NewC()[x: C.Goo(3), y: NewC()[C.Goo(4)]] += NewC()[C.Goo(5), C.Goo(6), NewC()[C.Goo(7)]]++; System.Console.WriteLine(); } } "; CompileAndVerify(text, expectedOutput: @" N,1,N,2,20,9,N,3,N,4,40,9,30,-49,N,5,6,N,7,70,9,50,60,-79,50,60,-79,-2,30,-49,16,-29,10,16, "); } [Fact] public void BoxingParameterArrayArguments() { var text = TypeWithIndexers + @" class Test { int this[params object[] args] { get { return args.Length; } } static void Main() { System.Console.WriteLine(new Test()[1, 2]); } } "; var verifier = CompileAndVerify(text, expectedOutput: @"2"); verifier.VerifyIL("Test.Main", @" { // Code size 40 (0x28) .maxstack 5 IL_0000: newobj ""Test..ctor()"" IL_0005: ldc.i4.2 IL_0006: newarr ""object"" IL_000b: dup IL_000c: ldc.i4.0 IL_000d: ldc.i4.1 IL_000e: box ""int"" IL_0013: stelem.ref IL_0014: dup IL_0015: ldc.i4.1 IL_0016: ldc.i4.2 IL_0017: box ""int"" IL_001c: stelem.ref IL_001d: call ""int Test.this[params object[]].get"" IL_0022: call ""void System.Console.WriteLine(int)"" IL_0027: ret } "); } [Fact] public void IndexerOverrideNotAllAccessors_DefaultParameterValues() { var text = @" using System; class Base { public virtual int this[int x, int y = 1] { get { Console.WriteLine(""Base.get y: "" + y); return y; } set { Console.WriteLine(""Base.set y: "" + y); } } } class Override : Base { public override int this[int x, int y = 2] { set { Console.WriteLine(""Override.set y: "" + y); } } } class Program { static void Main() { Base b = new Base(); _ = b[0]; b[0] = 0; Override o = new Override(); _ = o[0]; o[0] = 0; o[0] += 0; } } "; CompileAndVerify(text, expectedOutput: @"Base.get y: 1 Base.set y: 1 Base.get y: 1 Override.set y: 2 Base.get y: 1 Override.set y: 1 "); } #endregion Lowering [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/75032")] public void MissingDefaultMemberAttribute_01() { var text1 = @" public interface I1 { public I1 this[I1 args] { get; } } "; var comp1 = CreateCompilation(text1); comp1.MakeMemberMissing(WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor); comp1.VerifyDiagnostics( // (4,15): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor' // public I1 this[I1 args] { get; } Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(4, 15) ); comp1 = CreateCompilation(text1); comp1.MakeTypeMissing(WellKnownType.System_Reflection_DefaultMemberAttribute); comp1.VerifyDiagnostics( // (4,15): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor' // public I1 this[I1 args] { get; } Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(4, 15) ); comp1 = CreateCompilation(text1); comp1.VerifyEmitDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/75032")] public void MissingDefaultMemberAttribute_02() { var text1 = @" public interface I1 { public I1 this[I1 args] { get; } } "; var comp1 = CreateCompilation(text1); var text2 = @" class C : I1 { I1 I1.this[I1 args] => throw null; } "; var comp2 = CreateCompilation(text2, references: [comp1.ToMetadataReference()]); comp2.MakeMemberMissing(WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor); comp2.VerifyEmitDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/75032")] public void MissingDefaultMemberAttribute_03() { var text1 = @" using System.Collections.Generic; class Program { static IEnumerable<int> Test() { return [123]; } } "; var comp1 = CreateCompilation(text1); comp1.MakeMemberMissing(WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor); CompileAndVerify(comp1).VerifyDiagnostics(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/79436")] public void ParamArrayOrderOfEvaluation() { var text1 = @" public struct S1 { public int this[int i, params int[] j] { get { System.Console.Write(""get_Item ""); System.Console.Write(i); System.Console.Write(j[0]); System.Console.Write("" ""); return 0; } set { System.Console.Write(""set_Item ""); System.Console.Write(i); System.Console.Write(j[0]); System.Console.Write(value); } } } class Program { static void Main() { Test1(default); System.Console.WriteLine(); Test2(default); } static void Test1(S1 s) { s[Get1(), Get2()] += Get3(); } static void Test2(S1 s) { s[Get1(), [Get2()]] += Get3(); } public static int Get1() { System.Console.Write(""Get1 ""); return 1; } public static int Get2() { System.Console.Write(""Get2 ""); return 2; } public static int Get3() { System.Console.Write(""Get3 ""); return 3; } }"; var comp1 = CreateCompilation(text1, options: TestOptions.DebugExe); var verifier = CompileAndVerify(comp1, expectedOutput: @" Get1 Get2 get_Item 12 Get3 set_Item 123 Get1 Get2 get_Item 12 Get3 set_Item 123 ").VerifyDiagnostics(); var expectedIL = @" { // Code size 49 (0x31) .maxstack 6 .locals init (S1& V_0, int V_1, int[] V_2) IL_0000: nop IL_0001: ldarga.s V_0 IL_0003: stloc.0 IL_0004: call ""int Program.Get1()"" IL_0009: stloc.1 IL_000a: ldc.i4.1 IL_000b: newarr ""int"" IL_0010: dup IL_0011: ldc.i4.0 IL_0012: call ""int Program.Get2()"" IL_0017: stelem.i4 IL_0018: stloc.2 IL_0019: ldloc.0 IL_001a: ldloc.1 IL_001b: ldloc.2 IL_001c: ldloc.0 IL_001d: ldloc.1 IL_001e: ldloc.2 IL_001f: call ""int S1.this[int, params int[]].get"" IL_0024: call ""int Program.Get3()"" IL_0029: add IL_002a: call ""void S1.this[int, params int[]].set"" IL_002f: nop IL_0030: ret } "; verifier.VerifyIL("Program.Test1", expectedIL); verifier.VerifyIL("Program.Test2", expectedIL); } } }