]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile/internal/types2: use converter functions rather than...
authorRobert Griesemer <gri@golang.org>
Thu, 18 Feb 2021 00:04:59 +0000 (16:04 -0800)
committerRobert Griesemer <gri@golang.org>
Thu, 18 Feb 2021 20:47:07 +0000 (20:47 +0000)
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>
15 files changed:
src/cmd/compile/internal/importer/support.go
src/cmd/compile/internal/types2/assignments.go
src/cmd/compile/internal/types2/builtins.go
src/cmd/compile/internal/types2/call.go
src/cmd/compile/internal/types2/conversions.go
src/cmd/compile/internal/types2/expr.go
src/cmd/compile/internal/types2/issues_test.go
src/cmd/compile/internal/types2/lookup.go
src/cmd/compile/internal/types2/predicates.go
src/cmd/compile/internal/types2/sizes.go
src/cmd/compile/internal/types2/stdlib_test.go
src/cmd/compile/internal/types2/stmt.go
src/cmd/compile/internal/types2/type.go
src/cmd/compile/internal/types2/typestring.go
src/cmd/compile/internal/types2/typexpr.go

index 4f013f4a515aed3a92bc790929832e6eaca730d2..cac87745fe20932cd18be6feb7eb3bcaf74604b5 100644 (file)
@@ -129,16 +129,5 @@ func (t anyType) Under() types2.Type      { return t }
 func (t anyType) String() string          { return "any" }
 
 // 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) TypeParam() *types2.TypeParam { return nil }
index 6caa4863d5bd885190e7352b99381232a3ff9dfa..00495f39761e9ff6227e01327279accc5324813b 100644 (file)
@@ -52,7 +52,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.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)
        }
 
index 591a22f814c5e8f7e4a3e49a6243ad67fe0ca9c0..763122bc5bcd165beead7d82d8ef863c6d415630 100644 (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."
                S := x.typ
                var T Type
-               if s := S.Slice(); s != nil {
+               if s := asSlice(S); s != nil {
                        T = s.elem
                } else {
                        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:
                // close(c)
-               c := x.typ.Chan()
+               c := asChan(x.typ)
                if c == nil {
                        check.invalidArgf(x, "%s is not a channel", x)
                        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
                f := func(x Type) Type {
-                       if t := x.Basic(); t != nil {
+                       if t := asBasic(x); t != nil {
                                switch t.kind {
                                case Float32:
                                        return Typ[Complex64]
@@ -320,7 +320,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
        case _Copy:
                // copy(x, y []T) int
                var dst Type
-               if t := x.typ.Slice(); t != nil {
+               if t := asSlice(x.typ); t != nil {
                        dst = t.elem
                }
 
@@ -357,7 +357,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
 
        case _Delete:
                // delete(m, k)
-               m := x.typ.Map()
+               m := asMap(x.typ)
                if m == nil {
                        check.invalidArgf(x, "%s is not a map", x)
                        return
@@ -404,7 +404,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
 
                // the argument must be of complex type
                f := func(x Type) Type {
-                       if t := x.Basic(); t != nil {
+                       if t := asBasic(x); t != nil {
                                switch t.kind {
                                case Complex64:
                                        return Typ[Float32]
@@ -757,7 +757,7 @@ func makeSig(res Type, args ...Type) *Signature {
 //
 func implicitArrayDeref(typ Type) Type {
        if p, ok := typ.(*Pointer); ok {
-               if a := p.base.Array(); a != nil {
+               if a := asArray(p.base); a != nil {
                        return a
                }
        }
index 72a33b50b17f0f053aa64ceb00eda9b5c36124d1..10db701324c3beec306204018a621a026789640a 100644 (file)
@@ -121,7 +121,7 @@ func (check *Checker) call(x *operand, call *syntax.CallExpr) exprKind {
                case 1:
                        check.expr(x, call.ArgList[0])
                        if x.mode != invalid {
-                               if t := T.Interface(); t != nil {
+                               if t := asInterface(T); t != nil {
                                        check.completeInterface(nopos, t)
                                        if t.IsConstraint() {
                                                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
                cgocall := x.mode == cgofunc
 
-               sig := x.typ.Signature()
+               sig := asSignature(x.typ)
                if sig == nil {
                        check.invalidOpf(x, "cannot call non-function %s", x)
                        x.mode = invalid
index 90c08fb72f6395b7d6469b455d2efb3aae726fc0..c9603b263c19fc5bf5d9dbae9f78e9ed69074f8e 100644 (file)
@@ -21,7 +21,7 @@ func (check *Checker) conversion(x *operand, T Type) {
        switch {
        case constArg && isConstType(T):
                // constant conversion
-               switch t := T.Basic(); {
+               switch t := asBasic(T); {
                case representableConst(x.val, check, t, &x.val):
                        ok = true
                case isInteger(x.typ) && isString(t):
@@ -140,26 +140,26 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
 }
 
 func isUintptr(typ Type) bool {
-       t := typ.Basic()
+       t := asBasic(typ)
        return t != nil && t.kind == Uintptr
 }
 
 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 spec does not say so, but gc claims it is. See also
        //            issue 6326.
-       t := typ.Basic()
+       t := asBasic(typ)
        return t != nil && t.kind == UnsafePointer
 }
 
 func isPointer(typ Type) bool {
-       return typ.Pointer() != nil
+       return asPointer(typ) != nil
 }
 
 func isBytesOrRunes(typ Type) bool {
-       if s := typ.Slice(); s != nil {
-               t := s.elem.Basic()
+       if s := asSlice(typ); s != nil {
+               t := asBasic(s.elem)
                return t != nil && (t.kind == Byte || t.kind == Rune)
        }
        return false
index 9889e3113dd4d35507107fd3e09c27da80811b7b..07b23c9effeaf4d82bfe62d67115c11bb9459aea 100644 (file)
@@ -110,7 +110,7 @@ func (check *Checker) overflow(x *operand) {
        // Typed constants must be representable in
        // their type after each constant operation.
        if isTyped(x.typ) {
-               check.representable(x, x.typ.Basic())
+               check.representable(x, asBasic(x.typ))
                return
        }
 
@@ -173,7 +173,7 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) {
                return
 
        case syntax.Recv:
-               typ := x.typ.Chan()
+               typ := asChan(x.typ)
                if typ == nil {
                        check.invalidOpf(x, "cannot receive from non-channel %s", x)
                        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
        // update the recorded type.
        if !final && isUntyped(typ) {
-               old.typ = typ.Basic()
+               old.typ = asBasic(typ)
                check.untyped[x] = old
                return
        }
@@ -1396,7 +1396,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                                        duplicate := false
                                        // if the key is of interface type, the type is also significant when checking for duplicates
                                        xkey := keyVal(x.val)
-                                       if utyp.key.Interface() != nil {
+                                       if asInterface(utyp.key) != nil {
                                                for _, vtyp := range visited[xkey] {
                                                        if check.identical(vtyp, x.typ) {
                                                                duplicate = true
@@ -1465,7 +1465,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                }
 
                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
                                check.funcInst(x, e)
                                return expression
@@ -1498,7 +1498,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                        x.typ = typ.elem
 
                case *Pointer:
-                       if typ := typ.base.Array(); typ != nil {
+                       if typ := asArray(typ.base); typ != nil {
                                valid = true
                                length = typ.len
                                x.mode = variable
@@ -1536,7 +1536,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                                case *Array:
                                        e = t.elem
                                case *Pointer:
-                                       if t := t.base.Array(); t != nil {
+                                       if t := asArray(t.base); t != nil {
                                                e = t.elem
                                        }
                                case *Slice:
@@ -1665,7 +1665,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                        x.typ = &Slice{elem: typ.elem}
 
                case *Pointer:
-                       if typ := typ.base.Array(); typ != nil {
+                       if typ := asArray(typ.base); typ != nil {
                                valid = true
                                length = typ.len
                                x.typ = &Slice{elem: typ.elem}
@@ -1797,7 +1797,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                                case typexpr:
                                        x.typ = &Pointer{base: x.typ}
                                default:
-                                       if typ := x.typ.Pointer(); typ != nil {
+                                       if typ := asPointer(x.typ); typ != nil {
                                                x.mode = variable
                                                x.typ = typ.base
                                        } else {
index 9a73a46d116e100da521fd6fbd9f868ca7652784..5a32fa590acf689ebbc1920c9a198d52e5406d10 100644 (file)
@@ -391,7 +391,7 @@ func TestIssue28005(t *testing.T) {
                if obj == nil {
                        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 {
                        t.Fatalf("%s is not an interface", obj)
                }
@@ -414,7 +414,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.Interface().Method(0)
+       want := et.Underlying().(*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)
index 5dfb8bfee71cc83adb0c2720d4da30f8f8138177..df25c9cf701a6a17c26dde4575d7dd6da8ae0a59 100644 (file)
@@ -314,7 +314,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
                return
        }
 
-       if ityp := V.Interface(); ityp != nil {
+       if ityp := asInterface(V); ityp != nil {
                check.completeInterface(nopos, ityp)
                // TODO(gri) allMethods is sorted - can do this more efficiently
                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
        // spec: "If T is an interface type, x.(T) asserts that the
        //        dynamic type of x implements the interface T."
-       if T.Interface() != nil && !(strict || forceStrict) {
+       if asInterface(T) != nil && !(strict || forceStrict) {
                return
        }
        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
 // (named or unnamed) struct and returns its base. Otherwise it returns typ.
 func derefStructPtr(typ Type) Type {
-       if p := typ.Pointer(); p != nil {
-               if p.base.Struct() != nil {
+       if p := asPointer(typ); p != nil {
+               if asStruct(p.base) != nil {
                        return p.base
                }
        }
index b8fa15cdb83a27c007345bda4132ae370e8b5bcb..a7972c6928b8e8b4e6d48b51534a194f58b4d244 100644 (file)
@@ -79,7 +79,7 @@ func isConstType(typ Type) bool {
 
 // IsInterface reports whether typ is an interface type.
 func IsInterface(typ Type) bool {
-       return typ.Interface() != nil
+       return asInterface(typ) != nil
 }
 
 // Comparable reports whether values of type T are comparable.
index 9945dcd10c326041bba77c298e4b265238ef3561..9d8f3ae5ad2d96e69cdc05392149041a9ddaf4db 100644 (file)
@@ -241,7 +241,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.Struct()
+               s := asStruct(typ)
                o += conf.offsetsof(s)[i]
                typ = s.fields[i].typ
        }
index 0477e549983db4dfcafefbbcf8b0dd000b01e9bb..34925687e3589ab27d74d75c8925268d2a569537 100644 (file)
@@ -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().Interface().ExplicitMethod(0) // (error).Error
+       errorError := Universe.Lookup("error").Type().Underlying().(*Interface).ExplicitMethod(0) // (error).Error
        for id, obj := range info.Uses {
                predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError
                if predeclared == (obj.Pkg() != nil) {
index bab56b22ef85cfb1ca32618ebfab5e51de9c5b10..9d74e0e588c9072e8137eb01ff1848c4bfeac4ac 100644 (file)
@@ -351,7 +351,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
                        return
                }
 
-               tch := ch.typ.Chan()
+               tch := asChan(ch.typ)
                if tch == nil {
                        check.invalidOpf(s, "cannot send to non-chan type %s", ch.typ)
                        return
@@ -890,7 +890,7 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
        case *Slice:
                return Typ[Int], typ.elem, ""
        case *Pointer:
-               if typ := typ.base.Array(); typ != nil {
+               if typ := asArray(typ.base); typ != nil {
                        return Typ[Int], typ.elem, ""
                }
        case *Map:
index 7e51a138b5f0d702c2e7c7f73152e034a3695dd0..f90abba8da3399245168d596063f970b953fc821 100644 (file)
@@ -27,24 +27,6 @@ type Type interface {
        // String returns a string representation of a type.
        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
        // the respective type (possibly after unpacking
        // 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) 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) TypeParam() *TypeParam { return nil }
 
@@ -256,18 +223,6 @@ func NewTuple(x ...*Var) *Tuple {
 // but add all because missing one leads to very confusing bugs.
 // TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer;
 //           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) TypeParam() *TypeParam { return nil }
@@ -408,7 +363,7 @@ func unpack(typ Type) []Type {
        if typ == nil {
                return nil
        }
-       if sum := typ.Sum(); sum != nil {
+       if sum := asSum(typ); sum != nil {
                return sum.types
        }
        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 {
                // 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
                        // but they are still constructed and we need to detect such cycles.
                        if seen[e] {
@@ -661,7 +616,7 @@ func (t *Interface) Complete() *Interface {
 
        for _, typ := range t.embeddeds {
                utyp := typ.Under()
-               etyp := utyp.Interface()
+               etyp := asInterface(utyp)
                if etyp == nil {
                        if utyp != Typ[Invalid] {
                                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.
 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) 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 {
-       iface := t.bound.Interface()
+       iface := asInterface(t.bound)
        // use the type bound position if we have one
        pos := nopos
        if n, _ := t.bound.(*Named); n != nil {
@@ -884,22 +827,9 @@ func optype(typ Type) Type {
                }
                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) TypeParam() *TypeParam // declared below
 
@@ -917,19 +847,6 @@ type instance struct {
        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) TypeParam() *TypeParam { return t.expand().TypeParam() }
 
@@ -991,19 +908,6 @@ type top struct {
 // theTop is the singleton top type.
 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 *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 *bottom) 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
+}
index 6b6d7ad2be32a4e2dbadd9470cba3674c6cbdae4..4d778df43f5788c7f5a78d9b1b70c8df27d6079d 100644 (file)
@@ -327,7 +327,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).Interface()
+               b := asInterface(bound(p))
                if b != nil && !b.Empty() {
                        writeBounds = true
                        break
@@ -395,7 +395,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 := typ.Basic(); t == nil || t.kind != String {
+                                       if t := asBasic(typ); t == nil || t.kind != String {
                                                panic("internal error: string type expected")
                                        }
                                        writeType(buf, typ, qf, visited)
index b67a35ed3056452ec241e1b040b1c92d05bba979..7ee28abac36c35c52381e03024f8a7ed830d77b7 100644 (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
        // interface methods. Delay this check to the end of type-checking.
        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?
                        if t.allTypes != nil {
                                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"
                                        }
                                }
-                       } else if T := t.Basic(); T != nil {
+                       } else if T := asBasic(t); T != nil {
                                err = "basic or unnamed type"
                                if check.conf.CompilerErrorMessages {
                                        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 {
                pos := posList[i] // embedding position
                utyp := typ.Under()
-               etyp := utyp.Interface()
+               etyp := asInterface(utyp)
                if etyp == nil {
                        if utyp != Typ[Invalid] {
                                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.
        check.atEnd(func() {
                for i, t := range list {
-                       if t := t.Interface(); t != nil {
+                       if t := asInterface(t); t != nil {
                                check.completeInterface(types[i].Pos(), t)
                        }
                        if includes(list[:i], t) {