package apidiff

import (
	
	
	
)

// Two types are correspond if they are identical except for defined types,
// which must correspond.
//
// Two defined types correspond if they can be interchanged in the old and new APIs,
// possibly after a renaming.
//
// This is not a pure function. If we come across named types while traversing,
// we establish correspondence.
func ( *differ) (,  types.Type) bool {
	return .corr(, , nil)
}

// corr determines whether old and new correspond. The argument p is a list of
// known interface identities, to avoid infinite recursion.
//
// corr calls itself recursively as much as possible, to establish more
// correspondences and so check more of the API. E.g. if the new function has more
// parameters than the old, compare all the old ones before returning false.
//
// Compare this to the implementation of go/types.Identical.
func ( *differ) (,  types.Type,  *ifacePair) bool {
	 = types.Unalias()
	 = types.Unalias()
	// Structure copied from types.Identical.
	switch old := .(type) {
	case *types.Basic:
		if ,  := .(*types.Basic);  {
			return .Kind() == .Kind()
		}

	case *types.Array:
		if ,  := .(*types.Array);  {
			return .(.Elem(), .Elem(), ) && .Len() == .Len()
		}

	case *types.Slice:
		if ,  := .(*types.Slice);  {
			return .(.Elem(), .Elem(), )
		}

	case *types.Map:
		if ,  := .(*types.Map);  {
			return .(.Key(), .Key(), ) && .(.Elem(), .Elem(), )
		}

	case *types.Chan:
		if ,  := .(*types.Chan);  {
			return .(.Elem(), .Elem(), ) && .Dir() == .Dir()
		}

	case *types.Pointer:
		if ,  := .(*types.Pointer);  {
			return .(.Elem(), .Elem(), )
		}

	case *types.Signature:
		if ,  := .(*types.Signature);  {
			 := .(.Params(), .Params(), )
			 := .(.Results(), .Results(), )
			return .Variadic() == .Variadic() &&  && 
		}

	case *types.Tuple:
		if ,  := .(*types.Tuple);  {
			for  := 0;  < .Len(); ++ {
				if  >= .Len() || !.(.At().Type(), .At().Type(), ) {
					return false
				}
			}
			return .Len() == .Len()
		}

	case *types.Struct:
		if ,  := .(*types.Struct);  {
			for  := 0;  < .NumFields(); ++ {
				if  >= .NumFields() {
					return false
				}
				 := .Field()
				 := .Field()
				if .Anonymous() != .Anonymous() ||
					.Tag() != .Tag() ||
					!.(.Type(), .Type(), ) ||
					!.corrFieldNames(, ) {
					return false
				}
			}
			return .NumFields() == .NumFields()
		}

	case *types.Interface:
		if ,  := .(*types.Interface);  {
			// Deal with circularity. See the comment in types.Identical.
			 := &ifacePair{, , }
			for  != nil {
				if .identical() {
					return true // same pair was compared before
				}
				 = .prev
			}
			 := .sortedMethods()
			 := .sortedMethods()
			for ,  := range  {
				if  >= len() {
					return false
				}
				 := []
				if .methodID() != .methodID() || !.(.Type(), .Type(), ) {
					return false
				}
			}
			return .NumMethods() == .NumMethods()
		}

	case *types.Named:
		return .establishCorrespondence(, )

	case *types.TypeParam:
		if ,  := .(*types.TypeParam);  {
			if .Index() == .Index() {
				return true
			}
		}

	default:
		panic(fmt.Sprintf("unknown type kind %T", ))
	}
	return false
}

// Compare old and new field names. We are determining correspondence across packages,
// so just compare names, not packages. For an unexported, embedded field of named
// type (non-named embedded fields are possible with aliases), we check that the type
// names correspond. We check the types for correspondence before this is called, so
// we've established correspondence.
func ( *differ) (,  *types.Var) bool {
	if .Anonymous() && .Anonymous() && !.Exported() && !.Exported() {
		if ,  := .Type().(*types.Named);  {
			 := .Type().(*types.Named)
			return .establishCorrespondence(, )
		}
	}
	return .Name() == .Name()
}

// establishCorrespondence records and validates a correspondence between
// old and new.
//
// If this is the first type corresponding to old, it checks that the type
// declaration is compatible with old and records its correspondence.
// Otherwise, it checks that new is equivalent to the previously recorded
// type corresponding to old.
func ( *differ) ( *types.Named,  types.Type) bool {
	 := .Obj()
	// If there already is a corresponding new type for old, check that they
	// are the same.
	if  := .correspondMap.At();  != nil {
		return types.Identical(.(types.Type), )
	}
	// Attempt to establish a correspondence.
	// Assume the types don't correspond unless they have the same
	// ID, or are from the old and new packages, respectively.
	//
	// This is too conservative. For instance,
	//    [old] type A = q.B; [new] type A q.C
	// could be OK if in package q, B is an alias for C.
	// Or, using p as the name of the current old/new packages:
	//    [old] type A = q.B; [new] type A int
	// could be OK if in q,
	//    [old] type B int; [new] type B = p.A
	// In this case, p.A and q.B name the same type in both old and new worlds.
	// Note that this case doesn't imply circular package imports: it's possible
	// that in the old world, p imports q, but in the new, q imports p.
	//
	// However, if we didn't do something here, then we'd incorrectly allow cases
	// like the first one above in which q.B is not an alias for q.C
	//
	// What we should do is check that the old type, in the new world's package
	// of the same path, doesn't correspond to something other than the new type.
	// That is a bit hard, because there is no easy way to find a new package
	// matching an old one.
	switch new := .(type) {
	case *types.Named:
		 := 
		 := .Obj()
		 := .Obj()
		if .Pkg() != .old || .Pkg() != .new {
			// Compare the fully qualified names of the types.
			//
			// TODO(jba): when comparing modules, we should only look at the
			// paths relative to the module path, because the module paths may differ.
			// See cmd/gorelease/testdata/internalcompat.
			var ,  string
			if .Pkg() != nil {
				 = .Pkg().Path()
			}
			if .Pkg() != nil {
				 = .Pkg().Path()
			}
			return .Name() == .Name() &&  == 
		}
		// Two generic named types correspond if their type parameter lists correspond.
		// Since one or the other of those lists will be empty, it doesn't hurt
		// to check both.
		if isInstantiated() {
			if !isInstantiated() {
				// old is an instantiated type but new is not; they cannot correspond.
				return false
			}
			// Two instantiated types correspond if their origins correspond and
			// their type argument lists correspond.
			if !.correspond(.Origin(), .Origin()) {
				return false
			}
			if !.typeListsCorrespond(.TypeArgs(), .TypeArgs()) {
				return false
			}
		} else {
			if !.typeParamListsCorrespond(.TypeParams(), .TypeParams()) {
				return false
			}
		}
	case *types.Basic:
		if .Obj().Pkg() != .old {
			// A named type from a package other than old never corresponds to a basic type.
			return false
		}
	default:
		// Only named and basic types can correspond.
		return false
	}
	// If there is no correspondence, create one.
	.correspondMap.Set(, )
	// Check that the corresponding types are compatible.
	.checkCompatibleDefined(, , )
	return true
}

func ( *differ) (,  *types.TypeList) bool {
	if .Len() != .Len() {
		return false
	}
	for  := 0;  < .Len(); ++ {
		if !.correspond(.At(), .At()) {
			return false
		}
	}
	return true
}

// Two list of type parameters correspond if they are the same length, and
// the constraints of corresponding type parameters correspond.
func ( *differ) (,  *types.TypeParamList) bool {
	if .Len() != .Len() {
		return false
	}
	for  := 0;  < .Len(); ++ {
		if !.correspond(.At().Constraint(), .At().Constraint()) {
			return false
		}
	}
	return true
}

func ( *differ) ( *types.Interface) []*types.Func {
	 := make([]*types.Func, .NumMethods())
	for  := 0;  < .NumMethods(); ++ {
		[] = .Method()
	}
	sort.Slice(, func(,  int) bool { return .methodID([]) < .methodID([]) })
	return 
}

func ( *differ) ( *types.Func) string {
	// If the method belongs to one of the two packages being compared, use
	// just its name even if it's unexported. That lets us treat unexported names
	// from the old and new packages as equal.
	if .Pkg() == .old || .Pkg() == .new {
		return .Name()
	}
	return .Id()
}

// Copied from the go/types package:

// An ifacePair is a node in a stack of interface type pairs compared for identity.
type ifacePair struct {
	x, y *types.Interface
	prev *ifacePair
}

func ( *ifacePair) ( *ifacePair) bool {
	return .x == .x && .y == .y || .x == .y && .y == .x
}

// isInstantiated reports whether t is instantiated from a generic type.
func ( *types.Named) bool {
	return .Origin() != 
}