ast: let concrete index values supersede leftover "any" entries
A `ref = var` expression is recorded as "this ref can be anything", both to keep
the rule in the running for that ref and so that resolveVarToRef can map the var
back to the ref for later expressions in the body. insert() replaces such an
entry once a concrete value for the same ref shows up -- but only the first one,
and a chain of assignments leaves one behind per local:
x := input.role
y := x
y == "admin"
records `input.role = __local0__` and `input.role = __local1__`, then replaces
the first with `input.role = "admin"`. The second survives, Build finds a var
among the values for input.role and inserts the rule under anyValue, and every
rule in the set matches whatever input.role holds -- where the same body without
the intermediate assignment discriminates. Whether the leftovers happen to be
covered is accidental: `y in {"a", "b"}` contributes two concrete values and so
replaces both entries, while a single comparison replaces one.
Drop the var entries at trie-build time when a concrete value for the same ref
exists. Both come from the same body, so both have to hold, and the concrete
value is the stronger of the two constraints. Doing it here rather than in
insert() leaves the var -> ref associations resolveVarToRef needs in place for
the rest of the body. Var-valued entries never carry a mapper, so none is lost
in the process, and the multiple-scalar case is untouched: filtering only ever
removes vars.
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com> S
Stephan Renatus committed
1dc4400624f846d846661fda3c4929c16505ddea
Parent: 11c5d41
Committed by Stephan Renatus <s_renatus@apple.com>
on 8/28/2026, 7:28:21 AM