diff --git a/TestSuite/recursive_where_gen.pas b/TestSuite/recursive_where_gen.pas new file mode 100644 index 000000000..de3ab169b --- /dev/null +++ b/TestSuite/recursive_where_gen.pas @@ -0,0 +1,30 @@ +type + i0 = interface end; + + base_i = interface + where TSelf: base_i; + function fi(a: TSelf): TSelf; + end; + + base_c = abstract class + where TSelf: base_c; + function fc(a: TSelf): TSelf; abstract; + end; + + class1 = class(i0, base_i>) + public function fi(a: class1) := a; + end; + class2 = class(base_c>, base_i>) + public function fi(a: class2) := self; + public function fc(a: class2): class2; override := self; + end; + + record1 = record(i0, base_i>) + public function fi(a: record1) := self; + end; + + interface1 = interface(i0, base_i>) + + end; + +begin end. \ No newline at end of file diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index dd8b0786e..beacee734 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -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(); if (_class_definition.class_parents != null) { - // Ограничение шаблонов предка и интерфейсов нельзя проверять - // на первом проходе, когда они не добавлены в converted_type - var need_recheck_where = new List(_class_definition.class_parents.Count); - + need_recheck_where.Capacity = _class_definition.class_parents.Count; // В случае partial классов можно (и желательно) указывать интерфейсы, которые уже были в предыдущем описании // Поэтому проверять нужно только уникальное среди списка интерфейсов в этом описании var curr_def_interfaces = new List(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 = class(i1)" => "t1" реализует "i1" вместо "i1"??? + 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) {