fix: Handle execute-dynamic-code transpiler constraints for static locals and byte casts
Summary
Address execute-dynamic-code transpiler constraints (B-9):
- CS8421 / static local functions: Fix literal hoister to keep literals inline inside static local function bodies (top-level and nested; expression-bodied and block-bodied).
- CS8820 / static lambdas: Add Hint + SKILL.md guidance (hoister fix out of scope; remove
staticfrom lambda). - CS1503 / Color32 byte components: Document as known constraint; add compilation
Hint+Suggestionsand SKILL.md guidance for explicit(byte)casts.
Follow-up (separate PR 3-5, before Group 3 integration): Color32 repro Line=1 / caret on using line is a PR 3-3 lineage bug (using extraction shrinks #line region while Context uses original lines). Track in PR 3-5 with placeholder-line or line-offset mapping.
Pre-implementation verification
Repro 1a: nested static local (before fix)
Command:
uloop execute-dynamic-code --code $'int Compute(int value)\n{\n static int Double(int x) => x * 2;\n return Double(value);\n}\nreturn Compute(3);'
Raw Diagnostics[0] (before fix):
{
"Message": "CS8421: A static local function cannot contain a reference to '__uloop_literal_0'.",
"Line": 3,
"Column": 37,
"ErrorCode": "CS8421",
"Hint": "",
"Suggestions": [],
"Context": "L1:int Compute(int value)\nL2:{\nL3: static int Double(int x) => x * 2;\n ^\nL4: return Double(value);\nL5:}\nL6:return Compute(3);\n",
"PointerColumn": 37
}
Repro 1b: top-level static local — B-9 primary case (before fix)
Command:
uloop execute-dynamic-code --code $'static int Double(int x) => x * 2;\nreturn Double(3);'
Raw Diagnostics[0] (before fix; _braceDepth < 1 guard blocked hoister scope):
{
"Message": "CS8421: A static local function cannot contain a reference to '__uloop_literal_0'.",
"Line": 1,
"Column": 37,
"ErrorCode": "CS8421",
"Hint": "",
"Suggestions": [],
"Context": "L1:static int Double(int x) => x * 2;\n ^\nL2:return Double(3);\n",
"PointerColumn": 37
}
Investigation: Integer literals inside static local bodies were hoisted to __uloop_literal_N. Top-level static locals were missed because LiteralHoistScopeTracker required _braceDepth >= 1.
Decision: Fix — remove depth guard; keep literals inline inside recognized static local headers. CS8421 Hint/Suggestion targets remaining scanner gaps (remove static).
Repro 2: Color32 int literals (constraint)
Command:
uloop execute-dynamic-code --code $'using UnityEngine;\nreturn new Color32(255, 0, 0, 255);'
Raw Diagnostics[0] (before fix, no Hint):
{
"Message": "CS1503: Argument 1: cannot convert from 'int' to 'byte'",
"Line": 1,
"Column": 20,
"ErrorCode": "CS1503",
"Hint": "",
"Suggestions": [],
"Context": "L1:using UnityEngine;\n ^\nL2:return new Color32(255, 0, 0, 255);\n",
"PointerColumn": 20
}
Plain C# note: new Color32(255, 0, 0, 255) compiles in normal Unity scripts because numeric literals are compile-time constants with implicit narrowing to byte. Literal hoisting promotes them to int parameters.
Decision: Known constraint; Hint + SKILL.md + explicit cast workaround. Line/caret mismatch deferred to PR 3-5.
Repro 3: static lambda CS8820 (constraint + Hint)
Command:
uloop execute-dynamic-code --code $'System.Func<int,int> f = static x => x * 2;\nreturn f(3);'
Raw Diagnostics[0] (after Hint fix):
{
"Message": "CS8820: A static anonymous function cannot contain a reference to '__uloop_literal_0'.",
"Line": 1,
"Column": 42,
"ErrorCode": "CS8820",
"Hint": "Static lambdas cannot reference hoisted literal parameters. Remove the `static` modifier from the lambda, or use a non-static local function instead.",
"Suggestions": [
"Remove the `static` modifier from the lambda."
],
"Context": "L1:System.Func<int,int> f = static x => x * 2;\n ^\nL2:return f(3);\n",
"PointerColumn": 42
}
Convention checklist
- No overloads added
- No try-catch added
- No out/ref in new APIs (tuple return for hints)
- Additive only; no protocol bump
- Source SKILL.md edited;
.claude//.agents/regenerated viauloop skills install(byte-identical) - All test methods have what-comments; English commit/PR
Implementation
LiteralHoistScopeTracker: remove_braceDepth < 1guard; suppress hoisting inside recognized static local bodiesStaticLocalFunctionHeaderScanner: document unsupported header shapes (where, tuple returns, statement lambdas in expression bodies)DynamicCodeLiteralHoister.LiteralParameterPrefix: shared internal constantDynamicCodeTranspilerConstraintHints: CS8421 / CS8820 / CS1503 guidance via tuple returnSkill/SKILL.md: updated Known transpiler constraints
Verification
dist/darwin-arm64/uloop compile— 0 errors / 0 warningsDynamicCodeLiteralHoisterTests+DynamicCodeTranspilerConstraintHintsTests+DynamicCodeExecutionResponseFactoryTests— 15 passed
Post-fix repro 1b (top-level static local — B-9 primary)
{
"Success": true,
"Result": "6",
"Logs": ["Execution completed successfully"],
"CompilationErrors": [],
"ErrorMessage": "",
"Diagnostics": []
}
Post-fix repro 2 (Color32 — constraint with Hint)
Raw Diagnostics[0]:
{
"Message": "CS1503: Argument 1: cannot convert from 'int' to 'byte'",
"Line": 1,
"Column": 20,
"ErrorCode": "CS1503",
"Hint": "Literal hoisting promotes integer literals to int values. Unity APIs such as Color32 expect byte components and do not accept implicit int-to-byte conversion after hoisting, even though plain numeric literals compile in normal Unity scripts.",
"Suggestions": [
"Cast each component explicitly, for example: new Color32((byte)255, (byte)0, (byte)0, (byte)255)."
],
"Context": "L1:using UnityEngine;\n ^\nL2:return new Color32(255, 0, 0, 255);\n",
"PointerColumn": 20
}
Workaround verified:
{
"Success": true,
"Result": "RGBA(255, 0, 0, 255)",
"Logs": ["Execution completed successfully"]
}