mirror of
https://github.com/golang/go
synced 2024-11-26 06:38:00 -07:00
[dev.typeparams] go/types: move (remaining) type decls into their own files (cleanup)
This is a port of CL 332093 to go/types. A missing comment is added to named.go, and some TODOs were added to converge on the TypeParam API. Change-Id: I781a1d0d3fc6c11bb323123e954c106094d998ef Reviewed-on: https://go-review.googlesource.com/c/go/+/335040 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
624d152db7
commit
521828091c
25
src/go/types/array.go
Normal file
25
src/go/types/array.go
Normal file
@ -0,0 +1,25 @@
|
||||
// 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
|
||||
|
||||
// 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 NewArray(elem Type, len int64) *Array { return &Array{len: len, elem: elem} }
|
||||
|
||||
// Len returns the length of array a.
|
||||
// A negative result indicates an unknown length.
|
||||
func (a *Array) Len() int64 { return a.len }
|
||||
|
||||
// Elem returns element type of array a.
|
||||
func (a *Array) Elem() Type { return a.elem }
|
||||
|
||||
func (t *Array) Underlying() Type { return t }
|
||||
func (t *Array) String() string { return TypeString(t, nil) }
|
82
src/go/types/basic.go
Normal file
82
src/go/types/basic.go
Normal file
@ -0,0 +1,82 @@
|
||||
// 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
|
||||
|
||||
// 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 (b *Basic) Kind() BasicKind { return b.kind }
|
||||
|
||||
// Info returns information about properties of basic type b.
|
||||
func (b *Basic) Info() BasicInfo { return b.info }
|
||||
|
||||
// Name returns the name of basic type b.
|
||||
func (b *Basic) Name() string { return b.name }
|
||||
|
||||
func (t *Basic) Underlying() Type { return t }
|
||||
func (t *Basic) String() string { return TypeString(t, nil) }
|
35
src/go/types/chan.go
Normal file
35
src/go/types/chan.go
Normal file
@ -0,0 +1,35 @@
|
||||
// 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
|
||||
|
||||
// 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 NewChan(dir ChanDir, elem Type) *Chan {
|
||||
return &Chan{dir: dir, elem: elem}
|
||||
}
|
||||
|
||||
// Dir returns the direction of channel c.
|
||||
func (c *Chan) Dir() ChanDir { return c.dir }
|
||||
|
||||
// Elem returns the element type of channel c.
|
||||
func (c *Chan) Elem() Type { return c.elem }
|
||||
|
||||
func (t *Chan) Underlying() Type { return t }
|
||||
func (t *Chan) String() string { return TypeString(t, nil) }
|
58
src/go/types/instance.go
Normal file
58
src/go/types/instance.go
Normal file
@ -0,0 +1,58 @@
|
||||
// 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 "go/token"
|
||||
|
||||
// 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 (t *instance) expand() Type {
|
||||
v := t.value
|
||||
if v == nil {
|
||||
v = t.check.instantiate(t.pos, t.base, t.targs, t.poslist)
|
||||
if v == nil {
|
||||
v = Typ[Invalid]
|
||||
}
|
||||
t.value = v
|
||||
}
|
||||
// After instantiation we must have an invalid or a *Named type.
|
||||
if debug && v != Typ[Invalid] {
|
||||
_ = v.(*Named)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// expand expands a type instance into its instantiated
|
||||
// type and leaves all other types alone. expand does
|
||||
// not recurse.
|
||||
func expand(typ Type) Type {
|
||||
if t, _ := typ.(*instance); t != nil {
|
||||
return t.expand()
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// expandf is set to expand.
|
||||
// Call expandf when calling expand causes compile-time cycle error.
|
||||
var expandf func(Type) Type
|
||||
|
||||
func init() { expandf = expand }
|
||||
|
||||
func (t *instance) Underlying() Type { return t }
|
||||
func (t *instance) String() string { return TypeString(t, nil) }
|
24
src/go/types/map.go
Normal file
24
src/go/types/map.go
Normal file
@ -0,0 +1,24 @@
|
||||
// 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
|
||||
|
||||
// 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 NewMap(key, elem Type) *Map {
|
||||
return &Map{key: key, elem: elem}
|
||||
}
|
||||
|
||||
// Key returns the key type of map m.
|
||||
func (m *Map) Key() Type { return m.key }
|
||||
|
||||
// Elem returns the element type of map m.
|
||||
func (m *Map) Elem() Type { return m.elem }
|
||||
|
||||
func (t *Map) Underlying() Type { return t }
|
||||
func (t *Map) String() string { return TypeString(t, nil) }
|
144
src/go/types/named.go
Normal file
144
src/go/types/named.go
Normal file
@ -0,0 +1,144 @@
|
||||
// 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 "sync"
|
||||
|
||||
// TODO(rfindley) Clean up Named struct below; specifically the fromRHS field (can we use underlying?).
|
||||
|
||||
// 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 *Named // original, uninstantiated type
|
||||
fromRHS 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
|
||||
|
||||
resolve func(*Named) ([]*TypeName, Type, []*Func)
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
// 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 NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
|
||||
if _, ok := underlying.(*Named); ok {
|
||||
panic("types.NewNamed: underlying type must not be *Named")
|
||||
}
|
||||
return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods)
|
||||
}
|
||||
|
||||
func (t *Named) expand() *Named {
|
||||
if t.resolve == nil {
|
||||
return t
|
||||
}
|
||||
|
||||
t.once.Do(func() {
|
||||
// TODO(mdempsky): Since we're passing t to resolve anyway
|
||||
// (necessary because types2 expects the receiver type for methods
|
||||
// on defined interface types to be the Named rather than the
|
||||
// underlying Interface), maybe it should just handle calling
|
||||
// SetTParams, SetUnderlying, and AddMethod instead? Those
|
||||
// methods would need to support reentrant calls though. It would
|
||||
// also make the API more future-proof towards further extensions
|
||||
// (like SetTParams).
|
||||
|
||||
tparams, underlying, methods := t.resolve(t)
|
||||
|
||||
switch underlying.(type) {
|
||||
case nil, *Named:
|
||||
panic("invalid underlying type")
|
||||
}
|
||||
|
||||
t.tparams = tparams
|
||||
t.underlying = underlying
|
||||
t.methods = methods
|
||||
})
|
||||
return t
|
||||
}
|
||||
|
||||
// newNamed is like NewNamed but with a *Checker receiver and additional orig argument.
|
||||
func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named {
|
||||
typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods}
|
||||
if typ.orig == nil {
|
||||
typ.orig = typ
|
||||
}
|
||||
if obj.typ == nil {
|
||||
obj.typ = 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 check != nil {
|
||||
check.later(func() {
|
||||
switch typ.under().(type) {
|
||||
case *Named, *instance:
|
||||
panic("internal error: unexpanded underlying type")
|
||||
}
|
||||
typ.check = nil
|
||||
})
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// Obj returns the type name for the named type t.
|
||||
func (t *Named) Obj() *TypeName { return t.obj }
|
||||
|
||||
// _Orig returns the original generic type an instantiated type is derived from.
|
||||
// If t is not an instantiated type, the result is t.
|
||||
func (t *Named) _Orig() *Named { return t.orig }
|
||||
|
||||
// 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 (t *Named) TParams() []*TypeName { return t.expand().tparams }
|
||||
|
||||
// _SetTParams sets the type parameters of the named type t.
|
||||
func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = tparams }
|
||||
|
||||
// _TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated.
|
||||
func (t *Named) TArgs() []Type { return t.targs }
|
||||
|
||||
// SetTArgs sets the type arguments of the named type t.
|
||||
func (t *Named) SetTArgs(args []Type) { t.targs = args }
|
||||
|
||||
// NumMethods returns the number of explicit methods whose receiver is named type t.
|
||||
func (t *Named) NumMethods() int { return len(t.expand().methods) }
|
||||
|
||||
// Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
|
||||
func (t *Named) Method(i int) *Func { return t.expand().methods[i] }
|
||||
|
||||
// SetUnderlying sets the underlying type and marks t as complete.
|
||||
func (t *Named) SetUnderlying(underlying Type) {
|
||||
if underlying == nil {
|
||||
panic("types.Named.SetUnderlying: underlying type must not be nil")
|
||||
}
|
||||
if _, ok := underlying.(*Named); ok {
|
||||
panic("types.Named.SetUnderlying: underlying type must not be *Named")
|
||||
}
|
||||
t.expand().underlying = underlying
|
||||
}
|
||||
|
||||
// AddMethod adds method m unless it is already in the method list.
|
||||
func (t *Named) AddMethod(m *Func) {
|
||||
t.expand()
|
||||
if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 {
|
||||
t.methods = append(t.methods, m)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Named) Underlying() Type { return t.expand().underlying }
|
||||
func (t *Named) String() string { return TypeString(t, nil) }
|
19
src/go/types/pointer.go
Normal file
19
src/go/types/pointer.go
Normal file
@ -0,0 +1,19 @@
|
||||
// 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
|
||||
|
||||
// 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 NewPointer(elem Type) *Pointer { return &Pointer{base: elem} }
|
||||
|
||||
// Elem returns the element type for the given pointer p.
|
||||
func (p *Pointer) Elem() Type { return p.base }
|
||||
|
||||
func (t *Pointer) Underlying() Type { return t }
|
||||
func (t *Pointer) String() string { return TypeString(t, nil) }
|
19
src/go/types/slice.go
Normal file
19
src/go/types/slice.go
Normal file
@ -0,0 +1,19 @@
|
||||
// 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
|
||||
|
||||
// A Slice represents a slice type.
|
||||
type Slice struct {
|
||||
elem Type
|
||||
}
|
||||
|
||||
// NewSlice returns a new slice type for the given element type.
|
||||
func NewSlice(elem Type) *Slice { return &Slice{elem: elem} }
|
||||
|
||||
// Elem returns the element type of slice s.
|
||||
func (s *Slice) Elem() Type { return s.elem }
|
||||
|
||||
func (t *Slice) Underlying() Type { return t }
|
||||
func (t *Slice) String() string { return TypeString(t, nil) }
|
36
src/go/types/tuple.go
Normal file
36
src/go/types/tuple.go
Normal file
@ -0,0 +1,36 @@
|
||||
// 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
|
||||
|
||||
// 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 NewTuple(x ...*Var) *Tuple {
|
||||
if len(x) > 0 {
|
||||
return &Tuple{vars: x}
|
||||
}
|
||||
// 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 (t *Tuple) Len() int {
|
||||
if t != nil {
|
||||
return len(t.vars)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// At returns the i'th variable of tuple t.
|
||||
func (t *Tuple) At(i int) *Var { return t.vars[i] }
|
||||
|
||||
func (t *Tuple) Underlying() Type { return t }
|
||||
func (t *Tuple) String() string { return TypeString(t, nil) }
|
@ -4,12 +4,6 @@
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"go/token"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// A Type represents a type of Go.
|
||||
// All types implement the Type interface.
|
||||
type Type interface {
|
||||
@ -22,379 +16,31 @@ type Type interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// BasicKind describes the kind of basic type.
|
||||
type BasicKind int
|
||||
// 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),
|
||||
// because its type constraint contains no restrictions
|
||||
// besides methods.
|
||||
type top struct{}
|
||||
|
||||
const (
|
||||
Invalid BasicKind = iota // type is invalid
|
||||
// theTop is the singleton top type.
|
||||
var theTop = &top{}
|
||||
|
||||
// predeclared types
|
||||
Bool
|
||||
Int
|
||||
Int8
|
||||
Int16
|
||||
Int32
|
||||
Int64
|
||||
Uint
|
||||
Uint8
|
||||
Uint16
|
||||
Uint32
|
||||
Uint64
|
||||
Uintptr
|
||||
Float32
|
||||
Float64
|
||||
Complex64
|
||||
Complex128
|
||||
String
|
||||
UnsafePointer
|
||||
func (t *top) Underlying() Type { return t }
|
||||
func (t *top) String() string { return TypeString(t, nil) }
|
||||
|
||||
// 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 (b *Basic) Kind() BasicKind { return b.kind }
|
||||
|
||||
// Info returns information about properties of basic type b.
|
||||
func (b *Basic) Info() BasicInfo { return b.info }
|
||||
|
||||
// Name returns the name of basic type b.
|
||||
func (b *Basic) Name() string { return b.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 NewArray(elem Type, len int64) *Array { return &Array{len: len, elem: elem} }
|
||||
|
||||
// Len returns the length of array a.
|
||||
// A negative result indicates an unknown length.
|
||||
func (a *Array) Len() int64 { return a.len }
|
||||
|
||||
// Elem returns element type of array a.
|
||||
func (a *Array) Elem() Type { return a.elem }
|
||||
|
||||
// A Slice represents a slice type.
|
||||
type Slice struct {
|
||||
elem Type
|
||||
}
|
||||
|
||||
// NewSlice returns a new slice type for the given element type.
|
||||
func NewSlice(elem Type) *Slice { return &Slice{elem: elem} }
|
||||
|
||||
// Elem returns the element type of slice s.
|
||||
func (s *Slice) Elem() Type { return s.elem }
|
||||
|
||||
// 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 NewPointer(elem Type) *Pointer { return &Pointer{base: elem} }
|
||||
|
||||
// Elem returns the element type for the given pointer p.
|
||||
func (p *Pointer) Elem() Type { return p.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 NewTuple(x ...*Var) *Tuple {
|
||||
if len(x) > 0 {
|
||||
return &Tuple{vars: x}
|
||||
// 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(t Type) Type {
|
||||
// TODO(gri) is this correct for *Union?
|
||||
if n := asNamed(t); n != nil {
|
||||
return n.under()
|
||||
}
|
||||
// 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 (t *Tuple) Len() int {
|
||||
if t != nil {
|
||||
return len(t.vars)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// At returns the i'th variable of tuple t.
|
||||
func (t *Tuple) At(i int) *Var { return t.vars[i] }
|
||||
|
||||
// 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 NewMap(key, elem Type) *Map {
|
||||
return &Map{key: key, elem: elem}
|
||||
}
|
||||
|
||||
// Key returns the key type of map m.
|
||||
func (m *Map) Key() Type { return m.key }
|
||||
|
||||
// Elem returns the element type of map m.
|
||||
func (m *Map) Elem() Type { return m.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 NewChan(dir ChanDir, elem Type) *Chan {
|
||||
return &Chan{dir: dir, elem: elem}
|
||||
}
|
||||
|
||||
// Dir returns the direction of channel c.
|
||||
func (c *Chan) Dir() ChanDir { return c.dir }
|
||||
|
||||
// Elem returns the element type of channel c.
|
||||
func (c *Chan) Elem() Type { return c.elem }
|
||||
|
||||
// TODO(rfindley) Clean up Named struct below; specifically the fromRHS field (can we use underlying?).
|
||||
|
||||
// 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 *Named // original, uninstantiated type
|
||||
fromRHS 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
|
||||
|
||||
resolve func(*Named) ([]*TypeName, Type, []*Func)
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
// 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 NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
|
||||
if _, ok := underlying.(*Named); ok {
|
||||
panic("types.NewNamed: underlying type must not be *Named")
|
||||
}
|
||||
return (*Checker)(nil).newNamed(obj, nil, underlying, nil, methods)
|
||||
}
|
||||
|
||||
func (t *Named) expand() *Named {
|
||||
if t.resolve == nil {
|
||||
return t
|
||||
}
|
||||
|
||||
t.once.Do(func() {
|
||||
// TODO(mdempsky): Since we're passing t to resolve anyway
|
||||
// (necessary because types2 expects the receiver type for methods
|
||||
// on defined interface types to be the Named rather than the
|
||||
// underlying Interface), maybe it should just handle calling
|
||||
// SetTParams, SetUnderlying, and AddMethod instead? Those
|
||||
// methods would need to support reentrant calls though. It would
|
||||
// also make the API more future-proof towards further extensions
|
||||
// (like SetTParams).
|
||||
|
||||
tparams, underlying, methods := t.resolve(t)
|
||||
|
||||
switch underlying.(type) {
|
||||
case nil, *Named:
|
||||
panic("invalid underlying type")
|
||||
}
|
||||
|
||||
t.tparams = tparams
|
||||
t.underlying = underlying
|
||||
t.methods = methods
|
||||
})
|
||||
return t
|
||||
}
|
||||
|
||||
func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tparams []*TypeName, methods []*Func) *Named {
|
||||
typ := &Named{check: check, obj: obj, orig: orig, fromRHS: underlying, underlying: underlying, tparams: tparams, methods: methods}
|
||||
if typ.orig == nil {
|
||||
typ.orig = typ
|
||||
}
|
||||
if obj.typ == nil {
|
||||
obj.typ = 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 check != nil {
|
||||
check.later(func() {
|
||||
switch typ.under().(type) {
|
||||
case *Named, *instance:
|
||||
panic("internal error: unexpanded underlying type")
|
||||
}
|
||||
typ.check = nil
|
||||
})
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// Obj returns the type name for the named type t.
|
||||
func (t *Named) Obj() *TypeName { return t.obj }
|
||||
|
||||
// _Orig returns the original generic type an instantiated type is derived from.
|
||||
// If t is not an instantiated type, the result is t.
|
||||
func (t *Named) _Orig() *Named { return t.orig }
|
||||
|
||||
// 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 (t *Named) TParams() []*TypeName { return t.expand().tparams }
|
||||
|
||||
// _SetTParams sets the type parameters of the named type t.
|
||||
func (t *Named) SetTParams(tparams []*TypeName) { t.expand().tparams = tparams }
|
||||
|
||||
// _TArgs returns the type arguments after instantiation of the named type t, or nil if not instantiated.
|
||||
func (t *Named) TArgs() []Type { return t.targs }
|
||||
|
||||
// SetTArgs sets the type arguments of the named type t.
|
||||
func (t *Named) SetTArgs(args []Type) { t.targs = args }
|
||||
|
||||
// NumMethods returns the number of explicit methods whose receiver is named type t.
|
||||
func (t *Named) NumMethods() int { return len(t.expand().methods) }
|
||||
|
||||
// Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
|
||||
func (t *Named) Method(i int) *Func { return t.expand().methods[i] }
|
||||
|
||||
// SetUnderlying sets the underlying type and marks t as complete.
|
||||
func (t *Named) SetUnderlying(underlying Type) {
|
||||
if underlying == nil {
|
||||
panic("types.Named.SetUnderlying: underlying type must not be nil")
|
||||
}
|
||||
if _, ok := underlying.(*Named); ok {
|
||||
panic("types.Named.SetUnderlying: underlying type must not be *Named")
|
||||
}
|
||||
t.expand().underlying = underlying
|
||||
}
|
||||
|
||||
// AddMethod adds method m unless it is already in the method list.
|
||||
func (t *Named) AddMethod(m *Func) {
|
||||
t.expand()
|
||||
if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 {
|
||||
t.methods = append(t.methods, m)
|
||||
}
|
||||
}
|
||||
|
||||
// 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, for debugging only
|
||||
obj *TypeName // corresponding type name
|
||||
index int // type parameter index in source order, starting at 0
|
||||
bound Type // *Named or *Interface; underlying type is always *Interface
|
||||
}
|
||||
|
||||
// NewTypeParam returns a new TypeParam.
|
||||
func NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam {
|
||||
return (*Checker)(nil).newTypeParam(obj, index, bound)
|
||||
}
|
||||
|
||||
func (check *Checker) newTypeParam(obj *TypeName, index int, bound Type) *TypeParam {
|
||||
assert(bound != nil)
|
||||
|
||||
// Always increment lastID, even if it is not used.
|
||||
id := nextID()
|
||||
if check != nil {
|
||||
check.nextID++
|
||||
id = check.nextID
|
||||
}
|
||||
|
||||
typ := &TypeParam{check: check, id: id, obj: obj, index: index, bound: bound}
|
||||
if obj.typ == nil {
|
||||
obj.typ = typ
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
func (t *TypeParam) Bound() *Interface {
|
||||
// we may not have an interface (error reported elsewhere)
|
||||
iface, _ := under(t.bound).(*Interface)
|
||||
if iface == nil {
|
||||
return &emptyInterface
|
||||
}
|
||||
// use the type bound position if we have one
|
||||
pos := token.NoPos
|
||||
if n, _ := t.bound.(*Named); n != nil {
|
||||
pos = n.obj.pos
|
||||
}
|
||||
// TODO(rFindley) switch this to an unexported method on Checker.
|
||||
computeTypeSet(t.check, pos, iface)
|
||||
return iface
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -424,102 +70,6 @@ func optype(typ Type) Type {
|
||||
return under(typ)
|
||||
}
|
||||
|
||||
// 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 (t *instance) expand() Type {
|
||||
v := t.value
|
||||
if v == nil {
|
||||
v = t.check.instantiate(t.pos, t.base, t.targs, t.poslist)
|
||||
if v == nil {
|
||||
v = Typ[Invalid]
|
||||
}
|
||||
t.value = v
|
||||
}
|
||||
// After instantiation we must have an invalid or a *Named type.
|
||||
if debug && v != Typ[Invalid] {
|
||||
_ = v.(*Named)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// expand expands a type instance into its instantiated
|
||||
// type and leaves all other types alone. expand does
|
||||
// not recurse.
|
||||
func expand(typ Type) Type {
|
||||
if t, _ := typ.(*instance); t != nil {
|
||||
return t.expand()
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// expandf is set to expand.
|
||||
// Call expandf when calling expand causes compile-time cycle error.
|
||||
var expandf func(Type) Type
|
||||
|
||||
func init() { expandf = expand }
|
||||
|
||||
// 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),
|
||||
// because its type constraint contains no restrictions
|
||||
// besides methods.
|
||||
type top struct{}
|
||||
|
||||
// theTop is the singleton top type.
|
||||
var theTop = &top{}
|
||||
|
||||
// Type-specific implementations of Underlying.
|
||||
func (t *Basic) Underlying() Type { return t }
|
||||
func (t *Array) Underlying() Type { return t }
|
||||
func (t *Slice) Underlying() Type { return t }
|
||||
func (t *Pointer) Underlying() Type { return t }
|
||||
func (t *Tuple) Underlying() Type { return t }
|
||||
func (t *Map) Underlying() Type { return t }
|
||||
func (t *Chan) Underlying() Type { return t }
|
||||
func (t *Named) Underlying() Type { return t.expand().underlying }
|
||||
func (t *TypeParam) Underlying() Type { return t }
|
||||
func (t *instance) Underlying() Type { return t }
|
||||
func (t *top) Underlying() Type { return t }
|
||||
|
||||
// Type-specific implementations of String.
|
||||
func (t *Basic) String() string { return TypeString(t, nil) }
|
||||
func (t *Array) String() string { return TypeString(t, nil) }
|
||||
func (t *Slice) String() string { return TypeString(t, nil) }
|
||||
func (t *Pointer) String() string { return TypeString(t, nil) }
|
||||
func (t *Tuple) String() string { return TypeString(t, nil) }
|
||||
func (t *Map) String() string { return TypeString(t, nil) }
|
||||
func (t *Chan) String() string { return TypeString(t, nil) }
|
||||
func (t *Named) String() string { return TypeString(t, nil) }
|
||||
func (t *TypeParam) String() string { return TypeString(t, nil) }
|
||||
func (t *instance) String() string { return TypeString(t, nil) }
|
||||
func (t *top) String() string { return TypeString(t, 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(t Type) Type {
|
||||
// TODO(gri) is this correct for *Union?
|
||||
if n := asNamed(t); n != nil {
|
||||
return n.under()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// Converters
|
||||
//
|
||||
// A converter must only be called when a type is
|
||||
|
72
src/go/types/typeparam.go
Normal file
72
src/go/types/typeparam.go
Normal file
@ -0,0 +1,72 @@
|
||||
// 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 (
|
||||
"go/token"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// 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, for debugging only
|
||||
obj *TypeName // corresponding type name
|
||||
index int // type parameter index in source order, starting at 0
|
||||
bound Type // *Named or *Interface; underlying type is always *Interface
|
||||
}
|
||||
|
||||
// NewTypeParam returns a new TypeParam.
|
||||
func NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam {
|
||||
return (*Checker)(nil).newTypeParam(obj, index, bound)
|
||||
}
|
||||
|
||||
// TODO(rfindley): this is factored slightly differently in types2.
|
||||
func (check *Checker) newTypeParam(obj *TypeName, index int, bound Type) *TypeParam {
|
||||
assert(bound != nil)
|
||||
|
||||
// Always increment lastID, even if it is not used.
|
||||
id := nextID()
|
||||
if check != nil {
|
||||
check.nextID++
|
||||
id = check.nextID
|
||||
}
|
||||
|
||||
typ := &TypeParam{check: check, id: id, obj: obj, index: index, bound: bound}
|
||||
if obj.typ == nil {
|
||||
obj.typ = typ
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// TODO(rfindley): types2 to has Index and SetID. Should we add them here?
|
||||
|
||||
func (t *TypeParam) Bound() *Interface {
|
||||
// we may not have an interface (error reported elsewhere)
|
||||
iface, _ := under(t.bound).(*Interface)
|
||||
if iface == nil {
|
||||
return &emptyInterface
|
||||
}
|
||||
// use the type bound position if we have one
|
||||
pos := token.NoPos
|
||||
if n, _ := t.bound.(*Named); n != nil {
|
||||
pos = n.obj.pos
|
||||
}
|
||||
// TODO(rFindley) switch this to an unexported method on Checker.
|
||||
computeTypeSet(t.check, pos, iface)
|
||||
return iface
|
||||
}
|
||||
|
||||
func (t *TypeParam) Underlying() Type { return t }
|
||||
func (t *TypeParam) String() string { return TypeString(t, nil) }
|
Loading…
Reference in New Issue
Block a user