mirror of
https://github.com/golang/go
synced 2024-11-19 00:54:42 -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:
parent
8f712fcb98
commit
e405e03b16
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,31 +109,32 @@ 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 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))
|
||||
}
|
||||
for i, typ := range t.types {
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
buf.WriteByte('}')
|
||||
|
||||
case *Map:
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user