mirror of https://github.com/golang/go.git
go/types, types2: add Environment to Config
Port to types2 and adjust compiler accordingly. Change-Id: I2e72b151ef834977dca64cb2e62cedcac4e46062 Reviewed-on: https://go-review.googlesource.com/c/go/+/348578 Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
parent
f5f8a911d8
commit
a1f6208e56
|
|
@ -43,12 +43,12 @@ var haveLegacyImports = false
|
||||||
// for an imported package by overloading writeNewExportFunc, then
|
// for an imported package by overloading writeNewExportFunc, then
|
||||||
// that payload will be mapped into memory and passed to
|
// that payload will be mapped into memory and passed to
|
||||||
// newReadImportFunc.
|
// newReadImportFunc.
|
||||||
var newReadImportFunc = func(data string, pkg1 *types.Pkg, check *types2.Checker, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) {
|
var newReadImportFunc = func(data string, pkg1 *types.Pkg, env *types2.Environment, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) {
|
||||||
panic("unexpected new export data payload")
|
panic("unexpected new export data payload")
|
||||||
}
|
}
|
||||||
|
|
||||||
type gcimports struct {
|
type gcimports struct {
|
||||||
check *types2.Checker
|
env *types2.Environment
|
||||||
packages map[string]*types2.Package
|
packages map[string]*types2.Package
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,7 +61,7 @@ func (m *gcimports) ImportFrom(path, srcDir string, mode types2.ImportMode) (*ty
|
||||||
panic("mode must be 0")
|
panic("mode must be 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, pkg, err := readImportFile(path, typecheck.Target, m.check, m.packages)
|
_, pkg, err := readImportFile(path, typecheck.Target, m.env, m.packages)
|
||||||
return pkg, err
|
return pkg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -224,7 +224,7 @@ func parseImportPath(pathLit *syntax.BasicLit) (string, error) {
|
||||||
// readImportFile reads the import file for the given package path and
|
// readImportFile reads the import file for the given package path and
|
||||||
// returns its types.Pkg representation. If packages is non-nil, the
|
// returns its types.Pkg representation. If packages is non-nil, the
|
||||||
// types2.Package representation is also returned.
|
// types2.Package representation is also returned.
|
||||||
func readImportFile(path string, target *ir.Package, check *types2.Checker, packages map[string]*types2.Package) (pkg1 *types.Pkg, pkg2 *types2.Package, err error) {
|
func readImportFile(path string, target *ir.Package, env *types2.Environment, packages map[string]*types2.Package) (pkg1 *types.Pkg, pkg2 *types2.Package, err error) {
|
||||||
path, err = resolveImportPath(path)
|
path, err = resolveImportPath(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
@ -279,7 +279,7 @@ func readImportFile(path string, target *ir.Package, check *types2.Checker, pack
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg2, err = newReadImportFunc(data, pkg1, check, packages)
|
pkg2, err = newReadImportFunc(data, pkg1, env, packages)
|
||||||
} else {
|
} else {
|
||||||
// We only have old data. Oh well, fall back to the legacy importers.
|
// We only have old data. Oh well, fall back to the legacy importers.
|
||||||
haveLegacyImports = true
|
haveLegacyImports = true
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,13 @@ func checkFiles(noders []*noder) (posMap, *types2.Package, *types2.Info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// typechecking
|
// typechecking
|
||||||
|
env := types2.NewEnvironment()
|
||||||
importer := gcimports{
|
importer := gcimports{
|
||||||
|
env: env,
|
||||||
packages: map[string]*types2.Package{"unsafe": types2.Unsafe},
|
packages: map[string]*types2.Package{"unsafe": types2.Unsafe},
|
||||||
}
|
}
|
||||||
conf := types2.Config{
|
conf := types2.Config{
|
||||||
|
Environment: env,
|
||||||
GoVersion: base.Flag.Lang,
|
GoVersion: base.Flag.Lang,
|
||||||
IgnoreLabels: true, // parser already checked via syntax.CheckBranches mode
|
IgnoreLabels: true, // parser already checked via syntax.CheckBranches mode
|
||||||
CompilerErrorMessages: true, // use error strings matching existing compiler errors
|
CompilerErrorMessages: true, // use error strings matching existing compiler errors
|
||||||
|
|
@ -60,9 +63,7 @@ func checkFiles(noders []*noder) (posMap, *types2.Package, *types2.Info) {
|
||||||
// expand as needed
|
// expand as needed
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg := types2.NewPackage(base.Ctxt.Pkgpath, "")
|
pkg, err := conf.Check(base.Ctxt.Pkgpath, files, info)
|
||||||
importer.check = types2.NewChecker(&conf, pkg, info)
|
|
||||||
err := importer.check.Files(files)
|
|
||||||
|
|
||||||
base.ExitIfErrors()
|
base.ExitIfErrors()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import (
|
||||||
type pkgReader2 struct {
|
type pkgReader2 struct {
|
||||||
pkgDecoder
|
pkgDecoder
|
||||||
|
|
||||||
check *types2.Checker
|
env *types2.Environment
|
||||||
imports map[string]*types2.Package
|
imports map[string]*types2.Package
|
||||||
|
|
||||||
posBases []*syntax.PosBase
|
posBases []*syntax.PosBase
|
||||||
|
|
@ -26,11 +26,11 @@ type pkgReader2 struct {
|
||||||
typs []types2.Type
|
typs []types2.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func readPackage2(check *types2.Checker, imports map[string]*types2.Package, input pkgDecoder) *types2.Package {
|
func readPackage2(env *types2.Environment, imports map[string]*types2.Package, input pkgDecoder) *types2.Package {
|
||||||
pr := pkgReader2{
|
pr := pkgReader2{
|
||||||
pkgDecoder: input,
|
pkgDecoder: input,
|
||||||
|
|
||||||
check: check,
|
env: env,
|
||||||
imports: imports,
|
imports: imports,
|
||||||
|
|
||||||
posBases: make([]*syntax.PosBase, input.numElems(relocPosBase)),
|
posBases: make([]*syntax.PosBase, input.numElems(relocPosBase)),
|
||||||
|
|
@ -233,9 +233,7 @@ func (r *reader2) doTyp() (res types2.Type) {
|
||||||
obj, targs := r.obj()
|
obj, targs := r.obj()
|
||||||
name := obj.(*types2.TypeName)
|
name := obj.(*types2.TypeName)
|
||||||
if len(targs) != 0 {
|
if len(targs) != 0 {
|
||||||
// TODO(mdempsky) should use a single shared environment here
|
t, _ := types2.Instantiate(r.p.env, name.Type(), targs, false)
|
||||||
// (before, this used a shared checker)
|
|
||||||
t, _ := types2.Instantiate(types2.NewEnvironment(), name.Type(), targs, false)
|
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
return name.Type()
|
return name.Type()
|
||||||
|
|
|
||||||
|
|
@ -78,12 +78,12 @@ func unified(noders []*noder) {
|
||||||
base.Errorf("cannot use -G and -d=quirksmode together")
|
base.Errorf("cannot use -G and -d=quirksmode together")
|
||||||
}
|
}
|
||||||
|
|
||||||
newReadImportFunc = func(data string, pkg1 *types.Pkg, check *types2.Checker, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) {
|
newReadImportFunc = func(data string, pkg1 *types.Pkg, env *types2.Environment, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) {
|
||||||
pr := newPkgDecoder(pkg1.Path, data)
|
pr := newPkgDecoder(pkg1.Path, data)
|
||||||
|
|
||||||
// Read package descriptors for both types2 and compiler backend.
|
// Read package descriptors for both types2 and compiler backend.
|
||||||
readPackage(newPkgReader(pr), pkg1)
|
readPackage(newPkgReader(pr), pkg1)
|
||||||
pkg2 = readPackage2(check, packages, pr)
|
pkg2 = readPackage2(env, packages, pr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,11 @@ type ImporterFrom interface {
|
||||||
// A Config specifies the configuration for type checking.
|
// A Config specifies the configuration for type checking.
|
||||||
// The zero value for Config is a ready-to-use default configuration.
|
// The zero value for Config is a ready-to-use default configuration.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
// Environment is the environment used for resolving global
|
||||||
|
// identifiers. If nil, the type checker will initialize this
|
||||||
|
// field with a newly created environment.
|
||||||
|
Environment *Environment
|
||||||
|
|
||||||
// GoVersion describes the accepted Go language version. The string
|
// GoVersion describes the accepted Go language version. The string
|
||||||
// must follow the format "go%d.%d" (e.g. "go1.12") or ist must be
|
// must follow the format "go%d.%d" (e.g. "go1.12") or ist must be
|
||||||
// empty; an empty string indicates the latest language version.
|
// empty; an empty string indicates the latest language version.
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,6 @@ type Checker struct {
|
||||||
nextID uint64 // unique Id for type parameters (first valid Id is 1)
|
nextID uint64 // unique Id for type parameters (first valid Id is 1)
|
||||||
objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info
|
objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info
|
||||||
impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package
|
impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package
|
||||||
env *Environment // for deduplicating identical instances
|
|
||||||
|
|
||||||
// pkgPathMap maps package names to the set of distinct import paths we've
|
// pkgPathMap maps package names to the set of distinct import paths we've
|
||||||
// seen for that name, anywhere in the import graph. It is used for
|
// seen for that name, anywhere in the import graph. It is used for
|
||||||
|
|
@ -171,6 +170,11 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
|
||||||
conf = new(Config)
|
conf = new(Config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure we have an environment
|
||||||
|
if conf.Environment == nil {
|
||||||
|
conf.Environment = NewEnvironment()
|
||||||
|
}
|
||||||
|
|
||||||
// make sure we have an info struct
|
// make sure we have an info struct
|
||||||
if info == nil {
|
if info == nil {
|
||||||
info = new(Info)
|
info = new(Info)
|
||||||
|
|
@ -188,7 +192,6 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
|
||||||
version: version,
|
version: version,
|
||||||
objMap: make(map[Object]*declInfo),
|
objMap: make(map[Object]*declInfo),
|
||||||
impMap: make(map[importKey]*Package),
|
impMap: make(map[importKey]*Package),
|
||||||
env: NewEnvironment(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -317,7 +317,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
case *Named:
|
case *Named:
|
||||||
t.expand(check.env)
|
t.expand(check.conf.Environment)
|
||||||
|
|
||||||
// don't touch the type if it is from a different package or the Universe scope
|
// don't touch the type if it is from a different package or the Universe scope
|
||||||
// (doing so would lead to a race condition - was issue #35049)
|
// (doing so would lead to a race condition - was issue #35049)
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, posLis
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
inst := check.instance(pos, typ, targs, check.env)
|
inst := check.instance(pos, typ, targs, check.conf.Environment)
|
||||||
|
|
||||||
assert(len(posList) <= len(targs))
|
assert(len(posList) <= len(targs))
|
||||||
check.later(func() {
|
check.later(func() {
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ func (n *Named) expand(env *Environment) *Named {
|
||||||
// in subst) feels overly complicated. Can we simplify?
|
// in subst) feels overly complicated. Can we simplify?
|
||||||
if env == nil {
|
if env == nil {
|
||||||
if n.check != nil {
|
if n.check != nil {
|
||||||
env = n.check.env
|
env = n.check.conf.Environment
|
||||||
} else {
|
} else {
|
||||||
// If we're instantiating lazily, we might be outside the scope of a
|
// If we're instantiating lazily, we might be outside the scope of a
|
||||||
// type-checking pass. In that case we won't have a pre-existing
|
// type-checking pass. In that case we won't have a pre-existing
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ func (check *Checker) subst(pos syntax.Pos, typ Type, smap substMap, env *Enviro
|
||||||
if check != nil {
|
if check != nil {
|
||||||
subst.check = check
|
subst.check = check
|
||||||
if env == nil {
|
if env == nil {
|
||||||
env = check.env
|
env = check.conf.Environment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if env == nil {
|
if env == nil {
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,11 @@ type ImporterFrom interface {
|
||||||
// A Config specifies the configuration for type checking.
|
// A Config specifies the configuration for type checking.
|
||||||
// The zero value for Config is a ready-to-use default configuration.
|
// The zero value for Config is a ready-to-use default configuration.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
// Environment is the environment used for resolving global
|
||||||
|
// identifiers. If nil, the type checker will initialize this
|
||||||
|
// field with a newly created environment.
|
||||||
|
Environment *Environment
|
||||||
|
|
||||||
// GoVersion describes the accepted Go language version. The string
|
// GoVersion describes the accepted Go language version. The string
|
||||||
// must follow the format "go%d.%d" (e.g. "go1.12") or it must be
|
// must follow the format "go%d.%d" (e.g. "go1.12") or it must be
|
||||||
// empty; an empty string indicates the latest language version.
|
// empty; an empty string indicates the latest language version.
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,6 @@ type Checker struct {
|
||||||
nextID uint64 // unique Id for type parameters (first valid Id is 1)
|
nextID uint64 // unique Id for type parameters (first valid Id is 1)
|
||||||
objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info
|
objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info
|
||||||
impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package
|
impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package
|
||||||
env *Environment // for deduplicating identical instances
|
|
||||||
|
|
||||||
// pkgPathMap maps package names to the set of distinct import paths we've
|
// pkgPathMap maps package names to the set of distinct import paths we've
|
||||||
// seen for that name, anywhere in the import graph. It is used for
|
// seen for that name, anywhere in the import graph. It is used for
|
||||||
|
|
@ -174,6 +173,11 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
|
||||||
conf = new(Config)
|
conf = new(Config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure we have an environment
|
||||||
|
if conf.Environment == nil {
|
||||||
|
conf.Environment = NewEnvironment()
|
||||||
|
}
|
||||||
|
|
||||||
// make sure we have an info struct
|
// make sure we have an info struct
|
||||||
if info == nil {
|
if info == nil {
|
||||||
info = new(Info)
|
info = new(Info)
|
||||||
|
|
@ -192,7 +196,6 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
|
||||||
version: version,
|
version: version,
|
||||||
objMap: make(map[Object]*declInfo),
|
objMap: make(map[Object]*declInfo),
|
||||||
impMap: make(map[importKey]*Package),
|
impMap: make(map[importKey]*Package),
|
||||||
env: NewEnvironment(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,7 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
case *Named:
|
case *Named:
|
||||||
t.expand(check.env)
|
t.expand(check.conf.Environment)
|
||||||
// don't touch the type if it is from a different package or the Universe scope
|
// don't touch the type if it is from a different package or the Universe scope
|
||||||
// (doing so would lead to a race condition - was issue #35049)
|
// (doing so would lead to a race condition - was issue #35049)
|
||||||
if t.obj.pkg != check.pkg {
|
if t.obj.pkg != check.pkg {
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, posList
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
inst := check.instance(pos, typ, targs, check.env)
|
inst := check.instance(pos, typ, targs, check.conf.Environment)
|
||||||
|
|
||||||
assert(len(posList) <= len(targs))
|
assert(len(posList) <= len(targs))
|
||||||
check.later(func() {
|
check.later(func() {
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ func (n *Named) expand(env *Environment) *Named {
|
||||||
// in subst) feels overly complicated. Can we simplify?
|
// in subst) feels overly complicated. Can we simplify?
|
||||||
if env == nil {
|
if env == nil {
|
||||||
if n.check != nil {
|
if n.check != nil {
|
||||||
env = n.check.env
|
env = n.check.conf.Environment
|
||||||
} else {
|
} else {
|
||||||
// If we're instantiating lazily, we might be outside the scope of a
|
// If we're instantiating lazily, we might be outside the scope of a
|
||||||
// type-checking pass. In that case we won't have a pre-existing
|
// type-checking pass. In that case we won't have a pre-existing
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ func (check *Checker) subst(pos token.Pos, typ Type, smap substMap, env *Environ
|
||||||
if check != nil {
|
if check != nil {
|
||||||
subst.check = check
|
subst.check = check
|
||||||
if env == nil {
|
if env == nil {
|
||||||
env = check.env
|
env = check.conf.Environment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if env == nil {
|
if env == nil {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue