mirror of
https://github.com/google/go-jsonnet.git
synced 2025-08-07 14:57:24 +02:00
fix: Fix error messages when a comprehension iterates over a non-array.
Problems: - When iterating over an empty string in a list comprehension, the result is an empty string. This is a bug, it should be an error. - When iterating over a non-empty string in a list comprehension, the expected and unexpected types in the error message are swapped. - Error messages mention "std.flatMap" when object/list comprehensions would iterate over a value that is neither array nor string. ``` $ jsonnet --version Jsonnet commandline interpreter (Go implementation) v0.21.0-rc2 $ jsonnet -e '[a for a in ""]' "" $ jsonnet -e '[a for a in "b"]' RUNTIME ERROR: Unexpected type array, expected string <cmdline>:1:1-17 During evaluation $ jsonnet -e '{[a]: 1 for a in 2}' RUNTIME ERROR: std.flatMap second param must be array / string, got number <cmdline>:1:1-20 <cmdline>:1:1-20 During evaluation $ jsonnet -e '[a for a in 1]' RUNTIME ERROR: std.flatMap second param must be array / string, got number <cmdline>:1:1-15 During evaluation ``` FWIW, the C++ implementation does not have any of these problems. It gives: ``` RUNTIME ERROR: In comprehension, can only iterate over array. ``` In the Go implementation comprehensions are desugared to a call to std.flatMap which does accept a string in the "arr" parameter. The fix: Desugar comprehensions to a call to a new hidden builtin which only accepts arrays.
This commit is contained in:
parent
1add1e1b24
commit
1c79f577ba
14
builtins.go
14
builtins.go
@ -345,6 +345,19 @@ func builtinFlatMap(i *interpreter, funcv, arrv value) (value, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// builtinFlatMapArray is like builtinFlatMap, but only accepts array as the
|
||||
// arrv value. Desugared comprehensions contain a call to this function, rather
|
||||
// than builtinFlatMap, so that a better error message is printed when the
|
||||
// comprehension would iterate over a non-array.
|
||||
func builtinFlatMapArray(i *interpreter, funcv, arrv value) (value, error) {
|
||||
switch arrv := arrv.(type) {
|
||||
case *valueArray:
|
||||
return builtinFlatMap(i, funcv, arrv)
|
||||
default:
|
||||
return nil, i.typeErrorSpecific(arrv, &valueArray{})
|
||||
}
|
||||
}
|
||||
|
||||
func joinArrays(i *interpreter, sep *valueArray, arr *valueArray) (value, error) {
|
||||
result := make([]*cachedThunk, 0, arr.length())
|
||||
first := true
|
||||
@ -2880,4 +2893,5 @@ var funcBuiltins = buildBuiltinMap([]builtin{
|
||||
|
||||
// internal
|
||||
&unaryBuiltin{name: "$objectFlatMerge", function: builtinUglyObjectFlatMerge, params: ast.Identifiers{"x"}},
|
||||
&binaryBuiltin{name: "$flatMapArray", function: builtinFlatMapArray, params: ast.Identifiers{"func", "arr"}},
|
||||
})
|
||||
|
@ -184,7 +184,7 @@ func desugarForSpec(inside ast.Node, loc ast.LocationRange, forSpec *ast.ForSpec
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
current := buildStdCall("flatMap", loc, function, forSpec.Expr)
|
||||
current := buildStdCall("$flatMapArray", loc, function, forSpec.Expr)
|
||||
if forSpec.Outer == nil {
|
||||
return current, nil
|
||||
}
|
||||
|
@ -199,6 +199,7 @@ func prepareStdlib(g *typeGraph) {
|
||||
"mod": g.newSimpleFuncType(stringOrNumber, "a", "b"),
|
||||
"native": g.newSimpleFuncType(anyFunctionType, "x"),
|
||||
"$objectFlatMerge": g.newSimpleFuncType(anyObjectType, "x"),
|
||||
"$flatMapArray": g.newSimpleFuncType(anyArrayType, "func", "arr"),
|
||||
|
||||
// Boolean
|
||||
|
||||
|
10
testdata/array_comp_try_iterate_over_empty_string.golden
vendored
Normal file
10
testdata/array_comp_try_iterate_over_empty_string.golden
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected array
|
||||
-------------------------------------------------
|
||||
testdata/array_comp_try_iterate_over_empty_string:1:1-16
|
||||
|
||||
[a for a in '']
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
||||
|
1
testdata/array_comp_try_iterate_over_empty_string.jsonnet
vendored
Normal file
1
testdata/array_comp_try_iterate_over_empty_string.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
||||
[a for a in '']
|
0
testdata/array_comp_try_iterate_over_empty_string.linter.golden
vendored
Normal file
0
testdata/array_comp_try_iterate_over_empty_string.linter.golden
vendored
Normal file
@ -1,4 +1,4 @@
|
||||
RUNTIME ERROR: std.flatMap second param must be array / string, got object
|
||||
RUNTIME ERROR: Unexpected type object, expected array
|
||||
-------------------------------------------------
|
||||
testdata/array_comp_try_iterate_over_obj:1:1-16
|
||||
|
||||
|
10
testdata/array_comp_try_iterate_over_string.golden
vendored
Normal file
10
testdata/array_comp_try_iterate_over_string.golden
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected array
|
||||
-------------------------------------------------
|
||||
testdata/array_comp_try_iterate_over_string:1:1-17
|
||||
|
||||
[a for a in 'b']
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
||||
|
1
testdata/array_comp_try_iterate_over_string.jsonnet
vendored
Normal file
1
testdata/array_comp_try_iterate_over_string.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
||||
[a for a in 'b']
|
0
testdata/array_comp_try_iterate_over_string.linter.golden
vendored
Normal file
0
testdata/array_comp_try_iterate_over_string.linter.golden
vendored
Normal file
15
testdata/object_comp_try_iterate_over_obj.golden
vendored
Normal file
15
testdata/object_comp_try_iterate_over_obj.golden
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
RUNTIME ERROR: Unexpected type object, expected array
|
||||
-------------------------------------------------
|
||||
testdata/object_comp_try_iterate_over_obj:1:1-23
|
||||
|
||||
{ [a]: 0 for a in {} }
|
||||
|
||||
-------------------------------------------------
|
||||
testdata/object_comp_try_iterate_over_obj:1:1-23
|
||||
|
||||
{ [a]: 0 for a in {} }
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
||||
|
1
testdata/object_comp_try_iterate_over_obj.jsonnet
vendored
Normal file
1
testdata/object_comp_try_iterate_over_obj.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ [a]: 0 for a in {} }
|
0
testdata/object_comp_try_iterate_over_obj.linter.golden
vendored
Normal file
0
testdata/object_comp_try_iterate_over_obj.linter.golden
vendored
Normal file
15
testdata/object_comp_try_iterate_over_string.golden
vendored
Normal file
15
testdata/object_comp_try_iterate_over_string.golden
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
RUNTIME ERROR: Unexpected type string, expected array
|
||||
-------------------------------------------------
|
||||
testdata/object_comp_try_iterate_over_string:1:1-24
|
||||
|
||||
{ [a]: 0 for a in 'b' }
|
||||
|
||||
-------------------------------------------------
|
||||
testdata/object_comp_try_iterate_over_string:1:1-24
|
||||
|
||||
{ [a]: 0 for a in 'b' }
|
||||
|
||||
-------------------------------------------------
|
||||
During evaluation
|
||||
|
||||
|
1
testdata/object_comp_try_iterate_over_string.jsonnet
vendored
Normal file
1
testdata/object_comp_try_iterate_over_string.jsonnet
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ [a]: 0 for a in 'b' }
|
0
testdata/object_comp_try_iterate_over_string.linter.golden
vendored
Normal file
0
testdata/object_comp_try_iterate_over_string.linter.golden
vendored
Normal file
Loading…
Reference in New Issue
Block a user