test: enforce locals-query coverage

Assert that every bundled local-sensitive highlight query has a non-empty,
compilable locals query. Clarify the upstream-parity worst-case complexity of
lexical reference resolution in the framing document.
This commit is contained in:
Levi Neuwirth 2026-07-22 13:05:33 -04:00
parent 08ea6a3e12
commit e5db4a98f8
2 changed files with 29 additions and 1 deletions

View File

@ -221,7 +221,9 @@ cross-layer merge precedence remain unchanged after captures are selected.
### Q#LQ6 - Performance boundary ### Q#LQ6 - Performance boundary
Local analysis is linear in the locals-query captures for one settled layer. The locals-query capture walk is linear for one settled layer. Like upstream,
resolving references scans visible definitions newest-first, so the worst case
is $O(\text{captures} + \text{references} \times \text{definitions})$.
It runs only for a language whose highlight query actually contains a `local` It runs only for a language whose highlight query actually contains a `local`
predicate, and only once when a fresh parse bundle settles. predicate, and only once when a fresh parse bundle settles.

View File

@ -2666,6 +2666,32 @@ mod tests {
} }
} }
#[test]
fn local_sensitive_builtin_highlights_have_compilable_locals_queries() {
let registry = SyntaxRegistry::new();
for entry in BUILTIN_LANGUAGES {
let Some(highlights) = registry.highlights_query(entry.name) else {
continue;
};
if !query_uses_local_predicates(&highlights) {
continue;
}
assert!(
entry
.locals_query
.iter()
.any(|fragment| !fragment.trim().is_empty()),
"`{}` highlights use a local predicate but ship no locals query",
entry.name
);
assert!(
registry.locals_query(entry.name).is_some(),
"`{}` highlights use a local predicate but its locals query does not compile",
entry.name
);
}
}
#[test] #[test]
fn javascript_local_predicates_distinguish_lexical_scope() { fn javascript_local_predicates_distinguish_lexical_scope() {
let registry = SyntaxRegistry::new(); let registry = SyntaxRegistry::new();