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).

Category: Editor · Compare: Refactor → Introduce Constant (from field) — declaration-level

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

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

ArgumentTypeRequiredWhat it is
filestringyesWorkspace-relative path to the .ek9 source file holding the `name <- literal` declaration.
lineinteger1-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).
symbolstringThe 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