mirror of
https://github.com/golang/go
synced 2024-11-18 16:14:46 -07:00
go.tools/go/types: faster scopes, cleanups around method lookups
R=adonovan CC=golang-dev https://golang.org/cl/11787043
This commit is contained in:
parent
6dbbc59ae0
commit
c98ff05fdd
@ -288,11 +288,11 @@ func (check *checker) shortVarDecl(lhs, rhs []ast.Expr) {
|
||||
check.initVars(vars, rhs, true)
|
||||
|
||||
// declare variables
|
||||
n := scope.NumEntries()
|
||||
n := scope.Len()
|
||||
for _, obj := range vars {
|
||||
scope.Insert(obj)
|
||||
}
|
||||
if n == scope.NumEntries() {
|
||||
if n == scope.Len() {
|
||||
check.errorf(vars[0].Pos(), "no new variables on left side of :=")
|
||||
}
|
||||
}
|
||||
|
@ -237,7 +237,7 @@ func (check *checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||
}
|
||||
|
||||
// verify that m is in the method set of x.typ
|
||||
if _, isPtr := deref(m.typ.(*Signature).recv.typ); isPtr && !indirect {
|
||||
if !indirect && ptrRecv(m) {
|
||||
check.invalidOp(e.Pos(), "%s is not in method set of %s", sel, x.typ)
|
||||
goto Error
|
||||
}
|
||||
@ -271,7 +271,7 @@ func (check *checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||
// contains m and the argument list can be assigned to the parameter
|
||||
// list of m. If x is addressable and &x's method set contains m, x.m()
|
||||
// is shorthand for (&x).m()".
|
||||
if _, isPtr := deref(obj.typ.(*Signature).recv.typ); isPtr && !indirect && x.mode != variable {
|
||||
if !indirect && x.mode != variable && ptrRecv(obj) {
|
||||
check.invalidOp(e.Pos(), "%s is not in method set of %s", sel, x)
|
||||
goto Error
|
||||
}
|
||||
@ -281,7 +281,7 @@ func (check *checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||
typ := x.typ
|
||||
if x.mode == variable {
|
||||
// If typ is not an (unnamed) pointer, use *typ instead,
|
||||
// because the the method set of *typ includes the methods
|
||||
// because the method set of *typ includes the methods
|
||||
// of typ.
|
||||
// Variables are addressable, so we can always take their
|
||||
// address.
|
||||
|
@ -98,7 +98,7 @@ func lookupFieldOrMethod(typ Type, pkg *Package, name string) (obj Object, index
|
||||
return // blank fields/methods are never found
|
||||
}
|
||||
|
||||
// Start with typ as single entry at lowest depth.
|
||||
// Start with typ as single entry at shallowest depth.
|
||||
// If typ is not a named type, insert a nil type instead.
|
||||
typ, isPtr := deref(typ)
|
||||
t, _ := typ.(*Named)
|
||||
@ -280,11 +280,8 @@ func MissingMethod(typ Type, T *Interface) (method *Func, wrongType bool) {
|
||||
}
|
||||
|
||||
// verify that f is in the method set of typ
|
||||
// (the receiver is nil if f is an interface method)
|
||||
if recv := f.typ.(*Signature).recv; recv != nil {
|
||||
if _, isPtr := deref(recv.typ); isPtr && !indirect {
|
||||
return m, false
|
||||
}
|
||||
if !indirect && ptrRecv(f) {
|
||||
return m, false
|
||||
}
|
||||
|
||||
if !IsIdentical(obj.Type(), m.typ) {
|
||||
|
@ -143,7 +143,7 @@ func NewMethodSet(T Type) *MethodSet {
|
||||
// method set up to the current depth, allocated lazily
|
||||
var base methodSet
|
||||
|
||||
// Start with typ as single entry at lowest depth.
|
||||
// Start with typ as single entry at shallowest depth.
|
||||
// If typ is not a named type, insert a nil type instead.
|
||||
typ, isPtr := deref(T)
|
||||
t, _ := typ.(*Named)
|
||||
@ -258,7 +258,7 @@ func NewMethodSet(T Type) *MethodSet {
|
||||
|
||||
// A fieldSet is a set of fields and name collisions.
|
||||
// A collision indicates that multiple fields with the
|
||||
// same unique name appeared.
|
||||
// same unique id appeared.
|
||||
type fieldSet map[string]*Var // a nil entry indicates a name collision
|
||||
|
||||
// Add adds field f to the field set s.
|
||||
@ -282,7 +282,7 @@ func (s fieldSet) add(f *Var, multiples bool) fieldSet {
|
||||
|
||||
// A methodSet is a set of methods and name collisions.
|
||||
// A collision indicates that multiple methods with the
|
||||
// same unique name appeared.
|
||||
// same unique id appeared.
|
||||
type methodSet map[string]*Method // a nil entry indicates a name collision
|
||||
|
||||
// Add adds all functions in list to the method set s.
|
||||
|
@ -13,7 +13,7 @@ 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
|
||||
elems map[string]Object // allocated lazily
|
||||
}
|
||||
|
||||
// insert attempts to insert an object obj into objset s.
|
||||
@ -27,12 +27,12 @@ func (s *objset) insert(obj Object) Object {
|
||||
return nil
|
||||
}
|
||||
id := Id(obj.Pkg(), name)
|
||||
if alt := s.objmap[id]; alt != nil {
|
||||
if alt := s.elems[id]; alt != nil {
|
||||
return alt
|
||||
}
|
||||
if s.objmap == nil {
|
||||
s.objmap = make(map[string]Object)
|
||||
if s.elems == nil {
|
||||
s.elems = make(map[string]Object)
|
||||
}
|
||||
s.objmap[id] = obj
|
||||
s.elems[id] = obj
|
||||
return nil
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ func (check *checker) resolveFiles(files []*ast.File) {
|
||||
// add import to file scope
|
||||
if name == "." {
|
||||
// merge imported scope with file scope
|
||||
for _, obj := range imp.scope.entries {
|
||||
for _, obj := range imp.scope.elems {
|
||||
// gcimported package scopes contain non-exported
|
||||
// objects such as types used in partially exported
|
||||
// objects - do not accept them
|
||||
@ -320,7 +320,7 @@ func (check *checker) resolveFiles(files []*ast.File) {
|
||||
// Phase 2: Verify that objects in package and file scopes have different names.
|
||||
|
||||
for _, scope := range scopes {
|
||||
for _, obj := range scope.entries {
|
||||
for _, obj := range scope.elems {
|
||||
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())
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -25,20 +26,18 @@ type Scope struct {
|
||||
parent *Scope
|
||||
children []*Scope
|
||||
node ast.Node
|
||||
|
||||
entries []Object
|
||||
objmap map[string]Object // lazily allocated for large scopes
|
||||
elems map[string]Object // lazily allocated
|
||||
}
|
||||
|
||||
// NewScope returns a new, empty scope contained in the given parent
|
||||
// scope, if any.
|
||||
func NewScope(parent *Scope) *Scope {
|
||||
scope := &Scope{parent: parent}
|
||||
s := &Scope{parent: parent}
|
||||
// don't add children to Universe scope!
|
||||
if parent != nil && parent != Universe {
|
||||
parent.children = append(parent.children, scope)
|
||||
parent.children = append(parent.children, s)
|
||||
}
|
||||
return scope
|
||||
return s
|
||||
}
|
||||
|
||||
// Parent returns the scope's containing (parent) scope.
|
||||
@ -62,11 +61,20 @@ func (s *Scope) Parent() *Scope { return s.parent }
|
||||
// (universe and package scopes).
|
||||
func (s *Scope) Node() ast.Node { return s.node }
|
||||
|
||||
// NumEntries() returns the number of scope entries.
|
||||
func (s *Scope) NumEntries() int { return len(s.entries) }
|
||||
// Len() returns the number of scope elements.
|
||||
func (s *Scope) Len() int { return len(s.elems) }
|
||||
|
||||
// At returns the i'th scope entry for 0 <= i < NumEntries().
|
||||
func (s *Scope) At(i int) Object { return s.entries[i] }
|
||||
// Names returns the scope's element names in sorted order.
|
||||
func (s *Scope) Names() []string {
|
||||
names := make([]string, len(s.elems))
|
||||
i := 0
|
||||
for name := range s.elems {
|
||||
names[i] = name
|
||||
i++
|
||||
}
|
||||
sort.Strings(names)
|
||||
return names
|
||||
}
|
||||
|
||||
// NumChildren() returns the number of scopes nested in s.
|
||||
func (s *Scope) NumChildren() int { return len(s.children) }
|
||||
@ -77,15 +85,7 @@ func (s *Scope) Child(i int) *Scope { return s.children[i] }
|
||||
// Lookup returns the object in scope s with the given name if such an
|
||||
// object exists; otherwise the result is nil.
|
||||
func (s *Scope) Lookup(name string) Object {
|
||||
if s.objmap != nil {
|
||||
return s.objmap[name]
|
||||
}
|
||||
for _, obj := range s.entries {
|
||||
if obj.Name() == name {
|
||||
return obj
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return s.elems[name]
|
||||
}
|
||||
|
||||
// LookupParent follows the parent chain of scopes starting with s until
|
||||
@ -93,7 +93,7 @@ func (s *Scope) Lookup(name string) Object {
|
||||
// returns that object. If no such scope exists, the result is nil.
|
||||
func (s *Scope) LookupParent(name string) Object {
|
||||
for ; s != nil; s = s.parent {
|
||||
if obj := s.Lookup(name); obj != nil {
|
||||
if obj := s.elems[name]; obj != nil {
|
||||
return obj
|
||||
}
|
||||
}
|
||||
@ -110,7 +110,6 @@ func (s *Scope) LookupParent(name string) Object {
|
||||
// not inserted, but have their parent field set to s.
|
||||
func (s *Scope) Insert(obj Object) Object {
|
||||
name := obj.Name()
|
||||
|
||||
// spec: "The blank identifier, represented by the underscore
|
||||
// character _, may be used in a declaration like any other
|
||||
// identifier but the declaration does not introduce a new
|
||||
@ -119,48 +118,35 @@ func (s *Scope) Insert(obj Object) Object {
|
||||
obj.setParent(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
if alt := s.Lookup(name); alt != nil {
|
||||
if alt := s.elems[name]; alt != nil {
|
||||
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)
|
||||
if s.objmap != nil {
|
||||
s.objmap[name] = obj
|
||||
if s.elems == nil {
|
||||
s.elems = make(map[string]Object)
|
||||
}
|
||||
s.elems[name] = obj
|
||||
obj.setParent(s)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteTo writes a string representation of the scope to w.
|
||||
// WriteTo writes a string representation of the scope to w,
|
||||
// with the scope elements sorted by name.
|
||||
// The level of indentation is controlled by n >= 0, with
|
||||
// n == 0 for no indentation.
|
||||
// If recurse is set, it also prints nested (children) scopes.
|
||||
// If recurse is set, it also writes nested (children) scopes.
|
||||
func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) {
|
||||
const ind = ". "
|
||||
indn := strings.Repeat(ind, n)
|
||||
|
||||
if len(s.entries) == 0 {
|
||||
if len(s.elems) == 0 {
|
||||
fmt.Fprintf(w, "%sscope %p {}\n", indn, s)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "%sscope %p {\n", indn, s)
|
||||
indn1 := indn + ind
|
||||
for _, obj := range s.entries {
|
||||
fmt.Fprintf(w, "%s%s\n", indn1, obj)
|
||||
for _, name := range s.Names() {
|
||||
fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name])
|
||||
}
|
||||
|
||||
if recurse {
|
||||
|
@ -81,7 +81,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
||||
case *ast.LabeledStmt:
|
||||
scope := check.funcSig.labels
|
||||
if scope == nil {
|
||||
scope = new(Scope) // no label scope chain
|
||||
scope = NewScope(nil) // no label scope chain
|
||||
check.funcSig.labels = scope
|
||||
}
|
||||
label := s.Label
|
||||
|
@ -86,8 +86,8 @@ var predeclaredFunctions = [...]*Builtin{
|
||||
}
|
||||
|
||||
func init() {
|
||||
Universe = new(Scope)
|
||||
Unsafe = NewPackage(token.NoPos, "unsafe", "unsafe", NewScope(nil), nil, true)
|
||||
Universe = NewScope(nil)
|
||||
Unsafe = NewPackage(token.NoPos, "unsafe", "unsafe", NewScope(Universe), nil, true)
|
||||
|
||||
// predeclared types
|
||||
for _, t := range Typ {
|
||||
|
@ -48,8 +48,8 @@ func NewProgram(fset *token.FileSet, mode BuilderMode) *Program {
|
||||
}
|
||||
|
||||
// Create Values for built-in functions.
|
||||
for i, n := 0, types.Universe.NumEntries(); i < n; i++ {
|
||||
if obj, ok := types.Universe.At(i).(*types.Func); ok {
|
||||
for _, name := range types.Universe.Names() {
|
||||
if obj, ok := types.Universe.Lookup(name).(*types.Func); ok {
|
||||
prog.builtins[obj] = &Builtin{obj}
|
||||
}
|
||||
}
|
||||
@ -237,8 +237,8 @@ func (prog *Program) CreatePackage(info *importer.PackageInfo) *Package {
|
||||
// No code.
|
||||
// No position information.
|
||||
scope := p.Object.Scope()
|
||||
for i, n := 0, scope.NumEntries(); i < n; i++ {
|
||||
obj := scope.At(i)
|
||||
for _, name := range scope.Names() {
|
||||
obj := scope.Lookup(name)
|
||||
if obj, ok := obj.(*types.TypeName); ok {
|
||||
// TODO(adonovan): are the set of Func
|
||||
// objects passed to memberFromObject
|
||||
|
Loading…
Reference in New Issue
Block a user