v1.108.281 — A declared pattern with no implementation reads as a language without constants
A declared pattern with no implementation reads as a language without constants
Closes #428, reported by @mussonking. The Kotlin and Bash halves shipped in v1.108.267; these four are the rest.
Rust, Go, Java and PHP all declared constant_patterns in LANGUAGE_REGISTRY and had no branch in _extract_constant. The walker dispatched on the node type and fell off the end to return None.
Nothing errored, and that is the defect. A declared-and-unimplemented pattern is indistinguishable from a language that has no constants: search_symbols returns nothing, and the caller concludes the symbol does not exist. He caught it on a generated Rust contract file holding 935 pub const, which index_folder reported in no_symbols_files with zero symbols, and only because he knew the exact count.
What now extracts
const_item / static_item (Rust), const_declaration (Go, PHP), field_declaration (Java).
Three of the four bind N names per declaration, and Go does it two ways at once — const ( ... ) groups one spec per line, and const A, B = 1, 2 binds two names in one spec. A single-symbol return would have reported the first name of a 935-line block and dropped the rest, which reads as success.
No case heuristic on any of them. Python needs name.isupper() because an assignment is a constant only by convention; const is the declaration. Filtering on case would silently drop Go's unexported constants.
What is deliberately excluded
Rust static mut carries a mutable_specifier — the declaration says the binding can change. A Java constant is static final: a bare final field is per-instance and a bare static field is mutable shared state.
A missing constant is a recall bug the reporter could see. An ordinary field arriving as kind="constant" in every Java class in an index is a precision bug nobody goes looking for.
Java needed the walk gate widened, narrowly
The constant walk was gated on parent_symbol is None, which keeps function locals out — and a Java constant is a class member, so field_declaration sat in constant_patterns unreachable by construction. The gate now also accepts a container parent, for languages named in _CLASS_SCOPED_CONSTANT_LANGUAGES (currently {"java"}), never for a function parent.
Relaxing it for every language was declined: Python class bodies, JS class fields and PHP class constants would all start emitting constants they have never emitted, moving symbol counts in every index and every published dead-code grade.
Verification
tests/test_v1_108_281.py (10) covers the reporter's nested pub mod shape, the N-name forms and each exclusion. 9 of the 10 fail against d10490e; the one passing both sides is the control asserting Java function locals are still not constants.
EXEMPT in tests/test_constant_extraction_guard.py is now empty — its ratchet forced its own deletion — and all 17 languages declaring constant_patterns extract one.
Local suite 7848 passed / 10 skipped / 0 failed; 3.13 CI-env reproduce 7842 / 16, the same 7858 total. ruff check src/ clean. All 9 CI jobs green on aa78b8c.