diff options
author | Robert Griesemer <gri@golang.org> | 2022-01-14 17:01:43 -0800 |
---|---|---|
committer | Robert Griesemer <gri@golang.org> | 2022-01-24 21:27:13 +0000 |
commit | 0328b4f4cae6d2340ded9a7d2ce850b98d3bbcbe (patch) | |
tree | 6d3915da3daea83db8821aa6b9b0e92afc8e01eb | |
parent | b850f3629fa9c2dfb6a94a3d0e472a0cc87b949c (diff) | |
download | go-0328b4f4cae6d2340ded9a7d2ce850b98d3bbcbe.tar.gz go-0328b4f4cae6d2340ded9a7d2ce850b98d3bbcbe.zip |
go/types, types2: move validType code into its own file
The validType check is independent of the work of declaring objects.
Move it into a separate file for better separation of concerns and
code organization.
No other changes - this is purely a code move.
Preparation for fixing issue #48962.
Change-Id: Ib08db2d009c4890882d0978b278e965ca3078851
Reviewed-on: https://go-review.googlesource.com/c/go/+/378674
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>
-rw-r--r-- | src/cmd/compile/internal/types2/decl.go | 90 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/validtype.go | 95 | ||||
-rw-r--r-- | src/go/types/decl.go | 90 | ||||
-rw-r--r-- | src/go/types/validtype.go | 95 |
4 files changed, 190 insertions, 180 deletions
diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index d61d2a8b0d..22cea584d4 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -304,96 +304,6 @@ loop: return false } -type typeInfo uint - -// validType verifies that the given type does not "expand" infinitely -// 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 { - const ( - unknown typeInfo = iota - marked - valid - invalid - ) - - switch t := typ.(type) { - case *Array: - return check.validType(t.elem, path) - - case *Struct: - for _, f := range t.fields { - if check.validType(f.typ, path) == invalid { - return invalid - } - } - - case *Union: - for _, t := range t.terms { - if check.validType(t.typ, path) == invalid { - return invalid - } - } - - case *Interface: - for _, etyp := range t.embeddeds { - if check.validType(etyp, path) == invalid { - return invalid - } - } - - case *Named: - // If t is parameterized, we should be considering the instantiated (expanded) - // form of t, but in general we can't with this algorithm: if t is an invalid - // type it may be so because it infinitely expands through a type parameter. - // Instantiating such a type would lead to an infinite sequence of instantiations. - // In general, we need "type flow analysis" to recognize those cases. - // Example: type A[T any] struct{ x A[*T] } (issue #48951) - // In this algorithm we always only consider the original, uninstantiated type. - // This won't recognize some invalid cases with parameterized types, but it - // will terminate. - t = t.orig - - // 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) - if t.obj.pkg != check.pkg { - return valid - } - - // 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 - return invalid - } - - switch t.info { - case unknown: - t.info = marked - t.info = check.validType(t.fromRHS, append(path, t.obj)) // only types of current package added to path - case marked: - // cycle detected - for i, tn := range path { - if t.obj.pkg != check.pkg { - panic("type cycle via package-external type") - } - if tn == t.obj { - check.cycleError(path[i:]) - t.info = invalid - t.underlying = Typ[Invalid] - return invalid - } - } - panic("cycle start not found") - } - return t.info - } - - return valid -} - // cycleError reports a declaration cycle starting with // the object in cycle that is "first" in the source. func (check *Checker) cycleError(cycle []Object) { diff --git a/src/cmd/compile/internal/types2/validtype.go b/src/cmd/compile/internal/types2/validtype.go new file mode 100644 index 0000000000..24d65e2c24 --- /dev/null +++ b/src/cmd/compile/internal/types2/validtype.go @@ -0,0 +1,95 @@ +// Copyright 2022 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. + +package types2 + +type typeInfo uint + +// validType verifies that the given type does not "expand" infinitely +// 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 { + const ( + unknown typeInfo = iota + marked + valid + invalid + ) + + switch t := typ.(type) { + case *Array: + return check.validType(t.elem, path) + + case *Struct: + for _, f := range t.fields { + if check.validType(f.typ, path) == invalid { + return invalid + } + } + + case *Union: + for _, t := range t.terms { + if check.validType(t.typ, path) == invalid { + return invalid + } + } + + case *Interface: + for _, etyp := range t.embeddeds { + if check.validType(etyp, path) == invalid { + return invalid + } + } + + case *Named: + // If t is parameterized, we should be considering the instantiated (expanded) + // form of t, but in general we can't with this algorithm: if t is an invalid + // type it may be so because it infinitely expands through a type parameter. + // Instantiating such a type would lead to an infinite sequence of instantiations. + // In general, we need "type flow analysis" to recognize those cases. + // Example: type A[T any] struct{ x A[*T] } (issue #48951) + // In this algorithm we always only consider the original, uninstantiated type. + // This won't recognize some invalid cases with parameterized types, but it + // will terminate. + t = t.orig + + // 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) + if t.obj.pkg != check.pkg { + return valid + } + + // 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 + return invalid + } + + switch t.info { + case unknown: + t.info = marked + t.info = check.validType(t.fromRHS, append(path, t.obj)) // only types of current package added to path + case marked: + // cycle detected + for i, tn := range path { + if t.obj.pkg != check.pkg { + panic("type cycle via package-external type") + } + if tn == t.obj { + check.cycleError(path[i:]) + t.info = invalid + t.underlying = Typ[Invalid] + return invalid + } + } + panic("cycle start not found") + } + return t.info + } + + return valid +} diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 02af0d5f3e..5b54465f18 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -303,96 +303,6 @@ loop: return false } -type typeInfo uint - -// validType verifies that the given type does not "expand" infinitely -// 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 { - const ( - unknown typeInfo = iota - marked - valid - invalid - ) - - switch t := typ.(type) { - case *Array: - return check.validType(t.elem, path) - - case *Struct: - for _, f := range t.fields { - if check.validType(f.typ, path) == invalid { - return invalid - } - } - - case *Union: - for _, t := range t.terms { - if check.validType(t.typ, path) == invalid { - return invalid - } - } - - case *Interface: - for _, etyp := range t.embeddeds { - if check.validType(etyp, path) == invalid { - return invalid - } - } - - case *Named: - // If t is parameterized, we should be considering the instantiated (expanded) - // form of t, but in general we can't with this algorithm: if t is an invalid - // type it may be so because it infinitely expands through a type parameter. - // Instantiating such a type would lead to an infinite sequence of instantiations. - // In general, we need "type flow analysis" to recognize those cases. - // Example: type A[T any] struct{ x A[*T] } (issue #48951) - // In this algorithm we always only consider the original, uninstantiated type. - // This won't recognize some invalid cases with parameterized types, but it - // will terminate. - t = t.orig - - // 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) - if t.obj.pkg != check.pkg { - return valid - } - - // 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 - return invalid - } - - switch t.info { - case unknown: - t.info = marked - t.info = check.validType(t.fromRHS, append(path, t.obj)) // only types of current package added to path - case marked: - // cycle detected - for i, tn := range path { - if t.obj.pkg != check.pkg { - panic("type cycle via package-external type") - } - if tn == t.obj { - check.cycleError(path[i:]) - t.info = invalid - t.underlying = Typ[Invalid] - return invalid - } - } - panic("cycle start not found") - } - return t.info - } - - return valid -} - // cycleError reports a declaration cycle starting with // the object in cycle that is "first" in the source. func (check *Checker) cycleError(cycle []Object) { diff --git a/src/go/types/validtype.go b/src/go/types/validtype.go new file mode 100644 index 0000000000..8972a7ad85 --- /dev/null +++ b/src/go/types/validtype.go @@ -0,0 +1,95 @@ +// Copyright 2022 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. + +package types + +type typeInfo uint + +// validType verifies that the given type does not "expand" infinitely +// 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 { + const ( + unknown typeInfo = iota + marked + valid + invalid + ) + + switch t := typ.(type) { + case *Array: + return check.validType(t.elem, path) + + case *Struct: + for _, f := range t.fields { + if check.validType(f.typ, path) == invalid { + return invalid + } + } + + case *Union: + for _, t := range t.terms { + if check.validType(t.typ, path) == invalid { + return invalid + } + } + + case *Interface: + for _, etyp := range t.embeddeds { + if check.validType(etyp, path) == invalid { + return invalid + } + } + + case *Named: + // If t is parameterized, we should be considering the instantiated (expanded) + // form of t, but in general we can't with this algorithm: if t is an invalid + // type it may be so because it infinitely expands through a type parameter. + // Instantiating such a type would lead to an infinite sequence of instantiations. + // In general, we need "type flow analysis" to recognize those cases. + // Example: type A[T any] struct{ x A[*T] } (issue #48951) + // In this algorithm we always only consider the original, uninstantiated type. + // This won't recognize some invalid cases with parameterized types, but it + // will terminate. + t = t.orig + + // 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) + if t.obj.pkg != check.pkg { + return valid + } + + // 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 + return invalid + } + + switch t.info { + case unknown: + t.info = marked + t.info = check.validType(t.fromRHS, append(path, t.obj)) // only types of current package added to path + case marked: + // cycle detected + for i, tn := range path { + if t.obj.pkg != check.pkg { + panic("type cycle via package-external type") + } + if tn == t.obj { + check.cycleError(path[i:]) + t.info = invalid + t.underlying = Typ[Invalid] + return invalid + } + } + panic("cycle start not found") + } + return t.info + } + + return valid +} |