Recursive where for generic child types

This commit is contained in:
Sun Serega 2022-10-06 06:44:59 +03:00
parent c86877149e
commit 1eb9b28c0f
2 changed files with 49 additions and 17 deletions

View file

@ -0,0 +1,30 @@
type
i0 = interface end;
base_i<TSelf> = interface
where TSelf: base_i<TSelf>;
function fi(a: TSelf): TSelf;
end;
base_c<TSelf> = abstract class
where TSelf: base_c<TSelf>;
function fc(a: TSelf): TSelf; abstract;
end;
class1<T> = class(i0, base_i<class1<T>>)
public function fi(a: class1<T>) := a;
end;
class2<T> = class(base_c<class2<T>>, base_i<class2<T>>)
public function fi(a: class2<T>) := self;
public function fc(a: class2<T>): class2<T>; override := self;
end;
record1<T> = record(i0, base_i<record1<T>>)
public function fi(a: record1<T>) := self;
end;
interface1<T> = interface(i0, base_i<interface1<T>>)
end;
begin end.

View file

@ -3789,12 +3789,12 @@ namespace PascalABCCompiler.TreeConverter
// Для записей базовый класс устанавливает на SemanticRules.StructBaseType ещё в context.create_record_type
var need_set_base = _class_definition.keyword != PascalABCCompiler.SyntaxTree.class_keyword.Record;
// Ограничение шаблонов предка и интерфейсов нельзя проверять
// на первом проходе, когда ещё не все предки добавлены в converted_type
var need_recheck_where = new List<syntax_tree_node>();
if (_class_definition.class_parents != null)
{
// Ограничение шаблонов предка и интерфейсов нельзя проверять
// на первом проходе, когда они не добавлены в converted_type
var need_recheck_where = new List<syntax_tree_node>(_class_definition.class_parents.Count);
need_recheck_where.Capacity = _class_definition.class_parents.Count;
// В случае partial классов можно (и желательно) указывать интерфейсы, которые уже были в предыдущем описании
// Поэтому проверять нужно только уникальное среди списка интерфейсов в этом описании
var curr_def_interfaces = new List<type_node>(need_recheck_where.Capacity);
@ -3854,13 +3854,6 @@ namespace PascalABCCompiler.TreeConverter
}
context.skip_check_where_sections = false;
// Проверяем секции where предка/интерфейсов
// В самом конце, когда converted_type
// уже содержит всю информацию о предке и интерфейсах
foreach (var syntax_tn in need_recheck_where)
ret.visit(syntax_tn);
}
if (need_set_base)
@ -3871,12 +3864,21 @@ namespace PascalABCCompiler.TreeConverter
converted_type.SetBaseType(bt);
}
if (_class_definition.keyword==PascalABCCompiler.SyntaxTree.class_keyword.Class)
foreach (generic_type_instance_info gti in generic_convertions.get_type_instances(converted_type))
{
if (!(gti.pseudo_instance.base_type != null && gti.pseudo_instance.base_type.is_generic_type_instance && converted_type.IsPartial))
gti.pseudo_instance.SetBaseType(converted_type.base_type);
}
foreach (generic_type_instance_info gti in generic_convertions.get_type_instances(converted_type))
{
//TODO Зачем?
if (gti.pseudo_instance.base_type != null && gti.pseudo_instance.base_type.is_generic_type_instance && converted_type.IsPartial) continue;
//TODO "t1<T> = class(i1<T>)" => "t1<byte>" реализует "i1<T>" вместо "i1<byte>"???
gti.pseudo_instance.SetBaseType(converted_type.base_type);
gti.pseudo_instance.ImplementingInterfaces.Clear();
gti.pseudo_instance.ImplementingInterfaces.AddRange(converted_type.ImplementingInterfaces);
}
// Проверяем секции where предка/интерфейсов
// В самом конце, когда converted_type
// уже содержит всю информацию о предке и интерфейсах
foreach (var syntax_tn in need_recheck_where)
ret.visit(syntax_tn);
switch (_class_definition.keyword)
{