1
0
mirror of https://github.com/golang/go synced 2024-11-19 00:04:40 -07:00

go.tools/go/types: complete set of Interface accessors

Also: Provide GcCompatibilityMode for printing types
(intended for testing with gc-generated export data
only).

(TBR adonovan)

R=adonovan
TBR=adonovan
CC=golang-codereviews
https://golang.org/cl/44780043
This commit is contained in:
Robert Griesemer 2013-12-20 16:35:31 -08:00
parent 8f712fcb98
commit e405e03b16
6 changed files with 98 additions and 36 deletions

View File

@ -522,7 +522,7 @@ func (check *checker) convertUntyped(x *operand, target Type) {
} }
} }
case *Interface: case *Interface:
if !x.isNil() && t.NumMethods() > 0 /* empty interfaces are ok */ { if !x.isNil() && !t.Empty() /* empty interfaces are ok */ {
goto Error goto Error
} }
// Update operand types to the default type rather then // Update operand types to the default type rather then
@ -535,7 +535,7 @@ func (check *checker) convertUntyped(x *operand, target Type) {
target = Typ[UntypedNil] target = Typ[UntypedNil]
} else { } else {
// cannot assign untyped values to non-empty interfaces // cannot assign untyped values to non-empty interfaces
if t.NumMethods() > 0 { if !t.Empty() {
goto Error goto Error
} }
target = defaultType(x.typ) target = defaultType(x.typ)

View File

@ -246,7 +246,7 @@ func consolidateMultiples(list []embeddedType) []embeddedType {
// //
func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) { func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
// fast path for common case // fast path for common case
if T.NumMethods() == 0 { if T.Empty() {
return return
} }

View File

@ -266,7 +266,7 @@ func (x *operand) isAssignableTo(conf *Config, T Type) bool {
return Vb.kind == UntypedBool && isBoolean(Tu) return Vb.kind == UntypedBool && isBoolean(Tu)
} }
case *Interface: case *Interface:
return x.isNil() || t.NumMethods() == 0 return x.isNil() || t.Empty()
case *Pointer, *Signature, *Slice, *Map, *Chan: case *Pointer, *Signature, *Slice, *Map, *Chan:
return x.isNil() return x.isNil()
} }

View File

@ -247,15 +247,15 @@ func (s *Signature) IsVariadic() bool { return s.isVariadic }
// An Interface represents an interface type. // An Interface represents an interface type.
type Interface struct { type Interface struct {
methods []*Func // explicitly declared methods methods []*Func // ordered list of explicitly declared methods
types []*Named // explicitly embedded types embeddeds []*Named // ordered list of explicitly embedded types
allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset) allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset)
mset cachedMethodSet // method set for interface, lazily initialized mset cachedMethodSet // method set for interface, lazily initialized
} }
// NewInterface returns a new interface for the given methods. // NewInterface returns a new interface for the given methods and embedded types.
func NewInterface(methods []*Func, types []*Named) *Interface { func NewInterface(methods []*Func, embeddeds []*Named) *Interface {
typ := new(Interface) typ := new(Interface)
var mset objset var mset objset
@ -271,11 +271,11 @@ func NewInterface(methods []*Func, types []*Named) *Interface {
sort.Sort(byUniqueMethodName(methods)) sort.Sort(byUniqueMethodName(methods))
var allMethods []*Func var allMethods []*Func
if types == nil { if embeddeds == nil {
allMethods = methods allMethods = methods
} else { } else {
allMethods = append(allMethods, methods...) allMethods = append(allMethods, methods...)
for _, t := range types { for _, t := range embeddeds {
it := t.Underlying().(*Interface) it := t.Underlying().(*Interface)
for _, tm := range it.allMethods { for _, tm := range it.allMethods {
// Make a copy of the method and adjust its receiver type. // Make a copy of the method and adjust its receiver type.
@ -286,21 +286,40 @@ func NewInterface(methods []*Func, types []*Named) *Interface {
allMethods = append(allMethods, &newm) allMethods = append(allMethods, &newm)
} }
} }
sort.Sort(byUniqueTypeName(embeddeds))
sort.Sort(byUniqueMethodName(allMethods)) sort.Sort(byUniqueMethodName(allMethods))
} }
typ.methods = methods typ.methods = methods
typ.types = types typ.embeddeds = embeddeds
typ.allMethods = allMethods typ.allMethods = allMethods
return typ return typ
} }
// NumMethods returns the number of methods of interface t. // NumExplicitMethods returns the number of explicitly declared methods of interface t.
func (t *Interface) NumExplicitMethods() int { return len(t.methods) }
// ExplicitMethod returns the i'th explicitly declared method of interface t for 0 <= i < t.NumExplicitMethods().
// The methods are ordered by their unique Id.
func (t *Interface) ExplicitMethod(i int) *Func { return t.methods[i] }
// NumEmbeddeds returns the number of embedded types in interface t.
func (t *Interface) NumEmbeddeds() int { return len(t.embeddeds) }
// Embedded returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds().
// The types are ordered by the corresponding TypeName's unique Id.
func (t *Interface) Embedded(i int) *Named { return t.embeddeds[i] }
// NumMethods returns the total number of methods of interface t.
func (t *Interface) NumMethods() int { return len(t.allMethods) } func (t *Interface) NumMethods() int { return len(t.allMethods) }
// Method returns the i'th method of interface t for 0 <= i < t.NumMethods(). // Method returns the i'th method of interface t for 0 <= i < t.NumMethods().
// The methods are ordered by their unique Id.
func (t *Interface) Method(i int) *Func { return t.allMethods[i] } func (t *Interface) Method(i int) *Func { return t.allMethods[i] }
// Empty returns true if t is the empty interface.
func (t *Interface) Empty() bool { return len(t.allMethods) == 0 }
// A Map represents a map type. // A Map represents a map type.
type Map struct { type Map struct {
key, elem Type key, elem Type

View File

@ -9,9 +9,25 @@ package types
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"sort"
) )
// If GcCompatibilityMode is set, printing of types is modified
// to match the representation of some types in the gc compiler:
//
// - byte and rune lose their alias name and simply stand for
// uint8 and int32 respectively
//
// - embedded interfaces get flattened (the embedding info is lost,
// and certain recursive interface types cannot be printed anymore)
//
// This makes it easier to compare packages computed with the type-
// checker vs packages imported from gc export data.
//
// Caution: This flag affects all uses of WriteType, globally.
// It is only provided for testing in conjunction with
// gc-generated data. It may be removed at any time.
var GcCompatibilityMode bool
// TypeString returns the string representation of typ. // TypeString returns the string representation of typ.
// Named types are printed package-qualified if they // Named types are printed package-qualified if they
// do not belong to this package. // do not belong to this package.
@ -33,6 +49,15 @@ func WriteType(buf *bytes.Buffer, this *Package, typ Type) {
if t.kind == UnsafePointer { if t.kind == UnsafePointer {
buf.WriteString("unsafe.") buf.WriteString("unsafe.")
} }
if GcCompatibilityMode {
// forget the alias names
switch t.kind {
case Byte:
t = Typ[Uint8]
case Rune:
t = Typ[Int32]
}
}
buf.WriteString(t.name) buf.WriteString(t.name)
case *Array: case *Array:
@ -84,30 +109,31 @@ func WriteType(buf *bytes.Buffer, this *Package, typ Type) {
// } // }
// //
buf.WriteString("interface{") buf.WriteString("interface{")
// Sort methods instead of printing them in source order. if GcCompatibilityMode {
// This is needed at the moment because interfaces are // print flattened interface
// created by providing the list of source methods and // (useful to compare against gc-generated interfaces)
// embedded interfaces, but only have an accessor to the list for i, m := range t.allMethods {
// of all methods (which is sorted by name). By sorting here if i > 0 {
// we guarantee that the list is printed the same independent buf.WriteString("; ")
// of how the Interface was created. }
// TODO(gri) remove this extra step once we have the complete buf.WriteString(m.name)
// set of accessors for Interface. writeSignature(buf, this, m.typ.(*Signature))
var methods []*Func
methods = append(methods, t.methods...) // make a copy
sort.Sort(byUniqueMethodName(methods))
for i, m := range methods {
if i > 0 {
buf.WriteString("; ")
} }
buf.WriteString(m.name) } else {
writeSignature(buf, this, m.typ.(*Signature)) // print explicit interface methods and embedded types
} for i, m := range t.methods {
for i, typ := range t.types { if i > 0 {
if i > 0 || len(t.methods) > 0 { buf.WriteString("; ")
buf.WriteString("; ") }
buf.WriteString(m.name)
writeSignature(buf, this, m.typ.(*Signature))
}
for i, typ := range t.embeddeds {
if i > 0 || len(t.methods) > 0 {
buf.WriteString("; ")
}
WriteType(buf, this, typ)
} }
WriteType(buf, this, typ)
} }
buf.WriteByte('}') buf.WriteByte('}')

View File

@ -527,7 +527,7 @@ func (check *checker) interfaceType(ityp *ast.InterfaceType, def *Named, cycleOk
check.errorf(pos, "%s is not an interface", named) check.errorf(pos, "%s is not an interface", named)
continue continue
} }
iface.types = append(iface.types, named) iface.embeddeds = append(iface.embeddeds, named)
// collect embedded methods // collect embedded methods
for _, m := range embed.allMethods { for _, m := range embed.allMethods {
if check.declareInSet(&mset, pos, m) { if check.declareInSet(&mset, pos, m) {
@ -564,11 +564,28 @@ func (check *checker) interfaceType(ityp *ast.InterfaceType, def *Named, cycleOk
*m.typ.(*Signature) = *sig // update signature (don't replace it!) *m.typ.(*Signature) = *sig // update signature (don't replace it!)
} }
// TODO(gri) The list of explicit methods is only sorted for now to
// produce the same Interface as NewInterface. We may be able to
// claim source order in the future. Revisit.
sort.Sort(byUniqueMethodName(iface.methods))
// TODO(gri) The list of embedded types is only sorted for now to
// produce the same Interface as NewInterface. We may be able to
// claim source order in the future. Revisit.
sort.Sort(byUniqueTypeName(iface.embeddeds))
sort.Sort(byUniqueMethodName(iface.allMethods)) sort.Sort(byUniqueMethodName(iface.allMethods))
return iface return iface
} }
// byUniqueTypeName named type lists can be sorted by their unique type names.
type byUniqueTypeName []*Named
func (a byUniqueTypeName) Len() int { return len(a) }
func (a byUniqueTypeName) Less(i, j int) bool { return a[i].obj.Id() < a[j].obj.Id() }
func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
// byUniqueMethodName method lists can be sorted by their unique method names. // byUniqueMethodName method lists can be sorted by their unique method names.
type byUniqueMethodName []*Func type byUniqueMethodName []*Func