Any time you have to deal with "plumbing" (for lack of a better term), Go makes the job absolutely trivial. In a sense, I think it's a shame that Go has made it's name as "a language for concurrency" because I think that the concurrency features are in fact supporting features of the aforementioned usage: streaming dumb bytes left and right. Otherwise stated, Go is concurrent because concurrency helps ship bytes; it's not concurrent for the sake of solving general concurrency problems.
With that in mind, I'm still not clear on what makes Go's type system sub-par. I keep hearing this meme repeated, and although I know next to nothing about type theory, I have always found Go's type system to provide just enough scaffolding for byte-delivery pipework. Beyond that it just gets out of the way.
Consider this: Go is formally a static language, but it behaves (in the sense of how it's used in a workflow) in a manner closer to a dynamic language (compile time is equivalent to ipython's warm-up time, go playground makes testing snippets interactively very simple, etc). I think it's an error to compare Go with C. Go feels more like Python with concurrency and type safety.
So again: I understand the use-case for generics, but viewed through the lens of "nailing" the problem of shipping bytes (which again, I contend is Go's purpose), I fail to understand why Go's type system is repeatedly labeled as lacking. Go isn't Rust. It's not solving the same problems as Rust. From there, what is it that makes Go's type system shitty? I would describe it as "just enough type system".
Other than generics, what is it that people are expecting this damn thing to do? I'm very much open to being wrong (especially since this would inevitably introduce me to some interesting languages), but I can't quite conceptualize what people have in mind when they complain about Go's type system.