Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile: local type declarations in generic code don't work #47631

Closed
randall77 opened this issue Aug 10, 2021 · 16 comments
Closed

cmd/compile: local type declarations in generic code don't work #47631

randall77 opened this issue Aug 10, 2021 · 16 comments
Assignees
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FrozenDueToAge generics Issue is related to generics NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@randall77
Copy link
Contributor

package main

func F[T1 any]() {
	type x struct{}
}
func main() {
}
$ go run -gcflags=-G=3 tmp1.go
# command-line-arguments
<unknown line number>: internal compiler error: cannot export DCLTYPE (50) node

This looks like a general problem that we can't export/import local type declarations, including for inlining.

@randall77 randall77 self-assigned this Aug 10, 2021
@gopherbot
Copy link

Change https://golang.org/cl/341213 mentions this issue: [dev.typeparams] cmd/compile: enable export/import of local type declarations

@danscales
Copy link
Contributor

@findleyr pointed out that local generic types in non-generic functions somewhat work now:

package main

import "fmt"

func main() {
        type N[T any] struct{ t T }

        type N2[T comparable] struct{ t T }
        var x N[int]
        var y N2[string]
        fmt.Println(x, y)
}

Of course, if instead of main, we had an exported, inlinable function F, then we would get the same failure, since we would try to export F.

But just wanted to mention this case, since we need to either support it or disable it, depending on whether we support local generic types in Go 1.18.

@rogpeppe
Copy link
Contributor

rogpeppe commented Oct 9, 2021

FWIW some cases give a different kind of panic. For example https://go2goplay.golang.org/p/snfHm-qGhGD gives me this traceback:

# command-line-arguments
panic: runtime error: slice bounds out of range [:-1]

goroutine 1 [running]:
cmd/compile/internal/typecheck.genericTypeName(...)
	/home/rogpeppe/go/src/cmd/compile/internal/typecheck/subr.go:1405
cmd/compile/internal/typecheck.(*Tsubster).typ1(0xc000444478, 0xc000425c70)
	/home/rogpeppe/go/src/cmd/compile/internal/typecheck/subr.go:1106 +0x13bd
cmd/compile/internal/typecheck.(*Tsubster).Typ(0xc000414c60, 0x0)
	/home/rogpeppe/go/src/cmd/compile/internal/typecheck/subr.go:1046 +0x25
cmd/compile/internal/noder.(*subster).node.func1({0xe51478, 0xc000423110})
	/home/rogpeppe/go/src/cmd/compile/internal/noder/stencil.go:904 +0x305
cmd/compile/internal/ir.(*Decl).editChildren(0xc00040c4b0, 0xe504d8)
	/home/rogpeppe/go/src/cmd/compile/internal/ir/node_gen.go:462 +0x3c
cmd/compile/internal/ir.EditChildren(...)
	/home/rogpeppe/go/src/cmd/compile/internal/ir/visit.go:185
cmd/compile/internal/noder.(*subster).node.func1({0xe504d8, 0xc00040c2d0})
	/home/rogpeppe/go/src/cmd/compile/internal/noder/stencil.go:956 +0x548
cmd/compile/internal/noder.(*subster).node(0xc000444460, {0xe504d8, 0xc00040c2d0})
	/home/rogpeppe/go/src/cmd/compile/internal/noder/stencil.go:1174 +0xa5
cmd/compile/internal/noder.(*subster).list(0xc000404280, {0xc000414ae0, 0x2, 0xc0000885a0})
	/home/rogpeppe/go/src/cmd/compile/internal/noder/stencil.go:1432 +0x8e
cmd/compile/internal/noder.(*irgen).genericSubst(0xc00043c000, 0xc0004119f0, 0xc000422c30, {0xc000404250, 0x1, 0x1}, 0x0, 0xc00040c3f0)
	/home/rogpeppe/go/src/cmd/compile/internal/noder/stencil.go:757 +0xce6
cmd/compile/internal/noder.(*irgen).getInstantiation(0xc00043c000, 0xc000422c30, {0xc000404248, 0x1, 0x414b4f}, 0x0)
	/home/rogpeppe/go/src/cmd/compile/internal/noder/stencil.go:635 +0x205
cmd/compile/internal/noder.(*irgen).stencil.func1({0xe4fe98, 0xc000440090})
	/home/rogpeppe/go/src/cmd/compile/internal/noder/stencil.go:108 +0x2df
cmd/compile/internal/ir.Visit.func1({0xe4fe98, 0xc000440090})
	/home/rogpeppe/go/src/cmd/compile/internal/ir/visit.go:105 +0x30
cmd/compile/internal/ir.(*AssignStmt).doChildren(0xc000410730, 0xc00040c3d8)
	/home/rogpeppe/go/src/cmd/compile/internal/ir/node_gen.go:152 +0x82
cmd/compile/internal/ir.DoChildren(...)
	/home/rogpeppe/go/src/cmd/compile/internal/ir/visit.go:94
cmd/compile/internal/ir.Visit.func1({0xe4fab0, 0xc000410730})
	/home/rogpeppe/go/src/cmd/compile/internal/ir/visit.go:106 +0x57
cmd/compile/internal/ir.doNodes({0xc000414920, 0x2, 0x0}, 0xc00040c3d8)
	/home/rogpeppe/go/src/cmd/compile/internal/ir/node_gen.go:1512 +0x67
cmd/compile/internal/ir.(*Func).doChildren(0xe507f8, 0xc00040a2c0)
	/home/rogpeppe/go/src/cmd/compile/internal/ir/func.go:152 +0x2e
cmd/compile/internal/ir.DoChildren(...)
	/home/rogpeppe/go/src/cmd/compile/internal/ir/visit.go:94
cmd/compile/internal/ir.Visit.func1({0xe507f8, 0xc00040a2c0})
	/home/rogpeppe/go/src/cmd/compile/internal/ir/visit.go:106 +0x57
cmd/compile/internal/ir.Visit({0xe507f8, 0xc00040a2c0}, 0xc000416d00)
	/home/rogpeppe/go/src/cmd/compile/internal/ir/visit.go:108 +0xb8
cmd/compile/internal/noder.(*irgen).stencil(0xc00043c000)
	/home/rogpeppe/go/src/cmd/compile/internal/noder/stencil.go:90 +0x238
cmd/compile/internal/noder.(*irgen).generate(0xc00043c000, {0xc000072b80, 0x2, 0xb})
	/home/rogpeppe/go/src/cmd/compile/internal/noder/irgen.go:301 +0x359
cmd/compile/internal/noder.check2({0xc000072b80, 0x2, 0x2})
	/home/rogpeppe/go/src/cmd/compile/internal/noder/irgen.go:93 +0x175
cmd/compile/internal/noder.LoadPackage({0xc00001e220, 0x2, 0x0})
	/home/rogpeppe/go/src/cmd/compile/internal/noder/noder.go:90 +0x335
cmd/compile/internal/gc.Main(0xd0dec8)
	/home/rogpeppe/go/src/cmd/compile/internal/gc/main.go:190 +0xaf3
main.main()
	/home/rogpeppe/go/src/cmd/compile/main.go:55 +0xdd

It works fine if the struct type is anonymous.

@thepudds
Copy link
Contributor

Probably not that helpful, but FWIW, here is another example that fails on tip (640a49b Sat Oct 16 16:27:40 2021 +0000) with internal compiler error: cannot export DCLTYPE (50) node. I found this via fuzzing and reported to mdempsky back in June, though I think he said it was a known issue at the time.

package p

func P[T any](T) {
        type w []w
}
func A() { P([]string{}) }

@gopherbot
Copy link

Change https://golang.org/cl/355351 mentions this issue: cmd/compile: allow local type declarations when inlining

@qmuntal
Copy link
Contributor

qmuntal commented Oct 27, 2021

IMO this issue should be labeled as release-blocker, local type declarations are fairly common.

@vearutop
Copy link
Contributor

vearutop commented Nov 3, 2021

For additional information (or test), here are a couple more examples where this issue is exposed:
bool64/cache#10 (https://github.com/bool64/cache/runs/4090475198?check_suite_focus=true#step:5:28)

<autogenerated>:1: internal compiler error: cannot export DCLTYPE (50) node
	==> please file an issue and assign to gri@

And bool64/cache#11 (https://github.com/bool64/cache/runs/4090471755?check_suite_focus=true#step:5:28)

panic: runtime error: slice bounds out of range [:-1]

@gopherbot
Copy link

Change https://golang.org/cl/364054 mentions this issue: cmd/compile: error when using internal type declarations in generic functions

gopherbot pushed a commit that referenced this issue Nov 15, 2021
…unctions

We hope to support this feature one day, but it doesn't work currently.
Issue a nice error message instead of having the compiler crash.

Update #47631

Change-Id: I0359411410acbaf9a5b9dbb988cd933de1bb8438
Reviewed-on: https://go-review.googlesource.com/c/go/+/364054
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
@randall77 randall77 modified the milestones: Go1.18, Go1.19 Nov 15, 2021
@randall77
Copy link
Contributor Author

This feature is being pushed back to 1.19.

@ianlancetaylor ianlancetaylor added the generics Issue is related to generics label Nov 15, 2021
@gopherbot
Copy link

Change https://golang.org/cl/364134 mentions this issue: doc: mention generics in release notes

gopherbot pushed a commit that referenced this issue Nov 16, 2021
Also mention local types restriction.

We probably want to say more at some point, this is just a
placeholder to start.

Update #47631

Change-Id: I828e451e1e8504d21cb55c7132e9cb330b160a54
Reviewed-on: https://go-review.googlesource.com/c/go/+/364134
Trust: Keith Randall <khr@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
@gopherbot
Copy link

Change https://golang.org/cl/364314 mentions this issue: cmd/compile: prevent irgen crashing for empty local declaration stmt

gopherbot pushed a commit that referenced this issue Nov 16, 2021
Updates #47631
Fixes #49611

Change-Id: Ib4a4466038e0d4a9aa9380d7909f29f7d15c6c69
Reviewed-on: https://go-review.googlesource.com/c/go/+/364314
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
@gopherbot
Copy link

Change https://golang.org/cl/372154 mentions this issue: cmd/compile: don't allow generic type declarations inside functions

@zhuah
Copy link

zhuah commented Dec 24, 2021

can we support type alias in generic code?

package main

type S1[T any] struct {
}

func (s S1[T]) Build(fn func(t *T)) T {
	var t T
	fn(&t)
	return t
}

type Container[T any] struct {
	Value T
}

type S2[T any] struct{}

func (s S2[T]) Build() Container[T] {
	type valueType = Container[T]

	return S1[valueType]{}.Build(func(t *valueType) {
		*t = valueType{}
	})
}

func main() {

}

this type alias could significantly improve code readability, typically in complicate code.

lu4p added a commit to lu4p/garble that referenced this issue May 13, 2022
The seed obfuscator uses a type declaration in order to declare a function,
which returns a function with the same type.

This breaks when obfuscating literals inside generic functions, because
type declarations inside generic functions are not currently supported.

Therefore the obfuscator gets disabled until
golang/go#47631 is fixed.
lu4p added a commit to burrowers/garble that referenced this issue May 13, 2022
The seed obfuscator uses a type declaration in order to declare a function,
which returns a function with the same type.

This breaks when obfuscating literals inside generic functions, because
type declarations inside generic functions are not currently supported.

Therefore the obfuscator gets disabled until
golang/go#47631 is fixed.
@mknyszek
Copy link
Contributor

Should this be moved to Go 1.20? This is a new feature and we're already in the freeze. CC @randall77

@randall77 randall77 modified the milestones: Go1.19, Go1.20 May 18, 2022
@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Jul 13, 2022
@mknyszek
Copy link
Contributor

I'm told this is no longer a release blocker, so I'm dropping that label. I'll otherwise leave it as Todo and assigned to Keith.

@randall77
Copy link
Contributor Author

This is now fixed with unified IR.
@mdempsky

@golang golang locked and limited conversation to collaborators Sep 3, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FrozenDueToAge generics Issue is related to generics NeedsFix The path to resolution is known, but the work has not been done.
Projects
Development

No branches or pull requests