mirror of
https://github.com/golang/go
synced 2024-11-18 18:34:40 -07:00
go/types: use file not parse order for init order computation
The type-checker depended on (token.Pos) position information of the presented files to determine source order. That information is determined by the parse order of the files rather than the order in which the files are presented to the type-checker. Introduced an order number strictly determined by the file order as presented to the type-checker and the AST structure of each file; thus providing source order information even in the absence of (token.Pos) position information. Added test case (provided by adonovan). LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/151160043
This commit is contained in:
parent
4fd305d5dc
commit
a7f9d5d4f8
@ -588,6 +588,39 @@ func TestInitOrderInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMultiFileInitOrder(t *testing.T) {
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
mustParse := func(src string) *ast.File {
|
||||||
|
f, err := parser.ParseFile(fset, "main", src, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
fileA := mustParse(`package main; var a = 1`)
|
||||||
|
fileB := mustParse(`package main; var b = 2`)
|
||||||
|
|
||||||
|
// The initialization order must not depend on the parse
|
||||||
|
// order of the files, only on the presentation order to
|
||||||
|
// the type-checker.
|
||||||
|
for _, test := range []struct {
|
||||||
|
files []*ast.File
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{[]*ast.File{fileA, fileB}, "[a = 1 b = 2]"},
|
||||||
|
{[]*ast.File{fileB, fileA}, "[b = 2 a = 1]"},
|
||||||
|
} {
|
||||||
|
var info Info
|
||||||
|
if _, err := new(Config).Check("main", fset, test.files, &info); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if got := fmt.Sprint(info.InitOrder); got != test.want {
|
||||||
|
t.Fatalf("got %s; want %s", got, test.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFiles(t *testing.T) {
|
func TestFiles(t *testing.T) {
|
||||||
var sources = []string{
|
var sources = []string{
|
||||||
"package p; type T struct{}; func (T) m1() {}",
|
"package p; type T struct{}; func (T) m1() {}",
|
||||||
|
@ -205,8 +205,8 @@ func (a nodeQueue) Swap(i, j int) {
|
|||||||
func (a nodeQueue) Less(i, j int) bool {
|
func (a nodeQueue) Less(i, j int) bool {
|
||||||
x, y := a[i], a[j]
|
x, y := a[i], a[j]
|
||||||
// nodes are prioritized by number of incoming dependencies (1st key)
|
// nodes are prioritized by number of incoming dependencies (1st key)
|
||||||
// and source positions (2nd key)
|
// and source order (2nd key)
|
||||||
return x.in < y.in || x.in == y.in && x.obj.Pos() < y.obj.Pos()
|
return x.in < y.in || x.in == y.in && x.obj.order() < y.obj.order()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *nodeQueue) Push(x interface{}) {
|
func (a *nodeQueue) Push(x interface{}) {
|
||||||
|
@ -31,9 +31,18 @@ type Object interface {
|
|||||||
// String returns a human-readable string of the object.
|
// String returns a human-readable string of the object.
|
||||||
String() string
|
String() string
|
||||||
|
|
||||||
|
// order reflects a package-level object's source order: if object
|
||||||
|
// a is before object b in the source, then a.order() < b.order().
|
||||||
|
// order returns a value > 0 for package-level objects; it returns
|
||||||
|
// 0 for all other objects (including objects in file scopes).
|
||||||
|
order() uint32
|
||||||
|
|
||||||
// isUsed reports whether the object was marked as 'used'.
|
// isUsed reports whether the object was marked as 'used'.
|
||||||
isUsed() bool
|
isUsed() bool
|
||||||
|
|
||||||
|
// setOrder sets the order number of the object. It must be > 0.
|
||||||
|
setOrder(uint32)
|
||||||
|
|
||||||
// setParent sets the parent scope of the object.
|
// setParent sets the parent scope of the object.
|
||||||
setParent(*Scope)
|
setParent(*Scope)
|
||||||
|
|
||||||
@ -73,6 +82,8 @@ type object struct {
|
|||||||
pkg *Package
|
pkg *Package
|
||||||
name string
|
name string
|
||||||
typ Type
|
typ Type
|
||||||
|
|
||||||
|
order_ uint32
|
||||||
used bool
|
used bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,8 +96,10 @@ func (obj *object) Exported() bool { return ast.IsExported(obj.name) }
|
|||||||
func (obj *object) Id() string { return Id(obj.pkg, obj.name) }
|
func (obj *object) Id() string { return Id(obj.pkg, obj.name) }
|
||||||
func (obj *object) String() string { panic("abstract") }
|
func (obj *object) String() string { panic("abstract") }
|
||||||
|
|
||||||
func (obj *object) isUsed() bool { return obj.used }
|
func (obj *object) order() uint32 { return obj.order_ }
|
||||||
|
func (obj *object) isUsed() bool { return obj.used }
|
||||||
|
|
||||||
|
func (obj *object) setOrder(order uint32) { assert(order > 0); obj.order_ = order }
|
||||||
func (obj *object) setParent(parent *Scope) { obj.parent = parent }
|
func (obj *object) setParent(parent *Scope) { obj.parent = parent }
|
||||||
|
|
||||||
func (obj *object) sameId(pkg *Package, name string) bool {
|
func (obj *object) sameId(pkg *Package, name string) bool {
|
||||||
@ -118,7 +131,7 @@ type PkgName struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewPkgName(pos token.Pos, pkg *Package, name string, imported *Package) *PkgName {
|
func NewPkgName(pos token.Pos, pkg *Package, name string, imported *Package) *PkgName {
|
||||||
return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], false}, imported}
|
return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, false}, imported}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Imported returns the package that was imported.
|
// Imported returns the package that was imported.
|
||||||
@ -134,7 +147,7 @@ type Const struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val exact.Value) *Const {
|
func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val exact.Value) *Const {
|
||||||
return &Const{object: object{nil, pos, pkg, name, typ, false}, val: val}
|
return &Const{object: object{nil, pos, pkg, name, typ, 0, false}, val: val}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *Const) Val() exact.Value { return obj.val }
|
func (obj *Const) Val() exact.Value { return obj.val }
|
||||||
@ -145,7 +158,7 @@ type TypeName struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
|
func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
|
||||||
return &TypeName{object{nil, pos, pkg, name, typ, false}}
|
return &TypeName{object{nil, pos, pkg, name, typ, 0, false}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Variable represents a declared variable (including function parameters and results, and struct fields).
|
// A Variable represents a declared variable (including function parameters and results, and struct fields).
|
||||||
@ -158,15 +171,15 @@ type Var struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var {
|
func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var {
|
||||||
return &Var{object: object{nil, pos, pkg, name, typ, false}}
|
return &Var{object: object{nil, pos, pkg, name, typ, 0, false}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewParam(pos token.Pos, pkg *Package, name string, typ Type) *Var {
|
func NewParam(pos token.Pos, pkg *Package, name string, typ Type) *Var {
|
||||||
return &Var{object: object{nil, pos, pkg, name, typ, true}} // parameters are always 'used'
|
return &Var{object: object{nil, pos, pkg, name, typ, 0, true}} // parameters are always 'used'
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewField(pos token.Pos, pkg *Package, name string, typ Type, anonymous bool) *Var {
|
func NewField(pos token.Pos, pkg *Package, name string, typ Type, anonymous bool) *Var {
|
||||||
return &Var{object: object{nil, pos, pkg, name, typ, false}, anonymous: anonymous, isField: true}
|
return &Var{object: object{nil, pos, pkg, name, typ, 0, false}, anonymous: anonymous, isField: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *Var) Anonymous() bool { return obj.anonymous }
|
func (obj *Var) Anonymous() bool { return obj.anonymous }
|
||||||
@ -186,7 +199,7 @@ func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
|
|||||||
if sig != nil {
|
if sig != nil {
|
||||||
typ = sig
|
typ = sig
|
||||||
}
|
}
|
||||||
return &Func{object{nil, pos, pkg, name, typ, false}}
|
return &Func{object{nil, pos, pkg, name, typ, 0, false}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FullName returns the package- or receiver-type-qualified name of
|
// FullName returns the package- or receiver-type-qualified name of
|
||||||
|
@ -123,5 +123,5 @@ func orderedSetObjects(set map[Object]bool) []Object {
|
|||||||
type inSourceOrder []Object
|
type inSourceOrder []Object
|
||||||
|
|
||||||
func (a inSourceOrder) Len() int { return len(a) }
|
func (a inSourceOrder) Len() int { return len(a) }
|
||||||
func (a inSourceOrder) Less(i, j int) bool { return a[i].Pos() < a[j].Pos() }
|
func (a inSourceOrder) Less(i, j int) bool { return a[i].order() < a[j].order() }
|
||||||
func (a inSourceOrder) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
func (a inSourceOrder) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
|
@ -110,6 +110,7 @@ func (check *Checker) declarePkgObj(ident *ast.Ident, obj Object, d *declInfo) {
|
|||||||
|
|
||||||
check.declare(check.pkg.scope, ident, obj)
|
check.declare(check.pkg.scope, ident, obj)
|
||||||
check.objMap[obj] = d
|
check.objMap[obj] = d
|
||||||
|
obj.setOrder(uint32(len(check.objMap)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// collectObjects collects all file and package objects and inserts them
|
// collectObjects collects all file and package objects and inserts them
|
||||||
@ -341,6 +342,7 @@ func (check *Checker) collectObjects() {
|
|||||||
}
|
}
|
||||||
info := &declInfo{file: fileScope, fdecl: d}
|
info := &declInfo{file: fileScope, fdecl: d}
|
||||||
check.objMap[obj] = info
|
check.objMap[obj] = info
|
||||||
|
obj.setOrder(uint32(len(check.objMap)))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
|
check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
|
||||||
|
Loading…
Reference in New Issue
Block a user