diff --git a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs index e5a59d3..f068a55 100644 --- a/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs +++ b/src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs @@ -1490,6 +1490,28 @@ function main() AssertDiagnostics(text, diagnostics); } + + [Fact] + public void Binder_LocalFunction_Declaration() + { + var text = @" + function a(x : int) + { + b(string(x)) + + function b(x : string) + { + + } + } + "; + + var diagnostics = new List() + { + }; + + AssertDiagnostics(text, diagnostics); + } private Compilation AssertDiagnostics(string text, List expectedDiagnostics, bool generateGraph = false) { diff --git a/src/Compiler/CodeAnalysis/Binding/Binder.cs b/src/Compiler/CodeAnalysis/Binding/Binder.cs index dbebd67..07f448f 100644 --- a/src/Compiler/CodeAnalysis/Binding/Binder.cs +++ b/src/Compiler/CodeAnalysis/Binding/Binder.cs @@ -63,7 +63,7 @@ public static BoundGlobalScope BindGlobalScope(ImmutableArray syntax .OfType(); foreach (var functionSyntax in functionDeclarations) { - var function = binder.BindFunctionDeclaration(functionSyntax); + var function = binder.BindFunctionDeclaration(functionSyntax, null); binder.Diagnostics.AddRange(function.BoundScope!.Diagnostics); } @@ -123,15 +123,6 @@ public static BoundProgram BindProgram(BoundGlobalScope globalScope) foreach (var function in functionsToLower) { - // Structs generate declartions for their constructors. However, these have no function bodies. - // We will skip attempting to lower the bodies for these and allow the Emitter to automatically - // generate the code necessary. This will avoid the potential of reporting diagnostic errors to - // the user for code they never wrote. - if (function.ReturnType is StructSymbol && function.Name.EndsWith(".ctor")) - { - continue; - } - Debug.Assert(function.BoundScope != null); var binder = new Binder(function.BoundScope, function, function.Receiver); var body = binder.BindStatement(function.Declaration!.Body); @@ -160,7 +151,7 @@ private static BoundProgram EmptyProgram(BoundGlobalScope globalScope) ImmutableArray.Empty); } - private FunctionSymbol BindFunctionDeclaration(FunctionDeclarationSyntax syntax) + private FunctionSymbol BindFunctionDeclaration(FunctionDeclarationSyntax syntax, List? functionsToLower) { var parameters = ImmutableArray.CreateBuilder(); var seenParameterNames = new HashSet(); @@ -180,6 +171,12 @@ private FunctionSymbol BindFunctionDeclaration(FunctionDeclarationSyntax syntax) } } + var localFunctions = syntax.Body.Statements.OfType(); + foreach (var localFunction in localFunctions) + { + BindFunctionDeclaration(localFunction, functionsToLower); + } + var returnType = BindTypeClause(syntax.Type) ?? TypeSymbol.Void; var receiver = _type; var function = new FunctionSymbol(syntax.Identifier.Text, @@ -190,6 +187,7 @@ private FunctionSymbol BindFunctionDeclaration(FunctionDeclarationSyntax syntax) receiver); _scope.TryDeclareFunction(function); + functionsToLower?.Add(function); return function; } @@ -246,8 +244,7 @@ private void BindMemberBlockStatement(MemberBlockStatementSyntax syntax, List(); _scope = new BlockBoundScope(_scope); - foreach (var statementSyntax in syntax.Statements) + foreach (var statementSyntax in syntax.Statements.Where(s => s.Kind != SyntaxKind.FunctionDeclaration)) { var statement = BindStatement(statementSyntax); statements.Add(statement); diff --git a/src/Compiler/CodeAnalysis/Syntax/Parser.cs b/src/Compiler/CodeAnalysis/Syntax/Parser.cs index 73110b2..a2419b8 100644 --- a/src/Compiler/CodeAnalysis/Syntax/Parser.cs +++ b/src/Compiler/CodeAnalysis/Syntax/Parser.cs @@ -359,6 +359,8 @@ public StatementSyntax ParseStatement() return ParseContinueStatement(); case SyntaxKind.ReturnKeyword: return ParseReturnStatement(); + case SyntaxKind.FunctionKeyword: + return ParseFunctionDeclaration(); default: return ParseExpressionStatement(); }