// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package types

import (
	
	
	
)

// A Type represents a type of Go.
// All types implement the Type interface.
type Type interface {
	// Underlying returns the underlying type of a type
	// w/o following forwarding chains. Only used by
	// client packages (here for backward-compatibility).
	Underlying() Type

	// String returns a string representation of a type.
	String() string
}

// BasicKind describes the kind of basic type.
type BasicKind int

const (
	Invalid BasicKind = iota // type is invalid

	// predeclared types
	Bool
	Int
	Int8
	Int16
	Int32
	Int64
	Uint
	Uint8
	Uint16
	Uint32
	Uint64
	Uintptr
	Float32
	Float64
	Complex64
	Complex128
	String
	UnsafePointer

	// types for untyped values
	UntypedBool
	UntypedInt
	UntypedRune
	UntypedFloat
	UntypedComplex
	UntypedString
	UntypedNil

	// aliases
	Byte = Uint8
	Rune = Int32
)

// BasicInfo is a set of flags describing properties of a basic type.
type BasicInfo int

// Properties of basic types.
const (
	IsBoolean BasicInfo = 1 << iota
	IsInteger
	IsUnsigned
	IsFloat
	IsComplex
	IsString
	IsUntyped

	IsOrdered   = IsInteger | IsFloat | IsString
	IsNumeric   = IsInteger | IsFloat | IsComplex
	IsConstType = IsBoolean | IsNumeric | IsString
)

// A Basic represents a basic type.
type Basic struct {
	kind BasicKind
	info BasicInfo
	name string
}

// Kind returns the kind of basic type b.
func ( *Basic) () BasicKind { return .kind }

// Info returns information about properties of basic type b.
func ( *Basic) () BasicInfo { return .info }

// Name returns the name of basic type b.
func ( *Basic) () string { return .name }

// An Array represents an array type.
type Array struct {
	len  int64
	elem Type
}

// NewArray returns a new array type for the given element type and length.
// A negative length indicates an unknown length.
func ( Type,  int64) *Array { return &Array{len: , elem: } }

// Len returns the length of array a.
// A negative result indicates an unknown length.
func ( *Array) () int64 { return .len }

// Elem returns element type of array a.
func ( *Array) () Type { return .elem }

// A Slice represents a slice type.
type Slice struct {
	elem Type
}

// NewSlice returns a new slice type for the given element type.
func ( Type) *Slice { return &Slice{elem: } }

// Elem returns the element type of slice s.
func ( *Slice) () Type { return .elem }

// A Struct represents a struct type.
type Struct struct {
	fields []*Var
	tags   []string // field tags; nil if there are no tags
}

// NewStruct returns a new struct with the given fields and corresponding field tags.
// If a field with index i has a tag, tags[i] must be that tag, but len(tags) may be
// only as long as required to hold the tag with the largest index i. Consequently,
// if no field has a tag, tags may be nil.
func ( []*Var,  []string) *Struct {
	var  objset
	for ,  := range  {
		if .name != "_" && .insert() != nil {
			panic("multiple fields with the same name")
		}
	}
	if len() > len() {
		panic("more tags than fields")
	}
	return &Struct{fields: , tags: }
}

// NumFields returns the number of fields in the struct (including blank and embedded fields).
func ( *Struct) () int { return len(.fields) }

// Field returns the i'th field for 0 <= i < NumFields().
func ( *Struct) ( int) *Var { return .fields[] }

// Tag returns the i'th field tag for 0 <= i < NumFields().
func ( *Struct) ( int) string {
	if  < len(.tags) {
		return .tags[]
	}
	return ""
}

// A Pointer represents a pointer type.
type Pointer struct {
	base Type // element type
}

// NewPointer returns a new pointer type for the given element (base) type.
func ( Type) *Pointer { return &Pointer{base: } }

// Elem returns the element type for the given pointer p.
func ( *Pointer) () Type { return .base }

// A Tuple represents an ordered list of variables; a nil *Tuple is a valid (empty) tuple.
// Tuples are used as components of signatures and to represent the type of multiple
// assignments; they are not first class types of Go.
type Tuple struct {
	vars []*Var
}

// NewTuple returns a new tuple for the given variables.
func ( ...*Var) *Tuple {
	if len() > 0 {
		return &Tuple{vars: }
	}
	// TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer;
	//           it's too subtle and causes problems.
	return nil
}

// Len returns the number variables of tuple t.
func ( *Tuple) () int {
	if  != nil {
		return len(.vars)
	}
	return 0
}

// At returns the i'th variable of tuple t.
func ( *Tuple) ( int) *Var { return .vars[] }

// A Signature represents a (non-builtin) function or method type.
// The receiver is ignored when comparing signatures for identity.
type Signature struct {
	// We need to keep the scope in Signature (rather than passing it around
	// and store it in the Func Object) because when type-checking a function
	// literal we call the general type checker which returns a general Type.
	// We then unpack the *Signature and use the scope for the literal body.
	rparams  []*TypeName // receiver type parameters from left to right, or nil
	tparams  []*TypeName // type parameters from left to right, or nil
	scope    *Scope      // function scope, present for package-local signatures
	recv     *Var        // nil if not a method
	params   *Tuple      // (incoming) parameters from left to right; or nil
	results  *Tuple      // (outgoing) results from left to right; or nil
	variadic bool        // true if the last parameter's type is of the form ...T (or string, for append built-in only)
}

// NewSignature returns a new function type for the given receiver, parameters,
// and results, either of which may be nil. If variadic is set, the function
// is variadic, it must have at least one parameter, and the last parameter
// must be of unnamed slice type.
func ( *Var, ,  *Tuple,  bool) *Signature {
	if  {
		 := .Len()
		if  == 0 {
			panic("types.NewSignature: variadic function must have at least one parameter")
		}
		if ,  := .At( - 1).typ.(*Slice); ! {
			panic("types.NewSignature: variadic parameter must be of unnamed slice type")
		}
	}
	return &Signature{recv: , params: , results: , variadic: }
}

// Recv returns the receiver of signature s (if a method), or nil if a
// function. It is ignored when comparing signatures for identity.
//
// For an abstract method, Recv returns the enclosing interface either
// as a *Named or an *Interface. Due to embedding, an interface may
// contain methods whose receiver type is a different interface.
func ( *Signature) () *Var { return .recv }

// _TParams returns the type parameters of signature s, or nil.
func ( *Signature) () []*TypeName { return .tparams }

// _SetTParams sets the type parameters of signature s.
func ( *Signature) ( []*TypeName) { .tparams =  }

// Params returns the parameters of signature s, or nil.
func ( *Signature) () *Tuple { return .params }

// Results returns the results of signature s, or nil.
func ( *Signature) () *Tuple { return .results }

// Variadic reports whether the signature s is variadic.
func ( *Signature) () bool { return .variadic }

// A _Sum represents a set of possible types.
// Sums are currently used to represent type lists of interfaces
// and thus the underlying types of type parameters; they are not
// first class types of Go.
type _Sum struct {
	types []Type // types are unique
}

// _NewSum returns a new Sum type consisting of the provided
// types if there are more than one. If there is exactly one
// type, it returns that type. If the list of types is empty
// the result is nil.
func _NewSum( []Type) Type {
	if len() == 0 {
		return nil
	}

	// What should happen if types contains a sum type?
	// Do we flatten the types list? For now we check
	// and panic. This should not be possible for the
	// current use case of type lists.
	// TODO(gri) Come up with the rules for sum types.
	for ,  := range  {
		if ,  := .(*_Sum);  {
			panic("sum type contains sum type - unimplemented")
		}
	}

	if len() == 1 {
		return [0]
	}
	return &_Sum{types: }
}

// is reports whether all types in t satisfy pred.
func ( *_Sum) ( func(Type) bool) bool {
	if  == nil {
		return false
	}
	for ,  := range .types {
		if !() {
			return false
		}
	}
	return true
}

// An Interface represents an interface type.
type Interface struct {
	methods   []*Func // ordered list of explicitly declared methods
	types     Type    // (possibly a Sum) type declared with a type list (TODO(gri) need better field name)
	embeddeds []Type  // ordered list of explicitly embedded types

	allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset)
	allTypes   Type    // intersection of all embedded and locally declared types  (TODO(gri) need better field name)

	obj Object // type declaration defining this interface; or nil (for better error messages)
}

// unpack unpacks a type into a list of types.
// TODO(gri) Try to eliminate the need for this function.
func unpackType( Type) []Type {
	if  == nil {
		return nil
	}
	if  := asSum();  != nil {
		return .types
	}
	return []Type{}
}

// is reports whether interface t represents types that all satisfy pred.
func ( *Interface) ( func(Type) bool) bool {
	if .allTypes == nil {
		return false // we must have at least one type! (was bug)
	}
	for ,  := range unpackType(.allTypes) {
		if !() {
			return false
		}
	}
	return true
}

// emptyInterface represents the empty (completed) interface
var emptyInterface = Interface{allMethods: markComplete}

// markComplete is used to mark an empty interface as completely
// set up by setting the allMethods field to a non-nil empty slice.
var markComplete = make([]*Func, 0)

// NewInterface returns a new (incomplete) interface for the given methods and embedded types.
// Each embedded type must have an underlying type of interface type.
// NewInterface takes ownership of the provided methods and may modify their types by setting
// missing receivers. To compute the method set of the interface, Complete must be called.
//
// Deprecated: Use NewInterfaceType instead which allows any (even non-defined) interface types
// to be embedded. This is necessary for interfaces that embed alias type names referring to
// non-defined (literal) interface types.
func ( []*Func,  []*Named) *Interface {
	 := make([]Type, len())
	for ,  := range  {
		[] = 
	}
	return NewInterfaceType(, )
}

// NewInterfaceType returns a new (incomplete) interface for the given methods and embedded types.
// Each embedded type must have an underlying type of interface type (this property is not
// verified for defined types, which may be in the process of being set up and which don't
// have a valid underlying type yet).
// NewInterfaceType takes ownership of the provided methods and may modify their types by setting
// missing receivers. To compute the method set of the interface, Complete must be called.
func ( []*Func,  []Type) *Interface {
	if len() == 0 && len() == 0 {
		return &emptyInterface
	}

	// set method receivers if necessary
	 := new(Interface)
	for ,  := range  {
		if  := .typ.(*Signature); .recv == nil {
			.recv = NewVar(.pos, .pkg, "", )
		}
	}

	// All embedded types should be interfaces; however, defined types
	// may not yet be fully resolved. Only verify that non-defined types
	// are interfaces. This matches the behavior of the code before the
	// fix for #25301 (issue #25596).
	for ,  := range  {
		if ,  := .(*Named); ! && !IsInterface() {
			panic("embedded type is not an interface")
		}
	}

	// sort for API stability
	sortMethods()
	sortTypes()

	.methods = 
	.embeddeds = 
	return 
}

// NumExplicitMethods returns the number of explicitly declared methods of interface t.
func ( *Interface) () int { return len(.methods) }

// ExplicitMethod returns the i'th explicitly declared method of interface t for 0 <= i < t.NumExplicitMethods().
// The methods are ordered by their unique Id.
func ( *Interface) ( int) *Func { return .methods[] }

// NumEmbeddeds returns the number of embedded types in interface t.
func ( *Interface) () int { return len(.embeddeds) }

// Embedded returns the i'th embedded defined (*Named) type of interface t for 0 <= i < t.NumEmbeddeds().
// The result is nil if the i'th embedded type is not a defined type.
//
// Deprecated: Use EmbeddedType which is not restricted to defined (*Named) types.
func ( *Interface) ( int) *Named { ,  := .embeddeds[].(*Named); return  }

// EmbeddedType returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds().
func ( *Interface) ( int) Type { return .embeddeds[] }

// NumMethods returns the total number of methods of interface t.
// The interface must have been completed.
func ( *Interface) () int { .assertCompleteness(); return len(.allMethods) }

func ( *Interface) () {
	if .allMethods == nil {
		panic("interface is incomplete")
	}
}

// Method returns the i'th method of interface t for 0 <= i < t.NumMethods().
// The methods are ordered by their unique Id.
// The interface must have been completed.
func ( *Interface) ( int) *Func { .assertCompleteness(); return .allMethods[] }

// Empty reports whether t is the empty interface.
func ( *Interface) () bool {
	if .allMethods != nil {
		// interface is complete - quick test
		// A non-nil allTypes may still be empty and represents the bottom type.
		return len(.allMethods) == 0 && .allTypes == nil
	}
	return !.iterate(func( *Interface) bool {
		return len(.methods) > 0 || .types != nil
	}, nil)
}

// _HasTypeList reports whether interface t has a type list, possibly from an embedded type.
func ( *Interface) () bool {
	if .allMethods != nil {
		// interface is complete - quick test
		return .allTypes != nil
	}

	return .iterate(func( *Interface) bool {
		return .types != nil
	}, nil)
}

// _IsComparable reports whether interface t is or embeds the predeclared interface "comparable".
func ( *Interface) () bool {
	if .allMethods != nil {
		// interface is complete - quick test
		,  := lookupMethod(.allMethods, nil, "==")
		return  != nil
	}

	return .iterate(func( *Interface) bool {
		,  := lookupMethod(.methods, nil, "==")
		return  != nil
	}, nil)
}

// _IsConstraint reports t.HasTypeList() || t.IsComparable().
func ( *Interface) () bool {
	if .allMethods != nil {
		// interface is complete - quick test
		if .allTypes != nil {
			return true
		}
		,  := lookupMethod(.allMethods, nil, "==")
		return  != nil
	}

	return .iterate(func( *Interface) bool {
		if .types != nil {
			return true
		}
		,  := lookupMethod(.methods, nil, "==")
		return  != nil
	}, nil)
}

// iterate calls f with t and then with any embedded interface of t, recursively, until f returns true.
// iterate reports whether any call to f returned true.
func ( *Interface) ( func(*Interface) bool,  map[*Interface]bool) bool {
	if () {
		return true
	}
	for ,  := range .embeddeds {
		// e should be an interface but be careful (it may be invalid)
		if  := asInterface();  != nil {
			// Cyclic interfaces such as "type E interface { E }" are not permitted
			// but they are still constructed and we need to detect such cycles.
			if [] {
				continue
			}
			if  == nil {
				 = make(map[*Interface]bool)
			}
			[] = true
			if .(, ) {
				return true
			}
		}
	}
	return false
}

// isSatisfiedBy reports whether interface t's type list is satisfied by the type typ.
// If the type list is empty (absent), typ trivially satisfies the interface.
// TODO(gri) This is not a great name. Eventually, we should have a more comprehensive
//           "implements" predicate.
func ( *Interface) ( Type) bool {
	.Complete()
	if .allTypes == nil {
		return true
	}
	 := unpackType(.allTypes)
	return includes(, ) || includes(, under())
}

// Complete computes the interface's method set. It must be called by users of
// NewInterfaceType and NewInterface after the interface's embedded types are
// fully defined and before using the interface type in any way other than to
// form other types. The interface must not contain duplicate methods or a
// panic occurs. Complete returns the receiver.
func ( *Interface) () *Interface {
	// TODO(gri) consolidate this method with Checker.completeInterface
	if .allMethods != nil {
		return 
	}

	.allMethods = markComplete // avoid infinite recursion

	var  []*Func
	var  []*Func
	var  objset
	 := func( *Func,  bool) {
		switch  := .insert(); {
		case  == nil:
			 = append(, )
		case :
			panic("duplicate method " + .name)
		default:
			// check method signatures after all locally embedded interfaces are computed
			 = append(, , .(*Func))
		}
	}

	for ,  := range .methods {
		(, true)
	}

	 := .types

	for ,  := range .embeddeds {
		 := under()
		 := asInterface()
		if  == nil {
			if  != Typ[Invalid] {
				panic(fmt.Sprintf("%s is not an interface", ))
			}
			continue
		}
		.()
		for ,  := range .allMethods {
			(, false)
		}
		 = intersect(, .allTypes)
	}

	for  := 0;  < len();  += 2 {
		 := []
		 := [+1]
		if !Identical(.typ, .typ) {
			panic("duplicate method " + .name)
		}
	}

	if  != nil {
		sortMethods()
		.allMethods = 
	}
	.allTypes = 

	return 
}

// A Map represents a map type.
type Map struct {
	key, elem Type
}

// NewMap returns a new map for the given key and element types.
func (,  Type) *Map {
	return &Map{key: , elem: }
}

// Key returns the key type of map m.
func ( *Map) () Type { return .key }

// Elem returns the element type of map m.
func ( *Map) () Type { return .elem }

// A Chan represents a channel type.
type Chan struct {
	dir  ChanDir
	elem Type
}

// A ChanDir value indicates a channel direction.
type ChanDir int

// The direction of a channel is indicated by one of these constants.
const (
	SendRecv ChanDir = iota
	SendOnly
	RecvOnly
)

// NewChan returns a new channel type for the given direction and element type.
func ( ChanDir,  Type) *Chan {
	return &Chan{dir: , elem: }
}

// Dir returns the direction of channel c.
func ( *Chan) () ChanDir { return .dir }

// Elem returns the element type of channel c.
func ( *Chan) () Type { return .elem }

// A Named represents a named (defined) type.
type Named struct {
	check      *Checker    // for Named.under implementation; nilled once under has been called
	info       typeInfo    // for cycle detection
	obj        *TypeName   // corresponding declared object
	orig       Type        // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
	underlying Type        // possibly a *Named during setup; never a *Named once set up completely
	tparams    []*TypeName // type parameters, or nil
	targs      []Type      // type arguments (after instantiation), or nil
	methods    []*Func     // methods declared for this type (not the method set of this type); signatures are type-checked lazily
}

// NewNamed returns a new named type for the given type name, underlying type, and associated methods.
// If the given type name obj doesn't have a type yet, its type is set to the returned named type.
// The underlying type must not be a *Named.
func ( *TypeName,  Type,  []*Func) *Named {
	if ,  := .(*Named);  {
		panic("types.NewNamed: underlying type must not be *Named")
	}
	return (*Checker)(nil).newNamed(, , )
}

func ( *Checker) ( *TypeName,  Type,  []*Func) *Named {
	 := &Named{check: , obj: , orig: , underlying: , methods: }
	if .typ == nil {
		.typ = 
	}
	// Ensure that typ is always expanded, at which point the check field can be
	// nilled out.
	//
	// Note that currently we cannot nil out check inside typ.under(), because
	// it's possible that typ is expanded multiple times.
	//
	// TODO(rFindley): clean this up so that under is the only function mutating
	//                 named types.
	if  != nil {
		.later(func() {
			switch .under().(type) {
			case *Named, *instance:
				panic("internal error: unexpanded underlying type")
			}
			.check = nil
		})
	}
	return 
}

// Obj returns the type name for the named type t.
func ( *Named) () *TypeName { return .obj }

// TODO(gri) Come up with a better representation and API to distinguish
//           between parameterized instantiated and non-instantiated types.

// _TParams returns the type parameters of the named type t, or nil.
// The result is non-nil for an (originally) parameterized type even if it is instantiated.
func ( *Named) () []*TypeName { return .tparams }

// _TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated.
func ( *Named) () []Type { return .targs }

// _SetTArgs sets the type arguments of Named.
func ( *Named) ( []Type) { .targs =  }

// NumMethods returns the number of explicit methods whose receiver is named type t.
func ( *Named) () int { return len(.methods) }

// Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
func ( *Named) ( int) *Func { return .methods[] }

// SetUnderlying sets the underlying type and marks t as complete.
func ( *Named) ( Type) {
	if  == nil {
		panic("types.Named.SetUnderlying: underlying type must not be nil")
	}
	if ,  := .(*Named);  {
		panic("types.Named.SetUnderlying: underlying type must not be *Named")
	}
	.underlying = 
}

// AddMethod adds method m unless it is already in the method list.
func ( *Named) ( *Func) {
	if ,  := lookupMethod(.methods, .pkg, .name);  < 0 {
		.methods = append(.methods, )
	}
}

// Note: This is a uint32 rather than a uint64 because the
// respective 64 bit atomic instructions are not available
// on all platforms.
var lastId uint32

// nextId returns a value increasing monotonically by 1 with
// each call, starting with 1. It may be called concurrently.
func nextId() uint64 { return uint64(atomic.AddUint32(&lastId, 1)) }

// A _TypeParam represents a type parameter type.
type _TypeParam struct {
	check *Checker  // for lazy type bound completion
	id    uint64    // unique id
	obj   *TypeName // corresponding type name
	index int       // parameter index
	bound Type      // *Named or *Interface; underlying type is always *Interface
}

// newTypeParam returns a new TypeParam.
func ( *Checker) ( *TypeName,  int,  Type) *_TypeParam {
	assert( != nil)
	 := &_TypeParam{check: , id: nextId(), obj: , index: , bound: }
	if .typ == nil {
		.typ = 
	}
	return 
}

func ( *_TypeParam) () *Interface {
	 := asInterface(.bound)
	// use the type bound position if we have one
	 := token.NoPos
	if ,  := .bound.(*Named);  != nil {
		 = .obj.pos
	}
	// TODO(rFindley) switch this to an unexported method on Checker.
	.check.completeInterface(, )
	return 
}

// optype returns a type's operational type. Except for
// type parameters, the operational type is the same
// as the underlying type (as returned by under). For
// Type parameters, the operational type is determined
// by the corresponding type bound's type list. The
// result may be the bottom or top type, but it is never
// the incoming type parameter.
func optype( Type) Type {
	if  := asTypeParam();  != nil {
		// If the optype is typ, return the top type as we have
		// no information. It also prevents infinite recursion
		// via the asTypeParam converter function. This can happen
		// for a type parameter list of the form:
		// (type T interface { type T }).
		// See also issue #39680.
		if  := .Bound().allTypes;  != nil &&  !=  {
			// u != typ and u is a type parameter => under(u) != typ, so this is ok
			return under()
		}
		return theTop
	}
	return under()
}

// An instance represents an instantiated generic type syntactically
// (without expanding the instantiation). Type instances appear only
// during type-checking and are replaced by their fully instantiated
// (expanded) types before the end of type-checking.
type instance struct {
	check   *Checker    // for lazy instantiation
	pos     token.Pos   // position of type instantiation; for error reporting only
	base    *Named      // parameterized type to be instantiated
	targs   []Type      // type arguments
	poslist []token.Pos // position of each targ; for error reporting only
	value   Type        // base(targs...) after instantiation or Typ[Invalid]; nil if not yet set
}

// expand returns the instantiated (= expanded) type of t.
// The result is either an instantiated *Named type, or
// Typ[Invalid] if there was an error.
func ( *instance) () Type {
	 := .value
	if  == nil {
		 = .check.instantiate(.pos, .base, .targs, .poslist)
		if  == nil {
			 = Typ[Invalid]
		}
		.value = 
	}
	// After instantiation we must have an invalid or a *Named type.
	if debug &&  != Typ[Invalid] {
		_ = .(*Named)
	}
	return 
}

// expand expands a type instance into its instantiated
// type and leaves all other types alone. expand does
// not recurse.
func expand( Type) Type {
	if ,  := .(*instance);  != nil {
		return .expand()
	}
	return 
}

// expandf is set to expand.
// Call expandf when calling expand causes compile-time cycle error.
var expandf func(Type) Type

func init() { expandf = expand }

// bottom represents the bottom of the type lattice.
// It is the underlying type of a type parameter that
// cannot be satisfied by any type, usually because
// the intersection of type constraints left nothing).
type bottom struct{}

// theBottom is the singleton bottom type.
var theBottom = &bottom{}

// top represents the top of the type lattice.
// It is the underlying type of a type parameter that
// can be satisfied by any type (ignoring methods),
// usually because the type constraint has no type
// list.
type top struct{}

// theTop is the singleton top type.
var theTop = &top{}

// Type-specific implementations of Underlying.
func ( *Basic) () Type      { return  }
func ( *Array) () Type      { return  }
func ( *Slice) () Type      { return  }
func ( *Struct) () Type     { return  }
func ( *Pointer) () Type    { return  }
func ( *Tuple) () Type      { return  }
func ( *Signature) () Type  { return  }
func ( *_Sum) () Type       { return  }
func ( *Interface) () Type  { return  }
func ( *Map) () Type        { return  }
func ( *Chan) () Type       { return  }
func ( *Named) () Type      { return .underlying }
func ( *_TypeParam) () Type { return  }
func ( *instance) () Type   { return  }
func ( *bottom) () Type     { return  }
func ( *top) () Type        { return  }

// Type-specific implementations of String.
func ( *Basic) () string      { return TypeString(, nil) }
func ( *Array) () string      { return TypeString(, nil) }
func ( *Slice) () string      { return TypeString(, nil) }
func ( *Struct) () string     { return TypeString(, nil) }
func ( *Pointer) () string    { return TypeString(, nil) }
func ( *Tuple) () string      { return TypeString(, nil) }
func ( *Signature) () string  { return TypeString(, nil) }
func ( *_Sum) () string       { return TypeString(, nil) }
func ( *Interface) () string  { return TypeString(, nil) }
func ( *Map) () string        { return TypeString(, nil) }
func ( *Chan) () string       { return TypeString(, nil) }
func ( *Named) () string      { return TypeString(, nil) }
func ( *_TypeParam) () string { return TypeString(, nil) }
func ( *instance) () string   { return TypeString(, nil) }
func ( *bottom) () string     { return TypeString(, nil) }
func ( *top) () string        { return TypeString(, nil) }

// under returns the true expanded underlying type.
// If it doesn't exist, the result is Typ[Invalid].
// under must only be called when a type is known
// to be fully set up.
func under( Type) Type {
	// TODO(gri) is this correct for *Sum?
	if  := asNamed();  != nil {
		return .under()
	}
	return 
}

// Converters
//
// A converter must only be called when a type is
// known to be fully set up. A converter returns
// a type's operational type (see comment for optype)
// or nil if the type argument is not of the
// respective type.

func asBasic( Type) *Basic {
	,  := optype().(*Basic)
	return 
}

func asArray( Type) *Array {
	,  := optype().(*Array)
	return 
}

func asSlice( Type) *Slice {
	,  := optype().(*Slice)
	return 
}

func asStruct( Type) *Struct {
	,  := optype().(*Struct)
	return 
}

func asPointer( Type) *Pointer {
	,  := optype().(*Pointer)
	return 
}

func asTuple( Type) *Tuple {
	,  := optype().(*Tuple)
	return 
}

func asSignature( Type) *Signature {
	,  := optype().(*Signature)
	return 
}

func asSum( Type) *_Sum {
	,  := optype().(*_Sum)
	return 
}

func asInterface( Type) *Interface {
	,  := optype().(*Interface)
	return 
}

func asMap( Type) *Map {
	,  := optype().(*Map)
	return 
}

func asChan( Type) *Chan {
	,  := optype().(*Chan)
	return 
}

// If the argument to asNamed and asTypeParam is of the respective types
// (possibly after expanding an instance type), these methods return that type.
// Otherwise the result is nil.

func asNamed( Type) *Named {
	,  := expand().(*Named)
	return 
}

func asTypeParam( Type) *_TypeParam {
	,  := under().(*_TypeParam)
	return 
}