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)
}
convertInlineFragment converts a single GraphQL inline fragment
(`... on MyType { myField }`) into Go struct-fields.

containingTypedef is the type-def corresponding to the type into which we
are spreading; it may be either an interface type (when spreading into one)
or an object type (when writing the implementations of such an interface, or
when using an inline fragment in an object type which is rare).  If the
given fragment does not apply to that type, this function returns nil, nil.

In general, we treat such fragments' fields as if they were fields of the
parent selection-set (except of course they are only included in types the
fragment matches); see docs/DESIGN.md for more.
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
}