@@ -847,6 +847,236 @@ public void List_LargeCapacity_Growth()
847847 Assert . AreEqual ( i , list [ i ] ) ;
848848 }
849849 }
850+
851+ [ TestMethod ]
852+ public void List_GenericMethod_Foreach_Int ( )
853+ {
854+ // Exercises MVAR resolution: a generic method creates List<T> and iterates via foreach.
855+ // The virtual dispatch of MoveNext()/Current on IEnumerator<T> requires resolving
856+ // !!T (method-level generic parameter) through the caller's MethodSpec context.
857+ int result = SumList ( new int [ ] { 1 , 2 , 3 , 4 , 5 } ) ;
858+ Assert . AreEqual ( 15 , result ) ;
859+ }
860+
861+ [ TestMethod ]
862+ public void List_GenericMethod_Foreach_String ( )
863+ {
864+ // Same MVAR path but with reference types
865+ string result = ConcatList ( new string [ ] { "Hello" , " " , "World" } ) ;
866+ Assert . AreEqual ( "Hello World" , result ) ;
867+ }
868+
869+ [ TestMethod ]
870+ public void List_GenericMethod_Foreach_Class ( )
871+ {
872+ // MVAR resolution with user-defined class types
873+ var items = new DummyClass [ ]
874+ {
875+ new ( 1 , "One" ) ,
876+ new ( 2 , "Two" ) ,
877+ new ( 3 , "Three" )
878+ } ;
879+
880+ var result = CollectFromList ( items ) ;
881+ Assert . AreEqual ( 3 , result . Length ) ;
882+ Assert . AreEqual ( 1 , result [ 0 ] . Id ) ;
883+ Assert . AreEqual ( "Two" , result [ 1 ] . Name ) ;
884+ Assert . AreEqual ( 3 , result [ 2 ] . Id ) ;
885+ }
886+
887+ [ TestMethod ]
888+ public void List_GenericMethod_Contains ( )
889+ {
890+ // Exercises MVAR resolution through Contains which uses
891+ // equality checks on the generic type parameter
892+ Assert . IsTrue ( ListContains ( new int [ ] { 1 , 2 , 3 } , 2 ) ) ;
893+ Assert . IsFalse ( ListContains ( new int [ ] { 1 , 2 , 3 } , 5 ) ) ;
894+
895+ Assert . IsTrue ( ListContains ( new string [ ] { "A" , "B" , "C" } , "B" ) ) ;
896+ Assert . IsFalse ( ListContains ( new string [ ] { "A" , "B" , "C" } , "Z" ) ) ;
897+ }
898+
899+ [ TestMethod ]
900+ public void List_GenericMethod_AddAndCount ( )
901+ {
902+ // Exercises MVAR resolution through Add/Count on List<T>
903+ // where T is a method-level generic parameter
904+ Assert . AreEqual ( 5 , BuildListAndCount ( 1 , 2 , 3 , 4 , 5 ) ) ;
905+ Assert . AreEqual ( 3 , BuildListAndCount ( "A" , "B" , "C" ) ) ;
906+ }
907+
908+ [ TestMethod ]
909+ public void List_GenericMethod_IndexOf ( )
910+ {
911+ // Exercises MVAR resolution through IndexOf
912+ Assert . AreEqual ( 2 , ListIndexOf ( new int [ ] { 10 , 20 , 30 , 40 } , 30 ) ) ;
913+ Assert . AreEqual ( - 1 , ListIndexOf ( new int [ ] { 10 , 20 , 30 , 40 } , 99 ) ) ;
914+
915+ Assert . AreEqual ( 1 , ListIndexOf ( new string [ ] { "X" , "Y" , "Z" } , "Y" ) ) ;
916+ Assert . AreEqual ( - 1 , ListIndexOf ( new string [ ] { "X" , "Y" , "Z" } , "W" ) ) ;
917+ }
918+
919+ [ TestMethod ]
920+ public void List_GenericMethod_RemoveAndVerify ( )
921+ {
922+ // Exercises MVAR resolution through Remove + foreach verification
923+ var remaining = RemoveFromList ( new int [ ] { 1 , 2 , 3 , 4 , 5 } , 3 ) ;
924+ Assert . AreEqual ( 4 , remaining . Length ) ;
925+ Assert . AreEqual ( 1 , remaining [ 0 ] ) ;
926+ Assert . AreEqual ( 2 , remaining [ 1 ] ) ;
927+ Assert . AreEqual ( 4 , remaining [ 2 ] ) ;
928+ Assert . AreEqual ( 5 , remaining [ 3 ] ) ;
929+ }
930+
931+ [ TestMethod ]
932+ public void List_GenericMethod_InsertAndIterate ( )
933+ {
934+ // Exercises MVAR resolution through Insert + foreach iteration
935+ var result = InsertIntoList ( new int [ ] { 1 , 3 , 4 } , 1 , 2 ) ;
936+ Assert . AreEqual ( 4 , result . Length ) ;
937+ Assert . AreEqual ( 1 , result [ 0 ] ) ;
938+ Assert . AreEqual ( 2 , result [ 1 ] ) ;
939+ Assert . AreEqual ( 3 , result [ 2 ] ) ;
940+ Assert . AreEqual ( 4 , result [ 3 ] ) ;
941+ }
942+
943+ [ TestMethod ]
944+ public void List_GenericMethod_NestedIteration ( )
945+ {
946+ // Exercises MVAR resolution with nested generic method calls
947+ // The inner method iterates a List<T> created from the outer method's !!T
948+ var list = new List < int > { 1 , 2 , 3 } ;
949+ int sum = IterateAndSum ( list ) ;
950+ Assert . AreEqual ( 6 , sum ) ;
951+
952+ var listStr = new List < string > { "A" , "B" , "C" } ;
953+ int count = CountItems ( listStr ) ;
954+ Assert . AreEqual ( 3 , count ) ;
955+ }
956+
957+ // Generic helper methods that exercise MVAR resolution paths.
958+ // When these are called, the TypeSpec for List<T> contains !!T (MVAR)
959+ // which must be resolved from the caller's MethodSpec context.
960+
961+ private static int SumList < T > ( T [ ] source ) where T : struct
962+ {
963+ var list = new List < T > ( source ) ;
964+ int sum = 0 ;
965+
966+ foreach ( T item in list )
967+ {
968+ sum += ( int ) ( object ) item ;
969+ }
970+
971+ return sum ;
972+ }
973+
974+ private static string ConcatList < T > ( T [ ] source )
975+ {
976+ var list = new List < T > ( source ) ;
977+ string result = "" ;
978+
979+ foreach ( T item in list )
980+ {
981+ result += item . ToString ( ) ;
982+ }
983+
984+ return result ;
985+ }
986+
987+ private static T [ ] CollectFromList < T > ( T [ ] source )
988+ {
989+ var list = new List < T > ( source ) ;
990+ var result = new T [ list . Count ] ;
991+ int i = 0 ;
992+
993+ foreach ( T item in list )
994+ {
995+ result [ i ++ ] = item ;
996+ }
997+
998+ return result ;
999+ }
1000+
1001+ private static bool ListContains < T > ( T [ ] source , T value )
1002+ {
1003+ var list = new List < T > ( source ) ;
1004+ return list . Contains ( value ) ;
1005+ }
1006+
1007+ private static int BuildListAndCount < T > ( params T [ ] items )
1008+ {
1009+ var list = new List < T > ( ) ;
1010+
1011+ foreach ( T item in items )
1012+ {
1013+ list . Add ( item ) ;
1014+ }
1015+
1016+ return list . Count ;
1017+ }
1018+
1019+ private static int ListIndexOf < T > ( T [ ] source , T value )
1020+ {
1021+ var list = new List < T > ( source ) ;
1022+ return list . IndexOf ( value ) ;
1023+ }
1024+
1025+ private static T [ ] RemoveFromList < T > ( T [ ] source , T itemToRemove )
1026+ {
1027+ var list = new List < T > ( source ) ;
1028+ list . Remove ( itemToRemove ) ;
1029+
1030+ var result = new T [ list . Count ] ;
1031+ int i = 0 ;
1032+
1033+ foreach ( T item in list )
1034+ {
1035+ result [ i ++ ] = item ;
1036+ }
1037+
1038+ return result ;
1039+ }
1040+
1041+ private static T [ ] InsertIntoList < T > ( T [ ] source , int index , T item )
1042+ {
1043+ var list = new List < T > ( source ) ;
1044+ list . Insert ( index , item ) ;
1045+
1046+ var result = new T [ list . Count ] ;
1047+ int i = 0 ;
1048+
1049+ foreach ( T entry in list )
1050+ {
1051+ result [ i ++ ] = entry ;
1052+ }
1053+
1054+ return result ;
1055+ }
1056+
1057+ private static int IterateAndSum < T > ( List < T > list ) where T : struct
1058+ {
1059+ int sum = 0 ;
1060+
1061+ foreach ( T item in list )
1062+ {
1063+ sum += ( int ) ( object ) item ;
1064+ }
1065+
1066+ return sum ;
1067+ }
1068+
1069+ private static int CountItems < T > ( List < T > list )
1070+ {
1071+ int count = 0 ;
1072+
1073+ foreach ( T _ in list )
1074+ {
1075+ count ++ ;
1076+ }
1077+
1078+ return count ;
1079+ }
8501080 }
8511081
8521082 internal class DummyClass
0 commit comments