aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2022-01-14 17:01:43 -0800
committerRobert Griesemer <gri@golang.org>2022-01-24 21:27:13 +0000
commit0328b4f4cae6d2340ded9a7d2ce850b98d3bbcbe (patch)
tree6d3915da3daea83db8821aa6b9b0e92afc8e01eb
parentb850f3629fa9c2dfb6a94a3d0e472a0cc87b949c (diff)
downloadgo-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.go90
-rw-r--r--src/cmd/compile/internal/types2/validtype.go95
-rw-r--r--src/go/types/decl.go90
-rw-r--r--src/go/types/validtype.go95
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
+}