go.tools/go/types: simplified and faster Scope

- implemented objset for tracking duplicates of fields and methods
  which permitted a simpler and faster scope implementation in turn
- related cleanups and internal renames
- fixed a couple of identifier reporting bugs

Speed of type-checking itself increased by almost 10%
(from ~71Kloc/s to ~78Kloc/s on one machine, measured
via go test -run=Self).

R=adonovan
CC=golang-dev
https://golang.org/cl/11750043
This commit is contained in:
Robert Griesemer 2013-07-23 21:21:37 -07:00
parent 2f54663e0e
commit 66e7552830
16 changed files with 150 additions and 115 deletions

View File

@ -264,7 +264,7 @@ func (check *checker) shortVarDecl(lhs, rhs []ast.Expr) {
// Use the correct obj if the ident is redeclared. The // Use the correct obj if the ident is redeclared. The
// variable's scope starts after the declaration; so we // variable's scope starts after the declaration; so we
// must use Scope.Lookup here and call Scope.Insert later. // must use Scope.Lookup here and call Scope.Insert later.
if alt := scope.Lookup(nil, ident.Name); alt != nil { if alt := scope.Lookup(ident.Name); alt != nil {
// redeclared object must be a variable // redeclared object must be a variable
if alt, _ := alt.(*Var); alt != nil { if alt, _ := alt.(*Var); alt != nil {
obj = alt obj = alt

View File

@ -171,7 +171,7 @@ func (check *checker) selector(x *operand, e *ast.SelectorExpr) {
if ident, ok := e.X.(*ast.Ident); ok { if ident, ok := e.X.(*ast.Ident); ok {
if pkg, ok := check.topScope.LookupParent(ident.Name).(*Package); ok { if pkg, ok := check.topScope.LookupParent(ident.Name).(*Package); ok {
check.recordObject(ident, pkg) check.recordObject(ident, pkg)
exp := pkg.scope.Lookup(nil, sel) exp := pkg.scope.Lookup(sel)
if exp == nil { if exp == nil {
check.errorf(e.Pos(), "%s not declared by package %s", sel, ident) check.errorf(e.Pos(), "%s not declared by package %s", sel, ident)
goto Error goto Error

View File

@ -207,7 +207,7 @@ func declConst(pkg *Package, name string) *Const {
// the constant may have been imported before - if it exists // the constant may have been imported before - if it exists
// already in the respective scope, return that constant // already in the respective scope, return that constant
scope := pkg.scope scope := pkg.scope
if obj := scope.Lookup(nil, name); obj != nil { if obj := scope.Lookup(name); obj != nil {
return obj.(*Const) return obj.(*Const)
} }
// otherwise create a new constant and insert it into the scope // otherwise create a new constant and insert it into the scope
@ -218,7 +218,7 @@ func declConst(pkg *Package, name string) *Const {
func declTypeName(pkg *Package, name string) *TypeName { func declTypeName(pkg *Package, name string) *TypeName {
scope := pkg.scope scope := pkg.scope
if obj := scope.Lookup(nil, name); obj != nil { if obj := scope.Lookup(name); obj != nil {
return obj.(*TypeName) return obj.(*TypeName)
} }
obj := NewTypeName(token.NoPos, pkg, name, nil) obj := NewTypeName(token.NoPos, pkg, name, nil)
@ -231,7 +231,7 @@ func declTypeName(pkg *Package, name string) *TypeName {
func declVar(pkg *Package, name string) *Var { func declVar(pkg *Package, name string) *Var {
scope := pkg.scope scope := pkg.scope
if obj := scope.Lookup(nil, name); obj != nil { if obj := scope.Lookup(name); obj != nil {
return obj.(*Var) return obj.(*Var)
} }
obj := NewVar(token.NoPos, pkg, name, nil) obj := NewVar(token.NoPos, pkg, name, nil)
@ -241,7 +241,7 @@ func declVar(pkg *Package, name string) *Var {
func declFunc(pkg *Package, name string) *Func { func declFunc(pkg *Package, name string) *Func {
scope := pkg.scope scope := pkg.scope
if obj := scope.Lookup(nil, name); obj != nil { if obj := scope.Lookup(name); obj != nil {
return obj.(*Func) return obj.(*Func)
} }
obj := NewFunc(token.NoPos, pkg, name, nil) obj := NewFunc(token.NoPos, pkg, name, nil)
@ -390,7 +390,7 @@ func (p *gcParser) parseExportedName() (pkg *Package, name string) {
// //
func (p *gcParser) parseBasicType() Type { func (p *gcParser) parseBasicType() Type {
id := p.expect(scanner.Ident) id := p.expect(scanner.Ident)
obj := Universe.Lookup(nil, id) obj := Universe.Lookup(id)
if obj, ok := obj.(*TypeName); ok { if obj, ok := obj.(*TypeName); ok {
return obj.typ return obj.typ
} }

View File

@ -146,7 +146,7 @@ func TestGcImportedTypes(t *testing.T) {
continue continue
} }
obj := pkg.scope.Lookup(nil, objName) obj := pkg.scope.Lookup(objName)
// TODO(gri) should define an accessor on Object // TODO(gri) should define an accessor on Object
var kind ast.ObjKind var kind ast.ObjKind

36
go/types/objset.go Normal file
View File

@ -0,0 +1,36 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file implements objsets.
//
// An objset is similar to a Scope but objset elements
// are identified by their unique id, instead of their
// object name.
package types
// An objset is a set of objects identified by their unique id.
// The zero value for objset is a ready-to-use empty objset.
type objset struct {
objmap map[string]Object // allocated lazily
}
// insert attempts to insert an object obj into objset s.
// If s already contains an alternative object alt with
// the same name, insert leaves s unchanged and returns alt.
// Otherwise it inserts obj and returns nil.
// The object name must not be blank _.
func (s *objset) insert(obj Object) (alt Object) {
name := obj.Name()
assert(name != "_")
id := Id(obj.Pkg(), name)
if alt := s.objmap[id]; alt != nil {
return alt
}
if s.objmap == nil {
s.objmap = make(map[string]Object)
}
s.objmap[id] = obj
return nil
}

View File

@ -23,14 +23,29 @@ func (check *checker) reportAltDecl(obj Object) {
} }
} }
func (check *checker) declare(scope *Scope, id *ast.Ident, obj Object) { func (check *checker) declareObj(scope *Scope, id *ast.Ident, obj Object) {
if obj.Name() == "_" { if obj.Name() == "_" {
// blank identifiers are not declared // blank identifiers are not declared
obj.setParent(scope) obj.setParent(scope)
obj = nil
} else if alt := scope.Insert(obj); alt != nil { } else if alt := scope.Insert(obj); alt != nil {
check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name()) check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
check.reportAltDecl(alt) check.reportAltDecl(alt)
obj = nil // for callIdent below obj = nil
}
if id != nil {
check.recordObject(id, obj)
}
}
func (check *checker) declareFld(oset *objset, id *ast.Ident, obj Object) {
if obj.Name() == "_" {
// blank identifiers are not declared
obj = nil
} else if alt := oset.insert(obj); alt != nil {
check.errorf(obj.Pos(), "%s redeclared", obj.Name())
check.reportAltDecl(alt)
obj = nil
} }
if id != nil { if id != nil {
check.recordObject(id, obj) check.recordObject(id, obj)
@ -128,7 +143,7 @@ func (check *checker) resolveFiles(files []*ast.File) {
return return
} }
check.declare(pkg.scope, ident, obj) check.declareObj(pkg.scope, ident, obj)
objList = append(objList, obj) objList = append(objList, obj)
objMap[obj] = declInfo{scope, typ, init, nil} objMap[obj] = declInfo{scope, typ, init, nil}
} }
@ -195,13 +210,13 @@ func (check *checker) resolveFiles(files []*ast.File) {
if obj.IsExported() { if obj.IsExported() {
// Note: This will change each imported object's scope! // Note: This will change each imported object's scope!
// May be an issue for types aliases. // May be an issue for types aliases.
check.declare(scope, nil, obj) check.declareObj(scope, nil, obj)
check.recordImplicit(s, obj) check.recordImplicit(s, obj)
} }
} }
} else { } else {
// declare imported package object in file scope // declare imported package object in file scope
check.declare(scope, nil, imp2) check.declareObj(scope, nil, imp2)
} }
case *ast.ValueSpec: case *ast.ValueSpec:
@ -281,7 +296,7 @@ func (check *checker) resolveFiles(files []*ast.File) {
obj.parent = pkg.scope obj.parent = pkg.scope
check.recordObject(d.Name, obj) check.recordObject(d.Name, obj)
} else { } else {
check.declare(pkg.scope, d.Name, obj) check.declareObj(pkg.scope, d.Name, obj)
} }
} else { } else {
// Associate method with receiver base type name, if possible. // Associate method with receiver base type name, if possible.
@ -313,7 +328,7 @@ func (check *checker) resolveFiles(files []*ast.File) {
for _, scope := range scopes { for _, scope := range scopes {
for _, obj := range scope.entries { for _, obj := range scope.entries {
if alt := pkg.scope.Lookup(nil, obj.Name()); alt != nil { if alt := pkg.scope.Lookup(obj.Name()); alt != nil {
check.errorf(alt.Pos(), "%s already declared in this file through import of package %s", obj.Name(), obj.Pkg().Name()) check.errorf(alt.Pos(), "%s already declared in this file through import of package %s", obj.Name(), obj.Pkg().Name())
} }
} }
@ -503,41 +518,39 @@ func (check *checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, cycleOk
// spec: "For a base type, the non-blank names of methods bound // spec: "For a base type, the non-blank names of methods bound
// to it must be unique." // to it must be unique."
// => use a scope to determine redeclarations // => use an objset to determine redeclarations
scope := NewScope(nil) var mset objset
// spec: "If the base type is a struct type, the non-blank method // spec: "If the base type is a struct type, the non-blank method
// and field names must be distinct." // and field names must be distinct."
// => pre-populate the scope to find conflicts // => pre-populate the objset to find conflicts
// TODO(gri) consider keeping the objset with the struct instead
if t, _ := named.underlying.(*Struct); t != nil { if t, _ := named.underlying.(*Struct); t != nil {
for _, fld := range t.fields { for _, fld := range t.fields {
if fld.name != "_" { if fld.name != "_" {
scope.Insert(fld) assert(mset.insert(fld) == nil)
} }
} }
} }
// check each method // check each method
for _, m := range methods { for _, m := range methods {
assert(m.name != "_") // _ methods were excluded before ident := check.objMap[m].fdecl.Name
mdecl := check.objMap[m]
alt := scope.Insert(m)
m.parent = mdecl.file // correct parent scope (scope.Insert used scope)
if alt != nil { if alt := mset.insert(m); alt != nil {
switch alt := alt.(type) { switch alt.(type) {
case *Var: case *Var:
check.errorf(m.pos, "field and method with the same name %s", m.name) check.errorf(m.pos, "field and method with the same name %s", m.name)
check.reportAltDecl(alt)
m = nil
case *Func: case *Func:
check.errorf(m.pos, "method %s already declared for %s", m.name, named) check.errorf(m.pos, "method %s already declared for %s", m.name, named)
default:
unreachable()
}
check.reportAltDecl(alt) check.reportAltDecl(alt)
m = nil m = nil
} }
}
check.recordObject(mdecl.fdecl.Name, m) check.recordObject(ident, m)
// If the method is valid, type-check its signature, // If the method is valid, type-check its signature,
// and collect it with the named base type. // and collect it with the named base type.
@ -604,7 +617,7 @@ func (check *checker) declStmt(decl ast.Decl) {
check.arityMatch(s, last) check.arityMatch(s, last)
for i, name := range s.Names { for i, name := range s.Names {
check.declare(check.topScope, name, lhs[i]) check.declareObj(check.topScope, name, lhs[i])
} }
case token.VAR: case token.VAR:
@ -637,7 +650,7 @@ func (check *checker) declStmt(decl ast.Decl) {
check.arityMatch(s, nil) check.arityMatch(s, nil)
for i, name := range s.Names { for i, name := range s.Names {
check.declare(check.topScope, name, lhs[i]) check.declareObj(check.topScope, name, lhs[i])
} }
default: default:
@ -646,7 +659,7 @@ func (check *checker) declStmt(decl ast.Decl) {
case *ast.TypeSpec: case *ast.TypeSpec:
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil) obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
check.declare(check.topScope, s.Name, obj) check.declareObj(check.topScope, s.Name, obj)
check.typeDecl(obj, s.Type, nil, false) check.typeDecl(obj, s.Type, nil, false)
default: default:

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// This file implements Scopes.
package types package types
import ( import (
@ -16,15 +18,16 @@ import (
// objects can use that information for better printing. // objects can use that information for better printing.
// A Scope maintains a set of objects and links to its containing // A Scope maintains a set of objects and links to its containing
// (parent) and contained (children) scopes. // (parent) and contained (children) scopes. Objects may be inserted
// Objects may be inserted and looked up by name, or by package path // and looked up by name. The zero value for Scope is a ready-to-use
// and name. A nil *Scope acts like an empty scope for operations that // empty scope.
// do not modify the scope or access a scope's parent scope.
type Scope struct { type Scope struct {
parent *Scope parent *Scope
children []*Scope children []*Scope
entries []Object
node ast.Node node ast.Node
entries []Object
objmap map[string]Object // lazily allocated for large scopes
} }
// NewScope returns a new, empty scope contained in the given parent // NewScope returns a new, empty scope contained in the given parent
@ -60,74 +63,39 @@ func (s *Scope) Parent() *Scope { return s.parent }
func (s *Scope) Node() ast.Node { return s.node } func (s *Scope) Node() ast.Node { return s.node }
// NumEntries() returns the number of scope entries. // NumEntries() returns the number of scope entries.
// If s == nil, the result is 0. func (s *Scope) NumEntries() int { return len(s.entries) }
func (s *Scope) NumEntries() int {
if s == nil {
return 0 // empty scope
}
return len(s.entries)
}
// At returns the i'th scope entry for 0 <= i < NumEntries(). // At returns the i'th scope entry for 0 <= i < NumEntries().
func (s *Scope) At(i int) Object { return s.entries[i] } func (s *Scope) At(i int) Object { return s.entries[i] }
// NumChildren() returns the number of scopes nested in s. // NumChildren() returns the number of scopes nested in s.
// If s == nil, the result is 0. func (s *Scope) NumChildren() int { return len(s.children) }
func (s *Scope) NumChildren() int {
if s == nil {
return 0
}
return len(s.children)
}
// Child returns the i'th child scope for 0 <= i < NumChildren(). // Child returns the i'th child scope for 0 <= i < NumChildren().
func (s *Scope) Child(i int) *Scope { return s.children[i] } func (s *Scope) Child(i int) *Scope { return s.children[i] }
// Lookup returns the object in scope s with the given package // Lookup returns the object in scope s with the given name if such an
// and name if such an object exists; otherwise the result is nil. // object exists; otherwise the result is nil.
// A nil scope acts like an empty scope, and parent scopes are ignored. func (s *Scope) Lookup(name string) Object {
// if s.objmap != nil {
// If pkg != nil, both pkg.Path() and name are used to identify an return s.objmap[name]
// entry, per the Go rules for identifier equality. If pkg == nil,
// only the name is used and the package path is ignored.
func (s *Scope) Lookup(pkg *Package, name string) Object {
if s == nil {
return nil // empty scope
} }
// fast path: only the name must match
if pkg == nil {
for _, obj := range s.entries { for _, obj := range s.entries {
if obj.Name() == name { if obj.Name() == name {
return obj return obj
} }
} }
return nil return nil
}
// slow path: both pkg path and name must match
for _, obj := range s.entries {
if obj.sameId(pkg, name) {
return obj
}
}
// not found
return nil
// TODO(gri) Optimize Lookup by also maintaining a map representation
// for larger scopes.
} }
// LookupParent follows the parent chain of scopes starting with s until it finds // LookupParent follows the parent chain of scopes starting with s until
// a scope where Lookup(nil, name) returns a non-nil object, and then returns that // it finds a scope where Lookup(name) returns a non-nil object, and then
// object. If no such scope exists, the result is nil. // returns that object. If no such scope exists, the result is nil.
func (s *Scope) LookupParent(name string) Object { func (s *Scope) LookupParent(name string) Object {
for s != nil { for ; s != nil; s = s.parent {
if obj := s.Lookup(nil, name); obj != nil { if obj := s.Lookup(name); obj != nil {
return obj return obj
} }
s = s.parent
} }
return nil return nil
} }
@ -135,19 +103,34 @@ func (s *Scope) LookupParent(name string) Object {
// TODO(gri): Should Insert not be exported? // TODO(gri): Should Insert not be exported?
// Insert attempts to insert an object obj into scope s. // Insert attempts to insert an object obj into scope s.
// If s already contains an object with the same package path // If s already contains an alternative object alt with
// and name, Insert leaves s unchanged and returns that object. // the same name, Insert leaves s unchanged and returns alt.
// Otherwise it inserts obj, sets the object's scope to s, and // Otherwise it inserts obj, sets the object's scope to
// returns nil. The object must not have the blank _ name. // s, and returns nil. The object name must not be blank _.
//
func (s *Scope) Insert(obj Object) Object { func (s *Scope) Insert(obj Object) Object {
name := obj.Name() name := obj.Name()
assert(name != "_") assert(name != "_")
if alt := s.Lookup(obj.Pkg(), name); alt != nil { if alt := s.Lookup(name); alt != nil {
return alt return alt
} }
// populate parallel objmap for larger scopes
// TODO(gri) what is the right threshold? should we only use a map?
if len(s.entries) == 32 {
m := make(map[string]Object)
for _, obj := range s.entries {
m[obj.Name()] = obj
}
s.objmap = m
}
// add object
s.entries = append(s.entries, obj) s.entries = append(s.entries, obj)
if s.objmap != nil {
s.objmap[name] = obj
}
obj.setParent(s) obj.setParent(s)
return nil return nil
} }
@ -159,7 +142,7 @@ func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) {
const ind = ". " const ind = ". "
indn := strings.Repeat(ind, n) indn := strings.Repeat(ind, n)
if s.NumEntries() == 0 { if len(s.entries) == 0 {
fmt.Fprintf(w, "%sscope %p {}\n", indn, s) fmt.Fprintf(w, "%sscope %p {}\n", indn, s)
return return
} }

View File

@ -85,7 +85,7 @@ func (check *checker) stmt(s ast.Stmt) {
check.funcSig.labels = scope check.funcSig.labels = scope
} }
label := s.Label label := s.Label
check.declare(scope, label, NewLabel(label.Pos(), label.Name)) check.declareObj(scope, label, NewLabel(label.Pos(), label.Name))
check.stmt(s.Stmt) check.stmt(s.Stmt)
case *ast.ExprStmt: case *ast.ExprStmt:
@ -267,7 +267,7 @@ func (check *checker) stmt(s ast.Stmt) {
if tag == nil { if tag == nil {
// use fake true tag value and position it at the opening { of the switch // use fake true tag value and position it at the opening { of the switch
ident := &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"} ident := &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
check.recordObject(ident, Universe.Lookup(nil, "true")) check.recordObject(ident, Universe.Lookup("true"))
tag = ident tag = ident
} }
check.expr(&x, tag) check.expr(&x, tag)
@ -416,7 +416,7 @@ func (check *checker) stmt(s ast.Stmt) {
typ = x.typ typ = x.typ
} }
obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, typ) obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, typ)
check.declare(check.topScope, nil, obj) check.declareObj(check.topScope, nil, obj)
check.recordImplicit(clause, obj) check.recordImplicit(clause, obj)
} }
check.stmtList(clause.Body) check.stmtList(clause.Body)
@ -552,7 +552,7 @@ func (check *checker) stmt(s ast.Stmt) {
// declare variables // declare variables
for i, ident := range idents { for i, ident := range idents {
check.declare(check.topScope, ident, vars[i]) check.declareObj(check.topScope, ident, vars[i])
} }
} else { } else {
// ordinary assignment // ordinary assignment

View File

@ -193,7 +193,7 @@ func (t *Tuple) At(i int) *Var { return t.vars[i] }
// A Signature represents a (non-builtin) function type. // A Signature represents a (non-builtin) function type.
type Signature struct { type Signature struct {
scope *Scope // function scope scope *Scope // function scope, always present
labels *Scope // label scope, or nil (lazily allocated) labels *Scope // label scope, or nil (lazily allocated)
recv *Var // nil if not a method recv *Var // nil if not a method
params *Tuple // (incoming) parameters from left to right; or nil params *Tuple // (incoming) parameters from left to right; or nil
@ -205,7 +205,9 @@ type Signature struct {
// and results, either of which may be nil. If isVariadic is set, the function // and results, either of which may be nil. If isVariadic is set, the function
// is variadic, it must have at least one parameter, and the last parameter // is variadic, it must have at least one parameter, and the last parameter
// must be of unnamed slice type. // must be of unnamed slice type.
func NewSignature(recv *Var, params, results *Tuple, isVariadic bool) *Signature { func NewSignature(scope *Scope, recv *Var, params, results *Tuple, isVariadic bool) *Signature {
// TODO(gri) Should we rely on the correct (non-nil) incoming scope
// or should this function allocate and populate a scope?
if isVariadic { if isVariadic {
n := params.Len() n := params.Len()
if n == 0 { if n == 0 {
@ -215,7 +217,7 @@ func NewSignature(recv *Var, params, results *Tuple, isVariadic bool) *Signature
panic("types.NewSignature: variadic parameter must be of unnamed slice type") panic("types.NewSignature: variadic parameter must be of unnamed slice type")
} }
} }
return &Signature{nil, nil, recv, params, results, isVariadic} return &Signature{scope, nil, recv, params, results, isVariadic}
} }
// Recv returns the receiver of signature s, or nil. // Recv returns the receiver of signature s, or nil.

View File

@ -110,7 +110,7 @@ func TestTypes(t *testing.T) {
t.Errorf("%s: %s", src, err) t.Errorf("%s: %s", src, err)
continue continue
} }
typ := pkg.scope.Lookup(nil, "T").Type().Underlying() typ := pkg.scope.Lookup("T").Type().Underlying()
str := typeString(typ) str := typeString(typ)
if str != test.str { if str != test.str {
t.Errorf("%s: got %s, want %s", test.src, str, test.str) t.Errorf("%s: got %s, want %s", test.src, str, test.str)

View File

@ -360,7 +360,7 @@ func (check *checker) collectParams(scope *Scope, list *ast.FieldList, variadicO
// named parameter // named parameter
for _, name := range field.Names { for _, name := range field.Names {
par := NewVar(name.Pos(), check.pkg, name.Name, typ) par := NewVar(name.Pos(), check.pkg, name.Name, typ)
check.declare(scope, name, par) check.declareObj(scope, name, par)
params = append(params, par) params = append(params, par)
} }
} else { } else {
@ -385,7 +385,8 @@ func (check *checker) collectMethods(recv Type, list *ast.FieldList, cycleOk boo
return nil return nil
} }
scope := NewScope(nil) var mset objset
for _, f := range list.List { for _, f := range list.List {
// TODO(gri) Consider calling funcType here. // TODO(gri) Consider calling funcType here.
typ := check.typ(f.Type, nil, cycleOk) typ := check.typ(f.Type, nil, cycleOk)
@ -402,7 +403,7 @@ func (check *checker) collectMethods(recv Type, list *ast.FieldList, cycleOk boo
sig.recv = NewVar(token.NoPos, check.pkg, "", recv) sig.recv = NewVar(token.NoPos, check.pkg, "", recv)
for _, name := range f.Names { for _, name := range f.Names {
m := NewFunc(name.Pos(), check.pkg, name.Name, sig) m := NewFunc(name.Pos(), check.pkg, name.Name, sig)
check.declare(scope, name, m) check.declareFld(&mset, name, m)
methods = append(methods, m) methods = append(methods, m)
} }
} else { } else {
@ -417,7 +418,7 @@ func (check *checker) collectMethods(recv Type, list *ast.FieldList, cycleOk boo
check.errorf(f.Type.Pos(), "reference to incomplete type %s - unimplemented", f.Type) check.errorf(f.Type.Pos(), "reference to incomplete type %s - unimplemented", f.Type)
case *Interface: case *Interface:
for _, m := range t.methods { for _, m := range t.methods {
check.declare(scope, nil, m) check.declareFld(&mset, nil, m)
methods = append(methods, m) methods = append(methods, m)
} }
default: default:
@ -448,7 +449,7 @@ func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields [
return return
} }
scope := NewScope(nil) var fset objset
var typ Type // current field typ var typ Type // current field typ
var tag string // current field tag var tag string // current field tag
@ -461,7 +462,7 @@ func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields [
} }
fld := NewFieldVar(pos, check.pkg, name, typ, anonymous) fld := NewFieldVar(pos, check.pkg, name, typ, anonymous)
check.declare(scope, ident, fld) check.declareFld(&fset, ident, fld)
fields = append(fields, fld) fields = append(fields, fld)
} }

View File

@ -116,7 +116,7 @@ func init() {
def(NewFunc(token.NoPos, nil, f.name, f)) def(NewFunc(token.NoPos, nil, f.name, f))
} }
universeIota = Universe.Lookup(nil, "iota").(*Const) universeIota = Universe.Lookup("iota").(*Const)
} }
// Objects with names containing blanks are internal and not entered into // Objects with names containing blanks are internal and not entered into

View File

@ -116,7 +116,7 @@ func (info *PackageInfo) IsType(e ast.Expr) bool {
func (info *PackageInfo) IsPackageRef(sel *ast.SelectorExpr) types.Object { func (info *PackageInfo) IsPackageRef(sel *ast.SelectorExpr) types.Object {
if id, ok := sel.X.(*ast.Ident); ok { if id, ok := sel.X.(*ast.Ident); ok {
if pkg, ok := info.ObjectOf(id).(*types.Package); ok { if pkg, ok := info.ObjectOf(id).(*types.Package); ok {
return pkg.Scope().Lookup(nil, sel.Sel.Name) return pkg.Scope().Lookup(sel.Sel.Name)
} }
} }
return nil return nil
@ -245,5 +245,5 @@ func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature
panic("unknown builtin: " + builtin) panic("unknown builtin: " + builtin)
} }
return types.NewSignature(nil, types.NewTuple(params...), nil, isVariadic) return types.NewSignature(nil, nil, types.NewTuple(params...), nil, isVariadic)
} }

View File

@ -1716,7 +1716,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value
} else { } else {
// length = len(x). // length = len(x).
var c Call var c Call
c.Call.Func = fn.Prog.builtins[types.Universe.Lookup(nil, "len")] c.Call.Func = fn.Prog.builtins[types.Universe.Lookup("len")]
c.Call.Args = []Value{x} c.Call.Args = []Value{x}
c.setType(tInt) c.setType(tInt)
length = fn.emit(&c) length = fn.emit(&c)

View File

@ -394,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 // that is needed is the "pointerness" of Recv.Type, and for
// now, we'll set it to always be false since we're only // now, we'll set it to always be false since we're only
// concerned with rtype. Encapsulate this better. // concerned with rtype. Encapsulate this better.
sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", recvType), nil, nil, false) sig := types.NewSignature(nil, types.NewVar(token.NoPos, nil, "recv", recvType), nil, nil, false)
fn := ssa.NewFunction(name, sig, "fake reflect method") fn := ssa.NewFunction(name, sig, "fake reflect method")
fn.Pkg = pkg fn.Pkg = pkg
fn.Prog = pkg.Prog fn.Prog = pkg.Prog

View File

@ -140,7 +140,7 @@ func makeMethod(prog *Program, typ types.Type, obj *types.Method) *Function {
// //
func promotionWrapper(prog *Program, typ types.Type, obj *types.Method) *Function { func promotionWrapper(prog *Program, typ types.Type, obj *types.Method) *Function {
old := obj.Func.Type().(*types.Signature) old := obj.Func.Type().(*types.Signature)
sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", typ), old.Params(), old.Results(), old.IsVariadic()) sig := types.NewSignature(nil, types.NewVar(token.NoPos, nil, "recv", typ), old.Params(), old.Results(), old.IsVariadic())
// TODO(adonovan): include implicit field path in description. // TODO(adonovan): include implicit field path in description.
description := fmt.Sprintf("promotion wrapper for (%s).%s", old.Recv(), obj.Func.Name()) description := fmt.Sprintf("promotion wrapper for (%s).%s", old.Recv(), obj.Func.Name())
@ -310,7 +310,7 @@ func boundMethodWrapper(meth *Function) *Function {
s := meth.Signature s := meth.Signature
fn = &Function{ fn = &Function{
name: "bound$" + meth.String(), name: "bound$" + meth.String(),
Signature: types.NewSignature(nil, s.Params(), s.Results(), s.IsVariadic()), // drop recv Signature: types.NewSignature(nil, nil, s.Params(), s.Results(), s.IsVariadic()), // drop recv
Synthetic: "bound method wrapper for " + meth.String(), Synthetic: "bound method wrapper for " + meth.String(),
Prog: prog, Prog: prog,
pos: meth.Pos(), pos: meth.Pos(),
@ -359,7 +359,7 @@ func indirectionWrapper(meth *Function) *Function {
// TODO(adonovan): is there a *types.Func for this method? // TODO(adonovan): is there a *types.Func for this method?
fn = &Function{ fn = &Function{
name: meth.Name(), name: meth.Name(),
Signature: types.NewSignature(recv, s.Params(), s.Results(), s.IsVariadic()), Signature: types.NewSignature(nil, recv, s.Params(), s.Results(), s.IsVariadic()),
Prog: prog, Prog: prog,
Synthetic: "receiver indirection wrapper for " + meth.String(), Synthetic: "receiver indirection wrapper for " + meth.String(),
pos: meth.Pos(), pos: meth.Pos(),