diff --git a/NETGenerator/NETGenerator.cs b/NETGenerator/NETGenerator.cs index 1210a47ea..a02509605 100644 --- a/NETGenerator/NETGenerator.cs +++ b/NETGenerator/NETGenerator.cs @@ -6668,7 +6668,6 @@ namespace PascalABCCompiler.NETGenerator MethodBuilder methb = null; bool is_prop_acc = IsPropertyAccessor(value); MethodAttributes attrs = GetMethodAttributes(value, is_prop_acc); - IRuntimeManagedMethodBody irmmb = value.function_code as IRuntimeManagedMethodBody; if (irmmb != null) { diff --git a/TestSuite/explicitinterface.pas b/TestSuite/explicitinterface.pas new file mode 100644 index 000000000..fe7f3c607 --- /dev/null +++ b/TestSuite/explicitinterface.pas @@ -0,0 +1,30 @@ +type + IEnr = System.Collections.IEnumerator; + IEnb = System.Collections.IEnumerable; + + var a : integer; + type My = class(IEnumerable) + public + function IEnb.GetEnumerator(): IEnr; + begin + a := 1; + end; + function GetEnumerator(): IEnumerator; + begin + a := 2; + end; + + end; + +begin +var ien: IEnb := new My; +ien.GetEnumerator; +assert(a=1); +var ien2: IEnumerable := new My; +ien2.GetEnumerator; +assert(a=2); +a := 0; +var mc := new My; +mc.GetEnumerator(); +assert(a=2); +end. \ No newline at end of file diff --git a/TreeConverter/TreeConversion/compilation_context.cs b/TreeConverter/TreeConversion/compilation_context.cs index 631d67e05..f8235e3fe 100644 --- a/TreeConverter/TreeConversion/compilation_context.cs +++ b/TreeConverter/TreeConversion/compilation_context.cs @@ -164,7 +164,8 @@ namespace PascalABCCompiler.TreeConverter //TODO: Можно сделать возможность объявления вложенных типов. public common_type_node _ctn; // SSM - пытаюсь выходить из класса и входить заново private common_function_node_stack _func_stack=new common_function_node_stack(); - + private type_node _explicit_interface_type; + internal common_function_node_stack func_stack { get @@ -584,7 +585,21 @@ namespace PascalABCCompiler.TreeConverter return (_func_stack.top()); } } - + + public type_node converted_explicit_interface_type + { + get + { + return _explicit_interface_type; + } + //ssyy + set + { + _explicit_interface_type = value; + } + //\ssyy + } + public common_type_node converted_type { get @@ -894,7 +909,22 @@ namespace PascalABCCompiler.TreeConverter public void leave_type_method() { - if (_compiled_tn != null) + if (_explicit_interface_type != null) + { + function_node fn = top_function; + SymbolInfo si = _ctn.Scope.FindOnlyInType(fn.name, null); + function_node compar; + while (si != null) + { + compar = si.sym_info as function_node; + if (fn != compar && convertion_data_and_alghoritms.function_eq_params(fn, compar, false)) + //if (fn is common_namespace_function_node && compar is common_namespace_function_node && (fn as common_namespace_function_node).comprehensive_namespace == (compar as common_namespace_function_node).comprehensive_namespace) + + AddError(new FunctionDuplicateDefinition(compar, fn)); + si = si.Next; + } + } + else if (_compiled_tn != null) { function_node fn = top_function; SymbolInfo si = _compiled_tn.scope.FindOnlyInType(fn.name, null); @@ -909,8 +939,10 @@ namespace PascalABCCompiler.TreeConverter si = si.Next; } } - _ctn = null; + if (_explicit_interface_type == null) + _ctn = null; _compiled_tn = null; + _explicit_interface_type = null; } private readonly System.Collections.Generic.Stack type_stack = new System.Collections.Generic.Stack(); @@ -2701,12 +2733,26 @@ _cmn.types.AddElement(tctn);*/ } } } - + //Проверка типа на наличие функции из интерфейса private void check_implement_function(common_type_node cnode, function_node meth, type_node interf) { //Ищем все функции с нужным именем в типе и его предках SymbolInfo si = cnode.find_in_type(meth.name, cnode.Scope); + SymbolInfo tmp_si = null; + if (meth is compiled_function_node) + tmp_si = cnode.find_in_type((meth as compiled_function_node).cont_type.BaseFullName + "." + meth.name, cnode.Scope); + else if (meth is common_method_node) + tmp_si = cnode.find_in_type((meth as common_method_node).cont_type.BaseFullName + "." + meth.name, cnode.Scope); + if (tmp_si != null) + { + SymbolInfo tmp_si2 = tmp_si; + while (tmp_si2.Next != null) + tmp_si2 = tmp_si2.Next; + tmp_si.Next = si; + si = tmp_si; + } + function_node fn = null; while (si != null) { @@ -2724,7 +2770,7 @@ _cmn.types.AddElement(tctn);*/ { if (fn_common.name != meth.name) { - syntax_tree_visitor.AddError(fn_common.loc, "AMBIGUITY_BETWEEN_NAMES_{0}_AND_{1}" ,fn_common.name, meth.name); + syntax_tree_visitor.AddError(fn_common.loc, "AMBIGUITY_BETWEEN_NAMES_{0}_AND_{1}", fn_common.name, meth.name); } } else @@ -2732,7 +2778,7 @@ _cmn.types.AddElement(tctn);*/ fn_common.SetName(meth.name); fn_common.name_case_fixed = true; } - + } break; } @@ -2781,7 +2827,7 @@ _cmn.types.AddElement(tctn);*/ { AddError(new DerivedFromInterfaceMethodMustBePublicAndNonStatic( cnode.name, interf.name, - Tools.GetFullMethodHeaderString(meth),cnode.is_value_type, cnode.loc)); + Tools.GetFullMethodHeaderString(meth), cnode.is_value_type, cnode.loc)); } //Проверка пройдена! @@ -3022,7 +3068,11 @@ _cmn.types.AddElement(tctn);*/ bool in_unit = false; if (_func_stack.size<=1) { - if (_ctn!=null) + if (_explicit_interface_type != null) + { + si = _explicit_interface_type.find_in_type(fn.name); + } + else if (_ctn!=null) { si=_ctn.Scope.FindOnlyInScope(fn.name); if (_ctn is compiled_generic_instance_type_node && fn is common_namespace_function_node) @@ -3115,7 +3165,17 @@ _cmn.types.AddElement(tctn);*/ AddError(new FunctionDuplicateDefinition(compar, fn)); } else - AddError(new FunctionDuplicateDefinition(compar, fn)); + { + if (fn is common_method_node && compar is common_method_node) + { + common_method_node cmn1 = fn as common_method_node; + common_method_node cmn2 = compar as common_method_node; + if (cmn1.explicit_interface == cmn2.explicit_interface) + AddError(new FunctionDuplicateDefinition(compar, fn)); + } + else + AddError(new FunctionDuplicateDefinition(compar, fn)); + } } si = si.Next; continue; @@ -3349,7 +3409,7 @@ _cmn.types.AddElement(tctn);*/ //si.sym_info=fn; break; } - if (fn is common_method_node && !predef_find && syntax_tree_visitor.current_converted_method_not_in_class_defined) + if (fn is common_method_node && !predef_find && syntax_tree_visitor.current_converted_method_not_in_class_defined && _explicit_interface_type == null) { AddError(new NoMethodInClassWithThisParams(fn as common_method_node, (fn as common_method_node).cont_type, fn.loc)); } diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index e62dcc559..bd7e7ed4f 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -112,7 +112,15 @@ namespace PascalABCCompiler.TreeConverter internal void AddError(location loc, string ErrResourceString, params object[] values) { - ErrorsList.Add(new SimpleSemanticError(loc, ErrResourceString, values)); + Errors.Error err = new SimpleSemanticError(loc, ErrResourceString, values); + if (ThrowCompilationError) + { + throw err; + } + else + { + ErrorsList.Add(err); + } } internal void AddWarning(Errors.CompilerWarning err) @@ -9102,11 +9110,12 @@ namespace PascalABCCompiler.TreeConverter if(is_operator) op=(_method_name.meth_name as SyntaxTree.operator_name_ident).operator_type; _method_name.meth_name = ConvertOperatorNameToIdent(_method_name.meth_name); - + bool explicit_impl = false; if ((context.converting_block() != block_type.namespace_block) && (_method_name.class_name != null)) { - AddError(new OnlyProcedureNameAllowedInClassFunctionDefinition(_method_name.class_name.name, - get_location(_method_name.class_name))); + /*AddError(new OnlyProcedureNameAllowedInClassFunctionDefinition(_method_name.class_name.name, + get_location(_method_name.class_name)));*/ + explicit_impl = true; } if (is_operator && op==SyntaxTree.Operators.AddressOf && SemanticRules.AddressOfOperatorNonOverloaded) { @@ -9123,7 +9132,22 @@ namespace PascalABCCompiler.TreeConverter { num_template_args = ttn.template_args.idents.Count; } + common_type_node current_conv_type = context.converted_type; def_temp = context.enter_in_type_method(_method_name, _method_name.class_name.name, loc_type_name, num_template_args); + if (explicit_impl) + { + context.converted_type = current_conv_type; + if (def_temp is type_node && (def_temp as type_node).IsInterface) + { + context.converted_explicit_interface_type = def_temp as type_node; + SymbolInfo si = context.converted_explicit_interface_type.find_in_type(_method_name.meth_name.name); + if (si == null) + AddError(new UndefinedNameReference(_method_name.meth_name.name, get_location(_method_name.meth_name))); + } + else + AddError(new OnlyProcedureNameAllowedInClassFunctionDefinition(_method_name.class_name.name, + get_location(_method_name.class_name))); + } tp = def_temp as common_type_node; template_class tc = def_temp as template_class; //SyntaxTree.template_type_name ttn = _method_name.class_name as SyntaxTree.template_type_name; @@ -9256,7 +9280,12 @@ namespace PascalABCCompiler.TreeConverter if (current_function_header != null && current_function_header.proc_attributes != null && has_extensionmethod_attr(current_function_header.proc_attributes.proc_attributes)) context.create_function(_method_name.meth_name.name, loc_name, false); else - context.create_function(_method_name.meth_name.name, loc_name); + { + if (!explicit_impl) + context.create_function(_method_name.meth_name.name, loc_name); + else + context.create_function(context.converted_explicit_interface_type.BaseFullName+"."+_method_name.meth_name.name, loc_name); + } } context.extension_method = false; context.top_function.IsOperator = is_operator; @@ -11242,6 +11271,7 @@ namespace PascalABCCompiler.TreeConverter hard_node_test_and_visit(_procedure_definition.proc_header); } //\lroman// + //ssyy if (context.converted_template_type != null) @@ -11260,6 +11290,8 @@ namespace PascalABCCompiler.TreeConverter { return; } + if (context.converted_explicit_interface_type != null) + (context.top_function as common_method_node).explicit_interface = context.converted_explicit_interface_type; if (has_dll_import_attribute(context.top_function)) { if (_procedure_definition.proc_body != null) @@ -18506,6 +18538,8 @@ namespace PascalABCCompiler.TreeConverter public override void visit(SyntaxTree.same_type_node st) // SSM 22/06/13 { expression_node en = convert_strong(st.ex); + if (en == null) + AddError(get_location(st.ex),"CANNOT_EVALUATE_FUNCTION_TYPE"); return_value(en.type); } diff --git a/TreeConverter/TreeRealization/functions.cs b/TreeConverter/TreeRealization/functions.cs index d7772423b..773b3a09f 100644 --- a/TreeConverter/TreeRealization/functions.cs +++ b/TreeConverter/TreeRealization/functions.cs @@ -1283,6 +1283,7 @@ namespace PascalABCCompiler.TreeRealization private SemanticTree.field_access_level _field_access_level; private SemanticTree.polymorphic_state _polymorphic_state; + private type_node _explicit_interface; private bool _is_constructor; public bool first_statement = true; public bool inherited_ctor_called = false; @@ -1290,6 +1291,18 @@ namespace PascalABCCompiler.TreeRealization private bool _is_final = false; + public type_node explicit_interface + { + get + { + return _explicit_interface; + } + set + { + _explicit_interface = value; + } + } + public bool IsStatic { get @@ -1597,6 +1610,7 @@ namespace PascalABCCompiler.TreeRealization private int _num_of_default_parameters; private bool _is_extension_method=false; private compiled_type_node connected_to_type; + private List _generic_params; private static System.Collections.Generic.Dictionary compiled_methods = new System.Collections.Generic.Dictionary(); diff --git a/TreeConverter/TreeRealization/types.cs b/TreeConverter/TreeRealization/types.cs index 611e19e94..902abe2a2 100644 --- a/TreeConverter/TreeRealization/types.cs +++ b/TreeConverter/TreeRealization/types.cs @@ -342,6 +342,14 @@ namespace PascalABCCompiler.TreeRealization } } + public virtual string BaseFullName + { + get + { + return full_name; + } + } + /// /// Свойство по умолчанию. /// @@ -1732,6 +1740,14 @@ namespace PascalABCCompiler.TreeRealization } } + public override string BaseFullName + { + get + { + return this.comprehensive_namespace.namespace_full_name + "." + name; + } + } + public override string PrintableName { get @@ -3451,6 +3467,17 @@ namespace PascalABCCompiler.TreeRealization return base.PrintableName; } } + + public override string BaseFullName + { + get + { + Type t = _compiled_type; + if (t.IsGenericType) + t = t.GetGenericTypeDefinition(); + return t.FullName; + } + } } [Serializable] diff --git a/bin/Lng/Eng/SemanticErrors_ib.dat b/bin/Lng/Eng/SemanticErrors_ib.dat index 698e57439..927026f55 100644 --- a/bin/Lng/Eng/SemanticErrors_ib.dat +++ b/bin/Lng/Eng/SemanticErrors_ib.dat @@ -110,6 +110,8 @@ ILLEGAL_LAMBDA_PARAMETERS_NUMBER=Illegal lambda parameters number IMPOSSIBLE_TO_INFER_TYPES_IN_LAMBDA=Unable to infer types in lambda ANONYMOUS_DELEGATE_IN_INTERFACE_NOT_ALLOWED=Using of anonymous delegate in interface is not allowed. Declare the delegate type explicitly. PARAMETER_REFERENCE_IN_DEFAULT_PARAMETER_NOT_ALLOWED=Parameter references in default parameter value are not allowed +CANNOT_EVALUATE_FUNCTION_TYPE=Cannot infer the return type of function +TYPE_NAME_EXPECTED=Type name expected %PREFIX%=COMPILATIONERROR_ UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Unit expected, library found ASSEMBLY_{0}_READING_ERROR=Error by reading assembly '{0}' diff --git a/bin/Lng/Rus/SemanticErrors_ib.dat b/bin/Lng/Rus/SemanticErrors_ib.dat index ba7937fc3..1fc87b7c9 100644 --- a/bin/Lng/Rus/SemanticErrors_ib.dat +++ b/bin/Lng/Rus/SemanticErrors_ib.dat @@ -105,6 +105,8 @@ FIRST_PARAMETER_MUST_HAVE_NAME_SELF=Первый параметр должен EXTENSION_METHODS_FOR_CONSTRUCTED_TYPES_NOT_ALLOWED=Нельзя расширять этот тип EXTENSION_METHODS_IN_INTERFACE_PART_NOT_ALLOWED=Объявление extension-методов в интерфейсной части модуля недопустимо OPERATOR_SHOULD_BE_EXTENSION_METHOD=Оператор должен быть помечен модификатором extensionmethod +CANNOT_EVALUATE_FUNCTION_TYPE=Невозможно вывести тип функции +TYPE_NAME_EXPECTED=Ожидался тип %PREFIX%=COMPILATIONERROR_ UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Ожидался модуль, а встречена библиотека ASSEMBLY_{0}_READING_ERROR=Ошибка при чтении сборки '{0}'