]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: Steps towards removing ast.Object from exported API.
authorRobert Griesemer <gri@golang.org>
Fri, 28 Dec 2012 22:30:36 +0000 (14:30 -0800)
committerRobert Griesemer <gri@golang.org>
Fri, 28 Dec 2012 22:30:36 +0000 (14:30 -0800)
- introduced type Method for methods
- renamed StructField -> Field
- removed ObjList
- methods are not sorted anymore in interfaces (for now)

R=adonovan
CC=golang-dev
https://golang.org/cl/7023043

src/pkg/go/types/api.go
src/pkg/go/types/errors.go
src/pkg/go/types/expr.go
src/pkg/go/types/gcimporter.go
src/pkg/go/types/operand.go
src/pkg/go/types/predicates.go
src/pkg/go/types/testdata/decls0.src
src/pkg/go/types/types.go
src/pkg/go/types/types_test.go
src/pkg/go/types/universe.go

index a4f6af7847635d02861d552fbcbae3320f3471e4..8ccd969a8d19177d0785d2e49d8acf6d2552e593 100644 (file)
@@ -5,6 +5,8 @@
 // Package types declares the data structures for representing
 // Go types and implements typechecking of package files.
 //
+// WARNING: THE TYPES API IS SUBJECT TO SIGNIFICANT CHANGE.
+//
 package types
 
 import (
index f0ca69af5c5cafde0289cf85fe8ceaf7f0960801..728ea9fcbf6a8c3f689d04351ef0f8a4055761e7 100644 (file)
@@ -197,7 +197,7 @@ func typeString(typ Type) string {
        return buf.String()
 }
 
-func writeParams(buf *bytes.Buffer, params ObjList, isVariadic bool) {
+func writeParams(buf *bytes.Buffer, params []*ast.Object, isVariadic bool) {
        buf.WriteByte('(')
        for i, par := range params {
                if i > 0 {
@@ -287,7 +287,7 @@ func writeType(buf *bytes.Buffer, typ Type) {
                                buf.WriteString("; ")
                        }
                        buf.WriteString(m.Name)
-                       writeSignature(buf, m.Type.(*Signature))
+                       writeSignature(buf, m.Type)
                }
                buf.WriteByte('}')
 
index bf3be532a354857b643bccc20ab372358fec8e3c..8063f391c23406029cd3cad101f67bc00c15b129 100644 (file)
@@ -22,7 +22,7 @@ import (
 // - clients need access to builtins type information
 // - API tests are missing (e.g., identifiers should be handled as expressions in callbacks)
 
-func (check *checker) collectParams(list *ast.FieldList, variadicOk bool) (params ObjList, isVariadic bool) {
+func (check *checker) collectParams(list *ast.FieldList, variadicOk bool) (params []*ast.Object, isVariadic bool) {
        if list == nil {
                return
        }
@@ -70,7 +70,7 @@ func (check *checker) collectParams(list *ast.FieldList, variadicOk bool) (param
        return
 }
 
-func (check *checker) collectMethods(list *ast.FieldList) (methods ObjList) {
+func (check *checker) collectMethods(list *ast.FieldList) (methods []*Method) {
        if list == nil {
                return
        }
@@ -81,14 +81,13 @@ func (check *checker) collectMethods(list *ast.FieldList) (methods ObjList) {
                if len(f.Names) > 0 {
                        // methods (the parser ensures that there's only one
                        // and we don't care if a constructed AST has more)
-                       if _, ok := typ.(*Signature); !ok {
+                       sig, ok := typ.(*Signature)
+                       if !ok {
                                check.invalidAST(f.Type.Pos(), "%s is not a method signature", typ)
                                continue
                        }
                        for _, name := range f.Names {
-                               obj := name.Obj
-                               obj.Type = typ
-                               methods = append(methods, obj)
+                               methods = append(methods, &Method{name.Name, sig})
                        }
                } else {
                        // embedded interface
@@ -101,14 +100,20 @@ func (check *checker) collectMethods(list *ast.FieldList) (methods ObjList) {
                        }
                }
        }
-       // check for double declarations
-       methods.Sort()
-       prev := ""
-       for _, obj := range methods {
-               if obj.Name == prev {
-                       check.errorf(list.Pos(), "multiple methods named %s", prev)
+       // Check for double declarations.
+       // The parser inserts methods into an interface-local scope, so local
+       // double declarations are reported by the parser already. We need to
+       // check again for conflicts due to embedded interfaces. This will lead
+       // to a 2nd error message if the double declaration was reported before
+       // by the parser.
+       // TODO(gri) clean this up a bit
+       seen := make(map[string]bool)
+       for _, m := range methods {
+               if seen[m.Name] {
+                       check.errorf(list.Pos(), "multiple methods named %s", m.Name)
                        return // keep multiple entries, lookup will only return the first entry
                }
+               seen[m.Name] = true
        }
        return
 }
@@ -125,7 +130,7 @@ func (check *checker) tag(t *ast.BasicLit) string {
        return ""
 }
 
-func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields []*StructField) {
+func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields []*Field) {
        if list == nil {
                return
        }
@@ -135,15 +140,15 @@ func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields [
                if len(f.Names) > 0 {
                        // named fields
                        for _, name := range f.Names {
-                               fields = append(fields, &StructField{name.Name, typ, tag, false})
+                               fields = append(fields, &Field{name.Name, typ, tag, false})
                        }
                } else {
                        // anonymous field
                        switch t := deref(typ).(type) {
                        case *Basic:
-                               fields = append(fields, &StructField{t.Name, typ, tag, true})
+                               fields = append(fields, &Field{t.Name, typ, tag, true})
                        case *NamedType:
-                               fields = append(fields, &StructField{t.Obj.Name, typ, tag, true})
+                               fields = append(fields, &Field{t.Obj.Name, typ, tag, true})
                        default:
                                if typ != Typ[Invalid] {
                                        check.invalidAST(f.Type.Pos(), "anonymous field type %s must be named", typ)
@@ -921,7 +926,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
                        arg.Type = x.typ
                        x.mode = value
                        x.typ = &Signature{
-                               Params:     append(ObjList{arg}, sig.Params...),
+                               Params:     append([]*ast.Object{arg}, sig.Params...),
                                Results:    sig.Results,
                                IsVariadic: sig.IsVariadic,
                        }
index 4318e6aa21e507271ff07bd7f92de7cf9b11a811..732bb4668231a8486670451a678c1023d9c52bd4 100644 (file)
@@ -383,8 +383,8 @@ func (p *gcParser) parseName() (name string) {
 
 // Field = Name Type [ string_lit ] .
 //
-func (p *gcParser) parseField() *StructField {
-       var f StructField
+func (p *gcParser) parseField() *Field {
+       var f Field
        f.Name = p.parseName()
        f.Type = p.parseType()
        if p.tok == scanner.String {
@@ -406,7 +406,7 @@ func (p *gcParser) parseField() *StructField {
 // FieldList  = Field { ";" Field } .
 //
 func (p *gcParser) parseStructType() Type {
-       var fields []*StructField
+       var fields []*Field
 
        parseField := func() {
                fields = append(fields, p.parseField())
@@ -510,12 +510,12 @@ func (p *gcParser) parseSignature() *Signature {
 // visible in the export data.
 //
 func (p *gcParser) parseInterfaceType() Type {
-       var methods ObjList
+       var methods []*Method
 
        parseMethod := func() {
-               obj := ast.NewObj(ast.Fun, p.parseName())
-               obj.Type = p.parseSignature()
-               methods = append(methods, obj)
+               name := p.parseName()
+               typ := p.parseSignature()
+               methods = append(methods, &Method{name, typ})
        }
 
        p.expectKeyword("interface")
@@ -529,7 +529,6 @@ func (p *gcParser) parseInterfaceType() Type {
        }
        p.expect('}')
 
-       methods.Sort()
        return &Interface{Methods: methods}
 }
 
index e232f356e62f3d6b429d3a6a35a0b1015ded65a8..f85e6b40366d9181be91699e7ca424225a1fa8d2 100644 (file)
@@ -301,10 +301,10 @@ func lookupFieldBreadthFirst(list []embeddedType, name string) (res lookupResult
 
                        case *Interface:
                                // look for a matching method
-                               for _, obj := range typ.Methods {
-                                       if obj.Name == name {
-                                               assert(obj.Type != nil)
-                                               if !potentialMatch(e.multiples, value, obj.Type.(Type)) {
+                               for _, m := range typ.Methods {
+                                       if m.Name == name {
+                                               assert(m.Type != nil)
+                                               if !potentialMatch(e.multiples, value, m.Type) {
                                                        return // name collision
                                                }
                                        }
@@ -380,9 +380,9 @@ func lookupField(typ Type, name string) (operandMode, Type) {
                }
 
        case *Interface:
-               for _, obj := range typ.Methods {
-                       if obj.Name == name {
-                               return value, obj.Type.(Type)
+               for _, m := range typ.Methods {
+                       if m.Name == name {
+                               return value, m.Type
                        }
                }
        }
index ff6825ba3b44ac99bbf6201bb582e39b89100995..21d08fe14c53269938d51122b72de1981d3c1f9b 100644 (file)
@@ -165,7 +165,7 @@ func isIdentical(x, y Type) bool {
                // the same names and identical function types. Lower-case method names from
                // different packages are always different. The order of the methods is irrelevant.
                if y, ok := y.(*Interface); ok {
-                       return identicalTypes(x.Methods, y.Methods) // methods are sorted
+                       return identicalMethods(x.Methods, y.Methods) // methods are sorted
                }
 
        case *Map:
@@ -194,17 +194,36 @@ func isIdentical(x, y Type) bool {
 
 // identicalTypes returns true if both lists a and b have the
 // same length and corresponding objects have identical types.
-func identicalTypes(a, b ObjList) bool {
-       if len(a) == len(b) {
-               for i, x := range a {
-                       y := b[i]
-                       if !isIdentical(x.Type.(Type), y.Type.(Type)) {
-                               return false
-                       }
+func identicalTypes(a, b []*ast.Object) bool {
+       if len(a) != len(b) {
+               return false
+       }
+       for i, x := range a {
+               y := b[i]
+               if !isIdentical(x.Type.(Type), y.Type.(Type)) {
+                       return false
                }
-               return true
        }
-       return false
+       return true
+}
+
+// identicalMethods returns true if both lists a and b have the
+// same length and corresponding methods have identical types.
+// TODO(gri) make this more efficient
+func identicalMethods(a, b []*Method) bool {
+       if len(a) != len(b) {
+               return false
+       }
+       m := make(map[string]*Method)
+       for _, x := range a {
+               m[x.Name] = x
+       }
+       for _, y := range b {
+               if x := m[y.Name]; x == nil || !isIdentical(x.Type, y.Type) {
+                       return false
+               }
+       }
+       return true
 }
 
 // underlying returns the underlying type of typ.
@@ -257,14 +276,14 @@ func defaultType(typ Type) Type {
 // it returns the first missing method required by T and whether it
 // is missing or simply has the wrong type.
 //
-func missingMethod(typ Type, T *Interface) (method *ast.Object, wrongType bool) {
+func missingMethod(typ Type, T *Interface) (method *Method, wrongType bool) {
        // TODO(gri): distinguish pointer and non-pointer receivers
        // an interface type implements T if it has no methods with conflicting signatures
        // Note: This is stronger than the current spec. Should the spec require this?
        if ityp, _ := underlying(typ).(*Interface); ityp != nil {
                for _, m := range T.Methods {
                        mode, sig := lookupField(ityp, m.Name) // TODO(gri) no need to go via lookupField
-                       if mode != invalid && !isIdentical(sig, m.Type.(Type)) {
+                       if mode != invalid && !isIdentical(sig, m.Type) {
                                return m, true
                        }
                }
@@ -277,7 +296,7 @@ func missingMethod(typ Type, T *Interface) (method *ast.Object, wrongType bool)
                if mode == invalid {
                        return m, false
                }
-               if !isIdentical(sig, m.Type.(Type)) {
+               if !isIdentical(sig, m.Type) {
                        return m, true
                }
        }
index 70623c6166fe07d0baa9cf160b8cf60e2a84b989..33d4b3801490b3eeab9061d7301482de33e5ea8f 100644 (file)
@@ -127,7 +127,7 @@ type (
        I2 interface {
                m1()
        }
-       I3 interface {
+       I3 interface { /* ERROR "multiple methods named m1" */
                m1()
                m1 /* ERROR "redeclared" */ ()
        }
index 87df029564e56eb151298e390a03cf2374db0f2b..871d34ecf7a998f99be86f21b26a79fe7d696e8e 100644 (file)
@@ -4,13 +4,9 @@
 
 package types
 
-import (
-       "go/ast"
-       "sort"
-)
+import "go/ast"
 
 // All types implement the Type interface.
-// TODO(gri) Eventually determine what common Type functionality should be exported.
 type Type interface {
        aType()
 }
@@ -95,7 +91,8 @@ type Slice struct {
        Elt Type
 }
 
-type StructField struct {
+// A Field represents a field of a struct.
+type Field struct {
        Name        string // unqualified type name for anonymous fields
        Type        Type
        Tag         string
@@ -105,7 +102,7 @@ type StructField struct {
 // A Struct represents a struct type struct{...}.
 type Struct struct {
        implementsType
-       Fields []*StructField
+       Fields []*Field
 }
 
 func (typ *Struct) fieldIndex(name string) int {
@@ -126,16 +123,16 @@ type Pointer struct {
 // A Result represents a (multi-value) function call result.
 type Result struct {
        implementsType
-       Values ObjList // Signature.Results of the function called
+       Values []*ast.Object // Signature.Results of the function called
 }
 
 // A Signature represents a user-defined function type func(...) (...).
 type Signature struct {
        implementsType
-       Recv       *ast.Object // nil if not a method
-       Params     ObjList     // (incoming) parameters from left to right; or nil
-       Results    ObjList     // (outgoing) results from left to right; or nil
-       IsVariadic bool        // true if the last parameter's type is of the form ...T
+       Recv       *ast.Object   // nil if not a method
+       Params     []*ast.Object // (incoming) parameters from left to right; or nil
+       Results    []*ast.Object // (outgoing) results from left to right; or nil
+       IsVariadic bool          // true if the last parameter's type is of the form ...T
 }
 
 // builtinId is an id of a builtin function.
@@ -180,10 +177,16 @@ type builtin struct {
        isStatement bool // true if the built-in is valid as an expression statement
 }
 
+// A Method represents a method of an interface.
+type Method struct {
+       Name string
+       Type *Signature
+}
+
 // An Interface represents an interface type interface{...}.
 type Interface struct {
        implementsType
-       Methods ObjList // interface methods sorted by name; or nil
+       Methods []*Method // TODO(gri) consider keeping them in sorted order
 }
 
 // A Map represents a map type map[Key]Elt.
@@ -206,17 +209,6 @@ type NamedType struct {
        Underlying Type        // nil if not fully declared yet; never a *NamedType
 }
 
-// An ObjList represents an ordered (in some fashion) list of objects.
-type ObjList []*ast.Object
-
-// ObjList implements sort.Interface.
-func (list ObjList) Len() int           { return len(list) }
-func (list ObjList) Less(i, j int) bool { return list[i].Name < list[j].Name }
-func (list ObjList) Swap(i, j int)      { list[i], list[j] = list[j], list[i] }
-
-// Sort sorts an object list by object name.
-func (list ObjList) Sort() { sort.Sort(list) }
-
 // All concrete types embed implementsType which
 // ensures that all types implement the Type interface.
 type implementsType struct{}
index 3345a63d96dfa066f609d119440680c8843ea5bd..48a1d61e3bdabb62585cfa88f8f4163119a92529 100644 (file)
@@ -88,10 +88,7 @@ var testTypes = []testEntry{
        // interfaces
        dup("interface{}"),
        dup("interface{m()}"),
-       {`interface{
-               m(int) float32
-               String() string
-       }`, `interface{String() string; m(int) float32}`}, // methods are sorted
+       dup(`interface{m(int) float32; String() string}`),
        // TODO(gri) add test for interface w/ anonymous field
 
        // maps
index 0fbaa3329d44c8175787857573f50a2275436747..3b45fb74a90b6ab66f31b407e08725a8cf8c98b5 100644 (file)
@@ -118,10 +118,9 @@ func init() {
        {
                res := ast.NewObj(ast.Var, "")
                res.Type = Typ[String]
-               err := ast.NewObj(ast.Fun, "Error")
-               err.Type = &Signature{Results: ObjList{res}}
+               err := &Method{"Error", &Signature{Results: []*ast.Object{res}}}
                obj := def(ast.Typ, "error")
-               obj.Type = &NamedType{Underlying: &Interface{Methods: ObjList{err}}, Obj: obj}
+               obj.Type = &NamedType{Underlying: &Interface{Methods: []*Method{err}}, Obj: obj}
        }
 
        // predeclared constants