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:
parent
8f712fcb98
commit
e405e03b16
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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('}')
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user