go.tools/go/types: support for fake imports of package "C"
Also: - cleaner method set printing - disable debug mode internally (50% faster) R=adonovan, bradfitz CC=golang-dev https://golang.org/cl/12578043
This commit is contained in:
parent
56b9e46247
commit
875ff2496f
|
@ -29,16 +29,15 @@ import (
|
|||
"code.google.com/p/go.tools/go/exact"
|
||||
)
|
||||
|
||||
// Check type-checks a package and returns the resulting package object,
|
||||
// or a nil package and the first error. The package is specified by a
|
||||
// list of *ast.Files and corresponding file set, and the import path
|
||||
// the package is identified with. The clean path must not be empty or
|
||||
// dot (".").
|
||||
// Check type-checks a package and returns the resulting complete package
|
||||
// object, or a nil package and the first error. The package is specified
|
||||
// by a list of *ast.Files and corresponding file set, and the import path
|
||||
// the package is identified with. The clean path must not be empty or dot (".").
|
||||
//
|
||||
// For more control over type-checking and results, use Config.Check.
|
||||
func Check(path string, fset *token.FileSet, files []*ast.File) (*Package, error) {
|
||||
var conf Config
|
||||
pkg, err := conf.check(path, fset, files, nil)
|
||||
pkg, err := conf.Check(path, fset, files, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -52,6 +51,12 @@ type Config struct {
|
|||
// type-checked.
|
||||
IgnoreFuncBodies bool
|
||||
|
||||
// If FakeImportC is set, `import "C"` (for packages requiring Cgo)
|
||||
// and expressions with qualified identifiers referrring to package
|
||||
// C are silently ignored.
|
||||
// Caution: Effects may be unpredictable - do not use casually!
|
||||
FakeImportC bool
|
||||
|
||||
// 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:
|
||||
|
@ -125,12 +130,20 @@ type Info struct {
|
|||
Selections map[*ast.SelectorExpr]*Selection
|
||||
}
|
||||
|
||||
// Check type-checks a package and returns the resulting package object, the first
|
||||
// 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 clean path must not be empty or dot (".").
|
||||
// Check type-checks a package and returns the resulting package object,
|
||||
// the first error if any, and if info != nil, additional type information.
|
||||
// The package is marked as complete if no errors occurred, otherwise it is
|
||||
// incomplete.
|
||||
//
|
||||
// The package is specified by a list of *ast.Files and corresponding file
|
||||
// set, and the import path the package is identified with. The clean path
|
||||
// must not be empty or dot (".").
|
||||
func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
|
||||
return conf.check(path, fset, files, info)
|
||||
pkg, err := conf.check(path, fset, files, info)
|
||||
if err == nil {
|
||||
pkg.complete = true
|
||||
}
|
||||
return pkg, err
|
||||
}
|
||||
|
||||
// IsAssignableTo reports whether a value of type V
|
||||
|
|
|
@ -173,12 +173,12 @@ func (check *checker) selector(x *operand, e *ast.SelectorExpr) {
|
|||
check.recordObject(ident, pkg)
|
||||
exp := pkg.scope.Lookup(sel)
|
||||
if exp == nil {
|
||||
check.errorf(e.Pos(), "%s not declared by package %s", sel, ident)
|
||||
if !pkg.fake {
|
||||
check.errorf(e.Pos(), "%s not declared by package %s", sel, ident)
|
||||
}
|
||||
goto Error
|
||||
} else if !exp.IsExported() {
|
||||
// gcimported package scopes contain non-exported
|
||||
// objects such as types used in partially exported
|
||||
// objects - do not accept them
|
||||
}
|
||||
if !exp.IsExported() {
|
||||
check.errorf(e.Pos(), "%s not exported by package %s", sel, ident)
|
||||
goto Error
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
|
||||
// debugging/development support
|
||||
const (
|
||||
debug = true // leave on during development
|
||||
debug = false // leave on during development
|
||||
trace = false // turn on for detailed type resolution traces
|
||||
)
|
||||
|
||||
|
|
|
@ -370,7 +370,7 @@ func (p *gcParser) getPkg(id, name string) *Package {
|
|||
}
|
||||
pkg := p.imports[id]
|
||||
if pkg == nil && name != "" {
|
||||
pkg = NewPackage(token.NoPos, id, name, NewScope(nil), nil, false)
|
||||
pkg = NewPackage(token.NoPos, id, name, NewScope(nil), nil)
|
||||
p.imports[id] = pkg
|
||||
}
|
||||
return pkg
|
||||
|
@ -985,7 +985,7 @@ func (p *gcParser) parseExport() *Package {
|
|||
}
|
||||
|
||||
// package was imported completely and without errors
|
||||
pkg.complete = true
|
||||
pkg.MarkComplete()
|
||||
|
||||
return pkg
|
||||
}
|
||||
|
|
|
@ -28,8 +28,7 @@ func (s *MethodSet) String() string {
|
|||
var buf bytes.Buffer
|
||||
fmt.Fprintln(&buf, "MethodSet {")
|
||||
for _, f := range s.list {
|
||||
m := f.obj.(*Func)
|
||||
fmt.Fprintf(&buf, "\t%s -> %s\n", m.Id(), m)
|
||||
fmt.Fprintln(&buf, f)
|
||||
}
|
||||
fmt.Fprintln(&buf, "}")
|
||||
return buf.String()
|
||||
|
|
|
@ -122,16 +122,24 @@ func (obj *object) sameId(pkg *Package, name string) bool {
|
|||
}
|
||||
|
||||
// A Package represents the contents (objects) of a Go package.
|
||||
//
|
||||
// A package is complete if all its package scope objects are present.
|
||||
// Incomplete packages may arise via imports where the exported data
|
||||
// contains only partial information about transitively imported and
|
||||
// re-exported packages; or as a result of type-checking a package
|
||||
// that contains errors.
|
||||
//
|
||||
type Package struct {
|
||||
object
|
||||
path string // import path, "" for current (non-imported) package
|
||||
scope *Scope // imported objects
|
||||
imports map[string]*Package // map of import paths to imported packages
|
||||
complete bool // if set, this package was imported completely
|
||||
complete bool // if set, this package is complete
|
||||
fake bool // if set, this package is fake (internal use only)
|
||||
}
|
||||
|
||||
func NewPackage(pos token.Pos, path, name string, scope *Scope, imports map[string]*Package, complete bool) *Package {
|
||||
obj := &Package{object{nil, pos, nil, name, Typ[Invalid]}, path, scope, imports, complete}
|
||||
func NewPackage(pos token.Pos, path, name string, scope *Scope, imports map[string]*Package) *Package {
|
||||
obj := &Package{object{nil, pos, nil, name, Typ[Invalid]}, path, scope, imports, false, false}
|
||||
obj.pkg = obj
|
||||
return obj
|
||||
}
|
||||
|
@ -142,6 +150,9 @@ func (obj *Package) Scope() *Scope { return obj.scope }
|
|||
func (obj *Package) Imports() map[string]*Package { return obj.imports }
|
||||
func (obj *Package) Complete() bool { return obj.complete }
|
||||
|
||||
// MarkComplete marks a package as complete.
|
||||
func (obj *Package) MarkComplete() { obj.complete = true }
|
||||
|
||||
// A Const represents a declared constant.
|
||||
type Const struct {
|
||||
object
|
||||
|
|
|
@ -165,14 +165,22 @@ func (check *checker) resolveFiles(files []*ast.File) {
|
|||
for iota, spec := range d.Specs {
|
||||
switch s := spec.(type) {
|
||||
case *ast.ImportSpec:
|
||||
var imp *Package
|
||||
path, _ := strconv.Unquote(s.Path.Value)
|
||||
imp, err := importer(pkg.imports, path)
|
||||
if imp == nil && err == nil {
|
||||
err = errors.New("Config.Import returned nil")
|
||||
}
|
||||
if err != nil {
|
||||
check.errorf(s.Path.Pos(), "could not import %s (%s)", path, err)
|
||||
continue
|
||||
if path == "C" && check.conf.FakeImportC {
|
||||
// TODO(gri) shouldn't create a new one each time
|
||||
imp = NewPackage(token.NoPos, "C", "C", NewScope(nil), nil)
|
||||
imp.fake = true
|
||||
} else {
|
||||
var err error
|
||||
imp, err = importer(pkg.imports, path)
|
||||
if imp == nil && err == nil {
|
||||
err = errors.New("Config.Import returned nil but no error")
|
||||
}
|
||||
if err != nil {
|
||||
check.errorf(s.Path.Pos(), "could not import %s (%s)", path, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// local name overrides imported package name
|
||||
|
@ -185,7 +193,9 @@ func (check *checker) resolveFiles(files []*ast.File) {
|
|||
}
|
||||
}
|
||||
|
||||
imp2 := NewPackage(s.Pos(), path, name, imp.scope, nil, imp.complete)
|
||||
imp2 := NewPackage(s.Pos(), path, name, imp.scope, nil)
|
||||
imp2.complete = imp.complete
|
||||
imp2.fake = imp.fake
|
||||
if s.Name != nil {
|
||||
check.recordObject(s.Name, imp2)
|
||||
} else {
|
||||
|
|
|
@ -87,7 +87,8 @@ var predeclaredFunctions = [...]*Builtin{
|
|||
|
||||
func init() {
|
||||
Universe = NewScope(nil)
|
||||
Unsafe = NewPackage(token.NoPos, "unsafe", "unsafe", NewScope(Universe), nil, true)
|
||||
Unsafe = NewPackage(token.NoPos, "unsafe", "unsafe", NewScope(Universe), nil)
|
||||
Unsafe.complete = true
|
||||
|
||||
// predeclared types
|
||||
for _, t := range Typ {
|
||||
|
|
|
@ -24,7 +24,7 @@ type opaqueType struct {
|
|||
func (t *opaqueType) String() string { return t.name }
|
||||
|
||||
// A bogus "reflect" type-checker package. Shared across interpreters.
|
||||
var reflectTypesPackage = types.NewPackage(token.NoPos, "reflect", "reflect", nil, nil, true)
|
||||
var reflectTypesPackage = types.NewPackage(token.NoPos, "reflect", "reflect", nil, nil)
|
||||
|
||||
// rtype is the concrete type the interpreter uses to implement the
|
||||
// reflect.Type interface. Since its type is opaque to the target
|
||||
|
|
Loading…
Reference in New Issue