From 258d8d6c6a0250a3e0386003821ebcf08f14c6d9 Mon Sep 17 00:00:00 2001 From: Sun Serega Date: Tue, 27 Sep 2022 17:43:17 +0300 Subject: [PATCH 1/4] fix #2725 --- TestSuite/errors/err0237.pas | 13 +- TestSuite/errors/err0304.pas | 3 +- .../err0360_InherFromOnlyDeclClasses.pas | 13 - .../err0361_InherFromOnlyDeclClasses2.pas | 11 - .../convertion_data_and_alghoritms.cs | 13 - .../TreeConversion/syntax_tree_visitor.cs | 384 ++++++++---------- TreeConverter/TreeRealization/type_table.cs | 17 +- bin/Lng/Eng/SemanticErrors_ib.dat | 4 +- bin/Lng/Eng/SemanticErrors_ssyy.dat | 1 + bin/Lng/Rus/SemanticErrors_ssyy.dat | 1 + bin/Lng/Ukr/SemanticErrors_ssyy.dat | 1 + 11 files changed, 193 insertions(+), 268 deletions(-) delete mode 100644 TestSuite/errors/err0360_InherFromOnlyDeclClasses.pas delete mode 100644 TestSuite/errors/err0361_InherFromOnlyDeclClasses2.pas diff --git a/TestSuite/errors/err0237.pas b/TestSuite/errors/err0237.pas index a062e9f9b..5aa5bf10b 100644 --- a/TestSuite/errors/err0237.pas +++ b/TestSuite/errors/err0237.pas @@ -1,11 +1,10 @@ -type - t1=abstract class +//!Класс t2 абстрактный и не может иметь атрибут sealed, потому что метод test не реализован +type + t1 = abstract class procedure test; abstract; end; - t2=sealed class(t1) + t2 = sealed class(t1) end; - -begin - -end. \ No newline at end of file + +begin end. \ No newline at end of file diff --git a/TestSuite/errors/err0304.pas b/TestSuite/errors/err0304.pas index a6e7edf9e..cdcd03e00 100644 --- a/TestSuite/errors/err0304.pas +++ b/TestSuite/errors/err0304.pas @@ -1,4 +1,5 @@ -type +//!Предописание I2 не может быть использовано в качестве базового типа +type I1 = interface; I2 = interface; diff --git a/TestSuite/errors/err0360_InherFromOnlyDeclClasses.pas b/TestSuite/errors/err0360_InherFromOnlyDeclClasses.pas deleted file mode 100644 index ddf9ad5fb..000000000 --- a/TestSuite/errors/err0360_InherFromOnlyDeclClasses.pas +++ /dev/null @@ -1,13 +0,0 @@ -type - t0 = class end; - - A = class; - B = class(t0) - - end; - A = class - - end; - -begin -end. \ No newline at end of file diff --git a/TestSuite/errors/err0361_InherFromOnlyDeclClasses2.pas b/TestSuite/errors/err0361_InherFromOnlyDeclClasses2.pas deleted file mode 100644 index c815f76b4..000000000 --- a/TestSuite/errors/err0361_InherFromOnlyDeclClasses2.pas +++ /dev/null @@ -1,11 +0,0 @@ -type - TErr = class; - - TDer = class(List>) - end; - - TErr = class end; - -begin - -end. \ No newline at end of file diff --git a/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs b/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs index 2026ac07d..b9b049a44 100644 --- a/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs +++ b/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs @@ -3058,19 +3058,6 @@ namespace PascalABCCompiler.TreeConverter return null; // это вхолостую } - public bool ContainsForward(type_node tn) - { - if (tn.ForwardDeclarationOnly || tn.original_generic != null && tn.original_generic.ForwardDeclarationOnly) - return true; - if (tn is generic_instance_type_node tni) - foreach (var t in tn.instance_params) - { - var r = ContainsForward(t); - if (r) - return r; - } - return false; - } } } diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index 0405e768f..7dd0a71f0 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -3756,121 +3756,160 @@ namespace PascalABCCompiler.TreeConverter context.converted_type.SetIsSealed(true); context.converted_type.SetIsAbstract(true, null); // Причина null, потому что причины нет, класс статический а не абстрактный } + + common_type_node converted_type; + //TODO Выглядит странно - в каком это случае семантический узел записи создаётся с задержкой? + if (_class_definition.keyword==PascalABCCompiler.SyntaxTree.class_keyword.Record) + { + if (_record_created) + { + _record_created = false; + converted_type = context.converted_type; + } + else + { + converted_type = context.create_record_type(get_location(_class_definition), record_type_name); + if (record_is_generic) + { + context.create_generic_indicator(converted_type); + visit_generic_params(converted_type, _class_definition.template_args.idents); + } + else + { + if (_class_definition.template_args != null && _class_definition.template_args.idents != null) + { + AddError(get_location(_class_definition.template_args), "GENERIC_TYPE_NOT_ALLOWED_HERE"); + } + } + visit_where_list(_class_definition.where_section); + } + } + else + converted_type = context.converted_type; + + // Для записей базовый класс устанавливает на SemanticRules.StructBaseType ещё в context.create_record_type + var need_set_base = _class_definition.keyword != PascalABCCompiler.SyntaxTree.class_keyword.Record; + if (_class_definition.class_parents != null) + { + // Ограничение шаблонов предка и интерфейсов нельзя проверять + // на первом проходе, когда они не добавлены в converted_type + var need_recheck_where = new List(_class_definition.class_parents.Count); + + // В случае partial классов можно (и желательно) указывать интерфейсы, которые уже были в предыдущем описании + // Поэтому проверять нужно только уникальное среди списка интерфейсов в этом описании + var curr_def_interfaces = new List(need_recheck_where.Capacity); + + // Отключаем проверки where для случая + // t1 = ...(t0) + context.skip_check_where_sections = true; + for (int i = 0; i < _class_definition.class_parents.Count; i++) + { + var syntax_tn = _class_definition.class_parents[i]; + location loc = get_location(syntax_tn); + + var tn = (type_node)ret.visit(syntax_tn); + if (tn.is_generic_type_definition) need_recheck_where.Add(syntax_tn); + + if ((tn.original_generic??tn).ForwardDeclarationOnly) + AddError(loc, "FORWARD_DECLARATION_{0}_AS_BASE_TYPE", tn.PrintableName); + if (tn.is_generic_parameter) + AddError(loc, "CAN_NOT_INHERIT_FROM_GENERIC_PARAMETER"); + + for (var curr = tn; curr!=null; curr=curr.base_type) + { + curr = curr.original_generic ?? curr; + if (curr == converted_type) + AddError(loc, "TYPE_{0}_INHERITS_SELF", converted_type.PrintableName); + } + + // Если первый тип в списке - класс-предок + if (i==0 && !tn.IsInterface && _class_definition.keyword==PascalABCCompiler.SyntaxTree.class_keyword.Class) + { + if (tn.IsSealed) + AddError(loc, "PARENT_TYPE_IS_SEALED{0}", tn.PrintableName); + if (tn == SystemLibrary.SystemLibrary.value_type) + AddError(loc, "CAN_NOT_INHERIT_FROM_VALUE_TYPE"); + if (tn.IsPointer) + AddError(loc, "CAN_NOT_INHERIT_FROM_POINTER"); + if (tn.IsDelegate) + AddError(loc, "CAN_NOT_INHERIT_FROM_FUNCTION_TYPE"); + if (tn == SystemLibrary.SystemLibrary.delegate_base_type || tn == SystemLibrary.SystemLibrary.system_delegate_type) + AddError(loc, "CAN_NOT_INHERIT_FROM_DELEGATE_TYPE"); + + converted_type.SetBaseType(tn); + need_set_base = false; + + if (tn is common_type_node ctn && ctn.IsPartial) + inherited_from_partials_list.Add(converted_type); + + continue; + } + + // type_table.AddInterface проверяет что tn это интерфейс + type_table.AddInterface(converted_type, tn, loc); + if (curr_def_interfaces.Contains(tn)) + AddError(loc, "INTERFACE_{0}_ALREADY_ADDED_TO_IMPLEMENTING_LIST", tn.PrintableName); + else + curr_def_interfaces.Add(tn); + + } + 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) + { + var bt = + (converted_type.IsPartial ? converted_type.base_type : null) ?? + SemanticRules.ClassBaseType; + 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); + } + switch (_class_definition.keyword) { case PascalABCCompiler.SyntaxTree.class_keyword.Class: - //if (context.converted_type.IsPartial) - // generic_convertions.remove_type_instances(context.converted_type); - if (context.converted_type.is_value || context.converted_type.IsInterface) - { - AddError(get_location(_class_definition), "FORWARD_DECLARATION_OF_{0}_MISMATCH_DECLARATION", context.converted_type.name); - } - if ((_class_definition.class_parents != null) && (_class_definition.class_parents.types.Count > 0)) - { - if (context.converted_type.IsStatic) - AddError(get_location(_class_definition), "STATIC_CLASS_CANNOT_HAVE_PARENT"); - context.skip_check_where_sections = true; - type_node tn = ret.visit(_class_definition.class_parents.types[0]); - context.skip_check_where_sections = false; - //if (tn == context.converted_type) - if (type_table.original_types_equals(tn, context.converted_type)) - AddError(new UndefinedNameReference(tn.name, get_location(_class_definition.class_parents.types[0]))); - if (tn.IsSealed) - AddError(get_location(_class_definition.class_parents.types[0]), "PARENT_TYPE_IS_SEALED{0}", tn.name); - if (tn == SystemLibrary.SystemLibrary.value_type) - { - AddError(get_location(_class_definition.class_parents.types[0]), "CAN_NOT_INHERIT_FROM_VALUE_TYPE"); - } - if (tn.IsPointer) - { - AddError(get_location(_class_definition.class_parents.types[0]), "CAN_NOT_INHERIT_FROM_POINTER"); - } - if (tn.IsDelegate) - { - AddError(get_location(_class_definition.class_parents.types[0]), "CAN_NOT_INHERIT_FROM_FUNCTION_TYPE"); - } - if (tn == SystemLibrary.SystemLibrary.delegate_base_type || tn == SystemLibrary.SystemLibrary.system_delegate_type) - { - AddError(get_location(_class_definition.class_parents.types[0]), "CAN_NOT_INHERIT_FROM_DELEGATE_TYPE"); - } - Hashtable used_interfs = new Hashtable(); - if (tn is common_type_node && (tn as common_type_node).IsPartial) - inherited_from_partials_list.Add(context.converted_type); - //Если tn - это интерфейс - if (tn.IsInterface) - { - //Первым в списке предков идёт интерфейс, поэтому базовым будет object. - context.converted_type.SetBaseType(SemanticRules.ClassBaseType); + //if (converted_type.IsPartial) + // generic_convertions.remove_type_instances(converted_type); + + if (converted_type.is_value || converted_type.IsInterface) + AddError(get_location(_class_definition), "FORWARD_DECLARATION_OF_{0}_MISMATCH_DECLARATION", converted_type.name); + converted_type.is_class = true; - //Добавляем интерфейс - used_interfs.Add(tn, tn); - type_table.AddInterface(context.converted_type, tn, get_location(_class_definition.class_parents.types[0])); - if (tn.is_generic_type_instance) - ret.visit(_class_definition.class_parents.types[0]); - } - else - { - if (convertion_data_and_alghoritms.ContainsForward(tn)) // SSM 20/05/2020 #2140 - { - AddError(get_location(_class_definition.class_parents.types[0]), "FORWARD_DECLARATION_{0}_AS_BASE_TYPE", tn.name); - } - if (tn.is_generic_parameter) - { - AddError(get_location(_class_definition.class_parents.types[0]), "CAN_NOT_INHERIT_FROM_GENERIC_PARAMETER"); - } - context.converted_type.SetBaseType(tn); - if (tn.is_generic_type_instance) - ret.visit(_class_definition.class_parents.types[0]); - var type_instances = generic_convertions.get_type_instances(context.converted_type); - if (type_instances != null) - foreach (generic_type_instance_info gti in type_instances) - { - if (!(gti.pseudo_instance.base_type != null && gti.pseudo_instance.base_type.is_generic_type_instance && context.converted_type.IsPartial)) - gti.pseudo_instance.SetBaseType(tn); - } - } - //Теперь добавляем интерфейсы. - //Цикл с единицы, т.к. нулевой элемент уже был рассмотрен. - VisitAndAddInterfaces(context.converted_type, _class_definition.class_parents.types, 1, used_interfs); - //for (int i = 1; i < _class_definition.class_parents.types.Count; i++) - //{ - // type_node interf = ret.visit(_class_definition.class_parents.types[i]); - // AddInterface(context.converted_type, interf, get_location(_class_definition.class_parents.types[i])); - //} - } - else - { - if (!(context.converted_type.IsPartial && context.converted_type.base_type != null && context.converted_type.base_type != SemanticRules.ClassBaseType)) - context.converted_type.SetBaseType(SemanticRules.ClassBaseType); - else if (context.converted_type.IsPartial && context.converted_type.base_type != null) - context.converted_type.SetBaseType(context.converted_type.base_type); - } - - context.converted_type.is_class = true; if (_class_definition.body == null && (_class_definition.class_parents == null || _class_definition.class_parents.types.Count == 0)) { - if (context.converted_type.ForwardDeclarationOnly) - { - AddError(new NameRedefinition(context.converted_type.name, context.converted_type.Location, get_location(_class_definition))); - } - context.types_predefined.Add(context.converted_type); - context.converted_type.ForwardDeclarationOnly = true; + if (converted_type.ForwardDeclarationOnly) + AddError(new NameRedefinition(converted_type.name, converted_type.Location, get_location(_class_definition))); + converted_type.ForwardDeclarationOnly = true; + + context.types_predefined.Add(converted_type); } else { - context.converted_type.ForwardDeclarationOnly = false; + converted_type.ForwardDeclarationOnly = false; if (_class_definition.body == null) { generate_inherit_constructors(); - if (!context.converted_type.has_default_constructor) + if (!converted_type.has_default_constructor) { generate_default_constructor(); } } - List names = new List(); - List types = new List(); - if ((_class_definition.IsAutoClass())) + + if (_class_definition.IsAutoClass()) { // Если снова возникнет ошибка с предками в автоклассах, то не раскомментировать эти строки, а подумать, как разрешить //if (_class_definition.class_parents!=null) @@ -3888,6 +3927,8 @@ namespace PascalABCCompiler.TreeConverter } + List names = new List(); + List types = new List(); SyntaxTreeBuilder.AddMembersForAutoClass(_class_definition,ref names,ref types); //if (names.Select(s => s.name.ToLower()).Distinct().Count() != names.Count) @@ -3928,92 +3969,61 @@ namespace PascalABCCompiler.TreeConverter } } } - //if (!SemanticRules.OrderIndependedNames) - - weak_node_test_and_visit(_class_definition.body); - + //if (!SemanticRules.OrderIndependedNames) + weak_node_test_and_visit(_class_definition.body); } - common_type_node converted_type = context.converted_type; context.leave_block(); + + // Обязательно после context.leave_block, потому что там неявно-абстрактные методы помечают свой IsAbstract if (converted_type.IsSealed && converted_type.IsAbstract && !converted_type.IsStatic) + { if (converted_type.AbstractReason == null) AddError(get_location(_class_definition), "ABSTRACT_CLASS_CANNOT_BE_SEALED"); else AddError(get_location(_class_definition), converted_type.AbstractReason.Explanation, converted_type.name, converted_type.AbstractReason.ObjName); + } return; case PascalABCCompiler.SyntaxTree.class_keyword.Record: - common_type_node ctn; - if (_record_created) - { - _record_created = false; - ctn = context.converted_type; - } - else - { - ctn = context.create_record_type(get_location(_class_definition), record_type_name); - if (record_is_generic) - { - context.create_generic_indicator(ctn); - visit_generic_params(ctn, _class_definition.template_args.idents); - } - else - { - if (_class_definition.template_args != null && _class_definition.template_args.idents != null) - { - AddError(get_location(_class_definition.template_args), "GENERIC_TYPE_NOT_ALLOWED_HERE"); - } - } - visit_where_list(_class_definition.where_section); - } if (context.CurrentScope is SymbolTable.BlockScope) { AddError(get_location(_class_definition), "RECORD_CANNOT_BE_DECLARED_IN_BLOCK"); - ctn.internal_is_value = true; + converted_type.internal_is_value = true; context.leave_record(); - return_value(ctn); + return_value(converted_type); return; } - //Добавляем интерфейсы - предки. - if (_class_definition.class_parents != null) - { - VisitAndAddInterfaces(context.converted_type, _class_definition.class_parents.types, 0, new Hashtable()); - //for (int i = 0; i < _class_definition.class_parents.types.Count; i++) - //{ - // type_node interf = ret.visit(_class_definition.class_parents.types[i]); - // AddInterface(context.converted_type, interf, get_location(_class_definition.class_parents.types[i])); - //} - } - CheckWaitedRefTypes(ctn); + // "PMyRec = ^MyRec" перед описанием "MyRec" + CheckWaitedRefTypes(converted_type); + record_type_name = null; record_is_generic = false; - context.converted_type.internal_is_value = true; + converted_type.internal_is_value = true; if (_class_definition.body == null && (_class_definition.class_parents == null || _class_definition.class_parents.types.Count == 0)) { - if (context.converted_type.ForwardDeclarationOnly) - { - AddError(new NameRedefinition(context.converted_type.name, context.converted_type.Location, get_location(_class_definition))); - } - context.types_predefined.Add(context.converted_type); - context.converted_type.ForwardDeclarationOnly = true; + if (converted_type.ForwardDeclarationOnly) + AddError(new NameRedefinition(converted_type.name, converted_type.Location, get_location(_class_definition))); + context.types_predefined.Add(converted_type); + + converted_type.ForwardDeclarationOnly = true; } else { - context.converted_type.ForwardDeclarationOnly = false; + converted_type.ForwardDeclarationOnly = false; weak_node_test_and_visit(_class_definition.body); - + } /*if (_class_definition.body != null) hard_node_test_and_visit(_class_definition.body); else { - context.converted_type.ForwardDeclarationOnly = true; + converted_type.ForwardDeclarationOnly = true; }*/ /*if (_class_definition.body != null) foreach (SyntaxTree.var_def_statement var in (_class_definition.body.class_def_blocks[0].members)) @@ -4021,32 +4031,22 @@ namespace PascalABCCompiler.TreeConverter hard_node_test_and_visit(var); }*/ context.leave_record(); - return_value(ctn); + return_value(converted_type); return; //ssyy owns case PascalABCCompiler.SyntaxTree.class_keyword.Interface: - if (context.converted_type.is_value || !context.converted_type.IsInterface) + if (converted_type.is_value || !converted_type.IsInterface) { - AddError(get_location(_class_definition), "FORWARD_DECLARATION_OF_{0}_MISMATCH_DECLARATION", context.converted_type.name); + AddError(get_location(_class_definition), "FORWARD_DECLARATION_OF_{0}_MISMATCH_DECLARATION", converted_type.name); } if (SemanticRules.GenerateNativeCode) - context.converted_type.SetBaseType(SemanticRules.ClassBaseType); + converted_type.SetBaseType(SemanticRules.ClassBaseType); else - context.converted_type.SetBaseType(SystemLibrary.SystemLibrary.object_type); - context.converted_type.IsInterface = true; - context.converted_type.is_class = true; - //Добавляем интерфейсы - предки. - if (_class_definition.class_parents != null) - { - VisitAndAddInterfaces(context.converted_type, _class_definition.class_parents.types, 0, new Hashtable()); - //for (int i = 0; i < _class_definition.class_parents.types.Count; i++) - //{ - // type_node interf = ret.visit(_class_definition.class_parents.types[i]); - // AddInterface(context.converted_type, interf, get_location(_class_definition.class_parents.types[i])); - //} - } + converted_type.SetBaseType(SystemLibrary.SystemLibrary.object_type); + converted_type.IsInterface = true; + converted_type.is_class = true; - InitInterfaceScope(context.converted_type); + InitInterfaceScope(converted_type); //if (_class_definition.body == null) //{ @@ -4056,16 +4056,16 @@ namespace PascalABCCompiler.TreeConverter if (_class_definition.body == null && (_class_definition.class_parents == null || _class_definition.class_parents.types.Count == 0)) { - if (context.converted_type.ForwardDeclarationOnly) + if (converted_type.ForwardDeclarationOnly) { - AddError(new NameRedefinition(context.converted_type.name, context.converted_type.Location, get_location(_class_definition))); + AddError(new NameRedefinition(converted_type.name, converted_type.Location, get_location(_class_definition))); } - context.types_predefined.Add(context.converted_type); - context.converted_type.ForwardDeclarationOnly = true; + context.types_predefined.Add(converted_type); + converted_type.ForwardDeclarationOnly = true; } else { - context.converted_type.ForwardDeclarationOnly = false; + converted_type.ForwardDeclarationOnly = false; weak_node_test_and_visit(_class_definition.body); } //hard_node_test_and_visit(_class_definition.body); @@ -4077,22 +4077,6 @@ namespace PascalABCCompiler.TreeConverter } } - private void VisitAndAddInterfaces(common_type_node t, List types, int start, Hashtable used_interfaces) - { - for (int i = start; i < types.Count; i++) - { - type_node interf = ret.visit(types[i]); - location loc = get_location(types[i]); - if (used_interfaces[interf] != null) - { - AddError(loc, "INTERFACE_{0}_ALREADY_ADDED_TO_IMPLEMENTING_LIST", interf.PrintableName); - } - used_interfaces.Add(interf, interf); - check_cycle_interface_inheritance(t, interf, new List()); - type_table.AddInterface(t, interf, loc); - } - } - private void InitInterfaceScope(common_type_node ctn) { List interf_scopes = new List(ctn.ImplementingInterfaces.Count); @@ -12782,30 +12766,6 @@ namespace PascalABCCompiler.TreeConverter } } - private void check_cycle_interface_inheritance(common_type_node cnode, type_node base_of_cnode, List interfaces) - { - // Для интерфейсов всё это излишне. Поскольку нельзя использовать предописанные интерфейсы в списке наследования, то - // циклически интерфейс может наследовать только от себя. Поэтому достаточно проверять нерекурсивно свой список ImplementingInterfaces и если там есть этот интерфейс, то ошибка - if (!cnode.IsInterface) - return; - interfaces.Add(cnode); - common_type_node bt = base_of_cnode as common_type_node; - if (bt != null && bt.original_generic != null) - bt = bt.original_generic as common_type_node; - if (bt != null) - { - if (interfaces.Contains(bt)) - { - AddError(bt.loc, "TYPE_{0}_DERIVED_FROM_ITSELF", bt.PrintableName); - } - interfaces.Add(bt); - foreach (var tn in bt.ImplementingInterfaces) - { - check_cycle_interface_inheritance(bt, tn as type_node, interfaces); - } - } - } - private void check_where_from_base_class(common_type_node ctn) { if (ctn.base_type != null && ctn.base_type.is_generic_type_instance && ctn.is_generic_type_definition) diff --git a/TreeConverter/TreeRealization/type_table.cs b/TreeConverter/TreeRealization/type_table.cs index b1689a197..4104a0b96 100644 --- a/TreeConverter/TreeRealization/type_table.cs +++ b/TreeConverter/TreeRealization/type_table.cs @@ -352,16 +352,15 @@ namespace PascalABCCompiler.TreeRealization { throw new TreeConverter.SimpleSemanticError(loc, "FORWARD_DECLARATION_{0}_AS_IMPLEMENTING_INTERFACE", _interface.name); } - if (!cnode.ImplementingInterfaces.Contains(_interface)) + + if (cnode.ImplementingInterfaces.Contains(_interface)) + return; + cnode.ImplementingInterfaces.Add(_interface); + foreach (type_node tn in _interface.ImplementingInterfaces) { - cnode.ImplementingInterfaces.Add(_interface); - foreach (type_node tn in _interface.ImplementingInterfaces) - { - if (!cnode.ImplementingInterfaces.Contains(tn)) - { - cnode.ImplementingInterfaces.Add(tn); - } - } + if (cnode.ImplementingInterfaces.Contains(tn)) + continue; + cnode.ImplementingInterfaces.Add(tn); } } diff --git a/bin/Lng/Eng/SemanticErrors_ib.dat b/bin/Lng/Eng/SemanticErrors_ib.dat index ef06d9c97..99ac21375 100644 --- a/bin/Lng/Eng/SemanticErrors_ib.dat +++ b/bin/Lng/Eng/SemanticErrors_ib.dat @@ -139,8 +139,8 @@ OPERATOR_RETURN_TYPE_UNDEFINED_{0}=Return type of operator {0} is not defined an STRUCT_TYPE_DEFINITION_IN_AUTO_CLASS=Field types in auto classes cannot be record or array definition EXTERNAL_METHOD_SHOULD_BE_STATIC=external-methods should be static ABSTRACT_CLASS_CANNOT_BE_SEALED=Abstract classes can not be sealed -ABSTRACT_CLASS_CANNOT_BE_SEALED_BECAUSE_METHOD_NOT_IMPLEMENTED=Class {0} is abstract and connot be sealed, because method {1} not implement -ABSTRACT_CLASS_CANNOT_BE_SEALED_BECAUSE_PROPERTIE_NOT_IMPLEMENTED=Class {0} is abstract and connot be sealed, because propertie {1} not implement +ABSTRACT_CLASS_CANNOT_BE_SEALED_BECAUSE_METHOD_NOT_IMPLEMENTED=Class {0} is abstract and connot be sealed, because method {1} not implemented +ABSTRACT_CLASS_CANNOT_BE_SEALED_BECAUSE_PROPERTIE_NOT_IMPLEMENTED=Class {0} is abstract and connot be sealed, because propertie {1} not implemented ABSTRACT_CLASS_CANNOT_BE_SEALED_BECAUSE_ABSTRACT_PROPERTIE=Class {0} is abstract and connot be sealed, because propertie {1} is abstract EXPRESSION_EXPECTED=Expression expected CLASS_ATTRIBUTE_NOT_ALLOWED_IN_CLASS_PREDEFINTIONS=Can not declare class attributes in class predefintions diff --git a/bin/Lng/Eng/SemanticErrors_ssyy.dat b/bin/Lng/Eng/SemanticErrors_ssyy.dat index 87bd32ec6..5bfe42fac 100644 --- a/bin/Lng/Eng/SemanticErrors_ssyy.dat +++ b/bin/Lng/Eng/SemanticErrors_ssyy.dat @@ -94,6 +94,7 @@ TRIANGLE_BRACKETS_NOT_ALLOWED_WITH_COMMON_FUNCTIONS=Non-generic methods cannot b FUNCTION_{0}_DEPEND_FROM_{1}_TYPE_PARAMS=The number of type parameters in generic subprogramm '{0}' must be {1} WHERE_SECTION_MUST_BE_ONLY_IN_FIRST_DECLARATION=where-section is not valid in this context CAN_NOT_INHERIT_FROM_GENERIC_PARAMETER=Cannot derive from generic parameter +TYPE_{0}_INHERITS_SELF=Type '{0}' inherits from itself GENERIC_FUNCTION_{0}_CAN_NOT_BE_CALLED_WITH_THESE_PARAMETERS=Cannot call the generic function '{0}' with these arguments CAN_NOT_DEDUCE_TYPE_PARAMS_FROM_CALL_{0}=The type arguments for method '{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly CAN_NOT_CALL_ANY_GENERIC_FUNCTION_{0}_WITH_THESE_PARAMETERS=The best overloaded method match for '{0}' has some invalid arguments diff --git a/bin/Lng/Rus/SemanticErrors_ssyy.dat b/bin/Lng/Rus/SemanticErrors_ssyy.dat index c9978e401..8a6ea3cde 100644 --- a/bin/Lng/Rus/SemanticErrors_ssyy.dat +++ b/bin/Lng/Rus/SemanticErrors_ssyy.dat @@ -94,6 +94,7 @@ TRIANGLE_BRACKETS_NOT_ALLOWED_WITH_COMMON_FUNCTIONS=Спецификация п FUNCTION_{0}_DEPEND_FROM_{1}_TYPE_PARAMS=Число типов-параметров в спецификации обобщённой подпрограммы {0} должно быть равно {1} WHERE_SECTION_MUST_BE_ONLY_IN_FIRST_DECLARATION=Секцию where следует указывать только в предописании (предописание найдено) CAN_NOT_INHERIT_FROM_GENERIC_PARAMETER=Нельзя наследовать от generic-параметра +TYPE_{0}_INHERITS_SELF=Тип '{0}' наследует от самого себя GENERIC_FUNCTION_{0}_CAN_NOT_BE_CALLED_WITH_THESE_PARAMETERS=Обобщённая функция {0} не может быть вызвана с данным набором фактических параметров CAN_NOT_DEDUCE_TYPE_PARAMS_FROM_CALL_{0}=Невозможно вывести типы-параметры обобщённой подпрограммы {0} (укажите типы-параметры явно) CAN_NOT_CALL_ANY_GENERIC_FUNCTION_{0}_WITH_THESE_PARAMETERS=С данным списком формальных параметров невозможно вызвать ни одну из перегруженных generic-подпрограмм {0} diff --git a/bin/Lng/Ukr/SemanticErrors_ssyy.dat b/bin/Lng/Ukr/SemanticErrors_ssyy.dat index c77946406..1dcb2abd1 100644 --- a/bin/Lng/Ukr/SemanticErrors_ssyy.dat +++ b/bin/Lng/Ukr/SemanticErrors_ssyy.dat @@ -91,6 +91,7 @@ TRIANGLE_BRACKETS_NOT_ALLOWED_WITH_COMMON_FUNCTIONS=Специфікація з FUNCTION_{0}_DEPEND_FROM_{1}_TYPE_PARAMS=Число типів-параметрів у специфікації generic-підпрограми {0} має дорівнювати {1} WHERE_SECTION_MUST_BE_ONLY_IN_FIRST_DECLARATION=Секцію where слід вказувати тільки в передопису (предопис знайдено) CAN_NOT_INHERIT_FROM_GENERIC_PARAMETER=Не можна успадкувати від generic-параметру +TYPE_{0}_INHERITS_SELF=Тип '{0}' успадковує від себе GENERIC_FUNCTION_{0}_CAN_NOT_BE_CALLED_WITH_THESE_PARAMETERS=Generic-функція {0} не може бути викликана з даними набором фактичних параметрів CAN_NOT_DEDUCE_TYPE_PARAMS_FROM_CALL_{0}=Неможливо вивести типи-параметри generic-підпрограми {0} (вкажіть типи-параметри явно) CAN_NOT_CALL_ANY_GENERIC_FUNCTION_{0}_WITH_THESE_PARAMETERS=З даним списком формальних параметрів неможливо викликати жодну з перевантажених generic-підпрограм {0} From aea94d1df408e18422421ff7358d55d9c51aa82d Mon Sep 17 00:00:00 2001 From: Sun Serega Date: Tue, 27 Sep 2022 18:03:46 +0300 Subject: [PATCH 2/4] Errors and cleanup --- TestSuite/errors/err0512_recursive_inh.pas | 11 +++++++ TestSuite/recursive_where.pas | 32 +++++++++++++++++++ .../TreeConversion/syntax_tree_visitor.cs | 6 ++-- 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 TestSuite/errors/err0512_recursive_inh.pas create mode 100644 TestSuite/recursive_where.pas diff --git a/TestSuite/errors/err0512_recursive_inh.pas b/TestSuite/errors/err0512_recursive_inh.pas new file mode 100644 index 000000000..c91c2d5d3 --- /dev/null +++ b/TestSuite/errors/err0512_recursive_inh.pas @@ -0,0 +1,11 @@ +//!Type 't1' inherits from itself +type + t1 = partial class + + end; + t2 = class(t1) end; + t1 = partial class(t2) + + end; + +begin end. \ No newline at end of file diff --git a/TestSuite/recursive_where.pas b/TestSuite/recursive_where.pas new file mode 100644 index 000000000..bd7c5e504 --- /dev/null +++ b/TestSuite/recursive_where.pas @@ -0,0 +1,32 @@ +// issue#2725 + +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 7dd0a71f0..e9ed59d8d 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -3983,7 +3983,7 @@ namespace PascalABCCompiler.TreeConverter else AddError(get_location(_class_definition), converted_type.AbstractReason.Explanation, converted_type.name, converted_type.AbstractReason.ObjName); } - return; + break; case PascalABCCompiler.SyntaxTree.class_keyword.Record: if (context.CurrentScope is SymbolTable.BlockScope) @@ -4032,7 +4032,7 @@ namespace PascalABCCompiler.TreeConverter }*/ context.leave_record(); return_value(converted_type); - return; + break; //ssyy owns case PascalABCCompiler.SyntaxTree.class_keyword.Interface: if (converted_type.is_value || !converted_type.IsInterface) @@ -4070,7 +4070,7 @@ namespace PascalABCCompiler.TreeConverter } //hard_node_test_and_visit(_class_definition.body); context.leave_block(); - return; + break; //\ssyy owns default: throw new NotSupportedError(get_location(_class_definition)); From ae4ef7034f6feb3083855ef616ff63e0c1719795 Mon Sep 17 00:00:00 2001 From: Sun Serega Date: Tue, 27 Sep 2022 18:29:49 +0300 Subject: [PATCH 3/4] cleanup --- TestSuite/errors/err0369_where.pas | 3 ++- TreeConverter/TreeConversion/syntax_tree_visitor.cs | 2 +- TreeConverter/TreeRealization/generics.cs | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/TestSuite/errors/err0369_where.pas b/TestSuite/errors/err0369_where.pas index 2813c6898..d3c8cb428 100644 --- a/TestSuite/errors/err0369_where.pas +++ b/TestSuite/errors/err0369_where.pas @@ -1,4 +1,5 @@ -type +//!Невозможно инстанцировать, так как тип T не наследован от List +type t1 = class where T: List; diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index e9ed59d8d..dd8b0786e 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -3808,7 +3808,7 @@ namespace PascalABCCompiler.TreeConverter location loc = get_location(syntax_tn); var tn = (type_node)ret.visit(syntax_tn); - if (tn.is_generic_type_definition) need_recheck_where.Add(syntax_tn); + if (tn.is_generic_type_definition || tn.is_generic_type_instance) need_recheck_where.Add(syntax_tn); if ((tn.original_generic??tn).ForwardDeclarationOnly) AddError(loc, "FORWARD_DECLARATION_{0}_AS_BASE_TYPE", tn.PrintableName); diff --git a/TreeConverter/TreeRealization/generics.cs b/TreeConverter/TreeRealization/generics.cs index 997b646c1..9563b61a3 100644 --- a/TreeConverter/TreeRealization/generics.cs +++ b/TreeConverter/TreeRealization/generics.cs @@ -161,7 +161,7 @@ namespace PascalABCCompiler.TreeRealization // tn - не generic параметр - закомментировал if (base_type != tn && !type_table.is_derived(base_type, tn) /*&& !tn.is_generic_parameter*/) { - return new SimpleSemanticError(null, "PARAMETER_{0}_MUST_BE_DERIVED_FROM_{1}", tn.PrintableName, base_type.name); + return new SimpleSemanticError(null, "PARAMETER_{0}_MUST_BE_DERIVED_FROM_{1}", tn.PrintableName, base_type.PrintableName); } } if (gpe.is_class && !tn.is_class) @@ -179,7 +179,7 @@ namespace PascalABCCompiler.TreeRealization (tn.ImplementingInterfaces == null || !type_table.is_derived(di, tn))) { - return new SimpleSemanticError(null, "PARAMETER_{0}_MUST_IMPLEMENT_INTERFACE_{1}", tn.PrintableName, di.name); + return new SimpleSemanticError(null, "PARAMETER_{0}_MUST_IMPLEMENT_INTERFACE_{1}", tn.PrintableName, di.PrintableName); } } if (tn.IsStatic) From 7aafba3d1877bf1adcd6adb1f2b6188afb8975a2 Mon Sep 17 00:00:00 2001 From: Sun Serega Date: Tue, 27 Sep 2022 19:13:34 +0300 Subject: [PATCH 4/4] lang resources --- Localization/DefaultLang.resources | Bin 100748 -> 100600 bytes TestSuite/errors/err0512_recursive_inh.pas | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/DefaultLang.resources b/Localization/DefaultLang.resources index d04cd7526a243b735ab0ed4ec004cbcd08415dcc..38c63eb29e71c2cd4bc903fce83bcddcaffd4dce 100644 GIT binary patch delta 83 zcmV-Z0IdIvlLq*a29V$Z6tUr=O|w!@8NoSJSx`k^doX=pNlr*bQb|-(UsFX)Mm^H# p?;t08FnuQ=?cnk2<>d3_@*wW=Ao1Yr?&Izt@#W$Fw`mXoBY8Y4Do_9b delta 225 zcmew{k*#Mk+k^*gn{^RyTI86Q;+&sXQk0()kW-qTnWvYMSi;Mt8W7~_ z<{6=C%gd#&9|TpZkeHXE098EMpHZSd$kp95IK(w5-qFt`-r3(TB*@<q!lU2s-@ShO q^sNFfmz#f(FQy5+Twn*4=9OgTrf%-^6FxYdQIJt|`x|~no=N~o6=Meg diff --git a/TestSuite/errors/err0512_recursive_inh.pas b/TestSuite/errors/err0512_recursive_inh.pas index c91c2d5d3..bddad2b35 100644 --- a/TestSuite/errors/err0512_recursive_inh.pas +++ b/TestSuite/errors/err0512_recursive_inh.pas @@ -1,4 +1,4 @@ -//!Type 't1' inherits from itself +//!Тип 't1' наследует от самого себя type t1 = partial class