]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: factor out inference cycle detector (cleanup)
authorRobert Griesemer <gri@golang.org>
Wed, 12 Apr 2023 20:16:44 +0000 (13:16 -0700)
committerGopher Robot <gobot@golang.org>
Thu, 13 Apr 2023 14:46:51 +0000 (14:46 +0000)
Change-Id: If3c6724497dfbe8611ffffb4735e47ddc53a742c
Reviewed-on: https://go-review.googlesource.com/c/go/+/484158
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>

src/cmd/compile/internal/types2/infer.go
src/go/types/infer.go

index ee2bcf79e4fcdcc4966f902a01066813d990fed2..62ee1f080d1c8d94cb2b037f90e0f1a31f8b688f 100644 (file)
@@ -334,19 +334,16 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
        // Generally, cycles may occur across multiple type parameters and inferred types
        // (for instance, consider [P interface{ *Q }, Q interface{ func(P) }]).
        // We eliminate cycles by walking the graphs for all type parameters. If a cycle
-       // through a type parameter is detected, cycleFinder nils out the respective type
-       // which kills the cycle; this also means that the respective type could not be
-       // inferred.
+       // through a type parameter is detected, killCycles nils out the respective type
+       // (in the inferred list) which kills the cycle, and marks the corresponding type
+       // parameter as not inferred.
        //
        // TODO(gri) If useful, we could report the respective cycle as an error. We don't
        //           do this now because type inference will fail anyway, and furthermore,
        //           constraints with cycles of this kind cannot currently be satisfied by
        //           any user-supplied type. But should that change, reporting an error
        //           would be wrong.
-       w := cycleFinder{tparams, inferred, make(map[Type]bool)}
-       for _, t := range tparams {
-               w.typ(t) // t != nil
-       }
+       killCycles(tparams, inferred)
 
        // dirty tracks the indices of all types that may still contain type parameters.
        // We know that nil type entries and entries corresponding to provided (non-nil)
@@ -601,6 +598,20 @@ func coreTerm(tpar *TypeParam) (*term, bool) {
        return nil, false
 }
 
+// killCycles walks through the given type parameters and looks for cycles
+// created by type parameters whose inferred types refer back to that type
+// parameter, either directly or indirectly. If such a cycle is detected,
+// it is killed by setting the corresponding inferred type to nil.
+//
+// TODO(gri) Determine if we can simply abort inference as soon as we have
+// found a single cycle.
+func killCycles(tparams []*TypeParam, inferred []Type) {
+       w := cycleFinder{tparams, inferred, make(map[Type]bool)}
+       for _, t := range tparams {
+               w.typ(t) // t != nil
+       }
+}
+
 type cycleFinder struct {
        tparams []*TypeParam
        types   []Type
@@ -610,7 +621,7 @@ type cycleFinder struct {
 func (w *cycleFinder) typ(typ Type) {
        if w.seen[typ] {
                // We have seen typ before. If it is one of the type parameters
-               // in tparams, iterative substitution will lead to infinite expansion.
+               // in w.tparams, iterative substitution will lead to infinite expansion.
                // Nil out the corresponding type which effectively kills the cycle.
                if tpar, _ := typ.(*TypeParam); tpar != nil {
                        if i := tparamIndex(w.tparams, tpar); i >= 0 {
index 0f8e7aeddcceab95861b283ea493dc3d8510b157..e1decc8ca1b4662a627f5d339621b19c44ca3362 100644 (file)
@@ -336,19 +336,16 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type,
        // Generally, cycles may occur across multiple type parameters and inferred types
        // (for instance, consider [P interface{ *Q }, Q interface{ func(P) }]).
        // We eliminate cycles by walking the graphs for all type parameters. If a cycle
-       // through a type parameter is detected, cycleFinder nils out the respective type
-       // which kills the cycle; this also means that the respective type could not be
-       // inferred.
+       // through a type parameter is detected, killCycles nils out the respective type
+       // (in the inferred list) which kills the cycle, and marks the corresponding type
+       // parameter as not inferred.
        //
        // TODO(gri) If useful, we could report the respective cycle as an error. We don't
        //           do this now because type inference will fail anyway, and furthermore,
        //           constraints with cycles of this kind cannot currently be satisfied by
        //           any user-supplied type. But should that change, reporting an error
        //           would be wrong.
-       w := cycleFinder{tparams, inferred, make(map[Type]bool)}
-       for _, t := range tparams {
-               w.typ(t) // t != nil
-       }
+       killCycles(tparams, inferred)
 
        // dirty tracks the indices of all types that may still contain type parameters.
        // We know that nil type entries and entries corresponding to provided (non-nil)
@@ -603,6 +600,20 @@ func coreTerm(tpar *TypeParam) (*term, bool) {
        return nil, false
 }
 
+// killCycles walks through the given type parameters and looks for cycles
+// created by type parameters whose inferred types refer back to that type
+// parameter, either directly or indirectly. If such a cycle is detected,
+// it is killed by setting the corresponding inferred type to nil.
+//
+// TODO(gri) Determine if we can simply abort inference as soon as we have
+// found a single cycle.
+func killCycles(tparams []*TypeParam, inferred []Type) {
+       w := cycleFinder{tparams, inferred, make(map[Type]bool)}
+       for _, t := range tparams {
+               w.typ(t) // t != nil
+       }
+}
+
 type cycleFinder struct {
        tparams []*TypeParam
        types   []Type
@@ -612,7 +623,7 @@ type cycleFinder struct {
 func (w *cycleFinder) typ(typ Type) {
        if w.seen[typ] {
                // We have seen typ before. If it is one of the type parameters
-               // in tparams, iterative substitution will lead to infinite expansion.
+               // in w.tparams, iterative substitution will lead to infinite expansion.
                // Nil out the corresponding type which effectively kills the cycle.
                if tpar, _ := typ.(*TypeParam); tpar != nil {
                        if i := tparamIndex(w.tparams, tpar); i >= 0 {