Skip to content

Commit 8dc16dd

Browse files
committed
core/convert: Correct conversion of array types
The existing conversion used the old multiplication of lists when converting Go Array types to CUE. E.g. [3]string{} -> [string] * 3. This was deprecated years ago, and removed in issue #2237 and https://review.gerrithub.io/c/cue-lang/cue/+/1200221 Instead, we now convert [3]string{} -> list.Repeat([string], 3) Signed-off-by: Matthew Sackman <[email protected]> Change-Id: I49aa552a5d7cb04ba5279b10d54d6b4804747f0e Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1207907 Reviewed-by: Daniel Martí <[email protected]> TryBot-Result: CUEcueckoo <[email protected]>
1 parent e9ad52f commit 8dc16dd

File tree

2 files changed

+61
-37
lines changed

2 files changed

+61
-37
lines changed

internal/core/convert/go.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -770,9 +770,13 @@ func (c *goConverter) goTypeToValueRec(allowNullDefault bool, t reflect.Type) (e
770770
}
771771

772772
if t.Kind() == reflect.Array {
773-
e = ast.NewBinExpr(token.MUL,
774-
ast.NewLit(token.INT, strconv.Itoa(t.Len())),
775-
ast.NewList(elem))
773+
e = ast.NewCall(
774+
ast.NewSel(&ast.Ident{
775+
Name: "list",
776+
Node: ast.NewImport(nil, "list")},
777+
"Repeat"),
778+
ast.NewList(elem),
779+
ast.NewLit(token.INT, strconv.Itoa(t.Len())))
776780
} else {
777781
e = ast.NewList(&ast.Ellipsis{Type: elem})
778782
}

internal/core/convert/go_test.go

+54-34
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import (
3131
"cuelang.org/go/internal/core/convert"
3232
"cuelang.org/go/internal/core/debug"
3333
"cuelang.org/go/internal/core/runtime"
34+
35+
_ "cuelang.org/go/pkg"
3436
)
3537

3638
func mkBigInt(a int64) (v apd.Decimal) { v.SetInt64(a); return }
@@ -265,26 +267,27 @@ func TestX(t *testing.T) {
265267

266268
func TestConvertType(t *testing.T) {
267269
testCases := []struct {
268-
goTyp interface{}
269-
want string
270+
goTyp interface{}
271+
want string
272+
expectError bool
270273
}{{
271-
struct {
274+
goTyp: struct {
272275
A int `cue:">=0&<100"`
273276
B *big.Int `cue:">=0"`
274277
C *big.Int
275278
D big.Int
276279
F *big.Float
277280
}{},
278281
// TODO: indicate that B is explicitly an int only.
279-
`{
282+
want: `{
280283
A: (((int & >=-9223372036854775808) & <=9223372036854775807) & (>=0 & <100))
281284
B: (int & >=0)
282285
C?: int
283286
D: int
284287
F?: number
285288
}`,
286289
}, {
287-
&struct {
290+
goTyp: &struct {
288291
A int16 `cue:">=0&<100"`
289292
B error `json:"b,"`
290293
C string
@@ -294,7 +297,7 @@ func TestConvertType(t *testing.T) {
294297
T time.Time
295298
G func()
296299
}{},
297-
`(*null|{
300+
want: `(*null|{
298301
A: (((int & >=-32768) & <=32767) & (>=0 & <100))
299302
b: null
300303
C: string
@@ -304,83 +307,89 @@ func TestConvertType(t *testing.T) {
304307
T: _
305308
})`,
306309
}, {
307-
struct {
310+
goTyp: struct {
308311
A int `cue:"<"` // invalid
309312
}{},
310-
"_|_(invalid tag \"<\" for field \"A\": expected operand, found 'EOF' (and 1 more errors))",
313+
want: "_|_(invalid tag \"<\" for field \"A\": expected operand, found 'EOF' (and 1 more errors))",
314+
expectError: true,
311315
}, {
312-
struct {
316+
goTyp: struct {
313317
A int `json:"-"` // skip
314318
D *apd.Decimal
315319
P ***apd.Decimal
316320
I interface{ Foo() }
317321
T string `cue:""` // allowed
318322
h int
319323
}{},
320-
`{
324+
want: `{
321325
D?: number
322326
P?: (*null|number)
323327
I?: _
324328
T: (string & _)
325329
}`,
326330
}, {
327-
struct {
331+
goTyp: struct {
328332
A int8 `cue:"C-B"`
329333
B int8 `cue:"C-A,opt"`
330334
C int8 `cue:"A+B"`
331335
}{},
332336
// TODO: should B be marked as optional?
333-
`{
337+
want: `{
334338
A: (((int & >=-128) & <=127) & (〈0;C〉 - 〈0;B〉))
335339
B?: (((int & >=-128) & <=127) & (〈0;C〉 - 〈0;A〉))
336340
C: (((int & >=-128) & <=127) & (〈0;A〉 + 〈0;B〉))
337341
}`,
338342
}, {
339-
[]string{},
340-
`(*null|[
343+
goTyp: []string{},
344+
want: `(*null|[
341345
...string,
342346
])`,
343347
}, {
344-
[4]string{},
345-
`(4 * [
348+
goTyp: [4]string{},
349+
want: `〈import;list〉.Repeat([
346350
string,
347-
])`,
351+
], 4)`,
348352
}, {
349-
[]func(){},
350-
"_|_(unsupported Go type (func()))",
353+
goTyp: []func(){},
354+
want: "_|_(unsupported Go type (func()))",
355+
expectError: true,
351356
}, {
352-
map[string]struct{ A map[string]uint }{},
353-
`(*null|{
357+
goTyp: map[string]struct{ A map[string]uint }{},
358+
want: `(*null|{
354359
[string]: {
355360
A?: (*null|{
356361
[string]: ((int & >=0) & <=18446744073709551615)
357362
})
358363
}
359364
})`,
360365
}, {
361-
map[float32]int{},
362-
`_|_(unsupported Go type for map key (float32))`,
366+
goTyp: map[float32]int{},
367+
want: `_|_(unsupported Go type for map key (float32))`,
368+
expectError: true,
363369
}, {
364-
map[int]map[float32]int{},
365-
`_|_(unsupported Go type for map key (float32))`,
370+
goTyp: map[int]map[float32]int{},
371+
want: `_|_(unsupported Go type for map key (float32))`,
372+
expectError: true,
366373
}, {
367-
map[int]func(){},
368-
`_|_(unsupported Go type (func()))`,
374+
goTyp: map[int]func(){},
375+
want: `_|_(unsupported Go type (func()))`,
376+
expectError: true,
369377
}, {
370-
time.Now, // a function
371-
"_|_(unsupported Go type (func() time.Time))",
378+
goTyp: time.Now, // a function
379+
want: "_|_(unsupported Go type (func() time.Time))",
380+
expectError: true,
372381
}, {
373-
struct {
382+
goTyp: struct {
374383
Foobar string `cue:"\"foo,bar\",opt"`
375384
}{},
376-
`{
385+
want: `{
377386
Foobar?: (string & "foo,bar")
378387
}`,
379388
}, {
380-
struct {
389+
goTyp: struct {
381390
Foobar string `cue:"\"foo,opt,bar\""`
382391
}{},
383-
`{
392+
want: `{
384393
Foobar: (string & "foo,opt,bar")
385394
}`,
386395
}}
@@ -390,11 +399,22 @@ func TestConvertType(t *testing.T) {
390399
for _, tc := range testCases {
391400
t.Run("", func(t *testing.T) {
392401
ctx := adt.NewContext(r, &adt.Vertex{})
393-
v, _ := convert.GoTypeToExpr(ctx, tc.goTyp)
402+
v, err := convert.GoTypeToExpr(ctx, tc.goTyp)
394403
got := debug.NodeString(ctx, v, nil)
395404
if got != tc.want {
396405
t.Errorf("\n got %q;\nwant %q", got, tc.want)
397406
}
407+
if tc.expectError && err == nil {
408+
t.Errorf("\n expected an error but didn't get one")
409+
} else if !tc.expectError && err != nil {
410+
t.Errorf("\n got unexpected error: %v", err)
411+
}
412+
if err == nil && !tc.expectError {
413+
val, _ := ctx.Evaluate(&adt.Environment{}, v)
414+
if bot, ok := val.(*adt.Bottom); ok {
415+
t.Errorf("\n unexpected error when evaluating result of conversion: %v", bot)
416+
}
417+
}
398418
})
399419
}
400420
}

0 commit comments

Comments
 (0)