package gotypes

import (
	
	
	
	
)

// CmpType is a deterministic, environment-independent order over types, used to
// sort type slices into a stable order, never for identity (that goes through
// typeutil.Map) and never for output (that goes through a qualifier). Named types
// are ordered by package path + name rather than pointer, and every level is
// unaliased before comparison, so the order never depends on pointer addresses,
// load order, or whether a type was first seen through an alias. It is the
// ordering authority for types, so gotypes never has to serialize a type to a
// string except when rendering output or diagnostics.
//
// It is a WEAK order, not a structural total order: types that are not
// types.Identical can still compare equal. Named types are keyed on package
// path + name + type args (not their full definition), and type parameters on
// name + index (see the TypeParam case). Determinism therefore rests entirely on
// the absence of ties, not on the sort: every sorted slice holds types drawn from
// identity-keyed sets of provider-signature types that already differ in those
// keys, so no two elements ever compare equal, and the determinism tests guard
// that empirically: solve's TestNoCmpTypeTiesInSortedSlices asserts no tie
// reaches those sort sites. A structural string tiebreaker cannot substitute for
// this invariant: two distinct type parameters that share a name render
// identically, so no deterministic key separates them (their only distinguisher
// is object identity, which is exactly what this order avoids). Stability cannot
// be the safeguard either: several of these slices are collected from
// nondeterministically-ordered maps, where a stable sort would only preserve a
// nondeterministic input order. Callers still use a stable sort, but for
// consistency with plumb's other ordering sites rather than for determinism here.
func (,  types.Type) int {
	 = types.Unalias()
	 = types.Unalias()
	if ,  := typeRank(), typeRank();  !=  {
		return cmp.Compare(, )
	}
	switch a := .(type) {
	case *types.Basic:
		return cmp.Compare(.Kind(), .(*types.Basic).Kind())
	case *types.Pointer:
		return (.Elem(), .(*types.Pointer).Elem())
	case *types.Slice:
		return (.Elem(), .(*types.Slice).Elem())
	case *types.Array:
		 := .(*types.Array)
		if  := cmp.Compare(.Len(), .Len());  != 0 {
			return 
		}
		return (.Elem(), .Elem())
	case *types.Chan:
		 := .(*types.Chan)
		if  := cmp.Compare(.Dir(), .Dir());  != 0 {
			return 
		}
		return (.Elem(), .Elem())
	case *types.Map:
		 := .(*types.Map)
		if  := (.Key(), .Key());  != 0 {
			return 
		}
		return (.Elem(), .Elem())
	case *types.Signature:
		 := .(*types.Signature)
		if  := cmpBool(.Variadic(), .Variadic());  != 0 {
			return 
		}
		if  := cmpTuple(.Params(), .Params());  != 0 {
			return 
		}
		return cmpTuple(.Results(), .Results())
	case *types.Tuple:
		return cmpTuple(, .(*types.Tuple))
	case *types.Struct:
		 := .(*types.Struct)
		if  := cmp.Compare(.NumFields(), .NumFields());  != 0 {
			return 
		}
		for  := range .NumFields() {
			,  := .Field(), .Field()
			// Id() not Name() so an unexported field carries its package, matching
			// the identity semantics unify.go compares fields by.
			if  := strings.Compare(.Id(), .Id());  != 0 {
				return 
			}
			if  := cmpBool(.Embedded(), .Embedded());  != 0 {
				return 
			}
			if  := strings.Compare(.Tag(), .Tag());  != 0 {
				return 
			}
			if  := (.Type(), .Type());  != 0 {
				return 
			}
		}
		return 0
	case *types.Interface:
		 := .(*types.Interface)
		if  := cmp.Compare(.NumMethods(), .NumMethods());  != 0 {
			return 
		}
		for  := range .NumMethods() {
			,  := .Method(), .Method()
			if  := strings.Compare(.Id(), .Id());  != 0 {
				return 
			}
			if  := (.Type(), .Type());  != 0 {
				return 
			}
		}
		if  := cmp.Compare(.NumEmbeddeds(), .NumEmbeddeds());  != 0 {
			return 
		}
		for  := range .NumEmbeddeds() {
			if  := (.EmbeddedType(), .EmbeddedType());  != 0 {
				return 
			}
		}
		return 0
	case *types.Named:
		 := .(*types.Named)
		if  := cmpTypeName(.Obj(), .Obj());  != 0 {
			return 
		}
		return cmpTypeList(.TypeArgs(), .TypeArgs())
	case *types.TypeParam:
		 := .(*types.TypeParam)
		// Distinct parameters with the same name and index compare equal; a stable
		// sort leaves them in input order.
		if  := strings.Compare(.Obj().Name(), .Obj().Name());  != 0 {
			return 
		}
		return cmp.Compare(.Index(), .Index())
	case *types.Union:
		 := .(*types.Union)
		if  := cmp.Compare(.Len(), .Len());  != 0 {
			return 
		}
		for  := range .Len() {
			,  := .Term(), .Term()
			if  := cmpBool(.Tilde(), .Tilde());  != 0 {
				return 
			}
			if  := (.Type(), .Type());  != 0 {
				return 
			}
		}
		return 0
	}
	// Unreachable: typeRank already rejected any kind absent from this switch.
	panic(fmt.Sprintf("plumb: CmpType on unsupported type %T", ))
}

// typeRank orders the type kinds, the primary key of CmpType.
func ( types.Type) int {
	switch .(type) {
	case *types.Basic:
		return 0
	case *types.Pointer:
		return 1
	case *types.Slice:
		return 2
	case *types.Array:
		return 3
	case *types.Chan:
		return 4
	case *types.Map:
		return 5
	case *types.Signature:
		return 6
	case *types.Tuple:
		return 7
	case *types.Struct:
		return 8
	case *types.Interface:
		return 9
	case *types.Named:
		return 10
	case *types.TypeParam:
		return 11
	case *types.Union:
		return 12
	}
	panic(fmt.Sprintf("plumb: typeRank on unsupported type %T", ))
}

func (,  bool) int {
	switch {
	case  == :
		return 0
	case !:
		return -1
	default:
		return 1
	}
}

func (,  *types.Tuple) int {
	if  := cmp.Compare(.Len(), .Len());  != 0 {
		return 
	}
	for  := range .Len() {
		if  := CmpType(.At().Type(), .At().Type());  != 0 {
			return 
		}
	}
	return 0
}

// cmpTypeName orders named types' declaring objects by package path then name:
// environment-independent, unlike pointer identity.
func (,  *types.TypeName) int {
	,  := "", ""
	if .Pkg() != nil {
		 = .Pkg().Path()
	}
	if .Pkg() != nil {
		 = .Pkg().Path()
	}
	if  := strings.Compare(, );  != 0 {
		return 
	}
	return strings.Compare(.Name(), .Name())
}

func (,  *types.TypeList) int {
	// TypeList.Len is safe on a nil receiver (returns 0).
	,  := .Len(), .Len()
	if  := cmp.Compare(, );  != 0 {
		return 
	}
	for  := range  {
		if  := CmpType(.At(), .At());  != 0 {
			return 
		}
	}
	return 0
}