# Wolf diagnostics catalog GENERATED by `cargo xtask diag-catalog` from `crates/wolf_diag/src/registry.rs` — do not edit. Every code is a reviewed artifact: it ships with an explanation (`wolf --explain`) and at least one snapshot fixture (CI-enforced). ## E0001 — a statement begins with an operator Wolf ends a statement at the end of the line, so a line that begins with an operator such as `+` or `.` has nothing to attach to: the previous statement already ended at the newline. Continuations in wolf are *trailing* — to spread an expression over several lines, end the line with the operator (or an open `(`/`[`, inside which newlines never terminate), rather than starting the next line with it. Move the operator to the end of the previous line and the two lines become one statement again. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__grammar__newline_leading.snap, crates/wolf_parse/tests/snapshots/ambiguity_trees__expr_tree__newline_leading.snap, crates/wolf_parse/tests/snapshots/corpus_decls__grammar__newline_leading.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0001_leading_operator.snap ## E0002 — an empty statement (`;` that terminates nothing) In wolf, `;` and the end of a line are the same statement terminator, and a terminator must terminate something. A `;` directly after `{`, or directly after another terminator, ends an *empty* statement, which the grammar rejects rather than silently ignoring — a stray `;` is usually a typo or a leftover from another language. Delete the `;`; use it only to separate statements written on a single line. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__grammar__semicolon.snap, crates/wolf_parse/tests/snapshots/ambiguity_trees__expr_tree__semicolon.snap, crates/wolf_parse/tests/snapshots/corpus_decls__grammar__semicolon.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0002_empty_statement.snap ## E0003 — comparison operators do not chain `a < b < c` does not mean "b is between a and c" in wolf: comparison operators are non-associative, so the grammar rejects a comparison whose operand is itself a comparison instead of silently evaluating `(a < b) < c` on a boolean, which is never what anyone means. Write the two comparisons out and join them: `a < b && b < c`. Fixtures: crates/wolf_parse/tests/snapshots/broken_suite__cmp_chain.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0003_comparison_chain.snap ## E0004 — a float exponent written as member access `1.e5` is not a float in wolf: a float literal needs digits on both sides of the dot, so `1.e5` parses as the member `e5` accessed on the integer `1` — and integers have no such member. The exponent form you meant spells the fraction out: `1.0e5`. Write digits after the dot (`1.0e5`, `2.5e-3`) and the literal lexes as one float token; the suggested edit does exactly that ([gram.amb.intdot]). Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__grammar__intdot_exponent.snap, crates/wolf_sema/tests/snapshots/method_diagnostics__e0004_float_exponent.snap ## E0005 — `else` may not start a new line The newline after the `}` of the then-block ends the `if` statement, so an `else` on the next line belongs to nothing — wolf will not guess whether it was meant for the `if` above it. Put the `else` on the same line as the closing brace of the block before it: `} else {`. This is the one place wolf's newline-termination rule constrains layout ([gram.amb.else]). Fixtures: crates/wolf_parse/tests/snapshots/diagnostics__e0005_else_new_line.snap ## E0006 — a struct literal cannot sit bare in condition position In a condition or scrutinee — after `if`, `while`, `match`, or `for … in` — a `{` must open the construct's block, so a bare struct literal like `if x == Point { x: 1 } …` would be ambiguous: is `{ x: 1 }` the literal or the then-block? Wolf resolves the ambiguity by fiat: the `{` opens the block, always ([gram.amb.structlit]). To use a struct literal there, wrap it in parentheses — `if x == (Point { x: 1 }) { … }` — and the ambiguity disappears. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__grammar__structlit_cond.snap, crates/wolf_parse/tests/snapshots/ambiguity_trees__expr_tree__structlit_cond.snap, crates/wolf_parse/tests/snapshots/corpus_decls__grammar__structlit_cond.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0006_structlit_cond.snap ## E0007 — string interpolations nest deeper than 8 levels A string inside an interpolation inside a string can nest, but past 8 levels wolf stops you: nobody can read a 9-deep interpolation, and the limit exists to keep pathological one-liners out of the language ([gram.lex.str]). Hoist the innermost string expression into a `let` binding and interpolate the binding instead — each hoist removes a level. (The lexer has a separate hard safety rail at 32 levels, E0108.) Fixtures: crates/wolf_lex/tests/snapshots/diagnostics__e0108.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0007_interp_depth.snap ## E0008 — a reserved keyword used as a name All 50 of wolf's keywords are reserved everywhere — a keyword can never name a function, parameter, field, or binding, and wolf deliberately has no escape hatch like Rust's `r#` raw identifiers ([gram.inv.kw], spec/01 §9). Pick a different name; the conventional dodges are a trailing underscore (`type_`) or a more specific word (`kind`, `variant`). Member access is the one keyword-transparent position: `x.take(n)` is fine because `.take` can only be a member name. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__grammar__when_reserved.snap, crates/wolf_parse/tests/snapshots/ambiguity_trees__expr_tree__when_reserved.snap, crates/wolf_parse/tests/snapshots/corpus_decls__grammar__when_reserved.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0008_minimal.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0008_when_reserved.snap ## E0101 — invalid escape sequence in a string literal Inside a plain or multiline string, `\` starts an escape, and wolf recognizes exactly these: `\n`, `\t`, `\r`, `\0`, `\\`, `\"`, `\xNN` (two hex digits), and `\u{…}` (one to six hex digits) ([gram.lex.str.escape]). Anything else after a `\` is an error rather than passing through silently — a typo like `\d` almost always means a regex or a Windows path ended up in the wrong kind of string. For a literal backslash write `\\`; for text that should not be escaped at all, use a raw string `r"…"`, which has no escapes. Fixtures: crates/wolf_lex/tests/snapshots/diagnostics__e0101_hex.snap, crates/wolf_lex/tests/snapshots/diagnostics__e0101_unicode.snap, crates/wolf_lex/tests/snapshots/diagnostics__e0101_unknown.snap ## E0102 — unterminated string literal or interpolation A plain `"…"` string must close before the end of its line — a newline inside one is almost always a missing closing quote, so wolf ends the string there, reports it once, and carries on lexing the next line cleanly. If you meant the text to span lines, use a multiline `"""` string, which closes at the next `"""`. The same recovery applies to a format spec (`{value:…}`) left open at the end of a line, and to a string still open when the file ends. Fixtures: crates/wolf_lex/tests/snapshots/diagnostics__e0102_eol.snap, crates/wolf_lex/tests/snapshots/diagnostics__e0102_multiline_eof.snap, crates/wolf_lex/tests/snapshots/render__render_e0102_unterminated.snap ## E0103 — text after the opening `\ A multiline string's content starts on the line *after* the opening `"""` — the opener must be the last thing on its line (SE-0168 lineage: the layout is part of the literal). Text on the opening line has no column to measure the margin against, so wolf rejects it. Move the text down to the next line; the whitespace before the closing `"""` then defines the margin stripped from every content line. Fixtures: crates/wolf_lex/tests/snapshots/diagnostics__e0103.snap ## E0104 — a multiline string line sits left of the margin The whitespace before the closing `"""` is the *margin*: every content line of the multiline string must start with exactly that whitespace, which wolf strips when it builds the value ([gram.lex.str]). A line indented less than the margin has bytes the margin would eat, so wolf asks you to choose: indent the line to at least the margin, or move the closing `"""` left to the shallowest content line. Blank lines are exempt. This code also fires when the closing `"""` is not alone on its line — its column *is* the margin, so it must stand alone. Fixtures: crates/wolf_lex/tests/snapshots/diagnostics__e0104.snap, crates/wolf_lex/tests/snapshots/render__render_e0104_two_locus.snap ## E0105 — margin tabs and spaces do not match the closing `\ Wolf compares a multiline string's margin byte-for-byte, never by visual width: a tab in the margin of a content line matches only a tab in the whitespace before the closing `"""`, and a space only a space. Mixing them would make the stripped value depend on the reader's tab width, so it is an error instead. Re-indent the flagged line with the same tab/space mix as the closing delimiter's line — most editors fix this with one select-and-reindent. Fixtures: crates/wolf_lex/tests/snapshots/diagnostics__e0105.snap ## E0106 — source bytes are not valid UTF-8 Wolf source files are UTF-8, nothing else ([gram.lex.source]) — no latin-1, no UTF-16, no "mostly ASCII with a few stray bytes". The lexer reports one error per run of invalid bytes and skips them, so the rest of the file still lexes and later errors stay meaningful. Re-save the file as UTF-8; if the bytes are intentional binary data, they belong in a separate file loaded at runtime or a `\x…` escape, not raw in the source. Fixtures: crates/wolf_lex/tests/snapshots/diagnostics__e0106.snap ## E0107 — a stray character that fits no token This character cannot start any wolf token — commonly a `$` or `` ` `` from another language's syntax, an invisible Unicode character pasted from a web page, or a byte-order mark (wolf sources are BOM-less UTF-8). Delete the character. A related case is a lone `}` inside a string: `}` closes an interpolation there, so a literal closing brace must be written `}}` (just as `{{` is a literal `{`). Fixtures: crates/wolf_diag/tests/snapshots/render_snapshots__tab_expansion.snap, crates/wolf_diag/tests/snapshots/render_snapshots__width_truncation.snap, crates/wolf_lex/tests/snapshots/diagnostics__e0107.snap, crates/wolf_lex/tests/snapshots/diagnostics__e0107_lone_brace.snap, crates/wolf_lex/tests/snapshots/render__render_e0107_lone_brace.snap ## E0108 — string/interpolation nesting exceeds the lexer's 32-level rail Strings and interpolations nest through one mode stack, and past 32 levels the lexer refuses to push further — this is a hard safety rail against pathological or generated input, not a style limit. The language's *intended* ceiling is 8 levels, enforced with E0007 and its better advice; input deep enough to reach 32 is almost certainly machine-generated or malicious. Hoist inner strings into bindings, or generate simpler code. Fixtures: crates/wolf_lex/tests/snapshots/diagnostics__e0108.snap ## E0109 — unterminated raw or generalized string literal … Fixtures: crates/wolf_lex/tests/snapshots/diagnostics__e0109_generalized.snap, crates/wolf_lex/tests/snapshots/diagnostics__e0109_raw.snap ## E0201 — the parser expected a different token or construct here The workhorse parse error: at this position the grammar required something — a name, a `(`, an expression, a line end — and found something else. The message names exactly what was expected and the label points at where it should have been; the parser then inserts a zero-width placeholder and continues, so one miss does not cascade into a screenful. Fix the flagged spot first: later errors in the same region may be echoes of this one. Fixtures: crates/wolf_diag/tests/snapshots/render_snapshots__mock_sema_two_files.snap, crates/wolf_diag/tests/snapshots/render_snapshots__two_secondaries.snap, crates/wolf_parse/tests/snapshots/broken_suite__expr_typo.snap, crates/wolf_parse/tests/snapshots/broken_suite__match_missing_arrow.snap, crates/wolf_parse/tests/snapshots/broken_suite__missing_lbrace.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0201_missing_init.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0201_missing_name.snap, crates/wolf_parse/tests/snapshots/render__render_interp_span.snap ## E0202 — an opening delimiter is never closed A `(`, `[`, `{`, or `#[` was opened and its closing partner never arrived — the error points at the *opener*, because that is where the fix goes, with a note at the place the parser gave up looking. Inside `(` and `[`, newlines do not terminate statements, so one lost `)` can otherwise swallow every following line; the parser instead stops at the next declaration keyword and reports the wreck once. If the code below this error looks fine, trust the opener: count delimiters on the flagged line. Fixtures: crates/wolf_diag/tests/snapshots/render_snapshots__multiline_elided.snap, crates/wolf_diag/tests/snapshots/render_snapshots__multiline_primary.snap, crates/wolf_parse/tests/snapshots/broken_suite__call_unclosed_paren.snap, crates/wolf_parse/tests/snapshots/broken_suite__half_typed_fn_header.snap, crates/wolf_parse/tests/snapshots/broken_suite__missing_rparen.snap, crates/wolf_parse/tests/snapshots/broken_suite__unclosed_brace_eof.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0202_unclosed_brace.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0202_unclosed_paren.snap, crates/wolf_parse/tests/snapshots/render__render_e0202.snap ## E0203 — expected a declaration at the top level The top level of a wolf file (and the body of a `trait` or `impl`) is declarations only: `fn`, `let`, `var`, `const`, `type`, `struct`, `enum`, `trait`, `impl`, `use`, `import` — every one led by its keyword ([gram.item]). A bare expression or statement up here usually means a function body's `{` went missing above, or a keyword was mistyped (`fnn` for `fn` — the message suggests the fix when the typo is close). A run of stray lines is reported once: fix the first flagged line and the rest usually follow. Fixtures: crates/wolf_parse/tests/snapshots/broken_suite__keyword_typo.snap, crates/wolf_parse/tests/snapshots/broken_suite__stray_expr.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0203_keyword_typo.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0203_stray_expr.snap ## E0204 — malformed attribute An attribute is `#[name]`, optionally dotted (`#[pkg.name]`), with arguments that are literals or nested attributes: `#[inline]`, `#[repr(c)]`, `#[deprecated = "use other"]` ([gram.item.attr]). Anything else inside the `#[…]` — stray operators, unbalanced parens, a missing name — is malformed. Attributes attach to the declaration that follows them, so a broken attribute is contained and the declaration itself still parses. Fixtures: crates/wolf_parse/tests/snapshots/broken_suite__attr_garbage.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0204_attr_garbage.snap ## E0205 — malformed generic parameter list Generic parameters are square-bracketed names with optional bounds: `fn f[T](…)`, `struct Map[K: Hash + Eq, V] { … }`, and comptime value parameters as `[N: type]` ([gram.item.fn]). Each parameter starts with a name — nested brackets, literals, or operators cannot appear in parameter position. Note that wolf uses `[]` for generics everywhere; if you wrote ``, the angle brackets parse as comparisons, and this error (or E0201) is how that surfaces. Fixtures: crates/wolf_parse/tests/snapshots/broken_suite__bad_generics.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0205_bad_generics.snap ## E0206 — expected a type Type position — after `:` in a binding or parameter, after `->`, inside a type argument list — needs a type: a path like `int` or `pkg.Type`, possibly applied (`List[int]`), or one of the prefixed forms `*T`, `!T`, `shared T`, `handle T`, `weak T`, `distinct T`, `dyn Trait`, `fn(…) -> T` ([gram.type]). The token found here cannot begin any of those. If you deleted a type mid-edit, the `:` or `->` in front of it is now dangling — remove it or complete the type. Fixtures: crates/wolf_parse/tests/snapshots/diagnostics__e0206_missing_type.snap ## E0207 — expected a pattern Pattern position — after `let`/`var`, after `for`, at the head of a match or select arm — needs a pattern: a binding name, `_`, a literal, a tuple `(a, b)`, a payload form `Tag(x)`, an `@` binding, or an or-pattern joined with `|` ([gram.pat]). The token found here cannot begin one. In `let` position this often means the binding name was deleted or a keyword sits where the name should be (that case is E0008 with its own advice). Fixtures: crates/wolf_parse/tests/snapshots/diagnostics__e0207_missing_pattern.snap ## E0208 — assignment used as an expression Assignment is a *statement* in wolf: `x = y` stores into `x` and produces no value, so it cannot sit inside a larger expression ([gram.expr.assign]) — `if (x = 5) …` is the classic bug this rule exists to keep impossible. If you meant to compare, write `==`. If you really meant to assign first, make it its own statement on the line above, then use `x`. Chains like `a = b = c` are rejected as one mistake, reported once. Fixtures: crates/wolf_parse/tests/snapshots/broken_suite__assign_in_expr.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0208_assign_in_expr.snap ## E0209 — negative integer literal used as an index Wolf indexes count from the front only; there is no Python-style negative indexing, because a silent `-1` wrapping to "last element" is a classic off-by-one factory (D25). End-relative positions have their own operator: `^n` counts from the end, so `s[^1]` is the last element and `s[1..^1]` trims one from each side. Replace the `-` with `^` — the suggested edit does exactly that. (If you meant to index with a negative *computed* value, that is a bounds error at runtime; compute the offset explicitly instead.) Fixtures: crates/wolf_diag/tests/snapshots/render_snapshots__suggestion_edit_preview.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0209_negative_index.snap, crates/wolf_parse/tests/snapshots/render__render_e0209.snap ## E0210 — a moded receiver outside receiver position `(mut x)` and `(take x)` are receiver spellings, not expressions: they exist so a call to a `mut self` or `take self` method names its exclusive or consuming access at the call site — `(mut p).norm()` — mirroring the argument modes of `f(mut x)` (X1). Detached from a method call the mode marks nothing, so the grammar rejects it anywhere a `.` does not follow the closing parenthesis. Delete the mode to get a plain parenthesized expression, or complete the method call the receiver was written for ([gram.expr.primary]). Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__grammar__receiver_moded.snap, crates/wolf_parse/tests/snapshots/ambiguity_trees__expr_tree__receiver_moded.snap, crates/wolf_parse/tests/snapshots/corpus_decls__grammar__receiver_moded.snap, crates/wolf_parse/tests/snapshots/diagnostics__e0210_moded_receiver.snap ## E0301 — nothing with this name is in scope Wolf could not find anything with this name: it is not a local binding, a parameter, an item defined in this module (remember: every `.lu` file in a directory is the *same* module), one of this file's imports, or a prelude name. Most of the time this is a typo — when a near-miss exists the message suggests it, and applying the suggested edit fixes the program. If the name lives in another module, add the import: `use that_module` at the top of the file, then reach it as `that_module.name`. Names never resolve through types here — a capitalized name used as an error-row tag (D30) is deferred to the type checker rather than reported by this pass. Fixtures: crates/wolf_sema/tests/snapshots/diagnostics__e0301_member.snap, crates/wolf_sema/tests/snapshots/diagnostics__e0301_typo.snap ## E0302 — the same name is defined twice in one module A directory is one module in wolf: every `.lu` file in it contributes to a single shared namespace, and each top-level name may be defined only once across all of them (D32). The second definition is the flagged one; the other definition's location is shown alongside so you can pick which to keep. Rename one of them, or delete one — file boundaries do not create scopes, so moving a definition to a sibling file changes nothing. If both definitions really are different things, one of them probably belongs in its own subdirectory, which *is* a new module. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__resolve__dupdef__main.snap, crates/wolf_sema/tests/snapshots/diagnostics__e0302_duplicate.snap ## E0303 — modules import each other in a cycle Imports between wolf modules must form a DAG — a module cannot depend on itself through any chain of `use` declarations (D32). The message draws the whole cycle (`a → b → a`) and points at every `use` that participates, because the fix is rarely at the flagged line alone. The standard cure is to extract the pieces both sides need into a third module that each of them imports; the cycle disappears and the shared surface gets a name. Acyclic imports are what make wolf's module-parallel compilation and interface hashing possible, so there is no escape hatch. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__resolve__cycle__main.snap, crates/wolf_sema/tests/snapshots/diagnostics__e0303_cycle.snap ## E0304 — the item exists but is not visible from here The name resolves — the module you imported really does define it — but the item is private, and private is the default in wolf: visibility is granted with a keyword, never guessed from a naming convention. To use the item from another module, its definition needs `pub` (exported to everyone) or `pub(pkg)` (visible only within this package); the message names the visibility the access would need. If the item is deliberately private, the module means to hide it — look for the `pub` function it exposes instead. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__resolve__private__main.snap, crates/wolf_sema/tests/snapshots/diagnostics__e0304_private.snap ## E0305 — this import is never used Nothing in this file mentions the imported name, and an unused import is a hard error in wolf, not a lint: imports are the bounded, honest statement of what a file depends on, and dead ones rot fast (D32). Delete the line — the suggested edit does exactly that, and `wolf fix` can apply it unattended. Imports are file-scoped, so a name used only in a *sibling* file must be imported there, not here. There is no `import _` escape at v1; if you need an import purely for its side effects, comptime registration (D29) is the sanctioned pattern. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__resolve__unused__main.snap, crates/wolf_sema/tests/snapshots/diagnostics__e0305_unused.snap ## E0306 — an import that collides with another binding Each imported name must be new in its file: importing the same name twice (even from two different paths), importing something that a module-level definition already claims, or importing the module you are standing in all report this error. The colliding binding's location is shown alongside. Drop the redundant import, or give one side its own name with `use long.path as other_name`. `import c` headers are exempt from the twice rule — every `import c` feeds the same `c` namespace, so repeating it with a new header is the normal form. Fixtures: crates/wolf_sema/tests/snapshots/diagnostics__e0306_duplicate_import.snap ## E0401 — the types do not match The workhorse type error: an expression has one type, and the place it sits requires another. Wolf tracks *why* the requirement exists — a return type declared on the function, a parameter of the called function, a `let` annotation, the other operand of an operator — and the message points at that origin as well as the mismatch, so you can decide which side is wrong. When an `if` or `match` is used as a value and its branches disagree, neither branch is reported as "expected": both are shown, because the fix may belong to either. For large types the message names only the differing parts (a structural diff) instead of making you eyeball two long renderings. Note that wolf never converts numbers implicitly — `int` and `i64` are simply different types, and the fix is an explicit `as` conversion. Fixtures: crates/wolf_doc/tests/snapshots/generator__index_json_schema.snap, crates/wolf_doc/tests/snapshots/generator__module_page.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__arg_vs_return.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__coerce_no_widening.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__if_branch.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0401_arg_vs_return.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0401_deep_diff.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0401_if_branches.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0401_int_vs_float.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0401_let_annotation.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0401_match_arms.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0401_return_provenance.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0401_truthiness.snap ## E0402 — wrong number of arguments in a call The function exists and the call is well-formed, but the argument count does not match the function's parameter list — every wolf parameter is required (there are no optional or variadic parameters at v1), so a call must pass exactly as many arguments as the signature declares. The message shows where the function is defined so you can compare the lists side by side. Passing too many arguments often means an argument was meant for a different call; passing too few often means a value was dropped while refactoring. Check the order too: a swapped argument pair usually surfaces as a type mismatch on the *next* argument. Fixtures: crates/wolf_doc/tests/snapshots/generator__index_json_schema.snap, crates/wolf_doc/tests/snapshots/generator__module_page.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__arg_count.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0402_arg_count.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0402_assert_arity.snap ## E0403 — no such field Member access resolved the value's type, but that type has no field with this name. When a near-miss exists ("did you mean `radius`?") the message suggests it — most unknown fields are typos. Otherwise the struct's actual fields are listed, and the struct's definition site is shown so you can check which version of the type you are holding. Methods are looked up separately from fields: if you meant to *call* something, the parentheses matter — `p.len` is a field access, `p.len()` is a method call. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__field_typo.snap, crates/wolf_sema/tests/snapshots/method_diagnostics__e0403_unknown_method.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0403_field_typo.snap ## E0404 — this would be an infinite type Unification found a type that would have to contain itself — the classic case is applying a function to itself (`f(f)`), which needs a type `t = fn(t) -> …` that expands forever. No finite type satisfies the constraint, so wolf stops and shows the cycle rather than looping. This almost always signals a confusion one level up: a closure passed where its *result* was meant, or a recursion through values where a named recursive *type* (a struct or enum, which may mention itself by name) was intended. Introduce a named type or an explicit annotation at the point where the cycle closes. Fixtures: crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0404_infinite.snap ## E0405 — the type here cannot be inferred Nothing in the body pins this type down. Wolf infers freely *inside* function bodies, but the information must come from somewhere: literal types default by rule (`i32` for integers, `f64` for floats), closure parameters take their types from the context the closure is checked against, and everything else must flow from a use. A closure bound to a plain `let` and never given context is the common case — annotate its parameters (`fn(x: int) …`) or pass it directly to the call that gives it a type. This is deliberately an error, not a guess: an arbitrary default here would change meaning silently (D27). Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__ambiguous.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0405_cannot_infer.snap ## E0406 — this is not a function, so it cannot be called Call syntax `value(args)` applies only to functions and closures, and the thing being called here is neither — commonly a struct name (wolf constructs structs with braces: `Point { x: 1, y: 2 }`, not `Point(1, 2)`), a value that lost its function type to a shadowing binding, or a field that holds data rather than a closure. The message names the type the callee actually has. If you expected a method, note that methods resolve through the receiver's type, not this path — and a field holding a closure *is* callable as `x.field(…)`. Fixtures: crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0406_not_callable.snap ## E0407 — an item is missing its type annotation Items — functions, `const`s, module-level `let`/`var` bindings — declare their full signatures in wolf; inference happens only *inside* function bodies (D27). This is the separate-compilation firewall: a module's interface must be readable from its signatures alone, so an item's type may never depend on running inference over its body (SE-0244 calls the alternative "a mistake"). The compiler may well know the type — when the initializer makes it obvious, the suggested fix states it — but you still write it down: the annotation is what your callers, incremental rebuilds, and future readers depend on. Fixtures: crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0407_missing_annotation.snap ## E0408 — struct literal fields do not match the struct A struct literal must initialize every field of the struct exactly once — wolf has no field defaults and no partial construction, so a missing field is an error here at the literal, and a repeated field is an error on the second write. The message lists what is missing (or flags the duplicate) and points at the struct's definition. If many call sites want a "default" shape, the wolf pattern is an ordinary function that builds one (`fn default_config() -> Config { … }`) — explicit, checkable, and versioned with the type. Fixtures: crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0408_missing_field.snap ## E0409 — the operator does not work on this type Each operator family in wolf works on a fixed family of types: arithmetic (`+ - * / %`) on numbers, ordering (`< <= > >= <=>`) on numbers and on `str` (byte-lexicographic — lupin's byte order, no collation), logic (`&& || !`) on `bool` exactly, bitwise and shifts on integer types. This operand is outside the operator's family. Two classics: wolf has no truthiness, so `if x` on a number must be written as a comparison (`x != 0`); and `+` does not join strings — interpolation does (`"{first}{second}"`), which formats any primitive and never surprises you with a numeric `+` overload. Operators on user types come from traits, and need the trait in scope. Fixtures: crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0409_logic_on_int.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0409_string_plus.snap ## E0410 — a `let` binding cannot be assigned again `let` names a value once: the binding is immutable for its whole scope (spec/01 `[gram.item.let]` — "`let` immutable, `var` mutable"), and that covers plain assignment and every compound form (`=`, `+=`, `-=`, …). A binding you intend to update is declared with `var` instead — the fix-it offers exactly that edit. When the second value is really a *new* thing rather than an update to the old one, the wolf idiom is shadowing: a second `let x = …` introduces a fresh binding under the same name without mutating the first. Function parameters and `match` bindings are not `let` bindings; their mutability is governed by modes (`mut`, `take`), not by this rule. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__let_compound_assign.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__let_reassign.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__let_shadow_var_ok.snap, crates/wolf_sema/tests/snapshots/diagnostics__e0410_compound.snap, crates/wolf_sema/tests/snapshots/diagnostics__e0410_global.snap, crates/wolf_sema/tests/snapshots/diagnostics__e0410_let_reassign.snap ## E0411 — `str` has no character indexing Strings in wolf are UTF-8 byte slices, and byte offsets are the one honest currency (D25): `s.len` counts bytes, `find` returns byte offsets, and slicing (`s[a..b]`) takes byte offsets — checked, so an out-of-range offset or one that splits a multi-byte code point is a deterministic `bounds` fault, never UB and never a garbled character. What does not exist is `s[i]`: a single index cannot honestly name "a character" (code point? byte? grapheme?), so wolf refuses to guess. Reach for the operation you mean: a byte slice `s[i..j]` (or the recoverable `s.get(i..j)`), the byte view `s.bytes()`, or the search methods that hand back offsets. The end-relative forms are slices too: `s[^n..]` keeps the last `n` bytes, `s[..^n]` drops them — a single `s[^1]` is still character indexing and refuses the same way (negative indices are caught earlier still, as E0209 with a `^n` fix-it). Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__strings__char_index_fail.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0411_char_index.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0411_from_end_single.snap ## E0412 — this format spec is malformed A format spec (`"{x:spec}"`, D26) is a closed mini-language — `[[fill]align][+][0][width][.precision][type]` with alignment `<`/`^`/`>` and type one of `b o x X e E f` (spec §7.4 candidate, #28) — and every spec is known at compile time, so a spec the grammar cannot read is an error here, at the literal, never a surprise at run time. The common shapes: a stray character the grammar has no place for; `.` with no precision digits after it; `0` combined with an explicit fill or alignment (`{n:0>8}` zero-pads OR right-aligns — the spec must pick one, the compiler never picks silently); a multi-byte fill (width counts bytes, D25, so the fill must be a single byte); a width or precision beyond the 65535 cap. Note `{n:08}` is well-formed: the `0` is the zero-pad flag and `8` the width — zero-padding goes after the sign, so `{-42:06}` renders `-00042`. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__strings__format_spec_malformed.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0412_align_as_fill.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0412_malformed.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0412_zero_with_align.snap ## E0413 — the format spec does not fit this value's type Format specs are typed (D26): each field of the spec mini-language means something for specific hole types, and a field applied to a type it cannot describe is a compile error at the interpolation — never a silently ignored spec (the wolf-lang#10 rule) and never a runtime failure, because every spec is comptime-known. The rules: `+` prints a sign on numbers only; `0` zero-pads a number's digits; `.precision` is digits-after-the-point on a float and a maximum byte length on a `str` (never splitting a code point) — it means nothing on an integer or bool; base types `b`/`o`/`x`/`X` render integers; float notations `e`/`E`/`f` render floats. Fill, alignment, and width apply to every formattable type. Reach for the conversion first when the intent is "this number as hex, padded": `{n:>8x}` works because both fields fit an integer. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__strings__format_spec_mismatch.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0413_hex_on_str.snap, crates/wolf_sema/tests/snapshots/typecheck_diagnostics__e0413_precision_on_int.snap ## E0501 — the generic body uses something its bounds do not provide The golden rule of wolf generics: a generic body is checked once, against its declared bounds, and everything the body does with a type parameter must be provable from those bounds alone — a call site can then never fail inside the callee (D28). This body uses a capability — a trait method, an associated type or constant, an operator, `==`, a call — that no bound on the parameter provides. When a specific trait would supply it, the message says which bound to add and where; apply that edit and the body is provable again. Capabilities with no trait behind them yet (arithmetic and comparison operators arrive with the operator traits) cannot be granted by any bound today — for those, take a concrete type instead of a generic parameter. The error always lands here, at the definition, never as a backtrace out of some instantiation. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__traits__golden_arith.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__traits__golden_eq.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__traits__golden_missing_bound.snap, crates/wolf_sema/tests/snapshots/trait_diagnostics__e0501_add_bound.snap, crates/wolf_sema/tests/snapshots/trait_diagnostics__e0501_operator.snap ## E0502 — a type argument does not satisfy the generic's bound The generic function is fine — its body was proven against its bounds at its definition — but this call instantiates it with a type that does not satisfy one of those bounds: no impl of the named trait exists for the argument type. The fix is at the call, never inside the callee: pass a type that implements the trait, or write the missing `impl Trait for Type` in the trait's module or the type's module (coherence allows exactly those two homes). If the type is foreign and the trait is foreign, the sanctioned escape is an adapter: declare `type Local = distinct Foreign` and implement the trait for the adapter — same layout, free casts, its own impl set. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__traits__call_unmet_bound.snap, crates/wolf_sema/tests/snapshots/trait_diagnostics__e0502_unmet_bound.snap ## E0503 — this bound is not a trait Only traits can appear as bounds (`T: Show`) — the name written here resolves to something else: a struct, an enum, a type alias, a function, or a module. A bound is a promise about capabilities, and only traits define capability sets, so wolf rejects the bound rather than guessing what constraint you meant. Check the spelling first (a struct and the trait it implements often share a stem). This error also fires when a bound or `dyn` names a trait that declares its own input parameters: applying trait arguments inside a bound has no surface syntax yet, so such traits cannot be used as bounds today — use a trait without input parameters, or dispatch through qualified calls instead. Fixtures: crates/wolf_sema/tests/snapshots/trait_diagnostics__e0503_not_a_trait.snap ## E0504 — an impl must live with its trait or with its type Wolf's coherence rule keeps every `impl Trait for Type` findable and unique: the impl must be written in the module that defines the trait or in the module that defines the self type — nowhere else (the "simple orphan rule", D28). An impl in a third module could collide invisibly with someone else's, and which one wins would depend on who happens to be compiled together; wolf refuses instead. Move the impl into the trait's module or the type's module. When both are foreign — you own neither the trait nor the type — declare an adapter in your own module: `type Mine = distinct Theirs` has the same layout, casts freely to and from its base, starts with an empty impl set, and you may implement anything for it. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__traits__coherence_orphan__main.snap, crates/wolf_sema/tests/snapshots/trait_diagnostics__e0504_orphan.snap ## E0505 — an impl header parameter is not covered by the impl Every generic parameter of an impl must appear in the impl's subject — inside the self type or the trait's arguments. A parameter that appears nowhere (`impl[T] Show for Point`) is *uncovered*: no use of the impl could ever determine what `T` is, so the impl could apply infinitely many ways or none. Rust threads this needle with a covering rule; wolf v1 simply disallows uncovered parameters outright — simpler and more honest (D28). Delete the unused parameter, or make the impl subject actually mention it. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__traits__coherence_uncovered.snap, crates/wolf_sema/tests/snapshots/trait_diagnostics__e0505_uncovered.snap ## E0506 — two impls of the same trait overlap Global coherence means one trait has at most one impl for any given type — the program's behavior can never depend on which impl a particular call happened to see. These two impl headers can describe the same type (wolf checks by trial unification, so a blanket `impl[T] Show for T` overlaps a specific `impl Show for Point` exactly like two duplicates would), and wolf has no specialization: there is no rule that could pick a winner, deliberately (D28 — locked). Delete one impl, or narrow the blanket so the two sets of types are disjoint. Overlap is judged on headers alone; bounds on the impls do not disambiguate them. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__traits__coherence_overlap.snap, crates/wolf_sema/tests/snapshots/trait_diagnostics__e0506_overlap.snap ## E0507 — the impl does not match the trait it implements An `impl Trait for Type` must supply exactly what the trait declares: every required method with the same signature (after substituting the implementing type for `Self`), every associated type bound to a concrete type, and every associated constant at its declared type. This impl is missing a member, binds one at the wrong signature, or defines a member the trait never declared — extra members do not become part of the trait, because callers dispatch through the trait's declaration, not through any particular impl. The message names the member and shows the trait's declaration; make the impl agree with it. Fixtures: crates/wolf_sema/tests/snapshots/ctfe_diagnostics__staged_provenance_chain.snap, crates/wolf_sema/tests/snapshots/trait_diagnostics__e0507_mismatch.snap, crates/wolf_sema/tests/snapshots/trait_diagnostics__e0513_cycle.snap ## E0508 — the trait cannot be a `dyn` object: a generic method A `dyn Trait` value carries a witness table — one function pointer per method, fixed when the table is built. A generic method would need one entry per instantiation, a set that is not known until every caller is seen, so no finite table can represent it (the RFC 0255 model). The message names the offending method. Either drop the method's generic parameters (take a concrete type, or `dyn` of another trait, as the parameter), split the trait so the dynamic part is generic-free, or keep this trait static-only — generics over `T: Trait` have no such restriction and are wolf's default dispatch. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__traits__dyn_generic_method.snap, crates/wolf_sema/tests/snapshots/trait_diagnostics__e0508_dyn_generic.snap ## E0509 — the trait cannot be a `dyn` object: an unconstrained associated type or input escapes This trait's methods mention an associated type (or the trait declares input parameters), and a `dyn Trait` object erases exactly the information that would pin those down: two objects behind the same `dyn Trait` may answer `Self.Item` with two different types, so a method signature that exposes it has no single ABI to dispatch through. Wolf has no surface syntax yet for constraining an associated type at a `dyn` spelling, so any escape makes the trait dyn-unsafe. Keep the associated type out of the dynamic methods' signatures, split the trait, or use static generics (`T: Trait`), where associated types work fully. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__traits__dyn_assoc_escape.snap, crates/wolf_sema/tests/snapshots/trait_diagnostics__e0509_dyn_escape.snap ## E0510 — the trait cannot be a `dyn` object: `Self` outside receiver position Behind `dyn Trait`, the concrete type is erased — only the object itself knows what it is. A method that takes another `Self` as an ordinary parameter or returns `Self` by value would require the caller to name the erased type, which is exactly what `dyn` gave up (the RFC 0255 self-position rule; the receiver itself is fine, because the object supplies it). The message names the method. Replace the loose `Self` with a concrete type or another `dyn Trait`, or keep this trait to static generics, where `Self` is a known rigid type and all of this checks. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__traits__dyn_self_position.snap, crates/wolf_sema/tests/snapshots/trait_diagnostics__e0510_dyn_self.snap ## E0511 — a generic parameter cannot take type arguments Wolf generics are rank-1 over *types*, not over type constructors: a parameter `T` stands for one complete type, so applying it — `T[int]` — asks for higher-kinded polymorphism, which wolf does not have and v1 deliberately excludes (D28: the ceilings are spec'd, not discovered). The checking cost of higher kinds is a proof search wolf refuses to run; "the executed steps are in the source." Take the applied type as its own parameter instead: where you wanted `T[int]`, accept `U` and let the caller pass `List[int]` whole. Fixtures: crates/wolf_sema/tests/snapshots/trait_diagnostics__e0511_hkp.snap ## E0512 — associated types cannot have their own generic parameters An associated type inside a trait is an *output*: each impl binds it to one concrete type. Giving it generic parameters of its own (`type Item[X]`) would make it a generic associated type — a family of outputs indexed by types — which wolf v1 deliberately does not have (D28: no GATs; the ceilings are stated up front, Roc-style, rather than discovered at the bottom of an error). Restate the trait so the parameter lives on the trait itself or on the method that needs it; both of those are plain rank-1 generics and check today. Fixtures: crates/wolf_sema/tests/snapshots/trait_diagnostics__e0512_gat.snap ## E0513 — associated-type bindings form a cycle The associated types of this impl are defined in terms of each other — following the bindings (`type A = Self.B`, `type B = Self.A`) never reaches a concrete type. Wolf normalizes associated types by textual rewriting to a fixed point, which is deterministic and always terminates precisely because cyclic rule sets are rejected here instead of being chased forever (Carbon's rewrite-constraint model, D28). Bind at least one of the associated types in the cycle to a concrete type and let the others build on it. Fixtures: crates/wolf_sema/tests/snapshots/trait_diagnostics__e0513_cycle.snap ## E0601 — the error row is not well-formed An error row is a *set* of payload-carrying tags, so each tag may appear exactly once — `{Io(str), Io}` is rejected on the second `Io`, not silently merged, because two entries for one tag would disagree about its payload. The same rule keeps a row to at most one row variable (the entry naming a generic parameter, the row's polymorphic tail): a row extends exactly one tail. Delete the duplicate entry, or if the two entries really are different failures, give them different tag names — tags are structural, so any name you have not used yet is free. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__rows__negative__dup_tags.snap, crates/wolf_sema/tests/snapshots/row_diagnostics__e0601_duplicate_tag.snap ## E0602 — the error row does not include this tag An error can only flow where the receiving row expects it. This failure carries a tag — raised directly, or propagated by `?` from a callee's row — that the target row does not include. Rows compose by union and widen automatically toward *larger* rows, so the fix is almost always to extend the narrower row: the suggested edit adds the missing tags to the signature. There is no `From`-style conversion in `?` (deliberately — conversion in the operator makes inference unsolvable); if you meant to *collapse* several failure kinds into one, do it explicitly: handle the error (`else |err| …`) and raise your own tag. Functions with an inferred row (`-> !T`, private only) never hit this error — their rows grow to fit their bodies. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__rows__negative__missing_tag.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__rows__negative__open_into_closed.snap, crates/wolf_sema/tests/snapshots/pattern_diagnostics__e0602_pattern_unknown_tag.snap, crates/wolf_sema/tests/snapshots/row_diagnostics__e0602_large_rows.snap, crates/wolf_sema/tests/snapshots/row_diagnostics__e0602_missing_tag.snap ## E0603 — `?` needs a fallible operand The `?` operator propagates the error of a `!T` value and unwraps its ok half — but the expression it is applied to here cannot fail: its type has no error row. A `?` on an infallible value would do nothing, and wolf rejects dead operators rather than ignoring them, since a stray `?` usually means the call you expected to be fallible is not (check the callee's signature), or the value was already unwrapped by an earlier `?` or `else`. Delete the `?`, or apply it to the fallible call itself. Fixtures: crates/wolf_sema/tests/snapshots/row_diagnostics__e0603_try_infallible.snap ## E0604 — an error cannot leave a function with no error row This function's signature has no error row — it promises to always return normally — but the body raises or propagates an error (`?`, or an error-tag return). Errors are values that travel in the declared row, never an invisible side channel, so the signature must admit the failure. Make the function fallible: write `-> !T` (private functions infer their row from the body) or state the row explicitly with `-> T ! {Tag, …}`; or handle the error here instead — `else` with a default, or `else |err| …` — so nothing needs to escape. Fixtures: crates/wolf_sema/tests/snapshots/row_diagnostics__e0604_nonfallible_caller.snap ## E0605 — an exported function must state its error row Inferred rows (`-> !T`) are legal for module-private functions only: the compiler seals the row from the body, and no one outside the module ever depends on it. An exported (`pub`/`pub(pkg)`) signature is a contract other modules rebuild against, so its failure set must be stated in the interface, not derived from a body that can drift — Zig's inferred error sets show how an inferred public surface breaks recursion, function pointers, and target independence. The message names the sealed row the body implies; the suggested edit writes exactly that row into the signature (or drops the `!` when the body cannot fail at all). Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__rows__negative__pub_inferred.snap, crates/wolf_sema/tests/snapshots/row_diagnostics__e0605_pub_inferred.snap ## E0606 — the payloads of a shared error tag do not match Two rows share a tag name, but disagree about what the tag carries — `NotFound(Path)` cannot propagate into a row expecting `NotFound(str)`, and a raise of `Bad(int, int)` does not fit a row declaring `Bad(int)`. Tag names are structural, so the same name in two signatures is *the same tag*, and its payload types must agree everywhere it appears (propagation re-tags by injection — a bit-level move, never a conversion). Align the payload types across the signatures, or give the two failures different tag names if they are genuinely different shapes. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__rows__negative__payload_mismatch.snap, crates/wolf_sema/tests/snapshots/row_diagnostics__e0606_payload_mismatch.snap ## E0607 — `errdefer` only runs in a function that can fail `errdefer` schedules cleanup for the *error path*: it runs only when the function exits by returning an error, interleaved with `defer` in reverse declaration order. In a function with no error row there is no error path, so this `errdefer` could never run — wolf rejects dead cleanup rather than silently keeping it. Use plain `defer` if the cleanup should run on every exit; keep `errdefer` and make the function fallible (`-> !T` or an explicit row) if this function really can fail. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__rows__negative__errdefer_infallible.snap, crates/wolf_sema/tests/snapshots/row_diagnostics__e0607_errdefer_infallible.snap ## E0608 — `else` defaulting needs a fallible operand Postfix `else` is the defaulting operator: it takes a `!T` value and either substitutes the fallback or hands the error to a `|err|` handler. The expression to its left cannot fail, so there is nothing to default — the `else` would never fire. This usually means the fallible call was already unwrapped (an earlier `?` or `else`), or the callee is not actually fallible. Delete the `else`, or attach it to the fallible expression itself. (An `else` completing an `if` is a different construct — this message is about `expr else fallback`.) Fixtures: crates/wolf_sema/tests/snapshots/row_diagnostics__e0608_else_infallible.snap ## E0701 — comptime code reached for ambient IO Comptime evaluation is hermetically sandboxed (D33): no filesystem, no network, no environment variables, no clock, no randomness, no FFI — the intrinsics available at compile time are an explicit allowlist, and nothing ambient is on it. Each refusal names its category and its reason: confinement (compiling a package must never act on or read the machine that compiles it — `wolf add` must never mean arbitrary code runs with your credentials) or determinism (the same program and target must produce bit-identical comptime results on every host). Compute the value at runtime instead; file contents belong in *declared build inputs* through the package manifest, never in an evaluator capability. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__sandbox_clock.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__sandbox_env.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__sandbox_exec.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__sandbox_ffi.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__sandbox_fs.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__sandbox_io.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__sandbox_net.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__sandbox_net_socket.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__sandbox_random.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0701_clock.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0701_exec.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0701_ffi.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0701_fs.snap ## E0702 — comptime evaluation ran out of fuel Every comptime evaluation runs under an instruction budget, so a runaway computation ends in this report instead of a hung build — the budget also bounds comptime as an attack surface (D33). The diagnostic carries the comptime call backtrace, so the loop or recursion that burned the fuel is visible. If the computation is genuinely that large, raise the budget at the call site with `#[budget(fuel = N)]` — budgets have defaults, per-site overrides, and a hard ceiling; no spelling disables one. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__fuel_loop.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0702_fuel_fixit.snap ## E0703 — comptime evaluation exceeded its heap budget Comptime code allocates values in a compiler-owned arena with a hard cap, so evaluation can never exhaust the machine compiling the program (D33). Most overruns are unbounded value growth inside a loop — each iteration building a strictly larger value. The diagnostic points at the allocation that crossed the cap with the comptime backtrace attached. If the computation legitimately needs more, raise the cap at the call site with `#[budget(heap = N)]`; like all comptime budgets it has a hard ceiling and cannot be turned off. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__heap_flood.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0703_heap.snap ## E0704 — comptime evaluation recursed too deeply The comptime evaluator keeps its own explicit call stack, so deep recursion is a *resource limit* with a report, never a compiler crash (D33). The default depth accommodates ordinary recursive folds; an overflow usually means the recursion is missing its base case — the backtrace shows the repeating frame. If the depth is intentional, raise it at the call site with `#[budget(depth = N)]`, up to the hard ceiling; consider an iterative shape instead, which spends fuel rather than frames. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__depth_spiral.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0704_depth.snap ## E0705 — this value is not comptime-known A `comptime fn` runs during compilation, so every argument must be known at compile time: a literal, a `const`, a type, or the result of another comptime call. A runtime `let`/`var` local, a runtime global, or a self-referential `const` cannot cross into comptime position — the evaluator will not guess at a value the program has not produced yet. Bind the value with `const`, pass a literal, or move the computation to runtime if the input genuinely arrives at runtime. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__runtime_arg.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0705_runtime_arg.snap ## E0706 — comptime arithmetic faulted Checked arithmetic has exactly one semantics everywhere (X3): an operation that would trap at runtime — overflow past the declared width, division or remainder by zero, an out-of-range shift — is a compile error when it happens at comptime, at the declared widths of the declared target, never the host's. Intended wraparound is spelled in the type system as `wrapping[T]`, and wraps identically at comptime; there is no flag, profile, or mode that changes any of this. Fix the computation, widen the type, or spell the wraparound. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__overflow_i32.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0706_overflow.snap ## E0707 — const-generic equality needs a witness Const-expression equality in generic position is decided in three steps, and the line between them is fixed: (1) closed expressions fully evaluate and compare by value; (2) linear `+`/`-` arithmetic over generic parameters compares by ring normalization — `N + 1` equals `1 + N`, killing the Rust RFC-2000 identity-only wart at a defined line; (3) anything beyond linear — `*`, `/`, `%`, shifts, bit operators — is compared only by identical spelling, and differing spellings require an explicit witness. This error is step 3 firing: the two forms may well be equal, but the compiler will not run a decision procedure it cannot bound. Rewrite both sides into the same `+`/`-` form, or assert the equality where the reader can see it. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__norm_witness.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0707_witness.snap ## E0708 — layout is unresolved until codegen Sizes and offsets are decided when codegen lays types out, not by the type checker — so `size_of` at comptime answers only for fixed-width primitives today, and `typeinfo` describes fields without offsets. This is a staging rule, not a permanent refusal: when layout lands, the same intrinsics answer for aggregates, and code written against them starts compiling without change. Until then, compute from the primitive widths, or defer the computation to a later phase that has layout in hand. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__size_of_layout.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0708_layout.snap ## E0709 — invalid comptime budget attribute `#[budget(fuel = N, heap = N, depth = N)]` raises the evaluation budgets for one call site. Every budget has a default and a hard ceiling, and none can be disabled — a zero value, a value beyond the ceiling, or a key that is not a budget is rejected here (the bounded evaluation guarantee is part of the D33 sandbox, so there is deliberately no spelling that removes a limit). Use one of `fuel`, `heap`, or `depth` with a positive integer at or below the ceiling. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__budget_zero.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0709_budget_zero.snap ## E0710 — a comptime assertion failed `assert` inside comptime evaluation checks a fact during compilation and stops the build when the fact does not hold — it is the witness mechanism for properties the checker cannot see on its own, such as const-generic equalities beyond the linear line (E0707) or invariants of reflected type shapes. The diagnostic points at the failing assertion with the comptime call backtrace attached. Make the asserted condition true, or delete the assertion if the invariant was wrong. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__comptime__assert_static.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0710_assert.snap, crates/wolf_sema/tests/snapshots/ctfe_diagnostics__e0710_assert_message.snap ## E0801 — this `match` does not cover every case A `match` used in wolf must handle every value its scrutinee can be — there is no implicit fall-through and no runtime "no arm matched" error, so the checker proves coverage up front and names concrete values that slip past every arm ("`Timeout` not covered", "not covered: `2`"). Arms with `if` guards do not count toward coverage: a guard can be false, so only unguarded arms prove anything. Add arms for the listed witnesses, or end the `match` with a `_` arm (or a binding) to catch the rest deliberately. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__match_missing.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__match_str_nonexhaustive.snap, crates/wolf_sema/tests/snapshots/pattern_diagnostics__e0801_enum_witnesses.snap, crates/wolf_sema/tests/snapshots/pattern_diagnostics__e0801_guard_non_contribution.snap, crates/wolf_sema/tests/snapshots/pattern_diagnostics__e0801_int_witness.snap, crates/wolf_sema/tests/snapshots/pattern_diagnostics__e0801_row_missing_tag.snap ## E0802 — this `match` arm can never match The arms before this one already cover every value its pattern accepts, so the arm is dead: its body will never run, which usually means an arm is out of order, a pattern is broader than intended, or a case was written twice. The diagnostic points at the earlier arm that swallows this one. Delete the unreachable arm, or reorder the arms so the more specific pattern comes first. (This is a warning: the program still compiles and its meaning is unchanged.) Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__match_str_arm_unreachable.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__match_unreachable.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__pattern_shape.snap, crates/wolf_sema/tests/snapshots/pattern_diagnostics__e0602_pattern_unknown_tag.snap, crates/wolf_sema/tests/snapshots/pattern_diagnostics__e0802_duplicate_literal.snap, crates/wolf_sema/tests/snapshots/pattern_diagnostics__e0802_unreachable_arm.snap, crates/wolf_sema/tests/snapshots/pattern_diagnostics__e0808_variant_over_int.snap ## E0803 — more than one trait in scope provides this method `recv.method(…)` resolves through the traits in scope, and two or more of them declare a method with this name that the receiver's type implements — wolf will not pick one by precedence, because trait namespaces are isolated by design (D28) and a silent winner would change meaning when imports change. Say which trait you mean with the qualified form the suggestion offers: `Trait.method(recv, …)`. The qualified call is always available and never ambiguous. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__method_ambiguous.snap, crates/wolf_sema/tests/snapshots/method_diagnostics__e0803_two_traits.snap ## E0804 — the receiver's mode disagrees with the method's declaration A method declares how it takes `self` — `mut self` needs exclusive access, `take self` consumes the value — and the call site must say so where the reader can see it, exactly like argument modes (X1): `(mut p).norm()`, `(take conn).close()`. A bare receiver calls only `read self` methods; conversely, a `read self` method takes no mode. Wrap the receiver in the declared mode — the suggested edit inserts `(mut …)`/`(take …)` for you — or drop the mode the method does not ask for. Whether the access is actually exclusive is checked by the memory tiers; this rule is the syntax law only. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__receiver_bare_mut.snap, crates/wolf_sema/tests/snapshots/method_diagnostics__e0804_bare_mut_receiver.snap, crates/wolf_sema/tests/snapshots/method_diagnostics__e0804_list_push_bare.snap, crates/wolf_sema/tests/snapshots/method_diagnostics__e0804_superfluous_mode.snap, crates/wolf_sema/tests/snapshots/method_diagnostics__e0804_wrong_mode.snap ## E0805 — this `as` cast is outside the cast set `as` converts within a closed set: between numeric types (integers, floats, `wrapping[T]` — explicitly, since wolf never converts numbers implicitly), and between an adapter type (`type X = distinct B`) and its base, which share a layout so the cast is free both ways. Nothing else casts: `as` is not a parser of strings, not a truthiness bridge from `bool`, and not a reinterpretation of unrelated types. Build the value you need with the operation that names it — interpolation for strings ("{x}"), a comparison for `bool` (`x != 0`), a constructor or conversion function for everything else. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__cast_bad.snap, crates/wolf_sema/tests/snapshots/method_diagnostics__e0805_bool_to_int.snap, crates/wolf_sema/tests/snapshots/method_diagnostics__e0805_str_to_int.snap ## E0806 — a refutable pattern where matching cannot fail `let`, `var`, `for`, and parameters bind unconditionally — there is no "else" branch there, so their pattern must accept every value of the initializer's type. A pattern that can *fail* to match (a literal, an enum variant, an error-row tag) needs somewhere for the other values to go: that place is `match`. Move the test into a `match` (or an `if` on the value), keeping only irrefutable patterns — names, `_`, and tuples of those — in binding position. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__refutable_let.snap, crates/wolf_sema/tests/snapshots/pattern_diagnostics__e0806_refutable_let.snap ## E0807 — the method exists, but its trait is not in scope Method calls resolve through the traits *in scope* — defined in this module or brought in with `use` — so an implemented method still does not resolve when its trait was never imported: visible resolution is what keeps a new dependency from silently changing what `.method()` means (D28). The suggestion adds the `use` for the one trait that declares this method; after that the call resolves normally. The qualified form `Trait.method(recv, …)` works too, and needs the same import. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__method_scope__main.snap, crates/wolf_sema/tests/snapshots/method_diagnostics__e0807_out_of_scope.snap ## E0808 — the pattern does not fit the shape of the value A pattern mirrors the value it deconstructs, piece for piece: an enum variant or error tag with a payload is matched as `Name(pat, …)` with exactly as many sub-patterns as the payload has parts, a payload-less one as bare `Name`, and a tuple pattern needs the scrutinee to be a tuple of that width. This pattern binds a different number of pieces than the value carries, so it can never be checked against it. Match the declared shape — the diagnostic names it — adding `_` for pieces you do not need. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__pattern_shape.snap, crates/wolf_sema/tests/snapshots/pattern_diagnostics__e0808_payload_arity.snap, crates/wolf_sema/tests/snapshots/pattern_diagnostics__e0808_variant_over_int.snap ## E0809 — the handler pattern does not cover the row An `else` handler runs for every error its operand can carry — there is no second handler waiting behind it. A payload pattern in handler position (`else |Tag(p)|`) therefore has to cover the operand's whole row: on a single-tag row it destructures that tag's payload directly, and that is the form's purpose. On a wider row some error would reach a handler whose pattern rejects it, and no meaning exists for that moment. Bind the error and branch instead — `else |e| match e { … }` — which checks every arm for coverage the ordinary way. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__rows__else_tag_payload.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__rows__negative__handler_uncovered.snap, crates/wolf_sema/tests/snapshots/pattern_diagnostics__e0809_handler_uncovered.snap ## E1001 — this value was moved away (or never given one) before this use In wolf, assignment and argument passing *move* a value: after `let b = a` or `f(take a)`, the name `a` no longer holds anything — its value went to the new place, whole. Reading a moved-from (or never-initialized) name would read nothing, so the checker stops it here and points at the move it happened in. Moves are field-granular: moving `s.a` away leaves `s.b` usable, and only the moved path is off-limits. To keep using the original, make the duplication explicit where the move happens — `copy a` produces an independent value of any type — or give the name a new value first: assigning to a moved-from place makes it live again. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__move_use_after.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1001_branchy_move.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1001_defer_capture.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1001_partial_move.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1001_partial_reinit_residue.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1001_whole_value.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1002_take_while_mut.snap ## E1002 — this needs exclusive access, but the value is in use here While a value is passed `mut`, that call is the only way to touch it: `mut` means "mine alone for the whole call", so no other argument of the same call may read or write the same place, or any path that contains it ([mem.tier0.excl]). Distinct fields are distinct places — `f(mut p.x, mut p.y)` is fine — but `f(mut p, p.x)` is not, because `p.x` lives inside `p`. Split the call so the uses happen one after the other, pass disjoint fields instead of the whole value, or let the callee say what it really touches with a view set (`mut self.{x, y}`), which frees the caller to use the rest. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__excl_overlap.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__mut_read_overlap.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1002_copy_read_after_mut.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1002_prefix_mut_mut.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1002_read_while_mut.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1002_take_while_mut.snap ## E1004 — this value is placed in one region, but needed in another Every allocation lands in exactly one region — the innermost enclosing `region`/`in` block, else the caller's region — and it stays there for its whole life: moving a value never relocates its storage. Embedding a value into an aggregate that lives somewhere else would therefore create a reference between two regions, which safe wolf does not allow (one region could be freed while the other still points in). The diagnostic marks where each side was allocated; make the two placements one: build the value inside the same `region`/`in` block as its container, or `copy` it — a copy is a fresh allocation in the ambient region, so it lands where the container lives. When the two sides are different *parameters*, their regions are independent by default (that independence is what lets callers pass arguments from anywhere without annotations), and the same two fixes apply. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__region_conflict_params.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1004_cross_region_store.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1004_params_independent.snap ## E1005 — the region is open here, so its handle cannot move or freeze A region transfers as a closed subtree only: while a `region` block or `in` window is open, the region's affine value — its handle — is pinned in place, because the open window *is* a live borrow of that handle. Moving it, freezing it, sending it, or lending it `mut` while inside would leave the window standing on a region that belongs to someone else (or to nobody). The same rule covers a region whose *child* region is still open: the forest moves as closed subtrees, never around an open window. End the `region`/`in` block first and transfer after, or transfer first and open on the receiving side. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__region_freeze_open.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__region_move_while_open.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__region_transfer_open.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1005_freeze_while_open.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1005_move_while_open.snap ## E1006 — this type's `shared` references form a strong cycle `shared T` is reference-counted: the value is freed the moment its last strong reference drops. A cycle of strong references keeps itself alive forever — every cell waits on the others — and wolf has no cycle collector, because a leak is not an answer either. So strong `shared` edges must form a DAG, checked right here at the type definition ([mem.shared.rc.2]). Break the cycle at its back-edge: make that field `weak T` (upgrade to reach the value, it does not keep it alive) or `handle T` (a generational index that faults if the target is gone). If the structure is genuinely cyclic — a graph, a doubly-linked list — keep the whole structure inside one region instead: intra-region cycles are safe and free ([mem.region.intra.1]), and the region frees them wholesale. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__shared_cycle.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1006_cycle_through_list.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1006_direct_strong_cycle.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1006_two_type_cycle.snap ## E1007 — the argument's mode does not match the parameter's A parameter's mode is part of the deal between caller and callee, and wolf makes the caller spell it at the call site (X1): a `mut` parameter is written `f(mut x)` — the reader sees the mutation — and a `take` parameter is written `f(take x)` — the reader sees the value leave. This argument's spelling disagrees with the declaration: a mode is missing, or written where the parameter does not ask for one. The suggested edit inserts or removes the mode word at the argument; the parameter's declaration is marked so you can decide which side is wrong. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__mode_missing_mut.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1007_extra_mut.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1007_missing_mut.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1007_missing_take.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1007_take_where_mut.snap ## E1008 — the method touches a field outside its declared view `fn norm(mut self.{x, y})` is a promise: of all of `self`, this method touches only `self.x` and `self.y`. Callers lean on that promise — it is what lets them keep using `self.z` while the call runs — so a use of a field outside the view set (or of `self` whole) would quietly break every call site. Add the field to the view set if the method genuinely needs it, or drop to plain `mut self` to claim the full value — both change the signature, which is exactly where that decision belongs. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__view_set_violation.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1008_view_violation.snap ## E1009 — a `mut` argument needs a place, not a temporary `mut` lends a location out to be written, so the argument must *name a location* the caller can see again afterwards: a variable, a field path like `p.x`. A temporary — `f(mut 1 + 2)`, `f(mut g())` — has no such location: the callee's writes would vanish with it, which is never what the call meant. Bind the value first (`var t = …`, then `f(mut t)`), or pass the expression plainly if the callee only needs its value. (`take` of a temporary is fine — consuming a value nobody else owns needs no location.) Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__mut_arg_temporary.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1009_mut_temporary.snap ## E1010 — the value's region is freed while the value is still needed A region dies as a unit: when a `region` block ends (or a region value's scope does), every allocation in it is freed wholesale — that is the whole deal, one free instead of thousands. This value is allocated in such a region, but something that lives longer still holds it: an outer binding, the function's result, or module state. After the free, that holder would point at nothing. Keep value and region together: build the value outside the region block so it lands in the caller's region, aim the allocation at a longer-lived region explicitly (`let r = region()` … `in r { … }`), or widen the region block so it covers every use. Note that `copy` inside the block does not help — a copy is a fresh allocation in the *current* ambient region, which is still the dying one. `freeze` (making the whole region immortal and immutable) and `shared` (counted escape) are coming in later tiers for the cases that genuinely need to outlive the region. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__region_escape_container.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__region_escape_local.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1010_escape_via_binding.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1010_escape_via_value.snap ## E1011 — this would open a region while a region that contains it is open Any number of regions may be open at once, provided none of them contains another: the open set must be an antichain in the region forest ([mem.region.multiopen]). Sibling regions have disjoint data, so mutating through both windows at once is safe — but an owner's window already reaches everything its child region holds, so opening the child (or the owner) while the other is open would put one location behind two live mutable windows. The diagnostic marks both open sites. Close the first block before opening the second, or restructure so the two regions are siblings — neither stored inside the other — and open them together freely. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__region_open_ancestor.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1011_ancestor_open.snap ## E1012 — frozen data cannot be written `freeze` consumes a region and promotes everything in it to `imm`: deeply immutable, shareable from anywhere — across threads, without synchronization — and readable forever. That deal is permanent, and it is why frozen data needs no locks and no lifetimes; a single write anywhere would break every reader everywhere. This write reaches data that a `freeze` already promoted (the freeze site is marked). Do the mutation before freezing — build the value completely, freeze last — or keep a mutable `copy` alongside the frozen original for the part that must keep changing. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__region_freeze_write.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1012_reopen_frozen.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1012_write_through_frozen.snap ## E1013 — the container changes while a `for` loop iterates it `for x in xs` walks the container in place: the loop holds a read claim on `xs` for its whole extent, so the sequence being walked cannot grow, shrink, or move away mid-flight ([mem.iter.excl]). A `push`, `pop`, `clear`, element write, or move of `xs` inside the body changes the very thing the loop is standing on, and there is no coherent answer for what the next iteration should see. Collect the changes first and apply them after: gather them into a second list inside the loop, then apply to `xs` once the loop is done. Or take explicit control with an index loop — `var i = 0` and `while i < xs.len { …; i += 1 }` — where every pass re-reads the length and every access is its own bounds-checked read, so the loop's condition decides what growth means. (The claim is a read, not a move: `xs` stays live behind the walk and after it.) Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__list_mutate_while_iter.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1013_move_while_iterating.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1013_push_while_iterating.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1013_reassign_while_iterating.snap ## E1014 — a `read` parameter cannot be written A parameter with no mode word is `read`: the callee sees a value that is immutable for the whole call, and the caller keeps it ([mem.tier0.mode.read]) — absence is the syntax, and immutability is the deal it spells. This write reaches such a parameter; writes through its fields and elements count too, because the immutability is deep for the call's duration, and so does lending it `mut` to another call. Declare the parameter `mut` if this function's purpose is to change the caller's value — call sites then spell `f(mut x)`, so readers see the mutation. Declare it `take` if the function consumes the value and the caller is done with it. Or keep it `read` and work on this function's own duplicate: `var local = copy p` gives a value it owns outright. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__read_param_write.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1014_mut_lend.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1014_projected_write.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1014_read_self_write.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1014_whole_and_compound.snap ## E1101 — a task may not mutate state it captured from the enclosing function A spawned task's closure captures by value: `Copy` data copies, `imm` data shares, and a region must `move` (D14's verbs). What no capture mode provides is a mutable window onto the enclosing function's locals — this closure writes to a captured binding, which would be exactly the shared-mutable-state shape the memory model exists to forbid ([conc.task.spawn]). Tasks share by communicating instead: make a `channel` and send the result to the one owner who mutates, or, when the state truly is shared, guard it with a `Mutex` and do every access inside a `when` block, whose body has exclusive access to the payloads. The write the checker flagged would otherwise land on the task's private copy at best and race at worst. A write is not only an assignment. Handing a captured binding to a callee in `mut` mode — `(mut xs).push(1)` on the receiver, `f(mut xs)` at an argument — opens the same exclusive window, and for handle-backed state such as a `List` the callee's write reaches the enclosing function's allocation rather than the task's copy. Both spellings are this diagnostic. Fixtures: crates/wolf_diag/tests/snapshots/render_snapshots__teach_note_grouped.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__conc__capture_mut_arg.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__conc__capture_mut_lend.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__conc__capture_write_assign.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__conc__store_buffer.snap, crates/wolf_sema/tests/snapshots/conc_diagnostics__e1101_mut_lend_argument.snap, crates/wolf_sema/tests/snapshots/conc_diagnostics__e1101_mut_lend_receiver.snap, crates/wolf_sema/tests/snapshots/conc_diagnostics__e1101_projection_write.snap, crates/wolf_sema/tests/snapshots/conc_diagnostics__e1101_task_capture_write.snap, crates/wolf_sema/tests/snapshots/conc_diagnostics__e1101_two_spawns_note_once.snap ## E1102 — this channel's payload type is not sendable `channel[T](n)` carries values between tasks, so `T` must be safe to hand across a task boundary: `Copy` data, `imm` data, a region value (the send is its affine `move`), or a `sync` type ([conc.chan.type]). The payload type here is none of those — sending it would either alias one mutable value from two tasks or silently copy something whose identity matters. D14's three verbs are the ways out: `move` the data into a region and send the region, `freeze` it into `imm` data that shares by reference, or wrap it in a `sync` type such as a `Mutex` and share that. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__conc__chan_unsendable.snap, crates/wolf_sema/tests/snapshots/conc_diagnostics__e1102_unsendable_payload.snap ## E1103 — `when` blocks do not nest `when (a, b, …)` acquires its whole operand set before the body runs, in one canonical order — which is the construction that makes lock-order deadlock impossible ([conc.when.nodeadlock]). A `when` inside another `when` body is incremental acquisition by another spelling, and it would reopen the exact deadlock the construct closed, so the nesting is rejected where it is written ([conc.when.nonest]). Merge the two operand sets into the outer block — `when (a, b, c) { … }` acquires everything at once — or end the outer block before acquiring the next set. The same acquisition reached through a call is detected at run time as trap(deadlock). Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__conc__when_nested.snap, crates/wolf_sema/tests/snapshots/conc_diagnostics__e1103_nested_through_closure.snap, crates/wolf_sema/tests/snapshots/conc_diagnostics__e1103_nested_when.snap ## E1301 — this raw-tier operation needs an `unsafe` block Raw pointers themselves are inert values: creating, copying, storing, and passing them is free in safe code (creation is not a use). What the safe tier cannot contain are the raw tier's *operations* — reading or writing through a pointer, pointer casts, provenance operations (`addr`, `with_addr`, `expose`, `with_exposed`), `assume noalias`, `borrow … from …`, and calls into imported C. Each of those can reach behavior the safe tier's guarantees do not cover, so each one lives inside the `unsafe { }` ring, where the enclosing module carries the proof obligation. Wrap the operation in an `unsafe` block — the rules inside are *simpler* than the safe tier's, not stricter — and state the invariant the block maintains in a `# Safety:` comment. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__unsafe_raw_outside.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1301_prov_outside.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1301_raw_outside.snap ## E1302 — a raw pointer type cannot cross this boundary Unsafety never appears in types crossing function boundaries: every function signature is fully safe, and there are no `unsafe fn`s — the proof obligation is discharged at the `unsafe` block, and the module is the audit granule. A `*T` in a parameter or return type, or in an exported type's fields, would silently spread the raw tier through every caller's audit surface. Keep the pointer inside: pass a `handle` (revalidated at every access) or a region value instead, or hold the `*T` in a module-private field where the module's own invariants — and its `unsafe` blocks — can vouch for it. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__unsafe_sig.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1302_ptr_in_signature.snap ## E1303 — this module holds `#[trusted]` code the manifest does not declare `#[trusted]` marks code whose unsafe blocks assert invariants the checker cannot see — allocator internals, pinned FFI regions. The deal that keeps that auditable is declaration: every module containing `#[trusted]` functions must be listed in the package manifest's `trusted` entry, so a dependency growing new trusted code is a visible diff, not a silent one (`wolf audit-surface` reads this roster). Add the module to the `trusted` list in `wolf.pkg`, or remove the `#[trusted]` attribute if the code no longer asserts unseen invariants. Fixtures: crates/wolf_sema/tests/snapshots/audit_surface__audit_e1303_undeclared.snap ## E1304 — `assume noalias` needs raw pointers to assume about `assume noalias p, q` asserts that the ranges reachable through two *raw pointers* do not overlap, for the assertion's scope — it is the one way to hand the optimizer an aliasing fact the raw tier otherwise refuses to guess, and a false assertion is UB (checked dynamically). An operand that is not a raw pointer has nothing to assert: safe values already carry stronger, checked aliasing facts (`mut` is exclusive, `read` is frozen). Pass the `*T` values themselves, or drop the `assume` — safe code never needs it. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__unsafe_assume_malformed.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1304_assume_malformed.snap ## E1305 — this door needs a region and a raw pointer, in that order `borrow r from p` is one of exactly two doors from the raw tier back into the safe world: it asserts that `p` points into region `r`'s live allocation and yields a safe value governed by `r`'s rules from then on. The claim only makes sense with a `region` value on the left and a raw pointer (`*T`) on the right — anything else has no allocation to check the claim against. Pass the region the pointer really points into, or use the other door: launder the raw index through a checked `handle`, which re-validates its generation at every access. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__memory__unsafe_door_misuse.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__e1305_door_misuse.snap ## E1401 — undefined behavior detected by the checked-build UB machine The `--checked` execution machine (the miri-lite UB checker) ran this program against the operational memory model and reached a state the spec's closed UB enumeration names: every finding cites its `[mem.ub]` row (P1-P6, L1, L2, T1), the raw-tier operation responsible, and the licensed optimization the D2 pairing attaches to that row — the transformation compiled code is entitled to make, which is exactly why the unchecked behavior is undefined rather than merely wrong. The static tier accepts this program by design: raw pointers carry no statically-checkable aliasing claims, so the unsafe tier's obligations are discharged dynamically, here or by an independent oracle. Fix the operation the finding points at (the second span shows the provenance it violates); the near-miss corpus files show the closest defined shape for each row. Fixtures: crates/wolf_mem/tests/snapshots/ubcheck__e1401_uaf.snap ## E1501 — the package manifest does not parse `wolf.pkg` is declarative data in wolf's literal syntax: one `pkg { }` block of `key: value` entries, where a value is a string, an integer, a bare capability word, a `[ ]` list, or a nested `{ }` map. This file strays from that shape at the reported location. Two deliberate restrictions are worth knowing: manifest strings never interpolate (`{x}` in a manifest string is an error — a manifest is data, and data does not compute, D33), and no key is ever an expression. Fix the syntax at the span; the note names what the parser expected. Fixtures: crates/wolf_pkg/tests/snapshots/manifest_diags__e1501_syntax_error.snap ## E1502 — the package manifest has a schema error The manifest parsed as data, but the data does not fit the `wolf.pkg` schema: an unknown key, a value of the wrong shape, a dependency entry that names no source, or a malformed version. Dependency entries take exactly one source form: `{ path: "…" }` for a local tree, `{ git: "…", tag: "…" }` for a pinned VCS fetch, or `{ pkg: "owner/name", major: N, min: "X.Y.Z" }` for a registry dependency (the hosted registry service arrives later; the entry form is stable now, X7). Versions are dotted numerics (`"1.4.0"`). The message names the offending key and the accepted alternatives. Fixtures: crates/wolf_pkg/tests/snapshots/manifest_diags__e1502_unknown_key.snap, crates/wolf_pkg/tests/snapshots/script_frontmatter__e1502_in_script_frontmatter.snap ## E1503 — the manifest declares a build-time script hook — wolf has none, ever This manifest carries a key (`build`, `script`, `hooks`, or another install-hook spelling) that asks for code to run on the host at build or fetch time. Wolf rejects the key unconditionally: D33 is the locked decision that adding a wolf dependency NEVER means arbitrary code runs on your machine — no build.rs, no post-install hooks, no Turing-complete manifest. This is the supply-chain posture the whole ecosystem leans on, so it is enforced at parse time, before any dependency content is trusted for anything. Express C-library needs through the declarative `c: { … }` recipe schema, compute values in sandboxed `comptime` (no ambient IO), or wrap a system/prebuilt library. The key is refused, not ignored: a manifest that asks for execution does not resolve. Fixtures: crates/wolf_pkg/tests/snapshots/manifest_diags__e1503_build_script_refused.snap ## E1504 — this package uses a capability its manifest does not declare Capability manifests (I13) make a package's ambient-authority footprint a reviewable, diffable declaration: a package that touches `std.net` must say `capabilities: [net]` in its `wolf.pkg`, and likewise `fs` and `env` for those facades. The build found an import of a capability-carrying std module that the owning package's manifest does not declare. Declare the capability (making the footprint visible to every consumer running `wolf audit`) or drop the import. Undeclared capability use is a build error, not a warning — the audit tree is only trustworthy if it cannot silently under-report. Fixtures: crates/wolf_pkg/tests/snapshots/project_diags__e1504_undeclared_capability.snap ## E1505 — dependency resolution failed The dependency graph in `wolf.pkg` cannot be resolved: a `path` dependency points at a directory that does not exist or is not a package, a `git` dependency cannot be fetched or its pin is absent from the content store (run `wolf update` to fetch and record it), a dependency's own manifest fails to parse, or a registry-sourced entry was asked to resolve (the hosted registry arrives later; today's sources are `path` and `git`, X7). Resolution is deterministic — minimal version selection over declared minimums, no ranges, no solver — so this error is always about a source being unreachable or malformed, never about the resolver "choosing badly". Fixtures: crates/wolf_pkg/tests/snapshots/project_diags__e1505_registry_stub.snap ## E1506 — a dependency's content hash does not match wolf.sum `wolf.sum` is the integrity ledger: for every fetched dependency it records a content hash over the package's source tree, and every later build re-derives that hash and compares. A mismatch means the bits on disk are not the bits the ledger witnessed — an edited store entry, a moved tag, or a tampered mirror. The build refuses: mirrors and transports are untrusted by construction, only the hash is. If the change is intentional (you deliberately updated the dependency), run `wolf update` to refresh the ledger; otherwise treat the mismatch as the supply-chain alarm it is. Fixtures: crates/wolf_pkg/tests/snapshots/project_diags__e1506_tampered_store.snap ## E1507 — the script's frontmatter is not a manifest a single file may carry A script carries its manifest inside its leading `//!` block, as a `pkg { }` literal — the same schema and the same parser as `wolf.pkg`, so the two can never drift. A script's manifest is a SUBSET, though: `edition`, `wolf`, `deps`, `features`, and `capabilities`, and nothing else. There are no target-scoped dependency sections and no C build recipes, because a program that needs those has outgrown a single file: `wolf init --from-script ` turns the script into a real package with a real manifest, keeping the dependency entries verbatim. A script's identity is its path, so `name`, `version` and `fingerprint` have nothing to identify and are refused rather than ignored. Fixtures: crates/wolf_pkg/tests/snapshots/script_frontmatter__e1507_script_subset.snap ## E1508 — the script's frontmatter no longer matches its pinned resolution A script is one file, and it is still reproducible: the first run pins its resolved dependency versions in the cache, keyed by the script's path and the bytes of its frontmatter, and every later run replays that pin. `--locked` asserts the pin is still the answer — it is the CI posture, the same promise a checked-in lockfile makes for a project — and this error says the frontmatter changed since the pin was taken. Run without `--locked` (or with `--update`) to re-resolve and re-pin. Nothing was mutated: a resolution in the cache is never edited in place, so the old pin is still exactly what it was. Fixtures: crates/wolf_pkg/tests/snapshots/project_diags__e1508_frontmatter_drift.snap ## E1509 — a dependency is not in the cache and fetching is off Resolution is the only phase that may reach the network; a build never does (D33). This run needed a dependency the content store does not hold, while `--offline` (or a build's own no-fetch posture) forbade fetching it. The message names the package and the command that would fetch it. Nothing is silently skipped, and in particular a package that has never been verified cannot be used unverified: the failure is closed, not degraded. Once a dependency is in the store, every script and project that names it runs fully offline. Fixtures: crates/wolf_pkg/tests/snapshots/project_diags__e1509_offline_missing_dep.snap ## W0301 — file only partially formatted: syntax errors present `wolf fmt` formats through the resilient parse tree, so a file with syntax errors still mostly formats: every well-formed declaration and statement is laid out canonically, while the regions the parser could not understand — plus one statement of margin on each side — pass through byte-for-byte untouched, so half-typed code is never mangled. This warning marks that partial result, and `wolf fmt` exits nonzero so scripts and editors know the file is not fully canonical yet. Fix the syntax errors it reports alongside this warning and run `wolf fmt` again; with a clean parse the whole file formats and the warning disappears. Fixtures: crates/wolf_fmt/tests/snapshots/broken__w0301_partial_format.snap ## W0302 — `#[allow(…)]` names a code that is not registered The `#[allow(…)]` attribute suppresses warnings by their registered diagnostic codes — `#[allow(w1301)]` for one code, `#[allow(w13xx)]` for a family — and this argument matches no code in the registry (spec/01 §9; the catalog in `docs/diagnostics.md` lists every code that exists). An allow of nothing usually means a typo in the digits, or a code from a different toolchain version. Fix the code, or delete the argument; the attribute itself still applies its other arguments. This warning cannot suppress itself for the same misspelled code — name it correctly and the allow works. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__allow_unknown_code.snap, crates/wolf_sema/tests/snapshots/lint_diagnostics__w0302_unknown_code.snap ## W0303 — this `#[allow]` allows nothing `#[allow]` with no arguments suppresses no warnings at all: the attribute's whole meaning is the list of codes it names, item by item (`#[allow(w1301)]`), so an empty one is inert — almost always a half-written suppression or a leftover from deleting the codes out of it. Name the warning codes to allow, or delete the attribute; wolf reports the dead attribute rather than letting it sit there implying a suppression that never happens. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__allow_nothing.snap, crates/wolf_sema/tests/snapshots/lint_diagnostics__w0303_allow_nothing.snap ## W0304 — this declaration shadows a prelude name The prelude's names — `assert`, `print`, `List`, the reflection intrinsics, the built-in type names — resolve in every file with no import, and a declaration with the same name silently wins over the prelude for its whole module (file boundaries create no scopes). The loss is invisible at every use site: a module that declares its own `assert` severs itself from the assertion trap entirely, and calls that read as the intrinsic quietly run the local one. Pick another name; the prelude's inventory is small, fixed, and worth avoiding wholesale. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__shadow_prelude.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0304_shadow_binding.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0304_shadow_prelude.snap ## W0305 — this row tag shares its name with something else in scope Inside a function whose signature declares this tag, an identifier in raise position resolves to the tag first, while the same word everywhere else resolves to the item, import, or binding it shadows — one name, two meanings, decided by position. Programs with this collision have historically returned a module as an `int` with the caller's `else` never firing, which is why the rule of thumb is absolute: a tag may not share a name with anything in scope. Rename the tag (or the item); tags are cheap to rename because they exist only in rows, raises, and arms. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__tag_name_collision.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0305_tag_collision.snap ## W0306 — this statement is a bare prefix-operator expression A statement consisting only of a prefix operator applied to a value — `-total`, `!ready`, `&slot` — computes a value and throws it away, so it does nothing. Nearly always it is a broken continuation: the line above ended an expression, the newline terminated the statement, and what was meant as `a - b` became two statements with the second inert. Join the lines so the operator is read as binary (wolf never continues a statement across a newline that ends one), or delete the statement if the value really is unwanted. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__prefix_statement.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0306_prefix_statement.snap ## W0307 — the comparison after `else` applies to the fallback only `else` binds more loosely than any operator, so `count else 0 == max` parses as `count else (0 == max)` — the comparison happens first, against the fallback alone, and the `else` then defaults a boolean, not a count. When the intent is to default and then compare, wrap the default: `(count else 0) == max`. The warning fires on comparison operators in fallback position because a bare comparison as a fallback is nearly always the wrong grouping; parenthesize either reading to say which one is meant, and the warning stands down. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__else_comparison.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0307_else_comparison.snap ## W0308 — a `mut` argument is hidden inside a string interpolation This interpolation calls a function that mutates its argument, so building the string changes program state — a write buried where every reader expects pure formatting. Interpolations run left to right exactly once, so the code is well-defined; it is the placement that misleads, and such calls have a record of surfacing memory-model edge cases first. Hoist the call onto its own line, bind the result, and interpolate the binding: the mutation becomes visible where mutations are expected. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__mut_in_interp.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0308_mut_in_interp.snap ## W0309 — a raw string contains interpolation-shaped braces Raw literals interpolate nothing: `r"{who}"` is six bytes, braces included, while the same characters in every other string literal are an interpolation of `who`. Braces that spell an in-scope name inside a raw literal almost always mean the `r` prefix was added to (or left on) the wrong string. Drop the prefix to interpolate, or escape nothing and keep the raw literal if the six bytes are what is wanted — the warning exists because the two readings are one keystroke apart and produce different strings with no diagnostic. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__raw_interp_braces.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0309_raw_braces.snap ## W0310 — the `get_` prefix names nothing House convention, applied mechanically: no function wears a `get_` prefix. The prefix carries no information — every function gets something — so the name that matters is the noun after it: `get_len` is `len`, `get_first` is `first`. The one blessed `get` spelling is the bare word itself, the checked-access operation that answers with an absence row instead of a sentinel. Rename the function to the noun it fetches; if it is genuinely checked access, name it `get` and give it the absence row. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__get_prefix.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0310_get_prefix.snap ## W0311 — a predicate-named function must answer `bool` Names spelling `is_` or `has_` are the predicate convention: callers read `is_empty(x)` as a yes-or-no question, and nothing else is allowed to wear the shape. This function has the prefix but does not return `bool`, so every call site reads as a test and is not one. Either return `bool`, or rename the function after what it actually produces — the prefix is the promise, and a signature that does not keep it is worse than no convention at all. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__predicate_shape.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0311_predicate_int.snap ## W0312 — an `as_` conversion must borrow, and this one does not The naming split for conversions is allocation and ownership: `to_x` builds a new value, while `as_x` (and bare nouns) are views that borrow their operand and leave it untouched in the caller's hands. This `as_` function takes an operand `mut` or `take`, so it mutates or consumes what a caller reads as a borrowed view — the name promises one cost and the signature charges another. Rename it `to_x` (or after the operation it really performs), or change the mode to the read default a view deserves. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__as_view_consuming.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0312_as_view_take.snap ## W0313 — this `pub` item has no doc comment A `pub` item is a promise to other modules, and the doc comment is where the promise is written down: the contract sentence, the meaning of each row tag, the trap conditions. This exported item carries no `///` at all, so its callers get a name and a signature and must read the body for everything else. Write the contract line above the declaration; if the item is not worth documenting, it is usually not worth exporting — make it private instead. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__pub_undocumented.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0313_pub_undocumented.snap ## W0314 — this module contains exactly one item A module is a namespace, a visibility boundary, and a directory (D32) — real structure with a real reading cost. This one holds a single item, so the structure is all ceremony: importers write the module's name to reach one thing, and the tree grows a directory per function. Fold the item into the module that uses it, or grow the module into the family of items its name promises. A one-item module that is a deliberate seam can say so with an `#[allow]` and a reason. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__one_item_module__main.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__resolve__cycle__main.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__resolve__pkgvis__main.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__resolve__same_name__main.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__resolve__unused__main.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__rows__propagate__main.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__traits__coherence_orphan__main.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__method_scope__main.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0314_one_item_module.snap ## W0315 — nothing else in this package uses this `pub(pkg)` item `pub(pkg)` widens an item's visibility to the whole package — a claim that some other module in the package needs it. No other loaded module mentions this item's name, so the widened visibility is unearned: the item behaves as private and the declaration says otherwise, which misleads exactly the reader deciding whether a change to it is safe. Make it private; when another module really does take it up, widening back is a one-word change. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__pkg_item_unused__main.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0315_pkg_unused.snap ## W0316 — this module imports its own ancestor A child module reaching up into its ancestor couples the two in both directions at once: the ancestor owns the child structurally, and now the child depends on the ancestor's items too. The shape is legal — no cycle exists yet — but it sits one ordinary edit from the hard-error import cycle, because the ancestor importing any of its descendants closes the loop. Move the shared items down into the child (or into a sibling both can import) so the dependency runs one way, parent to child. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__ancestor_import__main.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0316_ancestor_import.snap ## W0401 — this literal does not fit the type it is cast to The value of this literal is known at compile time, and it lies outside the range of the cast's target type, so the conversion can never preserve it — the program carries a number that the type it is handed to cannot hold. Wolf's arithmetic is checked in every profile, and a conversion that must lose the value is the same hazard spelled as a cast. Use a wider target type, or change the literal; if truncation to the type's range is genuinely intended, say so with the `wrapping` family, which makes the wraparound part of the type. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__narrowing_literal.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0401_narrowing_literal.snap ## W0402 — `0.0 - x` is not negation Subtracting from a zero literal flips the sign of every float except one: `0.0 - (-0.0)` is `+0.0`, so the idiom silently erases the sign of a negative zero — and sign-honoring code (`copysign`, rounding, formatting of `-0.0`) then misbehaves on exactly one input. Wolf has a real unary minus: write `-x`, which negates every value including the zeros. The warning names the one-input difference because it has produced wrong library results that no test with nonzero data can catch. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__float_zero_minus.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0402_float_zero_minus.snap ## W0601 — this fallible result is silently discarded The expression produces a `!T` value — a result whose error row is part of its meaning — and the statement throws it away, error and all. A failure here vanishes without a trace: no propagation, no handling, no trap, just a dropped row, which is the one way wolf's error channel can be ignored by accident. Propagate it with `?`, handle it with `else`, or match on it; if the failure genuinely does not matter here, bind it away explicitly so the discard is visible to the reader. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__discarded_result.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0601_discarded_result.snap ## W0602 — a `pub` signature spells its error row anonymously This exported function writes its error row out inline, so every caller now depends on this exact set of tags with nothing naming the set — the row is public API that cannot be referred to, documented once, or evolved in one place. The row's meaning is stable (written rows never widen silently); what is hazardous is its evolution, since every later tag is a source-visible change at every call boundary. State the row deliberately and keep it small — one tag per failure a caller can act on — and reuse the same spelling at every boundary that shares it. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__rows__propagate__main.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0602_pub_row.snap ## W0603 — this row tag's case contradicts its payload A row tag's case is the reader's signal about whether there is anything to destructure: payload-free marks are lowercase bare words (`none`, `eof`, `parse`), payload-carrying tags are CapCase and name their payload type (`Parse(ParseErr)`). This tag breaks the pact — a CapCase mark implies data that is not there, a lowercase tag hides data that is, and `none` in particular never carries a payload, because "there is nothing here" and "this went wrong, here is how" are different answers on purpose. Rename the tag to match its payload, or move the payload to a tag whose case admits it. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__tag_case_payload.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__rows__negative__dup_tags.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__typecheck__match_exhaustive.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0603_none_payload.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0603_tag_case_payload.snap ## W0604 — bare `get` is the checked-access spelling, and this one cannot miss The convention reserves the bare name `get` for checked access: the operation that can find nothing and says so with an absence row (`-> T ! {none}`), consumed by `else` and `?`. This function is named `get` but declares no error row, so it promises a lookup and delivers a total function — callers reach for the `else` that checked access trains them to write, and there is nothing to handle. Give it the absence row if it can miss; name it after what it computes if it cannot. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__get_without_row.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0604_get_total_fn.snap ## W0801 — a capitalized name in this pattern binds instead of matching This scrutinee has no cases for the name to test, so the bare identifier binds a fresh name — the arm matches every value, and any arms below it are dead. A capitalized name in pattern position reads as a variant or tag test, which is exactly why this shape has produced first-arm-always dispatch in correct-looking code. If a constant comparison was meant, use a guard (`n if n == Zed`); if a binding was meant, give it a lowercase name so it reads as one. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__binder_capitalized.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w0801_binder_binds.snap ## W1001 — this region never allocates Region inference proves that no allocation is ever attributed to this region: nothing is built in it, nothing is moved into it, and its create/free pair is frame-local. The region is pure ceremony — it costs a reader the question "what lives here?" whose answer is "nothing", and it usually marks either leftover scaffolding or an allocation that silently landed in the ambient region instead of the one written for it. Delete the region, or move the allocation it was written for inside it. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__region_never_allocates.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__w1001_region_never_allocates.snap ## W1002 — this `mut` parameter is never written The parameter is declared `mut`, and the body never assigns to it, never passes it onward as `mut` or `take`, and never mutates through it — the mode buys writeback nothing uses. The cost lands on callers: every call site must spell `f(mut x)` and surrender exclusive access for a write that never happens, and every reader budgets for a mutation that is not there. Drop the `mut` from the parameter and from the call sites that pass it; the read default is the honest mode. (X1: the absence of a keyword is the mode.) Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__faults__exclusivity_nested_path.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__mut_param_unwritten.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w1002_mut_unwritten.snap ## W1003 — this `take` parameter is returned unchanged `take` is for true consumption — the caller gives the value up and it is gone. This function's body never touches the taken parameter and hands it straight back as its result, so the caller loses the value only to be handed it again through the return: a round trip that consumes nothing and costs every call site its binding. If the caller could reasonably keep using the value, the signature is wrong — take the read default (copying what it returns), or make the consumption real by transforming the value before it leaves. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__take_returned.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w1003_take_returned.snap ## W1101 — this write stays inside the task The closure given to `spawn` assigns to a name captured from the enclosing function. Task captures copy (or move) at spawn time, so the write lands on the task's own copy and the enclosing binding never sees it — the program runs, exits cleanly, and computes with a value that was never updated. Send the result over a channel, or return it through the scope's join, so the data flow between tasks is explicit; cross-task shared mutation is what `sync` types are for. Fixtures: crates/wolf_diag/tests/snapshots/render_snapshots__teach_note_grouped.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__conc__capture_write_assign.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__conc__store_buffer.snap, crates/wolf_sema/tests/snapshots/conc_diagnostics__e1101_task_capture_write.snap, crates/wolf_sema/tests/snapshots/conc_diagnostics__e1101_two_spawns_note_once.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w1101_task_capture_write.snap ## W1102 — the closure captured this value before it changed A closure captures by value at the moment it is created, and this binding is assigned after that moment — every later call of the closure still sees the old value. The program is legal and the copy semantics are deliberate; what bites is the reading, since the code looks like the closure tracks the variable. Create the closure after the last assignment, pass the value as a parameter at each call, or restructure so the captured binding never changes underneath it. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__conc__capture_write_assign.snap, crates/wolf_lex/tests/snapshots/corpus_snapshots__conc__store_buffer.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w1102_stale_capture.snap ## W1301 — this `unsafe` block does not state its invariant Every `unsafe` block discharges a proof obligation the checker cannot: some invariant, maintained by this module, makes the raw-tier operations inside defined. The reader auditing the module needs that invariant written down, next to the block that relies on it — the convention is a `# Safety:` comment immediately above the block (or on its first line) stating what must hold and why it does. This is a style lint, not a gate: the block still checks and compiles. Add the comment; future auditors — including `wolf audit-surface` — read the rings by exactly these markers. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__safety_comment_missing.snap, crates/wolf_mem/tests/snapshots/mem_diagnostics__w1301_missing_safety.snap ## W1302 — an `assume noalias` operand was reassigned `assume noalias p, q` asserts, at the point it is written, that its operands never alias — and the check is spent exactly there. Reassigning an operand afterwards leaves the assertion talking about a pointer the name no longer holds: `p = q` after the assume makes the two names alias while the license to assume otherwise still stands, which is undefined behavior waiting for an optimizer. State the assumption after the last assignment of its operands, or bind the asserted pointers to names that never change. Fixtures: crates/wolf_lex/tests/snapshots/corpus_snapshots__lints__assume_reassigned.snap, crates/wolf_sema/tests/snapshots/wave_diagnostics__w1302_assume_reassigned.snap ## W1501 — this doc comment links to a name that does not resolve A bracketed dotted path in a doc comment — `[List.push]`, `[connect]` — is an intra-doc link, and it resolves through the compiler's own name resolution rather than through string matching. That is the whole point: when the item it names is renamed or removed, the link breaks HERE, loudly, instead of silently becoming a dead reference on a published page. Write the path the code writes, or, if the brackets were meant as ordinary prose, drop them. Cross-package `std.` paths are not checked against this package's names and never warn. Documentation carries the same covenant as tests: it is verified, or it is not trusted. Fixtures: crates/wolf_doc/tests/snapshots/generator__w1501_broken_intra_doc_link.snap