Skip to content

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

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

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
Milestone

Comments

@alandonovan
Copy link
Contributor

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

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.

@griesemer griesemer added this to the Go1.5 milestone Dec 30, 2014
@griesemer griesemer added bug Documentation Issues describing a change to documentation. and removed bug Documentation Issues describing a change to documentation. labels Dec 30, 2014
@ianlancetaylor
Copy link
Member

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.

@robpike
Copy link
Contributor

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.

@griesemer griesemer added accepted and removed Documentation Issues describing a change to documentation. labels Jan 6, 2015
@griesemer
Copy link
Contributor

Fixed by golang/tools@44ee65f .

@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
Development

No branches or pull requests

5 participants