cmd/compile: instantiation cycle in closure function created by method of generic type
zhuah opened this issue · 5 comments
What version of Go are you using (go version
)?
$ go version go version devel go1.18-9d0ca262bb Wed Dec 15 00:33:55 2021 +0000 darwin/amd6
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env
What did you do?
https://go.dev/play/p/l9gzFUOBT5W?v=gotip
package main
import (
"fmt"
"strconv"
"strings"
)
type StringParser[T any] func(s string) (T, error)
func ParseList[T any](p StringParser[T], s string) ([]T, error) {
if s == "" {
return nil, nil
}
parts := strings.Split(s, ",")
vals := make([]T, len(parts))
for i, part := range parts {
v, err := p(part)
if err != nil {
return nil, err
}
vals[i] = v
}
return vals, nil
}
func (p StringParser[T]) ToListParser() StringParser[[]T] {
return func(s string) ([]T, error) {
return ParseList(p, s)
}
}
func ToListParser[T any](p StringParser[T]) StringParser[[]T] {
return func(s string) ([]T, error) {
return ParseList(p, s)
}
}
func main() {
p := StringParser[int](strconv.Atoi).ToListParser()
fmt.Println(p("1,2,3"))
}
ToListParser
is fine to compile,, but the compiler reports errors on StringParser.ToListParser
, :
./prog.go:9:19: instantiation cycle:
prog.go:27:54: T instantiated as []T
as i can see, []T
is depends on T
, rather than StringParser[T]
, there shouldn't be a cycle.
I don't know whether this is a bug, or go doesn't allow this usage ?
What did you expect to see?
What did you see instead?
I think the error is correct. StringParser[T]
's ToListParser
method has a return type of StringParser[[]T]
. This means if we want to instantiate StringParser[int]
, then we'll also have to instantiate StringParser[[]int]
too; which then means we'll also have to instantiate StringParser[[][]int]
, etc etc.
@mdempsky thank you, i got it.
it' may better be reported as infinite instantiation instead of cycle ?
which then means we'll also have to instantiate
StringParser[[][]int]
,
Could you explain how this follows from the previous part? There are no method calls for StringParser[[]int]
, so it looks like there should never be any need to consider StringParser[[][]int]
.
Similar code in (say) Rust compiles just fine:
struct StringParser<T> {
f: Box<dyn Fn(String) -> Option<T>>
}
impl<T> StringParser<T> {
fn to_list_parser(self) -> StringParser<Vec<T>> {
todo!()
}
}
fn parse_list<T>(p: StringParser<T>, s: String) -> Option<Vec<T>> {
todo!()
}
fn main() {
let p = StringParser { f: Box::new(|s| str::parse::<i64>(&s).ok()) };
(p.to_list_parser().f)("1,2,3".to_string());
}
Could you explain how this follows from the previous part?
Go allows method calls to happen dynamically through interface assertions or reflection. As a result, if a type is instantiated, all of its methods must be instantiated too, even if not statically called.
There are certainly cases where we could determine this isn't actually needed, but that would complicate the language specification.