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

go/types, types2: use a map instead of a field for marking in validType

With this change validType doesn't modify global state anymore.
It also eliminates the need for an extra field in each object.

Preparation for fixing issue #48962.

Change-Id: If241ec77ff48911d5b43d89adabfb8ef54452c6b
Reviewed-on: https://go-review.googlesource.com/c/go/+/378176
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Robert Griesemer 2022-01-12 15:54:15 -08:00
parent 0328b4f4ca
commit 4284d45553
12 changed files with 46 additions and 36 deletions

View File

@ -111,6 +111,7 @@ type Checker struct {
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
impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package
infoMap map[*Named]typeInfo // maps named types to their associated type info (for cycle detection)
// 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
@ -221,6 +222,7 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
version: version,
objMap: make(map[Object]*declInfo),
impMap: make(map[importKey]*Package),
infoMap: make(map[*Named]typeInfo),
}
}

View File

@ -477,7 +477,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
var rhs Type
check.later(func() {
check.validType(obj.typ, nil)
check.validType(obj.typ)
// If typ is local, an error was already reported where typ is specified/defined.
if check.isImportedConstraint(rhs) && !check.allowVersion(check.pkg, 1, 18) {
check.versionErrorf(tdecl.Type, "go1.18", "using type constraint %s", rhs)

View File

@ -12,7 +12,6 @@ import (
// A Named represents a named (defined) type.
type Named struct {
check *Checker
info typeInfo // for cycle detection
obj *TypeName // corresponding declared object for declared types; placeholder for instantiated types
orig *Named // original, uninstantiated type
fromRHS Type // type (on RHS of declaration) this *Named type is derived from (for cycle reporting)

View File

@ -31,7 +31,7 @@ func TestSizeof(t *testing.T) {
{Interface{}, 44, 88},
{Map{}, 16, 32},
{Chan{}, 12, 24},
{Named{}, 68, 128},
{Named{}, 64, 120},
{TypeParam{}, 28, 48},
{term{}, 12, 24},

View File

@ -487,7 +487,7 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def *
}
}
check.validType(inst, nil)
check.validType(inst)
})
return inst

View File

@ -4,14 +4,18 @@
package types2
type typeInfo uint
// validType verifies that the given type does not "expand" infinitely
// validType verifies that the given type does not "expand" indefinitely
// producing a cycle in the type graph. Cycles are detected by marking
// defined types.
// (Cycles involving alias types, as in "type A = [10]A" are detected
// earlier, via the objDecl cycle detection mechanism.)
func (check *Checker) validType(typ Type, path []Object) typeInfo {
func (check *Checker) validType(typ Type) {
check.validType0(typ, nil)
}
type typeInfo uint
func (check *Checker) validType0(typ Type, path []Object) typeInfo {
const (
unknown typeInfo = iota
marked
@ -21,25 +25,25 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
switch t := typ.(type) {
case *Array:
return check.validType(t.elem, path)
return check.validType0(t.elem, path)
case *Struct:
for _, f := range t.fields {
if check.validType(f.typ, path) == invalid {
if check.validType0(f.typ, path) == invalid {
return invalid
}
}
case *Union:
for _, t := range t.terms {
if check.validType(t.typ, path) == invalid {
if check.validType0(t.typ, path) == invalid {
return invalid
}
}
case *Interface:
for _, etyp := range t.embeddeds {
if check.validType(etyp, path) == invalid {
if check.validType0(etyp, path) == invalid {
return invalid
}
}
@ -65,14 +69,14 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
// don't report a 2nd error if we already know the type is invalid
// (e.g., if a cycle was detected earlier, via under).
if t.underlying == Typ[Invalid] {
t.info = invalid
check.infoMap[t] = invalid
return invalid
}
switch t.info {
switch check.infoMap[t] {
case unknown:
t.info = marked
t.info = check.validType(t.fromRHS, append(path, t.obj)) // only types of current package added to path
check.infoMap[t] = marked
check.infoMap[t] = check.validType0(t.fromRHS, append(path, t.obj)) // only types of current package added to path
case marked:
// cycle detected
for i, tn := range path {
@ -81,14 +85,14 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
}
if tn == t.obj {
check.cycleError(path[i:])
t.info = invalid
check.infoMap[t] = invalid
t.underlying = Typ[Invalid]
return invalid
}
}
panic("cycle start not found")
}
return t.info
return check.infoMap[t]
}
return valid

View File

@ -118,6 +118,7 @@ type Checker struct {
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
impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package
infoMap map[*Named]typeInfo // maps named types to their associated type info (for cycle detection)
// 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
@ -229,6 +230,7 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
version: version,
objMap: make(map[Object]*declInfo),
impMap: make(map[importKey]*Package),
infoMap: make(map[*Named]typeInfo),
}
}

View File

@ -530,7 +530,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
var rhs Type
check.later(func() {
check.validType(obj.typ, nil)
check.validType(obj.typ)
// If typ is local, an error was already reported where typ is specified/defined.
if check.isImportedConstraint(rhs) && !check.allowVersion(check.pkg, 1, 18) {
check.errorf(tdecl.Type, _UnsupportedFeature, "using type constraint %s requires go1.18 or later", rhs)

View File

@ -12,7 +12,6 @@ import (
// A Named represents a named (defined) type.
type Named struct {
check *Checker
info typeInfo // for cycle detection
obj *TypeName // corresponding declared object for declared types; placeholder for instantiated types
orig *Named // original, uninstantiated type
fromRHS Type // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)

View File

@ -30,7 +30,7 @@ func TestSizeof(t *testing.T) {
{Interface{}, 44, 88},
{Map{}, 16, 32},
{Chan{}, 12, 24},
{Named{}, 68, 128},
{Named{}, 64, 120},
{TypeParam{}, 28, 48},
{term{}, 12, 24},

View File

@ -472,7 +472,7 @@ func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *Named) (re
}
}
check.validType(inst, nil)
check.validType(inst)
})
return inst

View File

@ -4,14 +4,18 @@
package types
type typeInfo uint
// validType verifies that the given type does not "expand" infinitely
// validType verifies that the given type does not "expand" indefinitely
// producing a cycle in the type graph. Cycles are detected by marking
// defined types.
// (Cycles involving alias types, as in "type A = [10]A" are detected
// earlier, via the objDecl cycle detection mechanism.)
func (check *Checker) validType(typ Type, path []Object) typeInfo {
func (check *Checker) validType(typ Type) {
check.validType0(typ, nil)
}
type typeInfo uint
func (check *Checker) validType0(typ Type, path []Object) typeInfo {
const (
unknown typeInfo = iota
marked
@ -21,25 +25,25 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
switch t := typ.(type) {
case *Array:
return check.validType(t.elem, path)
return check.validType0(t.elem, path)
case *Struct:
for _, f := range t.fields {
if check.validType(f.typ, path) == invalid {
if check.validType0(f.typ, path) == invalid {
return invalid
}
}
case *Union:
for _, t := range t.terms {
if check.validType(t.typ, path) == invalid {
if check.validType0(t.typ, path) == invalid {
return invalid
}
}
case *Interface:
for _, etyp := range t.embeddeds {
if check.validType(etyp, path) == invalid {
if check.validType0(etyp, path) == invalid {
return invalid
}
}
@ -65,14 +69,14 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
// don't report a 2nd error if we already know the type is invalid
// (e.g., if a cycle was detected earlier, via under).
if t.underlying == Typ[Invalid] {
t.info = invalid
check.infoMap[t] = invalid
return invalid
}
switch t.info {
switch check.infoMap[t] {
case unknown:
t.info = marked
t.info = check.validType(t.fromRHS, append(path, t.obj)) // only types of current package added to path
check.infoMap[t] = marked
check.infoMap[t] = check.validType0(t.fromRHS, append(path, t.obj)) // only types of current package added to path
case marked:
// cycle detected
for i, tn := range path {
@ -81,14 +85,14 @@ func (check *Checker) validType(typ Type, path []Object) typeInfo {
}
if tn == t.obj {
check.cycleError(path[i:])
t.info = invalid
check.infoMap[t] = invalid
t.underlying = Typ[Invalid]
return invalid
}
}
panic("cycle start not found")
}
return t.info
return check.infoMap[t]
}
return valid