mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00: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
11 changed files with 532 additions and 468 deletions
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
|
package types
|
||||||
|
|
||||||
import (
|
|
||||||
"go/token"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Type represents a type of Go.
|
// A Type represents a type of Go.
|
||||||
// All types implement the Type interface.
|
// All types implement the Type interface.
|
||||||
type Type interface {
|
type Type interface {
|
||||||
|
|
@ -22,379 +16,31 @@ type Type interface {
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// BasicKind describes the kind of basic type.
|
// top represents the top of the type lattice.
|
||||||
type BasicKind int
|
// 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 (
|
// theTop is the singleton top type.
|
||||||
Invalid BasicKind = iota // type is invalid
|
var theTop = &top{}
|
||||||
|
|
||||||
// predeclared types
|
func (t *top) Underlying() Type { return t }
|
||||||
Bool
|
func (t *top) String() string { return TypeString(t, nil) }
|
||||||
Int
|
|
||||||
Int8
|
|
||||||
Int16
|
|
||||||
Int32
|
|
||||||
Int64
|
|
||||||
Uint
|
|
||||||
Uint8
|
|
||||||
Uint16
|
|
||||||
Uint32
|
|
||||||
Uint64
|
|
||||||
Uintptr
|
|
||||||
Float32
|
|
||||||
Float64
|
|
||||||
Complex64
|
|
||||||
Complex128
|
|
||||||
String
|
|
||||||
UnsafePointer
|
|
||||||
|
|
||||||
// types for untyped values
|
// under returns the true expanded underlying type.
|
||||||
UntypedBool
|
// If it doesn't exist, the result is Typ[Invalid].
|
||||||
UntypedInt
|
// under must only be called when a type is known
|
||||||
UntypedRune
|
// to be fully set up.
|
||||||
UntypedFloat
|
func under(t Type) Type {
|
||||||
UntypedComplex
|
// TODO(gri) is this correct for *Union?
|
||||||
UntypedString
|
if n := asNamed(t); n != nil {
|
||||||
UntypedNil
|
return n.under()
|
||||||
|
|
||||||
// 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}
|
|
||||||
}
|
|
||||||
// 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
|
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,
|
// optype returns a type's operational type. Except for type parameters,
|
||||||
// the operational type is the same as the underlying type (as returned
|
// the operational type is the same as the underlying type (as returned
|
||||||
// by under). For Type parameters, the operational type is determined
|
// by under). For Type parameters, the operational type is determined
|
||||||
|
|
@ -424,102 +70,6 @@ func optype(typ Type) Type {
|
||||||
return under(typ)
|
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
|
// Converters
|
||||||
//
|
//
|
||||||
// A converter must only be called when a type is
|
// 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…
Add table
Add a link
Reference in a new issue