mirror of
https://github.com/google/go-jsonnet.git
synced 2025-08-06 22:37:23 +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) {
|
func joinArrays(i *interpreter, sep *valueArray, arr *valueArray) (value, error) {
|
||||||
result := make([]*cachedThunk, 0, arr.length())
|
result := make([]*cachedThunk, 0, arr.length())
|
||||||
first := true
|
first := true
|
||||||
@ -2880,4 +2893,5 @@ var funcBuiltins = buildBuiltinMap([]builtin{
|
|||||||
|
|
||||||
// internal
|
// internal
|
||||||
&unaryBuiltin{name: "$objectFlatMerge", function: builtinUglyObjectFlatMerge, params: ast.Identifiers{"x"}},
|
&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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
current := buildStdCall("flatMap", loc, function, forSpec.Expr)
|
current := buildStdCall("$flatMapArray", loc, function, forSpec.Expr)
|
||||||
if forSpec.Outer == nil {
|
if forSpec.Outer == nil {
|
||||||
return current, nil
|
return current, nil
|
||||||
}
|
}
|
||||||
|
@ -199,6 +199,7 @@ func prepareStdlib(g *typeGraph) {
|
|||||||
"mod": g.newSimpleFuncType(stringOrNumber, "a", "b"),
|
"mod": g.newSimpleFuncType(stringOrNumber, "a", "b"),
|
||||||
"native": g.newSimpleFuncType(anyFunctionType, "x"),
|
"native": g.newSimpleFuncType(anyFunctionType, "x"),
|
||||||
"$objectFlatMerge": g.newSimpleFuncType(anyObjectType, "x"),
|
"$objectFlatMerge": g.newSimpleFuncType(anyObjectType, "x"),
|
||||||
|
"$flatMapArray": g.newSimpleFuncType(anyArrayType, "func", "arr"),
|
||||||
|
|
||||||
// Boolean
|
// 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
|
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