diff --git a/Compiler/PCU/PCUReader.cs b/Compiler/PCU/PCUReader.cs index 8f65d4e06..74b5b936a 100644 --- a/Compiler/PCU/PCUReader.cs +++ b/Compiler/PCU/PCUReader.cs @@ -2802,6 +2802,8 @@ namespace PascalABCCompiler.PCU cnfn.ConnectedToType.base_type.Scope.AddSymbol(cnfn.name, new SymbolInfo(cnfn)); else if (cnfn.ConnectedToType != null && cnfn.ConnectedToType.is_generic_parameter) cnfn.ConnectedToType.base_type.Scope.AddSymbol(cnfn.name, new SymbolInfo(cnfn)); + else if (cnfn.ConnectedToType is compiled_generic_instance_type_node && cnfn.ConnectedToType.original_generic.Scope != null) + cnfn.ConnectedToType.original_generic.Scope.AddSymbol(cnfn.name, new SymbolInfo(cnfn)); return cnfn; } @@ -2902,6 +2904,8 @@ namespace PascalABCCompiler.PCU cnfn.ConnectedToType.base_type.Scope.AddSymbol(cnfn.name, new SymbolInfo(cnfn)); else if (cnfn.ConnectedToType != null && cnfn.ConnectedToType.is_generic_parameter) cnfn.ConnectedToType.base_type.Scope.AddSymbol(cnfn.name, new SymbolInfo(cnfn)); + else if (cnfn.ConnectedToType is compiled_generic_instance_type_node && cnfn.ConnectedToType.original_generic.Scope != null) + cnfn.ConnectedToType.original_generic.Scope.AddSymbol(cnfn.name, new SymbolInfo(cnfn)); br.BaseStream.Seek(pos,SeekOrigin.Begin); return cnfn; } diff --git a/TestSuite/extensionmethods15.pas b/TestSuite/extensionmethods15.pas new file mode 100644 index 000000000..47a94c574 --- /dev/null +++ b/TestSuite/extensionmethods15.pas @@ -0,0 +1,12 @@ +function operator* (Self: (T1,T2); v: T3): (T1,T2,T3); extensionmethod; +begin + Result := (Self[0],Self[1],v); +end; + +begin + var t0 := (1,2); + var t1 := t0 * System.DateTime.Now.DayOfWeek; + assert(t1.Item3 = System.DateTime.Now.DayOfWeek); + var s := 4+Seq(1,2,3); + assert(s.ToArray()[0]=4); +end. \ No newline at end of file diff --git a/TestSuite/in1.pas b/TestSuite/in1.pas new file mode 100644 index 000000000..fbe469008 --- /dev/null +++ b/TestSuite/in1.pas @@ -0,0 +1,9 @@ +begin + var arr := Arr(1,2,3); + assert(5 in arr = false); + assert(2 in arr = true); + var l := new List(); + l += 4; + l += 5; + assert(4 in l = true); +end. \ No newline at end of file diff --git a/TestSuite/overloads3.pas b/TestSuite/overloads3.pas index 19132b7ee..c71dd2786 100644 --- a/TestSuite/overloads3.pas +++ b/TestSuite/overloads3.pas @@ -1,5 +1,5 @@ begin - {var b: byte := 2; + var b: byte := 2; var i: integer := 3; var s: shortint := 4; var w: word := 5; @@ -12,5 +12,5 @@ begin assert(min(b,lw)=2); assert(min(i,lw)=3); assert(min(b,i64)=2); - assert(min(i64,ui64)=7);} + assert(min(i64,ui64)=7); end. \ No newline at end of file diff --git a/TestSuite/overloads4.pas b/TestSuite/overloads4.pas new file mode 100644 index 000000000..161619261 --- /dev/null +++ b/TestSuite/overloads4.pas @@ -0,0 +1,29 @@ +var a: integer; +procedure Test(p: integer); +begin + a := 1; +end; +procedure Test(p: T); +begin + a := 2; +end; +procedure Test(params p: array of integer); +begin + a := 3; +end; +procedure Test(params p: array of T); +begin + a := 4; +end; +begin + Test(3); + assert(a = 1); + Test('a'); + assert(a = 2); + Test(byte(3)); + assert(a = 2); + Test(1,2); + assert(a = 3); + Test('a','b'); + assert(a = 4); +end. \ No newline at end of file diff --git a/TestSuite/params8.pas b/TestSuite/params8.pas new file mode 100644 index 000000000..7bcd672ad --- /dev/null +++ b/TestSuite/params8.pas @@ -0,0 +1,8 @@ +function Test(a: T): sequence of T; +begin + Result := Seq(a); +end; + +begin + assert(Test(2).ToArray()[0]=2); +end. \ No newline at end of file diff --git a/TestSuite/stringfunctions1.pas b/TestSuite/stringfunctions1.pas index 4c4695941..992d9aa7d 100644 --- a/TestSuite/stringfunctions1.pas +++ b/TestSuite/stringfunctions1.pas @@ -51,4 +51,7 @@ begin assert(StrToInt('234')=234); assert(StrToFloat('2.67')=2.67); assert(IntToStr(45)='45'); + var c: char := 'a'; + var o: object := 'bc'; + assert(c+o='abc'); end. \ No newline at end of file diff --git a/TestSuite/units/u_extensionmethods15.pas b/TestSuite/units/u_extensionmethods15.pas new file mode 100644 index 000000000..6ff7cb13e --- /dev/null +++ b/TestSuite/units/u_extensionmethods15.pas @@ -0,0 +1,13 @@ +unit u_extensionmethods15; +function operator* (Self: (T1,T2); v: T3): (T1,T2,T3); extensionmethod; +begin + Result := (Self[0],Self[1],v); +end; + +begin + var t0 := (1,2); + var t1 := t0 * System.DateTime.Now.DayOfWeek; + assert(t1.Item3 = System.DateTime.Now.DayOfWeek); + var s := 4+Seq(1,2,3); + assert(s.ToArray()[0]=4); +end. \ No newline at end of file diff --git a/TestSuite/units/u_extensionmethods4.pas b/TestSuite/units/u_extensionmethods4.pas new file mode 100644 index 000000000..f30106b33 --- /dev/null +++ b/TestSuite/units/u_extensionmethods4.pas @@ -0,0 +1,31 @@ +unit u_extensionmethods4; +function string.ToInt2: integer; +begin + Result := integer.Parse(Self); +end; + +function string.ToWords2(params delim: array of char): array of string; +begin + Result := Self.Split(delim,System.StringSplitOptions.RemoveEmptyEntries); +end; + +begin + var s := '123'; + //assert(s.ToInt = 123); + var i := s.ToInt2; + assert(i=123); + s := '222'; + i := s.ToInt2; + assert(i=222); + s := '111'; + i := s.ToInt2(); + assert(i=111); + s := 'abc def'; + var arr := s.ToWords2; + assert(arr[0]='abc'); + arr := 'ttt xxx'.ToWords2; + assert(arr[1] = 'xxx'); + s := 'p p p'; + foreach c: string in s.ToWords2 do + assert(c = 'p'); +end. \ No newline at end of file diff --git a/TestSuite/units/u_nested_lambdas_1.pas b/TestSuite/units/u_nested_lambdas_1.pas new file mode 100644 index 000000000..20be7d60a --- /dev/null +++ b/TestSuite/units/u_nested_lambdas_1.pas @@ -0,0 +1,24 @@ +unit u_nested_lambdas_1; +procedure p(f: Func>); +begin + +end; + +procedure p(f: Func>); +begin + var res := f(3).ToList(); + assert(res.Count = 4); + assert(res[0] = 0); + assert(res[1] = 1); + assert(res[2] = 4); + assert(res[3] = 9); +end; + +procedure Test; +begin + p(x -> Range(0, x).Select(y -> y * y)); +end; + +begin + Test; +end. \ No newline at end of file diff --git a/TestSuite/usesunits/use_extensionmethods15.pas b/TestSuite/usesunits/use_extensionmethods15.pas new file mode 100644 index 000000000..ca5850452 --- /dev/null +++ b/TestSuite/usesunits/use_extensionmethods15.pas @@ -0,0 +1,3 @@ +uses u_extensionmethods15; +begin +end. \ No newline at end of file diff --git a/TestSuite/usesunits/use_extensionmethods4.pas b/TestSuite/usesunits/use_extensionmethods4.pas new file mode 100644 index 000000000..9d99d30e9 --- /dev/null +++ b/TestSuite/usesunits/use_extensionmethods4.pas @@ -0,0 +1,4 @@ +uses u_extensionmethods4; +begin + +end. \ No newline at end of file diff --git a/TestSuite/usesunits/use_nested_lambdas_1.pas b/TestSuite/usesunits/use_nested_lambdas_1.pas new file mode 100644 index 000000000..a0c52d9ce --- /dev/null +++ b/TestSuite/usesunits/use_nested_lambdas_1.pas @@ -0,0 +1,4 @@ +uses u_nested_lambdas_1; +begin + +end. \ No newline at end of file diff --git a/TreeConverter/NetWrappers/NetHelper.cs b/TreeConverter/NetWrappers/NetHelper.cs index a9b314d38..190824b06 100644 --- a/TreeConverter/NetWrappers/NetHelper.cs +++ b/TreeConverter/NetWrappers/NetHelper.cs @@ -295,7 +295,9 @@ namespace PascalABCCompiler.NetHelper 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 generics_with_extension_methods = new Dictionary(); private static Dictionary> generic_array_type_extensions = new Dictionary>(); + private static List generic_parameter_type_extensions = new List(); public static Type PABCSystemType = null; public static Type PT4Type = null; public static Type StringType = typeof(string); @@ -522,6 +524,7 @@ namespace PascalABCCompiler.NetHelper } if (mths2 != null) mths2.Add(mi); + Dictionary> mht; if (members.TryGetValue(tmp, out mht)) { @@ -537,6 +540,28 @@ namespace PascalABCCompiler.NetHelper if (!mis2.Contains(mi)) mis2.Add(mi); } + if (tmp.IsGenericParameter && !generic_parameter_type_extensions.Contains(mi)) + { + generic_parameter_type_extensions.Add(mi); + foreach (Type tt in members.Keys) + { + if (members.TryGetValue(tt, 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)) @@ -554,6 +579,24 @@ namespace PascalABCCompiler.NetHelper mis2.Add(mi); } } + + foreach (Type gen_t in generics_with_extension_methods.Keys) + { + if (members.TryGetValue(gen_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()); @@ -1077,11 +1120,6 @@ namespace PascalABCCompiler.NetHelper } } - //public static void AddMembersOfInterfaceToList(Type t, BindingFlags bf, List mem_info) - //{ - // - //} - public static bool IsExtensionMethod(MethodInfo mi) { if (ExtensionAttributeType != null && mi.GetCustomAttributes(ExtensionAttributeType, false).Length > 0) @@ -1104,16 +1142,6 @@ namespace PascalABCCompiler.NetHelper } else { - //(ssyy) Забираем также и не public члены - //(ds) добавил BindingFlags.FlattenHierarchy - //(ssyy) убрал BindingFlags.FlattenHierarchy. Зачем оно было нужно? :) - //(ds) добавил BindingFlags.FlattenHierarchy, затем что: - //Ваня Бондарев (00:52:19 16/12/2007) - //BindingFlags.FlattenHierarchy eto flag kotoryj ukazyvaet, chto chleny - //tipa nado brat' ne tolko iz samogo tipa, no i ego bazovyh klassov - //t.GetMembers(BindingFlags.FlattenHierarchy) naprimer. Dlja vybora staticheskih - //chlenov eto objazatelno. - //Без этого не работает пример BindingFlags bf = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic; MemberInfo[] mis; if (t.IsInterface) @@ -1146,20 +1174,36 @@ namespace PascalABCCompiler.NetHelper { ht[mi.Name].Add(mi); } - if (ExtensionAttributeType != null /*&& t != StringType*/ && cur_used_assemblies.ContainsKey(SystemCoreAssembly)) + if (ExtensionAttributeType != null) { List meths = null; Type tmp_t = t; if (tmp_t.IsArray) arrays_with_extension_methods[tmp_t] = tmp_t; + if (tmp_t.IsGenericTypeDefinition) + generics_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) - || tmp_t.IsArray && generic_array_type_extensions.TryGetValue(tmp_t.GetArrayRank(), out meths)) + List meths1 = null; + List meths2 = null; + List meths3 = generic_parameter_type_extensions; + if (tmp_t.IsGenericType && !tmp_t.IsGenericTypeDefinition) + type_extensions.TryGetValue(tmp_t.GetGenericTypeDefinition(), out meths1); + if (tmp_t.IsArray) + generic_array_type_extensions.TryGetValue(tmp_t.GetArrayRank(), out meths2); + if (type_extensions.TryGetValue(tmp_t, out meths) || meths1 != null || meths2 != null || meths3 != null) { - foreach (MethodInfo mi in meths) + List all_meths = new List(); + if (meths != null) + all_meths.AddRange(meths); + if (meths1 != null) + all_meths.AddRange(meths1); + if (meths2 != null) + all_meths.AddRange(meths2); + if (meths3 != null) + all_meths.AddRange(meths3); + foreach (MethodInfo mi in all_meths) { if (cur_used_assemblies.ContainsKey(mi.DeclaringType.Assembly)) { diff --git a/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs b/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs index c2f1c5ae5..3a27be3f6 100644 --- a/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs +++ b/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs @@ -1997,61 +1997,6 @@ namespace PascalABCCompiler.TreeConverter } - // TODO: Исправить этот алгоритм, сделав каждый с каждым - вроде исправил - см. выше - /*j = 1; - while(j> distances = new SortedDictionary>(); + foreach (function_node fn in set_of_possible_functions) + { + int distance = 0; + for (int i = 0; i < parameters.Count; i++) + { + type_node from = parameters[i].type; + type_node to = fn.parameters[Math.Min(i,fn.parameters.Count-1)].type; + if (fn.parameters[Math.Min(i, fn.parameters.Count - 1)].is_params) + to = to.element_type; + distance += get_type_distance(from, to); + } + List lst; + if (distances.TryGetValue(distance,out lst)) + { + lst.Add(fn); + } + else + { + lst = new List(); + lst.Add(fn); + distances[distance] = lst; + } + } + foreach (int dist in distances.Keys) + { + List funcs = distances[dist]; + if (funcs.Count == 1) + { + possible_type_convertions_list tcl = get_conversions(parameters, funcs[0].parameters, true, loc); + convert_function_call_expressions(funcs[0], parameters, tcl); + return funcs[0]; + } + } return AddError(new SeveralFunctionsCanBeCalled(loc,set_of_possible_functions)); } + private int get_type_distance(type_node from, type_node to) + { + if (from == to) + return 0; + type_compare tc = type_table.compare_types(from, to); + if (tc == type_compare.non_comparable_type) + return 1000; + if (!from.IsInterface && to.IsInterface) + return 2; + if (tc == type_compare.less_type) + return 1; + if (tc == type_compare.greater_type) + return 3; + return 1000; + } + private function_node is_exist_eq_return_value_method(function_node fn, function_node_list funcs) { fn = find_eq_return_value_method_in_list(fn, funcs); diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index 339215644..3718fed9b 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -12170,6 +12170,8 @@ namespace PascalABCCompiler.TreeConverter top_function.ConnectedToType.base_type.Scope.AddSymbol(top_function.name, new SymbolInfo(context.top_function)); else if (top_function.ConnectedToType.is_generic_parameter) top_function.ConnectedToType.base_type.Scope.AddSymbol(top_function.name, new SymbolInfo(context.top_function)); + else if (top_function.ConnectedToType is compiled_generic_instance_type_node && top_function.ConnectedToType.original_generic.Scope != null) + top_function.ConnectedToType.original_generic.Scope.AddSymbol(top_function.name, new SymbolInfo(context.top_function)); break; } default: diff --git a/TreeConverter/TreeRealization/types.cs b/TreeConverter/TreeRealization/types.cs index 902abe2a2..7a20f3def 100644 --- a/TreeConverter/TreeRealization/types.cs +++ b/TreeConverter/TreeRealization/types.cs @@ -3108,7 +3108,7 @@ namespace PascalABCCompiler.TreeRealization } } - private SymbolInfo AddToSymbolInfo(SymbolInfo to, SymbolInfo from) + private SymbolInfo AddToSymbolInfo(SymbolInfo to, SymbolInfo from, bool clone=false) { if (to==null) { @@ -3117,6 +3117,16 @@ namespace PascalABCCompiler.TreeRealization if (from == null) { return to; + } + if (clone) + { + SymbolInfo old = to; + to = new SymbolInfo(); + to.sym_info = old.sym_info; + to.Next = old.Next; + to.scope = old.scope; + to.symbol_kind = old.symbol_kind; + to.access_level = old.access_level; } SymbolInfo iter=to; while(iter.Next!=null) @@ -3175,13 +3185,74 @@ namespace PascalABCCompiler.TreeRealization SymbolInfo si = scope.SymbolTable.Find(scope, name); SymbolInfo si2 = find_in_additional_names(name); SymbolInfo si3 = compiled_find(name); + bool clone = false; if (this.type_special_kind == SemanticTree.type_special_kind.array_kind && this.base_type.Scope != null) { SymbolInfo tmp_si = this.base_type.Scope.SymbolTable.Find(this.base_type.Scope, name); if (tmp_si != null) { - tmp_si.Next = si; - si = tmp_si; + if (si == null) + si = tmp_si; + else if (si.sym_info != tmp_si.sym_info) + { + tmp_si.Next = si; + si = tmp_si; + } + clone = true; + } + } + if (this.compiled_type.IsGenericType && !this.compiled_type.IsGenericTypeDefinition) + { + compiled_type_node ctn = compiled_type_node.get_type_node(this.compiled_type.GetGenericTypeDefinition()); + if (ctn.scope != null) + { + SymbolInfo tmp_si = ctn.scope.SymbolTable.Find(ctn.scope, name); + if (tmp_si != null && tmp_si.sym_info is function_node && (tmp_si.sym_info as function_node).is_extension_method) + { + if (si == null) + si = tmp_si; + else if (si.sym_info != tmp_si.sym_info) + si = AddToSymbolInfo(si, tmp_si); + clone = true; + } + } + } + compiled_type_node bas_type = base_type as compiled_type_node; + while (bas_type != null && bas_type.scope != null) + { + SymbolInfo tmp_si = bas_type.scope.SymbolTable.Find(bas_type.scope, name); + if (tmp_si != null && tmp_si.sym_info is function_node && (tmp_si.sym_info as function_node).is_extension_method) + { + if (si == null) + si = tmp_si; + else + { + if (si.sym_info != tmp_si.sym_info) + si = AddToSymbolInfo(si, tmp_si); + } + clone = true; + } + bas_type = bas_type.base_type as compiled_type_node; + } + for (int i = 0; i < ImplementingInterfaces.Count; i++) + { + compiled_type_node ctn = ImplementingInterfaces[i] as compiled_type_node; + if (ctn.is_generic_type_instance) + ctn = ctn.original_generic as compiled_type_node; + if (ctn != null && ctn.scope != null) + { + SymbolInfo tmp_si = ctn.scope.SymbolTable.Find(ctn.scope, name); + if (tmp_si != null && tmp_si.sym_info is function_node && (tmp_si.sym_info as function_node).is_extension_method) + { + if (si == null) + si = tmp_si; + else + { + if (si.sym_info != tmp_si.sym_info) + si = AddToSymbolInfo(si, tmp_si); + } + clone = true; + } } } if (si != null) @@ -3193,33 +3264,12 @@ namespace PascalABCCompiler.TreeRealization } else if (si3 != null) si = si3; - if (si == null && si2 == null && string.Compare(name, "Create", true) != 0) - { - compiled_type_node bas_type = base_type as compiled_type_node; - while (si == null && bas_type != null && bas_type.scope != null) - { - si = bas_type.scope.SymbolTable.Find(bas_type.scope, name); - bas_type = bas_type.base_type as compiled_type_node; - } - if (si == null) - { - for (int i = 0; i < ImplementingInterfaces.Count; i++) - { - compiled_type_node ctn = ImplementingInterfaces[i] as compiled_type_node; - if (ctn.is_generic_type_instance) - ctn = ctn.original_generic as compiled_type_node; - if (ctn != null && ctn.scope != null) - si = ctn.scope.SymbolTable.Find(ctn.scope, name); - if (si != null) - break; - } - } - } + if (si == null && si2 == null && this == SystemLibrary.SystemLibrary.string_type && SystemLibrary.SystemLibrary.syn_visitor.from_pabc_dll) { si = compiled_type_node.get_type_node(NetHelper.NetHelper.PABCSystemType).find_in_type(name); } - return AddToSymbolInfo(si, si2); + return AddToSymbolInfo(si, si2, clone); } }