Recursive where for generic child types
This commit is contained in:
parent
c86877149e
commit
1eb9b28c0f
30
TestSuite/recursive_where_gen.pas
Normal file
30
TestSuite/recursive_where_gen.pas
Normal 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.
|
||||||
|
|
@ -3789,12 +3789,12 @@ namespace PascalABCCompiler.TreeConverter
|
||||||
|
|
||||||
// Для записей базовый класс устанавливает на SemanticRules.StructBaseType ещё в context.create_record_type
|
// Для записей базовый класс устанавливает на SemanticRules.StructBaseType ещё в context.create_record_type
|
||||||
var need_set_base = _class_definition.keyword != PascalABCCompiler.SyntaxTree.class_keyword.Record;
|
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)
|
if (_class_definition.class_parents != null)
|
||||||
{
|
{
|
||||||
// Ограничение шаблонов предка и интерфейсов нельзя проверять
|
need_recheck_where.Capacity = _class_definition.class_parents.Count;
|
||||||
// на первом проходе, когда они не добавлены в converted_type
|
|
||||||
var need_recheck_where = new List<syntax_tree_node>(_class_definition.class_parents.Count);
|
|
||||||
|
|
||||||
// В случае partial классов можно (и желательно) указывать интерфейсы, которые уже были в предыдущем описании
|
// В случае partial классов можно (и желательно) указывать интерфейсы, которые уже были в предыдущем описании
|
||||||
// Поэтому проверять нужно только уникальное среди списка интерфейсов в этом описании
|
// Поэтому проверять нужно только уникальное среди списка интерфейсов в этом описании
|
||||||
var curr_def_interfaces = new List<type_node>(need_recheck_where.Capacity);
|
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;
|
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)
|
if (need_set_base)
|
||||||
|
|
@ -3871,12 +3864,21 @@ namespace PascalABCCompiler.TreeConverter
|
||||||
converted_type.SetBaseType(bt);
|
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))
|
||||||
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))
|
if (gti.pseudo_instance.base_type != null && gti.pseudo_instance.base_type.is_generic_type_instance && converted_type.IsPartial) continue;
|
||||||
gti.pseudo_instance.SetBaseType(converted_type.base_type);
|
//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)
|
switch (_class_definition.keyword)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue