1
0
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:
Chris Manghane 2014-03-05 14:16:21 -05:00 committed by Russ Cox
parent 202e6153f5
commit 671cc6efba
5 changed files with 86 additions and 12 deletions

View File

@ -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) {

View File

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

View File

@ -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)) {

View File

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

View 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)
}
}