func defaultType(typ Type) Type {
	if t, ok := typ.(*Basic); ok {
		switch t.kind {
		case UntypedBool:
			return Typ[Bool]
		case UntypedInt:
			return Typ[Int]
		case UntypedRune:
			return UniverseRune  
		case UntypedFloat:
			return Typ[Float64]
		case UntypedComplex:
			return Typ[Complex128]
		case UntypedString:
			return Typ[String]
		}
	}
	return typ
}
defaultType returns the default "typed" type for an "untyped" type;
it returns the incoming type for all other types. The default type
for untyped nil is untyped nil.
package types
import "sort"
func isNamed(typ Type) bool {
	if _, ok := typ.(*Basic); ok {
		return ok
	}
	_, ok := typ.(*Named)
	return ok
}
func isBoolean(typ Type) bool {
	t, ok := typ.Underlying().(*Basic)
	return ok && t.info&IsBoolean != 0
}
func isInteger(typ Type) bool {
	t, ok := typ.Underlying().(*Basic)
	return ok && t.info&IsInteger != 0
}
func isUnsigned(typ Type) bool {
	t, ok := typ.Underlying().(*Basic)
	return ok && t.info&IsUnsigned != 0
}
func isFloat(typ Type) bool {
	t, ok := typ.Underlying().(*Basic)
	return ok && t.info&IsFloat != 0
}
func isComplex(typ Type) bool {
	t, ok := typ.Underlying().(*Basic)
	return ok && t.info&IsComplex != 0
}
func isNumeric(typ Type) bool {
	t, ok := typ.Underlying().(*Basic)
	return ok && t.info&IsNumeric != 0
}
func isString(typ Type) bool {
	t, ok := typ.Underlying().(*Basic)
	return ok && t.info&IsString != 0
}
func isTyped(typ Type) bool {
	t, ok := typ.Underlying().(*Basic)
	return !ok || t.info&IsUntyped == 0
}
func isUntyped(typ Type) bool {
	t, ok := typ.Underlying().(*Basic)
	return ok && t.info&IsUntyped != 0
}
func isOrdered(typ Type) bool {
	t, ok := typ.Underlying().(*Basic)
	return ok && t.info&IsOrdered != 0
}
func isConstType(typ Type) bool {
	t, ok := typ.Underlying().(*Basic)
	return ok && t.info&IsConstType != 0
}
func isInterface(typ Type) bool {
	_, ok := typ.Underlying().(*Interface)
	return ok
}
func Comparable(T Type) bool {
	switch t := T.Underlying().(type) {
	case *Basic:
		return t.kind != UntypedNil
	case *Pointer, *Interface, *Chan:
		return true
	case *Struct:
		for _, f := range t.fields {
			if !Comparable(f.typ) {
				return false
			}
		}
		return true
	case *Array:
		return Comparable(t.elem)
	}
	return false
}
func hasNil(typ Type) bool {
	switch t := typ.Underlying().(type) {
	case *Basic:
		return t.kind == UnsafePointer
	case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
		return true
	}
	return false
}
func Identical(x, y Type) bool {
	return identical(x, y, nil)
}
type ifacePair struct {
	x, y *Interface
	prev *ifacePair
}
func (p *ifacePair) identical(q *ifacePair) bool {
	return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
}
func identical(x, y Type, p *ifacePair) bool {
	if x == y {
		return true
	}
	switch x := x.(type) {
	case *Basic:
		if y, ok := y.(*Basic); ok {
			return x.kind == y.kind
		}
	case *Array:
		if y, ok := y.(*Array); ok {
			return x.len == y.len && identical(x.elem, y.elem, p)
		}
	case *Slice:
		if y, ok := y.(*Slice); ok {
			return identical(x.elem, y.elem, p)
		}
	case *Struct:
		if y, ok := y.(*Struct); ok {
			if x.NumFields() == y.NumFields() {
				for i, f := range x.fields {
					g := y.fields[i]
					if f.anonymous != g.anonymous ||
						x.Tag(i) != y.Tag(i) ||
						!f.sameId(g.pkg, g.name) ||
						!identical(f.typ, g.typ, p) {
						return false
					}
				}
				return true
			}
		}
	case *Pointer:
		if y, ok := y.(*Pointer); ok {
			return identical(x.base, y.base, p)
		}
	case *Tuple:
		if y, ok := y.(*Tuple); ok {
			if x.Len() == y.Len() {
				if x != nil {
					for i, v := range x.vars {
						w := y.vars[i]
						if !identical(v.typ, w.typ, p) {
							return false
						}
					}
				}
				return true
			}
		}
	case *Signature:
		if y, ok := y.(*Signature); ok {
			return x.variadic == y.variadic &&
				identical(x.params, y.params, p) &&
				identical(x.results, y.results, p)
		}
	case *Interface:
		if y, ok := y.(*Interface); ok {
			a := x.allMethods
			b := y.allMethods
			if len(a) == len(b) {
				q := &ifacePair{x, y, p}
				for p != nil {
					if p.identical(q) {
						return true  
					}
					p = p.prev
				}
				if debug {
					assert(sort.IsSorted(byUniqueMethodName(a)))
					assert(sort.IsSorted(byUniqueMethodName(b)))
				}
				for i, f := range a {
					g := b[i]
					if f.Id() != g.Id() || !identical(f.typ, g.typ, q) {
						return false
					}
				}
				return true
			}
		}
	case *Map:
		if y, ok := y.(*Map); ok {
			return identical(x.key, y.key, p) && identical(x.elem, y.elem, p)
		}
	case *Chan:
		if y, ok := y.(*Chan); ok {
			return x.dir == y.dir && identical(x.elem, y.elem, p)
		}
	case *Named:
		if y, ok := y.(*Named); ok {
			return x.obj == y.obj
		}
	default:
		unreachable()
	}
	return false
}