Commit 152279f2 authored by Robert Griesemer's avatar Robert Griesemer

exp/types: Replace String method with TypeString function

This is more in sync with the rest of the package;
for instance, we have functions (not methods) to
deref or find the underlying type of a Type.

In the process use a single bytes.Buffer to create
the string representation for a type rather than
the (occasional) string concatenation.

R=r
CC=golang-dev
https://golang.org/cl/6458057
parent dcb6f598
...@@ -17,7 +17,6 @@ import ( ...@@ -17,7 +17,6 @@ import (
// All types implement the Type interface. // All types implement the Type interface.
type Type interface { type Type interface {
isType() isType()
String() string
} }
// All concrete types embed implementsType which // All concrete types embed implementsType which
...@@ -32,21 +31,12 @@ type Bad struct { ...@@ -32,21 +31,12 @@ type Bad struct {
Msg string // for better error reporting/debugging Msg string // for better error reporting/debugging
} }
func (t *Bad) String() string {
return fmt.Sprintf("badType(%s)", t.Msg)
}
// A Basic represents a (unnamed) basic type. // A Basic represents a (unnamed) basic type.
type Basic struct { type Basic struct {
implementsType implementsType
// TODO(gri) need a field specifying the exact basic type // TODO(gri) need a field specifying the exact basic type
} }
func (t *Basic) String() string {
// TODO(gri) print actual type information
return "basicType"
}
// An Array represents an array type [Len]Elt. // An Array represents an array type [Len]Elt.
type Array struct { type Array struct {
implementsType implementsType
...@@ -54,20 +44,12 @@ type Array struct { ...@@ -54,20 +44,12 @@ type Array struct {
Elt Type Elt Type
} }
func (t *Array) String() string {
return fmt.Sprintf("[%d]%s", t.Len, t.Elt)
}
// A Slice represents a slice type []Elt. // A Slice represents a slice type []Elt.
type Slice struct { type Slice struct {
implementsType implementsType
Elt Type Elt Type
} }
func (t *Slice) String() string {
return "[]" + t.Elt.String()
}
// A Struct represents a struct type struct{...}. // A Struct represents a struct type struct{...}.
// Anonymous fields are represented by objects with empty names. // Anonymous fields are represented by objects with empty names.
type Struct struct { type Struct struct {
...@@ -80,35 +62,12 @@ type Struct struct { ...@@ -80,35 +62,12 @@ type Struct struct {
// - there is no scope for fast lookup (but the parser creates one) // - there is no scope for fast lookup (but the parser creates one)
} }
func (t *Struct) String() string {
buf := bytes.NewBufferString("struct{")
for i, fld := range t.Fields {
if i > 0 {
buf.WriteString("; ")
}
if fld.Name != "" {
buf.WriteString(fld.Name)
buf.WriteByte(' ')
}
buf.WriteString(fld.Type.(Type).String())
if i < len(t.Tags) && t.Tags[i] != "" {
fmt.Fprintf(buf, " %q", t.Tags[i])
}
}
buf.WriteByte('}')
return buf.String()
}
// A Pointer represents a pointer type *Base. // A Pointer represents a pointer type *Base.
type Pointer struct { type Pointer struct {
implementsType implementsType
Base Type Base Type
} }
func (t *Pointer) String() string {
return "*" + t.Base.String()
}
// A Func represents a function type func(...) (...). // A Func represents a function type func(...) (...).
// Unnamed parameters are represented by objects with empty names. // Unnamed parameters are represented by objects with empty names.
type Func struct { type Func struct {
...@@ -119,6 +78,33 @@ type Func struct { ...@@ -119,6 +78,33 @@ type Func struct {
IsVariadic bool // true if the last parameter's type is of the form ...T IsVariadic bool // true if the last parameter's type is of the form ...T
} }
// An Interface represents an interface type interface{...}.
type Interface struct {
implementsType
Methods ObjList // interface methods sorted by name; or nil
}
// A Map represents a map type map[Key]Elt.
type Map struct {
implementsType
Key, Elt Type
}
// A Chan represents a channel type chan Elt, <-chan Elt, or chan<-Elt.
type Chan struct {
implementsType
Dir ast.ChanDir
Elt Type
}
// A Name represents a named type as declared in a type declaration.
type Name struct {
implementsType
Underlying Type // nil if not fully declared
Obj *ast.Object // corresponding declared object
// TODO(gri) need to remember fields and methods.
}
func writeParams(buf *bytes.Buffer, params ObjList, isVariadic bool) { func writeParams(buf *bytes.Buffer, params ObjList, isVariadic bool) {
buf.WriteByte('(') buf.WriteByte('(')
for i, par := range params { for i, par := range params {
...@@ -132,7 +118,7 @@ func writeParams(buf *bytes.Buffer, params ObjList, isVariadic bool) { ...@@ -132,7 +118,7 @@ func writeParams(buf *bytes.Buffer, params ObjList, isVariadic bool) {
if isVariadic && i == len(params)-1 { if isVariadic && i == len(params)-1 {
buf.WriteString("...") buf.WriteString("...")
} }
buf.WriteString(par.Type.(Type).String()) writeType(buf, par.Type.(Type))
} }
buf.WriteByte(')') buf.WriteByte(')')
} }
...@@ -147,7 +133,7 @@ func writeSignature(buf *bytes.Buffer, t *Func) { ...@@ -147,7 +133,7 @@ func writeSignature(buf *bytes.Buffer, t *Func) {
buf.WriteByte(' ') buf.WriteByte(' ')
if len(t.Results) == 1 && t.Results[0].Name == "" { if len(t.Results) == 1 && t.Results[0].Name == "" {
// single unnamed result // single unnamed result
buf.WriteString(t.Results[0].Type.(Type).String()) writeType(buf, t.Results[0].Type.(Type))
return return
} }
...@@ -155,20 +141,49 @@ func writeSignature(buf *bytes.Buffer, t *Func) { ...@@ -155,20 +141,49 @@ func writeSignature(buf *bytes.Buffer, t *Func) {
writeParams(buf, t.Results, false) writeParams(buf, t.Results, false)
} }
func (t *Func) String() string { func writeType(buf *bytes.Buffer, typ Type) {
buf := bytes.NewBufferString("func") switch t := typ.(type) {
writeSignature(buf, t) case *Bad:
return buf.String() fmt.Fprintf(buf, "badType(%s)", t.Msg)
}
// An Interface represents an interface type interface{...}. case *Basic:
type Interface struct { buf.WriteString("basicType") // TODO(gri) print actual type information
implementsType
Methods ObjList // interface methods sorted by name; or nil case *Array:
} fmt.Fprintf(buf, "[%d]", t.Len)
writeType(buf, t.Elt)
case *Slice:
buf.WriteString("[]")
writeType(buf, t.Elt)
func (t *Interface) String() string { case *Struct:
buf := bytes.NewBufferString("interface{") buf.WriteString("struct{")
for i, fld := range t.Fields {
if i > 0 {
buf.WriteString("; ")
}
if fld.Name != "" {
buf.WriteString(fld.Name)
buf.WriteByte(' ')
}
writeType(buf, fld.Type.(Type))
if i < len(t.Tags) && t.Tags[i] != "" {
fmt.Fprintf(buf, " %q", t.Tags[i])
}
}
buf.WriteByte('}')
case *Pointer:
buf.WriteByte('*')
writeType(buf, t.Base)
case *Func:
buf.WriteString("func")
writeSignature(buf, t)
case *Interface:
buf.WriteString("interface{")
for i, m := range t.Methods { for i, m := range t.Methods {
if i > 0 { if i > 0 {
buf.WriteString("; ") buf.WriteString("; ")
...@@ -177,27 +192,14 @@ func (t *Interface) String() string { ...@@ -177,27 +192,14 @@ func (t *Interface) String() string {
writeSignature(buf, m.Type.(*Func)) writeSignature(buf, m.Type.(*Func))
} }
buf.WriteByte('}') buf.WriteByte('}')
return buf.String()
}
// A Map represents a map type map[Key]Elt.
type Map struct {
implementsType
Key, Elt Type
}
func (t *Map) String() string { case *Map:
return fmt.Sprintf("map[%s]%s", t.Key, t.Elt) buf.WriteString("map[")
} writeType(buf, t.Key)
buf.WriteByte(']')
// A Chan represents a channel type chan Elt, <-chan Elt, or chan<-Elt. writeType(buf, t.Elt)
type Chan struct {
implementsType
Dir ast.ChanDir
Elt Type
}
func (t *Chan) String() string { case *Chan:
var s string var s string
switch t.Dir { switch t.Dir {
case ast.SEND: case ast.SEND:
...@@ -207,19 +209,20 @@ func (t *Chan) String() string { ...@@ -207,19 +209,20 @@ func (t *Chan) String() string {
default: default:
s = "chan " s = "chan "
} }
return s + t.Elt.String() buf.WriteString(s)
} writeType(buf, t.Elt)
// A Name represents a named type as declared in a type declaration. case *Name:
type Name struct { buf.WriteString(t.Obj.Name)
implementsType
Underlying Type // nil if not fully declared }
Obj *ast.Object // corresponding declared object
// TODO(gri) need to remember fields and methods.
} }
func (t *Name) String() string { // TypeString returns a string representation for typ.
return t.Obj.Name func TypeString(typ Type) string {
var buf bytes.Buffer
writeType(&buf, typ)
return buf.String()
} }
// If typ is a pointer type, Deref returns the pointer's base type; // If typ is a pointer type, Deref returns the pointer's base type;
......
...@@ -120,7 +120,7 @@ func TestTypes(t *testing.T) { ...@@ -120,7 +120,7 @@ func TestTypes(t *testing.T) {
continue continue
} }
typ := Underlying(pkg.Scope.Lookup("T").Type.(Type)) typ := Underlying(pkg.Scope.Lookup("T").Type.(Type))
str := typ.String() str := TypeString(typ)
if str != test.str { if str != test.str {
t.Errorf("%s: got %s, want %s", test.src, str, test.str) t.Errorf("%s: got %s, want %s", test.src, str, test.str)
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment