Skip to content

Commit 4564d2f

Browse files
committed
[auto] Task 0.1.10.CG6: Fix Multiple Entry Points Issue
1 parent 8774c1e commit 4564d2f

3 files changed

Lines changed: 105 additions & 17 deletions

File tree

build_tools/sharpy_auto_builder/state/execution_log.jsonl

Lines changed: 30 additions & 0 deletions
Large diffs are not rendered by default.

build_tools/sharpy_auto_builder/state/ground_truth.json

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{
22
"version": "1.0",
3-
"last_updated": "2026-01-16T10:04:28.046300",
3+
"last_updated": "2026-01-16T10:14:09.366362",
44
"phases": [
55
{
66
"id": "0.1.10",
77
"name": "Module Import Code Generation Fix",
88
"goal": "",
99
"status": "in_progress",
10-
"progress": 28.57142857142857,
10+
"progress": 42.857142857142854,
1111
"tasks": [
1212
{
1313
"id": "0.1.10.CG1",
@@ -181,8 +181,46 @@
181181
"files": [
182182
"src/Sharpy.Compiler/CodeGen/RoslynEmitter.cs"
183183
],
184-
"status": "in_progress",
185-
"executions": [],
184+
"status": "completed",
185+
"executions": [
186+
{
187+
"attempt_number": 1,
188+
"backend": "claude-code",
189+
"started_at": "2026-01-16T10:14:09.363428",
190+
"completed_at": "2026-01-16T10:14:09.363431",
191+
"success": true,
192+
"error_message": null,
193+
"changes_made": [],
194+
"tests_run": true,
195+
"tests_passed": true,
196+
"validation_results": [
197+
{
198+
"agent": "spec-adherence",
199+
"status": "passed",
200+
"timestamp": "2026-01-16T10:14:09.363414",
201+
"findings": [],
202+
"recommendations": [],
203+
"raw_output": "Now I have all the information needed. Let me compile the spec adherence report:\n\n## Spec Adherence Report: Handle From-Import Code Generation\n\n**Spec:** `docs/language_specification/import_statements.md`, `docs/language_specification/module_system.md`, `docs/language_specification/module_resolution.md`, `docs/design/module_access_code_generation.md`\n**Implementation:** `src/Sharpy.Compiler/CodeGen/RoslynEmitter.cs:283-303`\n\n### Compliant\n\n- [x] **From-import basic syntax**: `from module import X` generates `using static Namespace.Module.Exports;` (spec: import_statements.md line 32-33)\n- [x] **From-import multiple symbols**: `from module import X, Y, Z` generates single `using static` directive (tested in RoslynEmitterModuleTests.cs:856-881)\n- [x] **From-import wildcard**: `from module import *` generates `using static Namespace.Module.Exports;` (spec: import_statements.md line 28-29, tested at line 913-936)\n- [x] **.NET framework detection**: .NET namespaces (system.*, microsoft.*, etc.) don't use `.Exports` suffix (RoslynEmitter.cs:309-324)\n- [x] **Module name conversion**: `snake_case` \u2192 `PascalCase` (spec: module_resolution.md line 5-7, implementation at RoslynEmitter.cs:326-338)\n- [x] **From-import .NET modules**: `from system.io import File` generates `using System.IO;` (RoslynEmitter.cs:289-292)\n- [x] **Acronym handling**: Common acronyms (io, ui, xml, http, api, sql) are uppercased in namespace (spec: module_resolution.md line 6)\n- [x] **Using static for direct access**: From-imports enable direct member access without module prefix (spec: import_statements.md line 23, module_access_code_generation.md line 141)\n- [x] **Deduplication**: Multiple from-imports from same module generate single using directive (implementation at RoslynEmitter.cs:231-241)\n\n### Deviations\n\n- [ ] **Section import_statements.md line 25-26**: From-import with alias\n - **Spec says:** `from math import sqrt as square_root` is valid syntax\n - **Implementation:** The `GenerateFromImportUsings` method (RoslynEmitter.cs:283-303) ignores `AsName` field completely - it generates `using static` regardless of alias\n - **Expected:** Per design doc (module_access_code_generation.md line 294): `from module import X as Y` should map to `using Y = Namespace.Module.Exports.X;` (for types) OR generate local variable alias for methods\n - **Actual behavior:** Aliases are silently ignored; no local variable alias is generated\n - **Note:** Test at RoslynEmitterModuleTests.cs:966-993 acknowledges this: \"alias handled at usage site\" and \"semantic analyzer should handle the symbol aliasing\"\n - **Impact:** **Medium** - Aliases in from-imports are syntactically accepted but not semantically honored in code generation. Code using aliased names will fail to compile.\n\n- [ ] **Undocumented behavior**: Specific symbol selection is ignored\n - **Spec implies:** `from config import MAX_SIZE` should only import `MAX_SIZE`, not all exports\n - **Implementation:** The `Names` list is completely ignored - ALL symbols from the module's Exports class become available via `using static`\n - **Generated code:** `from config import MAX_SIZE` \u2192 `using static Config.Exports;` (ALL exports accessible)\n - **Impact:** **Low** - This is actually more permissive than the Python/spec semantics. It allows access to symbols not explicitly imported, but this won't cause compilation errors and matches C# conventions.\n\n### Undocumented Behavior\n\n1. **Framework namespace detection heuristic**: The list of framework prefixes (`system`, `microsoft`, `windows`, `xamarin`, `mono`, `netstandard`) is implementation-defined and not documented in the language specification. (RoslynEmitter.cs:312-319)\n\n2. **Literal name handling**: Backtick-escaped names in module paths are handled specially in `SimpleToPascalCase` (RoslynEmitter.cs:347-352), extracting the content between backticks.\n\n### Recommendations\n\n1. **From-import alias handling (Medium Priority):**\n - Option A: For type aliases, implement `using Y = Namespace.Module.Exports.X;`\n - Option B: For method/variable aliases, generate local variable at usage site: `var square_root = Sqrt;`\n - The design doc recommends Option B (module_access_examples.md:323-325)\n\n2. **Document framework namespace detection:**\n - Add to language specification the list of recognized .NET framework namespace prefixes\n - Consider making this configurable in project settings\n\n3. **Symbol-specific import enforcement (Optional):**\n - The current behavior (exposing all exports) is a reasonable C# mapping\n - If strict Python semantics are desired, the semantic analyzer would need to validate that only explicitly imported symbols are used\n\n---\n\n**Summary:**\n\nThe from-import code generation is **largely compliant** with the specification. The core mapping of `from module import X` \u2192 `using static Namespace.Module.Exports;` is correctly implemented. The main gap is that **from-import aliases** (`from X import Y as Z`) are syntactically accepted but the alias is not reflected in generated code - the symbol must still be referenced by its original name. This is noted as a known limitation in the test comments, suggesting it's deferred to semantic analysis or future work.\n"
204+
},
205+
{
206+
"agent": "verification-expert",
207+
"status": "passed",
208+
"timestamp": "2026-01-16T10:14:09.363419",
209+
"findings": [],
210+
"recommendations": [],
211+
"raw_output": "Now I have a comprehensive view of the test results. Let me compile the verification report:\n\n## Verification Report: Handle From-Import Code Generation\n\n### Test Results\n- **Total: 3,836** | **Passed: 3,686** | **Failed: 69** | **Skipped: 81**\n - Sharpy.Core.Tests: 735 passed, 0 failed, 0 skipped\n - Sharpy.Compiler.Tests: 2,951 passed, 69 failed, 81 skipped\n\n### From-Import Code Generation Tests\nAll **45 tests** specifically for `FromImport` functionality **PASSED**:\n\n| Test Category | Count | Status |\n|---------------|-------|--------|\n| Parser tests | 8 | \u2705 All passed |\n| Semantic tests | 22 | \u2705 All passed |\n| CodeGen tests (RoslynEmitterModuleTests) | 15 | \u2705 All passed |\n\n### Behavior Checks\n- [x] `from module import symbol` generates `using static Module.Exports;`\n- [x] Snake_case module names convert to PascalCase\n- [x] Nested module paths (`lib.math.operations`) generate correct namespace paths\n- [x] `from module import *` generates `using static Module.Exports;`\n- [x] Multiple from-imports from same module deduplicate to single `using static`\n- [x] Symbol aliases are handled (generates `using static`, alias resolved at usage)\n- [x] .NET framework modules (`system.io`) generate standard `using` directives\n- [x] Sharpy modules generate `using static` to access exports directly\n\n### Coverage Assessment\n**Task 0.1.10.CG5 (From-Import Code Generation) is fully covered** by unit tests in:\n- `RoslynEmitterModuleTests.cs` (lines 825-1038): 12 dedicated tests covering:\n - Basic from-import with Sharpy modules\n - Multiple symbol imports\n - Nested modules\n - Import all (`*`)\n - Snake_case conversion\n - Symbol aliases\n - Deduplication\n\n### Regression Check\n**68 failing tests detected** - These are **NOT related to Task 0.1.10.CG5** but represent pre-existing issues in other areas:\n\n1. **Multi-file compilation issues (Task 0.1.10.CG6)**: Most Phase0110 integration test failures are due to:\n - `CS0246`: Type/namespace not found (module namespaces not matching)\n - `CS0542`: 'Main' member name conflict (multiple entry points issue)\n\n2. **Other unrelated failures**: Control flow tests, nested module access (covered by different tasks)\n\n### Summary\n| Aspect | Status |\n|--------|--------|\n| Task 0.1.10.CG5 Implementation | \u2705 **Complete and Working** |\n| Unit Test Coverage | \u2705 **45/45 tests passing** |\n| Regressions from this task | \u274c **None detected** |\n\n### Recommendations\n1. **No action needed for Task 0.1.10.CG5** - From-import code generation is working correctly\n2. **Remaining work**: The 68 failures relate to:\n - **Task 0.1.10.CG6**: Fix multiple entry points issue (CS0542 errors)\n - **Task 0.1.10.CG3/CG4**: Module namespace resolution issues (CS0246 errors)\n - These are separate tasks and do not indicate issues with from-import code generation\n"
212+
},
213+
{
214+
"agent": "hallucination-defense",
215+
"status": "minor_issues",
216+
"timestamp": "2026-01-16T10:14:09.363422",
217+
"findings": [],
218+
"recommendations": [],
219+
"raw_output": "Good, `using static` is indeed available in C# 9.0 (it was introduced in C# 6.0).\n\nNow let me compile my verification report:\n\n---\n\n# Hallucination Defense Report\n\n## Claim-by-Claim Verification\n\n---\n\n**Claim:** The implementation is at `src/Sharpy.Compiler/CodeGen/RoslynEmitter.cs:283-303`\n\n**Verification:** Read the file and verified line numbers with `grep -n`\n\n**Result:** \u2705 CORRECT \u2014 The `GenerateFromImportUsings` method is exactly at lines 283-303.\n\n---\n\n**Claim:** For .NET Framework modules (e.g., `from system.io import File`), generates `using System.IO;`\n\n**Verification:** Read the code at lines 289-292 and verified with test `GenerateCompilationUnit_WithFromImport_GeneratesUsing`\n\n**Result:** \u2705 CORRECT \u2014 The code checks `isNetFramework` and yields `UsingDirective(ParseName(namespaceName))` for .NET modules.\n\n---\n\n**Claim:** For Sharpy modules (e.g., `from config import MAX_SIZE`), generates `using static Config.Exports;`\n\n**Verification:** Read code at lines 294-302 and verified with test `GenerateCompilationUnit_WithFromImportSharpyModule_GeneratesUsingStatic`\n\n**Result:** \u2705 CORRECT \u2014 The code generates `using static {namespace}.Exports;` via `.WithStaticKeyword(Token(SyntaxKind.StaticKeyword))`.\n\n---\n\n**Claim:** Uses C# `using static` to make all static members available\n\n**Verification:** Built test code with C# 9.0 using `using static System.Math;` and confirmed it compiles and works.\n\n**Result:** \u2705 CORRECT \u2014 C# `using static` imports all static members from a class.\n\n---\n\n**Claim:** Converts module names to PascalCase (e.g., `database_utils` \u2192 `DatabaseUtils`)\n\n**Verification:** Test `GenerateCompilationUnit_WithFromImportSnakeCaseModule_ConvertsToPascalCase` asserts `using static DatabaseUtils.ConnectionPool.Exports;`\n\n**Result:** \u2705 CORRECT \u2014 Tests pass and verify this behavior.\n\n---\n\n**Claim:** Using static for all symbols: The implementation generates `using static Module.Exports;` regardless of which specific symbols are imported\n\n**Verification:** Read code - there's no symbol-level filtering, just the module name is used.\n\n**Result:** \u2705 CORRECT \u2014 The code only uses `fromImport.Module`, not `fromImport.Names`.\n\n---\n\n**Claim:** C# `using static` doesn't support selective imports\n\n**Verification:** C# language specification - `using static` imports ALL static members of a type, not selective ones.\n\n**Result:** \u2705 CORRECT \u2014 This is a known C# language limitation.\n\n---\n\n**Claim:** PascalCase conversion examples: `lib.math.operations` \u2192 `Lib.Math.Operations.Exports`\n\n**Verification:** Test `GenerateCompilationUnit_WithFromImportNestedModule_GeneratesPascalCasePath` asserts `using static Lib.Math.Operations.Exports;`\n\n**Result:** \u2705 CORRECT \u2014 Test confirms this exact conversion.\n\n---\n\n**Claim:** Added 8 comprehensive tests to `src/Sharpy.Compiler.Tests/CodeGen/RoslynEmitterModuleTests.cs`\n\n**Verification:** Counted tests in `#region From-Import Tests for Sharpy Modules` using `sed` and `grep`\n\n**Result:** \u26a0\ufe0f MINOR_INCORRECT \u2014 There are **7 tests**, not 8:\n1. `GenerateCompilationUnit_WithFromImportSharpyModule_GeneratesUsingStatic`\n2. `GenerateCompilationUnit_WithFromImportMultipleSymbols_GeneratesUsingStatic`\n3. `GenerateCompilationUnit_WithFromImportNestedModule_GeneratesPascalCasePath`\n4. `GenerateCompilationUnit_WithFromImportAllSharpyModule_GeneratesUsingStatic`\n5. `GenerateCompilationUnit_WithFromImportSnakeCaseModule_ConvertsToPascalCase`\n6. `GenerateCompilationUnit_WithFromImportSymbolWithAlias_GeneratesUsingStatic`\n7. `GenerateCompilationUnit_MultipleFromImportsSameModule_GeneratesSingleUsingStatic`\n\n---\n\n**Claim:** Test names listed (1-4)\n\n**Verification:** Compared claimed names against actual test method names\n\n**Result:** \u2705 CORRECT \u2014 The listed test names 1-3 match exactly. Test 4 was truncated in the input.\n\n---\n\n**Claim:** The Roslyn API `UsingDirective(...).WithStaticKeyword(Token(SyntaxKind.StaticKeyword))` is correct\n\n**Verification:** Code compiles and all 37 tests in `RoslynEmitterModuleTests` pass.\n\n**Result:** \u2705 CORRECT \u2014 The API usage is valid Roslyn syntax.\n\n---\n\n**Claim:** `using static` is available in C# 9.0 (Unity constraint)\n\n**Verification:** Built test project with `<LangVersion>9.0</LangVersion>` using `using static System.Math;`\n\n**Result:** \u2705 CORRECT \u2014 `using static` was introduced in C# 6.0, so it's available in C# 9.0.\n\n---\n\n## Hallucination Summary\n\n- **Minor Issues:** 1 (Test count claimed as 8, actual is 7)\n- **Major Issues:** 0\n- **Verdict:** MINOR_ISSUES\n"
220+
}
221+
]
222+
}
223+
],
186224
"dependencies": [],
187225
"is_critical": false,
188226
"human_question": null,
@@ -198,7 +236,7 @@
198236
"src/Sharpy.Compiler/CodeGen/RoslynEmitter.cs",
199237
"src/Sharpy.Compiler/Project/ProjectCompiler.cs"
200238
],
201-
"status": "pending",
239+
"status": "in_progress",
202240
"executions": [],
203241
"dependencies": [],
204242
"is_critical": false,
@@ -226,14 +264,14 @@
226264
}
227265
],
228266
"current_phase_id": null,
229-
"current_task_id": "0.1.10.CG5",
230-
"total_attempts": 4,
231-
"total_successes": 4,
267+
"current_task_id": "0.1.10.CG6",
268+
"total_attempts": 5,
269+
"total_successes": 5,
232270
"total_failures": 0,
233271
"backend_stats": {
234272
"claude_code": {
235-
"attempts": 4,
236-
"successes": 4,
273+
"attempts": 5,
274+
"successes": 5,
237275
"failures": 0
238276
},
239277
"copilot": {
@@ -242,5 +280,5 @@
242280
"failures": 0
243281
}
244282
},
245-
"overall_progress": 28.57142857142857
283+
"overall_progress": 42.857142857142854
246284
}

src/Sharpy.Compiler/CodeGen/RoslynEmitter.cs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -448,10 +448,11 @@ private ClassDeclarationSyntax GenerateModuleClass(List<Statement> statements)
448448

449449
// Generate a Main method if:
450450
// 1. There's no user-defined main function, AND
451-
// 2. This is the entry point file (or there are executable statements that need wrapping)
452-
if (!hasMainFunction && (_context.IsEntryPoint || executableStatements.Count > 0))
451+
// 2. This is the entry point file, AND
452+
// 3. There are executable statements that need wrapping
453+
if (!hasMainFunction && _context.IsEntryPoint && executableStatements.Count > 0)
453454
{
454-
// Create a Main method for executable statements (or empty if no statements)
455+
// Create a Main method for executable statements
455456
// Clear declared variables and version tracking for Main method scope
456457
_declaredVariables.Clear();
457458
_variableVersions.Clear();
@@ -478,9 +479,19 @@ private ClassDeclarationSyntax GenerateModuleClass(List<Statement> statements)
478479
// This is a corner case we'll handle later
479480
Console.WriteLine($"Warning: {executableStatements.Count} module-level statement(s) ignored because a 'main' function is defined");
480481
}
482+
else if (!_context.IsEntryPoint && executableStatements.Count > 0)
483+
{
484+
// Non-entry-point files with executable statements: ignore them
485+
// Module-level executable code should only run in the entry point
486+
Console.WriteLine($"Warning: {executableStatements.Count} module-level executable statement(s) in non-entry-point file ignored");
487+
}
488+
489+
// Check if we're generating a Main method OR if there's a user-defined main function
490+
// (both will result in a method named "Main" in the class)
491+
bool willHaveMainMethod = hasMainFunction || (!hasMainFunction && _context.IsEntryPoint && executableStatements.Count > 0);
481492

482493
// Generate module class name from source file name
483-
var moduleClassName = GetModuleClassName();
494+
var moduleClassName = GetModuleClassName(willHaveMainMethod);
484495

485496
return ClassDeclaration(moduleClassName)
486497
.WithModifiers(TokenList(
@@ -489,15 +500,24 @@ private ClassDeclarationSyntax GenerateModuleClass(List<Statement> statements)
489500
.WithMembers(List(declarations));
490501
}
491502

492-
private string GetModuleClassName()
503+
private string GetModuleClassName(bool willGenerateMainMethod = false)
493504
{
494505
// Get the file name without extension and convert to PascalCase
495506
if (!string.IsNullOrEmpty(_context.SourceFilePath))
496507
{
497508
var fileName = Path.GetFileNameWithoutExtension(_context.SourceFilePath);
498509
if (!string.IsNullOrEmpty(fileName))
499510
{
500-
return SimpleToPascalCase(fileName);
511+
var className = SimpleToPascalCase(fileName);
512+
513+
// Avoid name collision: if the class would be named "Main" and we're generating
514+
// a Main method, use "Program" instead (following C# convention)
515+
if (className == "Main" && willGenerateMainMethod)
516+
{
517+
return "Program";
518+
}
519+
520+
return className;
501521
}
502522
}
503523

0 commit comments

Comments
 (0)