@@ -188,6 +188,14 @@ func isZero(v reflect.Value) bool {
188
188
}
189
189
190
190
func convert (ctx * context , src source , x interface {}) evaluated {
191
+ v := convertRec (ctx , src , x )
192
+ if v == nil {
193
+ return ctx .mkErr (baseValue {}, "unsupported Go type (%v)" , v )
194
+ }
195
+ return v
196
+ }
197
+
198
+ func convertRec (ctx * context , src source , x interface {}) evaluated {
191
199
switch v := x .(type ) {
192
200
case nil :
193
201
// Interpret a nil pointer as an undefined value that is only
@@ -279,27 +287,50 @@ func convert(ctx *context, src source, x interface{}) evaluated {
279
287
return toUint (ctx , src , uint64 (v ))
280
288
case uint64 :
281
289
return toUint (ctx , src , uint64 (v ))
290
+ case uintptr :
291
+ return toUint (ctx , src , uint64 (v ))
282
292
case float64 :
283
293
r := newNum (src , floatKind )
284
294
r .v .SetString (fmt .Sprintf ("%g" , v ))
285
295
return r
296
+ case float32 :
297
+ r := newNum (src , floatKind )
298
+ r .v .SetString (fmt .Sprintf ("%g" , v ))
299
+ return r
286
300
287
301
case reflect.Value :
288
302
if v .CanInterface () {
289
- return convert (ctx , src , v .Interface ())
303
+ return convertRec (ctx , src , v .Interface ())
290
304
}
291
305
292
306
default :
293
307
value := reflect .ValueOf (v )
294
308
switch value .Kind () {
309
+ case reflect .Bool :
310
+ return & boolLit {src .base (), value .Bool ()}
311
+
312
+ case reflect .String :
313
+ return & stringLit {src .base (), value .String (), nil }
314
+
315
+ case reflect .Int , reflect .Int8 , reflect .Int16 ,
316
+ reflect .Int32 , reflect .Int64 :
317
+ return toInt (ctx , src , value .Int ())
318
+
319
+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 ,
320
+ reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
321
+ return toUint (ctx , src , value .Uint ())
322
+
323
+ case reflect .Float32 , reflect .Float64 :
324
+ return convertRec (ctx , src , value .Float ())
325
+
295
326
case reflect .Ptr :
296
327
if value .IsNil () {
297
328
// Interpret a nil pointer as an undefined value that is only
298
329
// null by default, but may still be set: *null | _.
299
330
elem := goTypeToValue (ctx , false , reflect .TypeOf (v ).Elem ())
300
331
return makeNullable (elem , false ).(evaluated )
301
332
}
302
- return convert (ctx , src , value .Elem ().Interface ())
333
+ return convertRec (ctx , src , value .Elem ().Interface ())
303
334
304
335
case reflect .Struct :
305
336
obj := newStruct (src )
@@ -313,7 +344,15 @@ func convert(ctx *context, src source, x interface{}) evaluated {
313
344
if isOmitEmpty (& t ) && isZero (val ) {
314
345
continue
315
346
}
316
- sub := convert (ctx , src , val .Interface ())
347
+ sub := convertRec (ctx , src , val .Interface ())
348
+ if sub == nil {
349
+ // mimic behavior of encoding/json: skip fields of unsupported types
350
+ continue
351
+ }
352
+ if isBottom (sub ) {
353
+ return sub
354
+ }
355
+
317
356
// leave errors like we do during normal evaluation or do we
318
357
// want to return the error?
319
358
name := getName (& t )
@@ -328,21 +367,49 @@ func convert(ctx *context, src source, x interface{}) evaluated {
328
367
329
368
case reflect .Map :
330
369
obj := newStruct (src )
370
+
371
+ sorted := []string {}
372
+ keys := []string {}
331
373
t := value .Type ()
332
- if t .Key ().Kind () != reflect .String {
333
- return ctx .mkErr (src , "builtin map key not a string, but unsupported type %s" , t .Key ().String ())
374
+ switch key := t .Key (); key .Kind () {
375
+ case reflect .String ,
376
+ reflect .Int , reflect .Int8 , reflect .Int16 ,
377
+ reflect .Int32 , reflect .Int64 ,
378
+ reflect .Uint , reflect .Uint8 , reflect .Uint16 ,
379
+ reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
380
+ for _ , k := range value .MapKeys () {
381
+ s := fmt .Sprint (k )
382
+ keys = append (keys , s )
383
+ sorted = append (sorted , s )
384
+
385
+ val := value .MapIndex (k ).Interface ()
386
+ sub := convertRec (ctx , src , val )
387
+ // mimic behavior of encoding/json: report error of
388
+ // unsupported type.
389
+ if sub == nil {
390
+ return ctx .mkErr (baseValue {}, "unsupported Go type (%v)" , val )
391
+ }
392
+ if isBottom (sub ) {
393
+ return sub
394
+ }
395
+
396
+ // Set feature later.
397
+ obj .arcs = append (obj .arcs , arc {feature : 0 , v : sub })
398
+ }
399
+
400
+ default :
401
+ return ctx .mkErr (baseValue {}, "unsupported Go type for map key (%v)" , key )
334
402
}
335
- keys := []string {}
336
- for _ , k := range value .MapKeys () {
337
- keys = append (keys , k .String ())
403
+
404
+ // Assign label in normalized order.
405
+ sort .Strings (sorted )
406
+ for _ , k := range sorted {
407
+ ctx .strLabel (k )
338
408
}
339
- sort .Strings (keys )
340
- for _ , k := range keys {
341
- sub := convert (ctx , src , value .MapIndex (reflect .ValueOf (k )).Interface ())
342
- // leave errors like we do during normal evaluation or do we
343
- // want to return the error?
344
- f := ctx .strLabel (k )
345
- obj .arcs = append (obj .arcs , arc {feature : f , v : sub })
409
+
410
+ // Now assign the labels to the arcs.
411
+ for i , k := range keys {
412
+ obj .arcs [i ].feature = ctx .strLabel (k )
346
413
}
347
414
sort .Sort (obj )
348
415
return obj
@@ -351,7 +418,11 @@ func convert(ctx *context, src source, x interface{}) evaluated {
351
418
list := & list {baseValue : src .base ()}
352
419
arcs := []arc {}
353
420
for i := 0 ; i < value .Len (); i ++ {
354
- x := convert (ctx , src , value .Index (i ).Interface ())
421
+ val := value .Index (i ).Interface ()
422
+ x := convertRec (ctx , src , val )
423
+ if x == nil {
424
+ return ctx .mkErr (baseValue {}, "unsupported Go type (%v)" , val )
425
+ }
355
426
if isBottom (x ) {
356
427
return x
357
428
}
@@ -365,7 +436,7 @@ func convert(ctx *context, src source, x interface{}) evaluated {
365
436
return list
366
437
}
367
438
}
368
- return ctx . mkErr ( src , "builtin returned unsupported type %T" , x )
439
+ return nil
369
440
}
370
441
371
442
func toInt (ctx * context , src source , x int64 ) evaluated {
@@ -398,11 +469,33 @@ var (
398
469
//
399
470
// TODO: if this value will always be unified with a concrete type in Go, then
400
471
// many of the fields may be omitted.
401
- func goTypeToValue (ctx * context , allowNullDefault bool , t reflect.Type ) (e value ) {
472
+ func goTypeToValue (ctx * context , allowNullDefault bool , t reflect.Type ) value {
473
+ v := goTypeToValueRec (ctx , allowNullDefault , t )
474
+ if v == nil {
475
+ return ctx .mkErr (baseValue {}, "unsupported Go type (%v)" , t )
476
+ }
477
+ return v
478
+ }
479
+
480
+ func goTypeToValueRec (ctx * context , allowNullDefault bool , t reflect.Type ) (e value ) {
402
481
if e , ok := ctx .typeCache .Load (t ); ok {
403
482
return e .(value )
404
483
}
405
484
485
+ switch reflect .Zero (t ).Interface ().(type ) {
486
+ case * big.Int , big.Int :
487
+ e = & basicType {k : intKind }
488
+ goto store
489
+
490
+ case * big.Float , big.Float , * big.Rat , big.Rat :
491
+ e = & basicType {k : numKind }
492
+ goto store
493
+
494
+ case * apd.Decimal , apd.Decimal :
495
+ e = & basicType {k : numKind }
496
+ goto store
497
+ }
498
+
406
499
// Even if this is for types that we know cast to a certain type, it can't
407
500
// hurt to return top, as in these cases the concrete values will be
408
501
// strict instances and there cannot be any tags that further constrain
@@ -417,7 +510,7 @@ func goTypeToValue(ctx *context, allowNullDefault bool, t reflect.Type) (e value
417
510
for elem .Kind () == reflect .Ptr {
418
511
elem = elem .Elem ()
419
512
}
420
- e = goTypeToValue (ctx , false , elem )
513
+ e = goTypeToValueRec (ctx , false , elem )
421
514
if allowNullDefault {
422
515
e = wrapOrNull (e )
423
516
}
@@ -451,22 +544,6 @@ func goTypeToValue(ctx *context, allowNullDefault bool, t reflect.Type) (e value
451
544
e = & basicType {k : floatKind }
452
545
453
546
case reflect .Struct :
454
- // Some of these values have MarshalJSON methods, but that may not be
455
- // the case for older Go versions.
456
- name := fmt .Sprint (t )
457
- switch name {
458
- case "big.Int" :
459
- e = & basicType {k : intKind }
460
- goto store
461
- case "big.Rat" , "big.Float" , "apd.Decimal" :
462
- e = & basicType {k : floatKind }
463
- goto store
464
- case "time.Time" :
465
- // We let the concrete value decide.
466
- e = topSentinel
467
- goto store
468
- }
469
-
470
547
// First iterate to create struct, then iterate another time to
471
548
// resolve field tags to allow field tags to refer to the struct fields.
472
549
tags := map [label ]string {}
@@ -479,8 +556,8 @@ func goTypeToValue(ctx *context, allowNullDefault bool, t reflect.Type) (e value
479
556
continue
480
557
}
481
558
_ , ok := f .Tag .Lookup ("cue" )
482
- elem := goTypeToValue (ctx , ! ok , f .Type )
483
- if elem == nil {
559
+ elem := goTypeToValueRec (ctx , ! ok , f .Type )
560
+ if elem == nil || isBottom ( elem ) {
484
561
continue // Ignore fields for unsupported types
485
562
}
486
563
@@ -506,6 +583,9 @@ func goTypeToValue(ctx *context, allowNullDefault bool, t reflect.Type) (e value
506
583
507
584
for label , tag := range tags {
508
585
v := parseTag (ctx , obj , label , tag )
586
+ if isBottom (v ) {
587
+ return v
588
+ }
509
589
for i , a := range obj .arcs {
510
590
if a .feature == label {
511
591
// Instead of unifying with the existing type, we substitute
@@ -522,7 +602,10 @@ func goTypeToValue(ctx *context, allowNullDefault bool, t reflect.Type) (e value
522
602
if t .Elem ().Kind () == reflect .Uint8 {
523
603
e = & basicType {k : bytesKind }
524
604
} else {
525
- elem := goTypeToValue (ctx , allowNullDefault , t .Elem ())
605
+ elem := goTypeToValueRec (ctx , allowNullDefault , t .Elem ())
606
+ if elem == nil {
607
+ return ctx .mkErr (baseValue {}, "unsupported Go type (%v)" , t .Elem ())
608
+ }
526
609
527
610
var ln value = & top {}
528
611
if t .Kind () == reflect .Array {
@@ -535,16 +618,24 @@ func goTypeToValue(ctx *context, allowNullDefault bool, t reflect.Type) (e value
535
618
}
536
619
537
620
case reflect .Map :
538
- if key := t .Key (); key .Kind () != reflect .String {
539
- // What does the JSON library do here?
540
- e = ctx .mkErr (baseValue {}, "type %v not supported as key type" , key )
541
- break
621
+ switch key := t .Key (); key .Kind () {
622
+ case reflect .String , reflect .Int , reflect .Int8 , reflect .Int16 ,
623
+ reflect .Int32 , reflect .Int64 , reflect .Uint , reflect .Uint8 ,
624
+ reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
625
+ default :
626
+ return ctx .mkErr (baseValue {}, "unsupported Go type for map key (%v)" , key )
542
627
}
543
628
544
629
obj := newStruct (baseValue {})
545
630
sig := & params {}
546
631
sig .add (ctx .label ("_" , true ), & basicType {k : stringKind })
547
- v := goTypeToValue (ctx , allowNullDefault , t .Elem ())
632
+ v := goTypeToValueRec (ctx , allowNullDefault , t .Elem ())
633
+ if v == nil {
634
+ return ctx .mkErr (baseValue {}, "unsupported Go type (%v)" , t .Elem ())
635
+ }
636
+ if isBottom (v ) {
637
+ return v
638
+ }
548
639
obj .template = & lambdaExpr {params : sig , value : v }
549
640
550
641
e = wrapOrNull (obj )
@@ -559,7 +650,7 @@ store:
559
650
}
560
651
561
652
func wrapOrNull (e value ) value {
562
- if e .kind ().isAnyOf (nullKind ) {
653
+ if e == nil || isBottom ( e ) || e .kind ().isAnyOf (nullKind ) {
563
654
return e
564
655
}
565
656
return makeNullable (e , true )
0 commit comments