ek9_promote_to_constant
Moves a `name <- literal` declaration into the module's `defines constant` block (same name, original deleted); answers status, edits[] and conflicts[] (no-promotable-declaration, initialiser-not-a-literal, constant-name-collision).
When to use it
'Make temperature a module constant' is one call with file + symbol:'temperature' - no line needed. Use it when a whole `name <- literal` declaration (a property or a local) should become a shared module constant, keeping its name.
When not to use it
- Lifting a bare LITERAL and giving it a NEW name - use
ek9_extract_constant(the literal-level sibling). - Wanting a different constant name (e.g. UPPER_SNAKE) — promote first, then rename with
ek9_rename_symbol(there is no convention/rename parameter here). - The `<-` value is a compound expression, a call, or an interpolated backtick string — EK9 constants are literal-valued so it can never be promoted; lift a literal sub-expression with
ek9_extract_constantinstead.
Details
conflicts kinds: 'no-promotable-declaration' (line is not a simple name <- value), 'initialiser-not-a-literal' (compound/call/interpolated value), 'constant-name-collision' (a module constant already has that name — rename the declaration first). Placement is shared with ek9_extract_constant via ConstantBlockPlacer: append to the module's existing `defines constant` block (even cross-file, to avoid E11066/E11067) or create one; a 'constants-scattered' advisory attaches when constants already span 2+ files. Only the `identifier <- literal` form is promoted (name AND type preserved; the `as Type:` form is deferred — constant grammar has no type annotation), and typical would-fail causes are a now-immutable value reassigned or an external member access that no longer resolves.
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
file | string | yes | Workspace-relative path to the .ek9 source file holding the `name <- literal` declaration. |
line | integer | 1-based line of the declaration or a reference - OMIT it and pass symbol:'<name>' to let the tool find the line (a model counting lines in a file miscounts); if you do count, use ek9_read_file(lineNumbers:true). | |
symbol | string | The identifier you mean (e.g. 'total'); the tool finds its declaration line in file. Pass line only to anchor one specific occurrence. |
It also takes the arguments every tool takes.
Recorded calls
Real calls, recorded against small projects and checked on every build - a changed answer fails it.
Interpolated value refused
Request
{
"file" : "task.ek9",
"symbol" : "banner"
}
Response
{
"conflicts" : [ {
"kind" : "initialiser-not-a-literal",
"message" : "The declaration's value is not a single literal (it is a compound expression, a call, or an interpolated string), so it cannot become a constant — EK9 constants are literal-valued."
} ],
"edits" : [ ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 0,
"lineCount" : 0,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "conflicts",
"summary" : "Initialiser is not a literal",
"workspaceHash" : "<workspace-hash>",
"wouldBeDiagnostics" : [ ],
"written" : false
}
Literal local promoted
Request
{
"file" : "task.ek9",
"symbol" : "threshold"
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"before" : " threshold <- 50",
"endLine" : 9,
"file" : "task.ek9",
"startLine" : 9,
"type" : "delete"
}, {
"after" : "\n defines constant\n threshold <- 50\n",
"endLine" : 3,
"file" : "task.ek9",
"startLine" : 3,
"type" : "insert"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"resolvedPath" : "<workspace-root>/task.ek9",
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 2,
...
Cut short here: 9 more lines. The whole recorded call.
See also
- Show me in the IDE: Promote to Constant