[go] go/types, types2: include type arguments in instantiated type cycle errors

2 views
Skip to first unread message

Gerrit Bot (Gerrit)

unread,
Mar 6, 2026, 11:38:09 PMMar 6
to goph...@pubsubhelper.golang.org, David Teather, golang-co...@googlegroups.com

Gerrit Bot has uploaded the change for review

Commit message

go/types, types2: include type arguments in instantiated type cycle errors

When reporting layout cycles involving instantiated generic types, the
error chain omitted type arguments, making the output confusing since
the generic type itself makes no reference to the recursive type.

Fixes #75022
Change-Id: Ibd2c22afd9dbab03ab1df80d41e50b8cc5514ff0
GitHub-Last-Rev: 3f00ca41863791a5aff5fa55534f47180f99cb68
GitHub-Pull-Request: golang/go#78006

Change diff

diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go
index 97d486c..dbea193 100644
--- a/src/cmd/compile/internal/types2/decl.go
+++ b/src/cmd/compile/internal/types2/decl.go
@@ -255,6 +255,9 @@
// may refer to imported types. See go.dev/issue/50788.
// TODO(gri) This functionality is used elsewhere. Factor it out.
name := func(obj Object) string {
+ if named := asNamed(obj.Type()); named != nil && named.inst != nil {
+ return TypeString(named, check.qualifier)
+ }
return packagePrefix(obj.Pkg(), check.qualifier) + obj.Name()
}

diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go
index e564fb3..fd3cb04 100644
--- a/src/cmd/compile/internal/types2/issues_test.go
+++ b/src/cmd/compile/internal/types2/issues_test.go
@@ -1187,3 +1187,43 @@
t.Fatalf("unexpected type for {x}: %s", tv.Type)
}
}
+
+func TestIssue75022(t *testing.T) {
+ // Issue 75022: error messages for instantiated layout cycles should name
+ // the instantiation (e.g. "t[a] refers to a", not "t refers to a").
+ tests := []struct {
+ name string
+ src string
+ want []string
+ }{
+ {
+ name: "direct self-instantiation",
+ src: `package p
+type t[p any] struct { f p }
+type a t[a]`,
+ want: []string{"invalid recursive type", "a refers to t[a]", "t[a] refers to a"},
+ },
+ {
+ name: "self-instantiation via alias",
+ src: `package p
+type t[p any] struct { f p }
+type b = a
+type a t[b]`,
+ want: []string{"invalid recursive type", "a refers to t[b]", "t[b] refers to a"},
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ _, err := typecheck(test.src, nil, nil)
+ if err == nil {
+ t.Fatal("expected type-check error, got none")
+ }
+ for _, w := range test.want {
+ if !strings.Contains(err.Error(), w) {
+ t.Errorf("error message missing %q\n\tgot: %s", w, err)
+ }
+ }
+ })
+ }
+}
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index 486ef6f..a6533e2 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -257,6 +257,9 @@
// may refer to imported types. See go.dev/issue/50788.
// TODO(gri) This functionality is used elsewhere. Factor it out.
name := func(obj Object) string {
+ if named := asNamed(obj.Type()); named != nil && named.inst != nil {
+ return TypeString(named, check.qualifier)
+ }
return packagePrefix(obj.Pkg(), check.qualifier) + obj.Name()
}

diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go
index 3649189..f4c80d6 100644
--- a/src/go/types/issues_test.go
+++ b/src/go/types/issues_test.go
@@ -1201,3 +1201,49 @@
t.Fatalf("unexpected type for {x}: %s", tv.Type)
}
}
+
+func TestIssue75022(t *testing.T) {
+ // Issue 75022: error messages for instantiated layout cycles should name
+ // the instantiation (e.g. "t[a] refers to a", not "t refers to a").
+ tests := []struct {
+ name string
+ src string
+ want []string
+ }{
+ {
+ name: "direct self-instantiation",
+ src: `package p
+type t[p any] struct { f p }
+type a t[a]`,
+ want: []string{"invalid recursive type", "a refers to t[a]", "t[a] refers to a"},
+ },
+ {
+ name: "self-instantiation via alias",
+ src: `package p
+type t[p any] struct { f p }
+type b = a
+type a t[b]`,
+ want: []string{"invalid recursive type", "a refers to t[b]", "t[b] refers to a"},
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ var got []string
+ conf := &Config{
+ Error: func(err error) { got = append(got, err.Error()) },
+ Importer: defaultImporter(token.NewFileSet()),
+ }
+ typecheck(test.src, conf, nil)
+ if len(got) == 0 {
+ t.Fatal("expected type-check error, got none")
+ }
+ fullErr := strings.Join(got, "\n")
+ for _, w := range test.want {
+ if !strings.Contains(fullErr, w) {
+ t.Errorf("error message missing %q\n\tgot: %s", w, fullErr)
+ }
+ }
+ })
+ }
+}
diff --git a/test/fixedbugs/issue50788.dir/b.go b/test/fixedbugs/issue50788.dir/b.go
index 97ae208..c41870d 100644
--- a/test/fixedbugs/issue50788.dir/b.go
+++ b/test/fixedbugs/issue50788.dir/b.go
@@ -6,4 +6,4 @@

import "./a"

-type T a.T[T] // ERROR "invalid recursive type T\n.*T refers to a\.T\n.*a\.T refers to T"
+type T a.T[T] // ERROR "invalid recursive type T\n.*T refers to a\.T\[T\]\n.*a\.T\[T\] refers to T"

Change information

Files:
  • M src/cmd/compile/internal/types2/decl.go
  • M src/cmd/compile/internal/types2/issues_test.go
  • M src/go/types/decl.go
  • M src/go/types/issues_test.go
  • M test/fixedbugs/issue50788.dir/b.go
Change size: M
Delta: 5 files changed, 93 insertions(+), 1 deletion(-)
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newchange
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: Ibd2c22afd9dbab03ab1df80d41e50b8cc5514ff0
Gerrit-Change-Number: 752580
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-CC: David Teather <contact.da...@gmail.com>
unsatisfied_requirement
satisfied_requirement
open
diffy

Gopher Robot (Gerrit)

unread,
Mar 6, 2026, 11:42:10 PMMar 6
to David Teather, Gerrit Bot, goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

Message from Gopher Robot

Congratulations on opening your first change. Thank you for your contribution!

Next steps:
A maintainer will review your change and provide feedback. See
https://go.dev/doc/contribute#review for more info and tips to get your
patch through code review.

Most changes in the Go project go through a few rounds of revision. This can be
surprising to people new to the project. The careful, iterative review process
is our way of helping mentor contributors and ensuring that their contributions
have a lasting impact.

During May-July and Nov-Jan the Go project is in a code freeze, during which
little code gets reviewed or merged. If a reviewer responds with a comment like
R=go1.11 or adds a tag like "wait-release", it means that this CL will be
reviewed as part of the next development cycle. See https://go.dev/s/release
for more details.

Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: Ibd2c22afd9dbab03ab1df80d41e50b8cc5514ff0
Gerrit-Change-Number: 752580
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-CC: David Teather <contact.da...@gmail.com>
Gerrit-CC: Gopher Robot <go...@golang.org>
Gerrit-Comment-Date: Sat, 07 Mar 2026 04:42:02 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: No
unsatisfied_requirement
satisfied_requirement
open
diffy

Mark Freeman (Gerrit)

unread,
Apr 28, 2026, 7:40:26 PM (10 hours ago) Apr 28
to David Teather, Gerrit Bot, goph...@pubsubhelper.golang.org, Robert Findley, Robert Griesemer, Gopher Robot, golang-co...@googlegroups.com
Attention needed from Robert Findley and Robert Griesemer

Mark Freeman added 2 comments

File src/cmd/compile/internal/types2/issues_test.go
Line 1191, Patchset 1 (Latest):func TestIssue75022(t *testing.T) {
Mark Freeman . unresolved

Let's put this test in `src/internal/types/testdata/fixedbugs/issue75022.go` and use the error matching syntax. That might look like:

```
// Copyright 2026 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

type T[P any] struct {
_ P
}

type A T[A] // ERROR "A refers to T[A]"

type B = C
type C T[B] // ERROR "C refers to T[B]"

type D = T[D] // ERROR "D refers to itself"

```

That way we can drop the other `issues_test`.

File test/fixedbugs/issue50788.dir/b.go
Line 9, Patchset 1 (Latest):type T a.T[T] // ERROR "invalid recursive type T\n.*T refers to a\.T\[T\]\n.*a\.T\[T\] refers to T"
Mark Freeman . unresolved

Could we add another case here passing an imported type as an argument?

```
type U a.T[a.T[U]] // ERROR "invalid recursive type U\n.*U refers to a\.T\[a\.T\[U\]\]\n.*a\.T\[a\.T\[U\]\] refers to a\.T\[U\]\n.*a\.T\[U\] refers to U"
```

Open in Gerrit

Related details

Attention is currently required from:
  • Robert Findley
  • Robert Griesemer
Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement is not satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-Change-Id: Ibd2c22afd9dbab03ab1df80d41e50b8cc5514ff0
    Gerrit-Change-Number: 752580
    Gerrit-PatchSet: 1
    Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
    Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
    Gerrit-CC: David Teather <contact.da...@gmail.com>
    Gerrit-CC: Gopher Robot <go...@golang.org>
    Gerrit-CC: Mark Freeman <markf...@google.com>
    Gerrit-CC: Robert Findley <rfin...@golang.org>
    Gerrit-Attention: Robert Griesemer <g...@golang.org>
    Gerrit-Attention: Robert Findley <rfin...@golang.org>
    Gerrit-Comment-Date: Tue, 28 Apr 2026 23:40:22 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    unsatisfied_requirement
    open
    diffy

    Gerrit Bot (Gerrit)

    unread,
    Apr 28, 2026, 9:54:14 PM (7 hours ago) Apr 28
    to David Teather, goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
    Attention needed from Robert Griesemer

    Gerrit Bot uploaded new patchset

    Gerrit Bot uploaded patch set #2 to this change.
    Open in Gerrit

    Related details

    Attention is currently required from:
    • Robert Griesemer
    Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement is not satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: newpatchset
    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-Change-Id: Ibd2c22afd9dbab03ab1df80d41e50b8cc5514ff0
    Gerrit-Change-Number: 752580
    Gerrit-PatchSet: 2
    unsatisfied_requirement
    open
    diffy

    David Teather (Gerrit)

    unread,
    Apr 28, 2026, 9:57:24 PM (7 hours ago) Apr 28
    to Gerrit Bot, goph...@pubsubhelper.golang.org, Robert Findley, Mark Freeman, Robert Griesemer, Gopher Robot, golang-co...@googlegroups.com
    Attention needed from Mark Freeman and Robert Griesemer

    David Teather added 2 comments

    File src/cmd/compile/internal/types2/issues_test.go
    Line 1191, Patchset 1:func TestIssue75022(t *testing.T) {
    Mark Freeman . unresolved

    Let's put this test in `src/internal/types/testdata/fixedbugs/issue75022.go` and use the error matching syntax. That might look like:

    ```
    // Copyright 2026 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

    type T[P any] struct {
    _ P
    }

    type A T[A] // ERROR "A refers to T[A]"

    type B = C
    type C T[B] // ERROR "C refers to T[B]"

    type D = T[D] // ERROR "D refers to itself"

    ```

    That way we can drop the other `issues_test`.

    David Teather

    I added some testcases here to the `src/internal/types/testdata/fixedbugs/issue75022.go`, but it seems that the test suite only keeps the primary error for `go/types` see in `testFiles()` [source](https://github.com/golang/go/blob/master/src/go/types/check_test.go#L167-L171) which means I can't test the full "refers to T[A] chain".

    From my understanding the `go/test/fixedbugs/issue50788.dir` (which has the full error traces) only tests the `types2` package.

    So to keep test coverage, I kept the `TestIssue75022()` in `src/go/types/issues_test.go` for coverage on `go/types`. If there's a better way to keep the coverage let me know. Thanks!

    File test/fixedbugs/issue50788.dir/b.go
    Line 9, Patchset 1:type T a.T[T] // ERROR "invalid recursive type T\n.*T refers to a\.T\[T\]\n.*a\.T\[T\] refers to T"
    Mark Freeman . resolved

    Could we add another case here passing an imported type as an argument?

    ```
    type U a.T[a.T[U]] // ERROR "invalid recursive type U\n.*U refers to a\.T\[a\.T\[U\]\]\n.*a\.T\[a\.T\[U\]\] refers to a\.T\[U\]\n.*a\.T\[U\] refers to U"
    ```

    David Teather

    I have added in this test and a few more that reflect the original unit test `Test75022()` functionality

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Mark Freeman
    • Robert Griesemer
    Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement is not satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-Change-Id: Ibd2c22afd9dbab03ab1df80d41e50b8cc5514ff0
    Gerrit-Change-Number: 752580
    Gerrit-PatchSet: 2
    Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
    Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
    Gerrit-CC: David Teather <contact.da...@gmail.com>
    Gerrit-CC: Gopher Robot <go...@golang.org>
    Gerrit-CC: Mark Freeman <markf...@google.com>
    Gerrit-CC: Robert Findley <rfin...@golang.org>
    Gerrit-Attention: Robert Griesemer <g...@golang.org>
    Gerrit-Attention: Mark Freeman <markf...@google.com>
    Gerrit-Comment-Date: Wed, 29 Apr 2026 01:57:19 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Mark Freeman <markf...@google.com>
    unsatisfied_requirement
    open
    diffy
    Reply all
    Reply to author
    Forward
    0 new messages