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: cannot return a value even its type subjects to type constraints #51501

Closed
changkun opened this issue Mar 5, 2022 · 3 comments
Closed

Comments

@changkun
Copy link
Member

@changkun changkun commented Mar 5, 2022

Does this issue reproduce with the latest release?

Yes

What did you do?

https://go.dev/play/p/pCzjLWAepvO?v=gotip

package main

func foo[T ~int]() T {
	x := 42
	return T(x) // OK
}

func foo2[T ~int]() T {
	x := 42
	return int(x) // ERROR: cannot use int(x) (value of type int) as type T in return statement
}

func main() {}

What did you expect to see?

Compile pass.

What did you see instead?

Compile error.

@go101
Copy link

@go101 go101 commented Mar 5, 2022

type MyInt int

MyInt might be used as an argument passed to foo2 type parameter. An int value may not be assigned to a MyInt value.

In fact, even if the foo2 function is change to

func foo2[T int]() T {
	x := 42
	return int(x) // ERROR: cannot use int(x) (value of type int) as type T in return statement
}

it still doesn't compile. Please view #51403 for details.

@changkun
Copy link
Member Author

@changkun changkun commented Mar 5, 2022

Sigh, sounds very limited. Though I noticed that we could:

func foo2[T ~int]() T {
	x := 42
	return T(int(x)) // OK
}

But use cases like this still can't work:

package main

type A struct{}

func (a A) Foo() {}

type B struct{}

func (b B) Foo() {}

type C interface{ Foo() }

func Want[T C]() *T {

	var x T
	switch (interface{})(x).(type) {
	case A:
		return (*T)(&A{}) // cannot convert &A{} (value of type *A) to type *T: *A does not implement *T (type *T is pointer to interface, not interface)
	case B:
		return (*T)(&B{}) // cannot convert &B{} (value of type *B) to type *T: *B does not implement *T (type *T is pointer to interface, not interface)
	default:
		panic("unknown")
	}

}

func main() {
	Want[A]()
	Want[B]()
}

One have to import unsafe:

package main

import "unsafe"

type A struct{}

func (a A) Foo() {}

type B struct{}

func (b B) Foo() {}

type C interface{ Foo() }

func Want[T C]() *T {

	var x T
	switch (interface{})(x).(type) {
	case A:
		return (*T)(unsafe.Pointer(&A{})) // OK
	case B:
		return (*T)(unsafe.Pointer(&B{})) // OK
	default:
		panic("unknown")
	}

}

func main() {
	Want[A]()
	Want[B]()
}

@changkun changkun closed this as completed Mar 5, 2022
@go101
Copy link

@go101 go101 commented Mar 6, 2022

The pointer conversion problem is the same as: #50815

The key point here is the underlying type of T is an interface type. In fact, the underlying type of every type parameter type is an interface type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants