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/go2go: compiler treats returning type with generics incorrectly. #39655

Closed
googollee opened this issue Jun 17, 2020 · 10 comments
Closed

cmd/go2go: compiler treats returning type with generics incorrectly. #39655

googollee opened this issue Jun 17, 2020 · 10 comments

Comments

@googollee
Copy link

@googollee googollee commented Jun 17, 2020

What version of Go are you using (go version)?

$ go version
devel +ad307489d4 Tue Jun 16 05:49:35 2020 +0000.

Does this issue reproduce with the latest release?

No. It's a dev branch.

What operating system and processor architecture are you using (go env)?

I'm using https://go2goplay.golang.org/.

What did you do?

package main

type Result(type T) struct {
	t T
}

func F(type T)(v Result(T)) (Result(T)) {
	return v
}

What did you expect to see?

The code should be compiled

What did you see instead?

type checking failed for main
prog.go2:8:9: cannot use v (variable of type Result(T)) as T value in return statement

The return type of F should be Result(T), but the compiler thinks it's T, treating the definition as func F(type T)(v Result(T)) (Result T).

@andybons andybons changed the title The compiler treats returning type with generics incorrectly. cmd/go2go: compiler treats returning type with generics incorrectly. Jun 17, 2020
@andybons andybons modified the milestones: Unreleased, Unplanned Jun 17, 2020
@andybons
Copy link
Member

@andybons andybons commented Jun 17, 2020

@googollee
Copy link
Author

@googollee googollee commented Jun 17, 2020

It'd be easy to be fixed by func F(type T)(v Result(T)) Result(T). I think it needs to make it more clear what's (Result(T)) should be.

@griesemer
Copy link
Contributor

@griesemer griesemer commented Jun 17, 2020

This is working as expected. This code will work:

package main

type Result(type T) struct {
	t T
}

func F(type T)(v Result(T)) Result(T) {
	return v
}

Alternatively, you need to write (_ Result(T)) or ((Result(T))). The reason is that (Result(T)) is interpreted as (Result (T)), i.e., the result is named Result and is of parenthesized type (T), for backwards-compatibility.

This is a common mistake people are making, so we are considering changing this. This is also documented in the design draft.

@griesemer griesemer closed this Jun 17, 2020
@googollee
Copy link
Author

@googollee googollee commented Jun 20, 2020

@griesemer Thanks for clarifying.

@agnivade
Copy link
Contributor

@agnivade agnivade commented Jul 5, 2020

@griesemer - Sorry to comment on a closed issue, but perhaps it might make sense to add a line in https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md#using-generic-types-as-unnamed-function-parameter-types mentioning that we need to write Result(T) as (_ Result(T))/(Result(T))?

When I read that section, it seemed to suggest that the new proposal actually breaks backward compatibility, so there's no need to write code with extra parentheses.

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Jul 6, 2020

@agnivade I'm not sure quite what you are saying. It's OK to write func F() Result(T). The case that doesn't work at the moment is func F() (Result(T)). If you really want those parens then at the moment you need to write func F() (_ Result(T)) or func F() ((Result(T))).

@agnivade
Copy link
Contributor

@agnivade agnivade commented Jul 7, 2020

Ah yea sorry about that. I realize now that I went on a slight tangent. I just wanted some clarification about the syntax added to the doc. In my case, what I needed was (_ Result(T))/((Result(T))), as you can see here. But I didn't realize that and wrote Result(T). It took me some googling to figure this out because it wasn't very clear from the error message, which was this:

/tmp/go2go-run630056446/cache.go2:43:3: expected operand, found 'return' (and 1 more errors)

This is what I would like to be added in the doc. (Or is it already there somewhere and I have missed it?)

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Jul 8, 2020

I think that the current parser doesn't yet fully support the syntax described in the design draft. Let's revisit when that work is done.

@arl
Copy link
Contributor

@arl arl commented Jul 10, 2020

FWITW, the required pair of surrounding parentheses gets removed by gofmt, both on the playground and locally at 9fe9a32, which is slightly annoying since these are required for successful compilation.

Example (https://go2goplay.golang.org/p/lr-Nvr1ydPA)

package main

func main() {}

type A(type T) interface{}

// (1) try:
func _(type T)() (A(T), error) { return nil, nil }
//
//  --> error: mixed named and unnamed function parameters

// (2) add parentheses:
func _(type T)() ((A(T)), error) { return nil, nil }
//
//  --> ok, compiles

// (3) run gofmt on (2) gets you back to (1)

Something similar (https://go2goplay.golang.org/p/zJ7wmOIPWxK)

package main

func main() {}

type A(type T) interface{}

func _(type T)()    A(T)    { return nil } // ok
func _(type T)()   (A(T))   { return nil } // nok: cannot convert nil (untyped nil value) to T
func _(type T)()  ((A(T)))  { return nil } // ok
func _(type T)() (((A(T)))) { return nil } // ok

func _(type T)()   (A(T), error)  { return nil, nil } // mixed named and unnamed function parameters
func _(type T)()  ((A(T)), error) { return nil, nil } // ok

func _(type T)()   (a A(T), err error)  { return nil, nil } // ok
func _(type T)()  (a (A(T)), err error) { return nil, nil } // ok

PS: Sorry to comment on a closed issue, but I also don't think this is worth opening a new one, just let me know if I should do it anyway.

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

Successfully merging a pull request may close this issue.

None yet
6 participants
You can’t perform that action at this time.