Skip to content

Commit

Permalink
bug fix issue pascalabcnet#80
Browse files Browse the repository at this point in the history
  • Loading branch information
ibond84 committed Feb 6, 2016
1 parent a637664 commit d7a8f88
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 6 deletions.
12 changes: 12 additions & 0 deletions TestSuite/curry1.pas
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
function Curry<T1,T2,T3>(f: (T1,T2)->T3; t: T2): T1->T3;
begin
if f=nil then
raise new System.ArgumentNullException('f');
Result := x -> f(x,t)
end;

begin
var f: (integer, integer)->integer := (x,y)->x+y;
var f2: integer->integer := Curry(f,2);
assert(f2(3)=5);
end.
26 changes: 21 additions & 5 deletions TreeConverter/TreeConversion/convertion_data_and_alghoritms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1403,13 +1403,29 @@ internal static bool eq_type_nodes(type_node tn1, type_node tn2, bool strong)
{
return false;
}
common_type_node ctdef = tdef as common_type_node;
int count = ctdef.generic_params.Count;
for (int i = 0; i < count; ++i)

if (tdef is common_type_node)
{
if (ctdef.generic_params[i] != tinst.instance_params[i])
common_type_node ctdef = tdef as common_type_node;
int count = ctdef.generic_params.Count;
for (int i = 0; i < count; ++i)
{
return false;
if (ctdef.generic_params[i] != tinst.instance_params[i])
{
return false;
}
}
}
else if (tdef is compiled_type_node)
{
compiled_type_node ctdef = tdef as compiled_type_node;
int count = ctdef.generic_params.Count;
for (int i = 0; i < count; ++i)
{
if (ctdef.generic_params[i] != tinst.instance_params[i])
{
return false;
}
}
}
return true;
Expand Down
199 changes: 199 additions & 0 deletions TreeConverter/TreeConversion/syntax_tree_visitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5616,9 +5616,208 @@ internal void visit_method_call(SyntaxTree.method_call _method_call)
{
foreach (SyntaxTree.expression en in _method_call.parameters.expressions)
{
#region Отмечаем флаг в лямбдах, говорящий о том, что в первый раз будем их "обходить" для вывода типов
//lroman//
if (en is SyntaxTree.function_lambda_definition)
{
lambdas_are_in_parameters = true;
((SyntaxTree.function_lambda_definition)en).lambda_visit_mode = LambdaVisitMode.VisitForInitialMethodCallProcessing;
}
//lroman//
#endregion
exprs.AddElement(convert_strong(en));
}
}
location subloc = sloc;
#region Если встретились лямбды в фактических параметрах, то выбираем нужную функцию из перегруженных, выводим типы, отмечаем флаг в лямбдах, говорящий о том, что мы их реально обходим
//lroman//
if (lambdas_are_in_parameters)
{
LambdaHelper.processingLambdaParametersForTypeInference++;
// SSM 21.05.14 - попытка обработать перегруженные функции с параметрами-лямбдами с различными возвращаемыми значениями
function_node_list spf = null;
try
{
function_node ffn = convertion_data_and_alghoritms.select_function(exprs, si, subloc, syntax_nodes_parameters);
int exprCounter = 0;

foreach (SyntaxTree.expression en in _method_call.parameters.expressions)
{
if (!(en is SyntaxTree.function_lambda_definition))
{
exprCounter++;
continue;
}
else
{
var enLambda = (SyntaxTree.function_lambda_definition)en;
LambdaHelper.InferTypesFromVarStmt(ffn.parameters[exprCounter].type, enLambda, this);
enLambda.lambda_visit_mode = LambdaVisitMode.VisitForAdvancedMethodCallProcessing;
exprs[exprCounter] = convert_strong(en);
enLambda.lambda_visit_mode = LambdaVisitMode.VisitForInitialMethodCallProcessing;
exprCounter++;
}
}
}
catch (SeveralFunctionsCanBeCalled sf)
{
spf = sf.set_of_possible_functions; // Возможны несколько перегруженных версий - надо выводить дальше в надежде что какие-то уйдут и останется одна
}

Exception lastmultex = null;
if (spf != null) // пытаемся инстанцировать одну за другой и ошибки гасим try
{ // exprs - глобальная, поэтому надо копировать
int spfnum = -1; // первый номер правильно инстанцированной. Если потом встретился второй, то тоже ошибка
// SSM 4.08.15. Сейчас меняю эту логику. Если будет много кандидатов, но ровно один с совпадающим типом возвращаемого значения, то его и надо выбирать.
// не забыть, что аналогичный код есть в create_constructor_call!!!!!!!
int GoodVersionsCount = 0;
int GoodVersionsCountWithSameResType = 0;
for (int i = 0; i < spf.Count; i++) // цикл по версиям
{
function_node fnn = spf[i];
try
{
int exprCounter = 0;


expressions_list exprs1 = new expressions_list();
exprs1.AddRange(exprs); // сделали копию

foreach (SyntaxTree.expression en in _method_call.parameters.expressions)
{
if (!(en is SyntaxTree.function_lambda_definition))
{
exprCounter++;
continue;
}
else
{
var fld = en as SyntaxTree.function_lambda_definition;

var lambdaName = fld.lambda_name; //lroman Сохранять имя необходимо
var fl = fld.lambda_visit_mode;

// запомнили типы параметров лямбды - SSM
object[] realparamstype = new object[fld.formal_parameters.params_list.Count]; // здесь хранятся выведенные типы лямбд или null если типы явно заданы
for (var k = 0; k < fld.formal_parameters.params_list.Count; k++)
{
var laminftypeK = fld.formal_parameters.params_list[k].vars_type as SyntaxTree.lambda_inferred_type;
if (laminftypeK == null)
realparamstype[k] = null;
else realparamstype[k] = laminftypeK.real_type;
}

// запоминаем реальный тип возвращаемого значения если он не указан явно (это должен быть any_type или null если он указан явно) - он может измениться при следующем вызове, поэтому мы его восстановим
var restype = fld.return_type as SyntaxTree.lambda_inferred_type;
object realrestype = null;
if (restype != null)
realrestype = restype.real_type;
LambdaHelper.InferTypesFromVarStmt(fnn.parameters[exprCounter].type, fld, this);
fld.lambda_visit_mode = LambdaVisitMode.VisitForAdvancedMethodCallProcessing; //lroman
fld.lambda_name = LambdaHelper.GetAuxiliaryLambdaName(lambdaName); // поправляю имя. Думаю, назад возвращать не надо. ПРОВЕРИТЬ!

//contextChanger.SaveContextAndUpToNearestDefSect();
try
{
exprs1[exprCounter] = convert_strong(en);

type_node resexprtype = fld.RealSemTypeOfResExpr as type_node;
type_node resformaltype = fld.RealSemTypeOfResult as type_node;
var bbb = resexprtype == resformaltype; // только в одном случае должно быть true - эту версию и надо выбирать. Если в нескольких, то неоднозначность
if (bbb)
{
GoodVersionsCountWithSameResType += 1;
spfnum = i; // здесь запоминаем индекс потому что он точно подойдет. Тогда ниже он запоминаться не будет.
}

/*compiled_type_node tt;
tt = fnn.parameters[exprCounter].type as compiled_type_node;
if (tt != null && tt.compiled_type.FullName.ToLower().StartsWith("system.func"))
{
resformaltype = tt.instance_params[tt.instance_params.Count - 1]; // Последний параметр в записи Func<T,T1,...TN> - тип возвращаемого значения
var bbb = resexprtype == resformaltype; // только в одном случае должно быть true - эту версию и надо выбирать. Если в нескольких, то неоднозначность
if (bbb)
{
GoodVersionsCountWithSameResType += 1;
spfnum = i; // здесь запоминаем индекс потому что он точно подойдет. Тогда ниже он запоминаться не будет.
}
}*/
}
catch
{
throw;
}
finally
{
LambdaHelper.RemoveLambdaInfoFromCompilationContext(context, en as function_lambda_definition);
// восстанавливаем сохраненный тип возвращаемого значения
if (restype != null)
restype.real_type = realrestype;
// восстанавливаем сохраненные типы параметров лямбды, которые не были заданы явно
for (var k = 0; k < fld.formal_parameters.params_list.Count; k++)
{
var laminftypeK = fld.formal_parameters.params_list[k].vars_type as SyntaxTree.lambda_inferred_type;
if (laminftypeK != null)
laminftypeK.real_type = realparamstype[k];
}

fld.lambda_name = lambdaName; //lroman Восстанавливаем имена
fld.lambda_visit_mode = fl;
}

//contextChanger.RestoreCurrentContext();
exprCounter++;
}
}
/*if (spfnum >= 0) // два удачных инстанцирования - плохо. Может, одно - с более близким типом возвращаемого значения, тогда это плохо - надо доделать, но пока так
{
spfnum = -2;
break;
}*/

if (GoodVersionsCountWithSameResType == 0)
spfnum = i; // здесь запоминаем индекс только если нет подошедших, совпадающих по типу возвращаемого значения
GoodVersionsCount += 1;
for (int j = 0; j < exprs.Count; j++) // копируем назад если всё хорошо
exprs[j] = exprs1[j];
}
catch (Exception e)
{
// если сюда попали, значит, не вывели типы в лямбде и надо эту инстанцию пропускать
//contextChanger.RestoreCurrentContext();
lastmultex = e;
}
} // конец цикла по версиям
if (GoodVersionsCount > 1 && GoodVersionsCountWithSameResType != 1) // подошло много, но не было ровно одной с совпадающим типом возвращаемого значения
throw new SeveralFunctionsCanBeCalled(subloc, spf);
if (GoodVersionsCount == 0) // было много, но ни одна не подошла из-за лямбд
{
throw lastmultex;
//throw new NoFunctionWithSameArguments(subloc2, false);
}

int kk = 0;

foreach (SyntaxTree.expression en in _method_call.parameters.expressions) //lroman окончательно подставить типы в лямбды
{
if (!(en is SyntaxTree.function_lambda_definition))
{
kk++;
continue;
}
else
{
LambdaHelper.InferTypesFromVarStmt(spf[spfnum].parameters[kk].type, en as SyntaxTree.function_lambda_definition, this);
exprs[kk] = convert_strong(en);
kk++;
}
}
}
// SSM 21.05.14 end
LambdaHelper.processingLambdaParametersForTypeInference--;
}
//lroman//
#endregion

function_node del_func = convertion_data_and_alghoritms.select_function(exprs, si, sloc, syntax_nodes_parameters);
base_function_call bbfc = create_not_static_method_call(del_func, exp_int, sloc, proc_wait);
Expand Down
Loading

0 comments on commit d7a8f88

Please sign in to comment.