cleanup and more comments

This commit is contained in:
samuraiGH 2024-06-30 23:31:28 +03:00
parent 32f126370c
commit 464dc794a8
3 changed files with 116 additions and 162 deletions

View file

@ -11595,13 +11595,9 @@ namespace PascalABCCompiler.NETGenerator
public override void visit(IForeachNode value)
{
VarInfo vi = helper.GetVariable(value.VarIdent);
//Type interf = helper.GetTypeReference(value.InWhatExpr.type).tp;
Type var_tp = helper.GetTypeReference(value.VarIdent.type).tp;
//(ssyy) 12.04.2008 Поиск IEnumerable не нужен! Это дело семантики!
Type in_what_type = helper.GetTypeReference(value.InWhatExpr.type).tp;
Type return_type;
//bool is_generic = false;
//Type[] generic_args = null;
MethodInfo enumer_mi;
Type elementType = helper.GetTypeReference(value.ElementType).tp;
@ -11610,6 +11606,9 @@ namespace PascalABCCompiler.NETGenerator
if (is_generic)
{
// если элемент перечисления объявлен в коде
// или типоаргумент элемента перечисления объявлен в коде
// например IEnumerable<MyType>, array of MyType
if (helper.IsConstructedGenericType(elementType))
{
enumer_mi = TypeBuilder.GetMethod(
@ -11617,10 +11616,13 @@ namespace PascalABCCompiler.NETGenerator
TypeFactory.IEnumerableGenericType.GetMethod("GetEnumerator")
);
// IEnumerator<elementType>
return_type = enumer_mi.ReturnType
.GetGenericTypeDefinition()
.MakeGenericType(elementType);
}
// для полностью скомпилированных типов TypeBuilder не требуется
// IEnumerable<integer>, array of string
else
{
enumer_mi = TypeFactory.IEnumerableGenericType.MakeGenericType(elementType).GetMethod("GetEnumerator");

View file

@ -18591,6 +18591,9 @@ namespace PascalABCCompiler.TreeConverter
return IsIEnumerableInterface(orig.compiled_type);
}
/// <summary>
/// Собирает интерфейсы, реализованные типом и его предками
/// </summary>
private List<ITypeNode> CollectInterfacesFromTypeNode(type_node node)
{
var result = new List<ITypeNode>();
@ -18626,13 +18629,15 @@ namespace PascalABCCompiler.TreeConverter
var filteredInterfaces = CollectInterfacesFromTypeNode(node)
.Where(item => IsIEnumerableInterface(item))
.Select( item => (type_node)item )
.Cast<type_node>()
.ToArray();
var genericInterfaceCount = filteredInterfaces.Count(item => item.is_generic_type_instance);
if (node.IsInterface)
{
// интерфейс наследует несколько IEnumerable<T> с разными T
// невозможно выбрать. требуется явное приведение
if (genericInterfaceCount > 1)
return null;
@ -18642,9 +18647,6 @@ namespace PascalABCCompiler.TreeConverter
return IEnumType;
}
if (!(node is common_type_node))
throw null;
var commonType = (common_type_node)node;
var methods = commonType.methods.Where(item =>
@ -18675,6 +18677,8 @@ namespace PascalABCCompiler.TreeConverter
else
return IEnumTypedType.get_instance(method.return_value_type.instance_params);
default:
// в типе наследнике перекрыли GetEnumerator
// невозможно точно выбрать метод
return null;
}
}
@ -18683,11 +18687,15 @@ namespace PascalABCCompiler.TreeConverter
{
sys_coll_ienum = false;
if (tn is compiled_type_node || tn is compiled_generic_instance_type_node) // Если этот тип зашит в .NET
// IEnumerable<integer>, Range(1,10), Dictionary<string,integer>: tn = compiled_type_node
// IEnumerable<T>: tn = compiled_generic_instance_type_node
// FibGen = class(IEnumerable,IEnumerator): tn = common_type_node, en = compiled_type_node
// array of Person: tn = common_type_node
// поиск в типе, объявленном в другой сборке
// и тип и типоаргументы объявлены в другой сборке
// Dictionary<string, integer>: tn = compiled_type_node
// IEnumerable<integer>: tn = compiled_type_node
//
// тип объявлен в другой сборке, а типоаргументы в коде
// Dictionary<string, MyType>: tn = compiled_generic_instance_type_node
// IEnumerable<T1>: tn = compiled_generic_instance_type_node (например в generic подпрогамме)
if (tn is compiled_type_node || tn is compiled_generic_instance_type_node)
{
compiled_type_node orig;
@ -18736,7 +18744,9 @@ namespace PascalABCCompiler.TreeConverter
else
{
// для "tn is compiled_generic_instance_type_node" необходимо восстановить стёртые типы
var temp = foundElementType.GetGenericArguments();
// orig.instance_params содержит имена типоаргументов при объявлении
// tn.instance_params содержит фактические типоаргументы
// остаётся найти нужный индекс в orig и взять аргумент из tn
if (foundElementType.IsGenericParameter)
{
@ -18745,6 +18755,10 @@ namespace PascalABCCompiler.TreeConverter
}
else
{
// значит элемент последовательности сам является generic типом
// нужно сопоставить все типоаргументы из orig типоаргументам из tn
// нельзя просто брать все, тк их количество может отличаться
var declaredTypes = foundElementType
.GetGenericArguments()
.Select(item=> item.Name)
@ -18761,9 +18775,10 @@ namespace PascalABCCompiler.TreeConverter
return true;
}
// поиск в типе, объявленном в коде
// также сюда попадают set of T даже если они подтягиваются из библиотеки
else
// если мы самостоятельно определяем этот тип - можно реализовать в PascalABC.NET только IEnumerable. // Сейчас уже можно!!!!!
// Попытка реализовать IEnumerable<T> натыкается на необходимость определять GetEnumerator, возвращающий IEnumerator и IEnumerator<T>
{
// массивы и set of T
if (tn.element_type != null && tn.type_special_kind != SemanticTree.type_special_kind.typed_file)
@ -18790,70 +18805,7 @@ namespace PascalABCCompiler.TreeConverter
elem_type = desiredInterface.instance_params[0];
return true;
//var IEnstring = "System.Collections.IEnumerable";
//compiled_type_node ctn = compiled_type_node.get_type_node(NetHelper.NetHelper.FindType(IEnstring));
//if (tn == null || tn is null_type_node || tn.ImplementingInterfaces == null)
// {
// if (tn != null && tn.base_type != null)
// return FindIEnumerableElementType(tn.base_type, ref elem_type, out sys_coll_ienum);
// return false;
// }
// if (tn.element_type != null && tn.type_special_kind != SemanticTree.type_special_kind.typed_file) // еще может быть множество set of T - 22.02.16 SSM
// {
// elem_type = tn.element_type;
// if (tn.type_special_kind == type_special_kind.set_type)
// sys_coll_ienum = true;
// return true;
// }
// foreach (SemanticTree.ITypeNode itn in tn.ImplementingInterfaces) // Ищем интерфейс IEnumerable<T> и возвращаем T в качестве elem_type
// {
// if (itn is compiled_generic_instance_type_node)
// {
// var itnc = (itn as compiled_generic_instance_type_node);
// var tt = (itnc.original_generic as compiled_type_node).compiled_type;
// if (tt == typeof(System.Collections.Generic.IEnumerable<>))
// {
// elem_type = itnc.generic_parameters[0] as common_type_node;
// return true;
// }
// }
// }
// foreach (SemanticTree.ITypeNode itn in tn.ImplementingInterfaces) // если не нашли - ищем интерфейс IEnumerable и возвращаем object в качестве elem_type
// {
// if (itn is compiled_type_node) // Именно этот кусок отвечает за IEnumerable<integer> и мы его закомментировали
// {
// var itnc = (itn as compiled_type_node).compiled_type; /* SSM раскомментировал 15.05.2020 - пришла пора*/
// if (itnc.IsGenericType)
// {
// var my = itnc.GetGenericTypeDefinition();// = typeof(System.Collections.Generic.IEnumerable<>)
// if (my == typeof(System.Collections.Generic.IEnumerable<>))
// {
// var aarg1 = itnc.GetGenericArguments().First();
// elem_type = compiled_type_node.get_type_node(aarg1);
// return true;
// }
// }
// else /* end SSM раскомментировал 15.05.2020 - пришла пора*/
// if (itn == ctn)
// {
// elem_type = SystemLibrary.SystemLibrary.object_type;
// sys_coll_ienum = true;
// return true;
// }
// }
// }
}
//if (tn != null && tn.base_type != null)
// return FindIEnumerableElementType(tn.base_type, ref elem_type, out sys_coll_ienum);
//return false;
}
private int GenIdNum = 0;