github.com/codykaup/genqlient@v0.6.2/generate/types.go (about)

     1  package generate
     2  
     3  // This file defines the data structures from which genqlient generates types,
     4  // and the code to write them out as actual Go code.  The main entrypoint is
     5  // goType, which represents such a type, but convert.go also constructs each
     6  // of the implementing types, by traversing the GraphQL operation and schema.
     7  
     8  import (
     9  	"fmt"
    10  	"io"
    11  	"strings"
    12  
    13  	"github.com/vektah/gqlparser/v2/ast"
    14  )
    15  
    16  // goType represents a type for which we'll generate code.
    17  type goType interface {
    18  	// WriteDefinition writes the code for this type into the given io.Writer.
    19  	//
    20  	// TODO(benkraft): Some of the implementations might now benefit from being
    21  	// converted to templates.
    22  	WriteDefinition(io.Writer, *generator) error
    23  
    24  	// Reference returns the Go name of this type, e.g. []*MyStruct, and may be
    25  	// used to refer to it in Go code.
    26  	Reference() string
    27  
    28  	// GraphQLTypeName returns the name of the GraphQL type to which this Go type
    29  	// corresponds.
    30  	GraphQLTypeName() string
    31  
    32  	// SelectionSet returns the selection-set of the GraphQL field from which
    33  	// this type was generated, or nil if none is applicable (for GraphQL
    34  	// scalar, enum, and input types, as well as any opaque
    35  	// (non-genqlient-generated) type since those are validated upon creation).
    36  	SelectionSet() ast.SelectionSet
    37  
    38  	// Remove slice/pointer wrappers, and return the underlying (named (or
    39  	// builtin)) type.  For example, given []*MyStruct, return MyStruct.
    40  	Unwrap() goType
    41  
    42  	// Count the number of times Unwrap() will unwrap a slice type.  For
    43  	// example, given [][][]*MyStruct (or []**[][]*MyStruct, but we never
    44  	// currently generate that), return 3.
    45  	SliceDepth() int
    46  
    47  	// True if Unwrap() will unwrap a pointer at least once.
    48  	IsPointer() bool
    49  }
    50  
    51  var (
    52  	_ goType = (*goOpaqueType)(nil)
    53  	_ goType = (*goSliceType)(nil)
    54  	_ goType = (*goPointerType)(nil)
    55  	_ goType = (*goEnumType)(nil)
    56  	_ goType = (*goStructType)(nil)
    57  	_ goType = (*goInterfaceType)(nil)
    58  	_ goType = (*goGenericType)(nil)
    59  )
    60  
    61  type (
    62  	// goOpaqueType represents a user-defined or builtin type, often used to
    63  	// represent a GraphQL scalar.  (See Config.Bindings for more context.)
    64  	goOpaqueType struct {
    65  		GoRef                  string
    66  		GraphQLName            string
    67  		Marshaler, Unmarshaler string
    68  	}
    69  	// goTypenameForBuiltinType represents a builtin type that was
    70  	// given a different name due to a `typename` directive.  We
    71  	// create a type like `type MyString string` for it.
    72  	goTypenameForBuiltinType struct {
    73  		GoTypeName    string
    74  		GoBuiltinName string
    75  		GraphQLName   string
    76  	}
    77  	// goSliceType represents the Go type []Elem, used to represent GraphQL
    78  	// list types.
    79  	goSliceType struct{ Elem goType }
    80  	// goSliceType represents the Go type *Elem, used when requested by the
    81  	// user (perhaps to handle nulls explicitly, or to avoid copying large
    82  	// structures).
    83  	goPointerType struct{ Elem goType }
    84  	// goGenericType represent the Go type GoGenericRef[Elem], used when requested by the
    85  	// user to box nullable data without using pointers or sentinel values
    86  	goGenericType struct {
    87  		GoGenericRef string
    88  		Elem         goType
    89  	}
    90  )
    91  
    92  // Opaque types are defined by the user; pointers and slices need no definition
    93  func (typ *goOpaqueType) WriteDefinition(io.Writer, *generator) error { return nil }
    94  
    95  func (typ *goTypenameForBuiltinType) WriteDefinition(w io.Writer, g *generator) error {
    96  	fmt.Fprintf(w, "type %s %s", typ.GoTypeName, typ.GoBuiltinName)
    97  	return nil
    98  }
    99  func (typ *goSliceType) WriteDefinition(io.Writer, *generator) error   { return nil }
   100  func (typ *goPointerType) WriteDefinition(io.Writer, *generator) error { return nil }
   101  func (typ *goGenericType) WriteDefinition(io.Writer, *generator) error { return nil }
   102  
   103  func (typ *goOpaqueType) Reference() string             { return typ.GoRef }
   104  func (typ *goTypenameForBuiltinType) Reference() string { return typ.GoTypeName }
   105  func (typ *goSliceType) Reference() string              { return "[]" + typ.Elem.Reference() }
   106  func (typ *goPointerType) Reference() string            { return "*" + typ.Elem.Reference() }
   107  func (typ *goGenericType) Reference() string {
   108  	return fmt.Sprintf("%s[%s]", typ.GoGenericRef, typ.Elem.Reference())
   109  }
   110  
   111  func (typ *goOpaqueType) SelectionSet() ast.SelectionSet             { return nil }
   112  func (typ *goTypenameForBuiltinType) SelectionSet() ast.SelectionSet { return nil }
   113  func (typ *goSliceType) SelectionSet() ast.SelectionSet              { return typ.Elem.SelectionSet() }
   114  func (typ *goPointerType) SelectionSet() ast.SelectionSet            { return typ.Elem.SelectionSet() }
   115  func (typ *goGenericType) SelectionSet() ast.SelectionSet            { return typ.Elem.SelectionSet() }
   116  
   117  func (typ *goOpaqueType) GraphQLTypeName() string             { return typ.GraphQLName }
   118  func (typ *goTypenameForBuiltinType) GraphQLTypeName() string { return typ.GraphQLName }
   119  func (typ *goSliceType) GraphQLTypeName() string              { return typ.Elem.GraphQLTypeName() }
   120  func (typ *goPointerType) GraphQLTypeName() string            { return typ.Elem.GraphQLTypeName() }
   121  func (typ *goGenericType) GraphQLTypeName() string            { return typ.Elem.GraphQLTypeName() }
   122  
   123  // goEnumType represents a Go named-string type used to represent a GraphQL
   124  // enum.  In this case, we generate both the type (`type T string`) and also a
   125  // list of consts representing the values.
   126  type goEnumType struct {
   127  	GoName      string
   128  	GraphQLName string
   129  	Description string
   130  	Values      []goEnumValue
   131  }
   132  
   133  type goEnumValue struct {
   134  	GoName      string
   135  	GraphQLName string
   136  	Description string
   137  }
   138  
   139  func (typ *goEnumType) WriteDefinition(w io.Writer, g *generator) error {
   140  	// All GraphQL enums have underlying type string (in the Go sense).
   141  	writeDescription(w, typ.Description)
   142  	fmt.Fprintf(w, "type %s string\n", typ.GoName)
   143  	fmt.Fprintf(w, "const (\n")
   144  	for _, val := range typ.Values {
   145  		writeDescription(w, val.Description)
   146  		fmt.Fprintf(w, "%s %s = \"%s\"\n",
   147  			val.GoName, typ.GoName, val.GraphQLName)
   148  	}
   149  	fmt.Fprintf(w, ")\n")
   150  	return nil
   151  }
   152  
   153  func (typ *goEnumType) Reference() string              { return typ.GoName }
   154  func (typ *goEnumType) SelectionSet() ast.SelectionSet { return nil }
   155  func (typ *goEnumType) GraphQLTypeName() string        { return typ.GraphQLName }
   156  
   157  // goStructType represents a Go struct type used to represent a GraphQL object
   158  // or input-object type.
   159  type goStructType struct {
   160  	GoName    string
   161  	Fields    []*goStructField
   162  	IsInput   bool
   163  	Selection ast.SelectionSet
   164  	descriptionInfo
   165  	Generator *generator // for the convenience of the template
   166  }
   167  
   168  type goStructField struct {
   169  	GoName      string
   170  	GoType      goType
   171  	JSONName    string // i.e. the field's alias in this query
   172  	GraphQLName string // i.e. the field's name in its type-def
   173  	Omitempty   bool   // only used on input types
   174  	Description string
   175  }
   176  
   177  // IsAbstract returns true if this field is of abstract type (i.e. GraphQL
   178  // union or interface; equivalently, represented by an interface in Go).
   179  func (field *goStructField) IsAbstract() bool {
   180  	_, ok := field.GoType.Unwrap().(*goInterfaceType)
   181  	return ok
   182  }
   183  
   184  // IsEmbedded returns true if this field is embedded (a.k.a. anonymous), which
   185  // is in practice true if it corresponds to a named fragment spread in GraphQL.
   186  func (field *goStructField) IsEmbedded() bool {
   187  	return field.GoName == ""
   188  }
   189  
   190  // Selector returns the field's name, which is unqualified type-name if it's
   191  // embedded.
   192  func (field *goStructField) Selector() string {
   193  	if field.GoName != "" {
   194  		return field.GoName
   195  	}
   196  	// TODO(benkraft): This assumes the type is package-local, which is always
   197  	// true for embedded types for us, but isn't the most robust assumption.
   198  	return field.GoType.Unwrap().Reference()
   199  }
   200  
   201  // unmarshaler returns:
   202  //   - the name of the function to use to unmarshal this field
   203  //   - true if this is a fully-qualified name (false if it is a package-local
   204  //     unqualified name)
   205  //   - true if we need to generate an unmarshaler at all, false if the default
   206  //     behavior will suffice
   207  func (field *goStructField) unmarshaler() (qualifiedName string, needsImport bool, needsUnmarshaler bool) {
   208  	switch typ := field.GoType.Unwrap().(type) {
   209  	case *goOpaqueType:
   210  		if typ.Unmarshaler != "" {
   211  			return typ.Unmarshaler, true, true
   212  		}
   213  	case *goInterfaceType:
   214  		return "__unmarshal" + typ.Reference(), false, true
   215  	}
   216  	return "encoding/json.Unmarshal", true, field.IsEmbedded()
   217  }
   218  
   219  // Unmarshaler returns the Go name of the function to use to unmarshal this
   220  // field (which may be "json.Unmarshal" if there's not a special one).
   221  func (field *goStructField) Unmarshaler(g *generator) (string, error) {
   222  	name, needsImport, _ := field.unmarshaler()
   223  	if needsImport {
   224  		return g.ref(name)
   225  	}
   226  	return name, nil
   227  }
   228  
   229  // marshaler returns:
   230  //   - the fully-qualified name of the function to use to marshal this field
   231  //   - true if we need to generate an marshaler at all, false if the default
   232  //     behavior will suffice
   233  func (field *goStructField) marshaler() (qualifiedName string, needsImport bool, needsMarshaler bool) {
   234  	switch typ := field.GoType.Unwrap().(type) {
   235  	case *goOpaqueType:
   236  		if typ.Marshaler != "" {
   237  			return typ.Marshaler, true, true
   238  		}
   239  	case *goInterfaceType:
   240  		return "__marshal" + typ.Reference(), false, true
   241  	}
   242  	return "encoding/json.Marshal", true, field.IsEmbedded()
   243  }
   244  
   245  // Marshaler returns the Go name of the function to use to marshal this
   246  // field (which may be "json.Marshal" if there's not a special one).
   247  func (field *goStructField) Marshaler(g *generator) (string, error) {
   248  	name, needsImport, _ := field.marshaler()
   249  	if needsImport {
   250  		return g.ref(name)
   251  	}
   252  	return name, nil
   253  }
   254  
   255  // NeedsMarshaling returns true if this field needs special handling when
   256  // marshaling and unmarshaling, e.g. if it has a user-specified custom
   257  // (un)marshaler.  Note if it needs one, it needs the other: even if the user
   258  // only specified an unmarshaler, we need to add `json:"-"` to the field, which
   259  // means we need to specially handling it when marshaling.
   260  func (field *goStructField) NeedsMarshaling() bool {
   261  	_, _, ok1 := field.marshaler()
   262  	_, _, ok2 := field.unmarshaler()
   263  	return ok1 || ok2
   264  }
   265  
   266  // NeedsMarshaler returns true if any fields of this type need special
   267  // handling when (un)marshaling (see goStructField.NeedsMarshaling).
   268  func (typ *goStructType) NeedsMarshaling() bool {
   269  	for _, f := range typ.Fields {
   270  		if f.NeedsMarshaling() {
   271  			return true
   272  		}
   273  	}
   274  	return false
   275  }
   276  
   277  // selector represents a field and the path to get there from the type in
   278  // question, and is used in FlattenedFields, below.
   279  type selector struct {
   280  	*goStructField
   281  	// e.g. "OuterEmbed.InnerEmbed.LeafField"
   282  	Selector string
   283  }
   284  
   285  // FlattenedFields returns the fields of this type and its recursive embeds,
   286  // and the paths to reach them (via those embeds), but with different
   287  // visibility rules for conflicting fields than Go.
   288  //
   289  // (Before you read further, now's a good time to review [Go's rules].
   290  // Done?  Good.)
   291  //
   292  // To illustrate the need, consider the following query:
   293  //
   294  //	fragment A on T { id }
   295  //	fragment B on T { id }
   296  //	query Q { t { ...A ...B } }
   297  //
   298  // We generate types:
   299  //
   300  //	type A struct { Id string `json:"id"` }
   301  //	type B struct { Id string `json:"id"` }
   302  //	type QT struct { A; B }
   303  //
   304  // According to Go's embedding rules, QT has no field Id: since QT.A.Id and
   305  // QT.B.Id are at equal depth, neither wins and gets promoted.  (Go's JSON
   306  // library uses similar logic to decide which field to write to JSON, except
   307  // with the additional rule that a field with a JSON tag wins over a field
   308  // without; in our case both have such a field.)
   309  //
   310  // Those rules don't work for us.  When unmarshaling, we want to fill in all
   311  // the potentially-matching fields (QT.A.Id and QT.B.Id in this case), and when
   312  // marshaling, we want to always marshal exactly one potentially-conflicting
   313  // field; we're happy to use the Go visibility rules when they apply but we
   314  // need to always marshal one field, even if there's not a clear best choice.
   315  // For unmarshaling, our QT.UnmarshalJSON ends up unmarshaling the same JSON
   316  // object into QT, QT.A, and QT.B, which gives us the behavior we want.  But
   317  // for marshaling, we need to resolve the conflicts: if we simply marshaled QT,
   318  // QT.A, and QT.B, we'd have to do some JSON-surgery to join them, and we'd
   319  // probably end up with duplicate fields, which leads to unpredictable behavior
   320  // based on the reader.  That's no good.
   321  //
   322  // So: instead, we have our own rules, which work like the Go rules, except
   323  // that if there's a tie we choose the first field (in source order).  (In
   324  // practice, hopefully, they all match, but validating that is even more work
   325  // for a fairly rare case.)  This function returns, for each JSON-name, the Go
   326  // field we want to use.  In the example above, it would return:
   327  //
   328  //	[]selector{{<goStructField for QT.A.Id>, "A.Id"}}
   329  //
   330  // [Go's rules]: https://golang.org/ref/spec#Selectors
   331  func (typ *goStructType) FlattenedFields() ([]*selector, error) {
   332  	seenJSONNames := map[string]bool{}
   333  	retval := make([]*selector, 0, len(typ.Fields))
   334  
   335  	queue := make([]*selector, len(typ.Fields))
   336  	for i, field := range typ.Fields {
   337  		queue[i] = &selector{field, field.Selector()}
   338  	}
   339  
   340  	// Since our (non-embedded) fields always have JSON tags, the logic we want
   341  	// is simply: do a breadth-first search through the recursively embedded
   342  	// fields, and take the first one we see with a given JSON tag.
   343  	for len(queue) > 0 {
   344  		field := queue[0]
   345  		queue = queue[1:]
   346  		if field.IsEmbedded() {
   347  			typ, ok := field.GoType.(*goStructType)
   348  			if !ok {
   349  				// Should never happen: embeds correspond to named fragments,
   350  				// and even if the fragment is of interface type in GraphQL,
   351  				// either it's spread into a concrete type, or we are writing
   352  				// one of the implementations of the interface into which it's
   353  				// spread; either way we embed the corresponding implementation
   354  				// of the fragment.
   355  				return nil, errorf(nil,
   356  					"genqlient internal error: embedded field %s.%s was not a struct",
   357  					typ.GoName, field.GoName)
   358  			}
   359  
   360  			// Enqueue the embedded fields for our BFS.
   361  			for _, subField := range typ.Fields {
   362  				queue = append(queue,
   363  					&selector{subField, field.Selector + "." + subField.Selector()})
   364  			}
   365  			continue
   366  		}
   367  
   368  		if seenJSONNames[field.JSONName] {
   369  			// We already chose a selector for this JSON field.  Skip it.
   370  			continue
   371  		}
   372  
   373  		// Else, we are the selector we are looking for.
   374  		seenJSONNames[field.JSONName] = true
   375  		retval = append(retval, field)
   376  	}
   377  	return retval, nil
   378  }
   379  
   380  func (typ *goStructType) WriteDefinition(w io.Writer, g *generator) error {
   381  	writeDescription(w, structDescription(typ))
   382  
   383  	fmt.Fprintf(w, "type %s struct {\n", typ.GoName)
   384  	for _, field := range typ.Fields {
   385  		writeDescription(w, field.Description)
   386  		jsonTag := `"` + field.JSONName
   387  		if field.Omitempty {
   388  			jsonTag += ",omitempty"
   389  		}
   390  		jsonTag += `"`
   391  		if field.NeedsMarshaling() {
   392  			// certain types are handled in our (Un)MarshalJSON (see below)
   393  			jsonTag = `"-"`
   394  		}
   395  		// Note for embedded types field.GoName is "", which produces the code
   396  		// we want!
   397  		fmt.Fprintf(w, "\t%s %s `json:%s`\n",
   398  			field.GoName, field.GoType.Reference(), jsonTag)
   399  	}
   400  	fmt.Fprintf(w, "}\n")
   401  
   402  	// Write out getter methods for each field.  These are most useful for
   403  	// shared fields of an interface -- the methods will be included in the
   404  	// interface.  But they can be useful in other cases, for example where you
   405  	// have a union several of whose members have a shared field (and can
   406  	// thereby be handled together).  For simplicity's sake, we just write the
   407  	// methods always.
   408  	//
   409  	// Note we use the *flattened* fields here, which ensures we avoid
   410  	// conflicts in the case where multiple embedded types include the same
   411  	// field.
   412  	flattened, err := typ.FlattenedFields()
   413  	if err != nil {
   414  		return err
   415  	}
   416  	for _, field := range flattened {
   417  		description := fmt.Sprintf(
   418  			"Get%s returns %s.%s, and is useful for accessing the field via an interface.",
   419  			field.GoName, typ.GoName, field.GoName)
   420  		writeDescription(w, description)
   421  		fmt.Fprintf(w, "func (v *%s) Get%s() %s { return v.%s }\n",
   422  			typ.GoName, field.GoName, field.GoType.Reference(), field.Selector)
   423  	}
   424  
   425  	// Now, if needed, write the marshaler/unmarshaler.  We need one if we have
   426  	// any interface-typed fields, or any embedded fields.
   427  	//
   428  	// For interface-typed fields, ideally we'd write an UnmarshalJSON method
   429  	// on the field, but you can't add a method to an interface.  So we write a
   430  	// per-interface-type helper, but we have to call it (with a little
   431  	// boilerplate) everywhere the type is referenced.
   432  	//
   433  	// For embedded fields (from fragments), mostly the JSON library would just
   434  	// do what we want, but there are two problems.  First, if the embedded
   435  	// type has its own UnmarshalJSON, naively that would be promoted to
   436  	// become our UnmarshalJSON, which is no good.  But we don't want to just
   437  	// hide that method and inline its fields, either; we need to call its
   438  	// UnmarshalJSON (on the same object we unmarshal into this struct).
   439  	// Second, if the embedded type duplicates any fields of the embedding type
   440  	// -- maybe both the fragment and the selection into which it's spread
   441  	// select the same field, or several fragments select the same field -- the
   442  	// JSON library will only fill one of those (the least-nested one); we want
   443  	// to fill them all.
   444  	//
   445  	// For fields with a custom marshaler or unmarshaler, we do basically the
   446  	// same thing as interface-typed fields, except the user has defined the
   447  	// helper.
   448  	//
   449  	// Note that genqlient itself only uses unmarshalers for output types, and
   450  	// marshalers for input types.  But we write both in case you want to write
   451  	// your data to JSON for some reason (say to put it in a cache).  (And we
   452  	// need to write both if we need to write either, because in such cases we
   453  	// write a `json:"-"` tag on the field.)
   454  	//
   455  	// TODO(benkraft): If/when proposal #5901 is implemented (Go 1.18 at the
   456  	// earliest), we may be able to do some of this a simpler way.
   457  	if typ.NeedsMarshaling() {
   458  		err := g.render("unmarshal.go.tmpl", w, typ)
   459  		if err != nil {
   460  			return err
   461  		}
   462  		err = g.render("marshal.go.tmpl", w, typ)
   463  		if err != nil {
   464  			return err
   465  		}
   466  	}
   467  	return nil
   468  }
   469  
   470  func (typ *goStructType) Reference() string              { return typ.GoName }
   471  func (typ *goStructType) SelectionSet() ast.SelectionSet { return typ.Selection }
   472  func (typ *goStructType) GraphQLTypeName() string        { return typ.GraphQLName }
   473  
   474  // goInterfaceType represents a Go interface type, used to represent a GraphQL
   475  // interface or union type.
   476  type goInterfaceType struct {
   477  	GoName string
   478  	// Fields shared by all the interface's implementations;
   479  	// we'll generate getter methods for each.
   480  	SharedFields    []*goStructField
   481  	Implementations []*goStructType
   482  	Selection       ast.SelectionSet
   483  	descriptionInfo
   484  }
   485  
   486  func (typ *goInterfaceType) WriteDefinition(w io.Writer, g *generator) error {
   487  	writeDescription(w, interfaceDescription(typ))
   488  
   489  	// Write the interface.
   490  	fmt.Fprintf(w, "type %s interface {\n", typ.GoName)
   491  	implementsMethodName := fmt.Sprintf("implementsGraphQLInterface%v", typ.GoName)
   492  	fmt.Fprintf(w, "\t%s()\n", implementsMethodName)
   493  	for _, sharedField := range typ.SharedFields {
   494  		if sharedField.GoName == "" { // embedded type
   495  			fmt.Fprintf(w, "\t%s\n", sharedField.GoType.Reference())
   496  			continue
   497  		}
   498  
   499  		methodName := "Get" + sharedField.GoName
   500  		description := ""
   501  		if sharedField.GraphQLName == "__typename" {
   502  			description = fmt.Sprintf(
   503  				"%s returns the receiver's concrete GraphQL type-name "+
   504  					"(see interface doc for possible values).", methodName)
   505  		} else {
   506  			description = fmt.Sprintf(
   507  				`%s returns the interface-field %q from its implementation.`,
   508  				methodName, sharedField.GraphQLName)
   509  			if sharedField.Description != "" {
   510  				description = fmt.Sprintf(
   511  					"%s\nThe GraphQL interface field's documentation follows.\n\n%s",
   512  					description, sharedField.Description)
   513  			}
   514  		}
   515  
   516  		writeDescription(w, description)
   517  		fmt.Fprintf(w, "\t%s() %s\n", methodName, sharedField.GoType.Reference())
   518  	}
   519  	fmt.Fprintf(w, "}\n")
   520  
   521  	// Now, write out the implementations.
   522  	for _, impl := range typ.Implementations {
   523  		fmt.Fprintf(w, "func (v *%s) %s() {}\n",
   524  			impl.Reference(), implementsMethodName)
   525  	}
   526  
   527  	// Finally, write the marshal- and unmarshal-helpers, which
   528  	// will be called by struct fields referencing this type (see
   529  	// goStructType.WriteDefinition).
   530  	err := g.render("unmarshal_helper.go.tmpl", w, typ)
   531  	if err != nil {
   532  		return err
   533  	}
   534  	return g.render("marshal_helper.go.tmpl", w, typ)
   535  }
   536  
   537  func (typ *goInterfaceType) Reference() string              { return typ.GoName }
   538  func (typ *goInterfaceType) SelectionSet() ast.SelectionSet { return typ.Selection }
   539  func (typ *goInterfaceType) GraphQLTypeName() string        { return typ.GraphQLName }
   540  
   541  func (typ *goOpaqueType) Unwrap() goType             { return typ }
   542  func (typ *goTypenameForBuiltinType) Unwrap() goType { return typ }
   543  func (typ *goSliceType) Unwrap() goType              { return typ.Elem.Unwrap() }
   544  func (typ *goPointerType) Unwrap() goType            { return typ.Elem.Unwrap() }
   545  func (typ *goGenericType) Unwrap() goType            { return typ.Elem.Unwrap() }
   546  func (typ *goEnumType) Unwrap() goType               { return typ }
   547  func (typ *goStructType) Unwrap() goType             { return typ }
   548  func (typ *goInterfaceType) Unwrap() goType          { return typ }
   549  
   550  func (typ *goOpaqueType) SliceDepth() int             { return 0 }
   551  func (typ *goTypenameForBuiltinType) SliceDepth() int { return 0 }
   552  func (typ *goSliceType) SliceDepth() int              { return typ.Elem.SliceDepth() + 1 }
   553  func (typ *goPointerType) SliceDepth() int            { return 0 }
   554  func (typ *goGenericType) SliceDepth() int            { return 0 }
   555  func (typ *goEnumType) SliceDepth() int               { return 0 }
   556  func (typ *goStructType) SliceDepth() int             { return 0 }
   557  func (typ *goInterfaceType) SliceDepth() int          { return 0 }
   558  
   559  func (typ *goOpaqueType) IsPointer() bool             { return false }
   560  func (typ *goTypenameForBuiltinType) IsPointer() bool { return false }
   561  func (typ *goSliceType) IsPointer() bool              { return typ.Elem.IsPointer() }
   562  func (typ *goPointerType) IsPointer() bool            { return true }
   563  func (typ *goGenericType) IsPointer() bool            { return false }
   564  func (typ *goEnumType) IsPointer() bool               { return false }
   565  func (typ *goStructType) IsPointer() bool             { return false }
   566  func (typ *goInterfaceType) IsPointer() bool          { return false }
   567  
   568  func writeDescription(w io.Writer, desc string) {
   569  	if desc != "" {
   570  		for _, line := range strings.Split(desc, "\n") {
   571  			fmt.Fprintf(w, "// %s\n", strings.TrimLeft(line, " \t"))
   572  		}
   573  	}
   574  }