# 0089 — backtick raw-identifier escape + `#import c` foreign-name exemption from the reserved-type-name rule > **✅ RESOLVED** (foundation step F0.6). Two mechanisms, per Agra's design ruling: > > 1. **Backtick raw identifier.** The lexer recognises a leading backtick > (`` `s2 ``) and emits an `.identifier` token whose span excludes the backtick, > carrying a new `Token.is_raw` flag ([src/lexer.zig], [src/token.zig]). A raw > identifier is NEVER type-classified — the parser skips `Type.fromName` for it > in expression position ([src/parser.zig] `parsePrimary`), so it is always a > value identifier. The flag threads to `VarDecl.is_raw` / `Param.is_raw` > ([src/ast.zig]) at the binding sites, and `UnknownTypeChecker` skips the > reserved-name check for raw bindings ([src/ir/semantic_diagnostics.zig]). > Because the token tag stays `.identifier`, the escape works in every position > (local, global, param, field, function name, struct member, later reference) > with no per-site parser change. > 2. **`#import c` foreign-name exemption.** `c_import.zig` synthesizes foreign > `#foreign` decls with `Param.is_raw = true`, so generated C param names that > collide with reserved type names (`s1`, `s2`) import unedited. > > A *bare* reserved-name binding in sx still errors (issue 0076 preserved): the > `is_raw`-gated skip only fires for backtick / foreign names. Regression tests: > `examples/0151-types-backtick-raw-identifier.sx` (backtick, every position), > `examples/1220-ffi-c-import-reserved-name-params.{sx,h,c}` (foreign exemption), > `examples/1119-diagnostics-reserved-type-name-as-identifier.sx` (negative — > bare binding still rejected). Backtick lexer unit tests in `src/lexer.zig`. > > The original report is preserved below. --- ## Symptom Importing non-sx source whose names collide with sx reserved type names is rejected. `library/modules/stb_truetype.sx` is a `#import c { ... }` block over a vendored C header (`vendors/stb_truetype/stb_truetype.h`); C identifiers `s1`, `s2` (which collide with sx's signed-int type keywords `s1`..`sN`) produce: ``` error: 's1' is a reserved type name and cannot be used as an identifier error: 's2' is a reserved type name and cannot be used as an identifier ``` The user cannot hand-edit these — they are generated from the vendored C header. Separately, sx-authored code has NO way to deliberately use a reserved-name-spelled identifier even when it wants to. ## Root cause The parser classifies any reserved-type-name spelling (`s2`, `u8`, `f64`, …) as a `.type_expr` via `name_class.Type.fromName`, never as an `.identifier`. The F0.1 / issue-0076 fix added `UnknownTypeChecker.checkBindingName` (`src/ir/semantic_diagnostics.zig`) to reject a value binding / param spelled as a reserved type name (the `.type_expr`-vs-`.identifier` mismatch otherwise breaks address-of / autoref lowering). F0.1 deliberately extended this check to imported declarations — which is what now fires on the C-imported `s1`/`s2`. ## Desired behaviour (Agra ruling) External / imported source does NOT need to conform to sx naming standards. Two mechanisms: 1. **Auto-exempt imports.** `#import c` (and other foreign) declarations are treated as RAW identifiers: foreign names are never type-classified and never reserved-checked, so generated bindings "just work" with zero user edits. 2. **Backtick raw-identifier for sx code.** A leading backtick makes the following identifier raw — an identifier that is NEVER type-classified, so it bypasses the reserved-name rule: ```sx `s2 := 2.5; // OK — identifier "s2", distinct from the s2 signed-int type s2 := 2.5; // ERROR — bare s2 is still the reserved type name ``` Prefix form (single leading backtick on the identifier). The raw identifier's TEXT is `s2` (the backtick is not part of the name). A bare `s2` used as a TYPE remains the signed-int type. ## Reproduction sx-side (minimal): ```sx #import "modules/std.sx"; main :: () { `s2 := 2.5; // must compile: identifier s2 = 2.5 print("{}\n", `s2); // 2.5 } ``` Import-side: a `#import c` block over a header declaring `int s1, s2;` (or `stb_truetype.sx`) must NOT emit the reserved-type-name error.