func (set *SelectionSet) Field(i int) *SelectedField {
	return set.fields[i]
}
Field returns the i'th field in the selection set. Field will panic if i is
not in the range [0, set.Len()).
package graphql
import (
	"strings"
	"golang.org/x/xerrors"
	"zombiezen.com/go/graphql-server/internal/gqlang"
)
type SelectionSet struct {
	fields []*SelectedField
}
type selectionSetScope struct {
	source    string
	doc       *gqlang.Document  
	types     map[string]*gqlType
	variables map[string]Value
	typeCondition map[string]struct{}
}
func (s *selectionSetScope) withTypeCondition(c map[string]struct{}) *selectionSetScope {
	s2 := new(selectionSetScope)
	*s2 = *s
	s2.typeCondition = c
	return s2
}
func newSelectionSet(s *selectionSetScope, typ *gqlType, ast *gqlang.SelectionSet) (*SelectionSet, []error) {
	if ast == nil {
		return nil, nil
	}
	sel := new(SelectionSet)
	errs := sel.merge(s, typ, ast)
	return sel, errs
}
func (set *SelectionSet) merge(s *selectionSetScope, typ *gqlType, ast *gqlang.SelectionSet) []error {
	if ast == nil {
		return nil
	}
	var errs []error
	for _, sel := range ast.Sel {
		switch {
		case sel.Field != nil:
			errs = append(errs, set.addField(s, typ, sel.Field)...)
		case sel.FragmentSpread != nil:
			name := sel.FragmentSpread.Name.Value
			frag := s.doc.FindFragment(name)
			fragType := s.types[frag.Type.Name.Value]
			subScope := s
			if typ.isAbstract() {
				subScope = s.withTypeCondition(fragmentTypeCondition(typ, fragType))
			}
			mergeErrs := set.merge(subScope, fragType, frag.SelectionSet)
			for _, err := range mergeErrs {
				errs = append(errs, xerrors.Errorf("fragment %s: %w", name, err))
			}
		case sel.InlineFragment != nil:
			fragType := typ
			subScope := s
			if sel.InlineFragment.Type != nil {
				fragType = s.types[sel.InlineFragment.Type.Name.Value]
				if typ.isAbstract() {
					subScope = s.withTypeCondition(fragmentTypeCondition(typ, fragType))
				}
			}
			errs = append(errs, set.merge(subScope, fragType, sel.InlineFragment.SelectionSet)...)
		default:
			panic("unknown selection type")
		}
	}
	return errs
}
func fragmentTypeCondition(parentType, fragType *gqlType) map[string]struct{} {
	parentPossible := parentType.possibleTypes()
	possible := make(map[string]struct{})
	for p := range fragType.possibleTypes() {
		if _, inParent := parentPossible[p]; inParent {
			possible[p.Name().String()] = struct{}{}
		}
	}
	return possible
}
func (set *SelectionSet) addField(s *selectionSetScope, typ *gqlType, f *gqlang.Field) []error {
	name := f.Name.Value
	key := name
	if f.Alias != nil {
		key = f.Alias.Value
	}
	var fieldInfo *objectTypeField
	switch name {
	case typeNameFieldName:
		fieldInfo = typeNameField()
	case schemaFieldName:
		fieldInfo = schemaField()
	case typeByNameFieldName:
		fieldInfo = typeByNameField()
	default:
		fieldInfo = typ.obj.field(name)
	}
	field := set.find(s.typeCondition, key)
	var errs []error
	if field == nil {
		field = &SelectedField{
			typeCondition: s.typeCondition,
			name:          name,
			key:           key,
			loc:           astPositionToLocation(f.Start().ToPosition(s.source)),
		}
		set.fields = append(set.fields, field)
		var argErrs []error
		field.args, argErrs = coerceArgumentValues(s, fieldInfo.args, f.Arguments)
		for _, err := range argErrs {
			errs = append(errs, wrapFieldError(field.key, field.loc, err))
		}
		if fieldInfo.typ.selectionSetType() != nil {
			field.sub = new(SelectionSet)
		}
	} else {
		if len(s.typeCondition) == 0 || len(field.typeCondition) == 0 {
			field.typeCondition = nil
		} else {
			for cond := range s.typeCondition {
				field.typeCondition[cond] = struct{}{}
			}
		}
	}
	if fieldSelType := fieldInfo.typ.selectionSetType(); fieldSelType != nil {
		subErrs := field.sub.merge(s.withTypeCondition(nil), fieldSelType, f.SelectionSet)
		for _, err := range subErrs {
			errs = append(errs, wrapFieldError(field.key, field.loc, err))
		}
	}
	return errs
}
func (set *SelectionSet) forType(typeName string) *SelectionSet {
	if set == nil {
		return nil
	}
	conditional := false
	for _, f := range set.fields {
		if len(f.typeCondition) > 0 {
			conditional = true
			break
		}
	}
	if !conditional {
		return set
	}
	fields := make([]*SelectedField, 0, len(set.fields))
	for _, f := range set.fields {
		if len(f.typeCondition) == 0 {
			fields = append(fields, f)
			continue
		}
		if _, ok := f.typeCondition[typeName]; ok {
			fields = append(fields, f)
		}
	}
	return &SelectionSet{fields: fields}
}
func (set *SelectionSet) find(typeCondition map[string]struct{}, key string) *SelectedField {
	if set == nil {
		return nil
	}
	for _, f := range set.fields {
		if f.key != key {
			continue
		}
		if len(f.typeCondition) > 0 && len(typeCondition) > 0 && !typeConditionsOverlap(f.typeCondition, typeCondition) {
			continue
		}
		return f
	}
	return nil
}
func typeConditionsOverlap(cond1, cond2 map[string]struct{}) bool {
	for k := range cond1 {
		if _, ok := cond2[k]; ok {
			return true
		}
	}
	return false
}
func (set *SelectionSet) Len() int {
	if set == nil {
		return 0
	}
	return len(set.fields)
}