When it fires. A type’s own Equal method calls a generic function or
method, and the call’s type argument for a type parameter constrained by
comparable (or by a Go interface that embeds it) is that same type, or a
type that holds it by value: Option[Point], a tuple, a List[Point]. ==
on such a type parameter calls the value’s Equal, so Equal and the helper
would call each other until the stack runs out.
Equal reaches such a call through a method too: a method of a generic
type is compiled with the type’s comparable type parameter, so
Pair(p, o).Same() for struct Pair[T comparable] is the call same(p, o)
is. And it reaches one through the functions and methods of the same file
that it calls: eq(p, o) for func eq(a Point, b Point) bool = same(a, b).
The error then points at the call in Equal and names the path to the
generic call.
Minimal repro.
package main
func same[T comparable](a T, b T) bool = a == b
struct Point(x int, label string)
func (p Point) Equal(o Point) bool = same(p.label, o.label) && same(p, o)
func main() {
Println(Point(1, "a") == Point(2, "a"))
}
Error output.
error[GALA-E0108]: Point's own Equal calls same with T = Point, a comparable type parameter: == on T there calls Point's Equal, so the two call each other forever
--> main.gala:7:69
|
7 | func (p Point) Equal(o Point) bool = same(p.label, o.label) && same(p, o)
| ^^^^ compare Point's fields instead
|
= hint: compare Point's fields instead
Fix. Compare the fields, with the helper or with ==:
package main
func same[T comparable](a T, b T) bool = a == b
struct Point(x int, label string)
func (p Point) Equal(o Point) bool = same(p.label, o.label) && same(p.x, o.x)
func main() {
Println(Point(1, "a") == Point(2, "a"))
}
== written in Equal itself on the type’s own values is Go’s ==, so
p == o there does not recurse either.
Rationale. A generic function is compiled once for all its callers, so
== in it cannot be Go’s == for one caller and Equal for the others.
The check follows the functions and methods of the file that Equal calls.
It does not see a call made through a function value, or one made by a
function or method declared in another file or package; such a call recurses
the same way.