aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMax Neverov <neverov.max@gmail.com>2024-10-09 00:00:28 +0000
committerRobert Griesemer <gri@google.com>2024-10-22 22:20:29 +0000
commitbdc6dbbc6465bc617b778e6e3a1ae49daa35ea69 (patch)
treeb37627cf048bac43969a8f9e5de0f6067ef5c6a3 /src
parentd40ae5efc889bf4f0878eefe52694112e93a7542 (diff)
downloadgo-bdc6dbbc6465bc617b778e6e3a1ae49daa35ea69.tar.xz
go/types: improve recursive type error message
This change improves error message for recursive types. Currently, compilation of the [following program](https://go.dev/play/p/3ef84ObpzfG): package main type T1[T T2] struct{} type T2[T T1] struct{} returns an error: ./prog.go:3:6: invalid recursive type T1 ./prog.go:3:6: T1 refers to ./prog.go:4:6: T2 refers to ./prog.go:3:6: T1 With the patch applied the error message looks like: ./prog.go:3:6: invalid recursive type T1 ./prog.go:3:6: T1 refers to T2 ./prog.go:4:6: T2 refers to T1 Change-Id: Ic07cdffcffb1483c672b241fede4e694269b5b79 GitHub-Last-Rev: cd042fdc384cf5591b3258ca80fdc002bb8c5e0d GitHub-Pull-Request: golang/go#69574 Reviewed-on: https://go-review.googlesource.com/c/go/+/614084 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Tim King <taking@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/compile/internal/types2/decl.go17
-rw-r--r--src/cmd/compile/internal/types2/initorder.go10
-rw-r--r--src/go/types/decl.go18
-rw-r--r--src/go/types/initorder.go10
4 files changed, 23 insertions, 32 deletions
diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go
index 037155a6ca..b8e43231a1 100644
--- a/src/cmd/compile/internal/types2/decl.go
+++ b/src/cmd/compile/internal/types2/decl.go
@@ -334,17 +334,14 @@ func (check *Checker) cycleError(cycle []Object, start int) {
} else {
err.addf(obj, "invalid cycle in declaration of %s", objName)
}
- i := start
- for range cycle {
- err.addf(obj, "%s refers to", objName)
- i++
- if i >= len(cycle) {
- i = 0
- }
- obj = cycle[i]
- objName = name(obj)
+ // "cycle[i] refers to cycle[j]" for (i,j) = (s, s+1), (s+1, s+2), ..., (n, 0), (0,1), ..., (s-1,s) for len(cycle) = n, s = start.
+ n := len(cycle)
+ rotate := func(i int) int { return (i + start) % n }
+ for i := range n {
+ obj := cycle[rotate(i)]
+ next := cycle[rotate(i+1)]
+ err.addf(obj, "%s refers to %s", name(obj), name(next))
}
- err.addf(obj, "%s", objName)
err.report()
}
diff --git a/src/cmd/compile/internal/types2/initorder.go b/src/cmd/compile/internal/types2/initorder.go
index 09a53c98ef..9efbf7f69f 100644
--- a/src/cmd/compile/internal/types2/initorder.go
+++ b/src/cmd/compile/internal/types2/initorder.go
@@ -163,13 +163,11 @@ func (check *Checker) reportCycle(cycle []Object) {
err := check.newError(InvalidInitCycle)
err.addf(obj, "initialization cycle for %s", obj.Name())
- // subtle loop: print cycle[i] for i = 0, n-1, n-2, ... 1 for len(cycle) = n
- for i := len(cycle) - 1; i >= 0; i-- {
- err.addf(obj, "%s refers to", obj.Name())
- obj = cycle[i]
+ // "cycle[i] refers to cycle[j]" for (i,j) = (0, n-1), (n-1, n-2), ..., (1,0) for len(cycle) = n.
+ for j := len(cycle) - 1; j >= 0; j-- {
+ err.addf(obj, "%s refers to %s", obj.Name(), cycle[j].Name())
+ obj = cycle[j]
}
- // print cycle[0] again to close the cycle
- err.addf(obj, "%s", obj.Name())
err.report()
}
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index 4fd37df786..498eb16f84 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -335,17 +335,15 @@ func (check *Checker) cycleError(cycle []Object, start int) {
} else {
err.addf(obj, "invalid cycle in declaration of %s", objName)
}
- i := start
- for range cycle {
- err.addf(obj, "%s refers to", objName)
- i++
- if i >= len(cycle) {
- i = 0
- }
- obj = cycle[i]
- objName = name(obj)
+
+ // "cycle[i] refers to cycle[j]" for (i,j) = (s, s+1), (s+1, s+2), ..., (n, 0), (0,1), ..., (s-1,s) for len(cycle) = n, s = start.
+ n := len(cycle)
+ rotate := func(i int) int { return (i + start) % n }
+ for i := range n {
+ obj := cycle[rotate(i)]
+ next := cycle[rotate(i+1)]
+ err.addf(obj, "%s refers to %s", name(obj), name(next))
}
- err.addf(obj, "%s", objName)
err.report()
}
diff --git a/src/go/types/initorder.go b/src/go/types/initorder.go
index 077f2eccfe..682a63e2d7 100644
--- a/src/go/types/initorder.go
+++ b/src/go/types/initorder.go
@@ -166,13 +166,11 @@ func (check *Checker) reportCycle(cycle []Object) {
err := check.newError(InvalidInitCycle)
err.addf(obj, "initialization cycle for %s", obj.Name())
- // subtle loop: print cycle[i] for i = 0, n-1, n-2, ... 1 for len(cycle) = n
- for i := len(cycle) - 1; i >= 0; i-- {
- err.addf(obj, "%s refers to", obj.Name())
- obj = cycle[i]
+ // "cycle[i] refers to cycle[j]" for (i,j) = (0, n-1), (n-1, n-2), ..., (1,0) for len(cycle) = n.
+ for j := len(cycle) - 1; j >= 0; j-- {
+ err.addf(obj, "%s refers to %s", obj.Name(), cycle[j].Name())
+ obj = cycle[j]
}
- // print cycle[0] again to close the cycle
- err.addf(obj, "%s", obj.Name())
err.report()
}