Commit 95aaca67 authored by Robert Griesemer's avatar Robert Griesemer

go/types: Pkg *Package field for all objects

The field is nil for predeclared (universe)
objects and parameter/result variables.

R=adonovan
CC=golang-dev
https://golang.org/cl/7312093
parent 86d509b4
...@@ -70,7 +70,7 @@ func (check *checker) lookup(ident *ast.Ident) Object { ...@@ -70,7 +70,7 @@ func (check *checker) lookup(ident *ast.Ident) Object {
} }
if obj = check.objects[astObj]; obj == nil { if obj = check.objects[astObj]; obj == nil {
obj = newObj(astObj) obj = newObj(check.pkg, astObj)
check.objects[astObj] = obj check.objects[astObj] = obj
} }
check.register(ident, obj) check.register(ident, obj)
...@@ -346,7 +346,7 @@ func (check *checker) assocMethod(meth *ast.FuncDecl) { ...@@ -346,7 +346,7 @@ func (check *checker) assocMethod(meth *ast.FuncDecl) {
scope = new(Scope) scope = new(Scope)
check.methods[tname] = scope check.methods[tname] = scope
} }
check.declareIdent(scope, meth.Name, &Func{Name: meth.Name.Name, decl: meth}) check.declareIdent(scope, meth.Name, &Func{Pkg: check.pkg, Name: meth.Name.Name, decl: meth})
} }
func (check *checker) decl(decl ast.Decl) { func (check *checker) decl(decl ast.Decl) {
...@@ -378,7 +378,7 @@ func (check *checker) decl(decl ast.Decl) { ...@@ -378,7 +378,7 @@ func (check *checker) decl(decl ast.Decl) {
// since they are not in any scope. Create a dummy object for them. // since they are not in any scope. Create a dummy object for them.
if d.Name.Name == "init" { if d.Name.Name == "init" {
assert(obj == nil) // all other functions should have an object assert(obj == nil) // all other functions should have an object
obj = &Func{Name: d.Name.Name, decl: d} obj = &Func{Pkg: check.pkg, Name: d.Name.Name, decl: d}
check.register(d.Name, obj) check.register(d.Name, obj)
} }
check.object(obj, false) check.object(obj, false)
...@@ -403,8 +403,9 @@ func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package, ...@@ -403,8 +403,9 @@ func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package,
conversions: make(map[*ast.CallExpr]bool), conversions: make(map[*ast.CallExpr]bool),
} }
// handle panics // set results and handle panics
defer func() { defer func() {
pkg = check.pkg
switch p := recover().(type) { switch p := recover().(type) {
case nil, bailout: case nil, bailout:
// normal return or early exit // normal return or early exit
...@@ -422,8 +423,7 @@ func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package, ...@@ -422,8 +423,7 @@ func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package,
if imp == nil { if imp == nil {
imp = GcImport imp = GcImport
} }
pkg, methods := check.resolve(imp) methods := check.resolve(imp)
check.pkg = pkg
// associate methods with types // associate methods with types
for _, m := range methods { for _, m := range methods {
......
...@@ -238,6 +238,7 @@ func TestCheck(t *testing.T) { ...@@ -238,6 +238,7 @@ func TestCheck(t *testing.T) {
// the construction of the Universe var. // the construction of the Universe var.
if !testBuiltinsDeclared { if !testBuiltinsDeclared {
testBuiltinsDeclared = true testBuiltinsDeclared = true
// Pkg == nil for Universe objects
def(&Func{Name: "assert", Type: &builtin{_Assert, "assert", 1, false, true}}) def(&Func{Name: "assert", Type: &builtin{_Assert, "assert", 1, false, true}})
def(&Func{Name: "trace", Type: &builtin{_Trace, "trace", 0, true, true}}) def(&Func{Name: "trace", Type: &builtin{_Trace, "trace", 0, true, true}})
} }
......
...@@ -197,23 +197,25 @@ func (p *gcParser) next() { ...@@ -197,23 +197,25 @@ func (p *gcParser) next() {
} }
} }
func declConst(scope *Scope, name string) *Const { 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
if obj := scope.Lookup(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
obj := &Const{Name: name} obj := &Const{Pkg: pkg, Name: name}
scope.Insert(obj) scope.Insert(obj)
return obj return obj
} }
func declTypeName(scope *Scope, name string) *TypeName { func declTypeName(pkg *Package, name string) *TypeName {
scope := pkg.Scope
if obj := scope.Lookup(name); obj != nil { if obj := scope.Lookup(name); obj != nil {
return obj.(*TypeName) return obj.(*TypeName)
} }
obj := &TypeName{Name: name} obj := &TypeName{Pkg: pkg, Name: name}
// a named type may be referred to before the underlying type // a named type may be referred to before the underlying type
// is known - set it up // is known - set it up
obj.Type = &NamedType{Obj: obj} obj.Type = &NamedType{Obj: obj}
...@@ -221,20 +223,22 @@ func declTypeName(scope *Scope, name string) *TypeName { ...@@ -221,20 +223,22 @@ func declTypeName(scope *Scope, name string) *TypeName {
return obj return obj
} }
func declVar(scope *Scope, name string) *Var { func declVar(pkg *Package, name string) *Var {
scope := pkg.Scope
if obj := scope.Lookup(name); obj != nil { if obj := scope.Lookup(name); obj != nil {
return obj.(*Var) return obj.(*Var)
} }
obj := &Var{Name: name} obj := &Var{Pkg: pkg, Name: name}
scope.Insert(obj) scope.Insert(obj)
return obj return obj
} }
func declFunc(scope *Scope, name string) *Func { func declFunc(pkg *Package, name string) *Func {
scope := pkg.Scope
if obj := scope.Lookup(name); obj != nil { if obj := scope.Lookup(name); obj != nil {
return obj.(*Func) return obj.(*Func)
} }
obj := &Func{Name: name} obj := &Func{Pkg: pkg, Name: name}
scope.Insert(obj) scope.Insert(obj)
return obj return obj
} }
...@@ -507,7 +511,7 @@ func (p *gcParser) parseParameter() (par *Var, isVariadic bool) { ...@@ -507,7 +511,7 @@ func (p *gcParser) parseParameter() (par *Var, isVariadic bool) {
if p.tok == scanner.String { if p.tok == scanner.String {
p.next() p.next()
} }
par = &Var{Name: name, Type: typ} par = &Var{Name: name, Type: typ} // Pkg == nil
return return
} }
...@@ -637,7 +641,7 @@ func (p *gcParser) parseType() Type { ...@@ -637,7 +641,7 @@ func (p *gcParser) parseType() Type {
case '@': case '@':
// TypeName // TypeName
pkg, name := p.parseExportedName() pkg, name := p.parseExportedName()
return declTypeName(pkg.Scope, name).Type return declTypeName(pkg, name).Type
case '[': case '[':
p.next() // look ahead p.next() // look ahead
if p.tok == ']' { if p.tok == ']' {
...@@ -740,7 +744,7 @@ func (p *gcParser) parseNumber() (x operand) { ...@@ -740,7 +744,7 @@ func (p *gcParser) parseNumber() (x operand) {
func (p *gcParser) parseConstDecl() { func (p *gcParser) parseConstDecl() {
p.expectKeyword("const") p.expectKeyword("const")
pkg, name := p.parseExportedName() pkg, name := p.parseExportedName()
obj := declConst(pkg.Scope, name) obj := declConst(pkg, name)
var x operand var x operand
if p.tok != '=' { if p.tok != '=' {
obj.Type = p.parseType() obj.Type = p.parseType()
...@@ -806,7 +810,7 @@ func (p *gcParser) parseConstDecl() { ...@@ -806,7 +810,7 @@ func (p *gcParser) parseConstDecl() {
func (p *gcParser) parseTypeDecl() { func (p *gcParser) parseTypeDecl() {
p.expectKeyword("type") p.expectKeyword("type")
pkg, name := p.parseExportedName() pkg, name := p.parseExportedName()
obj := declTypeName(pkg.Scope, name) obj := declTypeName(pkg, name)
// The type object may have been imported before and thus already // The type object may have been imported before and thus already
// have a type associated with it. We still need to parse the type // have a type associated with it. We still need to parse the type
...@@ -825,7 +829,7 @@ func (p *gcParser) parseTypeDecl() { ...@@ -825,7 +829,7 @@ func (p *gcParser) parseTypeDecl() {
func (p *gcParser) parseVarDecl() { func (p *gcParser) parseVarDecl() {
p.expectKeyword("var") p.expectKeyword("var")
pkg, name := p.parseExportedName() pkg, name := p.parseExportedName()
obj := declVar(pkg.Scope, name) obj := declVar(pkg, name)
obj.Type = p.parseType() obj.Type = p.parseType()
} }
...@@ -886,7 +890,7 @@ func (p *gcParser) parseFuncDecl() { ...@@ -886,7 +890,7 @@ func (p *gcParser) parseFuncDecl() {
// "func" already consumed // "func" already consumed
pkg, name := p.parseExportedName() pkg, name := p.parseExportedName()
typ := p.parseFunc() typ := p.parseFunc()
declFunc(pkg.Scope, name).Type = typ declFunc(pkg, name).Type = typ
} }
// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" . // Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
......
...@@ -14,6 +14,7 @@ import ( ...@@ -14,6 +14,7 @@ import (
// All objects implement the Object interface. // All objects implement the Object interface.
// //
type Object interface { type Object interface {
GetPkg() *Package
GetName() string GetName() string
GetType() Type GetType() Type
GetPos() token.Pos GetPos() token.Pos
...@@ -34,6 +35,7 @@ type Package struct { ...@@ -34,6 +35,7 @@ type Package struct {
// A Const represents a declared constant. // A Const represents a declared constant.
type Const struct { type Const struct {
Pkg *Package
Name string Name string
Type Type Type Type
Val interface{} Val interface{}
...@@ -43,6 +45,7 @@ type Const struct { ...@@ -43,6 +45,7 @@ type Const struct {
// A TypeName represents a declared type. // A TypeName represents a declared type.
type TypeName struct { type TypeName struct {
Pkg *Package
Name string Name string
Type Type // *NamedType or *Basic Type Type // *NamedType or *Basic
...@@ -51,6 +54,7 @@ type TypeName struct { ...@@ -51,6 +54,7 @@ type TypeName struct {
// A Variable represents a declared variable (including function parameters and results). // A Variable represents a declared variable (including function parameters and results).
type Var struct { type Var struct {
Pkg *Package // nil for parameters
Name string Name string
Type Type Type Type
...@@ -60,12 +64,19 @@ type Var struct { ...@@ -60,12 +64,19 @@ type Var struct {
// A Func represents a declared function. // A Func represents a declared function.
type Func struct { type Func struct {
Pkg *Package
Name string Name string
Type Type // *Signature or *Builtin Type Type // *Signature or *Builtin
decl *ast.FuncDecl decl *ast.FuncDecl
} }
func (obj *Package) GetPkg() *Package { return obj }
func (obj *Const) GetPkg() *Package { return obj.Pkg }
func (obj *TypeName) GetPkg() *Package { return obj.Pkg }
func (obj *Var) GetPkg() *Package { return obj.Pkg }
func (obj *Func) GetPkg() *Package { return obj.Pkg }
func (obj *Package) GetName() string { return obj.Name } func (obj *Package) GetName() string { return obj.Name }
func (obj *Const) GetName() string { return obj.Name } func (obj *Const) GetName() string { return obj.Name }
func (obj *TypeName) GetName() string { return obj.Name } func (obj *TypeName) GetName() string { return obj.Name }
...@@ -126,7 +137,8 @@ func (*Func) anObject() {} ...@@ -126,7 +137,8 @@ func (*Func) anObject() {}
// TODO(gri) Once we do identifier resolution completely in // TODO(gri) Once we do identifier resolution completely in
// in the typechecker, this functionality can go. // in the typechecker, this functionality can go.
// //
func newObj(astObj *ast.Object) Object { func newObj(pkg *Package, astObj *ast.Object) Object {
assert(pkg != nil)
name := astObj.Name name := astObj.Name
typ, _ := astObj.Type.(Type) typ, _ := astObj.Type.(Type)
switch astObj.Kind { switch astObj.Kind {
...@@ -135,18 +147,18 @@ func newObj(astObj *ast.Object) Object { ...@@ -135,18 +147,18 @@ func newObj(astObj *ast.Object) Object {
case ast.Pkg: case ast.Pkg:
unreachable() unreachable()
case ast.Con: case ast.Con:
return &Const{Name: name, Type: typ, Val: astObj.Data, spec: astObj.Decl.(*ast.ValueSpec)} return &Const{Pkg: pkg, Name: name, Type: typ, Val: astObj.Data, spec: astObj.Decl.(*ast.ValueSpec)}
case ast.Typ: case ast.Typ:
return &TypeName{Name: name, Type: typ, spec: astObj.Decl.(*ast.TypeSpec)} return &TypeName{Pkg: pkg, Name: name, Type: typ, spec: astObj.Decl.(*ast.TypeSpec)}
case ast.Var: case ast.Var:
switch astObj.Decl.(type) { switch astObj.Decl.(type) {
case *ast.Field, *ast.ValueSpec, *ast.AssignStmt: // these are ok case *ast.Field, *ast.ValueSpec, *ast.AssignStmt: // these are ok
default: default:
unreachable() unreachable()
} }
return &Var{Name: name, Type: typ, decl: astObj.Decl} return &Var{Pkg: pkg, Name: name, Type: typ, decl: astObj.Decl}
case ast.Fun: case ast.Fun:
return &Func{Name: name, Type: typ, decl: astObj.Decl.(*ast.FuncDecl)} return &Func{Pkg: pkg, Name: name, Type: typ, decl: astObj.Decl.(*ast.FuncDecl)}
case ast.Lbl: case ast.Lbl:
unreachable() // for now unreachable() // for now
} }
......
...@@ -36,8 +36,9 @@ func (check *checker) resolveIdent(scope *Scope, ident *ast.Ident) bool { ...@@ -36,8 +36,9 @@ func (check *checker) resolveIdent(scope *Scope, ident *ast.Ident) bool {
return false return false
} }
func (check *checker) resolve(importer Importer) (pkg *Package, methods []*ast.FuncDecl) { func (check *checker) resolve(importer Importer) (methods []*ast.FuncDecl) {
pkg = &Package{Scope: &Scope{Outer: Universe}, Imports: make(map[string]*Package)} pkg := &Package{Scope: &Scope{Outer: Universe}, Imports: make(map[string]*Package)}
check.pkg = pkg
// complete package scope // complete package scope
i := 0 i := 0
......
...@@ -116,14 +116,14 @@ func TestResolveQualifiedIdents(t *testing.T) { ...@@ -116,14 +116,14 @@ func TestResolveQualifiedIdents(t *testing.T) {
for _, list := range x.Fields.List { for _, list := range x.Fields.List {
for _, f := range list.Names { for _, f := range list.Names {
assert(idents[f] == nil) assert(idents[f] == nil)
idents[f] = &Var{Name: f.Name} idents[f] = &Var{Pkg: pkg, Name: f.Name}
} }
} }
case *ast.InterfaceType: case *ast.InterfaceType:
for _, list := range x.Methods.List { for _, list := range x.Methods.List {
for _, f := range list.Names { for _, f := range list.Names {
assert(idents[f] == nil) assert(idents[f] == nil)
idents[f] = &Func{Name: f.Name} idents[f] = &Func{Pkg: pkg, Name: f.Name}
} }
} }
case *ast.CompositeLit: case *ast.CompositeLit:
...@@ -131,7 +131,7 @@ func TestResolveQualifiedIdents(t *testing.T) { ...@@ -131,7 +131,7 @@ func TestResolveQualifiedIdents(t *testing.T) {
if kv, ok := e.(*ast.KeyValueExpr); ok { if kv, ok := e.(*ast.KeyValueExpr); ok {
if k, ok := kv.Key.(*ast.Ident); ok { if k, ok := kv.Key.(*ast.Ident); ok {
assert(idents[k] == nil) assert(idents[k] == nil)
idents[k] = &Var{Name: k.Name} idents[k] = &Var{Pkg: pkg, Name: k.Name}
} }
} }
} }
......
...@@ -434,7 +434,7 @@ func (check *checker) stmt(s ast.Stmt) { ...@@ -434,7 +434,7 @@ func (check *checker) stmt(s ast.Stmt) {
} }
name := ast.NewIdent(res.Name) name := ast.NewIdent(res.Name)
name.NamePos = s.Pos() name.NamePos = s.Pos()
check.register(name, &Var{Name: res.Name, Type: res.Type}) check.register(name, &Var{Name: res.Name, Type: res.Type}) // Pkg == nil
lhs[i] = name lhs[i] = name
} }
if len(s.Results) > 0 || !named { if len(s.Results) > 0 || !named {
......
...@@ -55,10 +55,10 @@ var aliases = [...]*Basic{ ...@@ -55,10 +55,10 @@ var aliases = [...]*Basic{
} }
var predeclaredConstants = [...]*Const{ var predeclaredConstants = [...]*Const{
{"true", Typ[UntypedBool], true, nil}, {nil, "true", Typ[UntypedBool], true, nil},
{"false", Typ[UntypedBool], false, nil}, {nil, "false", Typ[UntypedBool], false, nil},
{"iota", Typ[UntypedInt], zeroConst, nil}, {nil, "iota", Typ[UntypedInt], zeroConst, nil},
{"nil", Typ[UntypedNil], nilConst, nil}, {nil, "nil", Typ[UntypedNil], nilConst, nil},
} }
var predeclaredFunctions = [...]*builtin{ var predeclaredFunctions = [...]*builtin{
...@@ -130,6 +130,15 @@ func def(obj Object) { ...@@ -130,6 +130,15 @@ func def(obj Object) {
scope := Universe scope := Universe
if ast.IsExported(name) { if ast.IsExported(name) {
scope = Unsafe.Scope scope = Unsafe.Scope
// set Pkg field
switch obj := obj.(type) {
case *TypeName:
obj.Pkg = Unsafe
case *Func:
obj.Pkg = Unsafe
default:
unreachable()
}
} }
if scope.Insert(obj) != nil { if scope.Insert(obj) != nil {
panic("internal error: double declaration") panic("internal error: double declaration")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment