You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Prompt: "Do a big issue about that! A bug issue i mean" — the double message seen while retiring from= on shift in #437.
Note
The following content was generated by AI.
What happened?
A call with a keyword the operator does not declare is refused by the signature line, which is right, and then refused a second time by a message about the keyword's value, which is wrong: the second line depends on what the value happens to look like, not on the mistake, and the rewrite it proposes does not exist.
The objective: shift() expects shift(<expr>, over=<dim>, offset=<n>[, edge='wrap'|<number>][, by=<lookup>])
The objective: 'g' is a dimension, and a dimension is not a value in an expression. Dimensions appear in 'foreach:', in operator arguments (sum(x, over=g)), and in where-comparisons — to use its coordinates as data, declare a parameter over it.
The first line is the whole answer. The second says the author used a dimension as a value, which they did not; they misspelled or invented a keyword. With a list as the value the second line becomes "shift(foo=) takes a number or the name of an integer parameter. Precompute it as a parameter." — advice to precompute a parameter for a keyword that does not exist. With a number or a parameter name as the value there is no second line at all, because those happen to pass the amount check. So the second message is decided by the value's shape, which is the tell: nothing about an undeclared keyword is decided by its value.
Expected: one refusal, the signature line, for every operator and every value.
Why it is a bug by this project's rules.AGENTS.md: an error message names the rewrite — the second line names a rewrite that is not the fix, and for a typo of edge= it points the author at parameters. Nothing is guessed — a keyword the operator did not declare has no kind, and reading it as a value is a default nobody asked for.
Where.call_shape_error in src/math_spec/operators.py reports the unknown keyword correctly. _call in src/math_spec/resolution.py then types every keyword in the call regardless, and Builtin.kind_of answers 'value' for any name it does not know (its return 'value' fallthrough), so the stray keyword's value goes through _amount, which is where both second lines come from. dual is the one operator that returns after a shape error, which is why it does not do this.
Every operator that takes keywords is affected. Reproduced on main at eac1930 (0.0.0-alpha.83), so it predates #437 and the lookup work:
call
second line
shift(p, over=g, offset=1, edge=0, foo=g)
"'g' is a dimension, and a dimension is not a value in an expression …"
shift(p, over=g, offset=1, edge=0, foo=[g, h])
"shift(foo=) takes a number or the name of an integer parameter. Precompute it as a parameter."
shift(p, over=g, offset=1, egde='wrap') (a typo of edge)
"shift(egde=) takes a number or the name of an integer parameter. Precompute it as a parameter."
sum(p, ovr=g) (a typo of over)
"'g' is a dimension, and a dimension is not a value in an expression …"
at(p, by=lk, scale=2 * c)
"at(scale=) takes a number or the name of an integer parameter. Precompute it as a parameter."
shift(p, over=g, offset=1, edge=0, foo=3)
none — a number is a valid amount
sum(p, by=lk, weight=c)
none — a parameter name is a valid amount
sum_back(p, over=g, witin=n) (a typo of within)
none — n is an int parameter
The three rows with no second line are the same bug: the value was silently accepted as an amount, and a keyword that does not exist was typed as if it did.
The fix, as I would make it. Two lines and a test. Builtin.kind_of returns nothing for a keyword the operator does not declare, and _call skips those. Every other error in the same call is still reported, and dual's early return stays as it is. The test asserts, for one operator and a value of each shape above, that the refusal is exactly the signature line — it fails on the tree as it stands. It belongs in tests/test_validation.py beside the other operator refusals. A separate fix(resolution) PR against main, not part of #437.
Which operating systems have you used?
Linux
Version
main at eac1930 (0.0.0-alpha.83). Also present on #437's branch.
Relevant log output
Reproduction, every row of the table
frommath_specimportto_specfrommath_spec.errorsimportLanguageErrorbase= {
'dimensions': {'g': {}, 'h': {}},
'lookups': {'lk': {'over': 'g', 'into': 'h'}},
'parameters': {'c': {'dims': ['g']}, 'n': {'dims': [], 'dtype': 'int'}},
'variables': {'p': {'foreach': ['g']}},
}
cases= {
'shift, a dimension name': 'sum(shift(p, over=g, offset=1, edge=0, foo=g))',
'shift, a list': 'sum(shift(p, over=g, offset=1, edge=0, foo=[g, h]))',
'shift, a number': 'sum(shift(p, over=g, offset=1, edge=0, foo=3))',
'shift, a typo of edge': "sum(shift(p, over=g, offset=1, egde='wrap'))",
'sum, a typo of over': 'sum(sum(p, ovr=g))',
'sum, a parameter name': 'sum(sum(p, by=lk, weight=c))',
'at, an expression': 'sum(at(p, by=lk, scale=2 * c))',
'sum_back, a typo of within': 'sum(sum_back(p, over=g, witin=n))',
}
forlabel, exprincases.items():
try:
to_spec(dict(base, objective={'sense': 'minimize', 'expression': expr}))
exceptLanguageErrorase:
print(f'### {label}\n{e}\n')
### shift, a dimension name
The objective: shift() expects shift(<expr>, over=<dim>, offset=<n>[, edge='wrap'|<number>][, by=<lookup>])
The objective: 'g' is a dimension, and a dimension is not a value in an expression. Dimensions appear in 'foreach:', in operator arguments (sum(x, over=g)), and in where-comparisons — to use its coordinates as data, declare a parameter over it.
### shift, a list
The objective: shift() expects shift(<expr>, over=<dim>, offset=<n>[, edge='wrap'|<number>][, by=<lookup>])
The objective: shift(foo=) takes a number or the name of an integer parameter. Precompute it as a parameter.
### shift, a number
The objective: shift() expects shift(<expr>, over=<dim>, offset=<n>[, edge='wrap'|<number>][, by=<lookup>])
### shift, a typo of edge
The objective: shift() expects shift(<expr>, over=<dim>, offset=<n>[, edge='wrap'|<number>][, by=<lookup>])
The objective: shift(egde=) takes a number or the name of an integer parameter. Precompute it as a parameter.
### sum, a typo of over
The objective: sum() expects sum(<expr>), sum(<expr>, over=<dim>) or sum(<expr>, by=<lookup>)
The objective: 'g' is a dimension, and a dimension is not a value in an expression. Dimensions appear in 'foreach:', in operator arguments (sum(x, over=g)), and in where-comparisons — to use its coordinates as data, declare a parameter over it.
### sum, a parameter name
The objective: sum() expects sum(<expr>), sum(<expr>, over=<dim>) or sum(<expr>, by=<lookup>)
### at, an expression
The objective: at() expects at(<expr>, by=<lookup>)
The objective: at(scale=) takes a number or the name of an integer parameter. Precompute it as a parameter.
### sum_back, a typo of within
The objective: sum_back() expects sum_back(<expr>, over=<dim>, within=<n|parameter>[, edge='wrap'][, by=<lookup>])
Note
The following content was generated by AI.
What happened?
A call with a keyword the operator does not declare is refused by the signature line, which is right, and then refused a second time by a message about the keyword's value, which is wrong: the second line depends on what the value happens to look like, not on the mistake, and the rewrite it proposes does not exist.
The first line is the whole answer. The second says the author used a dimension as a value, which they did not; they misspelled or invented a keyword. With a list as the value the second line becomes "shift(foo=) takes a number or the name of an integer parameter. Precompute it as a parameter." — advice to precompute a parameter for a keyword that does not exist. With a number or a parameter name as the value there is no second line at all, because those happen to pass the amount check. So the second message is decided by the value's shape, which is the tell: nothing about an undeclared keyword is decided by its value.
Expected: one refusal, the signature line, for every operator and every value.
Why it is a bug by this project's rules. AGENTS.md: an error message names the rewrite — the second line names a rewrite that is not the fix, and for a typo of
edge=it points the author at parameters. Nothing is guessed — a keyword the operator did not declare has no kind, and reading it as a value is a default nobody asked for.Where.
call_shape_errorinsrc/math_spec/operators.pyreports the unknown keyword correctly._callinsrc/math_spec/resolution.pythen types every keyword in the call regardless, andBuiltin.kind_ofanswers'value'for any name it does not know (itsreturn 'value'fallthrough), so the stray keyword's value goes through_amount, which is where both second lines come from.dualis the one operator that returns after a shape error, which is why it does not do this.Every operator that takes keywords is affected. Reproduced on
mainat eac1930 (0.0.0-alpha.83), so it predates #437 and the lookup work:shift(p, over=g, offset=1, edge=0, foo=g)shift(p, over=g, offset=1, edge=0, foo=[g, h])shift(p, over=g, offset=1, egde='wrap')(a typo ofedge)sum(p, ovr=g)(a typo ofover)at(p, by=lk, scale=2 * c)shift(p, over=g, offset=1, edge=0, foo=3)sum(p, by=lk, weight=c)sum_back(p, over=g, witin=n)(a typo ofwithin)nis anintparameterThe three rows with no second line are the same bug: the value was silently accepted as an amount, and a keyword that does not exist was typed as if it did.
The fix, as I would make it. Two lines and a test.
Builtin.kind_ofreturns nothing for a keyword the operator does not declare, and_callskips those. Every other error in the same call is still reported, anddual's early return stays as it is. The test asserts, for one operator and a value of each shape above, that the refusal is exactly the signature line — it fails on the tree as it stands. It belongs intests/test_validation.pybeside the other operator refusals. A separatefix(resolution)PR againstmain, not part of #437.Which operating systems have you used?
Version
mainat eac1930 (0.0.0-alpha.83). Also present on #437's branch.Relevant log output
Reproduction, every row of the table