[dev.typeparams] cmd/compile/internal/types2: use converter functions rather than methods

This change replaces methods with functions to reduce the API surface of
types2.Type and to match the approach taken in go/types. The converter
methods for Named and TypeParam will be addressed in a follow-up CL.

Also: Fixed behavior of optype to return the underlying type for
      arguments that are not type parameters.

Change-Id: Ia369c796754bc33bbaf0c9c8478badecb729279b
Reviewed-on: https://go-review.googlesource.com/c/go/+/293291
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-02-17 16:04:59 -08:00
parent 5ecb9a7887
commit 5e4da8670b
15 changed files with 108 additions and 155 deletions

View file

@ -129,16 +129,5 @@ func (t anyType) Under() types2.Type { return t }
func (t anyType) String() string { return "any" } func (t anyType) String() string { return "any" }
// types2.aType is not exported for now so we need to implemented these here. // types2.aType is not exported for now so we need to implemented these here.
func (anyType) Basic() *types2.Basic { return nil }
func (anyType) Array() *types2.Array { return nil }
func (anyType) Slice() *types2.Slice { return nil }
func (anyType) Struct() *types2.Struct { return nil }
func (anyType) Pointer() *types2.Pointer { return nil }
func (anyType) Tuple() *types2.Tuple { return nil }
func (anyType) Signature() *types2.Signature { return nil }
func (anyType) Sum() *types2.Sum { return nil }
func (anyType) Interface() *types2.Interface { return nil }
func (anyType) Map() *types2.Map { return nil }
func (anyType) Chan() *types2.Chan { return nil }
func (anyType) Named() *types2.Named { return nil } func (anyType) Named() *types2.Named { return nil }
func (anyType) TypeParam() *types2.TypeParam { return nil } func (anyType) TypeParam() *types2.TypeParam { return nil }

View file

@ -52,7 +52,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
// x.typ is typed // x.typ is typed
// A generic (non-instantiated) function value cannot be assigned to a variable. // A generic (non-instantiated) function value cannot be assigned to a variable.
if sig := x.typ.Signature(); sig != nil && len(sig.tparams) > 0 { if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
check.errorf(x, "cannot use generic function %s without instantiation in %s", x, context) check.errorf(x, "cannot use generic function %s without instantiation in %s", x, context)
} }

View file

@ -82,7 +82,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// of S and the respective parameter passing rules apply." // of S and the respective parameter passing rules apply."
S := x.typ S := x.typ
var T Type var T Type
if s := S.Slice(); s != nil { if s := asSlice(S); s != nil {
T = s.elem T = s.elem
} else { } else {
check.invalidArgf(x, "%s is not a slice", x) check.invalidArgf(x, "%s is not a slice", x)
@ -210,7 +210,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
case _Close: case _Close:
// close(c) // close(c)
c := x.typ.Chan() c := asChan(x.typ)
if c == nil { if c == nil {
check.invalidArgf(x, "%s is not a channel", x) check.invalidArgf(x, "%s is not a channel", x)
return return
@ -286,7 +286,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// the argument types must be of floating-point type // the argument types must be of floating-point type
f := func(x Type) Type { f := func(x Type) Type {
if t := x.Basic(); t != nil { if t := asBasic(x); t != nil {
switch t.kind { switch t.kind {
case Float32: case Float32:
return Typ[Complex64] return Typ[Complex64]
@ -320,7 +320,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
case _Copy: case _Copy:
// copy(x, y []T) int // copy(x, y []T) int
var dst Type var dst Type
if t := x.typ.Slice(); t != nil { if t := asSlice(x.typ); t != nil {
dst = t.elem dst = t.elem
} }
@ -357,7 +357,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
case _Delete: case _Delete:
// delete(m, k) // delete(m, k)
m := x.typ.Map() m := asMap(x.typ)
if m == nil { if m == nil {
check.invalidArgf(x, "%s is not a map", x) check.invalidArgf(x, "%s is not a map", x)
return return
@ -404,7 +404,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// the argument must be of complex type // the argument must be of complex type
f := func(x Type) Type { f := func(x Type) Type {
if t := x.Basic(); t != nil { if t := asBasic(x); t != nil {
switch t.kind { switch t.kind {
case Complex64: case Complex64:
return Typ[Float32] return Typ[Float32]
@ -757,7 +757,7 @@ func makeSig(res Type, args ...Type) *Signature {
// //
func implicitArrayDeref(typ Type) Type { func implicitArrayDeref(typ Type) Type {
if p, ok := typ.(*Pointer); ok { if p, ok := typ.(*Pointer); ok {
if a := p.base.Array(); a != nil { if a := asArray(p.base); a != nil {
return a return a
} }
} }

View file

@ -121,7 +121,7 @@ func (check *Checker) call(x *operand, call *syntax.CallExpr) exprKind {
case 1: case 1:
check.expr(x, call.ArgList[0]) check.expr(x, call.ArgList[0])
if x.mode != invalid { if x.mode != invalid {
if t := T.Interface(); t != nil { if t := asInterface(T); t != nil {
check.completeInterface(nopos, t) check.completeInterface(nopos, t)
if t.IsConstraint() { if t.IsConstraint() {
check.errorf(call, "cannot use interface %s in conversion (contains type list or is comparable)", T) check.errorf(call, "cannot use interface %s in conversion (contains type list or is comparable)", T)
@ -157,7 +157,7 @@ func (check *Checker) call(x *operand, call *syntax.CallExpr) exprKind {
// function/method call // function/method call
cgocall := x.mode == cgofunc cgocall := x.mode == cgofunc
sig := x.typ.Signature() sig := asSignature(x.typ)
if sig == nil { if sig == nil {
check.invalidOpf(x, "cannot call non-function %s", x) check.invalidOpf(x, "cannot call non-function %s", x)
x.mode = invalid x.mode = invalid

View file

@ -21,7 +21,7 @@ func (check *Checker) conversion(x *operand, T Type) {
switch { switch {
case constArg && isConstType(T): case constArg && isConstType(T):
// constant conversion // constant conversion
switch t := T.Basic(); { switch t := asBasic(T); {
case representableConst(x.val, check, t, &x.val): case representableConst(x.val, check, t, &x.val):
ok = true ok = true
case isInteger(x.typ) && isString(t): case isInteger(x.typ) && isString(t):
@ -140,26 +140,26 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
} }
func isUintptr(typ Type) bool { func isUintptr(typ Type) bool {
t := typ.Basic() t := asBasic(typ)
return t != nil && t.kind == Uintptr return t != nil && t.kind == Uintptr
} }
func isUnsafePointer(typ Type) bool { func isUnsafePointer(typ Type) bool {
// TODO(gri): Is this typ.Basic() instead of typ.(*Basic) correct? // TODO(gri): Is this asBasic(typ) instead of typ.(*Basic) correct?
// (The former calls typ.Under(), while the latter doesn't.) // (The former calls typ.Under(), while the latter doesn't.)
// The spec does not say so, but gc claims it is. See also // The spec does not say so, but gc claims it is. See also
// issue 6326. // issue 6326.
t := typ.Basic() t := asBasic(typ)
return t != nil && t.kind == UnsafePointer return t != nil && t.kind == UnsafePointer
} }
func isPointer(typ Type) bool { func isPointer(typ Type) bool {
return typ.Pointer() != nil return asPointer(typ) != nil
} }
func isBytesOrRunes(typ Type) bool { func isBytesOrRunes(typ Type) bool {
if s := typ.Slice(); s != nil { if s := asSlice(typ); s != nil {
t := s.elem.Basic() t := asBasic(s.elem)
return t != nil && (t.kind == Byte || t.kind == Rune) return t != nil && (t.kind == Byte || t.kind == Rune)
} }
return false return false

View file

@ -110,7 +110,7 @@ func (check *Checker) overflow(x *operand) {
// Typed constants must be representable in // Typed constants must be representable in
// their type after each constant operation. // their type after each constant operation.
if isTyped(x.typ) { if isTyped(x.typ) {
check.representable(x, x.typ.Basic()) check.representable(x, asBasic(x.typ))
return return
} }
@ -173,7 +173,7 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) {
return return
case syntax.Recv: case syntax.Recv:
typ := x.typ.Chan() typ := asChan(x.typ)
if typ == nil { if typ == nil {
check.invalidOpf(x, "cannot receive from non-channel %s", x) check.invalidOpf(x, "cannot receive from non-channel %s", x)
x.mode = invalid x.mode = invalid
@ -543,7 +543,7 @@ func (check *Checker) updateExprType(x syntax.Expr, typ Type, final bool) {
// If the new type is not final and still untyped, just // If the new type is not final and still untyped, just
// update the recorded type. // update the recorded type.
if !final && isUntyped(typ) { if !final && isUntyped(typ) {
old.typ = typ.Basic() old.typ = asBasic(typ)
check.untyped[x] = old check.untyped[x] = old
return return
} }
@ -1396,7 +1396,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
duplicate := false duplicate := false
// if the key is of interface type, the type is also significant when checking for duplicates // if the key is of interface type, the type is also significant when checking for duplicates
xkey := keyVal(x.val) xkey := keyVal(x.val)
if utyp.key.Interface() != nil { if asInterface(utyp.key) != nil {
for _, vtyp := range visited[xkey] { for _, vtyp := range visited[xkey] {
if check.identical(vtyp, x.typ) { if check.identical(vtyp, x.typ) {
duplicate = true duplicate = true
@ -1465,7 +1465,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
} }
if x.mode == value { if x.mode == value {
if sig := x.typ.Signature(); sig != nil && len(sig.tparams) > 0 { if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
// function instantiation // function instantiation
check.funcInst(x, e) check.funcInst(x, e)
return expression return expression
@ -1498,7 +1498,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
x.typ = typ.elem x.typ = typ.elem
case *Pointer: case *Pointer:
if typ := typ.base.Array(); typ != nil { if typ := asArray(typ.base); typ != nil {
valid = true valid = true
length = typ.len length = typ.len
x.mode = variable x.mode = variable
@ -1536,7 +1536,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
case *Array: case *Array:
e = t.elem e = t.elem
case *Pointer: case *Pointer:
if t := t.base.Array(); t != nil { if t := asArray(t.base); t != nil {
e = t.elem e = t.elem
} }
case *Slice: case *Slice:
@ -1665,7 +1665,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
x.typ = &Slice{elem: typ.elem} x.typ = &Slice{elem: typ.elem}
case *Pointer: case *Pointer:
if typ := typ.base.Array(); typ != nil { if typ := asArray(typ.base); typ != nil {
valid = true valid = true
length = typ.len length = typ.len
x.typ = &Slice{elem: typ.elem} x.typ = &Slice{elem: typ.elem}
@ -1797,7 +1797,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
case typexpr: case typexpr:
x.typ = &Pointer{base: x.typ} x.typ = &Pointer{base: x.typ}
default: default:
if typ := x.typ.Pointer(); typ != nil { if typ := asPointer(x.typ); typ != nil {
x.mode = variable x.mode = variable
x.typ = typ.base x.typ = typ.base
} else { } else {

View file

@ -391,7 +391,7 @@ func TestIssue28005(t *testing.T) {
if obj == nil { if obj == nil {
t.Fatal("object X not found") t.Fatal("object X not found")
} }
iface := obj.Type().Interface() // object X must be an interface iface := obj.Type().Underlying().(*Interface) // object X must be an interface
if iface == nil { if iface == nil {
t.Fatalf("%s is not an interface", obj) t.Fatalf("%s is not an interface", obj)
} }
@ -414,7 +414,7 @@ func TestIssue28282(t *testing.T) {
it := NewInterfaceType(nil, []Type{et}) it := NewInterfaceType(nil, []Type{et})
it.Complete() it.Complete()
// verify that after completing the interface, the embedded method remains unchanged // verify that after completing the interface, the embedded method remains unchanged
want := et.Interface().Method(0) want := et.Underlying().(*Interface).Method(0)
got := it.Method(0) got := it.Method(0)
if got != want { if got != want {
t.Fatalf("%s.Method(0): got %q (%p); want %q (%p)", it, got, got, want, want) t.Fatalf("%s.Method(0): got %q (%p); want %q (%p)", it, got, got, want, want)

View file

@ -314,7 +314,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
return return
} }
if ityp := V.Interface(); ityp != nil { if ityp := asInterface(V); ityp != nil {
check.completeInterface(nopos, ityp) check.completeInterface(nopos, ityp)
// TODO(gri) allMethods is sorted - can do this more efficiently // TODO(gri) allMethods is sorted - can do this more efficiently
for _, m := range T.allMethods { for _, m := range T.allMethods {
@ -434,7 +434,7 @@ func (check *Checker) assertableTo(V *Interface, T Type, strict bool) (method, w
// no static check is required if T is an interface // no static check is required if T is an interface
// spec: "If T is an interface type, x.(T) asserts that the // spec: "If T is an interface type, x.(T) asserts that the
// dynamic type of x implements the interface T." // dynamic type of x implements the interface T."
if T.Interface() != nil && !(strict || forceStrict) { if asInterface(T) != nil && !(strict || forceStrict) {
return return
} }
return check.missingMethod(T, V, false) return check.missingMethod(T, V, false)
@ -452,8 +452,8 @@ func deref(typ Type) (Type, bool) {
// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a // 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. // (named or unnamed) struct and returns its base. Otherwise it returns typ.
func derefStructPtr(typ Type) Type { func derefStructPtr(typ Type) Type {
if p := typ.Pointer(); p != nil { if p := asPointer(typ); p != nil {
if p.base.Struct() != nil { if asStruct(p.base) != nil {
return p.base return p.base
} }
} }

View file

@ -79,7 +79,7 @@ func isConstType(typ Type) bool {
// IsInterface reports whether typ is an interface type. // IsInterface reports whether typ is an interface type.
func IsInterface(typ Type) bool { func IsInterface(typ Type) bool {
return typ.Interface() != nil return asInterface(typ) != nil
} }
// Comparable reports whether values of type T are comparable. // Comparable reports whether values of type T are comparable.

View file

@ -241,7 +241,7 @@ func (conf *Config) offsetsof(T *Struct) []int64 {
func (conf *Config) offsetof(typ Type, index []int) int64 { func (conf *Config) offsetof(typ Type, index []int) int64 {
var o int64 var o int64
for _, i := range index { for _, i := range index {
s := typ.Struct() s := asStruct(typ)
o += conf.offsetsof(s)[i] o += conf.offsetsof(s)[i]
typ = s.fields[i].typ typ = s.fields[i].typ
} }

View file

@ -241,7 +241,7 @@ func typecheck(t *testing.T, path string, filenames []string) {
// Perform checks of API invariants. // Perform checks of API invariants.
// All Objects have a package, except predeclared ones. // All Objects have a package, except predeclared ones.
errorError := Universe.Lookup("error").Type().Interface().ExplicitMethod(0) // (error).Error errorError := Universe.Lookup("error").Type().Underlying().(*Interface).ExplicitMethod(0) // (error).Error
for id, obj := range info.Uses { for id, obj := range info.Uses {
predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError
if predeclared == (obj.Pkg() != nil) { if predeclared == (obj.Pkg() != nil) {

View file

@ -351,7 +351,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
return return
} }
tch := ch.typ.Chan() tch := asChan(ch.typ)
if tch == nil { if tch == nil {
check.invalidOpf(s, "cannot send to non-chan type %s", ch.typ) check.invalidOpf(s, "cannot send to non-chan type %s", ch.typ)
return return
@ -890,7 +890,7 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
case *Slice: case *Slice:
return Typ[Int], typ.elem, "" return Typ[Int], typ.elem, ""
case *Pointer: case *Pointer:
if typ := typ.base.Array(); typ != nil { if typ := asArray(typ.base); typ != nil {
return Typ[Int], typ.elem, "" return Typ[Int], typ.elem, ""
} }
case *Map: case *Map:

View file

@ -27,24 +27,6 @@ type Type interface {
// String returns a string representation of a type. // String returns a string representation of a type.
String() string String() string
// Converters
// A converter must only be called when a type is
// known to be fully set up. A converter returns
// a type's operational type (see comment for optype)
// or nil if the type is receiver is not of the
// respective type.
Basic() *Basic
Array() *Array
Slice() *Slice
Struct() *Struct
Pointer() *Pointer
Tuple() *Tuple
Signature() *Signature
Sum() *Sum
Interface() *Interface
Map() *Map
Chan() *Chan
// If the receiver for Named and TypeParam is of // If the receiver for Named and TypeParam is of
// the respective type (possibly after unpacking // the respective type (possibly after unpacking
// an instance type), these methods return that // an instance type), these methods return that
@ -61,21 +43,6 @@ func (aType) Underlying() Type { panic("unreachable") }
func (aType) Under() Type { panic("unreachable") } func (aType) Under() Type { panic("unreachable") }
func (aType) String() string { panic("unreachable") } func (aType) String() string { panic("unreachable") }
// Each type is implementing its version of these methods
// (Basic must implement Basic, etc.), the other methods
// are inherited.
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) Sum() *Sum { 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) Named() *Named { return nil }
func (aType) TypeParam() *TypeParam { return nil } func (aType) TypeParam() *TypeParam { return nil }
@ -256,18 +223,6 @@ func NewTuple(x ...*Var) *Tuple {
// but add all because missing one leads to very confusing bugs. // but add all because missing one leads to very confusing bugs.
// TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer; // TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer;
// it's too subtle and causes problems. // it's too subtle and causes problems.
func (*Tuple) Basic() *Basic { return nil }
func (*Tuple) Array() *Array { return nil }
func (*Tuple) Slice() *Slice { return nil }
func (*Tuple) Struct() *Struct { return nil }
func (*Tuple) Pointer() *Pointer { return nil }
// func (*Tuple) Tuple() *Tuple // implemented below
func (*Tuple) Signature() *Signature { return nil }
func (*Tuple) Sum() *Sum { return nil }
func (*Tuple) Interface() *Interface { return nil }
func (*Tuple) Map() *Map { return nil }
func (*Tuple) Chan() *Chan { return nil }
func (*Tuple) Named() *Named { return nil } func (*Tuple) Named() *Named { return nil }
func (*Tuple) TypeParam() *TypeParam { return nil } func (*Tuple) TypeParam() *TypeParam { return nil }
@ -408,7 +363,7 @@ func unpack(typ Type) []Type {
if typ == nil { if typ == nil {
return nil return nil
} }
if sum := typ.Sum(); sum != nil { if sum := asSum(typ); sum != nil {
return sum.types return sum.types
} }
return []Type{typ} return []Type{typ}
@ -594,7 +549,7 @@ func (t *Interface) iterate(f func(*Interface) bool, seen map[*Interface]bool) b
} }
for _, e := range t.embeddeds { for _, e := range t.embeddeds {
// e should be an interface but be careful (it may be invalid) // e should be an interface but be careful (it may be invalid)
if e := e.Interface(); e != nil { if e := asInterface(e); e != nil {
// Cyclic interfaces such as "type E interface { E }" are not permitted // Cyclic interfaces such as "type E interface { E }" are not permitted
// but they are still constructed and we need to detect such cycles. // but they are still constructed and we need to detect such cycles.
if seen[e] { if seen[e] {
@ -661,7 +616,7 @@ func (t *Interface) Complete() *Interface {
for _, typ := range t.embeddeds { for _, typ := range t.embeddeds {
utyp := typ.Under() utyp := typ.Under()
etyp := utyp.Interface() etyp := asInterface(utyp)
if etyp == nil { if etyp == nil {
if utyp != Typ[Invalid] { if utyp != Typ[Invalid] {
panic(fmt.Sprintf("%s is not an interface", typ)) panic(fmt.Sprintf("%s is not an interface", typ))
@ -775,18 +730,6 @@ func (check *Checker) NewNamed(obj *TypeName, underlying Type, methods []*Func)
// Obj returns the type name for the named type t. // Obj returns the type name for the named type t.
func (t *Named) Obj() *TypeName { return t.obj } func (t *Named) Obj() *TypeName { return t.obj }
// Converter methods
func (t *Named) Basic() *Basic { return t.Under().Basic() }
func (t *Named) Array() *Array { return t.Under().Array() }
func (t *Named) Slice() *Slice { return t.Under().Slice() }
func (t *Named) Struct() *Struct { return t.Under().Struct() }
func (t *Named) Pointer() *Pointer { return t.Under().Pointer() }
func (t *Named) Tuple() *Tuple { return t.Under().Tuple() }
func (t *Named) Signature() *Signature { return t.Under().Signature() }
func (t *Named) Interface() *Interface { return t.Under().Interface() }
func (t *Named) Map() *Map { return t.Under().Map() }
func (t *Named) Chan() *Chan { return t.Under().Chan() }
// func (t *Named) Named() *Named // declared below // func (t *Named) Named() *Named // declared below
func (t *Named) TypeParam() *TypeParam { return t.Under().TypeParam() } func (t *Named) TypeParam() *TypeParam { return t.Under().TypeParam() }
@ -853,7 +796,7 @@ func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypePa
} }
func (t *TypeParam) Bound() *Interface { func (t *TypeParam) Bound() *Interface {
iface := t.bound.Interface() iface := asInterface(t.bound)
// use the type bound position if we have one // use the type bound position if we have one
pos := nopos pos := nopos
if n, _ := t.bound.(*Named); n != nil { if n, _ := t.bound.(*Named); n != nil {
@ -884,22 +827,9 @@ func optype(typ Type) Type {
} }
return theTop return theTop
} }
return typ return typ.Under()
} }
// Converter methods
func (t *TypeParam) Basic() *Basic { return optype(t).Basic() }
func (t *TypeParam) Array() *Array { return optype(t).Array() }
func (t *TypeParam) Slice() *Slice { return optype(t).Slice() }
func (t *TypeParam) Struct() *Struct { return optype(t).Struct() }
func (t *TypeParam) Pointer() *Pointer { return optype(t).Pointer() }
func (t *TypeParam) Tuple() *Tuple { return optype(t).Tuple() }
func (t *TypeParam) Signature() *Signature { return optype(t).Signature() }
func (t *TypeParam) Sum() *Sum { return optype(t).Sum() }
func (t *TypeParam) Interface() *Interface { return optype(t).Interface() }
func (t *TypeParam) Map() *Map { return optype(t).Map() }
func (t *TypeParam) Chan() *Chan { return optype(t).Chan() }
// func (t *TypeParam) Named() *Named // Named does not unpack type parameters // func (t *TypeParam) Named() *Named // Named does not unpack type parameters
// func (t *TypeParam) TypeParam() *TypeParam // declared below // func (t *TypeParam) TypeParam() *TypeParam // declared below
@ -917,19 +847,6 @@ type instance struct {
aType aType
} }
// Converter methods
func (t *instance) Basic() *Basic { return t.Under().Basic() }
func (t *instance) Array() *Array { return t.Under().Array() }
func (t *instance) Slice() *Slice { return t.Under().Slice() }
func (t *instance) Struct() *Struct { return t.Under().Struct() }
func (t *instance) Pointer() *Pointer { return t.Under().Pointer() }
func (t *instance) Tuple() *Tuple { return t.Under().Tuple() }
func (t *instance) Signature() *Signature { return t.Under().Signature() }
func (t *instance) Sum() *Sum { return t.Under().Sum() }
func (t *instance) Interface() *Interface { return t.Under().Interface() }
func (t *instance) Map() *Map { return t.Under().Map() }
func (t *instance) Chan() *Chan { return t.Under().Chan() }
func (t *instance) Named() *Named { return t.expand().Named() } func (t *instance) Named() *Named { return t.expand().Named() }
func (t *instance) TypeParam() *TypeParam { return t.expand().TypeParam() } func (t *instance) TypeParam() *TypeParam { return t.expand().TypeParam() }
@ -991,19 +908,6 @@ type top struct {
// theTop is the singleton top type. // theTop is the singleton top type.
var theTop = &top{} var theTop = &top{}
// Type-specific implementations of type converters.
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 *Sum) Sum() *Sum { 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 *Named) Named() *Named { return t }
func (t *TypeParam) TypeParam() *TypeParam { return t } func (t *TypeParam) TypeParam() *TypeParam { return t }
@ -1061,3 +965,63 @@ func (t *TypeParam) String() string { return TypeString(t, nil) }
func (t *instance) String() string { return TypeString(t, nil) } func (t *instance) String() string { return TypeString(t, nil) }
func (t *bottom) String() string { return TypeString(t, nil) } func (t *bottom) String() string { return TypeString(t, nil) }
func (t *top) String() string { return TypeString(t, nil) } func (t *top) String() string { return TypeString(t, nil) }
// Converters
//
// A converter must only be called when a type is
// known to be fully set up. A converter returns
// a type's operational type (see comment for optype)
// or nil if the type argument is not of the
// respective type.
func asBasic(t Type) *Basic {
op, _ := optype(t).(*Basic)
return op
}
func asArray(t Type) *Array {
op, _ := optype(t).(*Array)
return op
}
func asSlice(t Type) *Slice {
op, _ := optype(t).(*Slice)
return op
}
func asStruct(t Type) *Struct {
op, _ := optype(t).(*Struct)
return op
}
func asPointer(t Type) *Pointer {
op, _ := optype(t).(*Pointer)
return op
}
// asTuple is not needed - not provided
func asSignature(t Type) *Signature {
op, _ := optype(t).(*Signature)
return op
}
func asSum(t Type) *Sum {
op, _ := optype(t).(*Sum)
return op
}
func asInterface(t Type) *Interface {
op, _ := optype(t).(*Interface)
return op
}
func asMap(t Type) *Map {
op, _ := optype(t).(*Map)
return op
}
func asChan(t Type) *Chan {
op, _ := optype(t).(*Chan)
return op
}

View file

@ -327,7 +327,7 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited
var writeBounds bool var writeBounds bool
for _, p := range list { for _, p := range list {
// bound(p) should be an interface but be careful (it may be invalid) // bound(p) should be an interface but be careful (it may be invalid)
b := bound(p).Interface() b := asInterface(bound(p))
if b != nil && !b.Empty() { if b != nil && !b.Empty() {
writeBounds = true writeBounds = true
break break
@ -395,7 +395,7 @@ func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visi
} else { } else {
// special case: // special case:
// append(s, "foo"...) leads to signature func([]byte, string...) // append(s, "foo"...) leads to signature func([]byte, string...)
if t := typ.Basic(); t == nil || t.kind != String { if t := asBasic(typ); t == nil || t.kind != String {
panic("internal error: string type expected") panic("internal error: string type expected")
} }
writeType(buf, typ, qf, visited) writeType(buf, typ, qf, visited)

View file

@ -142,7 +142,7 @@ func (check *Checker) ordinaryType(pos syntax.Pos, typ Type) {
// are in the middle of type-checking parameter declarations that might belong to // are in the middle of type-checking parameter declarations that might belong to
// interface methods. Delay this check to the end of type-checking. // interface methods. Delay this check to the end of type-checking.
check.atEnd(func() { check.atEnd(func() {
if t := typ.Interface(); t != nil { if t := asInterface(typ); t != nil {
check.completeInterface(pos, t) // TODO(gri) is this the correct position? check.completeInterface(pos, t) // TODO(gri) is this the correct position?
if t.allTypes != nil { if t.allTypes != nil {
check.softErrorf(pos, "interface contains type constraints (%s)", t.allTypes) check.softErrorf(pos, "interface contains type constraints (%s)", t.allTypes)
@ -403,7 +403,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
err = "pointer or interface type" err = "pointer or interface type"
} }
} }
} else if T := t.Basic(); T != nil { } else if T := asBasic(t); T != nil {
err = "basic or unnamed type" err = "basic or unnamed type"
if check.conf.CompilerErrorMessages { if check.conf.CompilerErrorMessages {
check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ) check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
@ -968,7 +968,7 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) {
for i, typ := range ityp.embeddeds { for i, typ := range ityp.embeddeds {
pos := posList[i] // embedding position pos := posList[i] // embedding position
utyp := typ.Under() utyp := typ.Under()
etyp := utyp.Interface() etyp := asInterface(utyp)
if etyp == nil { if etyp == nil {
if utyp != Typ[Invalid] { if utyp != Typ[Invalid] {
var format string var format string
@ -1226,7 +1226,7 @@ func (check *Checker) collectTypeConstraints(pos syntax.Pos, types []syntax.Expr
// Note: This is a quadratic algorithm, but type lists tend to be short. // Note: This is a quadratic algorithm, but type lists tend to be short.
check.atEnd(func() { check.atEnd(func() {
for i, t := range list { for i, t := range list {
if t := t.Interface(); t != nil { if t := asInterface(t); t != nil {
check.completeInterface(types[i].Pos(), t) check.completeInterface(types[i].Pos(), t)
} }
if includes(list[:i], t) { if includes(list[:i], t) {