1
0
mirror of https://github.com/golang/go synced 2024-11-18 13:14:47 -07:00

go.tools/go/types: rename Context -> Config (more apt name)

Also: Various minor cleanups.

R=adonovan, r
CC=golang-dev
https://golang.org/cl/11445044
This commit is contained in:
Robert Griesemer 2013-07-18 17:07:44 -07:00
parent 9460d02473
commit 40a278e5ee
18 changed files with 88 additions and 87 deletions

View File

@ -19,9 +19,9 @@ func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
pkg.spans = make(map[types.Object]Span)
pkg.types = make(map[ast.Expr]types.Type)
pkg.values = make(map[ast.Expr]exact.Value)
// By providing the Context with our own error function, it will continue
// By providing a Config with our own error function, it will continue
// past the first error. There is no need for that function to do anything.
context := types.Context{
config := types.Config{
Error: func(error) {},
}
info := &types.Info{
@ -29,7 +29,7 @@ func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
Values: pkg.values,
Objects: pkg.idents,
}
_, err := context.Check(pkg.path, fs, astFiles, info)
_, err := config.Check(pkg.path, fs, astFiles, info)
// update spans
for id, obj := range pkg.idents {
pkg.growSpan(id, obj)

View File

@ -4,7 +4,7 @@
// Package types declares the data types and implements
// the algorithms for type-checking of Go packages.
// Use Check and Context.Check to invoke the type-checker.
// Use Check and Config.Check to invoke the type-checker.
//
// Type-checking consists of several interdependent phases:
//
@ -34,19 +34,19 @@ import (
// list of *ast.Files and corresponding file set, and the import path
// the package is identified with. The path must not be empty or dot (".").
//
// For more control over type-checking and results, use Context.Check.
// For more control over type-checking and results, use Config.Check.
func Check(path string, fset *token.FileSet, files []*ast.File) (*Package, error) {
var ctxt Context
pkg, err := ctxt.check(path, fset, files, nil)
var conf Config
pkg, err := conf.check(path, fset, files, nil)
if err != nil {
return nil, err
}
return pkg, nil
}
// A Context specifies the supporting context for type checking.
// The zero value for a Context is a ready-to-use default context.
type Context struct {
// A Config specifies the configuration for type checking.
// The zero value for Config is a ready-to-use default configuration.
type Config struct {
// If Error != nil, it is called with each error found
// during type checking. The error strings of errors with
// detailed position information are formatted as follows:
@ -103,7 +103,7 @@ type Info struct {
// are not recorded.
Objects map[*ast.Ident]Object
// If Implicits != nil, it records the object for each node the implicitly
// If Implicits != nil, it records the object for each node that implicitly
// declares objects. The following node and object types may appear:
//
// node obj
@ -118,15 +118,15 @@ type Info struct {
// error if any, and if info != nil, additional type information. The package is
// specified by a list of *ast.Files and corresponding file set, and the import
// path the package is identified with. The path must not be empty or dot (".").
func (ctxt *Context) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
return ctxt.check(path, fset, files, info)
func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
return conf.check(path, fset, files, info)
}
// IsAssignableTo reports whether a value of type V
// is assignable to a variable of type T.
func IsAssignableTo(V, T Type) bool {
x := operand{mode: value, typ: V}
return x.isAssignableTo(nil, T) // context not needed for non-constant x
return x.isAssignableTo(nil, T) // config not needed for non-constant x
}
// BUG(gri): Conversions of constants only change the type, not the value (e.g., int(1.1) is wrong).

View File

@ -32,7 +32,7 @@ func (check *checker) assignment(x *operand, to Type) bool {
check.convertUntyped(x, to)
return x.mode != invalid && x.isAssignableTo(check.ctxt, to)
return x.mode != invalid && x.isAssignableTo(check.conf, to)
}
func (check *checker) initConst(lhs *Const, x *operand) {

View File

@ -236,7 +236,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin) {
if x.mode == invalid {
goto Error
}
if !x.isAssignableTo(check.ctxt, m.key) {
if !x.isAssignableTo(check.conf, m.key) {
check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.key)
goto Error
}
@ -327,7 +327,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin) {
case _Alignof:
x.mode = constant
x.val = exact.MakeInt64(check.ctxt.alignof(x.typ))
x.val = exact.MakeInt64(check.conf.alignof(x.typ))
x.typ = Typ[Uintptr]
case _Offsetof:
@ -355,14 +355,14 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin) {
check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, base)
goto Error
}
offs := check.ctxt.offsetof(base, index)
offs := check.conf.offsetof(base, index)
x.mode = constant
x.val = exact.MakeInt64(offs)
x.typ = Typ[Uintptr]
case _Sizeof:
x.mode = constant
x.val = exact.MakeInt64(check.ctxt.sizeof(x.typ))
x.val = exact.MakeInt64(check.conf.sizeof(x.typ))
x.typ = Typ[Uintptr]
case _Assert:

View File

@ -36,7 +36,7 @@ type exprInfo struct {
// A checker is an instance of the type checker.
type checker struct {
ctxt *Context
conf *Config
fset *token.FileSet
Info
@ -59,9 +59,9 @@ type checker struct {
indent int // indentation for tracing
}
func newChecker(ctxt *Context, fset *token.FileSet, pkg *Package) *checker {
func newChecker(conf *Config, fset *token.FileSet, pkg *Package) *checker {
return &checker{
ctxt: ctxt,
conf: conf,
fset: fset,
pkg: pkg,
methods: make(map[*TypeName]*Scope),
@ -133,14 +133,14 @@ func (check *checker) handleBailout(err *error) {
}
}
func (ctxt *Context) check(pkgPath string, fset *token.FileSet, files []*ast.File, info *Info) (pkg *Package, err error) {
func (conf *Config) check(pkgPath string, fset *token.FileSet, files []*ast.File, info *Info) (pkg *Package, err error) {
pkg = &Package{
path: pkgPath,
scope: NewScope(Universe),
imports: make(map[string]*Package),
}
check := newChecker(ctxt, fset, pkg)
check := newChecker(conf, fset, pkg)
defer check.handleBailout(&err)
// we need a reasonable path to continue
@ -149,11 +149,6 @@ func (ctxt *Context) check(pkgPath string, fset *token.FileSet, files []*ast.Fil
return
}
// install optional info
if info != nil {
check.Info = *info
}
// determine package name and files
i := 0
for _, file := range files {
@ -170,6 +165,11 @@ func (ctxt *Context) check(pkgPath string, fset *token.FileSet, files []*ast.Fil
}
}
// install optional info
if info != nil {
check.Info = *info
}
// TODO(gri) resolveFiles needs to be split up and renamed (cleanup)
check.resolveFiles(files[:i])

View File

@ -203,8 +203,8 @@ func checkFiles(t *testing.T, testfiles []string) {
}
// typecheck and collect typechecker errors
var ctxt Context
ctxt.Error = func(err error) {
var conf Config
conf.Error = func(err error) {
if *listErrors {
t.Error(err)
return
@ -216,7 +216,7 @@ func checkFiles(t *testing.T, testfiles []string) {
errlist = append(errlist, err)
}
}
ctxt.Check(pkgName, fset, files, nil)
conf.Check(pkgName, fset, files, nil)
if *listErrors {
return

View File

@ -58,7 +58,7 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type) {
// TODO(gri) verify the remaining conversions.
} else {
// non-constant conversion
if !x.isConvertible(check.ctxt, typ) {
if !x.isConvertible(check.conf, typ) {
goto ErrorMsg
}
x.mode = value
@ -91,9 +91,9 @@ Error:
x.expr = conv
}
func (x *operand) isConvertible(ctxt *Context, T Type) bool {
func (x *operand) isConvertible(conf *Config, T Type) bool {
// "x is assignable to T"
if x.isAssignableTo(ctxt, T) {
if x.isAssignableTo(conf, T) {
return true
}

View File

@ -58,7 +58,7 @@ func (check *checker) err(err error) {
if check.firsterr == nil {
check.firsterr = err
}
f := check.ctxt.Error
f := check.conf.Error
if f == nil {
panic(bailout{}) // report only first error
}

View File

@ -86,8 +86,8 @@ func EvalNode(fset *token.FileSet, node ast.Expr, pkg *Package, scope *Scope) (t
}
// initialize checker
var ctxt Context
check := newChecker(&ctxt, fset, pkg)
var conf Config
check := newChecker(&conf, fset, pkg)
check.topScope = scope
defer check.handleBailout(&err)
@ -95,7 +95,7 @@ func EvalNode(fset *token.FileSet, node ast.Expr, pkg *Package, scope *Scope) (t
var x operand
check.exprOrType(&x, node)
switch x.mode {
case invalid, novalue, typexprn:
case invalid, novalue:
fallthrough
default:
unreachable() // or bailed out with error

View File

@ -61,7 +61,8 @@ constant lhs must be representable as an integer.
When an expression gets its final type, either on the way out from rawExpr,
on the way down in updateExprType, or at the end of the type checker run,
if present the Context.Expr method is invoked to notify a go/types client.
the type (and constant value, if any) is recorded via Info.Types and Values,
if present.
*/
type opPredicates map[token.Token]func(Type) bool
@ -124,7 +125,7 @@ func (check *checker) unary(x *operand, op token.Token) {
typ := x.typ.Underlying().(*Basic)
size := -1
if isUnsigned(typ) {
size = int(check.ctxt.sizeof(typ))
size = int(check.conf.sizeof(typ))
}
x.val = exact.UnaryOp(op, x.val, size)
// Typed constants must be representable in
@ -154,7 +155,7 @@ func isComparison(op token.Token) bool {
return false
}
func isRepresentableConst(x exact.Value, ctxt *Context, as BasicKind) bool {
func isRepresentableConst(x exact.Value, conf *Config, as BasicKind) bool {
switch x.Kind() {
case exact.Unknown:
return true
@ -166,7 +167,7 @@ func isRepresentableConst(x exact.Value, ctxt *Context, as BasicKind) bool {
if x, ok := exact.Int64Val(x); ok {
switch as {
case Int:
var s = uint(ctxt.sizeof(Typ[as])) * 8
var s = uint(conf.sizeof(Typ[as])) * 8
return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
case Int8:
const s = 8
@ -180,7 +181,7 @@ func isRepresentableConst(x exact.Value, ctxt *Context, as BasicKind) bool {
case Int64:
return true
case Uint, Uintptr:
if s := uint(ctxt.sizeof(Typ[as])) * 8; s < 64 {
if s := uint(conf.sizeof(Typ[as])) * 8; s < 64 {
return 0 <= x && x <= int64(1)<<s-1
}
return 0 <= x
@ -211,7 +212,7 @@ func isRepresentableConst(x exact.Value, ctxt *Context, as BasicKind) bool {
n := exact.BitLen(x)
switch as {
case Uint, Uintptr:
var s = uint(ctxt.sizeof(Typ[as])) * 8
var s = uint(conf.sizeof(Typ[as])) * 8
return exact.Sign(x) >= 0 && n <= int(s)
case Uint64:
return exact.Sign(x) >= 0 && n <= 64
@ -270,7 +271,7 @@ func (check *checker) isRepresentable(x *operand, typ *Basic) {
return
}
if !isRepresentableConst(x.val, check.ctxt, typ.kind) {
if !isRepresentableConst(x.val, check.conf, typ.kind) {
var msg string
if isNumeric(x.typ) && isNumeric(typ) {
msg = "%s overflows (or cannot be accurately represented as) %s"
@ -287,7 +288,7 @@ func (check *checker) isRepresentable(x *operand, typ *Basic) {
// If typ is still an untyped and not the final type, updateExprType
// only updates the recorded untyped type for x and possibly its
// operands. Otherwise (i.e., typ is not an untyped type anymore,
// or it is the final type for x), Context.Expr is invoked, if present.
// or it is the final type for x), the type and value are recorded.
// Also, if x is a constant, it must be representable as a value of typ,
// and if x is the (formerly untyped) lhs operand of a non-constant
// shift, it must be an integer value.
@ -469,7 +470,7 @@ func (check *checker) comparison(x, y *operand, op token.Token) {
// TODO(gri) deal with interface vs non-interface comparison
valid := false
if x.isAssignableTo(check.ctxt, y.typ) || y.isAssignableTo(check.ctxt, x.typ) {
if x.isAssignableTo(check.conf, y.typ) || y.isAssignableTo(check.conf, x.typ) {
switch op {
case token.EQL, token.NEQ:
valid = isComparable(x.typ) ||
@ -779,10 +780,6 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type) {
case constant:
typ = x.typ
val = x.val
case typexprn:
x.mode = typexpr
typ = x.typ
record = false // type was already recorded
default:
typ = x.typ
}
@ -1220,8 +1217,13 @@ func (check *checker) expr0(x *operand, e ast.Expr, hint Type) {
case *ast.ArrayType, *ast.StructType, *ast.FuncType,
*ast.InterfaceType, *ast.MapType, *ast.ChanType:
x.mode = typexprn // not typexpr; Context.Expr callback was invoked by check.typ
x.mode = typexpr
x.typ = check.typ(e, nil, false)
// Note: rawExpr (caller of expr0) will call check.recordTypeAndValue
// even though check.typ has already called it. This is fine as both
// times the same expression and type are recorded. It is also not a
// performance issue because we only reach here for composite literal
// types, which are comparatively rare.
default:
if debug {

View File

@ -46,9 +46,9 @@ var (
return
}
var ctxt Context
var conf Config
types := make(map[ast.Expr]Type)
_, err = ctxt.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
if err != nil {
t.Error(err)
}

View File

@ -14,6 +14,7 @@ import (
)
// TODO(gri) Move Method and accessors to objects.go.
// TODO(gri) Method.Type() returns the wrong receiver type.
// A Method represents a concrete or abstract (interface)
// method of a method set.

View File

@ -22,7 +22,6 @@ const (
invalid operandMode = iota // operand is invalid
novalue // operand represents no value (result of a function call w/o result)
typexpr // operand is a type
typexprn // like typexpr; only used to communicate between checker.expr0 and checker.rawExpr
constant // operand is a constant; the operand's typ is a Basic type
variable // operand is an addressable variable
value // operand is a computed value
@ -33,7 +32,6 @@ var operandModeString = [...]string{
invalid: "invalid",
novalue: "no value",
typexpr: "type",
typexprn: "type/n",
constant: "constant",
variable: "variable",
value: "value",
@ -127,7 +125,7 @@ func (x *operand) isNil() bool {
// overlapping in functionality. Need to simplify and clean up.
// isAssignableTo reports whether x is assignable to a variable of type T.
func (x *operand) isAssignableTo(ctxt *Context, T Type) bool {
func (x *operand) isAssignableTo(conf *Config, T Type) bool {
if x.mode == invalid || T == Typ[Invalid] {
return true // avoid spurious errors
}
@ -186,7 +184,7 @@ func (x *operand) isAssignableTo(ctxt *Context, T Type) bool {
switch t := Tu.(type) {
case *Basic:
if x.mode == constant {
return isRepresentableConst(x.val, ctxt, t.kind)
return isRepresentableConst(x.val, conf, t.kind)
}
// The result of a comparison is an untyped boolean,
// but may not be a constant.
@ -207,5 +205,5 @@ func (x *operand) isAssignableTo(ctxt *Context, T Type) bool {
func (x *operand) isInteger() bool {
return x.mode == invalid ||
isInteger(x.typ) ||
x.mode == constant && isRepresentableConst(x.val, nil, UntypedInt) // no context required for UntypedInt
x.mode == constant && isRepresentableConst(x.val, nil, UntypedInt) // no *Config required for UntypedInt
}

View File

@ -86,14 +86,14 @@ func (check *checker) arityMatch(s, init *ast.ValueSpec) {
func (check *checker) resolveFiles(files []*ast.File) {
pkg := check.pkg
// Phase 1: Pre-declare all package scope objects so that they can be found
// when type-checking package objects.
// Phase 1: Pre-declare all package-level objects so that they can be found
// independent of source order.
var scopes []*Scope // corresponding file scope per file
var objList []Object
var objMap = make(map[Object]*decl)
var methods []*mdecl
var fileScope *Scope // current file scope, used by collect
var fileScope *Scope // current file scope, used by declare
declare := func(ident *ast.Ident, obj Object, typ, init ast.Expr) {
assert(ident.Name == obj.Name())
@ -118,7 +118,7 @@ func (check *checker) resolveFiles(files []*ast.File) {
objMap[obj] = &decl{fileScope, typ, init}
}
importer := check.ctxt.Import
importer := check.conf.Import
if importer == nil {
importer = GcImport
}
@ -146,7 +146,7 @@ func (check *checker) resolveFiles(files []*ast.File) {
path, _ := strconv.Unquote(s.Path.Value)
imp, err := importer(pkg.imports, path)
if imp == nil && err == nil {
err = errors.New("Context.Import returned nil")
err = errors.New("Config.Import returned nil")
}
if err != nil {
check.errorf(s.Path.Pos(), "could not import %s (%s)", path, err)

View File

@ -67,9 +67,9 @@ func TestResolveIdents(t *testing.T) {
}
// resolve and type-check package AST
var ctxt Context
var conf Config
idents := make(map[*ast.Ident]Object)
pkg, err := ctxt.Check("testResolveIdents", fset, files, &Info{Objects: idents})
pkg, err := conf.Check("testResolveIdents", fset, files, &Info{Objects: idents})
if err != nil {
t.Fatal(err)
}
@ -103,7 +103,7 @@ func TestResolveIdents(t *testing.T) {
})
}
// check that each identifier in the source is enumerated by the Context.Ident callback
// check that each identifier in the source is found in the idents map
for _, f := range files {
ast.Inspect(f, func(n ast.Node) bool {
if x, ok := n.(*ast.Ident); ok {

View File

@ -6,29 +6,29 @@
package types
func (ctxt *Context) alignof(typ Type) int64 {
if f := ctxt.Alignof; f != nil {
func (conf *Config) alignof(typ Type) int64 {
if f := conf.Alignof; f != nil {
if a := f(typ); a >= 1 {
return a
}
panic("Context.Alignof returned an alignment < 1")
panic("Config.Alignof returned an alignment < 1")
}
return DefaultAlignof(typ)
}
func (ctxt *Context) offsetsof(s *Struct) []int64 {
func (conf *Config) offsetsof(s *Struct) []int64 {
offsets := s.offsets
if offsets == nil && s.NumFields() > 0 {
// compute offsets on demand
if f := ctxt.Offsetsof; f != nil {
if f := conf.Offsetsof; f != nil {
offsets = f(s.fields)
// sanity checks
if len(offsets) != s.NumFields() {
panic("Context.Offsetsof returned the wrong number of offsets")
panic("Config.Offsetsof returned the wrong number of offsets")
}
for _, o := range offsets {
if o < 0 {
panic("Context.Offsetsof returned an offset < 0")
panic("Config.Offsetsof returned an offset < 0")
}
}
} else {
@ -42,22 +42,22 @@ func (ctxt *Context) offsetsof(s *Struct) []int64 {
// offsetof returns the offset of the field specified via
// the index sequence relative to typ. All embedded fields
// must be structs (rather than pointer to structs).
func (ctxt *Context) offsetof(typ Type, index []int) int64 {
func (conf *Config) offsetof(typ Type, index []int) int64 {
var o int64
for _, i := range index {
s := typ.Underlying().(*Struct)
o += ctxt.offsetsof(s)[i]
o += conf.offsetsof(s)[i]
typ = s.fields[i].typ
}
return o
}
func (ctxt *Context) sizeof(typ Type) int64 {
if f := ctxt.Sizeof; f != nil {
func (conf *Config) sizeof(typ Type) int64 {
if f := conf.Sizeof; f != nil {
if s := f(typ); s >= 0 {
return s
}
panic("Context.Sizeof returned a size < 0")
panic("Config.Sizeof returned a size < 0")
}
return DefaultSizeof(typ)
}
@ -67,7 +67,7 @@ func (ctxt *Context) sizeof(typ Type) int64 {
const DefaultMaxAlign = 8
// DefaultAlignof implements the default alignment computation
// for unsafe.Alignof. It is used if Context.Alignof == nil.
// for unsafe.Alignof. It is used if Config.Alignof == nil.
func DefaultAlignof(typ Type) int64 {
// For arrays and structs, alignment is defined in terms
// of alignment of the elements and fields, respectively.
@ -106,7 +106,7 @@ func align(x, a int64) int64 {
}
// DefaultOffsetsof implements the default field offset computation
// for unsafe.Offsetof. It is used if Context.Offsetsof == nil.
// for unsafe.Offsetof. It is used if Config.Offsetsof == nil.
func DefaultOffsetsof(fields []*Field) []int64 {
offsets := make([]int64, len(fields))
var o int64
@ -124,7 +124,7 @@ func DefaultOffsetsof(fields []*Field) []int64 {
const DefaultPtrSize = 8
// DefaultSizeof implements the default size computation
// for unsafe.Sizeof. It is used if Context.Sizeof == nil.
// for unsafe.Sizeof. It is used if Config.Sizeof == nil.
func DefaultSizeof(typ Type) int64 {
switch t := typ.Underlying().(type) {
case *Basic:

View File

@ -72,9 +72,9 @@ func typecheck(t *testing.T, path string, filenames []string) {
}
// typecheck package files
var ctxt Context
ctxt.Error = func(err error) { t.Error(err) }
ctxt.Check(path, fset, files, nil)
var conf Config
conf.Error = func(err error) { t.Error(err) }
conf.Check(path, fset, files, nil)
pkgCount++
}

View File

@ -30,7 +30,7 @@ type Context struct {
// The Importer will override any user-supplied values for its
// Expr, Ident, ImplicitObj and Import fields; other fields
// will be passed through to the type checker.
TypeChecker types.Context
TypeChecker types.Config
// If Loader is non-nil, it is used to satisfy imports.
//