Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/Compiler.Tests/CodeAnalysis/Syntax/Binding/BinderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>()
{
};

AssertDiagnostics(text, diagnostics);
}

private Compilation AssertDiagnostics(string text, List<string> expectedDiagnostics, bool generateGraph = false)
{
Expand Down
25 changes: 11 additions & 14 deletions src/Compiler/CodeAnalysis/Binding/Binder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public static BoundGlobalScope BindGlobalScope(ImmutableArray<SyntaxTree> syntax
.OfType<FunctionDeclarationSyntax>();
foreach (var functionSyntax in functionDeclarations)
{
var function = binder.BindFunctionDeclaration(functionSyntax);
var function = binder.BindFunctionDeclaration(functionSyntax, null);
binder.Diagnostics.AddRange(function.BoundScope!.Diagnostics);
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -160,7 +151,7 @@ private static BoundProgram EmptyProgram(BoundGlobalScope globalScope)
ImmutableArray<TypeSymbol>.Empty);
}

private FunctionSymbol BindFunctionDeclaration(FunctionDeclarationSyntax syntax)
private FunctionSymbol BindFunctionDeclaration(FunctionDeclarationSyntax syntax, List<FunctionSymbol>? functionsToLower)
{
var parameters = ImmutableArray.CreateBuilder<VariableSymbol>();
var seenParameterNames = new HashSet<string>();
Expand All @@ -180,6 +171,12 @@ private FunctionSymbol BindFunctionDeclaration(FunctionDeclarationSyntax syntax)
}
}

var localFunctions = syntax.Body.Statements.OfType<FunctionDeclarationSyntax>();
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,
Expand All @@ -190,6 +187,7 @@ private FunctionSymbol BindFunctionDeclaration(FunctionDeclarationSyntax syntax)
receiver);

_scope.TryDeclareFunction(function);
functionsToLower?.Add(function);
return function;
}

Expand Down Expand Up @@ -246,8 +244,7 @@ private void BindMemberBlockStatement(MemberBlockStatementSyntax syntax, List<Fu

case SyntaxKind.FunctionDeclaration:
var functionDeclarationSyntax = (FunctionDeclarationSyntax)statementSyntax;
var functionSymbol = BindFunctionDeclaration(functionDeclarationSyntax);
functionsToLower.Add(functionSymbol);
BindFunctionDeclaration(functionDeclarationSyntax, functionsToLower);
break;

default:
Expand Down Expand Up @@ -313,7 +310,7 @@ private BoundStatement BindBlockStatement(BlockStatementSyntax syntax)
var statements = ImmutableArray.CreateBuilder<BoundStatement>();
_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);
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/CodeAnalysis/Syntax/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ public StatementSyntax ParseStatement()
return ParseContinueStatement();
case SyntaxKind.ReturnKeyword:
return ParseReturnStatement();
case SyntaxKind.FunctionKeyword:
return ParseFunctionDeclaration();
default:
return ParseExpressionStatement();
}
Expand Down