]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types, types2: reorder object processing to avoid broken aliases
authorRobert Griesemer <gri@golang.org>
Fri, 21 Jan 2022 17:05:51 +0000 (09:05 -0800)
committerRobert Griesemer <gri@golang.org>
Mon, 24 Jan 2022 21:27:33 +0000 (21:27 +0000)
By processing non-alias type declarations before alias type declaration,
and those before everything else we can avoid some of the remaining
errors which are due to alias types not being available.

For #25838.
For #50259.
For #50276.
For #50729.

Change-Id: I233da2899a6d4954c239638624dfa8c08662e6b9
Reviewed-on: https://go-review.googlesource.com/c/go/+/380056
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>

src/cmd/compile/internal/types2/resolver.go
src/cmd/compile/internal/types2/testdata/fixedbugs/issue25838.go [new file with mode: 0644]
src/cmd/compile/internal/types2/testdata/fixedbugs/issue50259.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue50276.go2
src/go/types/resolver.go
src/go/types/testdata/fixedbugs/issue25838.go [new file with mode: 0644]
src/go/types/testdata/fixedbugs/issue50259.go2
src/go/types/testdata/fixedbugs/issue50276.go2
test/typeparam/issue50259.go

index a0cad404294c9e31ce69bf67e795f8600294fc14..05755f8cfd4aad01b75e72d0f2c68c375d3b1ca3 100644 (file)
@@ -656,27 +656,33 @@ func (check *Checker) packageObjects() {
                }
        }
 
-       // We process non-alias declarations first, in order to avoid situations where
-       // the type of an alias declaration is needed before it is available. In general
-       // this is still not enough, as it is possible to create sufficiently convoluted
-       // recursive type definitions that will cause a type alias to be needed before it
-       // is available (see issue #25838 for examples).
-       // As an aside, the cmd/compiler suffers from the same problem (#25838).
+       // We process non-alias type declarations first, followed by alias declarations,
+       // and then everything else. This appears to avoid most situations where the type
+       // of an alias is needed before it is available.
+       // There may still be cases where this is not good enough (see also issue #25838).
+       // In those cases Checker.ident will report an error ("invalid use of type alias").
        var aliasList []*TypeName
-       // phase 1
+       var othersList []Object // everything that's not a type
+       // phase 1: non-alias type declarations
        for _, obj := range objList {
-               // If we have a type alias, collect it for the 2nd phase.
-               if tname, _ := obj.(*TypeName); tname != nil && check.objMap[tname].tdecl.Alias {
-                       aliasList = append(aliasList, tname)
-                       continue
+               if tname, _ := obj.(*TypeName); tname != nil {
+                       if check.objMap[tname].tdecl.Alias {
+                               aliasList = append(aliasList, tname)
+                       } else {
+                               check.objDecl(obj, nil)
+                       }
+               } else {
+                       othersList = append(othersList, obj)
                }
-
-               check.objDecl(obj, nil)
        }
-       // phase 2
+       // phase 2: alias type declarations
        for _, obj := range aliasList {
                check.objDecl(obj, nil)
        }
+       // phase 3: all other declarations
+       for _, obj := range othersList {
+               check.objDecl(obj, nil)
+       }
 
        // At this point we may have a non-empty check.methods map; this means that not all
        // entries were deleted at the end of typeDecl because the respective receiver base
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue25838.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue25838.go
new file mode 100644 (file)
index 0000000..adbd138
--- /dev/null
@@ -0,0 +1,26 @@
+// 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 p
+
+// examples from the issue
+
+type (
+       e = f
+       f = g
+       g = []h
+       h i
+       i = j
+       j = e
+)
+
+type (
+       e1 = []h1
+       h1 e1
+)
+
+type (
+       P = *T
+       T P
+)
index a2e65c4c15d15e94eaa7dc34bdbc55964e1aed9f..6df8c64524324c68f800d3a412374bad6f4b7d18 100644 (file)
@@ -7,7 +7,7 @@ package p
 var x T[B]
 
 type T[_ any] struct{}
-type A T[B /* ERROR invalid use of type alias */ ]
+type A T[B]
 type B = T[A]
 
 // test case from issue
@@ -15,4 +15,4 @@ type B = T[A]
 var v Box[Step]
 type Box[T any] struct{}
 type Step = Box[StepBox]
-type StepBox Box[Step /* ERROR invalid use of type alias */ ]
+type StepBox Box[Step]
index 38a419d361ea48013f7a3a5e65ce1b95636b0117..97e477e6fa32108152e3658e0708fa2c537520d2 100644 (file)
@@ -11,7 +11,7 @@ type pair[S any] struct {}
 
 var _ transform[step]
 
-type box transform[step /* ERROR invalid use of type alias */ ]
+type box transform[step]
 type step = pair[box]
 
 // test case from issue
@@ -27,7 +27,7 @@ var first Transform[Step]
 // This line doesn't use the Step alias, and it compiles fine if you uncomment it.
 var second Transform[Pair[Box, interface{}]]
 
-type Box *Transform[Step /* ERROR invalid use of type alias */ ]
+type Box *Transform[Step]
 
 // This line is the same as the `first` line, but it comes after the Box declaration and
 // does not break the compile.
index 7a2dcbffbb17e172de42d720a1adb38f9d4bd253..9edf41bf3c2f5fc63f2c639c0fce9cfc3e4b19dc 100644 (file)
@@ -629,27 +629,33 @@ func (check *Checker) packageObjects() {
                }
        }
 
-       // We process non-alias declarations first, in order to avoid situations where
-       // the type of an alias declaration is needed before it is available. In general
-       // this is still not enough, as it is possible to create sufficiently convoluted
-       // recursive type definitions that will cause a type alias to be needed before it
-       // is available (see issue #25838 for examples).
-       // As an aside, the cmd/compiler suffers from the same problem (#25838).
+       // We process non-alias type declarations first, followed by alias declarations,
+       // and then everything else. This appears to avoid most situations where the type
+       // of an alias is needed before it is available.
+       // There may still be cases where this is not good enough (see also issue #25838).
+       // In those cases Checker.ident will report an error ("invalid use of type alias").
        var aliasList []*TypeName
-       // phase 1
+       var othersList []Object // everything that's not a type
+       // phase 1: non-alias type declarations
        for _, obj := range objList {
-               // If we have a type alias, collect it for the 2nd phase.
-               if tname, _ := obj.(*TypeName); tname != nil && check.objMap[tname].tdecl.Assign.IsValid() {
-                       aliasList = append(aliasList, tname)
-                       continue
+               if tname, _ := obj.(*TypeName); tname != nil {
+                       if check.objMap[tname].tdecl.Assign.IsValid() {
+                               aliasList = append(aliasList, tname)
+                       } else {
+                               check.objDecl(obj, nil)
+                       }
+               } else {
+                       othersList = append(othersList, obj)
                }
-
-               check.objDecl(obj, nil)
        }
-       // phase 2
+       // phase 2: alias type declarations
        for _, obj := range aliasList {
                check.objDecl(obj, nil)
        }
+       // phase 3: all other declarations
+       for _, obj := range othersList {
+               check.objDecl(obj, nil)
+       }
 
        // At this point we may have a non-empty check.methods map; this means that not all
        // entries were deleted at the end of typeDecl because the respective receiver base
diff --git a/src/go/types/testdata/fixedbugs/issue25838.go b/src/go/types/testdata/fixedbugs/issue25838.go
new file mode 100644 (file)
index 0000000..adbd138
--- /dev/null
@@ -0,0 +1,26 @@
+// 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 p
+
+// examples from the issue
+
+type (
+       e = f
+       f = g
+       g = []h
+       h i
+       i = j
+       j = e
+)
+
+type (
+       e1 = []h1
+       h1 e1
+)
+
+type (
+       P = *T
+       T P
+)
index a2e65c4c15d15e94eaa7dc34bdbc55964e1aed9f..6df8c64524324c68f800d3a412374bad6f4b7d18 100644 (file)
@@ -7,7 +7,7 @@ package p
 var x T[B]
 
 type T[_ any] struct{}
-type A T[B /* ERROR invalid use of type alias */ ]
+type A T[B]
 type B = T[A]
 
 // test case from issue
@@ -15,4 +15,4 @@ type B = T[A]
 var v Box[Step]
 type Box[T any] struct{}
 type Step = Box[StepBox]
-type StepBox Box[Step /* ERROR invalid use of type alias */ ]
+type StepBox Box[Step]
index 38a419d361ea48013f7a3a5e65ce1b95636b0117..97e477e6fa32108152e3658e0708fa2c537520d2 100644 (file)
@@ -11,7 +11,7 @@ type pair[S any] struct {}
 
 var _ transform[step]
 
-type box transform[step /* ERROR invalid use of type alias */ ]
+type box transform[step]
 type step = pair[box]
 
 // test case from issue
@@ -27,7 +27,7 @@ var first Transform[Step]
 // This line doesn't use the Step alias, and it compiles fine if you uncomment it.
 var second Transform[Pair[Box, interface{}]]
 
-type Box *Transform[Step /* ERROR invalid use of type alias */ ]
+type Box *Transform[Step]
 
 // This line is the same as the `first` line, but it comes after the Box declaration and
 // does not break the compile.
index 6987ebf790b957c42d888a94e0bc13593405c22c..59611ef3abee7c8ea7030f6b7952637e1f3bd829 100644 (file)
@@ -1,4 +1,4 @@
-// errorcheck -G=3
+// compile -G=3
 
 // Copyright 2022 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
@@ -9,5 +9,5 @@ package p
 var x T[B]
 
 type T[_ any] struct{}
-type A T[B] // ERROR "invalid use of type alias B in recursive type"
+type A T[B]
 type B = T[A]