golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.84k stars 17.65k forks source link

cmd/compile: internal compiler error using type parameters #48016

Closed dsnet closed 3 years ago

dsnet commented 3 years ago

Using go version devel go1.18-2c60a99f72 Fri Aug 27 05:13:44 2021 +0000 linux/amd64

When trying to compile some generic code, I get:

./arshal_funcs_generic.go:18:44: internal compiler error: found illegal assignment .shape.string -> json.T₁; 

goroutine 1 [running]:
runtime/debug.Stack()
    /usr/local/go.tip/src/runtime/debug/stack.go:24 +0x65
cmd/compile/internal/base.FatalfAt({0x0, 0x0}, {0xd0b468, 0x27}, {0xc0008cdb60, 0x3, 0x3})
    /usr/local/go.tip/src/cmd/compile/internal/base/print.go:227 +0x154
cmd/compile/internal/base.Fatalf(...)
    /usr/local/go.tip/src/cmd/compile/internal/base/print.go:196
cmd/compile/internal/noder.assignconvfn({0xe64da8, 0xc000ef2960}, 0xc000d01260)
    /usr/local/go.tip/src/cmd/compile/internal/noder/transform.go:413 +0x167
cmd/compile/internal/noder.typecheckaste(0x90, {0xc000ef6990, 0xc000ef6990}, 0x0, 0xc000ef2960, {0xc000ef4540, 0x1, 0x5b46f2}, 0x0)
    /usr/local/go.tip/src/cmd/compile/internal/noder/transform.go:465 +0x186
cmd/compile/internal/noder.transformCall(0xc000ef6990)
    /usr/local/go.tip/src/cmd/compile/internal/noder/transform.go:160 +0x199
cmd/compile/internal/noder.(*subster).node.func1({0xe645d8, 0xc000917050})
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:1045 +0xebd
cmd/compile/internal/ir.editNodes({0xc000ef4530, 0x1, 0xccfd80}, 0xc000efe9a8)
    /usr/local/go.tip/src/cmd/compile/internal/ir/node_gen.go:1521 +0x74
cmd/compile/internal/ir.(*AssignListStmt).editChildren(0xc000ef26c0, 0xe64060)
    /usr/local/go.tip/src/cmd/compile/internal/ir/node_gen.go:108 +0x6e
cmd/compile/internal/ir.EditChildren(...)
    /usr/local/go.tip/src/cmd/compile/internal/ir/visit.go:185
cmd/compile/internal/noder.(*subster).node.func1({0xe64060, 0xc00076efc0})
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:903 +0x423
cmd/compile/internal/noder.(*subster).node(0xc000e97600, {0xe64060, 0xc00076efc0})
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:1208 +0xa5
cmd/compile/internal/noder.(*subster).namelist(0xc000efd2c0, {0xc00087bc00, 0x7, 0xc0008ce2a0})
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:1284 +0xb7
cmd/compile/internal/noder.(*subster).node.func1({0xe64830, 0xc000951f40})
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:1082 +0x1173
cmd/compile/internal/ir.(*ConvExpr).editChildren(0xc000efd220, 0xc000efe990)
    /usr/local/go.tip/src/cmd/compile/internal/ir/node_gen.go:445 +0x58
cmd/compile/internal/ir.EditChildren(...)
    /usr/local/go.tip/src/cmd/compile/internal/ir/visit.go:185
cmd/compile/internal/noder.(*subster).node.func1({0xe64b50, 0xc00095b180})
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:903 +0x423
cmd/compile/internal/ir.(*StructKeyExpr).editChildren(0xc000efd1d0, 0xc000efe990)
    /usr/local/go.tip/src/cmd/compile/internal/ir/node_gen.go:1272 +0x58
cmd/compile/internal/ir.EditChildren(...)
    /usr/local/go.tip/src/cmd/compile/internal/ir/visit.go:185
cmd/compile/internal/noder.(*subster).node.func1({0xe66770, 0xc00095b130})
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:903 +0x423
cmd/compile/internal/ir.editNodes({0xc000eee7c0, 0x2, 0x6234ef}, 0xc000efe990)
    /usr/local/go.tip/src/cmd/compile/internal/ir/node_gen.go:1521 +0x74
cmd/compile/internal/ir.(*CompLitExpr).editChildren(0xc000e97680, 0xc000efe990)
    /usr/local/go.tip/src/cmd/compile/internal/ir/node_gen.go:405 +0xc9
cmd/compile/internal/ir.EditChildren(...)
    /usr/local/go.tip/src/cmd/compile/internal/ir/visit.go:185
cmd/compile/internal/noder.(*subster).node.func1({0xe649c0, 0xc0008c1380})
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:903 +0x423
cmd/compile/internal/ir.editNodes({0xc000ef4500, 0x1, 0xcd1880}, 0xc000efe990)
    /usr/local/go.tip/src/cmd/compile/internal/ir/node_gen.go:1521 +0x74
cmd/compile/internal/ir.(*ReturnStmt).editChildren(0xc000efd130, 0xe66130)
    /usr/local/go.tip/src/cmd/compile/internal/ir/node_gen.go:1056 +0x53
cmd/compile/internal/ir.EditChildren(...)
    /usr/local/go.tip/src/cmd/compile/internal/ir/visit.go:185
cmd/compile/internal/noder.(*subster).node.func1({0xe66130, 0xc00095b1d0})
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:903 +0x423
cmd/compile/internal/noder.(*subster).node(0xc000e97600, {0xe66130, 0xc00095b1d0})
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:1208 +0xa5
cmd/compile/internal/noder.(*subster).list(0xc000d05fe0, {0xc00094dda0, 0x2, 0xc0000bc5f0})
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:1296 +0x8e
cmd/compile/internal/noder.(*irgen).genericSubst(0xc00042a600, 0xc000efcb40, 0xc000cfed00, {0xc000d05f70, 0x1, 0x1}, 0x0, 0xc0007697c0)
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:722 +0xcc6
cmd/compile/internal/noder.(*irgen).getInstantiation(0xc00042a600, 0xc000cfed00, {0xc000d05f68, 0x1, 0x1}, 0x80)
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:608 +0x33d
cmd/compile/internal/noder.(*irgen).stencil.func1({0xe645d8, 0xc0009173b0})
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:109 +0x2df
cmd/compile/internal/ir.Visit.func1({0xe645d8, 0xc0009173b0})
    /usr/local/go.tip/src/cmd/compile/internal/ir/visit.go:105 +0x30
cmd/compile/internal/ir.(*ConvExpr).doChildren(0xc00095b770, 0xc000efe798)
    /usr/local/go.tip/src/cmd/compile/internal/ir/node_gen.go:437 +0x62
cmd/compile/internal/ir.DoChildren(...)
    /usr/local/go.tip/src/cmd/compile/internal/ir/visit.go:94
cmd/compile/internal/ir.Visit.func1({0xe64b50, 0xc00095b770})
    /usr/local/go.tip/src/cmd/compile/internal/ir/visit.go:106 +0x57
cmd/compile/internal/ir.doNodes({0xc0004b70b0, 0x1, 0xc000d022c0}, 0xc000efe798)
    /usr/local/go.tip/src/cmd/compile/internal/ir/node_gen.go:1512 +0x67
cmd/compile/internal/ir.(*CallExpr).doChildren(0xc000917440, 0xc000efe798)
    /usr/local/go.tip/src/cmd/compile/internal/ir/node_gen.go:263 +0x85
cmd/compile/internal/ir.DoChildren(...)
    /usr/local/go.tip/src/cmd/compile/internal/ir/visit.go:94
cmd/compile/internal/ir.Visit.func1({0xe645d8, 0xc000917440})
    /usr/local/go.tip/src/cmd/compile/internal/ir/visit.go:106 +0x57
cmd/compile/internal/ir.doNodes({0xc0004b7310, 0x1, 0x0}, 0xc000efe798)
    /usr/local/go.tip/src/cmd/compile/internal/ir/node_gen.go:1512 +0x67
cmd/compile/internal/ir.(*Func).doChildren(0xe64f38, 0xc000d022c0)
    /usr/local/go.tip/src/cmd/compile/internal/ir/func.go:152 +0x2e
cmd/compile/internal/ir.DoChildren(...)
    /usr/local/go.tip/src/cmd/compile/internal/ir/visit.go:94
cmd/compile/internal/ir.Visit.func1({0xe64f38, 0xc000d022c0})
    /usr/local/go.tip/src/cmd/compile/internal/ir/visit.go:106 +0x57
cmd/compile/internal/ir.Visit({0xe64f38, 0xc000d022c0}, 0xc000769780)
    /usr/local/go.tip/src/cmd/compile/internal/ir/visit.go:108 +0xb8
cmd/compile/internal/noder.(*irgen).stencil(0xc00042a600)
    /usr/local/go.tip/src/cmd/compile/internal/noder/stencil.go:91 +0x26a
cmd/compile/internal/noder.(*irgen).generate(0xc00042a600, {0xc0000b7a40, 0xc, 0x0})
    /usr/local/go.tip/src/cmd/compile/internal/noder/irgen.go:294 +0x2d8
cmd/compile/internal/noder.check2({0xc0000b7a40, 0xc, 0xc})
    /usr/local/go.tip/src/cmd/compile/internal/noder/irgen.go:92 +0x177
cmd/compile/internal/noder.LoadPackage({0xc000082aa0, 0xc, 0x0})
    /usr/local/go.tip/src/cmd/compile/internal/noder/noder.go:90 +0x335
cmd/compile/internal/gc.Main(0xd1e6d0)
    /usr/local/go.tip/src/cmd/compile/internal/gc/main.go:190 +0xaf3
main.main()
    /usr/local/go.tip/src/cmd/compile/main.go:55 +0xdd

Reproduction:

$ git clone https://github.com/go-json-experiment/json.git
$ cd json
$ git checkout origin/generics-bug
$ go build

\cc @mdempsky @ianlancetaylor @griesemer

ALTree commented 3 years ago

If you have closure variables in a range statement, this may be #47676.

dsnet commented 3 years ago

The relevant generic code is:

func MarshalFuncV1[T any](fn func(T) ([]byte, error)) typedMarshaler {
    t := reflect.TypeOf((*T)(nil)).Elem()
    return typedMarshaler{
        typ: t,
        fnc: func(mo MarshalOptions, enc *Encoder, va addressableValue) error {
            val, err := fn(va.Convert(t).Interface().(T))
            if err != nil {
                if err == SkipFunc {
                    err = errors.New("marshal function of type func(T) ([]byte, error) cannot be skipped")
                }
                // TODO: Avoid wrapping semantic errors.
                return &SemanticError{action: "marshal", GoType: t, Err: err}
            }
            if err := enc.WriteValue(val); err != nil {
                // TODO: Avoid wrapping semantic or I/O errors.
                return &SemanticError{action: "marshal", JSONKind: RawValue(val).Kind(), GoType: t, Err: err}
            }
            return nil
        },
    }
}

func init() {
    NewMarshalers(
        MarshalFuncV1(func(string) ([]byte, error) {
            return []byte("hello"), nil
        }),
    )
}

Closures are involved, but no range statements. Interestingly the compiler or crashes when calling MarshalFuncV1 in the init function.

mdempsky commented 3 years ago

Works with GOEXPERIMENT=unified.

dsnet commented 3 years ago

For those who aren't involved with generics work, what's the significance of GOEXPERIMENT=unified?

mdempsky commented 3 years ago

cmd/compile currently has three frontends: -G=0 is the legacy, pre-generics frontend; -G=3 is the first generics-aware frontend that's currently enabled by default and has some support for stenciling; GOEXPERIMENT=unified is the second generics-aware frontend that I wrote to minimize complexity and hopefully avoid compiler errors.

dsnet commented 3 years ago

GOEXPERIMENT=unified is the second generics-aware frontend that I wrote to minimize complexity and hopefully avoid compiler errors.

Thanks for the explanation. Well, this seems like an example bug that favors your experiment :smile:

danscales commented 3 years ago

Here's a fairly minimized case:

package main

func test1[T any](fn func(T) int) {
    fn1 := func() {
        var i interface{}
        val := fn(i.(T))
        println(val)
    }
    println(fn1)
}

func main() {
    test1(func(string) int {
        return 5
    })
}

The key is the function call with an arg that is the result of a '.(T)' type assert, but all inside a closure. Things work fine if the function call is not inside a closure.

@randall77

danscales commented 3 years ago

This is related/similar to issue #47676 . We probably need to do the substitution of the Defn nodes after the body of the function, since they often point into the body being stenciled.

gopherbot commented 3 years ago

Change https://golang.org/cl/346290 mentions this issue: cmd/compile: fix handling of Defn field during stenciling

dsnet commented 3 years ago

Thanks @danscales for the fix! I'm unfortunately hitting another different internal compiler error: #48103.