diff --git a/TestSuite/nested_lambdas_1.pas b/TestSuite/nested_lambdas_1.pas new file mode 100644 index 000000000..f23f3f501 --- /dev/null +++ b/TestSuite/nested_lambdas_1.pas @@ -0,0 +1,18 @@ +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; + +begin + p(x -> Range(0, x).Select(y -> y * y)); +end. \ No newline at end of file diff --git a/TestSuite/nested_lambdas_2.pas b/TestSuite/nested_lambdas_2.pas new file mode 100644 index 000000000..42acd1ce2 --- /dev/null +++ b/TestSuite/nested_lambdas_2.pas @@ -0,0 +1,14 @@ +procedure p(f: Func>); +begin + var res := f(5).ToList(); + assert(res.Count = 5); + assert(res[0] = 2); + assert(res[1] = 3); + assert(res[2] = 4); + assert(res[3] = 5); + assert(res[4] = 6); +end; + +begin + p(x -> Seq(1,2,3,4,5).Select(y -> Range(0, y).Select(z -> z).Count())); +end. \ No newline at end of file diff --git a/TestSuite/nested_lambdas_3.pas b/TestSuite/nested_lambdas_3.pas new file mode 100644 index 000000000..4a7a6a996 --- /dev/null +++ b/TestSuite/nested_lambdas_3.pas @@ -0,0 +1,27 @@ +type cl = class + public + 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 tt(); + begin + p(x -> Range(0, x).Select(y -> y * y)); + end; +end; + +begin + (new cl()).p(x -> Range(0, x).Select(y -> y * y)); + (new cl()).tt(); +end. \ No newline at end of file diff --git a/TestSuite/nested_lambdas_4.pas b/TestSuite/nested_lambdas_4.pas new file mode 100644 index 000000000..fd5e34ef2 --- /dev/null +++ b/TestSuite/nested_lambdas_4.pas @@ -0,0 +1,22 @@ +type cl = class + public + constructor(f: Func>); + begin + + end; + + constructor (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; + +end; + +begin + new cl(x -> Range(0, x).Select(y -> y * y)); +end. \ No newline at end of file diff --git a/TestSuite/nested_lambdas_5.pas b/TestSuite/nested_lambdas_5.pas new file mode 100644 index 000000000..31d67d191 --- /dev/null +++ b/TestSuite/nested_lambdas_5.pas @@ -0,0 +1,12 @@ +begin + var a := 3; + var ttt := Seq(1,2).Select(x -> begin + var t := 5; + result := Range(1,a+x).Select(y -> begin + var g := 5; + t += 5; + result := Range(1,2).Where(f -> f + a > 0).Select(z -> z + g + t); + end) + end).ToList(); + assert(ttt[0].ToList()[0].ToList()[0] = 31); +end. \ No newline at end of file diff --git a/TestSuite/nested_lambdas_6.pas b/TestSuite/nested_lambdas_6.pas new file mode 100644 index 000000000..8348885b9 --- /dev/null +++ b/TestSuite/nested_lambdas_6.pas @@ -0,0 +1,20 @@ +type cl = class + private gg := 9; + public + procedure h(k: integer); + begin + var a := 5; + Seq(1,2,3).Select(x -> begin + var t := 5; + result := Range(1,a).Select(y -> begin + var g := 5; + writeln(a); + result := Range(1,3).Where(f -> f + a > 0).Select(z -> z + g + t); + end) + end); + end; +end; + +begin + (new cl).h(6); +end. \ No newline at end of file diff --git a/TestSuite/nested_lambdas_7.pas b/TestSuite/nested_lambdas_7.pas new file mode 100644 index 000000000..5d294833b --- /dev/null +++ b/TestSuite/nested_lambdas_7.pas @@ -0,0 +1,20 @@ +type cl = class + protected gg:integer := 9; + public + function h(k: integer):string; + begin + var a := 5; + foreach var tt in Seq(1,2,3) do + begin + var d := Seq(1,2,3).Select(x -> begin + var e := 65; + result := e + x + tt + self.gg + Range(1,2).Select(y -> gg + self.gg+y+a + tt).First() + end).ToList(); + assert(d[0] = 100 + (tt * 2 - 1)); + end; + end; +end; + +begin + (new cl).h(5); +end. \ No newline at end of file diff --git a/TestSuite/nested_lambdas_8.pas b/TestSuite/nested_lambdas_8.pas new file mode 100644 index 000000000..f070c49e0 --- /dev/null +++ b/TestSuite/nested_lambdas_8.pas @@ -0,0 +1,15 @@ +begin + var yy := 5; + Range(1,1).Select(x -> begin + var l := x + yy; //6 + begin + writeln(l); + begin + writeln(l); + end; + end; + writeln(yy); + result := Range(1, x).Select(y -> y + l + yy + Seq(1,2).Select(z -> l + yy).First()) + end); + writeln(yy); +end. \ No newline at end of file diff --git a/TestSuite/nested_lambdas_9.pas b/TestSuite/nested_lambdas_9.pas new file mode 100644 index 000000000..3161af218 --- /dev/null +++ b/TestSuite/nested_lambdas_9.pas @@ -0,0 +1,13 @@ +procedure p(aa: T); where T: class; +begin + var a := Seq(1,2,3).Select(x -> begin + var tt := new List(); + writeln(aa); + tt.Add(aa); + result := tt.Select(y -> begin result := aa; writeln(aa) end).ToList() + end).ToList(); +end; + +begin + p('sss'); +end. \ No newline at end of file diff --git a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesSubstitutionClassGenerator.cs b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesSubstitutionClassGenerator.cs index 077ecd7f8..d05474013 100644 --- a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesSubstitutionClassGenerator.cs +++ b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesSubstitutionClassGenerator.cs @@ -20,7 +20,8 @@ namespace TreeConverter.LambdaExpressions.Closure private static int _generatedClassCounter; private static int _generatedUpperClassCounter; private readonly Dictionary _substitutions; - + private readonly List _lambdaIdReferences = new List(); + private readonly List _rewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo = new List(); public static void Reset() { _generatedClassCounter = 0; @@ -58,6 +59,8 @@ namespace TreeConverter.LambdaExpressions.Closure private const string GeneratedSubstitutingFieldPrefix = "<>local_variables_"; //это поле для того, чтобы заменять в текущем блоке, где захватывались переменные, левую часть dot_node private static int _generatedSubstitutingFieldCounter; + public List NestedLambdas { get; set; } + public syntax_tree_node CorrespondingSyntaxTreeNode { get; @@ -129,9 +132,25 @@ namespace TreeConverter.LambdaExpressions.Closure ClassDeclaration = classDeclaration; _generatedSubstitutingFieldName = generatedSubstitutingFieldName; CorrespondingTreeNode = correspondingTreeNode; + NestedLambdas = new List(); } } + private class LambdaReferencesSubstitutionInfo + { + public CapturedVariablesTreeNodeLambdaScope LambdaScope { get; set; } + public string VarName { get; set; } + public syntax_tree_node SyntaxTreeNodeWithVarDeclaration { get; set; } + public dot_node DotNode { get; set; } + } + + private class RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo + { + public CapturedVariablesTreeNode TreeNode { get; set; } + public string Varname { get; set; } + public syntax_tree_node NodeWithVarDecl { get; set; } + } + public CapturedVariablesSubstitutionClassGenerator(CapturedVariablesTreeNode capturedVariablesRootTreeNode) { _capturedVariablesRootTreeNode = capturedVariablesRootTreeNode; @@ -150,21 +169,27 @@ namespace TreeConverter.LambdaExpressions.Closure private void VisitCapturedVar(CapturedVariablesTreeNode scope, CapturedVariablesTreeNode.CapturedSymbolInfo symbolInfo) { - var varName = ((IVAriableDefinitionNode)symbolInfo.SymbolInfo.sym_info).name.ToLower(); //TODO: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + var varName = ((IVAriableDefinitionNode)symbolInfo.SymbolInfo.sym_info).name.ToLower(); var isSelfWordInClass = scope is CapturedVariablesTreeNodeClassScope && varName == compiler_string_consts.self_word; - for (var k = 0; k < symbolInfo.ReferencingLambdas.Count; k++) + foreach (var referencingLambda in symbolInfo.ReferencingLambdas.OrderByDescending(rl => rl.ScopeIndex)) { - var referencingLambda = symbolInfo.ReferencingLambdas[k]; if (scope != referencingLambda.ParentNode) { var upperScopesStack = new Stack(); var crawlUpScope = referencingLambda.ParentNode; + var anotherLambdaIsOnTheWay = crawlUpScope is CapturedVariablesTreeNodeLambdaScope; - while (crawlUpScope != scope) + while (crawlUpScope != null && crawlUpScope != scope && !anotherLambdaIsOnTheWay) { upperScopesStack.Push(crawlUpScope); crawlUpScope = crawlUpScope.ParentNode; + anotherLambdaIsOnTheWay = crawlUpScope is CapturedVariablesTreeNodeLambdaScope; + } + + if (anotherLambdaIsOnTheWay || crawlUpScope == null) + { + continue; } var upperScopeWhereVarsAreCaptured = scope; @@ -352,7 +377,6 @@ namespace TreeConverter.LambdaExpressions.Closure } } - //TODO: Nested Lambdas if (!(upperScopeWhereVarsAreCaptured == scope && upperScopeWhereVarsAreCaptured is CapturedVariablesTreeNodeClassScope)) { @@ -403,8 +427,27 @@ namespace TreeConverter.LambdaExpressions.Closure dotnode1 = new dot_node(dotnode1, new ident(varName)); } } - AddReferencesToIdentInLambda(referencingLambda.ChildNodes[0], varName, - symbolInfo.SyntaxTreeNodeWithVarDeclaration, dotnode1); + _lambdaIdReferences.Add(new LambdaReferencesSubstitutionInfo + { + LambdaScope = referencingLambda, + VarName = varName, + SyntaxTreeNodeWithVarDeclaration = symbolInfo.SyntaxTreeNodeWithVarDeclaration, + DotNode = dotnode1 + }); + } + else + { + var dotnode1 = new dot_node( + new ident(compiler_string_consts.self_word), + new ident(varName)); + + _lambdaIdReferences.Add(new LambdaReferencesSubstitutionInfo + { + LambdaScope = referencingLambda, + VarName = varName, + SyntaxTreeNodeWithVarDeclaration = symbolInfo.SyntaxTreeNodeWithVarDeclaration, + DotNode = dotnode1 + }); } } if (!referencingLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue || @@ -454,6 +497,18 @@ namespace TreeConverter.LambdaExpressions.Closure } } + var dotnode1 = new dot_node( + new ident(compiler_string_consts.self_word), + new ident(varName)); + + _lambdaIdReferences.Add(new LambdaReferencesSubstitutionInfo + { + LambdaScope = referencingLambda, + VarName = varName, + SyntaxTreeNodeWithVarDeclaration = symbolInfo.SyntaxTreeNodeWithVarDeclaration, + DotNode = dotnode1 + }); + if (!referencingLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue || scope.ScopeIndex > referencingLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod) { @@ -468,24 +523,93 @@ namespace TreeConverter.LambdaExpressions.Closure } } - private void AddReferencesToIdentInLambda(CapturedVariablesTreeNode scope, string varName, syntax_tree_node syntaxTreeNodeWithVarDeclaration, dot_node substDotNode) + private void AddReferencesToIdentInLambda(type_declaration upperScopeWhereVarsAreCapturedClass, CapturedVariablesTreeNode scope, string varName, syntax_tree_node syntaxTreeNodeWithVarDeclaration, dot_node substDotNode, bool nestedLambda) { - //TODO: Nested Lambdas - for (var i = 0; i < scope.ChildNodes.Count; i++) { - if (!(scope.ChildNodes[i] is CapturedVariablesTreeNodeLambdaScope)) // Вложенные лямбды пока не рассматриваем + if (!(scope.ChildNodes[i] is CapturedVariablesTreeNodeLambdaScope)) { var substKey = new SubstitutionKey(varName, syntaxTreeNodeWithVarDeclaration, scope.ChildNodes[i].CorrespondingSyntaxTreeNode); + if (_capturedVarsClassDefs.ContainsKey(scope.ChildNodes[i].ScopeIndex)) + { + var cl = _capturedVarsClassDefs[scope.ChildNodes[i].ScopeIndex]; + if (cl.AssignNodeForUpperClassFieldInitialization == null) + { + var fieldType = + SyntaxTreeBuilder.BuildSimpleType(upperScopeWhereVarsAreCapturedClass.type_name.name); + var field = + SyntaxTreeBuilder.BuildClassFieldsSection( + new List + { + new ident(cl.GeneratedUpperClassFieldName) + }, + new List { fieldType }); + + var clClass = (class_definition) cl.ClassDeclaration.type_def; + clClass.body.Add(field); + + cl.AssignNodeForUpperClassFieldInitialization = + new assign( + new dot_node(new ident(cl.GeneratedSubstitutingFieldName),new ident(cl.GeneratedUpperClassFieldName)), + new ident(compiler_string_consts.self_word)); + + } + } + if (!_substitutions.ContainsKey(substKey)) { _substitutions.Add(substKey, substDotNode); } - AddReferencesToIdentInLambda(scope.ChildNodes[i], varName, syntaxTreeNodeWithVarDeclaration, - substDotNode); + AddReferencesToIdentInLambda(upperScopeWhereVarsAreCapturedClass, scope.ChildNodes[i], varName, syntaxTreeNodeWithVarDeclaration, substDotNode, nestedLambda); + } + else + { + var scopeAsLambda = scope.ChildNodes[i] as CapturedVariablesTreeNodeLambdaScope; + if (scopeAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue) + { + dot_node substDotNode1; + if (!nestedLambda) + { + substDotNode1 = new dot_node(new ident(_capturedVarsClassDefs[scopeAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value].GeneratedUpperClassFieldName), new ident(varName)); + } + else + { + var parts = new Stack(); + var dn = substDotNode; + parts.Push((ident)dn.right); + + while (!(dn.left is ident && dn.right is ident)) + { + dn = (dot_node)dn.left; + parts.Push((ident)dn.right); + } + + parts.Push((ident)dn.left); + + substDotNode1 = new dot_node(new ident(_capturedVarsClassDefs[scopeAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value].GeneratedUpperClassFieldName), parts.Pop()); + + while (parts.Count > 0) + { + substDotNode1 = new dot_node(substDotNode, parts.Pop()); + } + } + + var substKey = new SubstitutionKey(varName, syntaxTreeNodeWithVarDeclaration, + scope.ChildNodes[0].CorrespondingSyntaxTreeNode); + if (!_substitutions.ContainsKey(substKey)) + { + _substitutions.Add(substKey, substDotNode1); + } + + AddReferencesToIdentInLambda(_capturedVarsClassDefs[scopeAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value].ClassDeclaration, scopeAsLambda.ChildNodes[0], varName, syntaxTreeNodeWithVarDeclaration, substDotNode1, true); + } + else + { + AddReferencesToIdentInLambda(upperScopeWhereVarsAreCapturedClass, scope.ChildNodes[0], varName, syntaxTreeNodeWithVarDeclaration, substDotNode, nestedLambda); + } } } } @@ -524,8 +648,7 @@ namespace TreeConverter.LambdaExpressions.Closure currentNode)); } - // TODO: тут предусматривать разные случаи - + var vars = variablesFromThisScopeWhichWereCaptured .Select(field => field.SymbolInfo.sym_info as IVAriableDefinitionNode) .ToList(); @@ -571,7 +694,6 @@ namespace TreeConverter.LambdaExpressions.Closure if (variablesFromThisScopeWhichWereCaptured.Count > 0) { - // TODO: тут предусматривать разные случаи var vars = variablesFromThisScopeWhichWereCaptured .Select(x => new @@ -586,7 +708,13 @@ namespace TreeConverter.LambdaExpressions.Closure { foreach (CapturedVariablesTreeNode childNode in currentNode.ChildNodes) { - RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariable(childNode, var.IVarDefinitionNode.name, var.VarDeclNode); + _rewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo.Add( + new RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo + { + TreeNode = childNode, + Varname = var.IVarDefinitionNode.name, + NodeWithVarDecl = var.VarDeclNode + }); } } } @@ -594,9 +722,15 @@ namespace TreeConverter.LambdaExpressions.Closure private void RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariable(CapturedVariablesTreeNode node, string varName, syntax_tree_node nodeWithVarDecl) { + if (node is CapturedVariablesTreeNodeLambdaScope) + { + RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariable(node.ChildNodes[0], varName, nodeWithVarDecl); + return; + } + if (!(node is CapturedVariablesTreeNodeBlockScope || node is CapturedVariablesTreeNodeForScope || - node is CapturedVariablesTreeNodeForEachScope)) // Добавляем ссылки только для скоупов-блоков и циклов, потому что остальные случаи должны были уже быть рассмотрены (когда эти случаи буду реализованы) + node is CapturedVariablesTreeNodeForEachScope)) { return; } @@ -637,6 +771,17 @@ namespace TreeConverter.LambdaExpressions.Closure { VisitTreeAndBuildClassDefinitions(_capturedVariablesRootTreeNode); + foreach (var ls in _lambdaIdReferences.Where(x => x.LambdaScope.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue)) + { + AddReferencesToIdentInLambda(_capturedVarsClassDefs[ls.LambdaScope.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value].ClassDeclaration, + ls.LambdaScope.ChildNodes[0], ls.VarName, ls.SyntaxTreeNodeWithVarDeclaration, ls.DotNode, false); + } + + foreach (var r in _rewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariableInfo) + { + RewriteReferencesForNodesThatAreChildNodesToThoseThatContainCapturedVariable(r.TreeNode, r.Varname, r.NodeWithVarDecl); + } + return new VariableSubstitutionsInfo { GeneratedScopeClassesInfo = _capturedVarsClassDefs, diff --git a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesSubstitutor.cs b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesSubstitutor.cs index 9f805a401..2054cd0ca 100644 --- a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesSubstitutor.cs +++ b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesSubstitutor.cs @@ -232,6 +232,34 @@ namespace TreeConverter.LambdaExpressions.Closure SubstituteInNode(currentBlock, node); } + private List GetNestedLambdasToBeAddedToThisClass(CapturedVariablesTreeNode scope) + { + var res = new List(); + + foreach (var child in scope.ChildNodes) + { + var childAsLambda = child as CapturedVariablesTreeNodeLambdaScope; + if (childAsLambda == null) + { + res.AddRange(GetNestedLambdasToBeAddedToThisClass(child)); + } + else + { + if (childAsLambda.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.HasValue) + { + continue; + } + else + { + res.Add(childAsLambda); + res.AddRange(GetNestedLambdasToBeAddedToThisClass(childAsLambda)); + } + } + } + + return res; + } + private void SubstituteLambdas() { for (var i = 0; i < _lambdasToBeAddedAsMethods.Count; i++) @@ -239,21 +267,30 @@ namespace TreeConverter.LambdaExpressions.Closure if (_lambdasToBeAddedAsMethods[i].ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod != null) { var classDef = _generatedScopeClassesInfo[_lambdasToBeAddedAsMethods[i].ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod.Value]; - + if (classDef.CorrespondingTreeNode is CapturedVariablesTreeNodeClassScope) { continue; } + + var otherLambdasToBeAddedAsMethods = + GetNestedLambdasToBeAddedToThisClass(_lambdasToBeAddedAsMethods[i]); + classDef.NestedLambdas.AddRange(otherLambdasToBeAddedAsMethods); + + foreach (var oltaam in otherLambdasToBeAddedAsMethods) + { + oltaam.LambdaDefinition.substituting_node = new ident(oltaam.LambdaDefinition.lambda_name); + } var left = new ident(classDef.GeneratedSubstitutingFieldName); var lambdaDef = _lambdasToBeAddedAsMethods[i].LambdaDefinition; lambdaDef.substituting_node = new dot_node(left, new ident(lambdaDef.lambda_name)); - var classDecl = (class_definition)classDef.ClassDeclaration.type_def; + /*var classDecl = (class_definition)classDef.ClassDeclaration.type_def; var procDecl = LambdaHelper.ConvertLambdaNodeToProcDefNode(lambdaDef); - classDecl.body.Add(SyntaxTreeBuilder.BuildOneMemberSection(procDecl)); + classDecl.body.Add(SyntaxTreeBuilder.BuildOneMemberSection(procDecl));*/ } } } @@ -370,6 +407,44 @@ namespace TreeConverter.LambdaExpressions.Closure } } + private void SubstituteLambdaParameters() + { + var lambdaScopes = + _capturedVarsTreeNodesDictionary.Where(n => n.Value is CapturedVariablesTreeNodeLambdaScope) + .Select(n => (CapturedVariablesTreeNodeLambdaScope)n.Value) + .ToList(); + + foreach (var lambdaScope in lambdaScopes) + { + CapturedVariablesSubstitutionClassGenerator.ScopeClassDefinition generatedClass; + if (_generatedScopeClassesInfo.TryGetValue(lambdaScope.ScopeIndex, out generatedClass)) + { + + var nodesToAdd = new List(); + nodesToAdd.Add(generatedClass.GeneratedVarStatementForScope); + if (generatedClass.AssignNodeForUpperClassFieldInitialization != null) + { + nodesToAdd.Add(generatedClass.AssignNodeForUpperClassFieldInitialization); + } + + var variables = lambdaScope + .VariablesDefinedInScope + .Where(l => l.ReferencingLambdas.Count > 0) + .Select(var => ((IVAriableDefinitionNode) var.SymbolInfo.sym_info).name.ToLower()) + .ToList(); + + foreach (var variable in variables) + { + var assignStmt = new assign(new dot_node(new ident(generatedClass.GeneratedSubstitutingFieldName), + new ident(variable)), new ident(variable)); + nodesToAdd.Add(assignStmt); + } + + ((statement_list)lambdaScope.LambdaDefinition.proc_body).subnodes.InsertRange(0, nodesToAdd); + } + } + } + private void SubstituteVariablesDeclarations() { var classDefsTreeNodes = _generatedScopeClassesInfo.Join(_capturedVarsTreeNodesDictionary, @@ -489,16 +564,105 @@ namespace TreeConverter.LambdaExpressions.Closure } } - private void VisitClassDefinitions() + private Tuple> CreateTypeDeclarationWithForwardDeclaration(type_declaration cl) + { + var oldClDef = (class_definition) cl.type_def; + var classDef = SyntaxTreeBuilder.BuildClassDefinition(true); + var typeDeclaration = new type_declaration(cl.type_name, classDef); + classDef.where_section = oldClDef.where_section; + var procedures = new List(); + var classMembers = new class_members(access_modifer.public_modifer); + classDef.body.class_def_blocks.Add(classMembers); + + foreach (var member in oldClDef.body.class_def_blocks.SelectMany(x => x.members)) + { + if (member is var_def_statement) + { + classMembers.Add(member); + } + else + { + var procDef = (procedure_definition) member; + if (procDef.proc_header is constructor) + { + classMembers.Add(procDef); + continue; + } + procedure_header procHeader; + if (procDef.proc_header is function_header) + { + var fh = (function_header) procDef.proc_header; + procHeader = new function_header + { + name = new method_name(fh.name.meth_name.name), + source_context = fh.source_context, + parameters = fh.parameters, + of_object = fh.of_object, + class_keyword = fh.class_keyword + }; + ((function_header)procHeader).return_type = fh.return_type; + } + else + { + procHeader = new procedure_header + { + name = new method_name(procDef.proc_header.name.meth_name.name), + source_context = procDef.proc_header.source_context, + parameters = procDef.proc_header.parameters, + of_object = procDef.proc_header.of_object, + class_keyword = procDef.proc_header.class_keyword + }; + } + + procDef.proc_header.name.class_name = cl.type_name; + procedures.Add(procDef); + classMembers.Add(procHeader); + } + } + + return new Tuple>(typeDeclaration, procedures); + } + + private List VisitClassDefinitions() { _visitor.context.SaveContextAndUpToGlobalLevel(); _visitor.lambdaProcessingState = LambdaProcessingState.ClosuresProcessingVisitGeneratedClassesPhase; - foreach (var clDecl in _generatedScopeClassesInfo.Where(cd => !(cd.Value.CorrespondingTreeNode is CapturedVariablesTreeNodeClassScope))) + var procedures = new List(); + var lambdaGroups = + _lambdasToBeAddedAsMethods.GroupBy(l => l.ScopeIndexOfClassWhereLambdaWillBeAddedAsMethod) + .ToDictionary(x => x.Key, x => x.ToList()); + foreach (var clDecl in _generatedScopeClassesInfo.Where(cd => !(cd.Value.CorrespondingTreeNode is CapturedVariablesTreeNodeClassScope)).OrderBy(cd => cd.Key)) { - _visitor.visit(clDecl.Value.ClassDeclaration); - } + var lambdas = clDecl.Value.NestedLambdas; + List ls; + if (lambdaGroups.TryGetValue(clDecl.Key, out ls)) + { + lambdas = lambdas.Concat(ls).ToList(); + } + var classDecl = (class_definition)clDecl.Value.ClassDeclaration.type_def; + foreach (var lambdaDef in lambdas) + { + var procDecl = LambdaHelper.ConvertLambdaNodeToProcDefNode(lambdaDef.LambdaDefinition); + classDecl.body.Add(SyntaxTreeBuilder.BuildOneMemberSection(procDecl)); + } + var cl = CreateTypeDeclarationWithForwardDeclaration(clDecl.Value.ClassDeclaration); + procedures.AddRange(cl.Item2); + _visitor.visit(cl.Item1); + } + + _visitor.context.RestoreCurrentContext(); + _visitor.lambdaProcessingState = LambdaProcessingState.ClosuresProcessingPhase; + + return procedures; + } + + private void VisitProceduresOfClasses(List procedures) + { + _visitor.context.SaveContextAndUpToGlobalLevel(); + _visitor.lambdaProcessingState = LambdaProcessingState.ClosuresProcessingVisitGeneratedClassesPhase; + procedures.ForEach(p => _visitor.visit(p)); _visitor.context.RestoreCurrentContext(); _visitor.lambdaProcessingState = LambdaProcessingState.ClosuresProcessingPhase; } @@ -581,9 +745,15 @@ namespace TreeConverter.LambdaExpressions.Closure /* Предусмотреть случай, когда захвата переменных не происходит, но мы все равно находимся в лямбде - это нужно сделать на FinishPhase в syntax_tree_visitor /* Не забыть про where секцию */ - for (var i = 0; i < _lambdasToBeAddedAsMethods.Count; i++) + var nestedLambdas = new List(); + foreach (var cl in _generatedScopeClassesInfo.Where(cd => !(cd.Value.CorrespondingTreeNode is CapturedVariablesTreeNodeClassScope))) { - var lambdaDef = _lambdasToBeAddedAsMethods[i].LambdaDefinition; + nestedLambdas.AddRange(cl.Value.NestedLambdas); + } + + foreach (CapturedVariablesTreeNodeLambdaScope t in _lambdasToBeAddedAsMethods.Concat(nestedLambdas)) + { + var lambdaDef = t.LambdaDefinition; if (lambdaDef.formal_parameters != null && lambdaDef.formal_parameters.params_list.Count > 0) { for (var j = 0; j < lambdaDef.formal_parameters.params_list.Count; j++) @@ -716,8 +886,17 @@ namespace TreeConverter.LambdaExpressions.Closure { get { - return _visitor.context.top_function != null && _visitor.context.top_function.generic_params != null || - _visitor.context._ctn != null && _visitor.context._ctn.generic_params != null; + var funcStackAsList = _visitor.context.func_stack == null + ? null + : _visitor.context.func_stack.CloneInternalStack().ToList(); + + var funcIsGeneric = false; + if (funcStackAsList != null) + { + funcIsGeneric = funcStackAsList.FirstOrDefault(f => f.generic_params != null) != null; + } + + return funcIsGeneric || _visitor.context._ctn != null && _visitor.context._ctn.generic_params != null; } } @@ -738,11 +917,19 @@ namespace TreeConverter.LambdaExpressions.Closure res.AddRange(_visitor.context._ctn.generic_params.Select(par => new ident(par.name))); } - if (_visitor.context.top_function != null && _visitor.context.top_function.generic_params != null) - { - res.AddRange(_visitor.context.top_function.generic_params.Select(par => new ident(par.name))); - } + var funcStackAsList = _visitor.context.func_stack == null + ? null + : _visitor.context.func_stack.CloneInternalStack().ToList(); + if (funcStackAsList != null) + { + var funcGeneric = funcStackAsList.FirstOrDefault(f => f.generic_params != null); + if (funcGeneric != null) + { + res.AddRange(funcGeneric.generic_params.Select(par => new ident(par.name))); + } + } + return res; } } @@ -856,14 +1043,16 @@ namespace TreeConverter.LambdaExpressions.Closure { OnLeave += OnNodeLeave; ProcessNode(statementList); - SubstituteTypesInCaseOfGenerics(); SubstituteLambdas(); + SubstituteTypesInCaseOfGenerics(); AddPropertiesToConvertingClass(); - VisitClassDefinitions(); + var procedures = VisitClassDefinitions(); SubstituteVariablesDeclarations(); SubstituteForLoopVariables(); SubstituteForEachLoopVariables(); SubstituteVarDefInProcedure(statementList); + //SubstituteLambdaParameters(); + VisitProceduresOfClasses(procedures); } } } \ No newline at end of file diff --git a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs index 13f317a21..2419aa7ca 100644 --- a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs +++ b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs @@ -16,7 +16,7 @@ namespace TreeConverter.LambdaExpressions.Closure private readonly syntax_tree_visitor _visitor; private CapturedVariablesTreeNode _currentTreeNode; private readonly Dictionary _scopesCapturedVarsNodesDictionary; - private CapturedVariablesTreeNodeLambdaScope _currentLambdaScopeNode; //TODO Пересмотреть для вложенных лямбд + private Stack _currentLambdaScopeNodeStack = new Stack(); private readonly Dictionary> _identsReferences; private CapturedVariablesTreeNode _rootNode; private CapturedVariablesTreeNodeClassScope _classScope; @@ -49,6 +49,13 @@ namespace TreeConverter.LambdaExpressions.Closure } } + private bool InLambdaContext + { + get + { + return _currentLambdaScopeNodeStack.Count > 0; + } + } public CapturedVariablesTreeBuilder(syntax_tree_visitor visitor) { _visitor = visitor; @@ -125,7 +132,7 @@ namespace TreeConverter.LambdaExpressions.Closure if (si == null) { - if (_currentLambdaScopeNode != null) + if (InLambdaContext) { _visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id))); return; @@ -154,13 +161,13 @@ namespace TreeConverter.LambdaExpressions.Closure si.sym_info.semantic_node_type == semantic_node_type.common_parameter || si.sym_info.semantic_node_type == semantic_node_type.class_field; - if (!(acceptableVarType) && _currentLambdaScopeNode != null) + if (!(acceptableVarType) && InLambdaContext) { _visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id))); return; } - if (si.sym_info.semantic_node_type == semantic_node_type.class_field && _currentLambdaScopeNode != null) + if (si.sym_info.semantic_node_type == semantic_node_type.class_field && InLambdaContext) { var semClassField = (class_field)si.sym_info; if (semClassField.polymorphic_state != polymorphic_state.ps_common) @@ -186,12 +193,12 @@ namespace TreeConverter.LambdaExpressions.Closure { if (si.sym_info.semantic_node_type == semantic_node_type.local_variable) { - if (!(idName == compiler_string_consts.self_word && si.scope is SymbolTable.ClassMethodScope && _classScope != null) && _currentLambdaScopeNode != null) + if (!(idName == compiler_string_consts.self_word && si.scope is SymbolTable.ClassMethodScope && _classScope != null) && InLambdaContext) { _visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id))); } } - if (si.sym_info.semantic_node_type == semantic_node_type.common_parameter && prScope.FunctionNode.parameters.First(v => v.name.ToLower() == idName).parameter_type != parameter_type.value && _currentLambdaScopeNode != null) + if (si.sym_info.semantic_node_type == semantic_node_type.common_parameter && prScope.FunctionNode.parameters.First(v => v.name.ToLower() == idName).parameter_type != parameter_type.value && InLambdaContext) { _visitor.AddError(new CannotCaptureNonValueParameters(_visitor.get_location(id))); } @@ -268,19 +275,43 @@ namespace TreeConverter.LambdaExpressions.Closure _identsReferences[substKey].Add(id); } - if (_currentLambdaScopeNode == null || - scopeIndex >= _currentLambdaScopeNode.ScopeIndex) + if (InLambdaContext && scope is CapturedVariablesTreeNodeLambdaScope && + scopeIndex < _currentLambdaScopeNodeStack.Peek().ScopeIndex) //TODO: Захват параметров лямбды в другой лямбде + { + _visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id))); + return; + } + + if (!InLambdaContext || + scopeIndex >= _currentLambdaScopeNodeStack.Peek().ScopeIndex) { return; } - if (!_currentLambdaScopeNode.CapturedVarsSymbolInfo.Contains(si)) + var stackAsList = _currentLambdaScopeNodeStack.ToList(); + stackAsList.RemoveAt(0); + + if (!_currentLambdaScopeNodeStack.Peek().CapturedVarsSymbolInfo.Contains(si)) { - _currentLambdaScopeNode.CapturedVarsSymbolInfo.Add(si); + _currentLambdaScopeNodeStack.Peek().CapturedVarsSymbolInfo.Add(si); + foreach (var capturedVariablesTreeNodeLambdaScope in stackAsList) + { + if (!capturedVariablesTreeNodeLambdaScope.CapturedVarsSymbolInfo.Contains(si)) + { + capturedVariablesTreeNodeLambdaScope.CapturedVarsSymbolInfo.Add(si); + } + } } - if (!idRef.ReferencingLambdas.Contains(_currentLambdaScopeNode)) + if (!idRef.ReferencingLambdas.Contains(_currentLambdaScopeNodeStack.Peek())) { - idRef.ReferencingLambdas.Add(_currentLambdaScopeNode); + idRef.ReferencingLambdas.Add(_currentLambdaScopeNodeStack.Peek()); + foreach (var capturedVariablesTreeNodeLambdaScope in stackAsList) + { + if (!idRef.ReferencingLambdas.Contains(capturedVariablesTreeNodeLambdaScope)) + { + idRef.ReferencingLambdas.Add(capturedVariablesTreeNodeLambdaScope); + } + } } } } @@ -529,14 +560,14 @@ namespace TreeConverter.LambdaExpressions.Closure _visitor.context.func_stack.top().scope.ScopeNum, lambdaDefinition); _currentTreeNode.LambdasDefinedInScope.Add(newTreeNode); - _currentLambdaScopeNode = newTreeNode; + _currentLambdaScopeNodeStack.Push(newTreeNode); if (_currentTreeNode != null) { _currentTreeNode.ChildNodes.Add(newTreeNode); } _currentTreeNode = newTreeNode; - + _scopesCapturedVarsNodesDictionary.Add(_currentTreeNode.ScopeIndex, _currentTreeNode); VisitProcParameters(procDecl.proc_header.parameters); ProcessNode(procDecl.proc_body); @@ -545,7 +576,7 @@ namespace TreeConverter.LambdaExpressions.Closure _visitor.context.remove_lambda_function(procDecl.proc_header.name.meth_name.name, false); _currentTreeNode = _currentTreeNode.ParentNode; - _currentLambdaScopeNode = null; //TODO: Вложенные лямбды - изменить это + _currentLambdaScopeNodeStack.Pop(); LambdaHelper.RemoveLambdaInfoFromCompilationContext(_visitor.context, lambdaDefinition); } diff --git a/TreeConverter/TreeConversion/compilation_context.cs b/TreeConverter/TreeConversion/compilation_context.cs index 4889fe6ec..686e711cb 100644 --- a/TreeConverter/TreeConversion/compilation_context.cs +++ b/TreeConverter/TreeConversion/compilation_context.cs @@ -1048,12 +1048,6 @@ namespace PascalABCCompiler.TreeConverter { var func_stack_as_array = _func_stack.CloneInternalStack().ToList(); - var upperLambda = func_stack_as_array.FirstOrDefault(func => LambdaHelper.IsLambdaName(func.name)); - if (upperLambda != null) - { - syntax_tree_visitor.AddError(new NestedLambdasAreNotSupportedInThisVersionOfCompiler(def_loc)); - } - var nestedFunc = func_stack_as_array.FirstOrDefault(func => func is common_in_function_function_node); if (nestedFunc != null) { diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index cb273e519..fb96f8351 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -5082,26 +5082,159 @@ namespace PascalABCCompiler.TreeConverter if (lambdas_are_in_parameters) { LambdaHelper.processingLambdaParametersForTypeInference++; - function_node ffn = convertion_data_and_alghoritms.select_function(exprs, si, subloc, syntax_nodes_parameters); - int exprCounter = 0; - if (skip_first_parameter) + // SSM 21.05.14 - попытка обработать перегруженные функции с параметрами-лямбдами с различными возвращаемыми значениями + function_node_list spf = null; + try { - exprCounter++; - } - foreach (SyntaxTree.expression en in _method_call.parameters.expressions) - { - if (!(en is SyntaxTree.function_lambda_definition)) + function_node ffn = convertion_data_and_alghoritms.select_function(exprs, si, subloc, syntax_nodes_parameters); + int exprCounter = 0; + if (skip_first_parameter) { exprCounter++; - continue; } - else + foreach (SyntaxTree.expression en in _method_call.parameters.expressions) { - LambdaHelper.InferTypesFromVarStmt(ffn.parameters[exprCounter].type, en as SyntaxTree.function_lambda_definition, this); - exprs[exprCounter] = convert_strong(en); - exprCounter++; + 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; // первый номер правильно инстанцированной. Если потом встретился второй, то тоже ошибка + 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); + } + 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; + } + + spfnum = i; + for (int j = 0; j < exprs.Count; j++) // копируем назад если всё хорошо + exprs[j] = exprs1[j]; + } + catch (Exception e) + { + // если сюда попали, значит, не вывели типы в лямбде и надо эту инстанцию пропускать + //contextChanger.RestoreCurrentContext(); + lastmultex = e; + } + } + if (spfnum == -2) // два удачных инстанцирования - плохо. Может, одно - с более близким типом возвращаемого значения, тогда это плохо - надо доделать, но пока так + throw new SeveralFunctionsCanBeCalled(subloc, spf); + if (spfnum == -1) // было много, но ни одна не подошла из-за лямбд + { + throw lastmultex; + //throw new NoFunctionWithSameArguments(subloc2, false); + } + + var 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// @@ -6022,8 +6155,11 @@ namespace PascalABCCompiler.TreeConverter } else { - LambdaHelper.InferTypesFromVarStmt(fn.parameters[exprCounter].type, en as SyntaxTree.function_lambda_definition, this); + var enLambda = (SyntaxTree.function_lambda_definition) en; + LambdaHelper.InferTypesFromVarStmt(fn.parameters[exprCounter].type, enLambda, this); + enLambda.lambda_visit_mode = LambdaVisitMode.VisitForAdvancedMethodCallProcessing; exprs[exprCounter] = convert_strong(en); + enLambda.lambda_visit_mode = LambdaVisitMode.VisitForInitialMethodCallProcessing; exprCounter++; } } @@ -6085,8 +6221,13 @@ namespace PascalABCCompiler.TreeConverter { exprs1[exprCounter] = convert_strong(en); } + catch + { + throw; + } finally { + LambdaHelper.RemoveLambdaInfoFromCompilationContext(context, en as function_lambda_definition); // восстанавливаем сохраненный тип возвращаемого значения if (restype != null) restype.real_type = realrestype; @@ -6121,7 +6262,6 @@ namespace PascalABCCompiler.TreeConverter // если сюда попали, значит, не вывели типы в лямбде и надо эту инстанцию пропускать //contextChanger.RestoreCurrentContext(); lastmultex = e; - context.converted_namespace.functions.remove_at(context.converted_namespace.functions.Count - 1); } } if (spfnum == -2) // два удачных инстанцирования - плохо. Может, одно - с более близким типом возвращаемого значения, тогда это плохо - надо доделать, но пока так @@ -10565,7 +10705,7 @@ namespace PascalABCCompiler.TreeConverter if ((context.top_function.semantic_node_type == semantic_node_type.common_method_node) || ((context.func_stack_size_is_one()) && (_is_interface_part))) { - context.leave_block(); + //context.leave_block(); } } body_exists = false; @@ -16154,9 +16294,11 @@ namespace PascalABCCompiler.TreeConverter } else { - LambdaHelper.InferTypesFromVarStmt(fn.parameters[exprCounter].type, - en as SyntaxTree.function_lambda_definition, this); + var enLambda = (SyntaxTree.function_lambda_definition)en; + LambdaHelper.InferTypesFromVarStmt(fn.parameters[exprCounter].type, enLambda, this); + enLambda.lambda_visit_mode = LambdaVisitMode.VisitForAdvancedMethodCallProcessing; exprs[exprCounter] = convert_strong(en); + enLambda.lambda_visit_mode = LambdaVisitMode.VisitForInitialMethodCallProcessing; exprCounter++; } } @@ -16226,8 +16368,13 @@ namespace PascalABCCompiler.TreeConverter { exprs1[exprCounter] = convert_strong(en); } + catch + { + throw; + } finally { + LambdaHelper.RemoveLambdaInfoFromCompilationContext(context, en as function_lambda_definition); // восстанавливаем сохраненный тип возвращаемого значения if (restype != null) restype.real_type = realrestype; @@ -16265,8 +16412,6 @@ namespace PascalABCCompiler.TreeConverter // если сюда попали, значит, не вывели типы в лямбде и надо эту инстанцию пропускать //contextChanger.RestoreCurrentContext(); lastmultex = e; - context.converted_namespace.functions.remove_at( - context.converted_namespace.functions.Count - 1); } } if (spfnum == -2)