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

go/types: fails to report type error for ill-formed call #9473

Closed
alandonovan opened this issue Dec 30, 2014 · 4 comments
Closed

go/types: fails to report type error for ill-formed call #9473

alandonovan opened this issue Dec 30, 2014 · 4 comments
Assignees
Milestone

Comments

@alandonovan
Copy link
Contributor

@alandonovan alandonovan commented Dec 30, 2014

package main
func f() (x, y []int)
var _ = append(f()...) // compile error: multiple-value f() in single-value context

In the program above, gc correctly reports a type error for the ill-formed call to append.
go/types does not.

@griesemer
Copy link
Contributor

@griesemer griesemer commented Dec 30, 2014

Interesting!

go/types handles parameter passing to built-ins essentially the same as for regular functions and so this should not be restricted to the built-in append, but also user-defined functions (see below). Furthermore, gccgo also accepts this code. In fact, both, go/types and gccgo accept his code:

package main

import "fmt"

func f() (x, y []int) {
return []int{1, 2}, []int{3, 4, 5}
}

func append2(x []int, y ...int) {
fmt.Printf("x = %v\n", x)
fmt.Printf("y = %v\n", y)
}

func main() {
fmt.Printf("%v\n", append(f()...))
append2(f()...)
}

gccgo even runs it "correctly":

$ gccgo x.go && ./a.out
[1 2 3 4 5]
x = [1 2]
y = [3 4 5]

That is, it's not obviously clear that this is a go/types issue.

Per the spec:

  1. "As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order. The call of f must contain no parameters other than the call of g, and g must have at least one return value. If f has a final ... parameter, it is assigned the return values of g that remain after assignment of regular parameters." (http://golang.org/ref/spec#Calls)

And:

  1. "If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created." (http://golang.org/ref/spec#Passing_arguments_to_..._parameters)

Thus, if 2) is done after 1), one might argue that the final argument after 1) is indeed a slice of the form []T and thus ... is applicable.

This is indeed what go/types does: it first "unpacks" f() and treats the results of f() as a sequence of individual results. The ... application to the last argument happens afterwards. I suspect gccgo does something analogous.

The spec is not specific enough in this case as evidenced by the different interpretations of it by go/types and gccco, vs gc, and we should clarify it. Permitting the code above could be an unintended consequence of the spec as written, or we can disallow it.

Loading

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Dec 31, 2014

As your example shows, there is nothing special about append here.

Although gccgo supports this kind of code, I'm inclined to think that it should not. The rule about ... in a call applies to the final argument. When the argument is a function call that returns multiple results, there is no clear final argument for ... to apply to. Applying it to the final function call result makes logical sense, but it is quite obscure, and I think better prohibited.

Loading

@robpike
Copy link
Contributor

@robpike robpike commented Jan 3, 2015

I came here to say what I saw Ian has already said. The issue is the ..., and it should not apply to the second result like this. Gc is correct to reject this program.

Loading

@griesemer
Copy link
Contributor

@griesemer griesemer commented Jan 8, 2015

Loading

@griesemer griesemer closed this Jan 8, 2015
@golang golang locked and limited conversation to collaborators Jun 25, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
5 participants