improving type recovery (#3341)

This commit is contained in:
samuraiGH 2025-10-01 11:48:04 +03:00 committed by GitHub
parent 0626885b5f
commit bfc3291d81
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 63 additions and 19 deletions

View file

@ -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<integer, Dictionary<integer, c0>>;
v6._element:= new List<Tuple<Dictionary<Dictionary<integer, c0>, integer>, Dictionary<Dictionary<integer, c0>, Dictionary<integer, c0>>, integer>>;
foreach var item in v6 do
item.FirstOrDefault;
Assert(check);
end.

Binary file not shown.

View file

@ -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<string, integer>) end;
c6<T1, T2> = class (IEnumerable<IEnumerable<Tuple<Dictionary<T2, T1>, Dictionary<T2, T2>, integer>>>)
public
_element: IEnumerable<Tuple<Dictionary<T2, T1>, Dictionary<T2, T2>, integer>>;
function GetEnumerator: IEnumerator<IEnumerable<Tuple<Dictionary<T2, T1>, Dictionary<T2, T2>, integer>>>;
begin
check:= true;
var l:= new List<IEnumerable<Tuple<Dictionary<T2, T1>, Dictionary<T2, T2>, integer>>>;
l.Add(_element);
result:= l.GetEnumerator;
end;
function IEnumerable.GetEnumerator: IEnumerator;
begin end;
end;
end.

View file

@ -19040,6 +19040,32 @@ namespace PascalABCCompiler.TreeConverter
}
}
private type_node RestoreTypesInGeneric(Type orig, IList<type_node> genericArgs)
{
if (!orig.IsGenericType)
throw new InvalidOperationException();
var actualTypes = new List<type_node>();
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<PascalType> >
// IEnumerable< Dictionary<integer, PascalType> >
//
// а также глубоко вложенными IEnumerable< IEnumerable<IEnumerable<PascalType>> >
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);
}
}