fix(vm): respect expr struct tag in "in" operator - #991
Open
akashchamp wants to merge 1 commit into
Open
akashchamp wants to merge 1 commit into
akashchamp wants to merge 1 commit into
Conversation
The `in` operator on a struct looked up the field by its raw Go name via reflect.Type.FieldByName, ignoring any `expr:"..."` rename tag. Plain field access (`foo.bar`) already resolves field names through the tag, so the two paths disagreed: `"bar" in foo` returned false and `"Inner" in foo` returned true for a field declared as `Inner ... `expr:"bar"``, the opposite of what `foo.bar`/`foo.Inner` do. Add structFieldByExprName, matching the checker's compile-time name resolution (a tag's value, or "-" to hide the field, replaces the Go name entirely rather than being an alias for it), and use it in runtime.In's struct case instead of the raw FieldByName lookup. Fixes expr-lang#990 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #990
Problem
The
inoperator on a struct checks membership using the struct's raw Gofield name via
reflect.Type.FieldByName, ignoring anyexpr:"..."renametag. Plain field access (
foo.bar) already resolves names through the tag,so the two code paths for the same struct disagree:
foo.bar/foo.Inner)"bar" in foofalsetruefoo.bar→map[](valid)"Inner" in footruefalsefoo.Inner→ compile errorFix
Added
structFieldByExprNameinvm/runtime/runtime.go, which resolves afield name the same way the checker does at compile time: once a field
carries an
exprtag, only that tag's value (or"-"to hide the field)identifies it, and the original Go name no longer applies.
runtime.In'sstruct case now uses this helper instead of the raw
FieldByNamelookup.This is scoped to the
inoperator only —Fetch/findStructField(usedfor dynamic field access, e.g. through embedded interfaces) are unchanged,
since that's a separate code path not reported in the issue.
Testing
TestIn_StructRespectsFieldTaginvm/runtime/runtime_test.go,a table-driven unit test directly against
In()covering: tag-renamedfield found by tag name, original Go name no longer found,
expr:"-"hidden field still excluded, and an untagged field still found by its Go
name (no regression for the untagged case).
test/issues/990/issue_test.go(TestIssue990), an end-to-endregression test using the public
expr.EvalAPI and the exact structshape from the issue's playground repro, following this repo's existing
test/issues/<N>convention.go test ./..., excluding the pre-existing,unrelated build failure in
test/exampleswhich fails identically onmasterbefore this change — confirmed by stashing the diff andrebuilding): all 57 testable packages pass.
go vet ./vm/... ./test/issues/990/...andgofmt -lare clean on thechanged files.
go test -run TestIssue990 -v ./test/issues/990/...that both expressions from the issue's own repro now evaluate to the
expected boolean, matching
foo.bar/foo.Inner's existing behavior.AI disclosure
This change was prepared with AI assistance (Claude Code). The repository
has no stated AI-contribution policy; noting this for transparency.