diff --git a/TestSuite/foreach_resolver1.pas b/TestSuite/foreach_resolver1.pas index c61937fea..3c56ac31e 100644 --- a/TestSuite/foreach_resolver1.pas +++ b/TestSuite/foreach_resolver1.pas @@ -1,5 +1,7 @@ {$reference 'foreach_resolver_lib.dll'} +uses System; + type c0 = class procedure pr:= exit; @@ -26,7 +28,7 @@ begin var v3:= new c3; v3._element:= 'myStr'; foreach var item in v3 do - print(item); + item.GetHashCode; Assert(check); check:= false; @@ -45,4 +47,12 @@ begin Assert(item = 4); Assert(check); + check:= false; + + var v6:= new c6>; + v6._element:= new List, integer>, Dictionary, Dictionary>, integer>>; + foreach var item in v6 do + item.FirstOrDefault; + + Assert(check); end. \ No newline at end of file diff --git a/TestSuite/foreach_resolver_lib.dll b/TestSuite/foreach_resolver_lib.dll index e56056d11..65df20be7 100644 Binary files a/TestSuite/foreach_resolver_lib.dll and b/TestSuite/foreach_resolver_lib.dll differ diff --git a/TestSuite/foreach_resolver_lib.pas b/TestSuite/foreach_resolver_lib.pas index 3f629a79e..1aa5a24cb 100644 --- a/TestSuite/foreach_resolver_lib.pas +++ b/TestSuite/foreach_resolver_lib.pas @@ -1,5 +1,5 @@ library foreach_resolver_lib; - uses System.Collections, System.Collections.Generic; + uses System, System.Collections, System.Collections.Generic; var check:= false; @@ -55,4 +55,20 @@ c4 = class (c2) end; c5 = class (c1) end; + + c6 = class (IEnumerable, Dictionary, integer>>>) + public + _element: IEnumerable, Dictionary, integer>>; + + function GetEnumerator: IEnumerator, Dictionary, integer>>>; + begin + check:= true; + var l:= new List, Dictionary, integer>>>; + l.Add(_element); + result:= l.GetEnumerator; + end; + + function IEnumerable.GetEnumerator: IEnumerator; + begin end; + end; end. \ No newline at end of file diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index e0c47de5e..0227063ea 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -19040,6 +19040,32 @@ namespace PascalABCCompiler.TreeConverter } } + private type_node RestoreTypesInGeneric(Type orig, IList genericArgs) + { + if (!orig.IsGenericType) + throw new InvalidOperationException(); + + var actualTypes = new List(); + + foreach (var declaredType in orig.GetGenericArguments()) + { + type_node actualType; + + if (declaredType.IsGenericParameter) + actualType = genericArgs[declaredType.GenericParameterPosition]; + else if (declaredType.IsGenericType) + actualType = RestoreTypesInGeneric(declaredType, genericArgs); + else + actualType = compiled_type_node.get_type_node(declaredType); + + actualTypes.Add(actualType); + } + + var result = compiled_type_node.get_type_node( orig.GetGenericTypeDefinition() ); + + return result.get_instance(actualTypes); + } + public bool FindIEnumerableElementType(type_node tn, ref type_node elem_type, out bool sys_coll_ienum) { sys_coll_ienum = false; @@ -19101,32 +19127,24 @@ namespace PascalABCCompiler.TreeConverter else { // для "tn is compiled_generic_instance_type_node" необходимо восстановить стёртые типы - // orig.instance_params содержит имена типоаргументов при объявлении - // tn.instance_params содержит фактические типоаргументы - // остаётся найти нужный индекс в orig и взять аргумент из tn + // tn.instance_params содержит фактические типоаргументы (их может быть несколько) + // чтобы взять нужный, проверяем позицию через .GenericParameterPosition if (foundElementType.IsGenericParameter) { - var ind = orig.instance_params.FindIndex(item => item.name == foundElementType.Name); + var ind = foundElementType.GenericParameterPosition; elem_type = tn.instance_params[ind]; } else { // значит элемент последовательности сам является generic типом - // нужно сопоставить все типоаргументы из orig типоаргументам из tn - // нельзя просто брать все, тк их количество может отличаться + // при чём его типоаргументы могут быть как из tn.instance_params, так и самостоятельными + // IEnumerable< IEnumerable > + // IEnumerable< Dictionary > + // + // а также глубоко вложенными IEnumerable< IEnumerable> > - var declaredTypes = foundElementType - .GetGenericArguments() - .Select(item=> item.Name) - .ToArray(); - - var actualTypes = tn.instance_params - .Where((item, i) => declaredTypes.Contains(orig.instance_params[i].name)) - .ToList(); - - elem_type = compiled_type_node.get_type_node( foundElementType.GetGenericTypeDefinition() ); - elem_type = elem_type.get_instance(actualTypes); + elem_type = RestoreTypesInGeneric(foundElementType, tn.instance_params); } }