diff --git a/CodeCompletion/DomSyntaxTreeVisitor.cs b/CodeCompletion/DomSyntaxTreeVisitor.cs index a09536f0d..7ffbc04ca 100644 --- a/CodeCompletion/DomSyntaxTreeVisitor.cs +++ b/CodeCompletion/DomSyntaxTreeVisitor.cs @@ -899,7 +899,10 @@ public override void visit(procedure_header _procedure_header) ps.proc_realization = pr; pr.loc = cur_loc; pr.head_loc = loc; - this.entry_scope.AddName("$method", pr); + if (impl_scope != null) + impl_scope.AddName("$method", pr); + else + this.entry_scope.AddName("$method", pr); } ps.head_loc = loc; if (!ps.is_extension) @@ -1183,7 +1186,10 @@ public override void visit(function_header _function_header) ps.proc_realization = pr; pr.loc = cur_loc; pr.head_loc = loc; - this.entry_scope.AddName("$method",pr); + if (impl_scope != null) + impl_scope.AddName("$method", pr); + else + this.entry_scope.AddName("$method", pr); } if (!ps.is_extension) { @@ -3634,6 +3640,7 @@ public override void visit(new_expr _new_expr) (returned_scope as ArrayScope).is_dynamic_arr = true; } save_return_value(); + if (_new_expr.params_list != null) foreach (expression ex in _new_expr.params_list.expressions) { if (ex is function_lambda_definition) diff --git a/SyntaxTree/tree/TreeHelper.cs b/SyntaxTree/tree/TreeHelper.cs index 12df58177..f04b5937c 100644 --- a/SyntaxTree/tree/TreeHelper.cs +++ b/SyntaxTree/tree/TreeHelper.cs @@ -704,8 +704,10 @@ public procedure_header(formal_parameters _parameters, procedure_attributes_list { var t = name.meth_name as template_type_name; template_args = t.template_args; - ident id = new ident(name.meth_name.name, name.meth_name.source_context); - name.meth_name = id; + if (name.meth_name is template_operator_name) + name.meth_name = new operator_name_ident((name.meth_name as template_operator_name).opname.operator_type, name.meth_name.source_context); + else + name.meth_name = new ident(name.meth_name.name, name.meth_name.source_context); } } diff --git a/TestSuite/CompilationSamples/PABCSystem.pas b/TestSuite/CompilationSamples/PABCSystem.pas index 17a446e43..cbcbb72f8 100644 --- a/TestSuite/CompilationSamples/PABCSystem.pas +++ b/TestSuite/CompilationSamples/PABCSystem.pas @@ -3127,6 +3127,14 @@ function System.Collections.Generic.IEnumerable.operator*(n: integer; a: sequ Result := a*n; end; +/// +function operator+(a, b: array of T): array of T; extensionmethod; +begin + Result := new T[a.Length+b.Length]; + a.CopyTo(Result,0); + b.CopyTo(Result,a.Length); +end; + // ----------------------------------------------------- // Sequences // ----------------------------------------------------- diff --git a/TestSuite/extensionmethods11.pas b/TestSuite/extensionmethods11.pas new file mode 100644 index 000000000..509d1e9bd --- /dev/null +++ b/TestSuite/extensionmethods11.pas @@ -0,0 +1,12 @@ +begin + var arr1 := Arr(1,2,3); + var arr2 := Arr(4,5,6); + var arr3: array of integer := arr1+arr2; + assert(arr3[3]=4); + var arr4 := Arr('aaa','bbb','ccc'); + var arr5 := Arr('ddd','eee','fff'); + var arr6: array of string; + arr6 := arr4 + arr5; + assert(arr6[5]='fff'); + +end. \ No newline at end of file diff --git a/TreeConverter/NetWrappers/NetHelper.cs b/TreeConverter/NetWrappers/NetHelper.cs index 4a4f3d836..ef2771964 100644 --- a/TreeConverter/NetWrappers/NetHelper.cs +++ b/TreeConverter/NetWrappers/NetHelper.cs @@ -294,6 +294,8 @@ public static class NetHelper { public static Assembly SystemCoreAssembly; private static Dictionary extension_methods = new Dictionary(); private static Dictionary> type_extensions = new Dictionary>(); + private static Dictionary arrays_with_extension_methods = new Dictionary(); + private static Dictionary> generic_array_type_extensions = new Dictionary>(); public static Type PABCSystemType = null; public static Type PT4Type = null; public static Type StringType = typeof(string); @@ -302,7 +304,9 @@ public static class NetHelper { public static void reset() { - cur_used_assemblies.Clear(); + if (cur_used_assemblies == null) + cur_used_assemblies = new Hashtable(); + cur_used_assemblies.Clear(); cur_used_assemblies[typeof(string).Assembly] = typeof(string).Assembly; cur_used_assemblies[typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly] = typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly; type_search_cache.Clear(); @@ -499,15 +503,59 @@ public static List init_namespaces(System.Reflection.Assembly _assembly) { List mths = null; + List mths2 = null; Type tmp = prms[0].ParameterType; + bool generic_type = false; if (tmp.IsGenericType) + { tmp = tmp.GetGenericTypeDefinition(); + generic_type = true; + } if (!type_extensions.TryGetValue(tmp, out mths)) { mths = new List(); type_extensions.Add(tmp, mths); } mths.Add(mi); + if (tmp.IsArray && !generic_array_type_extensions.TryGetValue(tmp.GetArrayRank(), out mths2)) + { + mths2 = new List(); + generic_array_type_extensions.Add(tmp.GetArrayRank(), mths2); + } + if (mths2 != null) + mths2.Add(mi); + Dictionary> mht; + if (members.TryGetValue(tmp, out mht)) + { + List mis2 = null; + string name = compiler_string_consts.GetNETOperName(mi.Name); + if (name == null) + name = mi.Name; + if (!mht.TryGetValue(name, out mis2)) + { + mis2 = new List(); + mht.Add(name, mis2); + } + if (!mis2.Contains(mi)) + mis2.Add(mi); + } + foreach (Type arr_t in arrays_with_extension_methods.Keys) + { + if (members.TryGetValue(arr_t, out mht)) + { + List mis2 = null; + string name = compiler_string_consts.GetNETOperName(mi.Name); + if (name == null) + name = mi.Name; + if (!mht.TryGetValue(name, out mis2)) + { + mis2 = new List(); + mht.Add(name, mis2); + } + if (!mis2.Contains(mi)) + mis2.Add(mi); + } + } } } extension_methods.Add(t, ext_meths.ToArray()); @@ -1110,20 +1158,27 @@ public static List GetMembers(Type t, string name) { List meths = null; Type tmp_t = t; + if (tmp_t.IsArray) + arrays_with_extension_methods[tmp_t] = tmp_t; cached_type_extensions[t] = t; while (tmp_t != null) { - if (type_extensions.TryGetValue(tmp_t, out meths) || tmp_t.IsGenericType && type_extensions.TryGetValue(tmp_t.GetGenericTypeDefinition(), out meths)) + if (type_extensions.TryGetValue(tmp_t, out meths) + || tmp_t.IsGenericType && type_extensions.TryGetValue(tmp_t.GetGenericTypeDefinition(), out meths) + || tmp_t.IsArray && generic_array_type_extensions.TryGetValue(tmp_t.GetArrayRank(), out meths)) { foreach (MethodInfo mi in meths) { if (cur_used_assemblies.ContainsKey(mi.DeclaringType.Assembly)) { List al = null; - if (!ht.TryGetValue(mi.Name, out al)) + string s = compiler_string_consts.GetNETOperName(mi.Name); + if (s == null) + s = mi.Name; + if (!ht.TryGetValue(s, out al)) { al = new List(); - ht[mi.Name] = al; + ht[s] = al; } al.Insert(0, mi); } @@ -1364,6 +1419,7 @@ public static SymbolInfo FindName(Type t, string name) if (name == null) return null; if (name == compiler_string_consts.assign_name) return null; string s = compiler_string_consts.GetNETOperName(name); + string tmp_name = name; if (s != null) { if (IsStandType(t)) return null; @@ -1373,7 +1429,6 @@ public static SymbolInfo FindName(Type t, string name) SymbolInfo si=null; List mis = GetMembers(t,name); - //(ssyy) . // , // (, - ). , diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index cb9955e17..da4bab5c7 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -8965,7 +8965,7 @@ private void visit_method_name(SyntaxTree.method_name _method_name) } else { - if (is_operator && context.converted_type == null && context.converted_template_type == null) + if (is_operator && context.converted_type == null && context.converted_template_type == null && !(current_function_header != null && current_function_header.template_args != null && current_function_header.template_args.idents.Count > 0)) { AddError(get_location(_method_name), "OVERLOADED_OPERATOR_MUST_BE_STATIC_FUNCTION"); } @@ -11209,9 +11209,13 @@ internal void CheckOverrideOrReintroduceExpectedWarning(location loc) } } + private procedure_header current_function_header = null; + public override void visit(SyntaxTree.function_header _function_header) { + current_function_header = _function_header; hard_node_test_and_visit(_function_header.name); + current_function_header = null; if (context.converted_template_type != null) { return; @@ -11337,9 +11341,11 @@ public override void visit(SyntaxTree.function_header _function_header) type_node ptn = p.type; if (ptn.is_generic_type_instance) ptn = ptn.original_generic; - if (ptn == cnfn.ConnectedToType) + if (ptn == cnfn.ConnectedToType || ptn == cnfn.ConnectedToType.original_generic) has_types = true; } + if (cnfn.ConnectedToType == null) + AddError(new SimpleSemanticError(cnfn.loc, "OPERATOR_SHOULD_BE_EXTENSION_METHOD")); if (!has_types) AddError(new SimpleSemanticError(cnfn.loc, "LEAST_ONE_PARAMETER_TYPE_SHOULD_EQ_DECLARING_TYPE_{0}",cnfn.ConnectedToType.name)); } @@ -11462,7 +11468,9 @@ private void visit_procedure_header(SyntaxTree.procedure_header _procedure_heade { AddError(get_location(_procedure_header), "CONSTRUCTOR_CAN_NOT_BE_GENERIC"); } + current_function_header = _procedure_header; hard_node_test_and_visit(_procedure_header.name); + current_function_header = null; if (context.converted_template_type != null) { return; @@ -11822,9 +11830,9 @@ public override void visit(SyntaxTree.procedure_attributes_list _procedure_attri AddError(get_location(_procedure_attributes_list), "EXTENSION_ATTRIBUTE_ONLY_FOR_NAMESPACE_FUNCTIONS_ALLOWED"); if (context.top_function.parameters.Count == 0) AddError(context.top_function.loc, "EXTENSION_METHODS_MUST_HAVE_LEAST_ONE_PARAMETER"); - if (context.top_function.parameters[0].parameter_type != SemanticTree.parameter_type.value) + if (!context.top_function.IsOperator && context.top_function.parameters[0].parameter_type != SemanticTree.parameter_type.value) AddError(context.top_function.loc, "FIRST_PARAMETER_SHOULDBE_ONLY_VALUE_PARAMETER"); - if (context.top_function.parameters[0].name.ToLower() != compiler_string_consts.self_word) + if (!context.top_function.IsOperator && context.top_function.parameters[0].name.ToLower() != compiler_string_consts.self_word) AddError(context.top_function.loc,"FIRST_PARAMETER_MUST_HAVE_NAME_SELF"); common_namespace_function_node top_function = context.top_function as common_namespace_function_node; top_function.ConnectedToType = context.top_function.parameters[0].type; diff --git a/bin/Lib/PABCSystem.pas b/bin/Lib/PABCSystem.pas index 17a446e43..cbcbb72f8 100644 --- a/bin/Lib/PABCSystem.pas +++ b/bin/Lib/PABCSystem.pas @@ -3127,6 +3127,14 @@ function System.Collections.Generic.IEnumerable.operator*(n: integer; a: sequ Result := a*n; end; +/// +function operator+(a, b: array of T): array of T; extensionmethod; +begin + Result := new T[a.Length+b.Length]; + a.CopyTo(Result,0); + b.CopyTo(Result,a.Length); +end; + // ----------------------------------------------------- // Sequences // ----------------------------------------------------- diff --git a/bin/Lng/Eng/SemanticErrors_ib.dat b/bin/Lng/Eng/SemanticErrors_ib.dat index ba6efd272..4cadcdc69 100644 --- a/bin/Lng/Eng/SemanticErrors_ib.dat +++ b/bin/Lng/Eng/SemanticErrors_ib.dat @@ -100,13 +100,14 @@ FIRST_PARAMETER_SHOULDBE_ONLY_VALUE_PARAMETER=var and const are not allowed for FIRST_PARAMETER_MUST_HAVE_NAME_SELF=Parameter with 'name' self expected EXTENSION_METHODS_FOR_CONSTRUCTED_TYPES_NOT_ALLOWED=Cannot extend this type EXTENSION_METHODS_IN_INTERFACE_PART_NOT_ALLOWED=Cannot declare extension methods in interface part of unit +OPERATOR_SHOULD_BE_EXTENSION_METHOD=Operator should be extension method +UNABLE_TO_CONVERT_FUNCTIONAL_TYPE_TO_PROCEDURAL_TYPE=Unable to convert functional type to procedural type +ILLEGAL_PARAMETERS_IN_LAMBDA=Illegal parameters in lambda +ILLEGAL_LAMBDA_VARIABLE_TYPE=Illegal lambda variable type +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 %PREFIX%=COMPILATIONERROR_ UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Unit expected, library found -ASSEMBLY_{0}_READING_ERROR=Error by reading assembly '{0}' -UNABLE_TO_CONVERT_FUNCTIONAL_TYPE_TO_PROCEDURAL_TYPE="Unable to convert functional type to procedural type" -ILLEGAL_PARAMETERS_IN_LAMBDA="Illegal parameters in lambda" -ILLEGAL_LAMBDA_VARIABLE_TYPE="Illegal lambda variable type" -ILLEGAL_LAMBDA_PARAMETERS_NUMBER="Illegal lambda parameters number" -IMPOSSIBLE_TO_INFER_TYPES_IN_LAMBDA="Impossible 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 \ No newline at end of file +ASSEMBLY_{0}_READING_ERROR=Error by reading assembly '{0}' \ No newline at end of file diff --git a/bin/Lng/Rus/SemanticErrors_ib.dat b/bin/Lng/Rus/SemanticErrors_ib.dat index 20e9d4fc8..72d2a5c45 100644 --- a/bin/Lng/Rus/SemanticErrors_ib.dat +++ b/bin/Lng/Rus/SemanticErrors_ib.dat @@ -102,6 +102,7 @@ FIRST_PARAMETER_SHOULDBE_ONLY_VALUE_PARAMETER=Недопустимо испол FIRST_PARAMETER_MUST_HAVE_NAME_SELF=Первый параметр должен иметь имя self EXTENSION_METHODS_FOR_CONSTRUCTED_TYPES_NOT_ALLOWED=Нельзя расширять этот тип EXTENSION_METHODS_IN_INTERFACE_PART_NOT_ALLOWED=Объявление extension-методов в интерфейсной части модуля недопустимо +OPERATOR_SHOULD_BE_EXTENSION_METHOD=Оператор должен быть помечен модификатором extensionmethod %PREFIX%=COMPILATIONERROR_ UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Ожидался модуль, а встречена библиотека ASSEMBLY_{0}_READING_ERROR=Ошибка при чтении сборки '{0}' \ No newline at end of file