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,71 +141,88 @@ func writeSignature(buf *bytes.Buffer, t *Func) { ...@@ -155,71 +141,88 @@ 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
}
func (t *Interface) String() string { case *Array:
buf := bytes.NewBufferString("interface{") fmt.Fprintf(buf, "[%d]", t.Len)
for i, m := range t.Methods { writeType(buf, t.Elt)
if i > 0 {
buf.WriteString("; ") case *Slice:
buf.WriteString("[]")
writeType(buf, t.Elt)
case *Struct:
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.WriteString(m.Name) buf.WriteByte('}')
writeSignature(buf, m.Type.(*Func))
}
buf.WriteByte('}')
return buf.String()
}
// A Map represents a map type map[Key]Elt. case *Pointer:
type Map struct { buf.WriteByte('*')
implementsType writeType(buf, t.Base)
Key, Elt Type
}
func (t *Map) String() string { case *Func:
return fmt.Sprintf("map[%s]%s", t.Key, t.Elt) buf.WriteString("func")
} writeSignature(buf, t)
// A Chan represents a channel type chan Elt, <-chan Elt, or chan<-Elt. case *Interface:
type Chan struct { buf.WriteString("interface{")
implementsType for i, m := range t.Methods {
Dir ast.ChanDir if i > 0 {
Elt Type buf.WriteString("; ")
} }
buf.WriteString(m.Name)
writeSignature(buf, m.Type.(*Func))
}
buf.WriteByte('}')
func (t *Chan) String() string { case *Map:
var s string buf.WriteString("map[")
switch t.Dir { writeType(buf, t.Key)
case ast.SEND: buf.WriteByte(']')
s = "chan<- " writeType(buf, t.Elt)
case ast.RECV:
s = "<-chan "
default:
s = "chan "
}
return s + t.Elt.String()
}
// A Name represents a named type as declared in a type declaration. case *Chan:
type Name struct { var s string
implementsType switch t.Dir {
Underlying Type // nil if not fully declared case ast.SEND:
Obj *ast.Object // corresponding declared object s = "chan<- "
// TODO(gri) need to remember fields and methods. case ast.RECV:
s = "<-chan "
default:
s = "chan "
}
buf.WriteString(s)
writeType(buf, t.Elt)
case *Name:
buf.WriteString(t.Obj.Name)
}
} }
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