cuelang.org/go@v0.13.0/internal/core/convert/go.go (about)

     1  // Copyright 2019 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package convert allows converting to and from Go values and Types.
    16  package convert
    17  
    18  import (
    19  	"encoding"
    20  	"encoding/json"
    21  	"fmt"
    22  	"math"
    23  	"math/big"
    24  	"reflect"
    25  	"slices"
    26  	"strconv"
    27  	"strings"
    28  
    29  	"github.com/cockroachdb/apd/v3"
    30  	"golang.org/x/text/encoding/unicode"
    31  
    32  	"cuelang.org/go/cue/ast"
    33  	"cuelang.org/go/cue/ast/astutil"
    34  	"cuelang.org/go/cue/errors"
    35  	"cuelang.org/go/cue/parser"
    36  	"cuelang.org/go/cue/token"
    37  	"cuelang.org/go/internal"
    38  	"cuelang.org/go/internal/core/adt"
    39  	"cuelang.org/go/internal/core/compile"
    40  	"cuelang.org/go/internal/types"
    41  )
    42  
    43  // This file contains functionality for converting Go to CUE.
    44  //
    45  // The code in this file is a prototype implementation and is far from
    46  // optimized.
    47  
    48  func GoValueToValue(ctx *adt.OpContext, x interface{}, nilIsTop bool) adt.Value {
    49  	v := GoValueToExpr(ctx, nilIsTop, x)
    50  	// TODO: return Value
    51  	return toValue(v)
    52  }
    53  
    54  func GoTypeToExpr(ctx *adt.OpContext, x interface{}) (adt.Expr, errors.Error) {
    55  	v := newGoConverter(ctx).convertGoType(reflect.TypeOf(x))
    56  	if err := ctx.Err(); err != nil {
    57  		return v, err.Err
    58  	}
    59  	return v, nil
    60  }
    61  
    62  type goConverter struct {
    63  	ctx    *adt.OpContext
    64  	tfile  *token.File
    65  	offset int
    66  }
    67  
    68  func newGoConverter(ctx *adt.OpContext) *goConverter {
    69  	return &goConverter{
    70  		ctx: ctx,
    71  		// Code in *[token.File] uses size+1 in a few places. So do
    72  		// MaxInt-2 to be sure to avoid wrap-around issues.
    73  		tfile:  token.NewFile(pkgID(), -1, math.MaxInt-2),
    74  		offset: 1,
    75  	}
    76  }
    77  
    78  func (c *goConverter) setNextPos(n ast.Node) ast.Node {
    79  	ast.SetPos(n, c.tfile.Pos(c.offset, 0))
    80  	c.offset++
    81  	return n
    82  }
    83  
    84  func toValue(e adt.Expr) adt.Value {
    85  	if v, ok := e.(adt.Value); ok {
    86  		return v
    87  	}
    88  	obj := &adt.Vertex{}
    89  	obj.AddConjunct(adt.MakeRootConjunct(nil, e))
    90  	return obj
    91  }
    92  
    93  func compileExpr(ctx *adt.OpContext, expr ast.Expr) adt.Value {
    94  	c, err := compile.Expr(nil, ctx, pkgID(), expr)
    95  	if err != nil {
    96  		return &adt.Bottom{
    97  			Err: errors.Promote(err, "compile")}
    98  	}
    99  	return adt.Resolve(ctx, c)
   100  }
   101  
   102  // parseTag parses a CUE expression from a cue tag.
   103  func parseTag(ctx *adt.OpContext, field, tag string) ast.Expr {
   104  	tag, _ = splitTag(tag)
   105  	if tag == "" {
   106  		return topSentinel
   107  	}
   108  	expr, err := parser.ParseExpr("<field:>", tag)
   109  	if err != nil {
   110  		err := errors.Promote(err, "parser")
   111  		ctx.AddErr(errors.Wrapf(err, ctx.Pos(),
   112  			"invalid tag %q for field %q", tag, field))
   113  		return &ast.BadExpr{}
   114  	}
   115  	return expr
   116  }
   117  
   118  // splitTag splits a cue tag into cue and options.
   119  func splitTag(tag string) (cue string, options string) {
   120  	q := strings.LastIndexByte(tag, '"')
   121  	if c := strings.IndexByte(tag[q+1:], ','); c >= 0 {
   122  		return tag[:q+1+c], tag[q+1+c+1:]
   123  	}
   124  	return tag, ""
   125  }
   126  
   127  // TODO: should we allow mapping names in cue tags? This only seems like a good
   128  // idea if we ever want to allow mapping CUE to a different name than JSON.
   129  var tagsWithNames = []string{"json", "yaml", "protobuf"}
   130  
   131  func getName(f *reflect.StructField) string {
   132  	name := f.Name
   133  	if f.Anonymous {
   134  		name = ""
   135  	}
   136  	for _, s := range tagsWithNames {
   137  		if tag, ok := f.Tag.Lookup(s); ok {
   138  			if p := strings.IndexByte(tag, ','); p >= 0 {
   139  				tag = tag[:p]
   140  			}
   141  			if tag != "" {
   142  				name = tag
   143  				break
   144  			}
   145  		}
   146  	}
   147  	return name
   148  }
   149  
   150  // isOptional indicates whether a field should be marked as optional.
   151  func isOptional(f *reflect.StructField) bool {
   152  	isOptional := false
   153  	switch f.Type.Kind() {
   154  	case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Interface, reflect.Slice:
   155  		// Note: it may be confusing to distinguish between an empty slice and
   156  		// a nil slice. However, it is also surprising to not be able to specify
   157  		// a default value for a slice. So for now we will allow it.
   158  		isOptional = true
   159  	}
   160  	if tag, ok := f.Tag.Lookup("cue"); ok {
   161  		// TODO: only if first field is not empty.
   162  		_, opt := splitTag(tag)
   163  		isOptional = false
   164  		for _, f := range strings.Split(opt, ",") {
   165  			switch f {
   166  			case "opt":
   167  				isOptional = true
   168  			case "req":
   169  				return false
   170  			}
   171  		}
   172  	} else if tag, ok = f.Tag.Lookup("json"); ok {
   173  		isOptional = false
   174  		for _, f := range strings.Split(tag, ",")[1:] {
   175  			if f == "omitempty" {
   176  				return true
   177  			}
   178  		}
   179  	}
   180  	return isOptional
   181  }
   182  
   183  // isOmitEmpty means that the zero value is interpreted as undefined.
   184  func isOmitEmpty(f *reflect.StructField) bool {
   185  	isOmitEmpty := false
   186  	switch f.Type.Kind() {
   187  	case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Interface, reflect.Slice:
   188  		// Note: it may be confusing to distinguish between an empty slice and
   189  		// a nil slice. However, it is also surprising to not be able to specify
   190  		// a default value for a slice. So for now we will allow it.
   191  		isOmitEmpty = true
   192  
   193  	default:
   194  		// TODO: we can also infer omit empty if a type cannot be nil if there
   195  		// is a constraint that unconditionally disallows the zero value.
   196  	}
   197  	tag, ok := f.Tag.Lookup("json")
   198  	if ok {
   199  		isOmitEmpty = false
   200  		for _, f := range strings.Split(tag, ",")[1:] {
   201  			if f == "omitempty" {
   202  				return true
   203  			}
   204  		}
   205  	}
   206  	return isOmitEmpty
   207  }
   208  
   209  func GoValueToExpr(ctx *adt.OpContext, nilIsTop bool, x interface{}) adt.Expr {
   210  	e := newGoConverter(ctx).convertRec(nilIsTop, x)
   211  	if e == nil {
   212  		return ctx.AddErrf("unsupported Go type (%T)", x)
   213  	}
   214  	return e
   215  }
   216  
   217  func isNil(x reflect.Value) bool {
   218  	switch x.Kind() {
   219  	// Only check for supported types; ignore func and chan.
   220  	case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Interface:
   221  		return x.IsNil()
   222  	}
   223  	return false
   224  }
   225  
   226  func (c *goConverter) convertRec(nilIsTop bool, x interface{}) (result adt.Value) {
   227  	if t := (&types.Value{}); types.CastValue(t, x) {
   228  		// TODO: panic if not the same runtime.
   229  		return t.V
   230  	}
   231  	src := c.ctx.Source()
   232  
   233  	switch v := x.(type) {
   234  	case nil:
   235  		if nilIsTop {
   236  			ident, _ := src.(*ast.Ident)
   237  			return &adt.Top{Src: ident}
   238  		}
   239  		return &adt.Null{Src: src}
   240  
   241  	case *ast.File:
   242  		x, err := compile.Files(nil, c.ctx, pkgID(), v)
   243  		if err != nil {
   244  			return &adt.Bottom{Err: errors.Promote(err, "compile")}
   245  		}
   246  		if _, n := x.SingleConjunct(); n != 1 {
   247  			panic("unexpected length")
   248  		}
   249  		return x
   250  
   251  	case ast.Expr:
   252  		return compileExpr(c.ctx, v)
   253  
   254  	case *big.Int:
   255  		v2 := new(apd.BigInt).SetMathBigInt(v)
   256  		return &adt.Num{
   257  			Src: src,
   258  			K:   adt.IntKind,
   259  			X:   *apd.NewWithBigInt(v2, 0),
   260  		}
   261  
   262  	case *big.Rat:
   263  		// should we represent this as a binary operation?
   264  		n := &adt.Num{Src: src, K: adt.IntKind}
   265  		_, err := internal.BaseContext.Quo(&n.X,
   266  			apd.NewWithBigInt(new(apd.BigInt).SetMathBigInt(v.Num()), 0),
   267  			apd.NewWithBigInt(new(apd.BigInt).SetMathBigInt(v.Denom()), 0),
   268  		)
   269  		if err != nil {
   270  			return c.ctx.AddErrf("could not convert *big.Rat: %v", err)
   271  		}
   272  		if !v.IsInt() {
   273  			n.K = adt.FloatKind
   274  		}
   275  		return n
   276  
   277  	case *big.Float:
   278  		n := &adt.Num{Src: src, K: adt.FloatKind}
   279  		_, _, err := n.X.SetString(v.String())
   280  		if err != nil {
   281  			return c.ctx.AddErr(errors.Promote(err, "invalid float"))
   282  		}
   283  		return n
   284  
   285  	case *apd.Decimal:
   286  		// TODO: should we allow an "int" bit to be set here? It is a bit
   287  		// tricky, as we would also need to pass down the result of rounding.
   288  		// So more likely an API must return explicitly whether a value is
   289  		// a float or an int after all.
   290  		// The code to autodetect whether something is an integer can be done
   291  		// with this:
   292  		kind := adt.FloatKind
   293  		var d apd.Decimal
   294  		res, _ := internal.BaseContext.RoundToIntegralExact(&d, v)
   295  		if !res.Inexact() {
   296  			kind = adt.IntKind
   297  			v = &d
   298  		}
   299  		n := &adt.Num{Src: src, K: kind}
   300  		n.X = *v
   301  		return n
   302  
   303  	case json.Marshaler:
   304  		b, err := v.MarshalJSON()
   305  		if err != nil {
   306  			return c.ctx.AddErr(errors.Promote(err, "json.Marshaler"))
   307  		}
   308  		expr, err := parser.ParseExpr("json", b)
   309  		if err != nil {
   310  			panic(err) // cannot happen
   311  		}
   312  		return compileExpr(c.ctx, expr)
   313  
   314  	case encoding.TextMarshaler:
   315  		b, err := v.MarshalText()
   316  		if err != nil {
   317  			return c.ctx.AddErr(errors.Promote(err, "encoding.TextMarshaler"))
   318  		}
   319  		s, _ := unicode.UTF8.NewEncoder().String(string(b))
   320  		return &adt.String{Src: src, Str: s}
   321  
   322  	case error:
   323  		var errs errors.Error
   324  		switch x := v.(type) {
   325  		case errors.Error:
   326  			errs = x
   327  		default:
   328  			errs = c.ctx.Newf("%s", x.Error())
   329  		}
   330  		return &adt.Bottom{Err: errs}
   331  	case bool:
   332  		return &adt.Bool{Src: src, B: v}
   333  	case string:
   334  		s, _ := unicode.UTF8.NewEncoder().String(v)
   335  		return &adt.String{Src: src, Str: s}
   336  	case []byte:
   337  		return &adt.Bytes{Src: src, B: v}
   338  	case int:
   339  		return c.toInt(int64(v))
   340  	case int8:
   341  		return c.toInt(int64(v))
   342  	case int16:
   343  		return c.toInt(int64(v))
   344  	case int32:
   345  		return c.toInt(int64(v))
   346  	case int64:
   347  		return c.toInt(v)
   348  	case uint:
   349  		return c.toUint(uint64(v))
   350  	case uint8:
   351  		return c.toUint(uint64(v))
   352  	case uint16:
   353  		return c.toUint(uint64(v))
   354  	case uint32:
   355  		return c.toUint(uint64(v))
   356  	case uint64:
   357  		return c.toUint(v)
   358  	case uintptr:
   359  		return c.toUint(uint64(v))
   360  	case float64:
   361  		n := &adt.Num{Src: src, K: adt.FloatKind}
   362  		_, err := n.X.SetFloat64(v)
   363  		if err != nil {
   364  			return c.ctx.AddErr(errors.Promote(err, "invalid float"))
   365  		}
   366  		return n
   367  	case float32:
   368  		n := &adt.Num{Src: src, K: adt.FloatKind}
   369  		// apd.Decimal has a SetFloat64 method, but no SetFloat32.
   370  		_, _, err := n.X.SetString(strconv.FormatFloat(float64(v), 'E', -1, 32))
   371  		if err != nil {
   372  			return c.ctx.AddErr(errors.Promote(err, "invalid float"))
   373  		}
   374  		return n
   375  
   376  	case reflect.Value:
   377  		if v.CanInterface() {
   378  			return c.convertRec(nilIsTop, v.Interface())
   379  		}
   380  
   381  	default:
   382  		value := reflect.ValueOf(v)
   383  		switch value.Kind() {
   384  		case reflect.Bool:
   385  			return &adt.Bool{Src: src, B: value.Bool()}
   386  
   387  		case reflect.String:
   388  			str := value.String()
   389  			str, _ = unicode.UTF8.NewEncoder().String(str)
   390  			// TODO: here and above: allow to fail on invalid strings.
   391  			// if !utf8.ValidString(str) {
   392  			// 	return ctx.AddErrf("cannot convert result to string: invalid UTF-8")
   393  			// }
   394  			return &adt.String{Src: src, Str: str}
   395  
   396  		case reflect.Int, reflect.Int8, reflect.Int16,
   397  			reflect.Int32, reflect.Int64:
   398  			return c.toInt(value.Int())
   399  
   400  		case reflect.Uint, reflect.Uint8, reflect.Uint16,
   401  			reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   402  			return c.toUint(value.Uint())
   403  
   404  		case reflect.Float32, reflect.Float64:
   405  			return c.convertRec(nilIsTop, value.Float())
   406  
   407  		case reflect.Ptr:
   408  			if value.IsNil() {
   409  				if nilIsTop {
   410  					ident, _ := src.(*ast.Ident)
   411  					return &adt.Top{Src: ident}
   412  				}
   413  				return &adt.Null{Src: src}
   414  			}
   415  			return c.convertRec(nilIsTop, value.Elem().Interface())
   416  
   417  		case reflect.Struct:
   418  			sl := &adt.StructLit{Src: c.setNextPos(ast.NewStruct())}
   419  			sl.Init(c.ctx)
   420  			v := &adt.Vertex{}
   421  
   422  			t := value.Type()
   423  			for i := 0; i < value.NumField(); i++ {
   424  				sf := t.Field(i)
   425  				if sf.PkgPath != "" {
   426  					continue
   427  				}
   428  				val := value.Field(i)
   429  				if !nilIsTop && isNil(val) {
   430  					continue
   431  				}
   432  				if tag, _ := sf.Tag.Lookup("json"); tag == "-" {
   433  					continue
   434  				}
   435  				if isOmitEmpty(&sf) && val.IsZero() {
   436  					continue
   437  				}
   438  				sub := c.convertRec(nilIsTop, val.Interface())
   439  				if sub == nil {
   440  					// mimic behavior of encoding/json: skip fields of unsupported types
   441  					continue
   442  				}
   443  				if _, ok := sub.(*adt.Bottom); ok {
   444  					return sub
   445  				}
   446  
   447  				// leave errors like we do during normal evaluation or do we
   448  				// want to return the error?
   449  				name := getName(&sf)
   450  				if name == "-" {
   451  					continue
   452  				}
   453  				if sf.Anonymous && name == "" {
   454  					arc, ok := sub.(*adt.Vertex)
   455  					if ok {
   456  						v.Arcs = append(v.Arcs, arc.Arcs...)
   457  					}
   458  					continue
   459  				}
   460  
   461  				f := c.ctx.StringLabel(name)
   462  				c.createField(f, sub, sl)
   463  				v.Arcs = append(v.Arcs, c.ensureArcVertex(sub, f))
   464  			}
   465  
   466  			env := c.ctx.Env(0)
   467  			if env == nil {
   468  				env = &adt.Environment{}
   469  			}
   470  			// There is no closedness or cycle info for Go structs, so we
   471  			// pass an empty CloseInfo.
   472  			v.AddStruct(sl, env, adt.CloseInfo{})
   473  			v.SetValue(c.ctx, &adt.StructMarker{})
   474  			v.ForceDone()
   475  
   476  			return v
   477  
   478  		case reflect.Map:
   479  			obj := &adt.StructLit{Src: c.setNextPos(ast.NewStruct())}
   480  			obj.Init(c.ctx)
   481  			v := &adt.Vertex{}
   482  
   483  			t := value.Type()
   484  			switch key := t.Key(); key.Kind() {
   485  			default:
   486  				if !key.Implements(textMarshaler) {
   487  					return c.ctx.AddErrf("unsupported Go type for map key (%v)", key)
   488  				}
   489  				fallthrough
   490  			case reflect.String,
   491  				reflect.Int, reflect.Int8, reflect.Int16,
   492  				reflect.Int32, reflect.Int64,
   493  				reflect.Uint, reflect.Uint8, reflect.Uint16,
   494  				reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   495  
   496  				iter := value.MapRange()
   497  				for iter.Next() {
   498  					k := iter.Key()
   499  					val := iter.Value()
   500  					// if isNil(val) {
   501  					// 	continue
   502  					// }
   503  
   504  					sub := c.convertRec(nilIsTop, val.Interface())
   505  					// mimic behavior of encoding/json: report error of
   506  					// unsupported type.
   507  					if sub == nil {
   508  						return c.ctx.AddErrf("unsupported Go type (%T)", val.Interface())
   509  					}
   510  					if isBottom(sub) {
   511  						return sub
   512  					}
   513  
   514  					s := fmt.Sprint(k)
   515  					f := c.ctx.StringLabel(s)
   516  					v.Arcs = append(v.Arcs, c.ensureArcVertex(sub, f))
   517  				}
   518  				slices.SortFunc(v.Arcs, func(a, b *adt.Vertex) int {
   519  					return strings.Compare(a.Label.IdentString(c.ctx), b.Label.IdentString(c.ctx))
   520  				})
   521  				// Create all the adt/ast fields after sorting the arcs
   522  				for _, arc := range v.Arcs {
   523  					c.createField(arc.Label, arc, obj)
   524  				}
   525  			}
   526  
   527  			env := c.ctx.Env(0)
   528  			if env == nil {
   529  				env = &adt.Environment{}
   530  			}
   531  			v.AddStruct(obj, env, adt.CloseInfo{})
   532  			v.SetValue(c.ctx, &adt.StructMarker{})
   533  			v.ForceDone()
   534  
   535  			return v
   536  
   537  		case reflect.Slice, reflect.Array:
   538  			list := &adt.ListLit{Src: ast.NewList()}
   539  			c.setNextPos(list.Src)
   540  
   541  			v := &adt.Vertex{}
   542  
   543  			for i := 0; i < value.Len(); i++ {
   544  				val := value.Index(i)
   545  				x := c.convertRec(nilIsTop, val.Interface())
   546  				if x == nil {
   547  					return c.ctx.AddErrf("unsupported Go type (%T)",
   548  						val.Interface())
   549  				}
   550  				if isBottom(x) {
   551  					return x
   552  				}
   553  				list.Elems = append(list.Elems, x)
   554  				f := adt.MakeIntLabel(adt.IntLabel, int64(i))
   555  				v.Arcs = append(v.Arcs, c.ensureArcVertex(x, f))
   556  			}
   557  
   558  			env := c.ctx.Env(0)
   559  			if env == nil {
   560  				env = &adt.Environment{}
   561  			}
   562  			v.AddConjunct(adt.MakeRootConjunct(env, list))
   563  			v.SetValue(c.ctx, &adt.ListMarker{})
   564  			v.ForceDone()
   565  
   566  			return v
   567  		}
   568  	}
   569  	return nil
   570  }
   571  
   572  func (c *goConverter) ensureArcVertex(x adt.Value, l adt.Feature) *adt.Vertex {
   573  	env := c.ctx.Env(0)
   574  	if env == nil {
   575  		env = &adt.Environment{}
   576  	}
   577  	arc, ok := x.(*adt.Vertex)
   578  	if ok {
   579  		a := *arc
   580  		arc = &a
   581  		arc.Label = l
   582  	} else {
   583  		arc = &adt.Vertex{Label: l}
   584  		arc.AddConjunct(adt.MakeRootConjunct(env, x))
   585  		arc.SetValue(c.ctx, x)
   586  		arc.ForceDone()
   587  	}
   588  	return arc
   589  }
   590  
   591  func (c *goConverter) createField(l adt.Feature, sub adt.Value, sl *adt.StructLit) {
   592  	src := sl.Src.(*ast.StructLit)
   593  	astField := &ast.Field{
   594  		Label:      ast.NewIdent(l.IdentString(c.ctx)),
   595  		Constraint: token.ILLEGAL,
   596  	}
   597  	if expr, ok := sub.Source().(ast.Expr); ok {
   598  		astField.Value = expr
   599  	}
   600  	c.setNextPos(astField.Label)
   601  	src.Elts = append(src.Elts, astField)
   602  	field := &adt.Field{Label: l, Value: sub, Src: astField}
   603  	sl.Decls = append(sl.Decls, field)
   604  }
   605  
   606  func (c *goConverter) toInt(x int64) adt.Value {
   607  	n := &adt.Num{Src: c.ctx.Source(), K: adt.IntKind}
   608  	n.X = *apd.New(x, 0)
   609  	return n
   610  }
   611  
   612  func (c *goConverter) toUint(x uint64) adt.Value {
   613  	n := &adt.Num{Src: c.ctx.Source(), K: adt.IntKind}
   614  	n.X.Coeff.SetUint64(x)
   615  	return n
   616  }
   617  
   618  func (c *goConverter) convertGoType(t reflect.Type) adt.Expr {
   619  	// TODO: this can be much more efficient.
   620  	// TODO: synchronize
   621  	return c.goTypeToValue(true, t)
   622  }
   623  
   624  var (
   625  	jsonMarshaler = reflect.TypeFor[json.Marshaler]()
   626  	textMarshaler = reflect.TypeFor[encoding.TextMarshaler]()
   627  	topSentinel   = ast.NewIdent("_")
   628  )
   629  
   630  // goTypeToValue converts a Go Type to a value.
   631  //
   632  // TODO: if this value will always be unified with a concrete type in Go, then
   633  // many of the fields may be omitted.
   634  func (c *goConverter) goTypeToValue(allowNullDefault bool, t reflect.Type) adt.Expr {
   635  	if _, t, ok := c.ctx.LoadType(t); ok {
   636  		return t
   637  	}
   638  
   639  	_, v := c.goTypeToValueRec(allowNullDefault, t)
   640  	if v == nil {
   641  		return c.ctx.AddErrf("unsupported Go type (%v)", t)
   642  	}
   643  	return v
   644  }
   645  
   646  func (c *goConverter) goTypeToValueRec(allowNullDefault bool, t reflect.Type) (e ast.Expr, expr adt.Expr) {
   647  	if src, t, ok := c.ctx.LoadType(t); ok {
   648  		return src, t
   649  	}
   650  
   651  	switch reflect.Zero(t).Interface().(type) {
   652  	case *big.Int, big.Int:
   653  		e = ast.NewIdent("int")
   654  		goto store
   655  
   656  	case *big.Float, big.Float, *big.Rat, big.Rat:
   657  		e = ast.NewIdent("number")
   658  		goto store
   659  
   660  	case *apd.Decimal, apd.Decimal:
   661  		e = ast.NewIdent("number")
   662  		goto store
   663  	}
   664  
   665  	// Even if this is for types that we know cast to a certain type, it can't
   666  	// hurt to return top, as in these cases the concrete values will be
   667  	// strict instances and there cannot be any tags that further constrain
   668  	// the values.
   669  	if t.Implements(jsonMarshaler) || t.Implements(textMarshaler) {
   670  		e = topSentinel
   671  		goto store
   672  	}
   673  
   674  	switch k := t.Kind(); k {
   675  	case reflect.Ptr:
   676  		elem := t.Elem()
   677  		for elem.Kind() == reflect.Ptr {
   678  			elem = elem.Elem()
   679  		}
   680  		e, _ = c.goTypeToValueRec(false, elem)
   681  		if allowNullDefault {
   682  			e = wrapOrNull(e)
   683  		}
   684  
   685  	case reflect.Interface:
   686  		switch t.Name() {
   687  		case "error":
   688  			// This is really null | _|_. There is no error if the error is null.
   689  			e = ast.NewNull()
   690  		default:
   691  			e = topSentinel // `_`
   692  		}
   693  
   694  	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
   695  		reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   696  		e = compile.LookupRange(t.Kind().String()).Source().(ast.Expr)
   697  
   698  	case reflect.Uint, reflect.Uintptr:
   699  		e = compile.LookupRange("uint64").Source().(ast.Expr)
   700  
   701  	case reflect.Int:
   702  		e = compile.LookupRange("int64").Source().(ast.Expr)
   703  
   704  	case reflect.String:
   705  		e = ast.NewIdent("__string")
   706  
   707  	case reflect.Bool:
   708  		e = ast.NewIdent("__bool")
   709  
   710  	case reflect.Float32, reflect.Float64:
   711  		e = ast.NewIdent("__number")
   712  
   713  	case reflect.Struct:
   714  		obj := &ast.StructLit{}
   715  
   716  		// TODO: dirty trick: set this to a temporary Vertex and then update the
   717  		// arcs and conjuncts of this vertex below. This will allow circular
   718  		// references. Maybe have a special kind of "hardlink" reference.
   719  		c.ctx.StoreType(t, obj, nil)
   720  
   721  		for i := 0; i < t.NumField(); i++ {
   722  			f := t.Field(i)
   723  			if f.PkgPath != "" {
   724  				continue
   725  			}
   726  			_, ok := f.Tag.Lookup("cue")
   727  			elem, _ := c.goTypeToValueRec(!ok, f.Type)
   728  			if isBad(elem) {
   729  				continue // Ignore fields for unsupported types
   730  			}
   731  
   732  			// leave errors like we do during normal evaluation or do we
   733  			// want to return the error?
   734  			name := getName(&f)
   735  			if name == "-" {
   736  				continue
   737  			}
   738  
   739  			if tag, ok := f.Tag.Lookup("cue"); ok {
   740  				v := parseTag(c.ctx, name, tag)
   741  				if isBad(v) {
   742  					return v, nil
   743  				}
   744  				elem = ast.NewBinExpr(token.AND, elem, v)
   745  			}
   746  			// TODO: if an identifier starts with __ (or otherwise is not a
   747  			// valid CUE name), make it a string and create a map to a new
   748  			// name for references.
   749  
   750  			// The GO JSON decoder always allows a value to be undefined.
   751  			d := &ast.Field{Label: ast.NewIdent(name), Value: elem}
   752  			c.setNextPos(d)
   753  			if isOptional(&f) {
   754  				internal.SetConstraint(d, token.OPTION)
   755  			}
   756  			obj.Elts = append(obj.Elts, d)
   757  		}
   758  
   759  		// TODO: should we validate references here? Can be done using
   760  		// astutil.ToFile and astutil.Resolve.
   761  
   762  		e = obj
   763  
   764  	case reflect.Array, reflect.Slice:
   765  		if t.Elem().Kind() == reflect.Uint8 {
   766  			e = ast.NewIdent("__bytes")
   767  		} else {
   768  			elem, _ := c.goTypeToValueRec(allowNullDefault, t.Elem())
   769  			if elem == nil {
   770  				b := c.ctx.AddErrf("unsupported Go type (%v)", t.Elem())
   771  				return &ast.BadExpr{}, b
   772  			}
   773  
   774  			if t.Kind() == reflect.Array {
   775  				e = ast.NewCall(
   776  					ast.NewSel(&ast.Ident{
   777  						Name: "list",
   778  						Node: ast.NewImport(nil, "list")},
   779  						"Repeat"),
   780  					ast.NewList(elem),
   781  					ast.NewLit(token.INT, strconv.Itoa(t.Len())))
   782  			} else {
   783  				e = ast.NewList(&ast.Ellipsis{Type: elem})
   784  			}
   785  		}
   786  		if k == reflect.Slice {
   787  			e = wrapOrNull(e)
   788  		}
   789  
   790  	case reflect.Map:
   791  		switch key := t.Key(); key.Kind() {
   792  		case reflect.String, reflect.Int, reflect.Int8, reflect.Int16,
   793  			reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8,
   794  			reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   795  		default:
   796  			b := c.ctx.AddErrf("unsupported Go type for map key (%v)", key)
   797  			return &ast.BadExpr{}, b
   798  		}
   799  
   800  		v, x := c.goTypeToValueRec(allowNullDefault, t.Elem())
   801  		if v == nil {
   802  			b := c.ctx.AddErrf("unsupported Go type (%v)", t.Elem())
   803  			return &ast.BadExpr{}, b
   804  		}
   805  		if isBad(v) {
   806  			return v, x
   807  		}
   808  
   809  		e = ast.NewStruct(&ast.Field{
   810  			Label: ast.NewList(ast.NewIdent("__string")),
   811  			Value: v,
   812  		})
   813  
   814  		e = wrapOrNull(e)
   815  	}
   816  
   817  store:
   818  	// TODO: store error if not nil?
   819  	if e != nil {
   820  		c.setNextPos(e)
   821  		f := &ast.File{Decls: []ast.Decl{&ast.EmbedDecl{Expr: e}}}
   822  		astutil.Resolve(f, func(_ token.Pos, msg string, args ...interface{}) {
   823  			c.ctx.AddErrf(msg, args...)
   824  		})
   825  		var x adt.Expr
   826  		x2, err := compile.Expr(nil, c.ctx, pkgID(), e)
   827  		if err != nil {
   828  			b := &adt.Bottom{Err: err}
   829  			c.ctx.AddBottom(b)
   830  			x = b
   831  		} else {
   832  			x = x2.Expr()
   833  		}
   834  		c.ctx.StoreType(t, e, x)
   835  		return e, x
   836  	}
   837  	return e, nil
   838  }
   839  
   840  func isBottom(x adt.Node) bool {
   841  	if x == nil {
   842  		return true
   843  	}
   844  	b, _ := x.(*adt.Bottom)
   845  	return b != nil
   846  }
   847  
   848  func isBad(x ast.Expr) bool {
   849  	if x == nil {
   850  		return true
   851  	}
   852  	if bad, _ := x.(*ast.BadExpr); bad != nil {
   853  		return true
   854  	}
   855  	return false
   856  }
   857  
   858  func wrapOrNull(e ast.Expr) ast.Expr {
   859  	switch x := e.(type) {
   860  	case *ast.BasicLit:
   861  		if x.Kind == token.NULL {
   862  			return x
   863  		}
   864  	case *ast.BadExpr:
   865  		return e
   866  	}
   867  	return makeNullable(e, true)
   868  }
   869  
   870  func makeNullable(e ast.Expr, nullIsDefault bool) ast.Expr {
   871  	var null ast.Expr = ast.NewNull()
   872  	if nullIsDefault {
   873  		null = &ast.UnaryExpr{Op: token.MUL, X: null}
   874  	}
   875  	return ast.NewBinExpr(token.OR, null, e)
   876  }
   877  
   878  // pkgID returns a package path that can never resolve to an existing package.
   879  func pkgID() string {
   880  	return "_"
   881  }