1
0
mirror of https://github.com/golang/go synced 2024-10-01 07:28:35 -06: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:
if !x.isNil() && t.NumMethods() > 0 /* empty interfaces are ok */ {
if !x.isNil() && !t.Empty() /* empty interfaces are ok */ {
goto Error
}
// Update operand types to the default type rather then
@ -535,7 +535,7 @@ func (check *checker) convertUntyped(x *operand, target Type) {
target = Typ[UntypedNil]
} else {
// cannot assign untyped values to non-empty interfaces
if t.NumMethods() > 0 {
if !t.Empty() {
goto Error
}
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) {
// fast path for common case
if T.NumMethods() == 0 {
if T.Empty() {
return
}

View File

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

View File

@ -247,15 +247,15 @@ func (s *Signature) IsVariadic() bool { return s.isVariadic }
// An Interface represents an interface type.
type Interface struct {
methods []*Func // explicitly declared methods
types []*Named // explicitly embedded types
methods []*Func // ordered list of explicitly declared methods
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)
mset cachedMethodSet // method set for interface, lazily initialized
}
// NewInterface returns a new interface for the given methods.
func NewInterface(methods []*Func, types []*Named) *Interface {
// NewInterface returns a new interface for the given methods and embedded types.
func NewInterface(methods []*Func, embeddeds []*Named) *Interface {
typ := new(Interface)
var mset objset
@ -271,11 +271,11 @@ func NewInterface(methods []*Func, types []*Named) *Interface {
sort.Sort(byUniqueMethodName(methods))
var allMethods []*Func
if types == nil {
if embeddeds == nil {
allMethods = methods
} else {
allMethods = append(allMethods, methods...)
for _, t := range types {
for _, t := range embeddeds {
it := t.Underlying().(*Interface)
for _, tm := range it.allMethods {
// 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)
}
}
sort.Sort(byUniqueTypeName(embeddeds))
sort.Sort(byUniqueMethodName(allMethods))
}
typ.methods = methods
typ.types = types
typ.embeddeds = embeddeds
typ.allMethods = allMethods
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) }
// 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] }
// 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.
type Map struct {
key, elem Type

View File

@ -9,9 +9,25 @@ package types
import (
"bytes"
"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.
// Named types are printed package-qualified if they
// do not belong to this package.
@ -33,6 +49,15 @@ func WriteType(buf *bytes.Buffer, this *Package, typ Type) {
if t.kind == UnsafePointer {
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)
case *Array:
@ -84,30 +109,31 @@ func WriteType(buf *bytes.Buffer, this *Package, typ Type) {
// }
//
buf.WriteString("interface{")
// Sort methods instead of printing them in source order.
// This is needed at the moment because interfaces are
// created by providing the list of source methods and
// embedded interfaces, but only have an accessor to the list
// of all methods (which is sorted by name). By sorting here
// we guarantee that the list is printed the same independent
// of how the Interface was created.
// TODO(gri) remove this extra step once we have the complete
// set of accessors for Interface.
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("; ")
if GcCompatibilityMode {
// print flattened interface
// (useful to compare against gc-generated interfaces)
for i, m := range t.allMethods {
if i > 0 {
buf.WriteString("; ")
}
buf.WriteString(m.name)
writeSignature(buf, this, m.typ.(*Signature))
}
buf.WriteString(m.name)
writeSignature(buf, this, m.typ.(*Signature))
}
for i, typ := range t.types {
if i > 0 || len(t.methods) > 0 {
buf.WriteString("; ")
} else {
// print explicit interface methods and embedded types
for i, m := range t.methods {
if i > 0 {
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('}')

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)
continue
}
iface.types = append(iface.types, named)
iface.embeddeds = append(iface.embeddeds, named)
// collect embedded methods
for _, m := range embed.allMethods {
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!)
}
// 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))
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.
type byUniqueMethodName []*Func