Skip to content

No EntryPoint placement builds in every target: C# rejects it at file/namespace scope, C++/Rust lose main inside a namespace, and Rust/Go drop it silently inside a class #128

Description

@matt-edmondson

What's wrong

EntryPoint exists so that "the name, the parameter spelling and the wiring that runs it are the generator's business" (Coder/Ast/EntryPoint.cs). In practice each generator writes it exactly where it sits in the AST, and no placement produces a runnable program in every target:

Where the EntryPoint is C# C++ C Rust Go
SourceFile member public static int Main() at top level: CS0106 ok ok ok ok
NamespaceDeclaration("App") member CS0116 (a namespace can't contain a method) App::main: undefined reference to main at link ok pub mod App { fn main() }: E0601 main function not found ok
ClassDeclaration("Program") member ok member Program::main: undefined reference to main function body inside a typedef struct: syntax error dropped silently (pub struct Program {}) dropped silently (type Program struct{})

C# writes a bare public static … Main in every position (CSharpGenerator.GenerateEntryPoint, Coder/Languages/CSharpGenerator.cs:926-943). EntryPointTests.Schema_TakesAnEntryPointAsAMemberButNotAsAStatement accepts it as a class member on purpose, "which is where C# puts Main", but that is exactly the position C++, C, Rust and Go can't use.

Repro (confirmed with dotnet build / g++ / rustc)

EntryPoint main = new() { ReturnsExitCode = true };
main.Body.Add(new ReturnStatement(new LiteralExpression<int>(0)));
SourceFile file = new("app");
NamespaceDeclaration ns = new("App");
ns.Members.Add(main);
file.Members.Add(ns);
// C#:   namespace App { public static int Main() { return 0; } }  -> CS0116
// C++:  namespace App { int main() { return 0; } }                -> ld: undefined reference to `main'
// Rust: pub mod App { ... fn main() {...} }                       -> error[E0601]

Why it matters

A caller who wants one AST to produce a runnable program in every language has no placement that works. Two of the failures (Rust and Go inside a class) produce no error or note at all: the program just has no entry point.

Suggested fix / acceptance criteria

  • C#: an EntryPoint outside a type is wrapped in public static class Program { … }. Inside a type it stays as it is today.
  • C++ and Rust: an EntryPoint inside a namespace or module is written at file scope, where the toolchain looks for it. For Rust, a root fn main can call App::run.
  • C, C++, Rust and Go: an EntryPoint inside a class is written at file scope, or at least reported with WriteInexpressible, and never dropped silently.
  • At least one placement (e.g. inside a NamespaceDeclaration) is compiled and linked by every language's compile test.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions