Why this fires¶
A tagged template tag"…" is not special syntax — the compiler lowers it to
an ordinary function call:
sh"git log -n {n} --oneline"
// ⇒ sh({"git log -n ", " --oneline"}, n)So the tag must resolve to a function in scope (a local, a top-level fn,
a prelude builtin like sh, or a plugin-exported function like ts). When it
resolves to nothing anywhere, the call could only fail at runtime with
attempt to call nil — TE970 surfaces the problem at check time instead,
usually catching a typo in the tag name:
let out = hs"git status".run()?
// ^ error[TE970]: tagged template `hs"…"` has no matching
// function `hs` in scope. Did you mean `sh"…"`?Fix it¶
1. Fix the typo¶
The diagnostic suggests the nearest name in scope (edit distance):
let out = sh"git status".run()? // `sh` is a prelude builtin2. Define (or import) the tag function¶
Any function with the shape fn tag(parts: [str], args: ...Any) -> T can be
a tag. The literal chunks arrive in parts; each interpolated value arrives
as its own argument — already separated, which is what makes tags
injection-safe by construction:
fn upper(parts: [str], args: ...Any) -> str {
// interleave parts and args, uppercasing the literals …
}
let s = upper"hello {name}"Notes¶
sql"…"andjson"…"never fire TE970 — they have bespoke compile-time lowering and validators instead of a runtime tag function.- Plugin tags (
ts"…",js"…", …) are resolved through the plugin registry at runtime; any tag matching a function exported by a bundled plugin declaration is left permissive. - When the tag resolves to a function with a known return type, the template
is typed as that return type (e.g.
sh"…"types asCmd), so chained calls like.run()?check properly.
See also¶
TE100— undefined variable (same resolution rules).- specs/shell-scripting.html §1 — command literals over tagged templates.