Improve entry main diagnostics

This commit is contained in:
sanjin 2026-05-22 13:04:49 +02:00
parent bcfc8d7b68
commit cda20bc895
5 changed files with 136 additions and 11 deletions

View File

@ -0,0 +1,26 @@
# Beta 4 Language Usability
## Scope
This post-`1.0.0-beta.3` slice reduces friction in ordinary project use
without changing the typed core or claiming new syntax stability.
## Current Work
- Improve project/workspace build and run entry diagnostics.
- Keep the accepted entry contract unchanged: `(fn main () -> i32 ...)`.
- Use precise diagnostic codes for missing and invalid entry `main` functions.
## Acceptance Gates
- `cargo test --test project_mode entry_main`
- `cargo fmt --check`
- `git diff --check`
## Deferrals
- No implicit `main` return conversions.
- No argument-taking `main`.
- No async, package registry, or stable ABI/layout promises.
- Broader type aliases, match diagnostics, and destructuring remain candidate
follow-up items in the same language usability roadmap lane.

View File

@ -4156,8 +4156,11 @@ fn add_entry_wrapper(
else {
diagnostics.push(Diagnostic::new(
&entry_module.file,
"MissingImport",
format!("entry module `{}` has no `main` function", manifest.entry),
"ProjectEntryMainMissing",
format!(
"entry module `{}` has no `main` function; build/run require `(fn main () -> i32 ...)`",
manifest.entry
),
));
return;
};
@ -4166,8 +4169,12 @@ fn add_entry_wrapper(
diagnostics.push(
Diagnostic::new(
&entry_module.file,
"MissingImport",
"project entry `main` must have no parameters and return `i32`",
"ProjectEntryMainInvalidSignature",
format!(
"project entry `main` must have signature `(fn main () -> i32 ...)`; found {} parameter(s) and return `{}`",
entry_function.params.len(),
entry_function.return_type
),
)
.with_span(entry_function.span),
);
@ -4229,9 +4236,9 @@ fn add_workspace_entry_wrapper(
else {
diagnostics.push(Diagnostic::new(
&entry_module.file,
"MissingImport",
"WorkspaceEntryMainMissing",
format!(
"entry module `{}` in package `{}` has no `main` function",
"entry module `{}` in package `{}` has no `main` function; build/run require `(fn main () -> i32 ...)`",
package.manifest.entry, package.manifest.name
),
));
@ -4242,8 +4249,12 @@ fn add_workspace_entry_wrapper(
diagnostics.push(
Diagnostic::new(
&entry_module.file,
"MissingImport",
"workspace entry `main` must have no parameters and return `i32`",
"WorkspaceEntryMainInvalidSignature",
format!(
"workspace entry `main` must have signature `(fn main () -> i32 ...)`; found {} parameter(s) and return `{}`",
entry_function.params.len(),
entry_function.return_type
),
)
.with_span(entry_function.span),
);

View File

@ -587,6 +587,68 @@ fn workspace_build_requires_one_entry_package() {
);
}
#[test]
fn workspace_build_reports_entry_main_contract() {
let missing_main = write_workspace(
"workspace-missing-entry-main",
"[workspace]\nmembers = [\"packages/app\"]\n",
&[WorkspacePackageSpec {
member: "packages/app",
manifest: "[package]\nname = \"app\"\nversion = \"0.1.0\"\n",
modules: &[("main", "(module main)\n\n(test \"ok\"\n true)\n")],
}],
);
let missing_binary = unique_path("workspace-missing-entry-main-bin");
let missing_output = run_glagol([
"build".as_ref(),
"-o".as_ref(),
missing_binary.as_os_str(),
missing_main.as_os_str(),
]);
assert_exit_code("workspace missing entry main", &missing_output, 1);
assert_stderr_contains(
"workspace missing entry main",
&missing_output,
"WorkspaceEntryMainMissing",
);
assert_stderr_contains(
"workspace missing entry main",
&missing_output,
"build/run require `(fn main () -> i32 ...)`",
);
let bad_signature = write_workspace(
"workspace-bad-entry-main",
"[workspace]\nmembers = [\"packages/app\"]\n",
&[WorkspacePackageSpec {
member: "packages/app",
manifest: "[package]\nname = \"app\"\nversion = \"0.1.0\"\n",
modules: &[(
"main",
"(module main)\n\n(fn main () -> string\n \"bad\")\n",
)],
}],
);
let bad_binary = unique_path("workspace-bad-entry-main-bin");
let bad_output = run_glagol([
"build".as_ref(),
"-o".as_ref(),
bad_binary.as_os_str(),
bad_signature.as_os_str(),
]);
assert_exit_code("workspace bad entry main", &bad_output, 1);
assert_stderr_contains(
"workspace bad entry main",
&bad_output,
"WorkspaceEntryMainInvalidSignature",
);
assert_stderr_contains(
"workspace bad entry main",
&bad_output,
"found 0 parameter(s) and return `string`",
);
}
#[test]
fn workspace_package_boundaries_are_diagnostics() {
let missing = write_workspace(
@ -1244,7 +1306,16 @@ fn project_build_requires_entry_main_contract() {
missing_main.as_os_str(),
]);
assert_exit_code("missing entry main", &missing_output, 1);
assert_stderr_contains("missing entry main", &missing_output, "MissingImport");
assert_stderr_contains(
"missing entry main",
&missing_output,
"ProjectEntryMainMissing",
);
assert_stderr_contains(
"missing entry main",
&missing_output,
"build/run require `(fn main () -> i32 ...)`",
);
let bad_signature = write_project(
"bad-main-signature",
@ -1259,7 +1330,16 @@ fn project_build_requires_entry_main_contract() {
bad_signature.as_os_str(),
]);
assert_exit_code("bad entry main signature", &bad_output, 1);
assert_stderr_contains("bad entry main signature", &bad_output, "MissingImport");
assert_stderr_contains(
"bad entry main signature",
&bad_output,
"ProjectEntryMainInvalidSignature",
);
assert_stderr_contains(
"bad entry main signature",
&bad_output,
"found 1 parameter(s) and return `i32`",
);
}
#[test]

View File

@ -113,6 +113,10 @@ Candidate features:
Why fourth: these features improve real Slovo code while keeping generics and
traits deferred until the core has more feedback.
Started on `main` after `1.0.0-beta.3`: project/workspace build and run entry
diagnostics now use entry-specific codes and explicitly show the required
`(fn main () -> i32 ...)` contract.
### 5. Package And Workspace Discipline
Goal: make multi-package local development predictable before remote registry

View File

@ -10,7 +10,11 @@ integration/readiness release, not the first real beta.
## Unreleased
No unreleased changes yet.
- Project build/run entry diagnostics now use entry-specific codes:
`ProjectEntryMainMissing`, `ProjectEntryMainInvalidSignature`,
`WorkspaceEntryMainMissing`, and `WorkspaceEntryMainInvalidSignature`.
Messages now spell out the required `(fn main () -> i32 ...)` contract and
include the found parameter count and return type for invalid signatures.
## 1.0.0-beta.3