mirror of
https://github.com/golang/go
synced 2024-11-23 04:40:09 -07:00
cmd/gc: allow append and complex builtins to accept 2-result call expression as first argument.
Fixes #5793. LGTM=rsc R=rsc, adonovan, dave CC=golang-codereviews https://golang.org/cl/13367051
This commit is contained in:
parent
202e6153f5
commit
671cc6efba
@ -392,6 +392,8 @@ inlnode(Node **np)
|
|||||||
case OCALLFUNC:
|
case OCALLFUNC:
|
||||||
case OCALLMETH:
|
case OCALLMETH:
|
||||||
case OCALLINTER:
|
case OCALLINTER:
|
||||||
|
case OAPPEND:
|
||||||
|
case OCOMPLEX:
|
||||||
// if we just replaced arg in f(arg()) or return arg with an inlined call
|
// if we just replaced arg in f(arg()) or return arg with an inlined call
|
||||||
// and arg returns multiple values, glue as list
|
// and arg returns multiple values, glue as list
|
||||||
if(count(n->list) == 1 && n->list->n->op == OINLCALL && count(n->list->n->rlist) > 1) {
|
if(count(n->list) == 1 && n->list->n->op == OINLCALL && count(n->list->n->rlist) > 1) {
|
||||||
|
@ -344,6 +344,8 @@ orderexpr(Node **np, NodeList **out)
|
|||||||
case OCALLFUNC:
|
case OCALLFUNC:
|
||||||
case OCALLMETH:
|
case OCALLMETH:
|
||||||
case OCALLINTER:
|
case OCALLINTER:
|
||||||
|
case OAPPEND:
|
||||||
|
case OCOMPLEX:
|
||||||
ordercall(n, out);
|
ordercall(n, out);
|
||||||
n = copyexpr(n, n->type, out);
|
n = copyexpr(n, n->type, out);
|
||||||
break;
|
break;
|
||||||
|
@ -1212,17 +1212,29 @@ reswitch:
|
|||||||
|
|
||||||
case OCOMPLEX:
|
case OCOMPLEX:
|
||||||
ok |= Erv;
|
ok |= Erv;
|
||||||
if(twoarg(n) < 0)
|
if(count(n->list) == 1) {
|
||||||
goto error;
|
typechecklist(n->list, Efnstruct);
|
||||||
l = typecheck(&n->left, Erv | (top & Eiota));
|
t = n->list->n->left->type;
|
||||||
r = typecheck(&n->right, Erv | (top & Eiota));
|
if(t->outtuple != 2) {
|
||||||
if(l->type == T || r->type == T)
|
yyerror("invalid operation: complex expects two arguments, %N returns %d results", n->list->n, t->outtuple);
|
||||||
goto error;
|
goto error;
|
||||||
defaultlit2(&l, &r, 0);
|
}
|
||||||
if(l->type == T || r->type == T)
|
t = n->list->n->type->type;
|
||||||
goto error;
|
l = t->nname;
|
||||||
n->left = l;
|
r = t->down->nname;
|
||||||
n->right = r;
|
} else {
|
||||||
|
if(twoarg(n) < 0)
|
||||||
|
goto error;
|
||||||
|
l = typecheck(&n->left, Erv | (top & Eiota));
|
||||||
|
r = typecheck(&n->right, Erv | (top & Eiota));
|
||||||
|
if(l->type == T || r->type == T)
|
||||||
|
goto error;
|
||||||
|
defaultlit2(&l, &r, 0);
|
||||||
|
if(l->type == T || r->type == T)
|
||||||
|
goto error;
|
||||||
|
n->left = l;
|
||||||
|
n->right = r;
|
||||||
|
}
|
||||||
if(!eqtype(l->type, r->type)) {
|
if(!eqtype(l->type, r->type)) {
|
||||||
yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
|
yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
|
||||||
goto error;
|
goto error;
|
||||||
@ -1301,9 +1313,22 @@ reswitch:
|
|||||||
yyerror("missing arguments to append");
|
yyerror("missing arguments to append");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
typechecklist(args, Erv);
|
|
||||||
|
if(count(args) == 1 && !n->isddd)
|
||||||
|
typecheck(&args->n, Erv | Efnstruct);
|
||||||
|
else
|
||||||
|
typechecklist(args, Erv);
|
||||||
|
|
||||||
if((t = args->n->type) == T)
|
if((t = args->n->type) == T)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
// Unpack multiple-return result before type-checking.
|
||||||
|
if(istype(t, TSTRUCT)) {
|
||||||
|
t = t->type;
|
||||||
|
if(istype(t, TFIELD))
|
||||||
|
t = t->type;
|
||||||
|
}
|
||||||
|
|
||||||
n->type = t;
|
n->type = t;
|
||||||
if(!isslice(t)) {
|
if(!isslice(t)) {
|
||||||
if(isconst(args->n, CTNIL)) {
|
if(isconst(args->n, CTNIL)) {
|
||||||
|
@ -493,6 +493,11 @@ walkexpr(Node **np, NodeList **init)
|
|||||||
case OADD:
|
case OADD:
|
||||||
case OCOMPLEX:
|
case OCOMPLEX:
|
||||||
case OLROT:
|
case OLROT:
|
||||||
|
// Use results from call expression as arguments for complex.
|
||||||
|
if(n->op == OCOMPLEX && n->left == N && n->right == N) {
|
||||||
|
n->left = n->list->n;
|
||||||
|
n->right = n->list->next->n;
|
||||||
|
}
|
||||||
walkexpr(&n->left, init);
|
walkexpr(&n->left, init);
|
||||||
walkexpr(&n->right, init);
|
walkexpr(&n->right, init);
|
||||||
goto ret;
|
goto ret;
|
||||||
@ -2772,6 +2777,10 @@ append(Node *n, NodeList **init)
|
|||||||
l->n = cheapexpr(l->n, init);
|
l->n = cheapexpr(l->n, init);
|
||||||
|
|
||||||
nsrc = n->list->n;
|
nsrc = n->list->n;
|
||||||
|
|
||||||
|
// Resolve slice type of multi-valued return.
|
||||||
|
if(istype(nsrc->type, TSTRUCT))
|
||||||
|
nsrc->type = nsrc->type->type->type;
|
||||||
argc = count(n->list) - 1;
|
argc = count(n->list) - 1;
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
return nsrc;
|
return nsrc;
|
||||||
|
36
test/fixedbugs/issue5793.go
Normal file
36
test/fixedbugs/issue5793.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// run
|
||||||
|
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Issue 5793: calling 2-arg builtin with multiple-result f() call expression gives
|
||||||
|
// spurious error.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func complexArgs() (float64, float64) {
|
||||||
|
return 5, 7
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendArgs() ([]string, string) {
|
||||||
|
return []string{"foo"}, "bar"
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendMultiArgs() ([]byte, byte, byte) {
|
||||||
|
return []byte{'a', 'b'}, '1', '2'
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if c := complex(complexArgs()); c != 5+7i {
|
||||||
|
panic(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s := append(appendArgs()); len(s) != 2 || s[0] != "foo" || s[1] != "bar" {
|
||||||
|
panic(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
if b := append(appendMultiArgs()); len(b) != 4 || b[0] != 'a' || b[1] != 'b' || b[2] != '1' || b[3] != '2' {
|
||||||
|
panic(b)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user