From 221795b447af6a4fd8361f63b5e405c671a29c9b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 4 Jun 2013 15:15:41 -0400 Subject: [PATCH] go.tools/go/types: Factories for all objects R=adonovan CC=golang-dev https://golang.org/cl/9794044 --- go/types/api.go | 2 +- go/types/check_test.go | 4 +- go/types/errors.go | 9 +-- go/types/expr.go | 39 +++++------ go/types/gcimporter.go | 64 +++++++++-------- go/types/objects.go | 155 ++++++++++++++++++++--------------------- go/types/operand.go | 26 ++++--- go/types/predicates.go | 27 ++++--- go/types/resolver.go | 30 ++++---- go/types/sizes.go | 34 +++++---- go/types/stmt.go | 18 ++--- go/types/types.go | 46 ++---------- go/types/universe.go | 22 +++--- importer/pkginfo.go | 25 +++---- ssa/builder.go | 28 ++++---- ssa/emit.go | 2 +- ssa/interp/ops.go | 2 +- ssa/interp/reflect.go | 9 +-- ssa/print.go | 4 +- ssa/promote.go | 24 +++---- 20 files changed, 283 insertions(+), 287 deletions(-) diff --git a/go/types/api.go b/go/types/api.go index 32761144762..3a0f0953210 100644 --- a/go/types/api.go +++ b/go/types/api.go @@ -112,7 +112,7 @@ type Context struct { // of the given struct fields, in bytes. Otherwise DefaultOffsetsof // is called. Offsetsof must implement the offset guarantees // required by the spec. - Offsetsof func(fields []*Field) []int64 + Offsetsof func(fields *Scope) []int64 // If Sizeof != nil, it is called to determine the size of the // given type. Otherwise, DefaultSizeof is called. Sizeof must diff --git a/go/types/check_test.go b/go/types/check_test.go index 0fde5ef6781..b2afe387e12 100644 --- a/go/types/check_test.go +++ b/go/types/check_test.go @@ -232,8 +232,8 @@ func TestCheck(t *testing.T) { if !testBuiltinsDeclared { testBuiltinsDeclared = true // Pkg == nil for Universe objects - def(&Func{name: "assert", typ: &Builtin{_Assert, "assert", 1, false, true}}) - def(&Func{name: "trace", typ: &Builtin{_Trace, "trace", 0, true, true}}) + def(NewFunc(token.NoPos, nil, "assert", &Builtin{_Assert, "assert", 1, false, true})) + def(NewFunc(token.NoPos, nil, "trace", &Builtin{_Trace, "trace", 0, true, true})) } // For easy debugging w/o changing the testing code, diff --git a/go/types/errors.go b/go/types/errors.go index 5eeaa74ead7..105f0254028 100644 --- a/go/types/errors.go +++ b/go/types/errors.go @@ -259,15 +259,16 @@ func writeType(buf *bytes.Buffer, typ Type) { case *Struct: buf.WriteString("struct{") if t.fields != nil { - for i, f := range t.fields { + for i, obj := range t.fields.entries { if i > 0 { buf.WriteString("; ") } - if !f.IsAnonymous { - buf.WriteString(f.Name) + f := obj.(*Field) + if !f.anonymous { + buf.WriteString(f.name) buf.WriteByte(' ') } - writeType(buf, f.Type) + writeType(buf, f.typ) if tag := t.Tag(i); tag != "" { fmt.Fprintf(buf, " %q", tag) } diff --git a/go/types/expr.go b/go/types/expr.go index 03d01ae3878..aa3af52af75 100644 --- a/go/types/expr.go +++ b/go/types/expr.go @@ -92,7 +92,7 @@ func (check *checker) collectParams(scope *Scope, list *ast.FieldList, variadicO if len(field.Names) > 0 { // named parameter for _, name := range field.Names { - par := &Var{pos: name.Pos(), pkg: check.pkg, name: name.Name, typ: typ} + par := NewVar(name.Pos(), check.pkg, name.Name, typ) check.declare(scope, name, par) last = par @@ -101,7 +101,7 @@ func (check *checker) collectParams(scope *Scope, list *ast.FieldList, variadicO } } else { // anonymous parameter - par := &Var{pkg: check.pkg, typ: typ} + par := NewVar(ftype.Pos(), check.pkg, "", typ) check.callImplicitObj(field, par) last = nil // not accessible inside function @@ -138,7 +138,7 @@ func (check *checker) collectMethods(scope *Scope, list *ast.FieldList) *Scope { // TODO(gri) provide correct declaration info and scope // TODO(gri) with unified scopes (Scope, ObjSet) this can become // just a normal declaration - obj := &Func{name.Pos(), check.pkg, nil, name.Name, sig, nil} + obj := NewFunc(name.Pos(), check.pkg, name.Name, sig) if alt := methods.Insert(obj); alt != nil { check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name()) if pos := alt.Pos(); pos.IsValid() { @@ -182,26 +182,24 @@ func (check *checker) tag(t *ast.BasicLit) string { return "" } -func (check *checker) collectFields(scope *Scope, list *ast.FieldList, cycleOk bool) (fields []*Field, tags []string) { +func (check *checker) collectFields(scope *Scope, list *ast.FieldList, cycleOk bool) (tags []string) { if list == nil { return } var typ Type // current field typ var tag string // current field tag - add := func(field *ast.Field, ident *ast.Ident, name string, isAnonymous bool, pos token.Pos) { + add := func(field *ast.Field, ident *ast.Ident, name string, anonymous bool, pos token.Pos) { // TODO(gri): rethink this - at the moment we allocate only a prefix if tag != "" && tags == nil { - tags = make([]string, len(fields)) + tags = make([]string, scope.NumEntries()) } if tags != nil { tags = append(tags, tag) } - fld := &Var{pos: pos, pkg: check.pkg, name: name, typ: typ} + fld := NewField(pos, check.pkg, name, typ, anonymous) check.declare(scope, ident, fld) - - fields = append(fields, &Field{check.pkg, name, typ, isAnonymous, fld}) } for _, f := range list.List { @@ -1072,7 +1070,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle switch obj := obj.(type) { case *Package: - check.errorf(e.Pos(), "use of package %s not in selector", obj.Name) + check.errorf(e.Pos(), "use of package %s not in selector", obj.name) goto Error case *Const: if obj.typ == Typ[Invalid] { @@ -1161,7 +1159,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle fields := utyp.fields if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok { // all elements must have keys - visited := make([]bool, len(fields)) + visited := make([]bool, fields.NumEntries()) for _, e := range e.Elts { kv, _ := e.(*ast.KeyValueExpr) if kv == nil { @@ -1173,12 +1171,13 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key) continue } - i := utyp.fieldIndex(check.pkg, key.Name) + i := utyp.fields.Index(check.pkg, key.Name) if i < 0 { check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name) continue } - check.callIdent(key, fields[i].obj) + fld := fields.At(i).(*Field) + check.callIdent(key, fld) // 0 <= i < len(fields) if visited[i] { check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name) @@ -1186,7 +1185,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle } visited[i] = true check.expr(x, kv.Value, nil, iota) - etyp := fields[i].Type + etyp := fld.typ if !check.assignment(x, etyp) { if x.mode != invalid { check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp) @@ -1202,12 +1201,12 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle continue } check.expr(x, e, nil, iota) - if i >= len(fields) { + if i >= fields.NumEntries() { check.errorf(x.pos(), "too many values in struct literal") break // cannot continue } // i < len(fields) - etyp := fields[i].Type + etyp := fields.At(i).Type() if !check.assignment(x, etyp) { if x.mode != invalid { check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp) @@ -1215,7 +1214,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle continue } } - if len(e.Elts) < len(fields) { + if len(e.Elts) < fields.NumEntries() { check.errorf(e.Rbrace, "too few values in struct literal") // ok to continue } @@ -1346,7 +1345,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle } x.mode = value x.typ = &Signature{ - params: NewTuple(append([]*Var{{typ: x.typ}}, params...)...), + params: NewTuple(append([]*Var{NewVar(token.NoPos, check.pkg, "", x.typ)}, params...)...), results: sig.results, isVariadic: sig.isVariadic, } @@ -1703,9 +1702,9 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle case *ast.StructType: scope := NewScope(check.topScope) - fields, tags := check.collectFields(scope, e.Fields, cycleOk) + tags := check.collectFields(scope, e.Fields, cycleOk) x.mode = typexpr - x.typ = &Struct{scope: scope, fields: fields, tags: tags} + x.typ = &Struct{fields: scope, tags: tags} case *ast.FuncType: scope := NewScope(check.topScope) diff --git a/go/types/gcimporter.go b/go/types/gcimporter.go index c01d896f8c7..05d9746acf6 100644 --- a/go/types/gcimporter.go +++ b/go/types/gcimporter.go @@ -206,7 +206,7 @@ func declConst(pkg *Package, name string) *Const { return obj.(*Const) } // otherwise create a new constant and insert it into the scope - obj := &Const{pkg: pkg, name: name} + obj := NewConst(token.NoPos, pkg, name, nil, nil) scope.Insert(obj) return obj } @@ -216,7 +216,7 @@ func declTypeName(pkg *Package, name string) *TypeName { if obj := scope.Lookup(nil, name); obj != nil { return obj.(*TypeName) } - obj := &TypeName{pkg: pkg, name: name} + obj := NewTypeName(token.NoPos, pkg, name, nil) // a named type may be referred to before the underlying type // is known - set it up obj.typ = &Named{obj: obj} @@ -229,7 +229,7 @@ func declVar(pkg *Package, name string) *Var { if obj := scope.Lookup(nil, name); obj != nil { return obj.(*Var) } - obj := &Var{pkg: pkg, name: name} + obj := NewVar(token.NoPos, pkg, name, nil) scope.Insert(obj) return obj } @@ -239,7 +239,7 @@ func declFunc(pkg *Package, name string) *Func { if obj := scope.Lookup(nil, name); obj != nil { return obj.(*Func) } - obj := &Func{pkg: pkg, name: name} + obj := NewFunc(token.NoPos, pkg, name, nil) scope.Insert(obj) return obj } @@ -360,7 +360,7 @@ func (p *gcParser) getPkg(id, name string) *Package { } pkg := p.imports[id] if pkg == nil && name != "" { - pkg = &Package{name: name, path: id, scope: NewScope(nil)} + pkg = NewPackage(token.NoPos, id, name, NewScope(nil), nil, false) p.imports[id] = pkg } return pkg @@ -459,50 +459,55 @@ func (p *gcParser) parseName(materializePkg bool) (pkg *Package, name string) { // Field = Name Type [ string_lit ] . // func (p *gcParser) parseField() (*Field, string) { - var f Field - f.Pkg, f.Name = p.parseName(true) - f.Type = p.parseType() + pkg, name := p.parseName(true) + typ := p.parseType() + anonymous := false + if name == "" { + // anonymous field - typ must be T or *T and T must be a type name + switch typ := typ.Deref().(type) { + case *Basic: // basic types are named types + name = typ.name + case *Named: + name = typ.obj.name + default: + p.errorf("anonymous field expected") + } + anonymous = true + } tag := "" if p.tok == scanner.String { tag = p.expect(scanner.String) } - if f.Name == "" { - // anonymous field - typ must be T or *T and T must be a type name - switch typ := f.Type.Deref().(type) { - case *Basic: // basic types are named types - f.Name = typ.name - case *Named: - f.Name = typ.obj.name - default: - p.errorf("anonymous field expected") - } - f.IsAnonymous = true - } - return &f, tag + return NewField(token.NoPos, pkg, name, typ, anonymous), tag } // StructType = "struct" "{" [ FieldList ] "}" . // FieldList = Field { ";" Field } . // func (p *gcParser) parseStructType() Type { - var fields []*Field + var fields *Scope // lazily initialized var tags []string p.expectKeyword("struct") p.expect('{') - for p.tok != '}' { - if len(fields) > 0 { + for i := 0; p.tok != '}'; i++ { + if i > 0 { p.expect(';') } fld, tag := p.parseField() // TODO(gri) same code in collectFields (expr.go) - factor? if tag != "" && tags == nil { - tags = make([]string, len(fields)) + tags = make([]string, i) } if tags != nil { tags = append(tags, tag) } - fields = append(fields, fld) + if fields == nil { + fields = NewScope(nil) + } + if alt := fields.Insert(fld); alt != nil { + p.errorf("multiple fields named %s.%s", alt.Pkg().name, alt.Name()) + } } p.expect('}') @@ -525,7 +530,8 @@ func (p *gcParser) parseParameter() (par *Var, isVariadic bool) { if p.tok == scanner.String { p.next() } - par = &Var{name: name, typ: typ} // Pkg == nil + // TODO(gri) should we provide a package? + par = NewVar(token.NoPos, nil, name, typ) return } @@ -593,7 +599,7 @@ func (p *gcParser) parseInterfaceType() Type { if methods == nil { methods = NewScope(nil) } - if alt := methods.Insert(&Func{token.NoPos, pkg, nil, name, sig, nil}); alt != nil { + if alt := methods.Insert(NewFunc(token.NoPos, pkg, name, sig)); alt != nil { p.errorf("multiple methods named %s.%s", alt.Pkg().name, alt.Name()) } } @@ -885,7 +891,7 @@ func (p *gcParser) parseMethodDecl() { if base.methods == nil { base.methods = NewScope(nil) } - base.methods.Insert(&Func{token.NoPos, pkg, nil, name, sig, nil}) + base.methods.Insert(NewFunc(token.NoPos, pkg, name, sig)) } // FuncDecl = "func" ExportedName Func . diff --git a/go/types/objects.go b/go/types/objects.go index c425c992bf4..82a90404185 100644 --- a/go/types/objects.go +++ b/go/types/objects.go @@ -11,141 +11,136 @@ import ( "code.google.com/p/go.tools/go/exact" ) -// TODO(gri) provide a complete set of factory functions! // TODO(gri) All objects looks very similar now. Maybe just have single Object struct with an object kind? +// TODO(gri) Document factory, accessor methods, and fields. // An Object describes a named language entity such as a package, // constant, type, variable, function (incl. methods), or label. // All objects implement the Object interface. // type Object interface { - Pkg() *Package // nil for objects in the Universe scope and labels Parent() *Scope // the scope in which this object is declared - Name() string - Type() Type Pos() token.Pos // position of object identifier in declaration - // TODO(gri) provide String method! + Pkg() *Package // nil for objects in the Universe scope and labels + Name() string // the package local object name + Type() Type // the object type setParent(*Scope) + + // TODO(gri) provide String method! } +// An object implements the common parts of an Object. +type object struct { + parent *Scope + pos token.Pos + pkg *Package + name string + typ Type +} + +func (obj *object) Parent() *Scope { return obj.parent } +func (obj *object) Pos() token.Pos { return obj.pos } +func (obj *object) Pkg() *Package { return obj.pkg } +func (obj *object) Name() string { return obj.name } +func (obj *object) Type() Type { return obj.typ } + +func (obj *object) setParent(parent *Scope) { obj.parent = parent } + // A Package represents the contents (objects) of a Go package. type Package struct { - pos token.Pos // position of package import path or local package identifier, if present - name string - path string // import path, "" for current (non-imported) package - parent *Scope - scope *Scope // package-level scope + object + path string // import path, "" for current (non-imported) package + scope *Scope // imported objects imports map[string]*Package // map of import paths to imported packages complete bool // if set, this package was imported completely } -func NewPackage(path, name string) *Package { - return &Package{name: name, path: path, complete: true} +func NewPackage(pos token.Pos, path, name string, scope *Scope, imports map[string]*Package, complete bool) *Package { + obj := &Package{object{nil, pos, nil, name, Typ[Invalid]}, path, scope, imports, complete} + obj.pkg = obj + return obj } -func (obj *Package) Pkg() *Package { return obj } -func (obj *Package) Parent() *Scope { return obj.parent } -func (obj *Package) Scope() *Scope { return obj.scope } -func (obj *Package) Name() string { return obj.name } -func (obj *Package) Type() Type { return Typ[Invalid] } -func (obj *Package) Pos() token.Pos { return obj.pos } func (obj *Package) Path() string { return obj.path } +func (obj *Package) Scope() *Scope { return obj.scope } func (obj *Package) Imports() map[string]*Package { return obj.imports } func (obj *Package) Complete() bool { return obj.complete } -func (obj *Package) setParent(*Scope) { /* don't do anything - this is the package's scope */ -} // A Const represents a declared constant. type Const struct { - pos token.Pos // position of identifier in constant declaration - pkg *Package - parent *Scope - name string - typ Type - val exact.Value + object + val exact.Value visited bool // for initialization cycle detection } -func (obj *Const) Pkg() *Package { return obj.pkg } -func (obj *Const) Parent() *Scope { return obj.parent } -func (obj *Const) Name() string { return obj.name } -func (obj *Const) Type() Type { return obj.typ } -func (obj *Const) Pos() token.Pos { return obj.pos } -func (obj *Const) Val() exact.Value { return obj.val } -func (obj *Const) setParent(s *Scope) { obj.parent = s } +func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val exact.Value) *Const { + return &Const{object{nil, pos, pkg, name, typ}, val, false} +} + +func (obj *Const) Val() exact.Value { return obj.val } // A TypeName represents a declared type. type TypeName struct { - pos token.Pos // position of identifier in type declaration - pkg *Package - parent *Scope - name string - typ Type // *Named or *Basic + object } -func NewTypeName(pkg *Package, name string, typ Type) *TypeName { - return &TypeName{token.NoPos, pkg, nil, name, typ} +func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName { + return &TypeName{object{nil, pos, pkg, name, typ}} } -func (obj *TypeName) Pkg() *Package { return obj.pkg } -func (obj *TypeName) Parent() *Scope { return obj.parent } -func (obj *TypeName) Name() string { return obj.name } -func (obj *TypeName) Type() Type { return obj.typ } -func (obj *TypeName) Pos() token.Pos { return obj.pos } -func (obj *TypeName) setParent(s *Scope) { obj.parent = s } - // A Variable represents a declared variable (including function parameters and results). type Var struct { - pos token.Pos // position of identifier in variable declaration - pkg *Package // nil for parameters - parent *Scope - name string - typ Type + object visited bool // for initialization cycle detection } -func NewVar(pkg *Package, name string, typ Type) *Var { - return &Var{token.NoPos, pkg, nil, name, typ, false} +func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var { + return &Var{object{nil, pos, pkg, name, typ}, false} } -func (obj *Var) Pkg() *Package { return obj.pkg } -func (obj *Var) Parent() *Scope { return obj.parent } -func (obj *Var) Name() string { return obj.name } -func (obj *Var) Type() Type { return obj.typ } -func (obj *Var) Pos() token.Pos { return obj.pos } -func (obj *Var) setParent(s *Scope) { obj.parent = s } +// A Field represents a struct field. +type Field struct { + object + anonymous bool +} + +func NewField(pos token.Pos, pkg *Package, name string, typ Type, anonymous bool) *Field { + return &Field{object{nil, pos, pkg, name, typ}, anonymous} +} + +func (obj *Field) Anonymous() bool { return obj.anonymous } + +func (f *Field) isMatch(pkg *Package, name string) bool { + // spec: + // "Two identifiers are different if they are spelled differently, + // or if they appear in different packages and are not exported. + // Otherwise, they are the same." + if name != f.name { + return false + } + // f.Name == name + return ast.IsExported(name) || pkg.path == f.pkg.path +} // A Func represents a declared function. type Func struct { - pos token.Pos - pkg *Package - parent *Scope - name string - typ Type // *Signature or *Builtin + object decl *ast.FuncDecl // TODO(gri) can we get rid of this field? } -func (obj *Func) Pkg() *Package { return obj.pkg } -func (obj *Func) Parent() *Scope { return obj.parent } -func (obj *Func) Name() string { return obj.name } -func (obj *Func) Type() Type { return obj.typ } -func (obj *Func) Pos() token.Pos { return obj.pos } -func (obj *Func) setParent(s *Scope) { obj.parent = s } +func NewFunc(pos token.Pos, pkg *Package, name string, typ Type) *Func { + return &Func{object{nil, pos, pkg, name, typ}, nil} +} // A Label represents a declared label. type Label struct { - pos token.Pos - parent *Scope - name string + object } -func (obj *Label) Pkg() *Package { return nil } -func (obj *Label) Parent() *Scope { return obj.parent } -func (obj *Label) Name() string { return obj.name } -func (obj *Label) Type() Type { return nil } -func (obj *Label) Pos() token.Pos { return obj.pos } -func (obj *Label) setParent(s *Scope) { obj.parent = s } +func NewLabel(pos token.Pos, name string) *Label { + return &Label{object{nil, pos, nil, name, nil}} +} diff --git a/go/types/operand.go b/go/types/operand.go index e2e27869d02..fd755f868ae 100644 --- a/go/types/operand.go +++ b/go/types/operand.go @@ -275,10 +275,14 @@ func lookupFieldBreadthFirst(list []embeddedType, pkg *Package, name string) (re switch t := typ.underlying.(type) { case *Struct: // look for a matching field and collect embedded types - for i, f := range t.fields { + if t.fields == nil { + break + } + for i, obj := range t.fields.entries { + f := obj.(*Field) if f.isMatch(pkg, name) { - assert(f.Type != nil) - if !potentialMatch(e.multiples, variable, f.Type) { + assert(f.typ != nil) + if !potentialMatch(e.multiples, variable, f.typ) { return // name collision } var index []int @@ -296,10 +300,10 @@ func lookupFieldBreadthFirst(list []embeddedType, pkg *Package, name string) (re // T is a named type. If typ appeared multiple times at // this level, f.Type appears multiple times at the next // level. - if f.IsAnonymous && res.mode == invalid { + if f.anonymous && res.mode == invalid { // Ignore embedded basic types - only user-defined // named types can have methods or have struct fields. - if t, _ := f.Type.Deref().(*Named); t != nil { + if t, _ := f.typ.Deref().(*Named); t != nil { var index []int index = append(index, e.index...) // copy e.index index = append(index, i) @@ -370,18 +374,22 @@ func lookupField(typ Type, pkg *Package, name string) lookupResult { switch t := typ.(type) { case *Struct: + if t.fields == nil { + break + } var next []embeddedType - for i, f := range t.fields { + for i, obj := range t.fields.entries { + f := obj.(*Field) if f.isMatch(pkg, name) { - return lookupResult{variable, f.Type, []int{i}} + return lookupResult{variable, f.typ, []int{i}} } - if f.IsAnonymous { + if f.anonymous { // Possible optimization: If the embedded type // is a pointer to the current type we could // ignore it. // Ignore embedded basic types - only user-defined // named types can have methods or have struct fields. - if t, _ := f.Type.Deref().(*Named); t != nil { + if t, _ := f.typ.Deref().(*Named); t != nil { next = append(next, embeddedType{t, []int{i}, false}) } } diff --git a/go/types/predicates.go b/go/types/predicates.go index 97c88991d83..0ab836b4732 100644 --- a/go/types/predicates.go +++ b/go/types/predicates.go @@ -72,9 +72,11 @@ func isComparable(typ Type) bool { // assumes types are equal for pointers and channels return true case *Struct: - for _, f := range t.fields { - if !isComparable(f.Type) { - return false + if t.fields != nil { + for _, f := range t.fields.entries { + if !isComparable(f.Type()) { + return false + } } } return true @@ -126,14 +128,17 @@ func IsIdentical(x, y Type) bool { // and identical tags. Two anonymous fields are considered to have the same // name. Lower-case field names from different packages are always different. if y, ok := y.(*Struct); ok { - if len(x.fields) == len(y.fields) { - for i, f := range x.fields { - g := y.fields[i] - if f.IsAnonymous != g.IsAnonymous || - x.Tag(i) != y.Tag(i) || - !f.isMatch(g.Pkg, g.Name) || - !IsIdentical(f.Type, g.Type) { - return false + if x.NumFields() == y.NumFields() { + if x.fields != nil { + for i, obj := range x.fields.entries { + f := obj.(*Field) + g := y.fields.At(i).(*Field) + if f.anonymous != g.anonymous || + x.Tag(i) != y.Tag(i) || + !f.isMatch(g.pkg, g.name) || + !IsIdentical(f.typ, g.typ) { + return false + } } } return true diff --git a/go/types/resolver.go b/go/types/resolver.go index f9f15cb7f34..a780707dc22 100644 --- a/go/types/resolver.go +++ b/go/types/resolver.go @@ -119,7 +119,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) { name = s.Name.Name } - imp2 := &Package{name: name, scope: imp.scope} + imp2 := NewPackage(s.Pos(), path, name, imp.scope, nil, imp.complete) if s.Name != nil { check.callIdent(s.Name, imp2) } else { @@ -155,7 +155,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) { // declare all constants for i, name := range s.Names { - obj := &Const{pos: name.Pos(), pkg: pkg, name: name.Name, val: exact.MakeInt64(int64(iota))} + obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota))) check.declare(pkg.scope, name, obj) var init ast.Expr @@ -181,7 +181,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) { // declare all variables lhs := make([]*Var, len(s.Names)) for i, name := range s.Names { - obj := &Var{pos: name.Pos(), pkg: pkg, name: name.Name} + obj := NewVar(name.Pos(), pkg, name.Name, nil) lhs[i] = obj check.declare(pkg.scope, name, obj) @@ -218,7 +218,7 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) { } case *ast.TypeSpec: - obj := &TypeName{pos: s.Name.Pos(), pkg: pkg, name: s.Name.Name} + obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil) check.declare(pkg.scope, s.Name, obj) add(obj, s.Type, nil) @@ -233,7 +233,8 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) { methods = append(methods, &mdecl{fileScope, d}) continue } - obj := &Func{pos: d.Name.Pos(), pkg: pkg, name: d.Name.Name, decl: d} + obj := NewFunc(d.Name.Pos(), pkg, d.Name.Name, nil) + obj.decl = d if obj.name == "init" { // init functions are not visible - don't declare them in package scope obj.parent = pkg.scope @@ -309,7 +310,8 @@ func (check *checker) resolveFiles(files []*ast.File, importer Importer) { scope = new(Scope) check.methods[tname] = scope } - fun := &Func{pos: m.Name.Pos(), pkg: check.pkg, name: m.Name.Name, decl: m} + fun := NewFunc(m.Name.Pos(), check.pkg, m.Name.Name, nil) + fun.decl = m check.declare(scope, m.Name, fun) // HACK(gri) change method parent scope to file scope containing the declaration fun.parent = meth.file // remember the file scope @@ -478,9 +480,13 @@ func (check *checker) declareType(obj *TypeName, typ ast.Expr, cycleOk bool) { switch t := named.underlying.(type) { case *Struct: // struct fields must not conflict with methods - for _, f := range t.fields { - if m := scope.Lookup(nil, f.Name); m != nil { - check.errorf(m.Pos(), "type %s has both field and method named %s", obj.name, f.Name) + if t.fields == nil { + break + } + for _, f := range t.fields.entries { + name := f.Name() + if m := scope.Lookup(nil, name); m != nil { + check.errorf(m.Pos(), "type %s has both field and method named %s", obj.name, name) // ok to continue } } @@ -558,7 +564,7 @@ func (check *checker) declStmt(decl ast.Decl) { // declare all constants lhs := make([]*Const, len(s.Names)) for i, name := range s.Names { - obj := &Const{pos: name.Pos(), pkg: pkg, name: name.Name, val: exact.MakeInt64(int64(iota))} + obj := NewConst(name.Pos(), pkg, name.Name, nil, exact.MakeInt64(int64(iota))) check.callIdent(name, obj) lhs[i] = obj @@ -588,7 +594,7 @@ func (check *checker) declStmt(decl ast.Decl) { // declare all variables lhs := make([]*Var, len(s.Names)) for i, name := range s.Names { - obj := &Var{pos: name.Pos(), pkg: pkg, name: name.Name} + obj := NewVar(name.Pos(), pkg, name.Name, nil) check.callIdent(name, obj) lhs[i] = obj } @@ -633,7 +639,7 @@ func (check *checker) declStmt(decl ast.Decl) { } case *ast.TypeSpec: - obj := &TypeName{pos: s.Name.Pos(), pkg: pkg, name: s.Name.Name} + obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil) check.declare(check.topScope, s.Name, obj) check.declareType(obj, s.Type, false) diff --git a/go/types/sizes.go b/go/types/sizes.go index be53eb71dd2..ea327591968 100644 --- a/go/types/sizes.go +++ b/go/types/sizes.go @@ -18,12 +18,12 @@ func (ctxt *Context) alignof(typ Type) int64 { func (ctxt *Context) offsetsof(s *Struct) []int64 { offsets := s.offsets - if offsets == nil { + if offsets == nil && s.NumFields() > 0 { // compute offsets on demand if f := ctxt.Offsetsof; f != nil { offsets = f(s.fields) // sanity checks - if len(offsets) != len(s.fields) { + if len(offsets) != s.NumFields() { panic("Context.Offsetsof returned the wrong number of offsets") } for _, o := range offsets { @@ -50,7 +50,7 @@ func (ctxt *Context) offsetof(typ Type, index []int) int64 { return -1 } o += ctxt.offsetsof(s)[i] - typ = s.fields[i].Type + typ = s.fields.At(i).Type() } return o } @@ -84,9 +84,12 @@ func DefaultAlignof(typ Type) int64 { // is the largest of the values unsafe.Alignof(x.f) for each // field f of x, but at least 1." max := int64(1) - for _, f := range t.fields { - if a := DefaultAlignof(f.Type); a > max { - max = a + if t.fields != nil { + for _, obj := range t.fields.entries { + f := obj.(*Field) + if a := DefaultAlignof(f.typ); a > max { + max = a + } } } return max @@ -110,14 +113,19 @@ func align(x, a int64) int64 { // DefaultOffsetsof implements the default field offset computation // for unsafe.Offsetof. It is used if Context.Offsetsof == nil. -func DefaultOffsetsof(fields []*Field) []int64 { - offsets := make([]int64, len(fields)) +func DefaultOffsetsof(fields *Scope) []int64 { + n := fields.NumEntries() + if n == 0 { + return nil + } + offsets := make([]int64, n) var o int64 - for i, f := range fields { - a := DefaultAlignof(f.Type) + for i, obj := range fields.entries { + f := obj.(*Field) + a := DefaultAlignof(f.typ) o = align(o, a) offsets[i] = o - o += DefaultSizeof(f.Type) + o += DefaultSizeof(f.typ) } return offsets } @@ -144,7 +152,7 @@ func DefaultSizeof(typ Type) int64 { case *Slice: return DefaultPtrSize * 3 case *Struct: - n := len(t.fields) + n := t.NumFields() if n == 0 { return 0 } @@ -154,7 +162,7 @@ func DefaultSizeof(typ Type) int64 { offsets = DefaultOffsetsof(t.fields) t.offsets = offsets } - return offsets[n-1] + DefaultSizeof(t.fields[n-1].Type) + return offsets[n-1] + DefaultSizeof(t.fields.At(n-1).Type()) case *Signature: return DefaultPtrSize * 2 } diff --git a/go/types/stmt.go b/go/types/stmt.go index 90676ddda08..3da415f53d5 100644 --- a/go/types/stmt.go +++ b/go/types/stmt.go @@ -97,9 +97,9 @@ func (check *checker) assign1to1(lhs, rhs ast.Expr, x *operand, decl bool, iota var obj Object var typ Type if isConst { - obj = &Const{pos: ident.Pos(), pkg: check.pkg, name: ident.Name} + obj = NewConst(ident.Pos(), check.pkg, ident.Name, nil, nil) } else { - obj = &Var{pos: ident.Pos(), pkg: check.pkg, name: ident.Name} + obj = NewVar(ident.Pos(), check.pkg, ident.Name, nil) } defer check.declare(check.topScope, ident, obj) @@ -237,9 +237,9 @@ Error: var obj Object if isConst { - obj = &Const{pos: ident.Pos(), pkg: check.pkg, name: ident.Name} + obj = NewConst(ident.Pos(), check.pkg, ident.Name, nil, nil) } else { - obj = &Var{pos: ident.Pos(), pkg: check.pkg, name: ident.Name} + obj = NewVar(ident.Pos(), check.pkg, ident.Name, nil) } defer check.declare(check.topScope, ident, obj) @@ -323,7 +323,7 @@ func (check *checker) stmt(s ast.Stmt) { check.funcsig.labels = scope } label := s.Label - check.declare(scope, label, &Label{pos: label.Pos(), name: label.Name}) + check.declare(scope, label, NewLabel(label.Pos(), label.Name)) check.stmt(s.Stmt) case *ast.ExprStmt: @@ -404,7 +404,7 @@ func (check *checker) stmt(s ast.Stmt) { var obj Object if ident, ok := x.(*ast.Ident); ok { // use the correct obj if the ident is redeclared - obj = &Var{pos: ident.Pos(), pkg: check.pkg, name: ident.Name} + obj = NewVar(ident.Pos(), check.pkg, ident.Name, nil) if alt := check.topScope.Lookup(nil, ident.Name); alt != nil { obj = alt } @@ -412,7 +412,7 @@ func (check *checker) stmt(s ast.Stmt) { } else { check.errorf(x.Pos(), "cannot declare %s", x) // create a dummy variable - obj = &Var{pos: x.Pos(), pkg: check.pkg, name: "_"} + obj = NewVar(x.Pos(), check.pkg, "_", nil) } lhs[i] = obj } @@ -655,7 +655,7 @@ func (check *checker) stmt(s ast.Stmt) { var obj Object if lhs != nil { - obj = &Var{pos: lhs.Pos(), pkg: check.pkg, name: lhs.Name, typ: x.typ} + obj = NewVar(lhs.Pos(), check.pkg, lhs.Name, x.typ) check.declare(check.topScope, lhs, obj) } @@ -687,7 +687,7 @@ func (check *checker) stmt(s ast.Stmt) { if lhs != nil { // A single-type case clause implicitly declares a new variable shadowing lhs. if len(clause.List) == 1 && typ != nil { - obj := &Var{pos: lhs.Pos(), pkg: check.pkg, name: lhs.Name, typ: typ} + obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, typ) check.declare(check.topScope, nil, obj) check.callImplicitObj(clause, obj) } diff --git a/go/types/types.go b/go/types/types.go index f8ae5884e5f..ba1d5025b55 100644 --- a/go/types/types.go +++ b/go/types/types.go @@ -130,32 +130,19 @@ func NewSlice(elem Type) *Slice { return &Slice{elem} } // Elem returns the element type of slice s. func (s *Slice) Elem() Type { return s.elt } -// A Field represents a field of a struct. -type Field struct { - Pkg *Package - Name string - Type Type - IsAnonymous bool - - // TODO(gri) Temporary hack so we can report the correct *Var via Context.Ident. - // Make Field just this *Var and we can simplify a lot of struct code. - obj *Var -} - // A Struct represents a struct type. type Struct struct { - scope *Scope - fields []*Field - tags []string // field tags; nil of there are no tags + fields *Scope + tags []string // field tags; nil if there are no tags offsets []int64 // field offsets in bytes, lazily computed } -func NewStruct(fields []*Field, tags []string) *Struct { - return &Struct{scope: nil, fields: fields, tags: tags} +func NewStruct(fields *Scope, tags []string) *Struct { + return &Struct{fields: fields, tags: tags} } -func (s *Struct) NumFields() int { return len(s.fields) } -func (s *Struct) Field(i int) *Field { return s.fields[i] } +func (s *Struct) NumFields() int { return s.fields.NumEntries() } +func (s *Struct) Field(i int) *Field { return s.fields.At(i).(*Field) } func (s *Struct) Tag(i int) string { if i < len(s.tags) { return s.tags[i] @@ -163,27 +150,6 @@ func (s *Struct) Tag(i int) string { return "" } -func (f *Field) isMatch(pkg *Package, name string) bool { - // spec: - // "Two identifiers are different if they are spelled differently, - // or if they appear in different packages and are not exported. - // Otherwise, they are the same." - if name != f.Name { - return false - } - // f.Name == name - return ast.IsExported(name) || pkg.path == f.Pkg.path -} - -func (s *Struct) fieldIndex(pkg *Package, name string) int { - for i, f := range s.fields { - if f.isMatch(pkg, name) { - return i - } - } - return -1 -} - // A Pointer represents a pointer type. type Pointer struct { base Type diff --git a/go/types/universe.go b/go/types/universe.go index 3dc8bbd1242..373075b2a47 100644 --- a/go/types/universe.go +++ b/go/types/universe.go @@ -58,10 +58,10 @@ var aliases = [...]*Basic{ } var predeclaredConstants = [...]*Const{ - {name: "true", typ: Typ[UntypedBool], val: exact.MakeBool(true)}, - {name: "false", typ: Typ[UntypedBool], val: exact.MakeBool(false)}, - {name: "iota", typ: Typ[UntypedInt], val: exact.MakeInt64(0)}, - {name: "nil", typ: Typ[UntypedNil], val: exact.MakeNil()}, + NewConst(token.NoPos, nil, "true", Typ[UntypedBool], exact.MakeBool(true)), + NewConst(token.NoPos, nil, "false", Typ[UntypedBool], exact.MakeBool(false)), + NewConst(token.NoPos, nil, "iota", Typ[UntypedInt], exact.MakeInt64(0)), + NewConst(token.NoPos, nil, "nil", Typ[UntypedNil], exact.MakeNil()), } var predeclaredFunctions = [...]*Builtin{ @@ -88,23 +88,23 @@ var predeclaredFunctions = [...]*Builtin{ func init() { Universe = new(Scope) - Unsafe = &Package{name: "unsafe", scope: new(Scope)} + Unsafe = NewPackage(token.NoPos, "unsafe", "unsafe", NewScope(nil), nil, true) // predeclared types for _, t := range Typ { - def(&TypeName{name: t.name, typ: t}) + def(NewTypeName(token.NoPos, nil, t.name, t)) } for _, t := range aliases { - def(&TypeName{name: t.name, typ: t}) + def(NewTypeName(token.NoPos, nil, t.name, t)) } // error type { // Error has a nil package in its qualified name since it is in no package methods := NewScope(nil) - sig := &Signature{results: NewTuple(&Var{name: "", typ: Typ[String]})} - methods.Insert(&Func{token.NoPos, nil, nil, "Error", sig, nil}) - def(&TypeName{name: "error", typ: &Named{underlying: &Interface{methods: methods}}}) + sig := &Signature{results: NewTuple(NewVar(token.NoPos, nil, "", Typ[String]))} + methods.Insert(NewFunc(token.NoPos, nil, "Error", sig)) + def(NewTypeName(token.NoPos, nil, "error", &Named{underlying: &Interface{methods: methods}})) } for _, c := range predeclaredConstants { @@ -112,7 +112,7 @@ func init() { } for _, f := range predeclaredFunctions { - def(&Func{name: f.name, typ: f}) + def(NewFunc(token.NoPos, nil, f.name, f)) } universeIota = Universe.Lookup(nil, "iota").(*Const) diff --git a/importer/pkginfo.go b/importer/pkginfo.go index d956bfdf191..335799e03d1 100644 --- a/importer/pkginfo.go +++ b/importer/pkginfo.go @@ -6,6 +6,7 @@ import ( "code.google.com/p/go.tools/go/exact" "code.google.com/p/go.tools/go/types" "go/ast" + "go/token" "strconv" ) @@ -172,18 +173,18 @@ func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature isVariadic = true } params = append(params, - types.NewVar(nil, "", t0), - types.NewVar(nil, "", t1)) + types.NewVar(token.NoPos, nil, "", t0), + types.NewVar(token.NoPos, nil, "", t1)) case "print", "println": // print{,ln}(any, ...interface{}) isVariadic = true // Note, arg0 may have any type, not necessarily tEface. params = append(params, - types.NewVar(nil, "", info.TypeOf(e.Args[0])), - types.NewVar(nil, "", tEface)) + types.NewVar(token.NoPos, nil, "", info.TypeOf(e.Args[0])), + types.NewVar(token.NoPos, nil, "", tEface)) case "close": - params = append(params, types.NewVar(nil, "", info.TypeOf(e.Args[0]))) + params = append(params, types.NewVar(token.NoPos, nil, "", info.TypeOf(e.Args[0]))) case "copy": // copy([]T, []T) int @@ -196,7 +197,7 @@ func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature } else { panic("cannot infer types in call to copy()") } - stvar := types.NewVar(nil, "", st) + stvar := types.NewVar(token.NoPos, nil, "", st) params = append(params, stvar, stvar) case "delete": @@ -204,11 +205,11 @@ func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature tmap := info.TypeOf(e.Args[0]) tkey := tmap.Underlying().(*types.Map).Key() params = append(params, - types.NewVar(nil, "", tmap), - types.NewVar(nil, "", tkey)) + types.NewVar(token.NoPos, nil, "", tmap), + types.NewVar(token.NoPos, nil, "", tkey)) case "len", "cap": - params = append(params, types.NewVar(nil, "", info.TypeOf(e.Args[0]))) + params = append(params, types.NewVar(token.NoPos, nil, "", info.TypeOf(e.Args[0]))) case "real", "imag": // Reverse conversion to "complex" case below. @@ -223,7 +224,7 @@ func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature default: unreachable() } - params = append(params, types.NewVar(nil, "", argType)) + params = append(params, types.NewVar(token.NoPos, nil, "", argType)) case "complex": var argType types.Type @@ -237,11 +238,11 @@ func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature default: unreachable() } - v := types.NewVar(nil, "", argType) + v := types.NewVar(token.NoPos, nil, "", argType) params = append(params, v, v) case "panic": - params = append(params, types.NewVar(nil, "", tEface)) + params = append(params, types.NewVar(token.NoPos, nil, "", tEface)) case "recover": // no params diff --git a/ssa/builder.go b/ssa/builder.go index 0979f547a15..1dca792460f 100644 --- a/ssa/builder.go +++ b/ssa/builder.go @@ -42,7 +42,7 @@ type opaqueType struct { func (t *opaqueType) String() string { return t.name } var ( - varOk = types.NewVar(nil, "ok", tBool) + varOk = types.NewVar(token.NoPos, nil, "ok", tBool) // Type constants. tBool = types.Typ[types.Bool] @@ -55,8 +55,8 @@ var ( // The result type of a "select". tSelect = types.NewTuple( - types.NewVar(nil, "index", tInt), - types.NewVar(nil, "recv", tEface), + types.NewVar(token.NoPos, nil, "index", tInt), + types.NewVar(token.NoPos, nil, "recv", tEface), varOk) // SSA Value constants. @@ -253,7 +253,7 @@ func (b *builder) exprN(fn *Function, e ast.Expr) Value { tuple.(interface { setType(types.Type) }).setType(types.NewTuple( - types.NewVar(nil, "value", typ), + types.NewVar(token.NoPos, nil, "value", typ), varOk, )) return tuple @@ -358,7 +358,7 @@ func (b *builder) selector(fn *Function, e *ast.SelectorExpr, wantAddr, escaping index := -1 for i, n := 0, st.NumFields(); i < n; i++ { f := st.Field(i) - if MakeId(f.Name, f.Pkg) == id { + if MakeId(f.Name(), f.Pkg()) == id { index = i break } @@ -389,11 +389,11 @@ func (b *builder) selector(fn *Function, e *ast.SelectorExpr, wantAddr, escaping func (b *builder) fieldAddr(fn *Function, base ast.Expr, path *anonFieldPath, index int, fieldType types.Type, pos token.Pos, escaping bool) Value { var x Value if path != nil { - switch path.field.Type.Underlying().(type) { + switch path.field.Type().Underlying().(type) { case *types.Struct: - x = b.fieldAddr(fn, base, path.tail, path.index, path.field.Type, token.NoPos, escaping) + x = b.fieldAddr(fn, base, path.tail, path.index, path.field.Type(), token.NoPos, escaping) case *types.Pointer: - x = b.fieldExpr(fn, base, path.tail, path.index, path.field.Type, token.NoPos) + x = b.fieldExpr(fn, base, path.tail, path.index, path.field.Type(), token.NoPos) } } else { switch fn.Pkg.typeOf(base).Underlying().(type) { @@ -422,7 +422,7 @@ func (b *builder) fieldAddr(fn *Function, base ast.Expr, path *anonFieldPath, in func (b *builder) fieldExpr(fn *Function, base ast.Expr, path *anonFieldPath, index int, fieldType types.Type, pos token.Pos) Value { var x Value if path != nil { - x = b.fieldExpr(fn, base, path.tail, path.index, path.field.Type, token.NoPos) + x = b.fieldExpr(fn, base, path.tail, path.index, path.field.Type(), token.NoPos) } else { x = b.expr(fn, base) } @@ -1254,7 +1254,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, typ typ fname := kv.Key.(*ast.Ident).Name for i, n := 0, t.NumFields(); i < n; i++ { sf := t.Field(i) - if sf.Name == fname { + if sf.Name() == fname { fieldIndex = i e = kv.Value break @@ -1266,7 +1266,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, typ typ X: addr, Field: fieldIndex, } - faddr.setType(pointer(sf.Type)) + faddr.setType(pointer(sf.Type())) fn.emit(faddr) b.exprInPlace(fn, address{addr: faddr}, e) } @@ -1858,8 +1858,8 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token. } okv.setType(types.NewTuple( varOk, - types.NewVar(nil, "k", tk), - types.NewVar(nil, "v", tv), + types.NewVar(token.NoPos, nil, "k", tk), + types.NewVar(token.NoPos, nil, "v", tv), )) fn.emit(okv) @@ -1903,7 +1903,7 @@ func (b *builder) rangeChan(fn *Function, x Value, tk types.Type) (k Value, loop CommaOk: true, } recv.setType(types.NewTuple( - types.NewVar(nil, "k", tk), + types.NewVar(token.NoPos, nil, "k", tk), varOk, )) ko := fn.emit(recv) diff --git a/ssa/emit.go b/ssa/emit.go index e5e3834b1c9..eda08cea1f6 100644 --- a/ssa/emit.go +++ b/ssa/emit.go @@ -279,7 +279,7 @@ func emitTypeTest(f *Function, x Value, t types.Type) Value { CommaOk: true, } a.setType(types.NewTuple( - types.NewVar(nil, "value", t), + types.NewVar(token.NoPos, nil, "value", t), varOk, )) return f.emit(a) diff --git a/ssa/interp/ops.go b/ssa/interp/ops.go index 49c8b8484b5..2ec7c9760b7 100644 --- a/ssa/interp/ops.go +++ b/ssa/interp/ops.go @@ -217,7 +217,7 @@ func zero(t types.Type) value { case *types.Struct: s := make(structure, t.NumFields()) for i := range s { - s[i] = zero(t.Field(i).Type) + s[i] = zero(t.Field(i).Type()) } return s case *types.Chan: diff --git a/ssa/interp/reflect.go b/ssa/interp/reflect.go index e00a5149d3e..3658231b0af 100644 --- a/ssa/interp/reflect.go +++ b/ssa/interp/reflect.go @@ -8,6 +8,7 @@ package interp import ( "fmt" + "go/token" "reflect" "unsafe" @@ -23,7 +24,7 @@ type opaqueType struct { func (t *opaqueType) String() string { return t.name } // A bogus "reflect" type-checker package. Shared across interpreters. -var reflectTypesPackage = types.NewPackage("reflect", "reflect") +var reflectTypesPackage = types.NewPackage(token.NoPos, "reflect", "reflect", nil, nil, true) // rtype is the concrete type the interpreter uses to implement the // reflect.Type interface. Since its type is opaque to the target @@ -41,7 +42,7 @@ var rtypeType = makeNamedType("rtype", &opaqueType{nil, "rtype"}) var errorType = makeNamedType("error", &opaqueType{nil, "error"}) func makeNamedType(name string, underlying types.Type) *types.Named { - obj := types.NewTypeName(reflectTypesPackage, name, nil) + obj := types.NewTypeName(token.NoPos, reflectTypesPackage, name, nil) return types.NewNamed(obj, underlying, nil) } @@ -318,7 +319,7 @@ func ext۰reflect۰Value۰Field(fn *ssa.Function, args []value) value { // Signature: func (v reflect.Value, i int) reflect.Value v := args[0] i := args[1].(int) - return makeReflectValue(rV2T(v).t.Underlying().(*types.Struct).Field(i).Type, rV2V(v).(structure)[i]) + return makeReflectValue(rV2T(v).t.Underlying().(*types.Struct).Field(i).Type(), rV2V(v).(structure)[i]) } func ext۰reflect۰Value۰Interface(fn *ssa.Function, args []value) value { @@ -393,7 +394,7 @@ func newMethod(pkg *ssa.Package, recvType types.Type, name string) *ssa.Function // that is needed is the "pointerness" of Recv.Type, and for // now, we'll set it to always be false since we're only // concerned with rtype. Encapsulate this better. - sig := types.NewSignature(types.NewVar(nil, "recv", recvType), nil, nil, false) + sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", recvType), nil, nil, false) fn := ssa.NewFunction(name, sig) fn.Pkg = pkg fn.Prog = pkg.Prog diff --git a/ssa/print.go b/ssa/print.go index 7970e38b9b1..b90e8983021 100644 --- a/ssa/print.go +++ b/ssa/print.go @@ -229,7 +229,7 @@ func (v *FieldAddr) String() string { // Be robust against a bad index. name := "?" if 0 <= v.Field && v.Field < st.NumFields() { - name = st.Field(v.Field).Name + name = st.Field(v.Field).Name() } return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field) } @@ -239,7 +239,7 @@ func (v *Field) String() string { // Be robust against a bad index. name := "?" if 0 <= v.Field && v.Field < st.NumFields() { - name = st.Field(v.Field).Name + name = st.Field(v.Field).Name() } return fmt.Sprintf("%s.%s [#%d]", relName(v.X, v), name, v.Field) } diff --git a/ssa/promote.go b/ssa/promote.go index 6cec54e1c04..8ab5bf57eaf 100644 --- a/ssa/promote.go +++ b/ssa/promote.go @@ -51,7 +51,7 @@ func (p *anonFieldPath) reverse() []*anonFieldPath { // isIndirect returns true if the path indirects a pointer. func (p *anonFieldPath) isIndirect() bool { for ; p != nil; p = p.tail { - if isPointer(p.field.Type) { + if isPointer(p.field.Type()) { return true } } @@ -80,7 +80,7 @@ func (c candidate) String() string { s := "" // Inefficient! for p := c.path; p != nil; p = p.tail { - s = "." + p.field.Name + s + s = "." + p.field.Name() + s } return "@" + s + "." + c.method.Name() } @@ -142,7 +142,7 @@ func buildMethodSet(prog *Program, typ types.Type) MethodSet { for _, node := range list { t := typ // first time only if node != nil { - t = node.field.Type + t = node.field.Type() } t = t.Deref() @@ -168,10 +168,10 @@ func buildMethodSet(prog *Program, typ types.Type) MethodSet { case *types.Struct: for i, n := 0, t.NumFields(); i < n; i++ { f := t.Field(i) - nextcands[MakeId(f.Name, f.Pkg)] = nil // a field: block id + nextcands[MakeId(f.Name(), f.Pkg())] = nil // a field: block id // Queue up anonymous fields for next iteration. // Break cycles to ensure termination. - if f.IsAnonymous && !node.contains(f) { + if f.Anonymous() && !node.contains(f) { next = append(next, &anonFieldPath{node, i, f}) } } @@ -265,7 +265,7 @@ func addCandidate(m map[Id]*candidate, id Id, method *types.Func, concrete *Func // func makeBridgeMethod(prog *Program, typ types.Type, cand *candidate) *Function { old := cand.method.Type().(*types.Signature) - sig := types.NewSignature(types.NewVar(nil, "recv", typ), old.Params(), old.Results(), old.IsVariadic()) + sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", typ), old.Params(), old.Results(), old.IsVariadic()) if prog.mode&LogSource != 0 { defer logStack("makeBridgeMethod %s, %s, type %s", typ, cand, sig)() @@ -299,9 +299,9 @@ func makeBridgeMethod(prog *Program, typ types.Type, cand *candidate) *Function X: v, Field: p.index, } - sel.setType(pointer(p.field.Type)) + sel.setType(pointer(p.field.Type())) v = fn.emit(sel) - if isPointer(p.field.Type) { + if isPointer(p.field.Type()) { v = emitLoad(fn, v) } } @@ -458,7 +458,7 @@ func findPromotedField(st *types.Struct, id Id) (*anonFieldPath, int) { var list, next []*anonFieldPath for i, n := 0, st.NumFields(); i < n; i++ { f := st.Field(i) - if f.IsAnonymous { + if f.Anonymous() { list = append(list, &anonFieldPath{nil, i, f}) } } @@ -468,7 +468,7 @@ func findPromotedField(st *types.Struct, id Id) (*anonFieldPath, int) { for { // look for name in all types at this level for _, node := range list { - typ := node.field.Type.Deref().(*types.Named) + typ := node.field.Type().Deref().(*types.Named) if visited[typ] { continue } @@ -478,13 +478,13 @@ func findPromotedField(st *types.Struct, id Id) (*anonFieldPath, int) { case *types.Struct: for i, n := 0, typ.NumFields(); i < n; i++ { f := typ.Field(i) - if MakeId(f.Name, f.Pkg) == id { + if MakeId(f.Name(), f.Pkg()) == id { return node, i } } for i, n := 0, typ.NumFields(); i < n; i++ { f := typ.Field(i) - if f.IsAnonymous { + if f.Anonymous() { next = append(next, &anonFieldPath{node, i, f}) } }