From 50fd3cb1eed913a84a7f9c5f00e55c7fa46aa314 Mon Sep 17 00:00:00 2001 From: samuraiGH <87191377+samuraiGH@users.noreply.github.com> Date: Wed, 28 May 2025 23:01:09 +0300 Subject: [PATCH] * adding supports enumeration check for Pascal types in foreach resolver (#3272) * fix naming --- .../TreeConversion/syntax_tree_visitor.cs | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index 837d980aa..2f25070bb 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -18848,7 +18848,7 @@ namespace PascalABCCompiler.TreeConverter return isIEnumType || isIEnumTypedType; } - private Type FindIEnumerableInterfaceInCompiledType(Type compiledType) + private Type ChooseIEnumerableInterfaceInCompiledType(Type compiledType) { var IEnumType = typeof(IEnumerable); var IEnumTypedType = typeof(IEnumerable<>); @@ -18933,18 +18933,16 @@ namespace PascalABCCompiler.TreeConverter /// /// Собирает интерфейсы, реализованные типом и его предками /// - private List CollectInterfacesFromTypeNode(type_node node) + private IEnumerable CollectInterfacesFromTypeNode(type_node node) { - var result = new List(); - result.AddRange(node.ImplementingInterfaces); - - if (node.base_type != null) + do { - var interfInBase = CollectInterfacesFromTypeNode(node.base_type); - result.AddRange(interfInBase); - } + foreach (var item in node.ImplementingInterfaces) + yield return (type_node)item; - return result.Cast().ToList(); + node = node.base_type; + } + while (node != null); } private bool IsIEnumeratorInterface(type_node t) @@ -18961,7 +18959,7 @@ namespace PascalABCCompiler.TreeConverter return IsIEnumeratorInterface(orig.compiled_type); } - private type_node FindIEnumerableInterfaceInTypeNode(type_node node) + private type_node ChooseIEnumerableInterfaceInTypeNode(type_node node) { var IEnumType = compiled_type_node.get_type_node( typeof(IEnumerable) ); var IEnumTypedType = compiled_type_node.get_type_node( typeof(IEnumerable<>) ); @@ -19004,9 +19002,9 @@ namespace PascalABCCompiler.TreeConverter // выбираем IEnumerable if (genericInterfaceCount == 1) return filteredInterfaces.First(item => item.is_generic_type_instance); - // явно реализует IEnumerable - странно - заменил на null - SSM 23.05.25 + // явно реализует IEnumerable else - return null; // IEnumType; + return IEnumType; case 1: var method = methods[0]; @@ -19045,9 +19043,9 @@ namespace PascalABCCompiler.TreeConverter // непосредственно тип, от котоого разворачивается foreach Type ct = orig.compiled_type; - var isEnumeratedType = typeof(IEnumerable).IsAssignableFrom(ct); + var supportsEnumeration = typeof(IEnumerable).IsAssignableFrom(ct); - if (!isEnumeratedType) + if (!supportsEnumeration) return false; // для массива @@ -19062,7 +19060,7 @@ namespace PascalABCCompiler.TreeConverter } // в иных случаях ищем подходящий интерфейс - var desiredInterface = FindIEnumerableInterfaceInCompiledType(ct); + var desiredInterface = ChooseIEnumerableInterfaceInCompiledType(ct); if (desiredInterface == null) return false; @@ -19118,6 +19116,11 @@ namespace PascalABCCompiler.TreeConverter // также сюда попадают set of T даже если они подтягиваются из библиотеки else { + var supportsEnumeration = CollectInterfacesFromTypeNode(tn).Any(IsIEnumerableInterface); + + if (!supportsEnumeration) + return false; + // массивы и set of T if (tn.element_type != null && tn.type_special_kind != SemanticTree.type_special_kind.typed_file) { @@ -19129,7 +19132,7 @@ namespace PascalABCCompiler.TreeConverter return true; } - var desiredInterface = FindIEnumerableInterfaceInTypeNode(tn); + var desiredInterface = ChooseIEnumerableInterfaceInTypeNode(tn); if (desiredInterface == null) return false;