From 06a053ad7422365400151d50b5cc1f7126e64c3d Mon Sep 17 00:00:00 2001 From: Mikhalkovich Stanislav Date: Sun, 23 Jun 2019 14:43:27 +0300 Subject: [PATCH] =?UTF-8?q?fix=20#1744=20=D0=B1=D1=83=D0=B4=D1=8C=20=D0=BE?= =?UTF-8?q?=D0=BD=20=D0=BD=D0=B5=D0=BB=D0=B0=D0=B4=D0=B5=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Configuration/GlobalAssemblyInfo.cs | 2 +- Configuration/Version.defs | 4 +- ReleaseGenerators/PascalABCNET_version.nsh | 2 +- TestSuite/lambda_proc_func_1.pas | 18 ++++++++ TestSuite/lambda_proc_func_2.pas | 20 +++++++++ TreeConverter/TreeConversion/LambdaHelper.cs | 2 +- .../convertion_data_and_alghoritms.cs | 44 ++++++++++++++++++- TreeConverter/TreeRealization/types.cs | 2 +- 8 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 TestSuite/lambda_proc_func_1.pas create mode 100644 TestSuite/lambda_proc_func_2.pas diff --git a/Configuration/GlobalAssemblyInfo.cs b/Configuration/GlobalAssemblyInfo.cs index f2d68dd60..27e80cbbc 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 = "5"; public const string Build = "0"; - public const string Revision = "2139"; + public const string Revision = "2144"; 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 b87b502ab..d1bc240e1 100644 --- a/Configuration/Version.defs +++ b/Configuration/Version.defs @@ -1,4 +1,4 @@ -%MINOR%=5 -%REVISION%=2139 %COREVERSION%=0 +%REVISION%=2144 +%MINOR%=5 %MAJOR%=3 diff --git a/ReleaseGenerators/PascalABCNET_version.nsh b/ReleaseGenerators/PascalABCNET_version.nsh index 569c8a601..de1ab49c2 100644 --- a/ReleaseGenerators/PascalABCNET_version.nsh +++ b/ReleaseGenerators/PascalABCNET_version.nsh @@ -1 +1 @@ -!define VERSION '3.5.0.2139' +!define VERSION '3.5.0.2144' diff --git a/TestSuite/lambda_proc_func_1.pas b/TestSuite/lambda_proc_func_1.pas new file mode 100644 index 000000000..5cc3002e7 --- /dev/null +++ b/TestSuite/lambda_proc_func_1.pas @@ -0,0 +1,18 @@ +procedure p1(p: ()->()); +begin + Assert(1=2); +end; + +procedure p1(f: ()->T); +begin + Assert(1=1); +end; + +begin + p1( + function-> + begin + Result := 1; + end + ) +end. \ No newline at end of file diff --git a/TestSuite/lambda_proc_func_2.pas b/TestSuite/lambda_proc_func_2.pas new file mode 100644 index 000000000..45343e32c --- /dev/null +++ b/TestSuite/lambda_proc_func_2.pas @@ -0,0 +1,20 @@ +procedure p1(p: procedure); +begin + Assert(1=2) + //write('procedure') +end; + +procedure p1(f: ()->integer); +begin + Assert(1=1) + //write('function') +end; + +begin + p1( + function-> + begin + Result := 1; + end + ) +end. \ No newline at end of file diff --git a/TreeConverter/TreeConversion/LambdaHelper.cs b/TreeConverter/TreeConversion/LambdaHelper.cs index 73642c9b2..659c9d373 100644 --- a/TreeConverter/TreeConversion/LambdaHelper.cs +++ b/TreeConverter/TreeConversion/LambdaHelper.cs @@ -323,7 +323,7 @@ namespace PascalABCCompiler.TreeConverter // lambdaDef.usedkeyword == 1 // function var b = lambdaDef.usedkeyword == 0 && TryConvertFuncLambdaBodyWithMethodCallToProcLambdaBody(lambdaDef); // пытаться конвертировать только если мы явно не указали, что это функция if (!b) - throw new SimpleSemanticError(visitor.get_location(lambdaDef), "UNABLE_TO_CONVERT_FUNCTIONAL_TYPE_TO_PROCEDURAL_TYPE"); + visitor.AddError(visitor.get_location(lambdaDef), "UNABLE_TO_CONVERT_FUNCTIONAL_TYPE_TO_PROCEDURAL_TYPE"); } } } diff --git a/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs b/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs index 708b16080..4fad28a25 100644 --- a/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs +++ b/TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs @@ -1731,7 +1731,7 @@ namespace PascalABCCompiler.TreeConverter // Эту функцию можно написать оптимальнее - без внешнего while. Например. // Запускаем алгоритм сортировки на частичном порядке. Ищем min из оставшихся и меняем его местами с текущим. // Потом проходимся по частично отсортированному и из пары соседних удаляем тот, что меньше - private void functions_delete_greater(List set_of_possible_functions, possible_type_convertions_list_list tcll) + private void delete_greater_functions(List set_of_possible_functions, possible_type_convertions_list_list tcll) { bool remove = true; while (remove) @@ -1958,6 +1958,44 @@ namespace PascalABCCompiler.TreeConverter Errors.Error err = null; possible_type_convertions_list tc = get_conversions(parameters, set_of_possible_functions[i].parameters, is_alone_method_defined, loc, out err); + + var proc_func_OK_flag = true; + // Цикл по всем параметрам. Если формальный - процедура, а фактический - функция, то tc делать = null и взводить специальный флаг чтобы не возиться с делегатами дальше + + if (set_of_possible_functions.Count >= 2 && set_of_possible_functions[i].parameters.Count == parameters.Count) + for (var k = 0; k < parameters.Count; k++) + { + var fact = parameters[k]; + var formal = set_of_possible_functions[i].parameters[k]; + if (fact.type is delegated_methods dm) + { + var fact_is_function_with_return_value = dm.proper_methods.Count > 0 && dm.proper_methods[0].function.return_value_type != null; + var form_is_procedure = false; + + //if (formal.type is compiled_type_node || // Это на случай System.Action или ()->() + // formal.type is compiled_type_node) // Это на случай procedure + { + var d = formal.type.internal_interfaces; + if (d != null && d.ContainsKey(internal_interface_kind.delegate_interface)) + { + var q = d[internal_interface_kind.delegate_interface] as delegate_internal_interface; + if (q != null && q.return_value_type == null) // Это процедура + form_is_procedure = true; + } + } + + if (fact_is_function_with_return_value && form_is_procedure) + { + proc_func_OK_flag = false; + break; + } + + } + } + + if (proc_func_OK_flag == false) + tc = null; + // Вот здесь - если фактический параметр - функция, а формальный - процедура хотя бы в одном параметре, то надо нивелировать все преобразования и присваивать tc=null и не влазить в следующий код!!! if (err != null) return AddError(err); //fix dlja lambd i extension metodov (c->c.IsDigit) @@ -2017,7 +2055,9 @@ namespace PascalABCCompiler.TreeConverter return set_of_possible_functions[0]; } - functions_delete_greater(set_of_possible_functions,tcll); // SSM 06/06/19 refactoring + // Если остались параметры функция и процедура - обе без параметров, но функция возвращает T, то функция будет удалена этим алгоритмом, что неправильно! + // Потому что не учитывается вызов - в вызове может быть функция!! + delete_greater_functions(set_of_possible_functions,tcll); // SSM 06/06/19 refactoring //Тупая заглушка для примитивных типов. иначе не работает +=, у нас лишком много неявных приведений //в дальнейшем может вызвать странное поведение, это надо проверить diff --git a/TreeConverter/TreeRealization/types.cs b/TreeConverter/TreeRealization/types.cs index 0888ac6e4..4566ea44d 100644 --- a/TreeConverter/TreeRealization/types.cs +++ b/TreeConverter/TreeRealization/types.cs @@ -31,7 +31,7 @@ namespace PascalABCCompiler.TreeRealization private System.Collections.Generic.Dictionary type_intersections; //new System.Collections.Generic.Dictionary(); private List generated_type_intersections = null;//new List(); - private System.Collections.Generic.Dictionary internal_interfaces; + public System.Collections.Generic.Dictionary internal_interfaces; //new System.Collections.Generic.Dictionary(); //private System.Collections.Generic.Dictionary explicit_type_conversions =