1
0
mirror of https://github.com/golang/go synced 2024-09-29 23:24:29 -06:00

go/types, types2: factor out position comparison, share more code

This CL introduces the new files util.go and util_test.go for both
type checkers; these files factor out functionality that is different
between the type checkers so that more code (that is otherwise mostly
the same) can be generated.

With cmpPos/CmpPos factored out, go/types/scope.go can now be generated.

Change-Id: I35f67e53d83b3c5086a559b1e826db83d38ee217
Reviewed-on: https://go-review.googlesource.com/c/go/+/461596
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2023-01-11 09:17:55 -08:00 committed by Gopher Robot
parent 9251822631
commit 248950f192
15 changed files with 115 additions and 30 deletions

View File

@ -622,7 +622,7 @@ func sortedInstances(m map[*syntax.Name]Instance) (instances []recordedInstance)
instances = append(instances, recordedInstance{id, inst})
}
sort.Slice(instances, func(i, j int) bool {
return instances[i].Name.Pos().Cmp(instances[j].Name.Pos()) < 0
return CmpPos(instances[i].Name.Pos(), instances[j].Name.Pos()) < 0
})
return instances
}

View File

@ -360,7 +360,7 @@ func (check *Checker) cycleError(cycle []Object) {
func firstInSrc(path []Object) int {
fst, pos := 0, path[0].Pos()
for i, t := range path[1:] {
if t.Pos().Cmp(pos) < 0 {
if cmpPos(t.Pos(), pos) < 0 {
fst, pos = i+1, t.Pos()
}
}

View File

@ -284,7 +284,7 @@ func (w *monoGraph) localNamedVertex(pkg *Package, named *Named) int {
// parameters that it's implicitly parameterized by.
for scope := obj.Parent(); scope != root; scope = scope.Parent() {
for _, elem := range scope.elems {
if elem, ok := elem.(*TypeName); ok && !elem.IsAlias() && elem.Pos().Cmp(obj.Pos()) < 0 {
if elem, ok := elem.(*TypeName); ok && !elem.IsAlias() && cmpPos(elem.Pos(), obj.Pos()) < 0 {
if tpar, ok := elem.Type().(*TypeParam); ok {
if idx < 0 {
idx = len(w.vertices)

View File

@ -83,7 +83,7 @@ func (s *Scope) Lookup(name string) Object {
// whose scope is the scope of the package that exported them.
func (s *Scope) LookupParent(name string, pos syntax.Pos) (*Scope, Object) {
for ; s != nil; s = s.parent {
if obj := s.Lookup(name); obj != nil && (!pos.IsKnown() || obj.scopePos().Cmp(pos) <= 0) {
if obj := s.Lookup(name); obj != nil && (!pos.IsKnown() || cmpPos(obj.scopePos(), pos) <= 0) {
return s, obj
}
}
@ -175,7 +175,7 @@ func (s *Scope) End() syntax.Pos { return s.end }
// The result is guaranteed to be valid only if the type-checked
// AST has complete position information.
func (s *Scope) Contains(pos syntax.Pos) bool {
return s.pos.Cmp(pos) <= 0 && pos.Cmp(s.end) < 0
return cmpPos(s.pos, pos) <= 0 && cmpPos(pos, s.end) < 0
}
// Innermost returns the innermost (child) scope containing

View File

@ -64,7 +64,7 @@ func (check *Checker) usage(scope *Scope) {
}
}
sort.Slice(unused, func(i, j int) bool {
return unused[i].pos.Cmp(unused[j].pos) < 0
return cmpPos(unused[i].pos, unused[j].pos) < 0
})
for _, v := range unused {
check.softErrorf(v.pos, UnusedVar, "%s declared and not used", v.name)

View File

@ -0,0 +1,22 @@
// Copyright 2023 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 contains various functionality that is
// different between go/types and types2. Factoring
// out this code allows more of the rest of the code
// to be shared.
package types2
import "cmd/compile/internal/syntax"
// cmpPos compares the positions p and q and returns a result r as follows:
//
// r < 0: p is before q
// r == 0: p and q are the same position (but may not be identical)
// r > 0: p is after q
//
// If p and q are in different files, p is before q if the filename
// of p sorts lexicographically before the filename of q.
func cmpPos(p, q syntax.Pos) int { return p.Cmp(q) }

View File

@ -0,0 +1,12 @@
// Copyright 2023 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 exports various functionality of util.go
// so that it can be used in (package-external) tests.
package types2
import "cmd/compile/internal/syntax"
func CmpPos(p, q syntax.Pos) int { return cmpPos(p, q) }

View File

@ -620,7 +620,7 @@ func sortedInstances(m map[*ast.Ident]Instance) (instances []recordedInstance) {
instances = append(instances, recordedInstance{id, inst})
}
sort.Slice(instances, func(i, j int) bool {
return instances[i].Ident.Pos() < instances[j].Ident.Pos()
return CmpPos(instances[i].Ident.Pos(), instances[j].Ident.Pos()) < 0
})
return instances
}

View File

@ -355,7 +355,7 @@ func (check *Checker) cycleError(cycle []Object) {
func firstInSrc(path []Object) int {
fst, pos := 0, path[0].Pos()
for i, t := range path[1:] {
if t.Pos() < pos {
if cmpPos(t.Pos(), pos) < 0 {
fst, pos = i+1, t.Pos()
}
}

View File

@ -80,20 +80,25 @@ var filemap = map[string]action{
"package.go": nil,
"pointer.go": nil,
"predicates.go": nil,
"selection.go": nil,
"sizes.go": func(f *ast.File) { renameIdent(f, "IsSyncAtomicAlign64", "isSyncAtomicAlign64") },
"slice.go": nil,
"subst.go": func(f *ast.File) { fixTokenPos(f); fixTraceSel(f) },
"termlist.go": nil,
"termlist_test.go": nil,
"tuple.go": nil,
"typelists.go": nil,
"typeparam.go": nil,
"typeterm_test.go": nil,
"typeterm.go": nil,
"under.go": nil,
"universe.go": fixGlobalTypVarDecl,
"validtype.go": nil,
"scope.go": func(f *ast.File) {
fixTokenPos(f)
renameIdent(f, "Squash", "squash")
renameIdent(f, "InsertLazy", "_InsertLazy")
},
"selection.go": nil,
"sizes.go": func(f *ast.File) { renameIdent(f, "IsSyncAtomicAlign64", "isSyncAtomicAlign64") },
"slice.go": nil,
"subst.go": func(f *ast.File) { fixTokenPos(f); fixTraceSel(f) },
"termlist.go": nil,
"termlist_test.go": nil,
"tuple.go": nil,
"typelists.go": nil,
"typeparam.go": nil,
"typeterm_test.go": nil,
"typeterm.go": nil,
"under.go": nil,
"universe.go": fixGlobalTypVarDecl,
"validtype.go": nil,
}
// TODO(gri) We should be able to make these rewriters more configurable/composable.
@ -134,15 +139,23 @@ func fixTokenPos(f *ast.File) {
ast.Inspect(f, func(n ast.Node) bool {
switch n := n.(type) {
case *ast.ImportSpec:
// rewrite import path "cmd/compile/internal/syntax" to "go/token"
if n.Path.Kind == token.STRING && n.Path.Value == `"cmd/compile/internal/syntax"` {
n.Path.Value = `"go/token"`
return false
}
case *ast.SelectorExpr:
// rewrite syntax.Pos to token.Pos
if x, _ := n.X.(*ast.Ident); x != nil && x.Name == "syntax" && n.Sel.Name == "Pos" {
x.Name = "token"
return false
}
case *ast.CallExpr:
// rewrite x.IsKnown() to x.IsValid()
if fun, _ := n.Fun.(*ast.SelectorExpr); fun != nil && fun.Sel.Name == "IsKnown" && len(n.Args) == 0 {
fun.Sel.Name = "IsValid"
return false
}
}
return true
})
@ -153,6 +166,7 @@ func fixTraceSel(f *ast.File) {
ast.Inspect(f, func(n ast.Node) bool {
switch n := n.(type) {
case *ast.SelectorExpr:
// rewrite x.Trace to x.trace (for Config.Trace)
if n.Sel.Name == "Trace" {
n.Sel.Name = "trace"
return false
@ -169,6 +183,7 @@ func fixGlobalTypVarDecl(f *ast.File) {
ast.Inspect(f, func(n ast.Node) bool {
switch n := n.(type) {
case *ast.ValueSpec:
// rewrite type Typ = [...]Type{...} to type Typ = []Type{...}
if len(n.Names) == 1 && n.Names[0].Name == "Typ" && len(n.Values) == 1 {
n.Values[0].(*ast.CompositeLit).Type.(*ast.ArrayType).Len = nil
return false

View File

@ -282,7 +282,7 @@ func (w *monoGraph) localNamedVertex(pkg *Package, named *Named) int {
// parameters that it's implicitly parameterized by.
for scope := obj.Parent(); scope != root; scope = scope.Parent() {
for _, elem := range scope.elems {
if elem, ok := elem.(*TypeName); ok && !elem.IsAlias() && elem.Pos() < obj.Pos() {
if elem, ok := elem.(*TypeName); ok && !elem.IsAlias() && cmpPos(elem.Pos(), obj.Pos()) < 0 {
if tpar, ok := elem.Type().(*TypeParam); ok {
if idx < 0 {
idx = len(w.vertices)

View File

@ -1,3 +1,5 @@
// Code generated by "go run generator.go"; DO NOT EDIT.
// 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.
@ -83,7 +85,7 @@ func (s *Scope) Lookup(name string) Object {
// whose scope is the scope of the package that exported them.
func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) {
for ; s != nil; s = s.parent {
if obj := s.Lookup(name); obj != nil && (!pos.IsValid() || obj.scopePos() <= pos) {
if obj := s.Lookup(name); obj != nil && (!pos.IsValid() || cmpPos(obj.scopePos(), pos) <= 0) {
return s, obj
}
}
@ -107,11 +109,11 @@ func (s *Scope) Insert(obj Object) Object {
return nil
}
// _InsertLazy is like Insert, but allows deferring construction of the
// InsertLazy is like Insert, but allows deferring construction of the
// inserted object until it's accessed with Lookup. The Object
// returned by resolve must have the same name as given to _InsertLazy.
// returned by resolve must have the same name as given to InsertLazy.
// If s already contains an alternative object with the same name,
// _InsertLazy leaves s unchanged and returns false. Otherwise it
// InsertLazy leaves s unchanged and returns false. Otherwise it
// records the binding and returns true. The object's parent scope
// will be set to s after resolve is called.
func (s *Scope) _InsertLazy(name string, resolve func() Object) bool {
@ -129,7 +131,7 @@ func (s *Scope) insert(name string, obj Object) {
s.elems[name] = obj
}
// squash merges s with its parent scope p by adding all
// Squash merges s with its parent scope p by adding all
// objects of s to p, adding all children of s to the
// children of p, and removing s from p's children.
// The function f is called for each object obj in s which
@ -175,7 +177,7 @@ func (s *Scope) End() token.Pos { return s.end }
// The result is guaranteed to be valid only if the type-checked
// AST has complete position information.
func (s *Scope) Contains(pos token.Pos) bool {
return s.pos <= pos && pos < s.end
return cmpPos(s.pos, pos) <= 0 && cmpPos(pos, s.end) < 0
}
// Innermost returns the innermost (child) scope containing

View File

@ -65,7 +65,7 @@ func (check *Checker) usage(scope *Scope) {
}
}
sort.Slice(unused, func(i, j int) bool {
return unused[i].pos < unused[j].pos
return cmpPos(unused[i].pos, unused[j].pos) < 0
})
for _, v := range unused {
check.softErrorf(v, UnusedVar, "%s declared and not used", v.name)

22
src/go/types/util.go Normal file
View File

@ -0,0 +1,22 @@
// Copyright 2023 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 contains various functionality that is
// different between go/types and types2. Factoring
// out this code allows more of the rest of the code
// to be shared.
package types
import "go/token"
// cmpPos compares the positions p and q and returns a result r as follows:
//
// r < 0: p is before q
// r == 0: p and q are the same position (but may not be identical)
// r > 0: p is after q
//
// If p and q are in different files, p is before q if the filename
// of p sorts lexicographically before the filename of q.
func cmpPos(p, q token.Pos) int { return int(p - q) }

12
src/go/types/util_test.go Normal file
View File

@ -0,0 +1,12 @@
// Copyright 2023 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 exports various functionality of util.go
// so that it can be used in (package-external) tests.
package types
import "go/token"
func CmpPos(p, q token.Pos) int { return cmpPos(p, q) }