blob: 85d244cf04a5f2a8eca56db25d011330da6ce00f [file] [log] [blame]
// 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 declares the types used to represent Go types
package types
import (
// All types implement the Type interface.
type Type interface {
// All concrete types embed ImplementsType which
// ensures that all types implement the Type interface.
type ImplementsType struct{}
func (t *ImplementsType) isType() {}
// A Bad type is a non-nil placeholder type when we don't know a type.
type Bad struct {
Msg string // for better error reporting/debugging
// A Basic represents a (unnamed) basic type.
type Basic struct {
// TODO(gri) need a field specifying the exact basic type
// An Array represents an array type [Len]Elt.
type Array struct {
Len uint64
Elt Type
// A Slice represents a slice type []Elt.
type Slice struct {
Elt Type
// A Struct represents a struct type struct{...}.
// Anonymous fields are represented by objects with empty names.
type Struct struct {
Fields ObjList // struct fields; or nil
Tags []string // corresponding tags; or nil
// TODO(gri) This type needs some rethinking:
// - at the moment anonymous fields are marked with "" object names,
// and their names have to be reconstructed
// - there is no scope for fast lookup (but the parser creates one)
// A Pointer represents a pointer type *Base.
type Pointer struct {
Base Type
// A Func represents a function type func(...) (...).
// Unnamed parameters are represented by objects with empty names.
type Func struct {
Recv *ast.Object // nil if not a method
Params ObjList // (incoming) parameters from left to right; or nil
Results ObjList // (outgoing) results from left to right; or nil
IsVariadic bool // true if the last parameter's type is of the form ...T
// An Interface represents an interface type interface{...}.
type Interface struct {
Methods ObjList // interface methods sorted by name; or nil
// A Map represents a map type map[Key]Elt.
type Map struct {
Key, Elt Type
// A Chan represents a channel type chan Elt, <-chan Elt, or chan<-Elt.
type Chan struct {
Dir ast.ChanDir
Elt Type
// A Name represents a named type as declared in a type declaration.
type Name struct {
Underlying Type // nil if not fully declared
Obj *ast.Object // corresponding declared object
// TODO(gri) need to remember fields and methods.
// If typ is a pointer type, Deref returns the pointer's base type;
// otherwise it returns typ.
func Deref(typ Type) Type {
if typ, ok := typ.(*Pointer); ok {
return typ.Base
return typ
// Underlying returns the underlying type of a type.
func Underlying(typ Type) Type {
if typ, ok := typ.(*Name); ok {
utyp := typ.Underlying
if _, ok := utyp.(*Basic); !ok {
return utyp
// the underlying type of a type name referring
// to an (untyped) basic type is the basic type
// name
return typ
// An ObjList represents an ordered (in some fashion) list of objects.
type ObjList []*ast.Object
// ObjList implements sort.Interface.
func (list ObjList) Len() int { return len(list) }
func (list ObjList) Less(i, j int) bool { return list[i].Name < list[j].Name }
func (list ObjList) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
// Sort sorts an object list by object name.
func (list ObjList) Sort() { sort.Sort(list) }
// identicalTypes returns true if both lists a and b have the
// same length and corresponding objects have identical types.
func identicalTypes(a, b ObjList) bool {
if len(a) == len(b) {
for i, x := range a {
y := b[i]
if !Identical(x.Type.(Type), y.Type.(Type)) {
return false
return true
return false
// Identical returns true if two types are identical.
func Identical(x, y Type) bool {
if x == y {
return true
switch x := x.(type) {
case *Bad:
// A Bad type is always identical to any other type
// (to avoid spurious follow-up errors).
return true
case *Basic:
if y, ok := y.(*Basic); ok {
_ = y
case *Array:
// Two array types are identical if they have identical element types
// and the same array length.
if y, ok := y.(*Array); ok {
return x.Len == y.Len && Identical(x.Elt, y.Elt)
case *Slice:
// Two slice types are identical if they have identical element types.
if y, ok := y.(*Slice); ok {
return Identical(x.Elt, y.Elt)
case *Struct:
// Two struct types are identical if they have the same sequence of fields,
// and if corresponding fields have the same names, and identical types,
// and identical tags. Two anonymous fields are considered to have the same
// name. Lower-case field names from different packages are always different.
if y, ok := y.(*Struct); ok {
// TODO(gri) handle structs from different packages
if identicalTypes(x.Fields, y.Fields) {
for i, f := range x.Fields {
g := y.Fields[i]
if f.Name != g.Name || x.Tags[i] != y.Tags[i] {
return false
return true
case *Pointer:
// Two pointer types are identical if they have identical base types.
if y, ok := y.(*Pointer); ok {
return Identical(x.Base, y.Base)
case *Func:
// Two function types are identical if they have the same number of parameters
// and result values, corresponding parameter and result types are identical,
// and either both functions are variadic or neither is. Parameter and result
// names are not required to match.
if y, ok := y.(*Func); ok {
return identicalTypes(x.Params, y.Params) &&
identicalTypes(x.Results, y.Results) &&
x.IsVariadic == y.IsVariadic
case *Interface:
// Two interface types are identical if they have the same set of methods with
// the same names and identical function types. Lower-case method names from
// different packages are always different. The order of the methods is irrelevant.
if y, ok := y.(*Interface); ok {
return identicalTypes(x.Methods, y.Methods) // methods are sorted
case *Map:
// Two map types are identical if they have identical key and value types.
if y, ok := y.(*Map); ok {
return Identical(x.Key, y.Key) && Identical(x.Elt, y.Elt)
case *Chan:
// Two channel types are identical if they have identical value types
// and the same direction.
if y, ok := y.(*Chan); ok {
return x.Dir == y.Dir && Identical(x.Elt, y.Elt)
case *Name:
// Two named types are identical if their type names originate
// in the same type declaration.
if y, ok := y.(*Name); ok {
return x.Obj == y.Obj ||
// permit bad objects to be equal to avoid
// follow up errors
x.Obj != nil && x.Obj.Kind == ast.Bad ||
y.Obj != nil && y.Obj.Kind == ast.Bad
return false