mirror of https://github.com/golang/go.git
go/types: implement type conversion methods
Provide easy accessors to a type's underlying type. Instead of
if t, _ := typ.Underlying().(*XXX); t != nil { ... }
we can now write
if t := typ.XXX(); t != nil { ... }
where XXX is a type such as Basic, Array, Slice, Pointer, etc.
This removes a type assertion in all cases where typ is not a *Named
type and the code is easier to read.
Also, made Named.Underlying more robust by tracking cycles and nil
underlying types.
The Named.Underlying change is a first step towards making type
checking more lazy which eventually should permit dealing with
cycles that we cannot yet handle properly.
This change briefly breaks some external code (gcimporter, gccgoimporter)
due to the change in semantics of type.Underlying. This will be fixed by
the next change.
Passes go/types tests (but not all.bash).
Change-Id: I493a949e554da6f2a944e7e9b1f1f6f38f597042
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go2-dev/+/717606
Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
04f9e20db3
commit
63f4460f70
|
|
@ -125,3 +125,17 @@ type anyType struct{}
|
|||
|
||||
func (t anyType) Underlying() types.Type { return t }
|
||||
func (t anyType) String() string { return "any" }
|
||||
|
||||
// types.aType is not exported for now so we need to implemented these here.
|
||||
func (anyType) Basic() *types.Basic { return nil }
|
||||
func (anyType) Array() *types.Array { return nil }
|
||||
func (anyType) Slice() *types.Slice { return nil }
|
||||
func (anyType) Struct() *types.Struct { return nil }
|
||||
func (anyType) Pointer() *types.Pointer { return nil }
|
||||
func (anyType) Tuple() *types.Tuple { return nil }
|
||||
func (anyType) Signature() *types.Signature { return nil }
|
||||
func (anyType) Interface() *types.Interface { return nil }
|
||||
func (anyType) Map() *types.Map { return nil }
|
||||
func (anyType) Chan() *types.Chan { return nil }
|
||||
func (anyType) Named() *types.Named { return nil }
|
||||
func (anyType) TypeParam() *types.TypeParam { return nil }
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
|
|||
// x.typ is typed
|
||||
|
||||
// A generic (non-instantiated) function value cannot be assigned to a variable.
|
||||
if sig, _ := x.typ.Underlying().(*Signature); sig != nil && len(sig.tparams) > 0 {
|
||||
if sig := x.typ.Signature(); sig != nil && len(sig.tparams) > 0 {
|
||||
check.errorf(x.pos(), "cannot use generic function %s without instantiation in %s", x, context)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
// of S and the respective parameter passing rules apply."
|
||||
S := x.typ
|
||||
var T Type
|
||||
if s, _ := S.Underlying().(*Slice); s != nil {
|
||||
if s := S.Slice(); s != nil {
|
||||
T = s.elem
|
||||
} else {
|
||||
check.invalidArg(x.pos(), "%s is not a slice", x)
|
||||
|
|
@ -176,7 +176,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
}
|
||||
|
||||
case *TypeParam:
|
||||
if t.Interface().is(func(t Type) bool {
|
||||
if t.Bound().is(func(t Type) bool {
|
||||
switch t.(type) {
|
||||
case *Basic:
|
||||
if isString(t) && id == _Len {
|
||||
|
|
@ -209,7 +209,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
|
||||
case _Close:
|
||||
// close(c)
|
||||
c, _ := x.typ.Underlying().(*Chan)
|
||||
c := x.typ.Chan()
|
||||
if c == nil {
|
||||
check.invalidArg(x.pos(), "%s is not a channel", x)
|
||||
return
|
||||
|
|
@ -285,7 +285,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
|
||||
// the argument types must be of floating-point type
|
||||
f := func(x Type) Type {
|
||||
if t, _ := x.Underlying().(*Basic); t != nil {
|
||||
if t := x.Basic(); t != nil {
|
||||
switch t.kind {
|
||||
case Float32:
|
||||
return Typ[Complex64]
|
||||
|
|
@ -319,7 +319,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
case _Copy:
|
||||
// copy(x, y []T) int
|
||||
var dst Type
|
||||
if t, _ := x.typ.Underlying().(*Slice); t != nil {
|
||||
if t := x.typ.Slice(); t != nil {
|
||||
dst = t.elem
|
||||
}
|
||||
|
||||
|
|
@ -356,7 +356,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
|
||||
case _Delete:
|
||||
// delete(m, k)
|
||||
m, _ := x.typ.Underlying().(*Map)
|
||||
m := x.typ.Map()
|
||||
if m == nil {
|
||||
check.invalidArg(x.pos(), "%s is not a map", x)
|
||||
return
|
||||
|
|
@ -403,7 +403,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
|
||||
// the argument must be of complex type
|
||||
f := func(x Type) Type {
|
||||
if t, _ := x.Underlying().(*Basic); t != nil {
|
||||
if t := x.Basic(); t != nil {
|
||||
switch t.kind {
|
||||
case Complex64:
|
||||
return Typ[Float32]
|
||||
|
|
@ -674,11 +674,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
// applyTypeFunc returns nil.
|
||||
// If x is not a type parameter, the result is f(x).
|
||||
func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
|
||||
if tp, _ := x.Underlying().(*TypeParam); tp != nil {
|
||||
if tp := x.TypeParam(); tp != nil {
|
||||
// Test if t satisfies the requirements for the argument
|
||||
// type and collect possible result types at the same time.
|
||||
var resTypes []Type
|
||||
if !tp.Interface().is(func(x Type) bool {
|
||||
if !tp.Bound().is(func(x Type) bool {
|
||||
if r := f(x); r != nil {
|
||||
resTypes = append(resTypes, r)
|
||||
return true
|
||||
|
|
@ -725,7 +725,7 @@ func makeSig(res Type, args ...Type) *Signature {
|
|||
//
|
||||
func implicitArrayDeref(typ Type) Type {
|
||||
if p, ok := typ.(*Pointer); ok {
|
||||
if a, ok := p.base.Underlying().(*Array); ok {
|
||||
if a := p.base.Array(); a != nil {
|
||||
return a
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
|
|||
// function/method call
|
||||
cgocall := x.mode == cgofunc
|
||||
|
||||
sig, _ := x.typ.Underlying().(*Signature)
|
||||
sig := x.typ.Signature()
|
||||
if sig == nil {
|
||||
check.invalidOp(x.pos(), "cannot call non-function %s", x)
|
||||
x.mode = invalid
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ func (check *Checker) contractDecl(obj *Contract, cdecl *ast.ContractSpec) {
|
|||
for _, targ := range targs {
|
||||
tpar := targ.(*TypeParam)
|
||||
iface := bounds[tpar.index].underlying.(*Interface)
|
||||
embed := tpar.Interface() // don't use Named form of tpar.bound
|
||||
embed := tpar.Bound() // don't use Named form of tpar.bound
|
||||
iface.embeddeds = append(iface.embeddeds, embed)
|
||||
check.posMap[iface] = append(check.posMap[iface], econtr.Pos()) // satisfy completeInterface requirements
|
||||
// check.contractExpr assigned a type bound to its incoming type arguments,
|
||||
|
|
@ -176,7 +176,7 @@ func (check *Checker) contractDecl(obj *Contract, cdecl *ast.ContractSpec) {
|
|||
|
||||
// Contracts don't have types, but we need to set a type to
|
||||
// detect recursive declarations and satisfy assertions.
|
||||
type contractType struct{}
|
||||
type contractType struct{ aType }
|
||||
|
||||
func (contractType) String() string { return "<dummy contract type>" }
|
||||
func (contractType) Underlying() Type { panic("unreachable") }
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ func (check *Checker) conversion(x *operand, T Type) {
|
|||
switch {
|
||||
case constArg && isConstType(T):
|
||||
// constant conversion
|
||||
switch t := T.Underlying().(*Basic); {
|
||||
switch t := T.Basic(); {
|
||||
case representableConst(x.val, check, t, &x.val):
|
||||
ok = true
|
||||
case isInteger(x.typ) && isString(t):
|
||||
|
|
@ -137,27 +137,26 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
|
|||
}
|
||||
|
||||
func isUintptr(typ Type) bool {
|
||||
t, ok := typ.Underlying().(*Basic)
|
||||
return ok && t.kind == Uintptr
|
||||
t := typ.Basic()
|
||||
return t != nil && t.kind == Uintptr
|
||||
}
|
||||
|
||||
func isUnsafePointer(typ Type) bool {
|
||||
// TODO(gri): Is this (typ.Underlying() instead of just typ) correct?
|
||||
// The spec does not say so, but gc claims it is. See also
|
||||
// issue 6326.
|
||||
t, ok := typ.Underlying().(*Basic)
|
||||
return ok && t.kind == UnsafePointer
|
||||
t := typ.Basic()
|
||||
return t != nil && t.kind == UnsafePointer
|
||||
}
|
||||
|
||||
func isPointer(typ Type) bool {
|
||||
_, ok := typ.Underlying().(*Pointer)
|
||||
return ok
|
||||
return typ.Pointer() != nil
|
||||
}
|
||||
|
||||
func isBytesOrRunes(typ Type) bool {
|
||||
if s, ok := typ.(*Slice); ok {
|
||||
t, ok := s.elem.Underlying().(*Basic)
|
||||
return ok && (t.kind == Byte || t.kind == Rune)
|
||||
if s := typ.Slice(); s != nil {
|
||||
t := s.elem.Basic()
|
||||
return t != nil && (t.kind == Byte || t.kind == Rune)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,8 +94,8 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr, op token.Token) {
|
|||
return
|
||||
|
||||
case token.ARROW:
|
||||
typ, ok := x.typ.Underlying().(*Chan)
|
||||
if !ok {
|
||||
typ := x.typ.Chan()
|
||||
if typ == nil {
|
||||
check.invalidOp(x.pos(), "cannot receive from non-channel %s", x)
|
||||
x.mode = invalid
|
||||
return
|
||||
|
|
@ -117,7 +117,7 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr, op token.Token) {
|
|||
}
|
||||
|
||||
if x.mode == constant_ {
|
||||
typ := x.typ.Underlying().(*Basic)
|
||||
typ := x.typ.Basic()
|
||||
var prec uint
|
||||
if isUnsigned(typ) {
|
||||
prec = uint(check.conf.sizeof(typ) * 8)
|
||||
|
|
@ -444,7 +444,7 @@ func (check *Checker) updateExprType(x ast.Expr, typ Type, final bool) {
|
|||
// If the new type is not final and still untyped, just
|
||||
// update the recorded type.
|
||||
if !final && isUntyped(typ) {
|
||||
old.typ = typ.Underlying().(*Basic)
|
||||
old.typ = typ.Basic()
|
||||
check.untyped[x] = old
|
||||
return
|
||||
}
|
||||
|
|
@ -512,8 +512,8 @@ func (check *Checker) convertUntyped(x *operand, target Type) {
|
|||
|
||||
// In case of a type parameter, conversion must succeed against
|
||||
// all types enumerated by the the type parameter bound.
|
||||
if t, _ := target.Underlying().(*TypeParam); t != nil {
|
||||
types := t.Interface().allTypes
|
||||
if t := target.TypeParam(); t != nil {
|
||||
types := t.Bound().allTypes
|
||||
if len(types) == 0 {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -742,7 +742,7 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
|
|||
if e != nil {
|
||||
x.expr = e // for better error message
|
||||
}
|
||||
check.representable(x, x.typ.Underlying().(*Basic))
|
||||
check.representable(x, x.typ.Basic())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -878,7 +878,7 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o
|
|||
if x.mode == constant_ && y.mode == constant_ {
|
||||
xval := x.val
|
||||
yval := y.val
|
||||
typ := x.typ.Underlying().(*Basic)
|
||||
typ := x.typ.Basic()
|
||||
// force integer division of integer operands
|
||||
if op == token.QUO && isInteger(typ) {
|
||||
op = token.QUO_ASSIGN
|
||||
|
|
@ -1255,7 +1255,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||
duplicate := false
|
||||
// if the key is of interface type, the type is also significant when checking for duplicates
|
||||
xkey := keyVal(x.val)
|
||||
if _, ok := utyp.key.Underlying().(*Interface); ok {
|
||||
if utyp.key.Interface() != nil {
|
||||
for _, vtyp := range visited[xkey] {
|
||||
if check.identical(vtyp, x.typ) {
|
||||
duplicate = true
|
||||
|
|
@ -1338,7 +1338,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||
x.typ = typ.elem
|
||||
|
||||
case *Pointer:
|
||||
if typ, _ := typ.base.Underlying().(*Array); typ != nil {
|
||||
if typ := typ.base.Array(); typ != nil {
|
||||
valid = true
|
||||
length = typ.len
|
||||
x.mode = variable
|
||||
|
|
@ -1367,7 +1367,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||
// in its type bound support indexing and have the
|
||||
// same element type.
|
||||
var elem Type
|
||||
if typ.Interface().is(func(t Type) bool {
|
||||
if typ.Bound().is(func(t Type) bool {
|
||||
var e Type
|
||||
switch t := t.(type) {
|
||||
case *Basic:
|
||||
|
|
@ -1377,7 +1377,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||
case *Array:
|
||||
e = t.elem
|
||||
case *Pointer:
|
||||
if t, _ := t.base.Underlying().(*Array); t != nil {
|
||||
if t := t.base.Array(); t != nil {
|
||||
e = t.elem
|
||||
}
|
||||
case *Slice:
|
||||
|
|
@ -1449,7 +1449,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||
x.typ = &Slice{elem: typ.elem}
|
||||
|
||||
case *Pointer:
|
||||
if typ, _ := typ.base.Underlying().(*Array); typ != nil {
|
||||
if typ := typ.base.Array(); typ != nil {
|
||||
valid = true
|
||||
length = typ.len
|
||||
x.typ = &Slice{elem: typ.elem}
|
||||
|
|
@ -1528,7 +1528,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||
case *Interface:
|
||||
xtyp = t
|
||||
case *TypeParam:
|
||||
xtyp = t.Interface()
|
||||
xtyp = t.Bound()
|
||||
strict = true
|
||||
default:
|
||||
check.invalidOp(x.pos(), "%s is not an interface or generic type", x)
|
||||
|
|
@ -1558,7 +1558,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||
case typexpr:
|
||||
x.typ = &Pointer{base: x.typ}
|
||||
default:
|
||||
if typ, ok := x.typ.Underlying().(*Pointer); ok {
|
||||
if typ := x.typ.Pointer(); typ != nil {
|
||||
x.mode = variable
|
||||
x.typ = typ.base
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -384,9 +384,12 @@ func TestIssue28005(t *testing.T) {
|
|||
}
|
||||
}
|
||||
if obj == nil {
|
||||
t.Fatal("interface not found")
|
||||
t.Fatal("object X not found")
|
||||
}
|
||||
iface := obj.Type().Interface() // object X must be an interface
|
||||
if iface == nil {
|
||||
t.Fatalf("%s is not an interface", obj)
|
||||
}
|
||||
iface := obj.Type().Underlying().(*Interface) // I must be an interface
|
||||
|
||||
// Each iface method m is embedded; and m's receiver base type name
|
||||
// must match the method's name per the choice in the source file.
|
||||
|
|
@ -406,7 +409,7 @@ func TestIssue28282(t *testing.T) {
|
|||
it := NewInterfaceType(nil, []Type{et})
|
||||
it.Complete()
|
||||
// verify that after completing the interface, the embedded method remains unchanged
|
||||
want := et.Underlying().(*Interface).Method(0)
|
||||
want := et.Interface().Method(0)
|
||||
got := it.Method(0)
|
||||
if got != want {
|
||||
t.Fatalf("%s.Method(0): got %q (%p); want %q (%p)", it, got, got, want, want)
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ func (check *Checker) missingMethod(V Type, addressable bool, T *Interface, stat
|
|||
return
|
||||
}
|
||||
|
||||
if ityp, _ := V.Underlying().(*Interface); ityp != nil {
|
||||
if ityp := V.Interface(); ityp != nil {
|
||||
check.completeInterface(token.NoPos, ityp)
|
||||
// TODO(gri) allMethods is sorted - can do this more efficiently
|
||||
for _, m := range T.allMethods {
|
||||
|
|
@ -411,7 +411,7 @@ func (check *Checker) assertableTo(V *Interface, T Type, strict bool) (method, w
|
|||
// no static check is required if T is an interface
|
||||
// spec: "If T is an interface type, x.(T) asserts that the
|
||||
// dynamic type of x implements the interface T."
|
||||
if _, ok := T.Underlying().(*Interface); ok && !(strict || forceStrict) {
|
||||
if T.Interface() != nil && !(strict || forceStrict) {
|
||||
return
|
||||
}
|
||||
return check.missingMethod(T, false, V, false)
|
||||
|
|
@ -438,8 +438,8 @@ func derefUnpack(typ Type) (Type, bool) {
|
|||
// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a
|
||||
// (named or unnamed) struct and returns its base. Otherwise it returns typ.
|
||||
func derefStructPtr(typ Type) Type {
|
||||
if p, _ := typ.Underlying().(*Pointer); p != nil {
|
||||
if _, ok := p.base.Underlying().(*Struct); ok {
|
||||
if p := typ.Pointer(); p != nil {
|
||||
if p.base.Struct() != nil {
|
||||
return p.base
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func is(typ Type, what BasicInfo) bool {
|
|||
case *Basic:
|
||||
return t.info&what != 0
|
||||
case *TypeParam:
|
||||
return t.Interface().is(func(typ Type) bool { return is(typ, what) })
|
||||
return t.Bound().is(func(typ Type) bool { return is(typ, what) })
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -45,26 +45,25 @@ func isNumeric(typ Type) bool { return is(typ, IsNumeric) }
|
|||
func isString(typ Type) bool { return is(typ, IsString) }
|
||||
|
||||
func isTyped(typ Type) bool {
|
||||
t, ok := typ.Underlying().(*Basic)
|
||||
return !ok || t.info&IsUntyped == 0
|
||||
t := typ.Basic()
|
||||
return t == nil || t.info&IsUntyped == 0
|
||||
}
|
||||
|
||||
func isUntyped(typ Type) bool {
|
||||
t, ok := typ.Underlying().(*Basic)
|
||||
return ok && t.info&IsUntyped != 0
|
||||
t := typ.Basic()
|
||||
return t != nil && t.info&IsUntyped != 0
|
||||
}
|
||||
|
||||
func isOrdered(typ Type) bool { return is(typ, IsOrdered) }
|
||||
|
||||
func isConstType(typ Type) bool {
|
||||
t, ok := typ.Underlying().(*Basic)
|
||||
return ok && t.info&IsConstType != 0
|
||||
t := typ.Basic()
|
||||
return t != nil && t.info&IsConstType != 0
|
||||
}
|
||||
|
||||
// IsInterface reports whether typ is an interface type.
|
||||
func IsInterface(typ Type) bool {
|
||||
_, ok := typ.Underlying().(*Interface)
|
||||
return ok
|
||||
return typ.Interface() != nil
|
||||
}
|
||||
|
||||
// Comparable reports whether values of type T are comparable.
|
||||
|
|
@ -86,7 +85,7 @@ func Comparable(T Type) bool {
|
|||
case *Array:
|
||||
return Comparable(t.elem)
|
||||
case *TypeParam:
|
||||
iface := t.Interface()
|
||||
iface := t.Bound()
|
||||
// If the magic method == exists, the type parameter is comparable.
|
||||
_, m := lookupMethod(iface.allMethods, nil, "==")
|
||||
return m != nil || iface.is(Comparable)
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ func (conf *Config) offsetsof(T *Struct) []int64 {
|
|||
func (conf *Config) offsetof(typ Type, index []int) int64 {
|
||||
var o int64
|
||||
for _, i := range index {
|
||||
s := typ.Underlying().(*Struct)
|
||||
s := typ.Struct()
|
||||
o += conf.offsetsof(s)[i]
|
||||
typ = s.fields[i].typ
|
||||
}
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ func typecheck(t *testing.T, path string, filenames []string) {
|
|||
// Perform checks of API invariants.
|
||||
|
||||
// All Objects have a package, except predeclared ones.
|
||||
errorError := Universe.Lookup("error").Type().Underlying().(*Interface).ExplicitMethod(0) // (error).Error
|
||||
errorError := Universe.Lookup("error").Type().Interface().ExplicitMethod(0) // (error).Error
|
||||
for id, obj := range info.Uses {
|
||||
predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError
|
||||
if predeclared == (obj.Pkg() != nil) {
|
||||
|
|
|
|||
|
|
@ -350,8 +350,8 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
|||
return
|
||||
}
|
||||
|
||||
tch, ok := ch.typ.Underlying().(*Chan)
|
||||
if !ok {
|
||||
tch := ch.typ.Chan()
|
||||
if tch == nil {
|
||||
check.invalidOp(s.Arrow, "cannot send to non-chan type %s", ch.typ)
|
||||
return
|
||||
}
|
||||
|
|
@ -616,7 +616,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
|||
case *Interface:
|
||||
xtyp = t
|
||||
case *TypeParam:
|
||||
xtyp = t.Interface()
|
||||
xtyp = t.Bound()
|
||||
strict = true
|
||||
default:
|
||||
check.errorf(x.pos(), "%s is not an interface or generic type", &x)
|
||||
|
|
@ -883,7 +883,7 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
|
|||
case *Slice:
|
||||
return Typ[Int], typ.elem, ""
|
||||
case *Pointer:
|
||||
if typ, _ := typ.base.Underlying().(*Array); typ != nil {
|
||||
if typ := typ.base.Array(); typ != nil {
|
||||
return Typ[Int], typ.elem, ""
|
||||
}
|
||||
case *Map:
|
||||
|
|
@ -898,7 +898,7 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
|
|||
first := true
|
||||
var key, val Type
|
||||
var msg string
|
||||
typ.Interface().is(func(t Type) bool {
|
||||
typ.Bound().is(func(t Type) bool {
|
||||
k, v, m := rangeKeyVal(t, wantKey, wantVal)
|
||||
if k == nil || m != "" {
|
||||
key, val, msg = k, v, m
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
|||
// check bounds
|
||||
for i, tname := range tparams {
|
||||
tpar := tname.typ.(*TypeParam)
|
||||
iface := tpar.Interface()
|
||||
iface := tpar.Bound()
|
||||
if iface.Empty() {
|
||||
continue // no type bound
|
||||
}
|
||||
|
|
@ -161,8 +161,8 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
|||
|
||||
// If targ is itself a type parameter, each of its possible types, but at least one, must be in the
|
||||
// list of iface types (i.e., the targ type list must be a non-empty subset of the iface types).
|
||||
if targ, _ := targ.Underlying().(*TypeParam); targ != nil {
|
||||
targBound := targ.Interface()
|
||||
if targ := targ.TypeParam(); targ != nil {
|
||||
targBound := targ.Bound()
|
||||
if len(targBound.allTypes) == 0 {
|
||||
check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ)
|
||||
break
|
||||
|
|
@ -226,24 +226,24 @@ func (subst *subster) typ(typ Type) Type {
|
|||
case *Array:
|
||||
elem := subst.typ(t.elem)
|
||||
if elem != t.elem {
|
||||
return &Array{t.len, elem}
|
||||
return &Array{len: t.len, elem: elem}
|
||||
}
|
||||
|
||||
case *Slice:
|
||||
elem := subst.typ(t.elem)
|
||||
if elem != t.elem {
|
||||
return &Slice{elem}
|
||||
return &Slice{elem: elem}
|
||||
}
|
||||
|
||||
case *Struct:
|
||||
if fields, copied := subst.varList(t.fields); copied {
|
||||
return &Struct{fields, t.tags}
|
||||
return &Struct{fields: fields, tags: t.tags}
|
||||
}
|
||||
|
||||
case *Pointer:
|
||||
base := subst.typ(t.base)
|
||||
if base != t.base {
|
||||
return &Pointer{base}
|
||||
return &Pointer{base: base}
|
||||
}
|
||||
|
||||
case *Tuple:
|
||||
|
|
@ -256,7 +256,15 @@ func (subst *subster) typ(typ Type) Type {
|
|||
params := subst.tuple(t.params)
|
||||
results := subst.tuple(t.results)
|
||||
if recv != t.recv || params != t.params || results != t.results {
|
||||
return &Signature{t.rparams, t.tparams, t.scope, recv, params, results, t.variadic}
|
||||
return &Signature{
|
||||
rparams: t.rparams,
|
||||
tparams: t.tparams,
|
||||
scope: t.scope,
|
||||
recv: recv,
|
||||
params: params,
|
||||
results: results,
|
||||
variadic: t.variadic,
|
||||
}
|
||||
}
|
||||
|
||||
case *Interface:
|
||||
|
|
@ -274,13 +282,13 @@ func (subst *subster) typ(typ Type) Type {
|
|||
key := subst.typ(t.key)
|
||||
elem := subst.typ(t.elem)
|
||||
if key != t.key || elem != t.elem {
|
||||
return &Map{key, elem}
|
||||
return &Map{key: key, elem: elem}
|
||||
}
|
||||
|
||||
case *Chan:
|
||||
elem := subst.typ(t.elem)
|
||||
if elem != t.elem {
|
||||
return &Chan{t.dir, elem}
|
||||
return &Chan{dir: t.dir, elem: elem}
|
||||
}
|
||||
|
||||
case *Named:
|
||||
|
|
@ -398,7 +406,7 @@ func (subst *subster) var_(v *Var) *Var {
|
|||
func (subst *subster) tuple(t *Tuple) *Tuple {
|
||||
if t != nil {
|
||||
if vars, copied := subst.varList(t.vars); copied {
|
||||
return &Tuple{vars}
|
||||
return &Tuple{vars: vars}
|
||||
}
|
||||
}
|
||||
return t
|
||||
|
|
|
|||
|
|
@ -14,8 +14,38 @@ type Type interface {
|
|||
|
||||
// String returns a string representation of a type.
|
||||
String() string
|
||||
|
||||
// Converters
|
||||
Basic() *Basic
|
||||
Array() *Array
|
||||
Slice() *Slice
|
||||
Struct() *Struct
|
||||
Pointer() *Pointer
|
||||
Tuple() *Tuple
|
||||
Signature() *Signature
|
||||
Interface() *Interface
|
||||
Map() *Map
|
||||
Chan() *Chan
|
||||
Named() *Named
|
||||
TypeParam() *TypeParam
|
||||
}
|
||||
|
||||
// aType implements default type behavior
|
||||
type aType struct{}
|
||||
|
||||
func (aType) Basic() *Basic { return nil }
|
||||
func (aType) Array() *Array { return nil }
|
||||
func (aType) Slice() *Slice { return nil }
|
||||
func (aType) Struct() *Struct { return nil }
|
||||
func (aType) Pointer() *Pointer { return nil }
|
||||
func (aType) Tuple() *Tuple { return nil }
|
||||
func (aType) Signature() *Signature { return nil }
|
||||
func (aType) Interface() *Interface { return nil }
|
||||
func (aType) Map() *Map { return nil }
|
||||
func (aType) Chan() *Chan { return nil }
|
||||
func (aType) Named() *Named { return nil }
|
||||
func (aType) TypeParam() *TypeParam { return nil }
|
||||
|
||||
// BasicKind describes the kind of basic type.
|
||||
type BasicKind int
|
||||
|
||||
|
|
@ -79,6 +109,7 @@ type Basic struct {
|
|||
kind BasicKind
|
||||
info BasicInfo
|
||||
name string
|
||||
aType
|
||||
}
|
||||
|
||||
// Kind returns the kind of basic type b.
|
||||
|
|
@ -94,11 +125,12 @@ func (b *Basic) Name() string { return b.name }
|
|||
type Array struct {
|
||||
len int64
|
||||
elem Type
|
||||
aType
|
||||
}
|
||||
|
||||
// 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, elem} }
|
||||
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.
|
||||
|
|
@ -110,10 +142,11 @@ func (a *Array) Elem() Type { return a.elem }
|
|||
// A Slice represents a slice type.
|
||||
type Slice struct {
|
||||
elem Type
|
||||
aType
|
||||
}
|
||||
|
||||
// NewSlice returns a new slice type for the given element type.
|
||||
func NewSlice(elem Type) *Slice { return &Slice{elem} }
|
||||
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 }
|
||||
|
|
@ -122,6 +155,7 @@ func (s *Slice) Elem() Type { return s.elem }
|
|||
type Struct struct {
|
||||
fields []*Var
|
||||
tags []string // field tags; nil if there are no tags
|
||||
aType
|
||||
}
|
||||
|
||||
// NewStruct returns a new struct with the given fields and corresponding field tags.
|
||||
|
|
@ -158,6 +192,7 @@ func (s *Struct) Tag(i int) string {
|
|||
// A Pointer represents a pointer type.
|
||||
type Pointer struct {
|
||||
base Type // element type
|
||||
aType
|
||||
}
|
||||
|
||||
// NewPointer returns a new pointer type for the given element (base) type.
|
||||
|
|
@ -171,16 +206,23 @@ func (p *Pointer) Elem() Type { return p.base }
|
|||
// assignments; they are not first class types of Go.
|
||||
type Tuple struct {
|
||||
vars []*Var
|
||||
aType
|
||||
}
|
||||
|
||||
// NewTuple returns a new tuple for the given variables.
|
||||
func NewTuple(x ...*Var) *Tuple {
|
||||
if len(x) > 0 {
|
||||
return &Tuple{x}
|
||||
return &Tuple{vars: x}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// We cannot rely on the embedded Basic() method because (*Tuple)(nil)
|
||||
// is a valid *Tuple value but (*Tuple)(nil).Basic() would panic without
|
||||
// this implementation.
|
||||
// TODO(gri) It seems that at the moment we only need this converter.
|
||||
func (*Tuple) Basic() *Basic { return nil }
|
||||
|
||||
// Len returns the number variables of tuple t.
|
||||
func (t *Tuple) Len() int {
|
||||
if t != nil {
|
||||
|
|
@ -206,6 +248,7 @@ type Signature struct {
|
|||
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)
|
||||
aType
|
||||
}
|
||||
|
||||
// NewSignature returns a new function type for the given receiver, parameters,
|
||||
|
|
@ -222,7 +265,7 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
|
|||
panic("types.NewSignature: variadic parameter must be of unnamed slice type")
|
||||
}
|
||||
}
|
||||
return &Signature{nil, nil, nil, recv, params, results, variadic}
|
||||
return &Signature{recv: recv, params: params, results: results, variadic: variadic}
|
||||
}
|
||||
|
||||
// Recv returns the receiver of signature s (if a method), or nil if a
|
||||
|
|
@ -256,6 +299,8 @@ type Interface struct {
|
|||
|
||||
allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset)
|
||||
allTypes []Type // list of types declared with or embedded in this interface
|
||||
|
||||
aType
|
||||
}
|
||||
|
||||
// is reports whether interface t represents types that all satisfy pred.
|
||||
|
|
@ -374,23 +419,23 @@ func (t *Interface) Empty() bool {
|
|||
|
||||
// empty reports whether interface t is empty without requiring the
|
||||
// interface to be complete. Should only be called by Interface.Empty.
|
||||
func empty(t *Interface, visited map[*Interface]bool) bool {
|
||||
func empty(t *Interface, seen map[*Interface]bool) bool {
|
||||
if len(t.methods) != 0 || len(t.types) != 0 {
|
||||
return false
|
||||
}
|
||||
for _, e := range t.embeddeds {
|
||||
// e should be an interface but be careful (it may be invalid)
|
||||
if e, _ := e.Underlying().(*Interface); e != nil {
|
||||
if e := e.Interface(); e != 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 visited[e] {
|
||||
if seen[e] {
|
||||
continue
|
||||
}
|
||||
if visited == nil {
|
||||
visited = make(map[*Interface]bool)
|
||||
if seen == nil {
|
||||
seen = make(map[*Interface]bool)
|
||||
}
|
||||
visited[e] = true
|
||||
if !empty(e, visited) {
|
||||
seen[e] = true
|
||||
if !empty(e, seen) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -444,7 +489,7 @@ func (t *Interface) Complete() *Interface {
|
|||
types = append(types, t.types...)
|
||||
|
||||
for _, typ := range t.embeddeds {
|
||||
typ := typ.Underlying().(*Interface)
|
||||
typ := typ.Interface()
|
||||
typ.Complete()
|
||||
for _, m := range typ.allMethods {
|
||||
addMethod(m, false)
|
||||
|
|
@ -472,11 +517,12 @@ func (t *Interface) Complete() *Interface {
|
|||
// A Map represents a map type.
|
||||
type Map struct {
|
||||
key, elem Type
|
||||
aType
|
||||
}
|
||||
|
||||
// NewMap returns a new map for the given key and element types.
|
||||
func NewMap(key, elem Type) *Map {
|
||||
return &Map{key, elem}
|
||||
return &Map{key: key, elem: elem}
|
||||
}
|
||||
|
||||
// Key returns the key type of map m.
|
||||
|
|
@ -489,6 +535,7 @@ func (m *Map) Elem() Type { return m.elem }
|
|||
type Chan struct {
|
||||
dir ChanDir
|
||||
elem Type
|
||||
aType
|
||||
}
|
||||
|
||||
// A ChanDir value indicates a channel direction.
|
||||
|
|
@ -503,7 +550,7 @@ const (
|
|||
|
||||
// NewChan returns a new channel type for the given direction and element type.
|
||||
func NewChan(dir ChanDir, elem Type) *Chan {
|
||||
return &Chan{dir, elem}
|
||||
return &Chan{dir: dir, elem: elem}
|
||||
}
|
||||
|
||||
// Dir returns the direction of channel c.
|
||||
|
|
@ -521,6 +568,7 @@ type Named struct {
|
|||
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
|
||||
aType
|
||||
}
|
||||
|
||||
// NewNamed returns a new named type for the given type name, underlying type, and associated methods.
|
||||
|
|
@ -540,6 +588,21 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
|
|||
// Obj returns the type name for the named type t.
|
||||
func (t *Named) Obj() *TypeName { return t.obj }
|
||||
|
||||
// Converter methods
|
||||
func (t *Named) Basic() *Basic { return t.Underlying().Basic() }
|
||||
func (t *Named) Array() *Array { return t.Underlying().Array() }
|
||||
func (t *Named) Slice() *Slice { return t.Underlying().Slice() }
|
||||
func (t *Named) Struct() *Struct { return t.Underlying().Struct() }
|
||||
func (t *Named) Pointer() *Pointer { return t.Underlying().Pointer() }
|
||||
func (t *Named) Tuple() *Tuple { return t.Underlying().Tuple() }
|
||||
func (t *Named) Signature() *Signature { return t.Underlying().Signature() }
|
||||
func (t *Named) Interface() *Interface { return t.Underlying().Interface() }
|
||||
func (t *Named) Map() *Map { return t.Underlying().Map() }
|
||||
func (t *Named) Chan() *Chan { return t.Underlying().Chan() }
|
||||
|
||||
// func (t *Named) Named() *Named // declared below
|
||||
func (t *Named) TypeParam() *TypeParam { return t.Underlying().TypeParam() }
|
||||
|
||||
// TODO(gri) Come up with a better representation and API to distinguish
|
||||
// between parameterized instantiated and non-instantiated types.
|
||||
|
||||
|
|
@ -583,12 +646,13 @@ type TypeParam struct {
|
|||
obj *TypeName // corresponding type name
|
||||
index int // parameter index
|
||||
bound Type // *Named or *Interface; underlying type is always *Interface
|
||||
aType
|
||||
}
|
||||
|
||||
// NewTypeParam returns a new TypeParam.
|
||||
func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypeParam {
|
||||
assert(bound != nil)
|
||||
typ := &TypeParam{check.nextId, obj, index, bound}
|
||||
typ := &TypeParam{id: check.nextId, obj: obj, index: index, bound: bound}
|
||||
check.nextId++
|
||||
if obj.typ == nil {
|
||||
obj.typ = typ
|
||||
|
|
@ -596,36 +660,73 @@ func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypePa
|
|||
return typ
|
||||
}
|
||||
|
||||
func (t *TypeParam) Interface() *Interface {
|
||||
iface := t.bound.Underlying().(*Interface)
|
||||
func (t *TypeParam) Bound() *Interface {
|
||||
iface := t.bound.Interface()
|
||||
iface.Complete() // TODO(gri) should we use check.completeInterface instead?
|
||||
return iface
|
||||
}
|
||||
|
||||
// Implementations for Type methods.
|
||||
|
||||
func (b *Basic) Underlying() Type { return b }
|
||||
func (a *Array) Underlying() Type { return a }
|
||||
func (s *Slice) Underlying() Type { return s }
|
||||
func (s *Struct) Underlying() Type { return s }
|
||||
func (p *Pointer) Underlying() Type { return p }
|
||||
func (t *Tuple) Underlying() Type { return t }
|
||||
func (s *Signature) Underlying() Type { return s }
|
||||
func (t *Interface) Underlying() Type { return t }
|
||||
func (m *Map) Underlying() Type { return m }
|
||||
func (c *Chan) Underlying() Type { return c }
|
||||
func (t *Named) Underlying() Type { return t.underlying }
|
||||
func (t *TypeParam) Underlying() Type { return t } // TODO(gri) should this return t.Interface() instead?
|
||||
func (t *Basic) Basic() *Basic { return t }
|
||||
func (t *Array) Array() *Array { return t }
|
||||
func (t *Slice) Slice() *Slice { return t }
|
||||
func (t *Struct) Struct() *Struct { return t }
|
||||
func (t *Pointer) Pointer() *Pointer { return t }
|
||||
func (t *Tuple) Tuple() *Tuple { return t }
|
||||
func (t *Signature) Signature() *Signature { return t }
|
||||
func (t *Interface) Interface() *Interface { return t }
|
||||
func (t *Map) Map() *Map { return t }
|
||||
func (t *Chan) Chan() *Chan { return t }
|
||||
func (t *Named) Named() *Named { return t }
|
||||
func (t *TypeParam) TypeParam() *TypeParam { return t }
|
||||
|
||||
func (b *Basic) String() string { return TypeString(b, nil) }
|
||||
func (a *Array) String() string { return TypeString(a, nil) }
|
||||
func (s *Slice) String() string { return TypeString(s, nil) }
|
||||
func (s *Struct) String() string { return TypeString(s, nil) }
|
||||
func (p *Pointer) String() string { return TypeString(p, nil) }
|
||||
func (t *Basic) Underlying() Type { return t }
|
||||
func (t *Array) Underlying() Type { return t }
|
||||
func (t *Slice) Underlying() Type { return t }
|
||||
func (t *Struct) Underlying() Type { return t }
|
||||
func (t *Pointer) Underlying() Type { return t }
|
||||
func (t *Tuple) Underlying() Type { return t }
|
||||
func (t *Signature) Underlying() Type { return t }
|
||||
func (t *Interface) Underlying() Type { return t }
|
||||
func (t *Map) Underlying() Type { return t }
|
||||
func (t *Chan) Underlying() Type { return t }
|
||||
func (t *Named) Underlying() Type {
|
||||
var u Type
|
||||
var seen map[*Named]bool
|
||||
// TODO(gri) If we have a chain of named types, update the
|
||||
// underlying types once we have found the bottom
|
||||
// (optimization).
|
||||
for {
|
||||
u = t.underlying
|
||||
if u == nil {
|
||||
return Typ[Invalid]
|
||||
}
|
||||
n, ok := t.underlying.(*Named)
|
||||
if !ok {
|
||||
return u // not a *Named type
|
||||
}
|
||||
if seen[t] {
|
||||
return Typ[Invalid] // we have a cycle
|
||||
}
|
||||
if seen == nil {
|
||||
seen = make(map[*Named]bool)
|
||||
}
|
||||
seen[t] = true
|
||||
t = n
|
||||
}
|
||||
}
|
||||
func (t *TypeParam) Underlying() Type { return t }
|
||||
|
||||
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 *Struct) 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 (s *Signature) String() string { return TypeString(s, nil) }
|
||||
func (t *Signature) String() string { return TypeString(t, nil) }
|
||||
func (t *Interface) String() string { return TypeString(t, nil) }
|
||||
func (m *Map) String() string { return TypeString(m, nil) }
|
||||
func (c *Chan) String() string { return TypeString(c, 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) }
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited
|
|||
var writeBounds bool
|
||||
for _, p := range list {
|
||||
// bound(p) should be an interface but be careful (it may be invalid)
|
||||
b, _ := bound(p).Underlying().(*Interface)
|
||||
b := bound(p).Interface()
|
||||
if b != nil && !b.Empty() {
|
||||
writeBounds = true
|
||||
break
|
||||
|
|
@ -371,7 +371,7 @@ func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visi
|
|||
} else {
|
||||
// special case:
|
||||
// append(s, "foo"...) leads to signature func([]byte, string...)
|
||||
if t, ok := typ.Underlying().(*Basic); !ok || t.kind != String {
|
||||
if t := typ.Basic(); t == nil || t.kind != String {
|
||||
panic("internal error: string type expected")
|
||||
}
|
||||
writeType(buf, typ, qf, visited)
|
||||
|
|
|
|||
|
|
@ -34,39 +34,39 @@ var (
|
|||
// Use Universe.Lookup("byte").Type() to obtain the specific
|
||||
// alias basic type named "byte" (and analogous for "rune").
|
||||
var Typ = []*Basic{
|
||||
Invalid: {Invalid, 0, "invalid type"},
|
||||
Invalid: {Invalid, 0, "invalid type", aType{}},
|
||||
|
||||
Bool: {Bool, IsBoolean, "bool"},
|
||||
Int: {Int, IsInteger, "int"},
|
||||
Int8: {Int8, IsInteger, "int8"},
|
||||
Int16: {Int16, IsInteger, "int16"},
|
||||
Int32: {Int32, IsInteger, "int32"},
|
||||
Int64: {Int64, IsInteger, "int64"},
|
||||
Uint: {Uint, IsInteger | IsUnsigned, "uint"},
|
||||
Uint8: {Uint8, IsInteger | IsUnsigned, "uint8"},
|
||||
Uint16: {Uint16, IsInteger | IsUnsigned, "uint16"},
|
||||
Uint32: {Uint32, IsInteger | IsUnsigned, "uint32"},
|
||||
Uint64: {Uint64, IsInteger | IsUnsigned, "uint64"},
|
||||
Uintptr: {Uintptr, IsInteger | IsUnsigned, "uintptr"},
|
||||
Float32: {Float32, IsFloat, "float32"},
|
||||
Float64: {Float64, IsFloat, "float64"},
|
||||
Complex64: {Complex64, IsComplex, "complex64"},
|
||||
Complex128: {Complex128, IsComplex, "complex128"},
|
||||
String: {String, IsString, "string"},
|
||||
UnsafePointer: {UnsafePointer, 0, "Pointer"},
|
||||
Bool: {Bool, IsBoolean, "bool", aType{}},
|
||||
Int: {Int, IsInteger, "int", aType{}},
|
||||
Int8: {Int8, IsInteger, "int8", aType{}},
|
||||
Int16: {Int16, IsInteger, "int16", aType{}},
|
||||
Int32: {Int32, IsInteger, "int32", aType{}},
|
||||
Int64: {Int64, IsInteger, "int64", aType{}},
|
||||
Uint: {Uint, IsInteger | IsUnsigned, "uint", aType{}},
|
||||
Uint8: {Uint8, IsInteger | IsUnsigned, "uint8", aType{}},
|
||||
Uint16: {Uint16, IsInteger | IsUnsigned, "uint16", aType{}},
|
||||
Uint32: {Uint32, IsInteger | IsUnsigned, "uint32", aType{}},
|
||||
Uint64: {Uint64, IsInteger | IsUnsigned, "uint64", aType{}},
|
||||
Uintptr: {Uintptr, IsInteger | IsUnsigned, "uintptr", aType{}},
|
||||
Float32: {Float32, IsFloat, "float32", aType{}},
|
||||
Float64: {Float64, IsFloat, "float64", aType{}},
|
||||
Complex64: {Complex64, IsComplex, "complex64", aType{}},
|
||||
Complex128: {Complex128, IsComplex, "complex128", aType{}},
|
||||
String: {String, IsString, "string", aType{}},
|
||||
UnsafePointer: {UnsafePointer, 0, "Pointer", aType{}},
|
||||
|
||||
UntypedBool: {UntypedBool, IsBoolean | IsUntyped, "untyped bool"},
|
||||
UntypedInt: {UntypedInt, IsInteger | IsUntyped, "untyped int"},
|
||||
UntypedRune: {UntypedRune, IsInteger | IsUntyped, "untyped rune"},
|
||||
UntypedFloat: {UntypedFloat, IsFloat | IsUntyped, "untyped float"},
|
||||
UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, "untyped complex"},
|
||||
UntypedString: {UntypedString, IsString | IsUntyped, "untyped string"},
|
||||
UntypedNil: {UntypedNil, IsUntyped, "untyped nil"},
|
||||
UntypedBool: {UntypedBool, IsBoolean | IsUntyped, "untyped bool", aType{}},
|
||||
UntypedInt: {UntypedInt, IsInteger | IsUntyped, "untyped int", aType{}},
|
||||
UntypedRune: {UntypedRune, IsInteger | IsUntyped, "untyped rune", aType{}},
|
||||
UntypedFloat: {UntypedFloat, IsFloat | IsUntyped, "untyped float", aType{}},
|
||||
UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, "untyped complex", aType{}},
|
||||
UntypedString: {UntypedString, IsString | IsUntyped, "untyped string", aType{}},
|
||||
UntypedNil: {UntypedNil, IsUntyped, "untyped nil", aType{}},
|
||||
}
|
||||
|
||||
var aliases = [...]*Basic{
|
||||
{Byte, IsInteger | IsUnsigned, "byte"},
|
||||
{Rune, IsInteger, "rune"},
|
||||
{Byte, IsInteger | IsUnsigned, "byte", aType{}},
|
||||
{Rune, IsInteger, "rune", aType{}},
|
||||
}
|
||||
|
||||
func defPredeclaredTypes() {
|
||||
|
|
@ -214,7 +214,7 @@ func defPredeclaredContracts() {
|
|||
// The interface is parameterized with a single
|
||||
// type parameter to match the comparable contract.
|
||||
pname := NewTypeName(token.NoPos, nil, "T", nil)
|
||||
pname.typ = &TypeParam{0, pname, 0, &emptyInterface}
|
||||
pname.typ = &TypeParam{0, pname, 0, &emptyInterface, aType{}}
|
||||
|
||||
// The type bound interface needs a name so we can attach the
|
||||
// type parameter and to match the usual set up of contracts.
|
||||
|
|
|
|||
Loading…
Reference in New Issue