@@ -34,7 +34,7 @@ internal class ExpressionNodeVisitor : VBasic.VisualBasicSyntaxVisitor<Task<CSha
3434 private readonly bool _optionCompareText = false ;
3535 private readonly VisualBasicEqualityComparison _visualBasicEqualityComparison ;
3636 private readonly Stack < ExpressionSyntax > _withBlockLhs = new Stack < ExpressionSyntax > ( ) ;
37- private readonly AdditionalLocals _additionalLocals ;
37+ private readonly HoistedNodeState _additionalLocals ;
3838 private readonly MethodsWithHandles _methodsWithHandles ;
3939 private readonly QueryConverter _queryConverter ;
4040 private readonly Lazy < IDictionary < ITypeSymbol , string > > _convertMethodsLookupByReturnType ;
@@ -43,7 +43,7 @@ internal class ExpressionNodeVisitor : VBasic.VisualBasicSyntaxVisitor<Task<CSha
4343 private INamedTypeSymbol _vbBooleanTypeSymbol ;
4444
4545 public ExpressionNodeVisitor ( SemanticModel semanticModel ,
46- VisualBasicEqualityComparison visualBasicEqualityComparison , AdditionalLocals additionalLocals ,
46+ VisualBasicEqualityComparison visualBasicEqualityComparison , HoistedNodeState additionalLocals ,
4747 Compilation csCompilation , MethodsWithHandles methodsWithHandles , CommonConversions commonConversions ,
4848 HashSet < string > extraUsingDirectives )
4949 {
@@ -817,20 +817,20 @@ private async Task<CSharpSyntaxNode> WithRemovedRedundantConversionOrNull(VBSynt
817817 public override async Task < CSharpSyntaxNode > VisitInvocationExpression (
818818 VBasic . Syntax . InvocationExpressionSyntax node )
819819 {
820- var invocationSymbol = _semanticModel . GetSymbolInfo ( node ) . ExtractBestMatch < ISymbol > ( ) ;
821- var withinLocalFunction = RequiresLocalFunction ( node , invocationSymbol as IMethodSymbol ) ;
820+ var invocationSymbol = _semanticModel . GetSymbolInfo ( node ) . ExtractBestMatch < IMethodSymbol > ( ) ;
821+ var withinLocalFunction = RequiresLocalFunction ( node , invocationSymbol ) ;
822822 if ( withinLocalFunction ) {
823823 _additionalLocals . PushScope ( ) ;
824824 }
825825 try {
826826 var convertedInvocation = await ConvertInvocation ( node , invocationSymbol ) ;
827827 if ( withinLocalFunction ) {
828-
828+ return await HoistAndCallLocalFunction ( node , invocationSymbol , ( ExpressionSyntax ) convertedInvocation ) ;
829829 }
830830 return await ConvertInvocation ( node , invocationSymbol ) ;
831831 } finally {
832832 if ( withinLocalFunction ) {
833- _additionalLocals . PopScope ( ) ;
833+ _additionalLocals . PopExpressionScope ( ) ;
834834 }
835835 }
836836 }
@@ -919,27 +919,26 @@ async Task<CSharpSyntaxNode> CreateElementAccess()
919919 /// <param name="invocation"></param>
920920 /// <param name="invocationSymbol"></param>
921921 /// <returns></returns>
922- //private async Task<(string Id, StatementSyntax FunctionDeclaration)> CreateLocalByRefFunction(VBSyntax.InvocationExpressionSyntax invocation, IMethodSymbol invocationSymbol)
923- //{
924- // RequiresLocalFunction(invocation, invocationSymbol);
925-
926- // var localFuncName = $"local{invocationSymbol.Name}";
927- // const string retVariableName = "ret";
928- // var localFuncId = SyntaxFactory.IdentifierName(localFuncName);
929- // // Need essentially the original invocation with any byref args swapped out for temporaries
930- // var callAndStoreResult = CommonConversions.CreateLocalVariableDeclarationAndAssignment(retVariableName,
931- // SyntaxFactory.InvocationExpression(expression,
932- // );
933-
934- // var block = SyntaxFactory.Block(
935- // callAndStoreResult,
936- // AssignStmt(expression, tempArg),
937- // SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName(retVariableName))
938- // );
939- // var localfunction = SyntaxFactory.LocalFunctionStatement(CommonConversions.GetTypeSyntax(invocationSymbol.ReturnType),
940- // localFuncId.Identifier).WithBody(block);
941- // return (localFuncName, localfunction);
942- //}
922+ private async Task < InvocationExpressionSyntax > HoistAndCallLocalFunction ( VBSyntax . InvocationExpressionSyntax invocation , IMethodSymbol invocationSymbol , ExpressionSyntax csExpression )
923+ {
924+ const string retVariableName = "ret" ;
925+ var localFuncName = $ "local{ invocationSymbol . Name } ";
926+ var generatedNames = new HashSet < string > ( ) ; //TODO: Populate from local scope
927+
928+ var callAndStoreResult = CommonConversions . CreateLocalVariableDeclarationAndAssignment ( retVariableName , csExpression ) ;
929+
930+ var statements = await _additionalLocals . CreateLocals ( invocation , new [ ] { callAndStoreResult } , generatedNames , _semanticModel ) ;
931+
932+ var localFuncId = SyntaxFactory . IdentifierName ( localFuncName ) ;
933+
934+ var block = SyntaxFactory . Block (
935+ statements . Concat ( SyntaxFactory . ReturnStatement ( SyntaxFactory . IdentifierName ( retVariableName ) ) . Yield ( ) )
936+ ) ;
937+ var localFunction = SyntaxFactory . LocalFunctionStatement ( CommonConversions . GetTypeSyntax ( invocationSymbol . ReturnType ) ,
938+ localFuncId . Identifier ) . WithBody ( block ) ;
939+ _additionalLocals . Hoist ( new HoistedStatement ( localFunction ) ) ;
940+ return SyntaxFactory . InvocationExpression ( localFuncId , SyntaxFactory . ArgumentList ( ) ) ;
941+ }
943942
944943 private bool RequiresLocalFunction ( VBSyntax . InvocationExpressionSyntax invocation , IMethodSymbol invocationSymbol )
945944 {
0 commit comments