func (g *generator) convertNamedFragment(fragment *ast.FragmentDefinition) (goType, error) {
	typ := g.schema.Types[fragment.TypeCondition]
	comment, directive, err := g.parsePrecedingComment(fragment, nil, fragment.Position, nil)
	if err != nil {
		return nil, err
	}
	desc := descriptionInfo{
		CommentOverride:    comment,
		GraphQLName:        typ.Name,
		GraphQLDescription: typ.Description,
		FragmentName:       fragment.Name,
	}
	fields, err := g.convertSelectionSet(
		newPrefixList(fragment.Name), fragment.SelectionSet, typ, directive)
	if err != nil {
		return nil, err
	}
	if directive.GetFlatten() {
		i, err := validateFlattenOption(typ, fragment.SelectionSet, fragment.Position)
		if err == nil {
			return fields[i].GoType, nil
		}
	}
	switch typ.Kind {
	case ast.Object:
		goType := &goStructType{
			GoName:          fragment.Name,
			Fields:          fields,
			Selection:       fragment.SelectionSet,
			descriptionInfo: desc,
			Generator:       g,
		}
		g.typeMap[fragment.Name] = goType
		return goType, nil
	case ast.Interface, ast.Union:
		implementationTypes := g.schema.GetPossibleTypes(typ)
		goType := &goInterfaceType{
			GoName:          fragment.Name,
			SharedFields:    fields,
			Implementations: make([]*goStructType, len(implementationTypes)),
			Selection:       fragment.SelectionSet,
			descriptionInfo: desc,
		}
		g.typeMap[fragment.Name] = goType
		for i, implDef := range implementationTypes {
			implFields, err := g.convertSelectionSet(
				newPrefixList(fragment.Name), fragment.SelectionSet, implDef, directive)
			if err != nil {
				return nil, err
			}
			implDesc := desc
			implDesc.GraphQLName = implDef.Name
			implTyp := &goStructType{
				GoName:          fragment.Name + upperFirst(implDef.Name),
				Fields:          implFields,
				Selection:       fragment.SelectionSet,
				descriptionInfo: implDesc,
				Generator:       g,
			}
			goType.Implementations[i] = implTyp
			g.typeMap[implTyp.GoName] = implTyp
		}
		return goType, nil
	default:
		return nil, errorf(fragment.Position, "invalid type for fragment: %v is a %v",
			fragment.TypeCondition, typ.Kind)
	}
}
convertNamedFragment converts a single GraphQL named fragment-definition
(`fragment MyFragment on MyType { ... }`) into a Go struct.
package generate
import (
	"fmt"
	"github.com/vektah/gqlparser/v2/ast"
)
func (g *generator) getType(
	goName, graphQLName string,
	selectionSet ast.SelectionSet,
	pos *ast.Position,
) (goType, error) {
	typ, ok := g.typeMap[goName]
	if !ok {
		return nil, nil
	}
	if typ.GraphQLTypeName() != graphQLName {
		return typ, errorf(
			pos, "conflicting definition for %s; this can indicate either "+
				"a genqlient internal error, a conflict between user-specified "+
				"type-names, or some very tricksy GraphQL field/type names: "+
				"expected GraphQL type %s, got %s",
			goName, typ.GraphQLTypeName(), graphQLName)
	}
	expectedSelectionSet := typ.SelectionSet()
	if err := selectionsMatch(pos, selectionSet, expectedSelectionSet); err != nil {
		return typ, errorf(
			pos, "conflicting definition for %s; this can indicate either "+
				"a genqlient internal error, a conflict between user-specified "+
				"type-names, or some very tricksy GraphQL field/type names: %v",
			goName, err)
	}
	return typ, nil
}
func (g *generator) addType(typ goType, goName string, pos *ast.Position) (goType, error) {
	otherTyp, err := g.getType(goName, typ.GraphQLTypeName(), typ.SelectionSet(), pos)
	if otherTyp != nil || err != nil {
		return otherTyp, err
	}
	g.typeMap[goName] = typ
	return typ, nil
}
func (g *generator) baseTypeForOperation(operation ast.Operation) (*ast.Definition, error) {
	switch operation {
	case ast.Query:
		return g.schema.Query, nil
	case ast.Mutation:
		return g.schema.Mutation, nil
	case ast.Subscription:
		if !g.Config.AllowBrokenFeatures {
			return nil, errorf(nil, "genqlient does not yet support subscriptions")
		}
		return g.schema.Subscription, nil
	default:
		return nil, errorf(nil, "unexpected operation: %v", operation)
	}
}
func (g *generator) convertOperation(
	operation *ast.OperationDefinition,
	queryOptions *genqlientDirective,
) (goType, error) {
	name := operation.Name + "Response"
	namePrefix := newPrefixList(operation.Name)
	if queryOptions.TypeName != "" {
		name = queryOptions.TypeName
		namePrefix = newPrefixList(queryOptions.TypeName)
	}
	baseType, err := g.baseTypeForOperation(operation.Operation)
	if err != nil {
		return nil, errorf(operation.Position, "%v", err)
	}
	fields, err := g.convertSelectionSet(
		namePrefix, operation.SelectionSet, baseType, queryOptions)
	if err != nil {
		return nil, err
	}
	if queryOptions.GetFlatten() {
		i, err := validateFlattenOption(baseType, operation.SelectionSet, operation.Position)
		if err == nil {
			return fields[i].GoType, nil
		}
	}
	goType := &goStructType{
		GoName: name,
		descriptionInfo: descriptionInfo{
			CommentOverride: fmt.Sprintf(
				"%v is returned by %v on success.", name, operation.Name),
			GraphQLName: baseType.Name,
		},
		Fields:    fields,
		Selection: operation.SelectionSet,
		Generator: g,
	}
	return g.addType(goType, goType.GoName, operation.Position)
}
var builtinTypes = map[string]string{
	"Int":     "int",
	"Float":   "float64",
	"String":  "string",
	"Boolean": "bool",
	"ID":      "string",
}
func (g *generator) convertArguments(
	operation *ast.OperationDefinition,
	queryOptions *genqlientDirective,
) (*goStructType, error) {
	if len(operation.VariableDefinitions) == 0 {
		return nil, nil
	}
	name := "__" + operation.Name + "Input"
	fields := make([]*goStructField, len(operation.VariableDefinitions))
	for i, arg := range operation.VariableDefinitions {
		_, options, err := g.parsePrecedingComment(arg, nil, arg.Position, queryOptions)
		if err != nil {
			return nil, err
		}
		goName := upperFirst(arg.Variable)
		goTyp, err := g.convertType(nil, arg.Type, nil, options, queryOptions)
		if err != nil {
			return nil, err
		}
		fields[i] = &goStructField{
			GoName:      goName,
			GoType:      goTyp,
			JSONName:    arg.Variable,
			GraphQLName: arg.Variable,
			Omitempty:   options.GetOmitempty(),
		}
	}
	goTyp := &goStructType{
		GoName:    name,
		Fields:    fields,
		Selection: nil,
		IsInput:   true,
		descriptionInfo: descriptionInfo{
			CommentOverride: fmt.Sprintf("%s is used internally by genqlient", name),
			GraphQLName: name,
		},
		Generator: g,
	}
	goTypAgain, err := g.addType(goTyp, goTyp.GoName, operation.Position)
	if err != nil {
		return nil, err
	}
	goTyp, ok := goTypAgain.(*goStructType)
	if !ok {
		return nil, errorf(
			operation.Position, "internal error: input type was %T", goTypAgain)
	}
	return goTyp, nil
}
func (g *generator) convertType(
	namePrefix *prefixList,
	typ *ast.Type,
	selectionSet ast.SelectionSet,
	options, queryOptions *genqlientDirective,
) (goType, error) {
	localBinding := options.Bind
	if localBinding != "" && localBinding != "-" {
		goRef, err := g.ref(localBinding)
		return &goOpaqueType{GoRef: goRef, GraphQLName: typ.Name()}, err
	}
	if typ.Elem != nil {
		elem, err := g.convertType(
			namePrefix, typ.Elem, selectionSet, options, queryOptions)
		return &goSliceType{elem}, err
	}
	def := g.schema.Types[typ.Name()]
	goTyp, err := g.convertDefinition(
		namePrefix, def, typ.Position, selectionSet, options, queryOptions)
	if options.GetPointer() {
		goTyp = &goPointerType{goTyp}
	}
	return goTyp, err
}
func (g *generator) convertDefinition(
	namePrefix *prefixList,
	def *ast.Definition,
	pos *ast.Position,
	selectionSet ast.SelectionSet,
	options, queryOptions *genqlientDirective,
) (goType, error) {
	globalBinding, ok := g.Config.Bindings[def.Name]
	if ok && options.Bind != "-" {
		if def.Kind == ast.Object || def.Kind == ast.Interface || def.Kind == ast.Union {
			err := g.validateBindingSelection(
				def.Name, globalBinding, pos, selectionSet)
			if err != nil {
				return nil, err
			}
		}
		goRef, err := g.ref(globalBinding.Type)
		return &goOpaqueType{
			GoRef:       goRef,
			GraphQLName: def.Name,
			Marshaler:   globalBinding.Marshaler,
			Unmarshaler: globalBinding.Unmarshaler,
		}, err
	}
	goBuiltinName, ok := builtinTypes[def.Name]
	if ok && options.TypeName == "" {
		return &goOpaqueType{GoRef: goBuiltinName, GraphQLName: def.Name}, nil
	}
	var name string
	if options.TypeName != "" {
		name = options.TypeName
		if namePrefix != nil && namePrefix.head == name && namePrefix.tail == nil {
			name = makeLongTypeName(namePrefix, def.Name)
		}
		namePrefix = newPrefixList(options.TypeName)
	} else if def.Kind == ast.InputObject || def.Kind == ast.Enum {
		name = upperFirst(def.Name)
	} else {
		name = makeTypeName(namePrefix, def.Name)
	}
	existing, err := g.getType(name, def.Name, selectionSet, pos)
	if existing != nil || err != nil {
		return existing, err
	}
	desc := descriptionInfo{
		GraphQLDescription: def.Description,
		GraphQLName:        def.Name,
	}
	kind := def.Kind
	if options.GetStruct() && validateStructOption(def, selectionSet, pos) == nil {
		kind = ast.Object
	}
	switch kind {
	case ast.Object:
		fields, err := g.convertSelectionSet(
			namePrefix, selectionSet, def, queryOptions)
		if err != nil {
			return nil, err
		}
		if options.GetFlatten() {
			i, err := validateFlattenOption(def, selectionSet, pos)
			if err == nil {
				return fields[i].GoType, nil
			}
		}
		goType := &goStructType{
			GoName:          name,
			Fields:          fields,
			Selection:       selectionSet,
			descriptionInfo: desc,
			Generator:       g,
		}
		return g.addType(goType, goType.GoName, pos)
	case ast.InputObject:
		goType := &goStructType{
			GoName:          name,
			Fields:          make([]*goStructField, len(def.Fields)),
			descriptionInfo: desc,
			IsInput:         true,
			Generator:       g,
		}
		_, err := g.addType(goType, goType.GoName, pos)
		if err != nil {
			return nil, err
		}
		for i, field := range def.Fields {
			_, fieldOptions, err := g.parsePrecedingComment(
				field, def, field.Position, queryOptions)
			if err != nil {
				return nil, err
			}
			goName := upperFirst(field.Name)
			fieldGoType, err := g.convertType(
				namePrefix, field.Type, nil, fieldOptions, queryOptions)
			if err != nil {
				return nil, err
			}
			goType.Fields[i] = &goStructField{
				GoName:      goName,
				GoType:      fieldGoType,
				JSONName:    field.Name,
				GraphQLName: field.Name,
				Description: field.Description,
				Omitempty:   fieldOptions.GetOmitempty(),
			}
		}
		return goType, nil
	case ast.Interface, ast.Union:
		sharedFields, err := g.convertSelectionSet(
			namePrefix, selectionSet, def, queryOptions)
		if err != nil {
			return nil, err
		}
		if options.GetFlatten() {
			i, err := validateFlattenOption(def, selectionSet, pos)
			if err == nil {
				return sharedFields[i].GoType, nil
			}
		}
		implementationTypes := g.schema.GetPossibleTypes(def)
		goType := &goInterfaceType{
			GoName:          name,
			SharedFields:    sharedFields,
			Implementations: make([]*goStructType, len(implementationTypes)),
			Selection:       selectionSet,
			descriptionInfo: desc,
		}
		for i, implDef := range implementationTypes {
			implTyp, err := g.convertDefinition(
				namePrefix, implDef, pos, selectionSet, options, queryOptions)
			if err != nil {
				return nil, err
			}
			implStructTyp, ok := implTyp.(*goStructType)
			if !ok {  
				return nil, errorf(
					pos, "interface %s had non-object implementation %s",
					def.Name, implDef.Name)
			}
			goType.Implementations[i] = implStructTyp
		}
		return g.addType(goType, goType.GoName, pos)
	case ast.Enum:
		goType := &goEnumType{
			GoName:      name,
			GraphQLName: def.Name,
			Description: def.Description,
			Values:      make([]goEnumValue, len(def.EnumValues)),
		}
		for i, val := range def.EnumValues {
			goType.Values[i] = goEnumValue{Name: val.Name, Description: val.Description}
		}
		return g.addType(goType, goType.GoName, pos)
	case ast.Scalar:
		if builtinTypes[def.Name] != "" {
			goType := &goTypenameForBuiltinType{
				GoTypeName:    name,
				GoBuiltinName: builtinTypes[def.Name],
				GraphQLName:   def.Name,
			}
			return g.addType(goType, goType.GoTypeName, pos)
		}
		return nil, errorf(
			pos, `unknown scalar %v: please add it to "bindings" in genqlient.yaml`, def.Name)
	default:
		return nil, errorf(pos, "unexpected kind: %v", def.Kind)
	}
}
func (g *generator) convertSelectionSet(
	namePrefix *prefixList,
	selectionSet ast.SelectionSet,
	containingTypedef *ast.Definition,
	queryOptions *genqlientDirective,
) ([]*goStructField, error) {
	fields := make([]*goStructField, 0, len(selectionSet))
	for _, selection := range selectionSet {
		_, selectionOptions, err := g.parsePrecedingComment(
			selection, nil, selection.GetPosition(), queryOptions)
		if err != nil {
			return nil, err
		}
		switch selection := selection.(type) {
		case *ast.Field:
			field, err := g.convertField(
				namePrefix, selection, selectionOptions, queryOptions)
			if err != nil {
				return nil, err
			}
			fields = append(fields, field)
		case *ast.FragmentSpread:
			maybeField, err := g.convertFragmentSpread(selection, containingTypedef)
			if err != nil {
				return nil, err
			} else if maybeField != nil {
				fields = append(fields, maybeField)
			}
		case *ast.InlineFragment:
			fragmentFields, err := g.convertInlineFragment(
				namePrefix, selection, containingTypedef, queryOptions)
			if err != nil {
				return nil, err
			}
			fields = append(fields, fragmentFields...)
		default:
			return nil, errorf(nil, "invalid selection type: %T", selection)
		}
	}
	uniqFields := make([]*goStructField, 0, len(selectionSet))
	fragmentNames := make(map[string]bool, len(selectionSet))
	fieldNames := make(map[string]bool, len(selectionSet))
	for _, field := range fields {
		if field.JSONName == "" {
			name := field.GoType.Reference()
			if fragmentNames[name] {
				continue
			}
			uniqFields = append(uniqFields, field)
			fragmentNames[name] = true
			continue
		}
		if fieldNames[field.JSONName] {
			switch field.GoType.Unwrap().(type) {
			case *goOpaqueType, *goEnumType:
				continue
			case *goStructType, *goInterfaceType:
				return nil, errorf(nil,
					"genqlient doesn't allow duplicate fields with different selections "+
						"(see https://github.com/Khan/genqlient/issues/64); "+
						"duplicate field: %s.%s", containingTypedef.Name, field.JSONName)
			default:
				return nil, errorf(nil, "unexpected field-type: %T", field.GoType.Unwrap())
			}
		}
		uniqFields = append(uniqFields, field)
		fieldNames[field.JSONName] = true
	}
	return uniqFields, nil
}
func fragmentMatches(containingTypedef, fragmentTypedef *ast.Definition) bool {
	if containingTypedef.Name == fragmentTypedef.Name {
		return true
	}
	for _, iface := range containingTypedef.Interfaces {
		if iface == fragmentTypedef.Name {
			return true
		}
	}
	return false
}
func (g *generator) convertInlineFragment(
	namePrefix *prefixList,
	fragment *ast.InlineFragment,
	containingTypedef *ast.Definition,
	queryOptions *genqlientDirective,
) ([]*goStructField, error) {
	fragmentTypedef := g.schema.Types[fragment.TypeCondition]
	if !fragmentMatches(containingTypedef, fragmentTypedef) {
		return nil, nil
	}
	return g.convertSelectionSet(namePrefix, fragment.SelectionSet,
		containingTypedef, queryOptions)
}
func (g *generator) convertFragmentSpread(
	fragmentSpread *ast.FragmentSpread,
	containingTypedef *ast.Definition,
) (*goStructField, error) {
	if !fragmentMatches(containingTypedef, fragmentSpread.Definition.Definition) {
		return nil, nil
	}
	typ, ok := g.typeMap[fragmentSpread.Name]
	if !ok {
		var err error
		typ, err = g.convertNamedFragment(fragmentSpread.Definition)
		if err != nil {
			return nil, err
		}
	}
	iface, ok := typ.(*goInterfaceType)
	if ok && containingTypedef.Kind == ast.Object {
		for _, impl := range iface.Implementations {
			if impl.GraphQLName == containingTypedef.Name {
				typ = impl
			}
		}
	}
	return &goStructField{GoName: ""  , GoType: typ}, nil
}