diff --git a/TestSuite/errors/err0394.pas b/TestSuite/errors/err0394.pas new file mode 100644 index 000000000..025e43d2b --- /dev/null +++ b/TestSuite/errors/err0394.pas @@ -0,0 +1,11 @@ +type + t1 = class + + static procedure operator+=(a: t1; d: System.Action) := exit; + + end; + +begin + var a := new t1; + a += ()->Writeln(1); +end. \ No newline at end of file diff --git a/TestSuite/lambdas11.pas b/TestSuite/lambdas11.pas new file mode 100644 index 000000000..541a94f67 --- /dev/null +++ b/TestSuite/lambdas11.pas @@ -0,0 +1,18 @@ +type + t1 = class + l: List := new List; + static procedure operator+=(a: t1; d: Action0); + begin + a.l.Add(d); + end; + + end; + +var i: integer; + +begin + var a := new t1; + a += ()->Inc(i); + a.l[0](); + assert(i = 1); +end. \ No newline at end of file diff --git a/TestSuite/lambdas12.pas b/TestSuite/lambdas12.pas new file mode 100644 index 000000000..987156f50 --- /dev/null +++ b/TestSuite/lambdas12.pas @@ -0,0 +1,8 @@ +var i: integer; + +begin + var l := new List; + l += ()->Inc(i); + l[0](); + assert(i = 1); +end. \ No newline at end of file diff --git a/TestSuite/lambdas13.pas b/TestSuite/lambdas13.pas new file mode 100644 index 000000000..44adbef80 --- /dev/null +++ b/TestSuite/lambdas13.pas @@ -0,0 +1,10 @@ +type TProc = procedure; + +var i: integer; + +begin + var l := new List; + l += ()->Inc(i); + l[0]; + assert(i = 1); +end. \ No newline at end of file diff --git a/TestSuite/lambdas14.pas b/TestSuite/lambdas14.pas new file mode 100644 index 000000000..d38e81ead --- /dev/null +++ b/TestSuite/lambdas14.pas @@ -0,0 +1,21 @@ +var i: integer; +type + t1 = class + + static procedure operator+=(a: t1; d: System.Action); + begin + i := 1; + end; + static procedure operator+=(a: t1; d: Action0); + begin + i := 2; + end; + end; + +begin + var a := new t1; + a += ()->Writeln(1); + assert(i = 2); + a += (x: integer)->Writeln(1); + assert(i = 1); +end. \ No newline at end of file diff --git a/TreeConverter/TreeConversion/LambdaHelper.cs b/TreeConverter/TreeConversion/LambdaHelper.cs index 214bed468..f3fdcb4c6 100644 --- a/TreeConverter/TreeConversion/LambdaHelper.cs +++ b/TreeConverter/TreeConversion/LambdaHelper.cs @@ -260,7 +260,7 @@ namespace PascalABCCompiler.TreeConverter /// /// Вывод типа параметров лямбд и типа возвращаемого значения при присваивании лямбды переменной /// - public static void InferTypesFromVarStmt(type_node leftType, function_lambda_definition lambdaDef, syntax_tree_visitor visitor) + public static void InferTypesFromVarStmt(type_node leftType, function_lambda_definition lambdaDef, syntax_tree_visitor visitor, Operators op = Operators.Undefined) { if (lambdaDef == null) return; @@ -271,7 +271,47 @@ namespace PascalABCCompiler.TreeConverter if (dii_left == null) { if (leftType != SystemLibrary.SystemLibrary.system_delegate_type) - visitor.AddError(visitor.get_location(lambdaDef), "ILLEGAL_LAMBDA_VARIABLE_TYPE"); + { + if (op != Operators.Undefined) + { + var sil = leftType.find_in_type(name_reflector.get_name(op)); + if (sil.Count > 0) + { + foreach (SymbolInfo si in sil) + { + if (si.sym_info is function_node) + { + function_node fn = si.sym_info as function_node; + if (fn.parameters.Count == 2) + { + dii_left = (delegate_internal_interface)fn.parameters[1].type.get_internal_interface(internal_interface_kind.delegate_interface); + if (dii_left != null) + break; + if (fn.parameters[1].type.is_generic_parameter) + { + compiled_type_node ctn = leftType as compiled_type_node; + common_type_node ctn2 = leftType as common_type_node; + if (ctn != null && ctn.is_generic_type_instance && fn.parameters[0].type.is_generic_type_instance && ctn.original_generic == fn.parameters[0].type.original_generic) + { + dii_left = (delegate_internal_interface)ctn.generic_params[0].get_internal_interface(internal_interface_kind.delegate_interface); + if (dii_left != null) + break; + } + if (ctn2 != null && ctn2.is_generic_type_instance && ctn2.instance_params.Count > 0 && fn.parameters[0].type.is_generic_type_instance && ctn2.original_generic == fn.parameters[0].type.original_generic) + { + dii_left = (delegate_internal_interface)ctn2.instance_params[0].get_internal_interface(internal_interface_kind.delegate_interface); + if (dii_left != null) + break; + } + } + } + } + } + } + } + if (dii_left == null) + visitor.AddError(visitor.get_location(lambdaDef), "ILLEGAL_LAMBDA_VARIABLE_TYPE"); + } else return; } diff --git a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Assign.cs b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Assign.cs index dd13ca9ba..320003628 100644 --- a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Assign.cs +++ b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Assign.cs @@ -135,7 +135,7 @@ namespace PascalABCCompiler.TreeConverter { #region Вывод параметров лямбда-выражения - LambdaHelper.InferTypesFromVarStmt(to.type, fromAsLambda, this); //lroman// + LambdaHelper.InferTypesFromVarStmt(to.type, fromAsLambda, this, _assign.operator_type); //lroman// #endregion