зеркало из https://github.com/golang/tools.git
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:
Родитель
2f54663e0e
Коммит
66e7552830
|
@ -264,7 +264,7 @@ func (check *checker) shortVarDecl(lhs, rhs []ast.Expr) {
|
|||
// Use the correct obj if the ident is redeclared. The
|
||||
// variable's scope starts after the declaration; so we
|
||||
// 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
|
||||
if alt, _ := alt.(*Var); alt != nil {
|
||||
obj = alt
|
||||
|
|
|
@ -171,7 +171,7 @@ func (check *checker) selector(x *operand, e *ast.SelectorExpr) {
|
|||
if ident, ok := e.X.(*ast.Ident); ok {
|
||||
if pkg, ok := check.topScope.LookupParent(ident.Name).(*Package); ok {
|
||||
check.recordObject(ident, pkg)
|
||||
exp := pkg.scope.Lookup(nil, sel)
|
||||
exp := pkg.scope.Lookup(sel)
|
||||
if exp == nil {
|
||||
check.errorf(e.Pos(), "%s not declared by package %s", sel, ident)
|
||||
goto Error
|
||||
|
|
|
@ -207,7 +207,7 @@ func declConst(pkg *Package, name string) *Const {
|
|||
// the constant may have been imported before - if it exists
|
||||
// already in the respective scope, return that constant
|
||||
scope := pkg.scope
|
||||
if obj := scope.Lookup(nil, name); obj != nil {
|
||||
if obj := scope.Lookup(name); obj != nil {
|
||||
return obj.(*Const)
|
||||
}
|
||||
// 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 {
|
||||
scope := pkg.scope
|
||||
if obj := scope.Lookup(nil, name); obj != nil {
|
||||
if obj := scope.Lookup(name); obj != nil {
|
||||
return obj.(*TypeName)
|
||||
}
|
||||
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 {
|
||||
scope := pkg.scope
|
||||
if obj := scope.Lookup(nil, name); obj != nil {
|
||||
if obj := scope.Lookup(name); obj != nil {
|
||||
return obj.(*Var)
|
||||
}
|
||||
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 {
|
||||
scope := pkg.scope
|
||||
if obj := scope.Lookup(nil, name); obj != nil {
|
||||
if obj := scope.Lookup(name); obj != nil {
|
||||
return obj.(*Func)
|
||||
}
|
||||
obj := NewFunc(token.NoPos, pkg, name, nil)
|
||||
|
@ -390,7 +390,7 @@ func (p *gcParser) parseExportedName() (pkg *Package, name string) {
|
|||
//
|
||||
func (p *gcParser) parseBasicType() Type {
|
||||
id := p.expect(scanner.Ident)
|
||||
obj := Universe.Lookup(nil, id)
|
||||
obj := Universe.Lookup(id)
|
||||
if obj, ok := obj.(*TypeName); ok {
|
||||
return obj.typ
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ func TestGcImportedTypes(t *testing.T) {
|
|||
continue
|
||||
}
|
||||
|
||||
obj := pkg.scope.Lookup(nil, objName)
|
||||
obj := pkg.scope.Lookup(objName)
|
||||
|
||||
// TODO(gri) should define an accessor on Object
|
||||
var kind ast.ObjKind
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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() == "_" {
|
||||
// blank identifiers are not declared
|
||||
obj.setParent(scope)
|
||||
obj = nil
|
||||
} else if alt := scope.Insert(obj); alt != nil {
|
||||
check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
|
||||
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 {
|
||||
check.recordObject(id, obj)
|
||||
|
@ -128,7 +143,7 @@ func (check *checker) resolveFiles(files []*ast.File) {
|
|||
return
|
||||
}
|
||||
|
||||
check.declare(pkg.scope, ident, obj)
|
||||
check.declareObj(pkg.scope, ident, obj)
|
||||
objList = append(objList, obj)
|
||||
objMap[obj] = declInfo{scope, typ, init, nil}
|
||||
}
|
||||
|
@ -195,13 +210,13 @@ func (check *checker) resolveFiles(files []*ast.File) {
|
|||
if obj.IsExported() {
|
||||
// Note: This will change each imported object's scope!
|
||||
// May be an issue for types aliases.
|
||||
check.declare(scope, nil, obj)
|
||||
check.declareObj(scope, nil, obj)
|
||||
check.recordImplicit(s, obj)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// declare imported package object in file scope
|
||||
check.declare(scope, nil, imp2)
|
||||
check.declareObj(scope, nil, imp2)
|
||||
}
|
||||
|
||||
case *ast.ValueSpec:
|
||||
|
@ -281,7 +296,7 @@ func (check *checker) resolveFiles(files []*ast.File) {
|
|||
obj.parent = pkg.scope
|
||||
check.recordObject(d.Name, obj)
|
||||
} else {
|
||||
check.declare(pkg.scope, d.Name, obj)
|
||||
check.declareObj(pkg.scope, d.Name, obj)
|
||||
}
|
||||
} else {
|
||||
// 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 _, 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())
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
// to it must be unique."
|
||||
// => use a scope to determine redeclarations
|
||||
scope := NewScope(nil)
|
||||
// => use an objset to determine redeclarations
|
||||
var mset objset
|
||||
|
||||
// spec: "If the base type is a struct type, the non-blank method
|
||||
// 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 {
|
||||
for _, fld := range t.fields {
|
||||
if fld.name != "_" {
|
||||
scope.Insert(fld)
|
||||
assert(mset.insert(fld) == nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check each method
|
||||
for _, m := range methods {
|
||||
assert(m.name != "_") // _ methods were excluded before
|
||||
mdecl := check.objMap[m]
|
||||
alt := scope.Insert(m)
|
||||
m.parent = mdecl.file // correct parent scope (scope.Insert used scope)
|
||||
ident := check.objMap[m].fdecl.Name
|
||||
|
||||
if alt != nil {
|
||||
switch alt := alt.(type) {
|
||||
if alt := mset.insert(m); alt != nil {
|
||||
switch alt.(type) {
|
||||
case *Var:
|
||||
check.errorf(m.pos, "field and method with the same name %s", m.name)
|
||||
check.reportAltDecl(alt)
|
||||
m = nil
|
||||
case *Func:
|
||||
check.errorf(m.pos, "method %s already declared for %s", m.name, named)
|
||||
check.reportAltDecl(alt)
|
||||
m = nil
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
check.reportAltDecl(alt)
|
||||
m = nil
|
||||
}
|
||||
|
||||
check.recordObject(mdecl.fdecl.Name, m)
|
||||
check.recordObject(ident, m)
|
||||
|
||||
// If the method is valid, type-check its signature,
|
||||
// and collect it with the named base type.
|
||||
|
@ -604,7 +617,7 @@ func (check *checker) declStmt(decl ast.Decl) {
|
|||
check.arityMatch(s, last)
|
||||
|
||||
for i, name := range s.Names {
|
||||
check.declare(check.topScope, name, lhs[i])
|
||||
check.declareObj(check.topScope, name, lhs[i])
|
||||
}
|
||||
|
||||
case token.VAR:
|
||||
|
@ -637,7 +650,7 @@ func (check *checker) declStmt(decl ast.Decl) {
|
|||
check.arityMatch(s, nil)
|
||||
|
||||
for i, name := range s.Names {
|
||||
check.declare(check.topScope, name, lhs[i])
|
||||
check.declareObj(check.topScope, name, lhs[i])
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -646,7 +659,7 @@ func (check *checker) declStmt(decl ast.Decl) {
|
|||
|
||||
case *ast.TypeSpec:
|
||||
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)
|
||||
|
||||
default:
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file implements Scopes.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
|
@ -16,15 +18,16 @@ import (
|
|||
// objects can use that information for better printing.
|
||||
|
||||
// A Scope maintains a set of objects and links to its containing
|
||||
// (parent) and contained (children) scopes.
|
||||
// Objects may be inserted and looked up by name, or by package path
|
||||
// and name. A nil *Scope acts like an empty scope for operations that
|
||||
// do not modify the scope or access a scope's parent scope.
|
||||
// (parent) and contained (children) scopes. Objects may be inserted
|
||||
// and looked up by name. The zero value for Scope is a ready-to-use
|
||||
// empty scope.
|
||||
type Scope struct {
|
||||
parent *Scope
|
||||
children []*Scope
|
||||
entries []Object
|
||||
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
|
||||
|
@ -60,74 +63,39 @@ func (s *Scope) Parent() *Scope { return s.parent }
|
|||
func (s *Scope) Node() ast.Node { return s.node }
|
||||
|
||||
// NumEntries() returns the number of scope entries.
|
||||
// If s == nil, the result is 0.
|
||||
func (s *Scope) NumEntries() int {
|
||||
if s == nil {
|
||||
return 0 // empty scope
|
||||
}
|
||||
return len(s.entries)
|
||||
}
|
||||
func (s *Scope) NumEntries() int { return len(s.entries) }
|
||||
|
||||
// At returns the i'th scope entry for 0 <= i < NumEntries().
|
||||
func (s *Scope) At(i int) Object { return s.entries[i] }
|
||||
|
||||
// NumChildren() returns the number of scopes nested in s.
|
||||
// If s == nil, the result is 0.
|
||||
func (s *Scope) NumChildren() int {
|
||||
if s == nil {
|
||||
return 0
|
||||
}
|
||||
return len(s.children)
|
||||
}
|
||||
func (s *Scope) NumChildren() int { return len(s.children) }
|
||||
|
||||
// Child returns the i'th child scope for 0 <= i < NumChildren().
|
||||
func (s *Scope) Child(i int) *Scope { return s.children[i] }
|
||||
|
||||
// Lookup returns the object in scope s with the given package
|
||||
// and name if such an object exists; otherwise the result is nil.
|
||||
// A nil scope acts like an empty scope, and parent scopes are ignored.
|
||||
//
|
||||
// If pkg != nil, both pkg.Path() and name are used to identify an
|
||||
// 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
|
||||
// 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]
|
||||
}
|
||||
|
||||
// fast path: only the name must match
|
||||
if pkg == nil {
|
||||
for _, obj := range s.entries {
|
||||
if obj.Name() == name {
|
||||
return obj
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// slow path: both pkg path and name must match
|
||||
for _, obj := range s.entries {
|
||||
if obj.sameId(pkg, name) {
|
||||
if obj.Name() == 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
|
||||
// a scope where Lookup(nil, name) returns a non-nil object, and then returns that
|
||||
// object. If no such scope exists, the result is nil.
|
||||
// LookupParent follows the parent chain of scopes starting with s until
|
||||
// it finds a scope where Lookup(name) returns a non-nil object, and then
|
||||
// returns that object. If no such scope exists, the result is nil.
|
||||
func (s *Scope) LookupParent(name string) Object {
|
||||
for s != nil {
|
||||
if obj := s.Lookup(nil, name); obj != nil {
|
||||
for ; s != nil; s = s.parent {
|
||||
if obj := s.Lookup(name); obj != nil {
|
||||
return obj
|
||||
}
|
||||
s = s.parent
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -135,19 +103,34 @@ func (s *Scope) LookupParent(name string) Object {
|
|||
// TODO(gri): Should Insert not be exported?
|
||||
|
||||
// Insert attempts to insert an object obj into scope s.
|
||||
// If s already contains an object with the same package path
|
||||
// and name, Insert leaves s unchanged and returns that object.
|
||||
// Otherwise it inserts obj, sets the object's scope to s, and
|
||||
// returns nil. The object must not have the blank _ name.
|
||||
//
|
||||
// If s already contains an alternative object alt with
|
||||
// the same name, Insert leaves s unchanged and returns alt.
|
||||
// Otherwise it inserts obj, sets the object's scope to
|
||||
// s, and returns nil. The object name must not be blank _.
|
||||
func (s *Scope) Insert(obj Object) Object {
|
||||
name := obj.Name()
|
||||
assert(name != "_")
|
||||
if alt := s.Lookup(obj.Pkg(), name); alt != nil {
|
||||
if alt := s.Lookup(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
|
||||
}
|
||||
obj.setParent(s)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -159,7 +142,7 @@ func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) {
|
|||
const ind = ". "
|
||||
indn := strings.Repeat(ind, n)
|
||||
|
||||
if s.NumEntries() == 0 {
|
||||
if len(s.entries) == 0 {
|
||||
fmt.Fprintf(w, "%sscope %p {}\n", indn, s)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
check.funcSig.labels = scope
|
||||
}
|
||||
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)
|
||||
|
||||
case *ast.ExprStmt:
|
||||
|
@ -267,7 +267,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
if tag == nil {
|
||||
// use fake true tag value and position it at the opening { of the switch
|
||||
ident := &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
|
||||
check.recordObject(ident, Universe.Lookup(nil, "true"))
|
||||
check.recordObject(ident, Universe.Lookup("true"))
|
||||
tag = ident
|
||||
}
|
||||
check.expr(&x, tag)
|
||||
|
@ -416,7 +416,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
typ = x.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.stmtList(clause.Body)
|
||||
|
@ -552,7 +552,7 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||
|
||||
// declare variables
|
||||
for i, ident := range idents {
|
||||
check.declare(check.topScope, ident, vars[i])
|
||||
check.declareObj(check.topScope, ident, vars[i])
|
||||
}
|
||||
} else {
|
||||
// ordinary assignment
|
||||
|
|
|
@ -193,7 +193,7 @@ func (t *Tuple) At(i int) *Var { return t.vars[i] }
|
|||
|
||||
// A Signature represents a (non-builtin) function type.
|
||||
type Signature struct {
|
||||
scope *Scope // function scope
|
||||
scope *Scope // function scope, always present
|
||||
labels *Scope // label scope, or nil (lazily allocated)
|
||||
recv *Var // nil if not a method
|
||||
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
|
||||
// is variadic, it must have at least one parameter, and the last parameter
|
||||
// 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 {
|
||||
n := params.Len()
|
||||
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")
|
||||
}
|
||||
}
|
||||
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.
|
||||
|
|
|
@ -110,7 +110,7 @@ func TestTypes(t *testing.T) {
|
|||
t.Errorf("%s: %s", src, err)
|
||||
continue
|
||||
}
|
||||
typ := pkg.scope.Lookup(nil, "T").Type().Underlying()
|
||||
typ := pkg.scope.Lookup("T").Type().Underlying()
|
||||
str := typeString(typ)
|
||||
if str != test.str {
|
||||
t.Errorf("%s: got %s, want %s", test.src, str, test.str)
|
||||
|
|
|
@ -360,7 +360,7 @@ func (check *checker) collectParams(scope *Scope, list *ast.FieldList, variadicO
|
|||
// named parameter
|
||||
for _, name := range field.Names {
|
||||
par := NewVar(name.Pos(), check.pkg, name.Name, typ)
|
||||
check.declare(scope, name, par)
|
||||
check.declareObj(scope, name, par)
|
||||
params = append(params, par)
|
||||
}
|
||||
} else {
|
||||
|
@ -385,7 +385,8 @@ func (check *checker) collectMethods(recv Type, list *ast.FieldList, cycleOk boo
|
|||
return nil
|
||||
}
|
||||
|
||||
scope := NewScope(nil)
|
||||
var mset objset
|
||||
|
||||
for _, f := range list.List {
|
||||
// TODO(gri) Consider calling funcType here.
|
||||
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)
|
||||
for _, name := range f.Names {
|
||||
m := NewFunc(name.Pos(), check.pkg, name.Name, sig)
|
||||
check.declare(scope, name, m)
|
||||
check.declareFld(&mset, name, m)
|
||||
methods = append(methods, m)
|
||||
}
|
||||
} 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)
|
||||
case *Interface:
|
||||
for _, m := range t.methods {
|
||||
check.declare(scope, nil, m)
|
||||
check.declareFld(&mset, nil, m)
|
||||
methods = append(methods, m)
|
||||
}
|
||||
default:
|
||||
|
@ -448,7 +449,7 @@ func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields [
|
|||
return
|
||||
}
|
||||
|
||||
scope := NewScope(nil)
|
||||
var fset objset
|
||||
|
||||
var typ Type // current field typ
|
||||
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)
|
||||
check.declare(scope, ident, fld)
|
||||
check.declareFld(&fset, ident, fld)
|
||||
fields = append(fields, fld)
|
||||
}
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ func init() {
|
|||
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
|
||||
|
|
|
@ -116,7 +116,7 @@ func (info *PackageInfo) IsType(e ast.Expr) bool {
|
|||
func (info *PackageInfo) IsPackageRef(sel *ast.SelectorExpr) types.Object {
|
||||
if id, ok := sel.X.(*ast.Ident); 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
|
||||
|
@ -245,5 +245,5 @@ func (info *PackageInfo) BuiltinCallSignature(e *ast.CallExpr) *types.Signature
|
|||
panic("unknown builtin: " + builtin)
|
||||
}
|
||||
|
||||
return types.NewSignature(nil, types.NewTuple(params...), nil, isVariadic)
|
||||
return types.NewSignature(nil, nil, types.NewTuple(params...), nil, isVariadic)
|
||||
}
|
||||
|
|
|
@ -1716,7 +1716,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value
|
|||
} else {
|
||||
// length = len(x).
|
||||
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.setType(tInt)
|
||||
length = fn.emit(&c)
|
||||
|
|
|
@ -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
|
||||
// now, we'll set it to always be false since we're only
|
||||
// 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.Pkg = pkg
|
||||
fn.Prog = pkg.Prog
|
||||
|
|
|
@ -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 {
|
||||
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.
|
||||
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
|
||||
fn = &Function{
|
||||
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(),
|
||||
Prog: prog,
|
||||
pos: meth.Pos(),
|
||||
|
@ -359,7 +359,7 @@ func indirectionWrapper(meth *Function) *Function {
|
|||
// TODO(adonovan): is there a *types.Func for this method?
|
||||
fn = &Function{
|
||||
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,
|
||||
Synthetic: "receiver indirection wrapper for " + meth.String(),
|
||||
pos: meth.Pos(),
|
||||
|
|
Загрузка…
Ссылка в новой задаче