From c692fe0c5e04f588d5b6067132098ea73e613712 Mon Sep 17 00:00:00 2001 From: miks1965 Date: Tue, 16 Jan 2018 19:44:01 +0300 Subject: [PATCH] bug fix #547 --- Configuration/GlobalAssemblyInfo.cs | 2 +- Configuration/Version.defs | 2 +- ReleaseGenerators/PascalABCNET_version.nsh | 2 +- TestSuite/Average4funs.pas | 14 ++ .../convertion_data_and_alghoritms.cs | 121 +++++++++++++++++- TreeConverter/TreeRealization/generics.cs | 11 +- 6 files changed, 143 insertions(+), 9 deletions(-) create mode 100644 TestSuite/Average4funs.pas diff --git a/Configuration/GlobalAssemblyInfo.cs b/Configuration/GlobalAssemblyInfo.cs index 2257aa197..6d8770210 100644 --- a/Configuration/GlobalAssemblyInfo.cs +++ b/Configuration/GlobalAssemblyInfo.cs @@ -15,7 +15,7 @@ internal static class RevisionClass public const string Major = "3"; public const string Minor = "3"; public const string Build = "0"; - public const string Revision = "1617"; + public const string Revision = "1623"; public const string MainVersion = Major + "." + Minor; public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision; diff --git a/Configuration/Version.defs b/Configuration/Version.defs index 1f300a5fa..de6b70d75 100644 --- a/Configuration/Version.defs +++ b/Configuration/Version.defs @@ -1,4 +1,4 @@ %COREVERSION%=0 -%REVISION%=1617 +%REVISION%=1623 %MINOR%=3 %MAJOR%=3 diff --git a/ReleaseGenerators/PascalABCNET_version.nsh b/ReleaseGenerators/PascalABCNET_version.nsh index 1ce3c56c0..4fda1f0d6 100644 --- a/ReleaseGenerators/PascalABCNET_version.nsh +++ b/ReleaseGenerators/PascalABCNET_version.nsh @@ -1 +1 @@ -!define VERSION '3.3.0.1617' +!define VERSION '3.3.0.1623' diff --git a/TestSuite/Average4funs.pas b/TestSuite/Average4funs.pas new file mode 100644 index 000000000..6b221ed37 --- /dev/null +++ b/TestSuite/Average4funs.pas @@ -0,0 +1,14 @@ +{function Average1(Self: sequence of TSource; selector: TSource -> integer): real; extensionmethod; +begin + +end; + +function Average1(Self: sequence of TSource; selector: TSource -> real): real; extensionmethod; +begin +end;} + +begin + var pupils : array of integer := (1,2,3); + var r := pupils.Average(p->p); + Assert(abs(r - 2)<0.000001); +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 764760b04..781201dae 100644 --- a/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs +++ b/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs @@ -1704,7 +1704,22 @@ namespace PascalABCCompiler.TreeConverter SystemLibrary.SystemLibrary.init_reference_type(ctn); } - //Первый параметр - выходной. Он содержит выражения с необходимыми преобразованиями типов. + /// + /// Получение compiled_type_node из либо compiled_type_node либо compiled_generic_instance_type_node. Используется ниже локально + /// + private compiled_type_node get_compiled_type_node(type_node t) + { + var ctn = t as compiled_type_node; + if (ctn == null) + { + var cgn = t as compiled_generic_instance_type_node; + if (cgn != null) + ctn = cgn.original_generic as compiled_type_node; + } + return ctn; + } + + //Первый параметр - выходной. Он содержит выражения с необходимыми преобразованиями типов. public function_node select_function(expressions_list parameters, SymbolInfoList functions, location loc, List syntax_nodes_parameters = null) { if (functions == null) @@ -2106,6 +2121,110 @@ namespace PascalABCCompiler.TreeConverter return funcs[0]; } + Func IsFunc = t => t.IsGenericType && t.FullName.StartsWith("System.Func"); + Func get_type = tt => + { + var ct = get_compiled_type_node(tt); + return ct?.compiled_type; + }; + Func IsFuncT = tt => + { + var ct = get_compiled_type_node(tt); + if (ct == null) + return false; + Type t = ct.compiled_type; + return IsFunc(t); + }; + + + var ParamsCount = funcs[0].parameters.Count; + var b = funcs.All(f => f.parameters.Count == ParamsCount); + if (!b) break; + + var bools = Enumerable.Range(1, funcs.Count()).Select(x => true).ToList(); + + var AllOK = true; + for (var i=0; i < ParamsCount; i++) + { + // Хочу взять проекцию всех функций на i-тый параметр + var parsi = funcs.Select(f => f.parameters[i].type); + if (parsi.Any(p => !IsFuncT(p))) // Если какой-то параметр не функция, то пробросим его + continue; + + var argss = funcs.Select(f => get_type(f.parameters[i].type).GetGenericArguments()).ToArray(); // последовательность массивов параметров Func + var cnts = argss.Select(a => a.Count()); + + var fpi = funcs[0].parameters[i]; + var cnt = get_type(fpi.type).GetGenericArguments().Count(); + // Проверю, что у остальных функций столько же параметров + if (cnts.Any(c => c != cnts.First())) // если нет, то - всё - это ошибка - многозначность. Хотя тут уже не должно быть + { + AllOK = false; + break; + } + + // Цикл по параметрам Func кроме последнего + for (var k = 0; k < cnt - 1; k++) + { + var kpars = funcs.Select(f => get_type(f.parameters[i].type).GetGenericArguments()[k]); + Type p0 = kpars.First(); + bool bb = kpars.All(p => p.Equals(p0)); + if (!bb) + { + AllOK = false; + break; + } + } + if (!AllOK) + break; + + var kres = funcs.Select(f => get_type(f.parameters[i].type).GetGenericArguments()[cnt - 1]).ToArray(); + + //if (funcs[0].is_extension_method) + var fldiResType = funcs[0].is_extension_method ? // странно, но всегда кво параметров в syntax_nodes_parameters на 1 меньше. Иначе падает + ((syntax_nodes_parameters[i - 1] as SyntaxTree.function_lambda_definition).RealSemTypeOfResult as compiled_type_node).compiled_type : + ((syntax_nodes_parameters[i - 1] as SyntaxTree.function_lambda_definition).RealSemTypeOfResult as compiled_type_node).compiled_type; + + for (int n = 0; n < bools.Count; n++) + { + if (!fldiResType.Equals(kres[n])) + bools[n] = false; + } + //var rettype_i = + } + if (AllOK) + if (bools.Count(x=>x==true) == 1) // урра! нашлась ровно одна функция! мы победили! + { + var ind = bools.IndexOf(true); + return funcs[ind]; + } + + /// Проба 15.01.18 - потом удалить + /*{ + var f1 = funcs[0]; + var f2 = funcs[1]; + for (int i = 0; i < parameters.Count; i++) + { + type_node f1i = f1.parameters[i].type; + type_node f2i = f2.parameters[i].type; + var f1ic = get_compiled_type_node(f1i); + var f2ic = get_compiled_type_node(f2i); + if (f1ic == null || f2ic == null) + break; + Type ct1 = f1ic.compiled_type; + Type ct2 = f2ic.compiled_type; + if (IsFunc(ct1) && IsFunc(ct2)) + { + var l1 = ct1.GetGenericArguments()[0]; + var l2 = ct2.GetGenericArguments()[0]; + var b = l1.Equals(l2); + var b1 = l1 == l2; + } + //var p = syntax_nodes_parameters[i]; + } + + }*/ + // Вот здесь нужен анализ всех оставшихся функций. // Если они отличаются только функциональными параметрами и у этих параметров // одинаковый тип параметров (они уже инстанцированы!), то надо еще раз diff --git a/TreeConverter/TreeRealization/generics.cs b/TreeConverter/TreeRealization/generics.cs index 08f58d6c8..17c9a86f8 100644 --- a/TreeConverter/TreeRealization/generics.cs +++ b/TreeConverter/TreeRealization/generics.cs @@ -885,14 +885,15 @@ namespace PascalABCCompiler.TreeRealization } foreach (var formal_delegate in formal_delegates) - //Перебираем все полученные формальные параемтры, соотвтетсвующие фактическим лямбдам + // Перебираем все полученные формальные параметры, соответствующие фактическим лямбдам { var lambda_syntax_node = lambda_syntax_nodes[formal_delegate.Key]; Exception on_lambda_body_compile_exception; - // Исключение которое может возникнуть в результате компиляции тела лямбды если мы выберем неправильные типы параметров - if (!TryToDeduceTypesInLambda(lambda_syntax_node, formal_delegate.Value, deduced, nils, - out on_lambda_body_compile_exception)) - //Пробуем вычислить типы из лямбд + // Исключение которое может возникнуть в результате компиляции тела лямбды если мы выберем неправильные типы параметров + var b = TryToDeduceTypesInLambda(lambda_syntax_node, formal_delegate.Value, deduced, nils, + out on_lambda_body_compile_exception); + if (!b) + // Пробуем вычислить типы из лямбд { RestoreLambdasStates(lambda_syntax_nodes.Values.ToList(), saved_lambdas_states);