1
0
mirror of https://github.com/golang/go synced 2024-11-23 04:10:04 -07:00

go/types, types2: reorder object processing to avoid broken aliases

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>
This commit is contained in:
Robert Griesemer 2022-01-21 09:05:51 -08:00
parent fe85c24431
commit 671e1150c6
9 changed files with 102 additions and 38 deletions

View File

@ -656,27 +656,33 @@ func (check *Checker) packageObjects() {
} }
} }
// We process non-alias declarations first, in order to avoid situations where // We process non-alias type declarations first, followed by alias declarations,
// the type of an alias declaration is needed before it is available. In general // and then everything else. This appears to avoid most situations where the type
// this is still not enough, as it is possible to create sufficiently convoluted // of an alias is needed before it is available.
// recursive type definitions that will cause a type alias to be needed before it // There may still be cases where this is not good enough (see also issue #25838).
// is available (see issue #25838 for examples). // In those cases Checker.ident will report an error ("invalid use of type alias").
// As an aside, the cmd/compiler suffers from the same problem (#25838).
var aliasList []*TypeName var aliasList []*TypeName
// phase 1 var othersList []Object // everything that's not a type
// phase 1: non-alias type declarations
for _, obj := range objList { for _, obj := range objList {
// If we have a type alias, collect it for the 2nd phase. if tname, _ := obj.(*TypeName); tname != nil {
if tname, _ := obj.(*TypeName); tname != nil && check.objMap[tname].tdecl.Alias { if check.objMap[tname].tdecl.Alias {
aliasList = append(aliasList, tname) aliasList = append(aliasList, tname)
continue } else {
}
check.objDecl(obj, nil) check.objDecl(obj, nil)
} }
// phase 2 } else {
othersList = append(othersList, obj)
}
}
// phase 2: alias type declarations
for _, obj := range aliasList { for _, obj := range aliasList {
check.objDecl(obj, nil) 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 // 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 // entries were deleted at the end of typeDecl because the respective receiver base

View File

@ -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
)

View File

@ -7,7 +7,7 @@ package p
var x T[B] var x T[B]
type T[_ any] struct{} type T[_ any] struct{}
type A T[B /* ERROR invalid use of type alias */ ] type A T[B]
type B = T[A] type B = T[A]
// test case from issue // test case from issue
@ -15,4 +15,4 @@ type B = T[A]
var v Box[Step] var v Box[Step]
type Box[T any] struct{} type Box[T any] struct{}
type Step = Box[StepBox] type Step = Box[StepBox]
type StepBox Box[Step /* ERROR invalid use of type alias */ ] type StepBox Box[Step]

View File

@ -11,7 +11,7 @@ type pair[S any] struct {}
var _ transform[step] var _ transform[step]
type box transform[step /* ERROR invalid use of type alias */ ] type box transform[step]
type step = pair[box] type step = pair[box]
// test case from issue // 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. // This line doesn't use the Step alias, and it compiles fine if you uncomment it.
var second Transform[Pair[Box, interface{}]] 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 // This line is the same as the `first` line, but it comes after the Box declaration and
// does not break the compile. // does not break the compile.

View File

@ -629,27 +629,33 @@ func (check *Checker) packageObjects() {
} }
} }
// We process non-alias declarations first, in order to avoid situations where // We process non-alias type declarations first, followed by alias declarations,
// the type of an alias declaration is needed before it is available. In general // and then everything else. This appears to avoid most situations where the type
// this is still not enough, as it is possible to create sufficiently convoluted // of an alias is needed before it is available.
// recursive type definitions that will cause a type alias to be needed before it // There may still be cases where this is not good enough (see also issue #25838).
// is available (see issue #25838 for examples). // In those cases Checker.ident will report an error ("invalid use of type alias").
// As an aside, the cmd/compiler suffers from the same problem (#25838).
var aliasList []*TypeName var aliasList []*TypeName
// phase 1 var othersList []Object // everything that's not a type
// phase 1: non-alias type declarations
for _, obj := range objList { for _, obj := range objList {
// If we have a type alias, collect it for the 2nd phase. if tname, _ := obj.(*TypeName); tname != nil {
if tname, _ := obj.(*TypeName); tname != nil && check.objMap[tname].tdecl.Assign.IsValid() { if check.objMap[tname].tdecl.Assign.IsValid() {
aliasList = append(aliasList, tname) aliasList = append(aliasList, tname)
continue } else {
}
check.objDecl(obj, nil) check.objDecl(obj, nil)
} }
// phase 2 } else {
othersList = append(othersList, obj)
}
}
// phase 2: alias type declarations
for _, obj := range aliasList { for _, obj := range aliasList {
check.objDecl(obj, nil) 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 // 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 // entries were deleted at the end of typeDecl because the respective receiver base

View File

@ -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
)

View File

@ -7,7 +7,7 @@ package p
var x T[B] var x T[B]
type T[_ any] struct{} type T[_ any] struct{}
type A T[B /* ERROR invalid use of type alias */ ] type A T[B]
type B = T[A] type B = T[A]
// test case from issue // test case from issue
@ -15,4 +15,4 @@ type B = T[A]
var v Box[Step] var v Box[Step]
type Box[T any] struct{} type Box[T any] struct{}
type Step = Box[StepBox] type Step = Box[StepBox]
type StepBox Box[Step /* ERROR invalid use of type alias */ ] type StepBox Box[Step]

View File

@ -11,7 +11,7 @@ type pair[S any] struct {}
var _ transform[step] var _ transform[step]
type box transform[step /* ERROR invalid use of type alias */ ] type box transform[step]
type step = pair[box] type step = pair[box]
// test case from issue // 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. // This line doesn't use the Step alias, and it compiles fine if you uncomment it.
var second Transform[Pair[Box, interface{}]] 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 // This line is the same as the `first` line, but it comes after the Box declaration and
// does not break the compile. // does not break the compile.

View File

@ -1,4 +1,4 @@
// errorcheck -G=3 // compile -G=3
// Copyright 2022 The Go Authors. All rights reserved. // Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
@ -9,5 +9,5 @@ package p
var x T[B] var x T[B]
type T[_ any] struct{} 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] type B = T[A]