Reject duplicate function parameters#876
Open
rohan-patnaik wants to merge 1 commit into
Open
Conversation
Contributor
|
Great, does the same problem exist in cpp? |
|
CPP is fine |
stephenamar-db
pushed a commit
to databricks/sjsonnet
that referenced
this pull request
Jun 22, 2026
…ontexts (#1011) ## Motivation go-jsonnet issue #873 reports that `(function(x, x, x) x)(null, 3, 2)` silently returns `2` instead of rejecting duplicate parameter names. sjsonnet already rejected duplicates in function expressions, but the error message was misleading in local bindings and object methods (e.g. "Expected \")\"" or "Expected \":\""). ## Modification The `params` parser correctly detects duplicates via `flatMapX` + `Fail`. However, in `bind` (`local f(x,x)=...`) and `field` (`{f(x,x):...}`), the optional group `.?` around `params` swallowed the "no duplicate parameter" error and backtracked, producing misleading errors. Two changes fix this: 1. In `field()`: added `~/` (cut) after `"("` to commit to the params path once `"("` is matched: `"(" ~/ params(...) ~ ")"`. 2. In `params()`: set `ctx.cut = true` programmatically when a duplicate is detected, preventing outer `.?` operators from swallowing the error. Also captures `Pos` for each parameter to position the error at the duplicate parameter name (not at the closing paren). ## Result All duplicate parameter contexts now produce the correct error `"Expected no duplicate parameter: x"` with accurate position info: - `(function(x, x, x) x)` -> ParseError (already worked) - `local f(x, x) = x` -> ParseError (was `"Expected )"`) - `{ f(x, x): x }` -> ParseError (was `"Expected :"`) - `{ local f(x, x) = x }` -> ParseError (was `"Expected )"`) - Nested bindings also fixed as a bonus. Tests pass on Scala 3.3.7, 2.13.18, 2.12.21. ## References - google/go-jsonnet#873 ## Cross-implementation comparison: Duplicate function parameters | Implementation | Detection Phase | All Contexts Covered | Error Message Example | |---|---|---|---| | **sjsonnet (this fix)** | Parse time | ✅ All 4 contexts | `Expected no duplicate parameter: x` | | **cpp-jsonnet** | Static analysis (post-parse) | ✅ All 4 (via desugaring) | `Duplicate function parameter: x` | | **go-jsonnet** (master) | ❌ None | ❌ Bug — silently accepts | N/A — last argument wins silently | | **go-jsonnet** ([PR #876](google/go-jsonnet#876), unmerged) | Parse time | ✅ All 4 | `Duplicate function parameter: a` / `Duplicate method parameter: x` | | **jrsonnet** | Static analysis (post-parse) | ✅ All 4 (via desugaring) | `local is already defined in the current frame: x` | ### Behavior by test case | Test Case | sjsonnet (fix) | cpp-jsonnet | go-jsonnet | jrsonnet | |---|---|---|---|---| | `(function(x, x, x) x)(null, 3, 2)` | ✅ ParseError | ✅ StaticError | ❌ Returns `2` | ✅ StaticError | | `local f(x, x) = x; f(1, 2)` | ✅ ParseError | ✅ StaticError | ❌ Accepted | ✅ StaticError | | `{ f(x, x): x }.f(1, 2)` | ✅ ParseError | ✅ StaticError | ❌ Accepted | ✅ StaticError | | `{ local f(x, x) = x, a: f(1, 2) }` | ✅ ParseError | ✅ StaticError | ❌ Accepted | ✅ StaticError | ### Key differences - **Detection timing**: sjsonnet and go-jsonnet (PR #876) detect at parse time; cpp-jsonnet and jrsonnet detect during a separate static analysis pass after parsing. - **Error message specificity**: go-jsonnet PR #876 distinguishes "function parameter" vs "method parameter"; cpp-jsonnet uses "function parameter" uniformly (methods desugar to functions before the check). - **Position accuracy**: sjsonnet points to the duplicate parameter name; cpp-jsonnet points to the entire function AST node. - **go-jsonnet master** has a known bug ([issue #873](google/go-jsonnet#873)) where duplicate parameters are silently accepted with "last argument wins" semantics.
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.
Rejects duplicate parameter names while parsing function and method parameter lists.
Previously, go-jsonnet accepted inputs like:
That makes argument/default handling ambiguous and differs from other Jsonnet implementations, which reject duplicate parameters.
This change tracks parameter names while parsing and returns a static error when the same name appears twice. It covers normal functions, local function sugar, and object methods.
Fixes #873.
Testing:
go test ./internal/parsergo test ./...