Commit 9dc22b6d authored by Russ Cox's avatar Russ Cox

more 6g reorg; checkpoint.

typecheck.c is now responsible for all type checking
except for assignment and function argument "..."

R=ken
OCL=32661
CL=32667
parent 17808905
...@@ -907,6 +907,8 @@ nodarg(Type *t, int fp) ...@@ -907,6 +907,8 @@ nodarg(Type *t, int fp)
n->class = PPARAM; n->class = PPARAM;
break; break;
} }
n->typecheck = 1;
return n; return n;
} }
......
...@@ -200,8 +200,6 @@ bad: ...@@ -200,8 +200,6 @@ bad:
defaultlit(&n, T); defaultlit(&n, T);
*np = n; *np = n;
} }
yyerror("cannot convert %T constant to %T", n->type, t);
n->diag = 1;
return; return;
} }
...@@ -336,6 +334,9 @@ evconst(Node *n) ...@@ -336,6 +334,9 @@ evconst(Node *n)
switch(n->op) { switch(n->op) {
case OMAKE: case OMAKE:
case OMAKEMAP:
case OMAKESLICE:
case OMAKECHAN:
return; return;
} }
...@@ -557,7 +558,7 @@ evconst(Node *n) ...@@ -557,7 +558,7 @@ evconst(Node *n)
if(cmpslit(nl, nr) > 0) if(cmpslit(nl, nr) > 0)
goto settrue; goto settrue;
goto setfalse; goto setfalse;
case TUP(OADD, CTSTR): case TUP(OADDSTR, CTSTR):
len = v.u.sval->len + nr->val.u.sval->len; len = v.u.sval->len + nr->val.u.sval->len;
str = mal(sizeof(*str) + len); str = mal(sizeof(*str) + len);
str->len = len; str->len = len;
...@@ -605,6 +606,7 @@ unary: ...@@ -605,6 +606,7 @@ unary:
case TUP(OCONV, CTFLT): case TUP(OCONV, CTFLT):
case TUP(OCONV, CTSTR): case TUP(OCONV, CTSTR):
case TUP(OCONV, CTNIL): case TUP(OCONV, CTNIL):
case TUP(OARRAYBYTESTR, CTNIL):
convlit1(&nl, n->type, 1); convlit1(&nl, n->type, 1);
break; break;
......
...@@ -672,9 +672,9 @@ funclit1(Node *ntype, NodeList *body) ...@@ -672,9 +672,9 @@ funclit1(Node *ntype, NodeList *body)
for(l=func->cvars; l; l=l->next) { for(l=func->cvars; l; l=l->next) {
a = l->n; a = l->n;
d = oldname(a->sym); d = oldname(a->sym);
addrescapes(d);
args = list(args, nod(OADDR, d, N)); args = list(args, nod(OADDR, d, N));
} }
typechecklist(args, Erv);
n = nod(OCALL, clos, N); n = nod(OCALL, clos, N);
n->list = args; n->list = args;
...@@ -1642,7 +1642,7 @@ embedded(Sym *s) ...@@ -1642,7 +1642,7 @@ embedded(Sym *s)
NodeList* NodeList*
variter(NodeList *vl, Node *nt, NodeList *el) variter(NodeList *vl, Node *nt, NodeList *el)
{ {
int doexpr; int doexpr, lno;
Node *v, *e, *a; Node *v, *e, *a;
Type *tv; Type *tv;
NodeList *r; NodeList *r;
...@@ -1663,23 +1663,37 @@ variter(NodeList *vl, Node *nt, NodeList *el) ...@@ -1663,23 +1663,37 @@ variter(NodeList *vl, Node *nt, NodeList *el)
break; break;
} }
e = el->n; e = el->n;
el = el->next;
} else } else
e = N; e = N;
v = vl->n; v = vl->n;
tv = t; tv = t;
if(t == T) { if(e) {
lno = lineno;
lineno = v->lineno;
typecheck(&e, Erv); typecheck(&e, Erv);
defaultlit(&e, T); defaultlit(&e, t);
tv = e->type; if(t)
e = typecheckconv(nil, e, t, 0);
if(tv == nil)
tv = e->type;
if(tv && tv->etype == TNIL) {
yyerror("cannot initialize %#N to untyped nil", v);
tv = nil;
}
lineno = lno;
} }
a = N; a = N;
if(e != N || funcdepth > 0) if((e != N && tv != T) || funcdepth > 0)
a = nod(OAS, v, e); a = nod(OAS, v, e);
dodclvar(v, tv, &r); dodclvar(v, tv, &r);
if(a != N) if(a != N)
r = list(r, a); r = list(r, a);
if(el) {
el->n = e;
el = el->next;
}
} }
if(el != nil) if(el != nil)
yyerror("extra expr in var dcl"); yyerror("extra expr in var dcl");
......
...@@ -328,36 +328,41 @@ enum ...@@ -328,36 +328,41 @@ enum
OLITERAL, OLITERAL,
// exprs // exprs
OADD, OSUB, OOR, OXOR, OADD, OSUB, OOR, OXOR, OADDSTR,
OADDR, OADDR,
OANDAND, OANDAND,
OAPPENDSTR,
OARRAY, OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR,
OAS, OAS2, OASOP, OAS, OAS2, OASOP,
OBAD, OBAD,
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
OCAP, OCAP,
OCLOSE, OCLOSE,
OCLOSED, OCLOSED,
OCOMPOS, OCOMPSLICE, OCOMPMAP, OCMPIFACE, OCMPSTR,
OCONV, OCONVNOP, OCONVRUNE, OCONVSTRB, OCONVSTRI, OCONVA2S, OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
OCOMPSLICE, OCOMPMAP,
OCONV, OCONVNOP, OCONVA2S, OCONVIFACE, OCONVSLICE,
ODCL, ODCLFUNC, ODCLFIELD, ODCLARG, ODCL, ODCLFUNC, ODCLFIELD, ODCLARG,
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
ODOTTYPE, ODOTTYPE,
OEQ, ONE, OLT, OLE, OGE, OGT, OEQ, ONE, OLT, OLE, OGE, OGT,
OFUNC, OFUNC,
OIND, OIND,
OINDEX, OINDEXSTR, OINDEXMAP, OINDEXARR, OINDEX, OINDEXSTR, OINDEXMAP,
OKEY, OPARAM, OKEY, OPARAM,
OLEN, OLEN,
OMAKE, OMAKE, OMAKECHAN, OMAKEMAP, OMAKESLICE,
OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT, OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT,
ONEW, ONEW,
ONOT, OCOM, OPLUS, OMINUS, ONOT, OCOM, OPLUS, OMINUS,
OOROR, OOROR,
OPANIC, OPANICN, OPRINT, OPRINTN, OPANIC, OPANICN, OPRINT, OPRINTN,
OSEND, OSEND, OSENDNB,
OSLICE, OSLICESTR, OSLICEARR, OSLICE, OSLICEARR, OSLICESTR,
ORECV, ORECV,
ORUNESTR,
// stmts // stmts
OBLOCK, OBLOCK,
...@@ -470,10 +475,9 @@ enum ...@@ -470,10 +475,9 @@ enum
enum enum
{ {
Etop = 1<<1, // evaluated at statement level Etop = 1<<1, // evaluated at statement level
Elv = 1<<2, // evaluated in lvalue context Erv = 1<<2, // evaluated in value context
Erv = 1<<3, // evaluated in rvalue context Etype = 1<<3,
Etype = 1<<4, Ecall = 1<<4,
Ecall = 1<<5,
}; };
#define BITS 5 #define BITS 5
...@@ -658,6 +662,8 @@ EXTERN ushort blockgen; // max block number ...@@ -658,6 +662,8 @@ EXTERN ushort blockgen; // max block number
EXTERN ushort block; // current block number EXTERN ushort block; // current block number
EXTERN int hasdefer; // flag that curfn has defer statetment EXTERN int hasdefer; // flag that curfn has defer statetment
EXTERN Node* curfn;
EXTERN int maxround; EXTERN int maxround;
EXTERN int widthptr; EXTERN int widthptr;
...@@ -986,14 +992,12 @@ NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**); ...@@ -986,14 +992,12 @@ NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
NodeList* ascompatte(int, Type**, NodeList*, int, NodeList**); NodeList* ascompatte(int, Type**, NodeList*, int, NodeList**);
int ascompat(Type*, Type*); int ascompat(Type*, Type*);
Node* newcompat(Node*); Node* newcompat(Node*);
Node* makecompat(Node*);
Node* stringop(Node*, NodeList**); Node* stringop(Node*, NodeList**);
Type* fixmap(Type*); Type* fixmap(Type*);
Node* mapop(Node*, NodeList**); Node* mapop(Node*, NodeList**);
Type* fixchan(Type*); Type* fixchan(Type*);
Node* chanop(Node*, NodeList**); Node* chanop(Node*, NodeList**);
Node* arrayop(Node*); Node* ifacecvt(Type*, Node*, int, NodeList**);
Node* ifacecvt(Type*, Node*, int);
Node* ifaceop(Node*); Node* ifaceop(Node*);
int ifaceas(Type*, Type*, int); int ifaceas(Type*, Type*, int);
int ifaceas1(Type*, Type*, int); int ifaceas1(Type*, Type*, int);
...@@ -1011,11 +1015,11 @@ Node* arraylit(Node*, Node*, NodeList**); ...@@ -1011,11 +1015,11 @@ Node* arraylit(Node*, Node*, NodeList**);
Node* maplit(Node*, Node*, NodeList**); Node* maplit(Node*, Node*, NodeList**);
Node* selectas(Node*, Node*, NodeList**); Node* selectas(Node*, Node*, NodeList**);
Node* old2new(Node*, Type*, NodeList**); Node* old2new(Node*, Type*, NodeList**);
void addrescapes(Node*);
void heapmoves(void); void heapmoves(void);
void walkdeflist(NodeList*); void walkdeflist(NodeList*);
void walkdef(Node*); void walkdef(Node*);
void typechecklist(NodeList*, int); void typechecklist(NodeList*, int);
Node* typecheckconv(Node*, Node*, Type*, int);
Node* typecheck(Node**, int); Node* typecheck(Node**, int);
/* /*
......
...@@ -123,7 +123,8 @@ file: ...@@ -123,7 +123,8 @@ file:
{ {
if(debug['f']) if(debug['f'])
frame(1); frame(1);
fninit($4); if(nerrors == 0)
fninit($4);
if(nsyntaxerrors == 0) if(nsyntaxerrors == 0)
testdclstack(); testdclstack();
} }
...@@ -882,7 +883,7 @@ pexpr: ...@@ -882,7 +883,7 @@ pexpr:
| convtype lbrace braced_keyval_list '}' | convtype lbrace braced_keyval_list '}'
{ {
// composite expression // composite expression
$$ = nod(OCOMPOS, N, $1); $$ = nod(OCOMPLIT, N, $1);
$$->list = $3; $$->list = $3;
// If the opening brace was an LBODY, // If the opening brace was an LBODY,
...@@ -894,7 +895,7 @@ pexpr: ...@@ -894,7 +895,7 @@ pexpr:
| pexpr '{' braced_keyval_list '}' | pexpr '{' braced_keyval_list '}'
{ {
// composite expression // composite expression
$$ = nod(OCOMPOS, N, $1); $$ = nod(OCOMPLIT, N, $1);
$$->list = $3; $$->list = $3;
} }
| fnliteral | fnliteral
......
...@@ -208,11 +208,12 @@ exprfmt(Fmt *f, Node *n, int prec) ...@@ -208,11 +208,12 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->left, 0); exprfmt(f, n->left, 0);
break; break;
case OCOMPOS: case OCOMPLIT:
fmtprint(f, "<compos>"); fmtprint(f, "<compos>");
break; break;
case ODOT: case ODOT:
case ODOTPTR:
case ODOTINTER: case ODOTINTER:
case ODOTMETH: case ODOTMETH:
exprfmt(f, n->left, 7); exprfmt(f, n->left, 7);
......
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
/*
* static initialization
*/
#include "go.h" #include "go.h"
static struct static struct
......
...@@ -1209,6 +1209,14 @@ Nconv(Fmt *fp) ...@@ -1209,6 +1209,14 @@ Nconv(Fmt *fp)
goto out; goto out;
} }
if(fp->flags & FmtSign) {
if(n->type == T || n->type->etype == TNIL)
fmtprint(fp, "nil");
else
fmtprint(fp, "%#N (type %T)", n, n->type);
goto out;
}
if(fp->flags & FmtSharp) { if(fp->flags & FmtSharp) {
exprfmt(fp, n, 0); exprfmt(fp, n, 0);
goto out; goto out;
...@@ -1593,22 +1601,7 @@ eqtype(Type *t1, Type *t2) ...@@ -1593,22 +1601,7 @@ eqtype(Type *t1, Type *t2)
int int
cvttype(Type *dst, Type *src) cvttype(Type *dst, Type *src)
{ {
Sym *ds, *ss; return eqtype1(dst, src, 0, 0);
int ret;
if(eqtype1(dst, src, 0, 0))
return 1;
// Can convert if assignment compatible when
// top-level names are ignored.
ds = dst->sym;
dst->sym = nil;
ss = src->sym;
src->sym = nil;
ret = ascompat(dst, src);
dst->sym = ds;
src->sym = ss;
return ret == 1;
} }
int int
...@@ -1746,6 +1739,7 @@ noconv(Type *t1, Type *t2) ...@@ -1746,6 +1739,7 @@ noconv(Type *t1, Type *t2)
void void
argtype(Node *on, Type *t) argtype(Node *on, Type *t)
{ {
dowidth(t);
if(!subtype(&on->type, t, 0)) if(!subtype(&on->type, t, 0))
fatal("argtype: failed %N %T\n", on, t); fatal("argtype: failed %N %T\n", on, t);
} }
...@@ -2274,7 +2268,7 @@ saferef(Node *n, NodeList **init) ...@@ -2274,7 +2268,7 @@ saferef(Node *n, NodeList **init)
r = nod(OXXX, N, N); r = nod(OXXX, N, N);
*r = *n; *r = *n;
r->left = l; r->left = l;
typecheck(&r, Elv); typecheck(&r, Erv);
walkexpr(&r, init); walkexpr(&r, init);
return r; return r;
...@@ -2288,7 +2282,7 @@ saferef(Node *n, NodeList **init) ...@@ -2288,7 +2282,7 @@ saferef(Node *n, NodeList **init)
walkexpr(&a, init); walkexpr(&a, init);
*init = list(*init, a); *init = list(*init, a);
r = nod(OIND, l, N); r = nod(OIND, l, N);
typecheck(&r, Elv); typecheck(&r, Erv);
walkexpr(&r, init); walkexpr(&r, init);
return r; return r;
} }
......
...@@ -2,12 +2,35 @@ ...@@ -2,12 +2,35 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
/*
* type check the whole tree of an expression.
* calculates expression types.
* evaluates compile time constants.
* marks variables that escape the local frame.
* rewrites n->op to be more specific in some cases.
* sets n->walk to walking function.
*
* TODO:
* trailing ... section of function calls
* statements
*/
#include "go.h" #include "go.h"
static void implicitstar(Node**); static void implicitstar(Node**);
static int onearg(Node*); static int onearg(Node*);
static int lookdot(Node*, Type*); static int lookdot(Node*, Type*);
static int convert(Node**, Type*, int); static void typecheckaste(int, Type*, NodeList*);
static int exportassignok(Type*);
static Type* lookdot1(Sym *s, Type *t, Type *f);
static int nokeys(NodeList*);
static void typecheckcomplit(Node**);
static void addrescapes(Node*);
static void checklvalue(Node*, char*);
static void checkassign(Node*);
static void checkassignlist(NodeList*);
static int islvalue(Node*);
void void
typechecklist(NodeList *l, int top) typechecklist(NodeList *l, int top)
...@@ -17,26 +40,23 @@ typechecklist(NodeList *l, int top) ...@@ -17,26 +40,23 @@ typechecklist(NodeList *l, int top)
} }
/* /*
* type check the whole tree of an expression. * type check node *np.
* calculates expression types.
* evaluates compile time constants.
* marks variables that escape the local frame.
* rewrites n->op to be more specific in some cases.
* replaces *np with a new pointer in some cases. * replaces *np with a new pointer in some cases.
* returns the final value of *np as a convenience. * returns the final value of *np as a convenience.
*/ */
Node* Node*
typecheck(Node **np, int top) typecheck(Node **np, int top)
{ {
int et, op, nerr, len; int et, op;
NodeList *ll;
Node *n, *l, *r; Node *n, *l, *r;
NodeList *args; NodeList *args;
int i, lno, ok; int lno, ok;
Type *t; Type *t;
n = *np; n = *np;
if(n == N || n->typecheck == 1) if(n == N)
return N;
if(n->typecheck == 1 && n->op != ONAME) // XXX for test/func4.go
return n; return n;
if(n->typecheck == 2) if(n->typecheck == 2)
fatal("typecheck loop"); fatal("typecheck loop");
...@@ -63,7 +83,7 @@ reswitch: ...@@ -63,7 +83,7 @@ reswitch:
goto ret; goto ret;
case ONONAME: case ONONAME:
ok |= Elv | Erv; ok |= Erv;
goto ret; goto ret;
case ONAME: case ONAME:
...@@ -72,8 +92,6 @@ reswitch: ...@@ -72,8 +92,6 @@ reswitch:
goto error; goto error;
} }
ok |= Erv; ok |= Erv;
if(n->class != PFUNC)
ok |= Elv;
goto ret; goto ret;
/* /*
...@@ -187,7 +205,7 @@ reswitch: ...@@ -187,7 +205,7 @@ reswitch:
* type or expr * type or expr
*/ */
case OIND: case OIND:
l = typecheck(&n->left, top | Etype); l = typecheck(&n->left, Erv | Etype);
if((t = l->type) == T) if((t = l->type) == T)
goto error; goto error;
if(l->op == OTYPE) { if(l->op == OTYPE) {
...@@ -198,9 +216,10 @@ reswitch: ...@@ -198,9 +216,10 @@ reswitch:
goto ret; goto ret;
} }
if(!isptr[t->etype]) { if(!isptr[t->etype]) {
yyerror("invalid indirect %#N (non-pointer type %T)", n, t); yyerror("invalid indirect of %+N", n);
goto error; goto error;
} }
ok |= Erv;
n->type = t->type; n->type = t->type;
goto ret; goto ret;
...@@ -209,7 +228,8 @@ reswitch: ...@@ -209,7 +228,8 @@ reswitch:
*/ */
case OASOP: case OASOP:
ok |= Etop; ok |= Etop;
l = typecheck(&n->left, Elv); l = typecheck(&n->left, Erv);
checkassign(n->left);
r = typecheck(&n->right, Erv); r = typecheck(&n->right, Erv);
if(l->type == T || r->type == T) if(l->type == T || r->type == T)
goto error; goto error;
...@@ -280,6 +300,19 @@ reswitch: ...@@ -280,6 +300,19 @@ reswitch:
n->right = r; n->right = r;
} }
} }
if(et == TSTRING) {
if(iscmp[n->op]) {
n->etype = n->op;
n->op = OCMPSTR;
} else if(n->op == OASOP)
n->op = OAPPENDSTR;
else if(n->op == OADD)
n->op = OADDSTR;
}
if(et == TINTER) {
n->etype = n->op;
n->op = OCMPIFACE;
}
n->type = t; n->type = t;
goto ret; goto ret;
...@@ -315,73 +348,29 @@ reswitch: ...@@ -315,73 +348,29 @@ reswitch:
* exprs * exprs
*/ */
case OADDR: case OADDR:
typecheck(&n->left, Elv); typecheck(&n->left, Erv);
if(n->left->type == T)
goto error;
switch(n->left->op) {
case OMAPLIT:
case OSTRUCTLIT:
case OARRAYLIT:
break;
default:
checklvalue(n->left, "take the address of");
}
defaultlit(&n->left, T); defaultlit(&n->left, T);
l = n->left; l = n->left;
if((t = l->type) == T) if((t = l->type) == T)
goto error; goto error;
addrescapes(n->left);
n->type = ptrto(t); n->type = ptrto(t);
goto ret; goto ret;
case OCOMPOS: case OCOMPLIT:
l = typecheck(&n->right /* sic */, Etype /* TODO | Edotarray */); typecheckcomplit(&n);
if((t = l->type) == T) if(n->type == T)
goto error;
nerr = nerrors;
switch(t->etype) {
case TARRAY:
len = 0;
i = 0;
for(ll=n->list; ll; ll=ll->next) {
l = ll->n;
if(l->op == OKEY) {
typecheck(&l->left, Erv);
evconst(l->left);
i = nonnegconst(l->left);
typecheck(&l->right, Erv);
defaultlit(&l->right, t->type);
// TODO more forceful conversion of l->right
} else {
typecheck(&ll->n, Erv);
defaultlit(&ll->n, t->type);
// TODO more forceful conversion
}
i++;
if(i > len) {
len = i;
if(t->bound >= 0 && len > t->bound) {
setlineno(l);
yyerror("array index out of bounds");
t->bound = -1; // no more errors
}
}
}
if(t->bound == -100)
t->bound = len;
break;
case TMAP:
for(ll=n->list; ll; ll=ll->next) {
l = ll->n;
if(l->op != OKEY) {
yyerror("missing key in map literal");
continue;
}
typecheck(&l->left, Erv);
typecheck(&l->right, Erv);
defaultlit(&l->left, t->down);
defaultlit(&l->right, t->type);
// TODO more forceful
}
break;
case TSTRUCT:
// fatal("compos %T", t);
;
}
if(nerr != nerrors)
goto error; goto error;
n->type = t;
goto ret; goto ret;
case ODOT: case ODOT:
...@@ -399,7 +388,7 @@ reswitch: ...@@ -399,7 +388,7 @@ reswitch:
n->op = ODOTPTR; n->op = ODOTPTR;
} }
if(!lookdot(n, t)) { if(!lookdot(n, t)) {
yyerror("%#N undefined (%S in type %T)", n, n->right->sym, t); yyerror("%#N undefined (type %T has no field %S)", n, t, n->right->sym);
goto error; goto error;
} }
switch(n->op) { switch(n->op) {
...@@ -409,7 +398,6 @@ reswitch: ...@@ -409,7 +398,6 @@ reswitch:
break; break;
default: default:
ok |= Erv; ok |= Erv;
// TODO ok |= Elv sometimes
break; break;
} }
goto ret; goto ret;
...@@ -448,24 +436,24 @@ reswitch: ...@@ -448,24 +436,24 @@ reswitch:
goto error; goto error;
case TARRAY: case TARRAY:
ok |= Erv | Elv; ok |= Erv;
defaultlit(&n->right, types[TUINT]); defaultlit(&n->right, types[TUINT]);
n->type = t->type; n->type = t->type;
break; break;
case TMAP: case TMAP:
n->etype = 0; n->etype = 0;
if(top & Elv) ok |= Erv;
n->etype = 1; // clumsy hack
ok |= Erv | Elv;
defaultlit(&n->right, t->down); defaultlit(&n->right, t->down);
n->type = t->type; n->type = t->type;
n->op = OINDEXMAP;
break; break;
case TSTRING: case TSTRING:
ok |= Erv; ok |= Erv;
defaultlit(&n->right, types[TUINT]); defaultlit(&n->right, types[TUINT]);
n->type = types[TUINT8]; n->type = types[TUINT8];
n->op = OINDEXSTR;
break; break;
} }
goto ret; goto ret;
...@@ -477,11 +465,11 @@ reswitch: ...@@ -477,11 +465,11 @@ reswitch:
if((t = l->type) == T) if((t = l->type) == T)
goto error; goto error;
if(t->etype != TCHAN) { if(t->etype != TCHAN) {
yyerror("invalid operation: %#N (recv from non-chan type %T)", n, t); yyerror("invalid operation: %#N (receive from non-chan type %T)", n, t);
goto error; goto error;
} }
if(!(t->chan & Crecv)) { if(!(t->chan & Crecv)) {
yyerror("invalid operation: %#N (recv from send-only type %T)", n, t); yyerror("invalid operation: %#N (receive from send-only type %T)", n, t);
goto error; goto error;
} }
n->type = t->type; n->type = t->type;
...@@ -496,7 +484,7 @@ reswitch: ...@@ -496,7 +484,7 @@ reswitch:
if((t = l->type) == T) if((t = l->type) == T)
goto error; goto error;
if(!(t->chan & Csend)) { if(!(t->chan & Csend)) {
yyerror("invalid operation: %#N (send to recv-only type %T)", n, t); yyerror("invalid operation: %#N (send to receive-only type %T)", n, t);
goto error; goto error;
} }
defaultlit(&n->right, t->type); defaultlit(&n->right, t->type);
...@@ -506,7 +494,7 @@ reswitch: ...@@ -506,7 +494,7 @@ reswitch:
// TODO: more aggressive // TODO: more aggressive
n->etype = 0; n->etype = 0;
if(top & Erv) if(top & Erv)
n->etype = 1; // clumsy hack n->op = OSENDNB;
ok |= Etop | Erv; ok |= Etop | Erv;
n->type = types[TBOOL]; n->type = types[TBOOL];
goto ret; goto ret;
...@@ -527,13 +515,13 @@ reswitch: ...@@ -527,13 +515,13 @@ reswitch:
if((t = n->right->left->type) == T) if((t = n->right->left->type) == T)
goto error; goto error;
if(!isint[t->etype]) { if(!isint[t->etype]) {
yyerror("invalid array index %#N (type %T)", n->right->left, t); yyerror("invalid slice index %#N (type %T)", n->right->left, t);
goto error; goto error;
} }
if((t = n->right->right->type) == T) if((t = n->right->right->type) == T)
goto error; goto error;
if(!isint[t->etype]) { if(!isint[t->etype]) {
yyerror("invalid array index %#N (type %T)", n->right->right, t); yyerror("invalid slice index %#N (type %T)", n->right->right, t);
goto error; goto error;
} }
l = n->left; l = n->left;
...@@ -541,24 +529,25 @@ reswitch: ...@@ -541,24 +529,25 @@ reswitch:
goto error; goto error;
// TODO(rsc): 64-bit slice index needs to be checked // TODO(rsc): 64-bit slice index needs to be checked
// for overflow in generated code // for overflow in generated code
switch(t->etype) { if(istype(t, TSTRING)) {
default: n->type = t;
yyerror("invalid operation: %#N (slice of type %T)", n, t); n->op = OSLICESTR;
goto error; goto ret;
}
case TARRAY: if(isfixedarray(t)) {
n->type = typ(TARRAY); n->type = typ(TARRAY);
n->type->type = t; n->type->type = t->type;
n->type->bound = -1; n->type->bound = -1;
n = arrayop(n); dowidth(n->type);
break; n->op = OSLICEARR;
goto ret;
case TSTRING: }
if(isslice(t)) {
n->type = t; n->type = t;
n = stringop(n, nil); goto ret;
break;
} }
goto ret; yyerror("cannot slice %#N (type %T)", l, t);
goto error;
/* /*
* call and call like * call and call like
...@@ -572,14 +561,16 @@ reswitch: ...@@ -572,14 +561,16 @@ reswitch:
n->right = N; n->right = N;
goto reswitch; goto reswitch;
} }
l = typecheck(&n->left, Erv | Etype | Ecall); typecheck(&n->left, Erv | Etype | Ecall);
defaultlit(&n->left, T);
l = n->left;
typechecklist(n->list, Erv); typechecklist(n->list, Erv);
if((t = l->type) == T) if((t = l->type) == T)
{
yyerror("skip %#N", n);
goto error; goto error;
} dowidth(t);
if(l->op == OTYPE) {
switch(l->op) {
case OTYPE:
ok |= Erv; ok |= Erv;
// turn CALL(type, arg) into CONV(arg) w/ type // turn CALL(type, arg) into CONV(arg) w/ type
n->left = N; n->left = N;
...@@ -588,8 +579,25 @@ yyerror("skip %#N", n); ...@@ -588,8 +579,25 @@ yyerror("skip %#N", n);
n->op = OCONV; n->op = OCONV;
n->type = l->type; n->type = l->type;
goto doconv; goto doconv;
case ODOTINTER:
n->op = OCALLINTER;
break;
case ODOTMETH:
n->op = OCALLMETH;
typecheckaste(OCALL, getthisx(t), list1(l->left));
break;
default:
n->op = OCALLFUNC;
if(t->etype != TFUNC) {
yyerror("cannot call non-function %#N (type %T)", l, t);
goto error;
}
break;
} }
// TODO: check args typecheckaste(OCALL, getinargx(t), n->list);
if(t->outtuple == 0) { if(t->outtuple == 0) {
ok |= Etop; ok |= Etop;
goto ret; goto ret;
...@@ -642,9 +650,7 @@ yyerror("skip %#N", n); ...@@ -642,9 +650,7 @@ yyerror("skip %#N", n);
goto ret; goto ret;
case OCLOSED: case OCLOSED:
ok |= Erv;
case OCLOSE: case OCLOSE:
ok |= Etop;
if(onearg(n) < 0) if(onearg(n) < 0)
goto error; goto error;
typecheck(&n->left, Erv); typecheck(&n->left, Erv);
...@@ -656,25 +662,22 @@ yyerror("skip %#N", n); ...@@ -656,25 +662,22 @@ yyerror("skip %#N", n);
yyerror("invalid operation: %#N (non-chan type %T)", n, t); yyerror("invalid operation: %#N (non-chan type %T)", n, t);
goto error; goto error;
} }
if(n->op == OCLOSED) if(n->op == OCLOSED) {
n->type = types[TBOOL]; n->type = types[TBOOL];
ok |= Erv;
} else
ok |= Etop;
goto ret; goto ret;
case OCONV: case OCONV:
doconv: doconv:
typecheck(&n->left, Erv); typecheck(&n->left, Erv);
defaultlit(&n->left, n->type); defaultlit(&n->left, n->type);
if((t = n->left->type) == T) if((t = n->left->type) == T || n->type == T)
goto error; goto error;
switch(convert(&n->left, n->type, 1)) { n = typecheckconv(n, n->left, n->type, 1);
case -1: if(n->type == T)
goto error; goto error;
case 0:
n = n->left;
break;
case OCONV:
break;
}
goto ret; goto ret;
case OMAKE: case OMAKE:
...@@ -723,8 +726,11 @@ yyerror("skip %#N", n); ...@@ -723,8 +726,11 @@ yyerror("skip %#N", n);
yyerror("non-integer cap argument to make(%T)", t); yyerror("non-integer cap argument to make(%T)", t);
goto error; goto error;
} }
if(r == N)
r = nodintconst(0);
n->left = l; n->left = l;
n->right = r; n->right = r;
n->op = OMAKESLICE;
break; break;
case TMAP: case TMAP:
...@@ -740,7 +746,9 @@ yyerror("skip %#N", n); ...@@ -740,7 +746,9 @@ yyerror("skip %#N", n);
goto error; goto error;
} }
n->left = l; n->left = l;
} } else
n->left = nodintconst(0);
n->op = OMAKEMAP;
break; break;
case TCHAN: case TCHAN:
...@@ -757,11 +765,14 @@ yyerror("skip %#N", n); ...@@ -757,11 +765,14 @@ yyerror("skip %#N", n);
goto error; goto error;
} }
n->left = l; n->left = l;
} } else
n->left = nodintconst(0);
n->op = OMAKECHAN;
break; break;
} }
if(args != nil) { if(args != nil) {
yyerror("too many arguments to make(%T)", t); yyerror("too many arguments to make(%T)", t);
n->op = OMAKE;
goto error; goto error;
} }
n->type = t; n->type = t;
...@@ -796,12 +807,16 @@ yyerror("skip %#N", n); ...@@ -796,12 +807,16 @@ yyerror("skip %#N", n);
* statements * statements
*/ */
case OAS: case OAS:
typecheck(&n->left, Elv); typecheck(&n->left, Erv);
checkassign(n->left);
typecheck(&n->right, Erv); typecheck(&n->right, Erv);
if(n->left->type != T && n->right && n->right->type != T)
n->right = typecheckconv(nil, n->right, n->left->type, 0);
goto ret; goto ret;
case OAS2: case OAS2:
typechecklist(n->list, Elv); typechecklist(n->list, Erv);
checkassignlist(n->list);
typechecklist(n->rlist, Erv); typechecklist(n->rlist, Erv);
goto ret; goto ret;
...@@ -835,7 +850,9 @@ yyerror("skip %#N", n); ...@@ -835,7 +850,9 @@ yyerror("skip %#N", n);
case ORETURN: case ORETURN:
typechecklist(n->list, Erv); typechecklist(n->list, Erv);
// TODO convert if(curfn->type->outnamed && n->list == nil)
goto ret;
typecheckaste(ORETURN, getoutargx(curfn->type), n->list);
goto ret; goto ret;
case OSELECT: case OSELECT:
...@@ -851,7 +868,7 @@ yyerror("skip %#N", n); ...@@ -851,7 +868,7 @@ yyerror("skip %#N", n);
goto ret; goto ret;
case OTYPECASE: case OTYPECASE:
typecheck(&n->left, Elv); typecheck(&n->left, Erv);
goto ret; goto ret;
case OTYPESW: case OTYPESW:
...@@ -870,7 +887,7 @@ ret: ...@@ -870,7 +887,7 @@ ret:
yyerror("type %T is not an expression", n->type); yyerror("type %T is not an expression", n->type);
goto error; goto error;
} }
if((top & (Elv|Erv|Etype)) == Etype && n->op != OTYPE) { if((top & (Erv|Etype)) == Etype && n->op != OTYPE) {
yyerror("%O is not a type", n->op); yyerror("%O is not a type", n->op);
goto error; goto error;
} }
...@@ -982,7 +999,7 @@ lookdot(Node *n, Type *t) ...@@ -982,7 +999,7 @@ lookdot(Node *n, Type *t)
if(t->etype == TINTER) { if(t->etype == TINTER) {
if(isptr[n->left->type->etype]) { if(isptr[n->left->type->etype]) {
n->left = nod(OIND, n->left, N); // implicitstar n->left = nod(OIND, n->left, N); // implicitstar
typecheck(&n->left, Elv); typecheck(&n->left, Erv);
} }
n->op = ODOTINTER; n->op = ODOTINTER;
} }
...@@ -994,7 +1011,8 @@ lookdot(Node *n, Type *t) ...@@ -994,7 +1011,8 @@ lookdot(Node *n, Type *t)
rcvr = getthisx(f2->type)->type->type; rcvr = getthisx(f2->type)->type->type;
if(!eqtype(rcvr, tt)) { if(!eqtype(rcvr, tt)) {
if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) { if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
typecheck(&n->left, Elv); typecheck(&n->left, Erv);
checklvalue(n->left, "call pointer method on");
addrescapes(n->left); addrescapes(n->left);
n->left = nod(OADDR, n->left, N); n->left = nod(OADDR, n->left, N);
typecheck(&n->left, Erv); typecheck(&n->left, Erv);
...@@ -1016,104 +1034,624 @@ lookdot(Node *n, Type *t) ...@@ -1016,104 +1034,624 @@ lookdot(Node *n, Type *t)
return 0; return 0;
} }
/*
* try to convert *np to t.
* explicit means conversion like int64(n).
* not explicit means assignment, return, or function call parameter.
* return -1 for failure, 0 if OCONV node not needed, 1 if OCONV is needed.
*/
static int static int
convert(Node **np, Type *t, int explicit) nokeys(NodeList *l)
{ {
int et; for(; l; l=l->next)
Node *n, *n1; if(l->n->op == OKEY)
Type *tt; return 0;
return 1;
}
n = *np; Node*
typecheckconv(Node *nconv, Node *n, Type *t, int explicit)
{
int et, op;
Node *n1;
if(n->type == t) op = OCONV;
return 0; et = 0;
if(eqtype(n->type, t)) // preexisting error
return OCONV; if(t == T || t->etype == TFORW)
return n;
/*
* implicit conversions
*/
// XXX wtf?
convlit1(&n, t, explicit); convlit1(&n, t, explicit);
if(n->type == T) if(n->type == T)
return -1; return n;
if(eqtype(t, n->type)) {
exportassignok(t);
op = OCONVNOP;
if(!explicit || t == n->type)
return n;
goto conv;
}
// interfaces are not subject to the name restrictions below.
// accept anything involving interfaces and let walkiface
// generate a good message. some messages have to be
// delayed anyway.
if(isnilinter(t) || isnilinter(n->type) || isinter(t) || isinter(n->type)) {
et = ifaceas1(t, n->type, 0);
op = OCONVIFACE;
goto conv;
}
// otherwise, if concrete types have names, they must match.
if(!explicit && t->sym && n->type->sym && t != n->type)
goto badimplicit;
// channel must not lose directionality
if(t->etype == TCHAN && n->type->etype == TCHAN) {
if(t->chan & ~n->type->chan) {
if(!explicit)
goto badimplicit;
goto badexplicit;
}
if(eqtype(t->type, n->type->type)) {
op = OCONVNOP;
goto conv;
}
}
// no-op conversion // array to slice
if(cvttype(t, n->type) == 1) { if(isslice(t) && isptr[n->type->etype] && isfixedarray(n->type->type)
&& eqtype(t->type, n->type->type->type)) {
op = OCONVSLICE;
goto conv;
}
if(!explicit) {
badimplicit:
yyerror("cannot use %+N as type %T", n, t);
n = nod(OCONV, n, N); // leave type == T
n->typecheck = 1;
return n;
}
/*
* explicit conversions
*/
// same representation
if(cvttype(t, n->type)) {
if(n->op == OLITERAL) { if(n->op == OLITERAL) {
// can convert literal in place // can convert literal in place
n1 = nod(OXXX, N, N); n1 = nod(OXXX, N, N);
*n1 = *n; *n1 = *n;
n1->type = t; n1->type = t;
*np = n1; return n1;
return 0;
} }
return OCONV; op = OCONVNOP;
} goto conv;
if(!explicit) {
yyerror("cannot use %#N (type %T) as type %T", n, n->type, t);
return -1;
} }
// simple fix-float // simple fix-float
if(isint[n->type->etype] || isfloat[n->type->etype]) if(isint[t->etype] || isfloat[t->etype])
if(isint[t->etype] || isfloat[t->etype]) { if(isint[n->type->etype] || isfloat[n->type->etype]) {
// evconst(n); // XXX is this needed? // evconst(n); // XXX is this needed?
return OCONV; goto conv;
}
// to/from interface.
// ifaceas1 will generate a good error if the conversion fails.
if(t->etype == TINTER || n->type->etype == TINTER) {
n = ifacecvt(t, n, ifaceas1(t, n->type, 0));
n->type = t;
*np = n;
return 0;
} }
// to string // to string
if(istype(t, TSTRING)) { if(istype(t, TSTRING)) {
// integer rune // integer rune
et = n->type->etype; if(isint[n->type->etype]) {
if(isint[et]) { op = ORUNESTR;
// xxx; goto conv;
return OCONVRUNE; }
// *[10]byte -> string? convert *[10]byte -> []byte
// in preparation for next step
if(isptr[n->type->etype] && isfixedarray(n->type->type)) {
switch(n->type->type->type->etype) {
case TUINT8:
case TINT:
n1 = nod(OCONV, n, N);
n1->type = typ(TARRAY);
n1->type->bound = -1;
n1->type->type = n->type->type->type;
dowidth(n1->type);
typecheck(&n1, Erv);
walkexpr(&n1, nil);
n = n1;
break;
}
} }
// []byte and *[10]byte -> string // []byte -> string
tt = T; if(isslice(n->type)) {
if(isptr[et] && isfixedarray(n->type->type)) switch(n->type->type->etype) {
tt = n->type->type->type; case TUINT8:
else if(isslice(n->type)) op = OARRAYBYTESTR;
tt = n->type->type; goto conv;
if(tt) { case TINT:
if(tt->etype == TUINT8) op = OARRAYRUNESTR;
return OCONVSTRB; goto conv;
if(tt->etype == TINT) }
return OCONVSTRI;
} }
} }
// convert static array to slice
if(isslice(t) && isptr[n->type->etype] && isfixedarray(n->type->type)
&& eqtype(t->type, n->type->type->type))
return OCONVA2S;
// convert to unsafe pointer // convert to unsafe pointer
if(isptrto(t, TANY) if(isptrto(t, TANY)
&& (isptr[n->type->etype] || n->type->etype == TUINTPTR)) && (isptr[n->type->etype] || n->type->etype == TUINTPTR))
return OCONV; goto conv;
// convert from unsafe pointer // convert from unsafe pointer
if(isptrto(n->type, TANY) if(isptrto(n->type, TANY)
&& (isptr[t->etype] || t->etype == TUINTPTR)) && (isptr[t->etype] || t->etype == TUINTPTR))
return OCONV; goto conv;
badexplicit:
yyerror("cannot convert %+N to type %T", n, t);
nconv->type = T;
return nconv;
conv:
if(nconv == nil) {
nconv = nod(OXXX, n, N);
nconv->type = t;
nconv->typecheck = 1;
}
nconv->etype = et;
nconv->op = op;
return nconv;
}
/*
* typecheck assignment: type list = type list
*/
static void
typecheckastt(int op, Type *t1, Type *t2)
{
for(t1=t1->type, t2=t2->type; t1; t1=t1->down, t2=t2->down) {
if(t2 == nil) {
yyerror("too few");
return;
}
if(!eqtype(t1->type, t2->type)) {
yyerror("wrong");
}
}
if(t2 != nil)
yyerror("too many");
}
/*
* typecheck assignment: type list = expression list
*/
static void
typecheckaste(int op, Type *tstruct, NodeList *nl)
{
Type *t, *tl;
Node *n;
if(nl != nil && nl->next == nil && nl->n->type != T && nl->n->type->etype == TSTRUCT && nl->n->type->funarg) {
typecheckastt(op, tstruct, nl->n->type);
return;
}
for(tl=tstruct->type; tl; tl=tl->down) {
t = tl->type;
if(isddd(t)) {
for(; nl; nl=nl->next)
defaultlit(&nl->n, T);
return;
}
if(nl == nil) {
yyerror("not enough arguments to %#O", op);
return;
}
n = nl->n;
if(n->type != T)
nl->n = typecheckconv(nil, n, t, 0);
nl = nl->next;
}
if(nl != nil) {
yyerror("too many arguments to %#O", op);
return;
}
}
/*
* do the export rules allow writing to this type?
* cannot be implicitly assigning to any type with
* an unavailable field.
*/
static int
exportassignok(Type *t)
{
Type *f;
Sym *s;
if(t == T)
return 1;
switch(t->etype) {
default:
// most types can't contain others; they're all fine.
break;
case TSTRUCT:
for(f=t->type; f; f=f->down) {
if(f->etype != TFIELD)
fatal("structas: not field");
s = f->sym;
// s == nil doesn't happen for embedded fields (they get the type symbol).
// it only happens for fields in a ... struct.
if(s != nil && !exportname(s->name) && strcmp(package, s->package) != 0) {
yyerror("implicit assignment of %T field '%s'", t, s->name);
return 0;
}
if(!exportassignok(f->type))
return 0;
}
break;
case TARRAY:
if(t->bound < 0) // slices are pointers; that's fine
break;
if(!exportassignok(t->type))
return 0;
break;
}
return 1;
}
/*
* type check composite
*/
static void
fielddup(Node *n, Node *hash[], ulong nhash)
{
uint h;
char *s;
Node *a;
if(n->op != ONAME)
fatal("fielddup: not ONAME");
s = n->sym->name;
h = stringhash(s)%nhash;
for(a=hash[h]; a!=N; a=a->ntest) {
if(strcmp(a->sym->name, s) == 0) {
yyerror("duplicate field name in struct literal: %s", s);
return;
}
}
n->ntest = hash[h];
hash[h] = n;
}
static void
keydup(Node *n, Node *hash[], ulong nhash)
{
uint h;
ulong b;
double d;
int i;
Node *a;
Node cmp;
char *s;
evconst(n);
if(n->op != OLITERAL)
return; // we dont check variables
switch(n->val.ctype) {
default: // unknown, bool, nil
b = 23;
break;
case CTINT:
b = mpgetfix(n->val.u.xval);
break;
case CTFLT:
d = mpgetflt(n->val.u.fval);
s = (char*)&d;
b = 0;
for(i=sizeof(d); i>0; i--)
b = b*PRIME1 + *s++;
break;
case CTSTR:
b = 0;
s = n->val.u.sval->s;
for(i=n->val.u.sval->len; i>0; i--)
b = b*PRIME1 + *s++;
break;
}
h = b%nhash;
memset(&cmp, 0, sizeof(cmp));
for(a=hash[h]; a!=N; a=a->ntest) {
cmp.op = OEQ;
cmp.left = n;
cmp.right = a;
evconst(&cmp);
b = cmp.val.u.bval;
if(b) {
// too lazy to print the literal
yyerror("duplicate key in map literal");
return;
}
}
n->ntest = hash[h];
hash[h] = n;
}
yyerror("cannot convert %#N (type %T) to type %T", n, n->type, t); static void
return -1; indexdup(Node *n, Node *hash[], ulong nhash)
{
uint h;
Node *a;
ulong b, c;
if(n->op != OLITERAL)
fatal("indexdup: not OLITERAL");
b = mpgetfix(n->val.u.xval);
h = b%nhash;
for(a=hash[h]; a!=N; a=a->ntest) {
c = mpgetfix(a->val.u.xval);
if(b == c) {
yyerror("duplicate index in array literal: %ld", b);
return;
}
}
n->ntest = hash[h];
hash[h] = n;
}
static void
typecheckcomplit(Node **np)
{
int bad, i, len, nerr;
Node *l, *n, *hash[101];
NodeList *ll;
Type *t, *f;
n = *np;
memset(hash, 0, sizeof hash);
// TODO: dup detection
l = typecheck(&n->right /* sic */, Etype /* TODO | Edotarray */);
if((t = l->type) == T)
goto error;
nerr = nerrors;
switch(t->etype) {
default:
yyerror("invalid type for composite literal: %T", t);
n->type = T;
break;
case TARRAY:
len = 0;
i = 0;
for(ll=n->list; ll; ll=ll->next) {
l = ll->n;
if(l->op == OKEY) {
typecheck(&l->left, Erv);
evconst(l->left);
i = nonnegconst(l->left);
if(i < 0) {
yyerror("array index must be non-negative integer constant");
i = -(1<<30); // stay negative for a while
}
typecheck(&l->right, Erv);
defaultlit(&l->right, t->type);
l->right = typecheckconv(nil, l->right, t->type, 0);
} else {
typecheck(&ll->n, Erv);
defaultlit(&ll->n, t->type);
ll->n = typecheckconv(nil, ll->n, t->type, 0);
ll->n = nod(OKEY, nodintconst(i), ll->n);
ll->n->left->type = types[TINT];
ll->n->left->typecheck = 1;
}
if(i >= 0)
indexdup(ll->n->left, hash, nelem(hash));
i++;
if(i > len) {
len = i;
if(t->bound >= 0 && len > t->bound) {
setlineno(l);
yyerror("array index out of bounds");
t->bound = -1; // no more errors
}
}
}
if(t->bound == -100)
t->bound = len;
if(t->bound < 0)
n->right = nodintconst(len);
n->op = OARRAYLIT;
break;
case TMAP:
for(ll=n->list; ll; ll=ll->next) {
l = ll->n;
if(l->op != OKEY) {
typecheck(&ll->n, Erv);
yyerror("missing key in map literal");
continue;
}
typecheck(&l->left, Erv);
typecheck(&l->right, Erv);
defaultlit(&l->left, t->down);
defaultlit(&l->right, t->type);
l->left = typecheckconv(nil, l->left, t->down, 0);
l->right = typecheckconv(nil, l->right, t->type, 0);
keydup(l->left, hash, nelem(hash));
}
n->op = OMAPLIT;
break;
case TSTRUCT:
bad = 0;
if(n->list != nil && nokeys(n->list)) {
// simple list of variables
f = t->type;
for(ll=n->list; ll; ll=ll->next) {
typecheck(&ll->n, Erv);
if(f == nil) {
if(!bad++)
yyerror("too many values in struct initializer");
continue;
}
ll->n = typecheckconv(nil, ll->n, f->type, 0);
ll->n = nod(OKEY, newname(f->sym), ll->n);
ll->n->left->typecheck = 1;
f = f->down;
}
} else {
// keyed list
for(ll=n->list; ll; ll=ll->next) {
l = ll->n;
if(l->op != OKEY) {
if(!bad++)
yyerror("mixture of field:value and value initializers");
typecheck(&ll->n, Erv);
continue;
}
if(l->left->sym == S) {
yyerror("invalid field name %#N in struct initializer", l->left);
typecheck(&l->right, Erv);
continue;
}
l->left->typecheck = 1;
f = lookdot1(l->left->sym, t, t->type);
typecheck(&l->right, Erv);
if(f == nil)
continue;
fielddup(newname(f->sym), hash, nelem(hash));
l->right = typecheckconv(nil, l->right, f->type, 0);
}
}
n->op = OSTRUCTLIT;
break;
}
if(nerr != nerrors)
goto error;
n->type = t;
*np = n;
return;
error:
n->type = T;
*np = n;
}
/*
* the address of n has been taken and might be used after
* the current function returns. mark any local vars
* as needing to move to the heap.
*/
static void
addrescapes(Node *n)
{
char buf[100];
switch(n->op) {
default:
// probably a type error already.
// dump("addrescapes", n);
break;
case ONAME:
if(n->noescape)
break;
switch(n->class) {
case PPARAMOUT:
yyerror("cannot take address of out parameter %s", n->sym->name);
break;
case PAUTO:
case PPARAM:
// if func param, need separate temporary
// to hold heap pointer.
if(n->class == PPARAM) {
// expression to refer to stack copy
n->stackparam = nod(OPARAM, n, N);
n->stackparam->type = n->type;
n->stackparam->addable = 1;
n->stackparam->xoffset = n->xoffset;
}
n->class |= PHEAP;
n->addable = 0;
n->ullman = 2;
n->alloc = callnew(n->type);
n->xoffset = 0;
// create stack variable to hold pointer to heap
n->heapaddr = nod(0, N, N);
tempname(n->heapaddr, ptrto(n->type));
snprint(buf, sizeof buf, "&%S", n->sym);
n->heapaddr->sym = lookup(buf);
break;
}
break;
case OIND:
case ODOTPTR:
break;
case ODOT:
case OINDEX:
// ODOTPTR has already been introduced,
// so these are the non-pointer ODOT and OINDEX.
// In &x[0], if x is a slice, then x does not
// escape--the pointer inside x does, but that
// is always a heap pointer anyway.
if(!isslice(n->left->type))
addrescapes(n->left);
break;
}
}
static int
islvalue(Node *n)
{
switch(n->op) {
case OINDEX:
case OIND:
case ODOTPTR:
return 1;
case ODOT:
return islvalue(n->left);
case ONAME:
if(n->class == PFUNC)
return 0;
return 1;
}
return 0;
}
static void
checklvalue(Node *n, char *verb)
{
if(!islvalue(n))
yyerror("cannot %s %#N", verb, n);
}
static void
checkassign(Node *n)
{
if(islvalue(n))
return;
if(n->op == OINDEXMAP) {
n->etype = 1;
return;
}
yyerror("cannot assign to %#N", n);
}
static void
checkassignlist(NodeList *l)
{
for(; l; l=l->next)
checkassign(l->n);
} }
...@@ -4,15 +4,13 @@ ...@@ -4,15 +4,13 @@
#include "go.h" #include "go.h"
static Node* curfn; static Node* walkprint(Node*, NodeList**);
static Node* prcompat(Node*);
static Node* mkcall(char*, Type*, NodeList**, ...); static Node* mkcall(char*, Type*, NodeList**, ...);
static Node* mkcall1(Node*, Type*, NodeList**, ...); static Node* mkcall1(Node*, Type*, NodeList**, ...);
static Node* conv(Node*, Type*); static Node* conv(Node*, Type*);
static Node* chanfn(char*, int, Type*); static Node* chanfn(char*, int, Type*);
static Node* mapfn(char*, Type*); static Node* mapfn(char*, Type*);
static Node* makenewvar(Type*, NodeList**, Node**);
enum enum
{ {
Inone, Inone,
...@@ -79,7 +77,6 @@ void ...@@ -79,7 +77,6 @@ void
walk(Node *fn) walk(Node *fn)
{ {
char s[50]; char s[50];
// int nerr;
curfn = fn; curfn = fn;
if(debug['W']) { if(debug['W']) {
...@@ -89,12 +86,9 @@ walk(Node *fn) ...@@ -89,12 +86,9 @@ walk(Node *fn)
if(curfn->type->outtuple) if(curfn->type->outtuple)
if(walkret(curfn->nbody)) if(walkret(curfn->nbody))
yyerror("function ends without a return statement"); yyerror("function ends without a return statement");
// nerr = nerrors;
typechecklist(curfn->nbody, Etop); typechecklist(curfn->nbody, Etop);
/* TODO(rsc) if(nerrors != 0)
if(nerrors != nerr)
return; return;
*/
walkstmtlist(curfn->nbody); walkstmtlist(curfn->nbody);
if(debug['W']) { if(debug['W']) {
snprint(s, sizeof(s), "after walk %S", curfn->nname->sym); snprint(s, sizeof(s), "after walk %S", curfn->nname->sym);
...@@ -223,6 +217,7 @@ walkstmt(Node **np) ...@@ -223,6 +217,7 @@ walkstmt(Node **np)
dump("nottop", n); dump("nottop", n);
break; break;
case OAPPENDSTR:
case OASOP: case OASOP:
case OAS: case OAS:
case OAS2: case OAS2:
...@@ -336,16 +331,22 @@ walkexpr(Node **np, NodeList **init) ...@@ -336,16 +331,22 @@ walkexpr(Node **np, NodeList **init)
Node *r, *l; Node *r, *l;
NodeList *ll, *lr; NodeList *ll, *lr;
Type *t; Type *t;
Sym *s;
int et, cl, cr; int et, cl, cr;
int32 lno; int32 lno;
Node *n; Node *n, *fn;
n = *np; n = *np;
if(n == N) if(n == N)
return; return;
// annoying case - not typechecked
if(n->op == OKEY) {
walkexpr(&n->left, init);
walkexpr(&n->right, init);
return;
}
lno = setlineno(n); lno = setlineno(n);
if(debug['w'] > 1) if(debug['w'] > 1)
...@@ -356,7 +357,6 @@ walkexpr(Node **np, NodeList **init) ...@@ -356,7 +357,6 @@ walkexpr(Node **np, NodeList **init)
fatal("missed typecheck"); fatal("missed typecheck");
} }
reswitch:
t = T; t = T;
et = Txxx; et = Txxx;
...@@ -367,15 +367,9 @@ reswitch: ...@@ -367,15 +367,9 @@ reswitch:
goto ret; goto ret;
case OTYPE: case OTYPE:
case OCALLMETH:
case OCALLINTER:
case OCALLFUNC:
case ONONAME: case ONONAME:
case OINDREG: case OINDREG:
case OEMPTY: case OEMPTY:
case OCONVNOP:
case OCOMPMAP:
case OCOMPSLICE:
goto ret; goto ret;
case ONOT: case ONOT:
...@@ -401,6 +395,13 @@ reswitch: ...@@ -401,6 +395,13 @@ reswitch:
case OOROR: case OOROR:
case OSUB: case OSUB:
case OMUL: case OMUL:
case OEQ:
case ONE:
case OLT:
case OLE:
case OGE:
case OGT:
case OADD:
walkexpr(&n->left, init); walkexpr(&n->left, init);
walkexpr(&n->right, init); walkexpr(&n->right, init);
goto ret; goto ret;
...@@ -410,7 +411,7 @@ reswitch: ...@@ -410,7 +411,7 @@ reswitch:
case OPANIC: case OPANIC:
case OPANICN: case OPANICN:
walkexprlist(n->list, init); walkexprlist(n->list, init);
n = prcompat(n); n = walkprint(n, init);
goto ret; goto ret;
case OLITERAL: case OLITERAL:
...@@ -420,104 +421,50 @@ reswitch: ...@@ -420,104 +421,50 @@ reswitch:
case ONAME: case ONAME:
if(!(n->class & PHEAP) && n->class != PPARAMREF) if(!(n->class & PHEAP) && n->class != PPARAMREF)
n->addable = 1; n->addable = 1;
if(n->type == T) {
s = n->sym;
if(s->undef == 0) {
if(n->etype != 0)
yyerror("walkexpr: %S must be called", s, init);
else
yyerror("walkexpr: %S undeclared", s, init);
s->undef = 1;
}
}
goto ret; goto ret;
case OCALL: case OCALLINTER:
if(n->left == N) t = n->left->type;
if(n->list && n->list->n->op == OAS)
goto ret; goto ret;
if(n->left->op == ONAME && n->left->etype != 0) {
// builtin OLEN, OCAP, etc.
n->op = n->left->etype;
n->left = N;
goto reswitch;
}
walkexpr(&n->left, init); walkexpr(&n->left, init);
defaultlit(&n->left, T); walkexprlist(n->list, init);
ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
goto ret;
case OCALLFUNC:
t = n->left->type; t = n->left->type;
if(t == T) if(n->list && n->list->n->op == OAS)
goto ret; goto ret;
walkexpr(&n->left, init);
switch(n->left->op) { walkexprlist(n->list, init);
case ODOTMETH: ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
n->op = OCALLMETH; n->list = reorder1(ll);
break; if(isselect(n)) {
case ODOTINTER: // special prob with selectsend and selectrecv:
n->op = OCALLINTER; // if chan is nil, they don't know big the channel
break; // element is and therefore don't know how to find
case OTYPE: // the output bool, so we clear it before the call.
n->op = OCONV; Node *b;
// turn CALL(type, arg) into CONV(arg) w/ type. b = nodbool(0);
n->type = n->left->type; lr = ascompatte(n->op, getoutarg(t), list1(b), 0, init);
if(n->list == nil) { n->list = concat(n->list, lr);
yyerror("missing argument in type conversion");
goto ret;
}
if(n->list->next != nil) {
yyerror("too many arguments in type conversion");
goto ret;
}
n->left = n->list->n;
n->list = nil;
goto reswitch;
default:
n->op = OCALLFUNC;
break;
} }
goto ret;
if(t->etype != TFUNC) { case OCALLMETH:
yyerror("call of a non-function: %T", t); t = n->left->type;
if(n->list && n->list->n->op == OAS)
goto ret; goto ret;
} walkexpr(&n->left, init);
dowidth(t);
walkexprlist(n->list, init); walkexprlist(n->list, init);
ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
switch(n->op) { lr = ascompatte(n->op, getthis(t), list1(n->left->left), 0, init);
default: ll = concat(ll, lr);
fatal("walk: op: %O", n->op); n->left->left = N;
ullmancalc(n->left);
case OCALLINTER: n->list = reorder1(ll);
ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
break;
case OCALLFUNC:
ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
if(isselect(n)) {
// special prob with selectsend and selectrecv:
// if chan is nil, they don't know big the channel
// element is and therefore don't know how to find
// the output bool, so we clear it before the call.
Node *b;
b = nodbool(0);
lr = ascompatte(n->op, getoutarg(t), list1(b), 0, init);
n->list = concat(n->list, lr);
}
break;
case OCALLMETH:
ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
lr = ascompatte(n->op, getthis(t), list1(n->left->left), 0, init);
ll = concat(ll, lr);
n->left->left = N;
ullmancalc(n->left);
n->list = reorder1(ll);
break;
}
goto ret; goto ret;
case OAS: case OAS:
...@@ -571,12 +518,10 @@ reswitch: ...@@ -571,12 +518,10 @@ reswitch:
} }
break; break;
case OINDEX: case OINDEXMAP:
if(cl == 2 && cr == 1) { if(cl == 2 && cr == 1) {
// a,b = map[] - mapaccess2 // a,b = map[] - mapaccess2
walkexpr(&r->left, init); walkexpr(&r->left, init);
if(!istype(r->left->type, TMAP))
break;
l = mapop(n, init); l = mapop(n, init);
if(l == N) if(l == N)
break; break;
...@@ -634,7 +579,7 @@ reswitch: ...@@ -634,7 +579,7 @@ reswitch:
} }
if(et == Inone) if(et == Inone)
break; break;
r = ifacecvt(r->type, r->left, et); r = ifacecvt(r->type, r->left, et, init);
ll = ascompatet(n->op, n->list, &r->type, 0, init); ll = ascompatet(n->op, n->list, &r->type, 0, init);
n = liststmt(concat(list1(r), ll)); n = liststmt(concat(list1(r), ll));
goto ret; goto ret;
...@@ -643,11 +588,9 @@ reswitch: ...@@ -643,11 +588,9 @@ reswitch:
} }
switch(l->op) { switch(l->op) {
case OINDEX: case OINDEXMAP:
if(cl == 1 && cr == 2) { if(cl == 1 && cr == 2) {
// map[] = a,b - mapassign2 // map[] = a,b - mapassign2
if(!istype(l->left->type, TMAP))
break;
l = mapop(n, init); l = mapop(n, init);
if(l == N) if(l == N)
break; break;
...@@ -664,42 +607,18 @@ reswitch: ...@@ -664,42 +607,18 @@ reswitch:
case ODOTTYPE: case ODOTTYPE:
walkdottype(n, init); walkdottype(n, init);
// fall through
case OCONV:
walkconv(&n, init); walkconv(&n, init);
goto ret; goto ret;
case OCOMPOS: case OCONV:
walkexpr(&n->right, init); case OCONVNOP:
t = n->right->type; walkexpr(&n->left, init);
n->type = t;
if(t == T)
goto ret;
switch(t->etype) {
default:
yyerror("invalid type for composite literal: %T", t);
goto ret;
case TSTRUCT:
r = structlit(n, N, init);
break;
case TARRAY:
r = arraylit(n, N, init);
break;
case TMAP:
r = maplit(n, N, init);
break;
}
n = r;
goto ret; goto ret;
case OASOP: case OASOP:
walkexpr(&n->left, init); walkexpr(&n->left, init);
l = n->left; l = n->left;
if(l->op == OINDEX && istype(l->left->type, TMAP)) if(l->op == OINDEXMAP)
n = mapop(n, init); n = mapop(n, init);
walkexpr(&n->right, init); walkexpr(&n->right, init);
if(n->etype == OANDNOT) { if(n->etype == OANDNOT) {
...@@ -708,11 +627,7 @@ reswitch: ...@@ -708,11 +627,7 @@ reswitch:
n->right->type = n->right->left->type; n->right->type = n->right->left->type;
goto ret; goto ret;
} }
if(istype(n->left->type, TSTRING)) {
n = stringop(n, init);
goto ret;
}
/* /*
* on 32-bit arch, rewrite 64-bit ops into l = l op r * on 32-bit arch, rewrite 64-bit ops into l = l op r
*/ */
...@@ -734,25 +649,6 @@ reswitch: ...@@ -734,25 +649,6 @@ reswitch:
n->right->type = n->right->left->type; n->right->type = n->right->left->type;
goto ret; goto ret;
case OEQ:
case ONE:
case OLT:
case OLE:
case OGE:
case OGT:
case OADD:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
if(istype(n->left->type, TSTRING)) {
n = stringop(n, nil);
goto ret;
}
if(isinter(n->left->type)) {
n = ifaceop(n);
goto ret;
}
goto ret;
case ODIV: case ODIV:
case OMOD: case OMOD:
/* /*
...@@ -779,131 +675,246 @@ reswitch: ...@@ -779,131 +675,246 @@ reswitch:
case OINDEX: case OINDEX:
walkexpr(&n->left, init); walkexpr(&n->left, init);
walkexpr(&n->right, init); walkexpr(&n->right, init);
if(n->left == N || n->right == N) goto ret;
case OINDEXMAP:
if(n->etype == 1)
goto ret; goto ret;
t = n->left->type; t = n->left->type;
if(t == T) n = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right);
goto ret;
switch(t->etype) {
case TSTRING:
n = stringop(n, nil);
break;
case TMAP:
if(n->etype != 1) // clumsy hack
n = mapop(n, nil);
break;
}
goto ret; goto ret;
case OCLOSE:
case OCLOSED:
case OSEND:
case ORECV: case ORECV:
walkexpr(&n->left, init); walkexpr(&n->left, init);
walkexpr(&n->right, init); walkexpr(&n->right, init);
n = chanop(n, init); n = mkcall1(chanfn("chanrecv1", 2, n->left->type), n->type, init, n->left);
goto ret; goto ret;
case OSLICE: case OSLICE:
walkexpr(&n->left, init); walkexpr(&n->left, init);
walkexpr(&n->right->left, init); walkexpr(&n->right->left, init);
walkexpr(&n->right->right, init); walkexpr(&n->right->right, init);
if(n->left == N || n->right == N) // dynamic slice
goto ret; // arraysliced(old []any, lb int, hb int, width int) (ary []any)
t = n->left->type; t = n->type;
if(t == T) fn = syslook("arraysliced", 1);
argtype(fn, t->type); // any-1
argtype(fn, t->type); // any-2
n = mkcall1(fn, t, init,
n->left,
conv(n->right->left, types[TINT]),
conv(n->right->right, types[TINT]),
nodintconst(t->type->width));
goto ret;
case OSLICEARR:
walkexpr(&n->left, init);
walkexpr(&n->right->left, init);
walkexpr(&n->right->right, init);
// static slice
// arrayslices(old *any, nel int, lb int, hb int, width int) (ary []any)
t = n->type;
fn = syslook("arrayslices", 1);
argtype(fn, n->left->type); // any-1
argtype(fn, t->type); // any-2
n = mkcall1(fn, t, init,
nod(OADDR, n->left, N), nodintconst(t->bound),
conv(n->right->left, types[TINT]),
conv(n->right->right, types[TINT]),
nodintconst(t->type->width));
goto ret;
case OADDR:;
Node *nvar, *nstar;
// turn &Point(1, 2) or &[]int(1, 2) or &[...]int(1, 2) into allocation.
// initialize with
// nvar := new(*Point);
// *nvar = Point(1, 2);
// and replace expression with nvar
switch(n->left->op) {
case OARRAYLIT:
nvar = makenewvar(n->type, init, &nstar);
arraylit(n->left, nstar, init);
n = nvar;
goto ret; goto ret;
if(t->etype == TSTRING) {
n = stringop(n, nil); case OMAPLIT:
nvar = makenewvar(n->type, init, &nstar);
maplit(n->left, nstar, init);
n = nvar;
goto ret; goto ret;
}
if(t->etype == TARRAY) {
n = arrayop(n); case OSTRUCTLIT:
nvar = makenewvar(n->type, init, &nstar);
structlit(n->left, nstar, init);
n = nvar;
goto ret; goto ret;
} }
walkexpr(&n->left, init);
goto ret; goto ret;
case OADDR: case ONEW:
if(n->left->op == OCOMPOS) { n = callnew(n->type->type);
walkexpr(&n->left->right, init); goto ret;
n->left->type = n->left->right->type;
if(n->left->type == T)
goto ret;
Node *nvar, *nas, *nstar; case OCMPSTR:
// sys_cmpstring(s1, s2) :: 0
r = mkcall("cmpstring", types[TINT], init,
conv(n->left, types[TSTRING]),
conv(n->right, types[TSTRING]));
r = nod(n->etype, r, nodintconst(0));
typecheck(&r, Erv);
n = r;
goto ret;
// turn &Point(1, 2) or &[]int(1, 2) or &[...]int(1, 2) into allocation. case OADDSTR:
// initialize with // sys_catstring(s1, s2)
// nvar := new(*Point); n = mkcall("catstring", n->type, init,
// *nvar = Point(1, 2); conv(n->left, types[TSTRING]),
// and replace expression with nvar conv(n->right, types[TSTRING]));
goto ret;
nvar = nod(OXXX, N, N); case OAPPENDSTR:
tempname(nvar, ptrto(n->left->type)); // s1 = sys_catstring(s1, s2)
if(n->etype != OADD)
fatal("walkasopstring: not add");
r = mkcall("catstring", n->left->type, init,
conv(n->left, types[TSTRING]),
conv(n->right, types[TSTRING]));
r = nod(OAS, n->left, r);
n = r;
goto ret;
nas = nod(OAS, nvar, callnew(n->left->type)); case OSLICESTR:
typecheck(&nas, Etop); // sys_slicestring(s, lb, hb)
walkexpr(&nas, init); n = mkcall("slicestring", n->type, init,
*init = list(*init, nas); conv(n->left, types[TSTRING]),
conv(n->right->left, types[TINT]),
conv(n->right->right, types[TINT]));
goto ret;
nstar = nod(OIND, nvar, N); case OINDEXSTR:
nstar->type = n->left->type; // TODO(rsc): should be done in back end
// sys_indexstring(s, i)
n = mkcall("indexstring", n->type, init,
conv(n->left, types[TSTRING]),
conv(n->right, types[TINT]));
goto ret;
switch(n->left->type->etype) { case OCLOSE:
case TSTRUCT: // cannot use chanfn - closechan takes any, not chan any
structlit(n->left, nstar, init); fn = syslook("closechan", 1);
break; argtype(fn, n->left->type);
case TARRAY: n = mkcall1(fn, T, init, n->left);
arraylit(n->left, nstar, init); goto ret;
break;
case TMAP:
maplit(n->left, nstar, init);
break;
default:
goto badlit;
}
// walkexpr(&n->left->left, init); case OCLOSED:
n = nvar; // cannot use chanfn - closechan takes any, not chan any
goto ret; fn = syslook("closedchan", 1);
} argtype(fn, n->left->type);
n = mkcall1(fn, n->type, init, n->left);
goto ret;
badlit: case OMAKECHAN:
if(istype(n->left->type, TFUNC) && n->left->class == PFUNC) { n = mkcall1(chanfn("newchan", 1, n->type), n->type, init,
if(!n->diag) { nodintconst(n->type->type->width),
n->diag = 1; nodintconst(algtype(n->type->type)),
yyerror("cannot take address of function"); conv(n->left, types[TINT]));
}
}
if(n->left == N)
goto ret;
walkexpr(&n->left, init);
t = n->left->type;
if(t == T)
goto ret;
addrescapes(n->left);
n->type = ptrto(t);
goto ret; goto ret;
case OMAKE: case OMAKEMAP:
n = makecompat(n); t = n->type;
fn = syslook("newmap", 1);
argtype(fn, t->down); // any-1
argtype(fn, t->type); // any-2
n = mkcall1(fn, n->type, init,
nodintconst(t->down->width), // key width
nodintconst(t->type->width), // val width
nodintconst(algtype(t->down)), // key algorithm
nodintconst(algtype(t->type)), // val algorithm
conv(n->left, types[TINT]));
goto ret; goto ret;
case ONEW: case OMAKESLICE:
if(n->list == nil) { // newarray(nel int, max int, width int) (ary []any)
yyerror("missing argument to new"); t = n->type;
goto ret; fn = syslook("newarray", 1);
} argtype(fn, t->type); // any-1
if(n->list->next) n = mkcall1(fn, n->type, nil,
yyerror("too many arguments to new"); conv(n->left, types[TINT]),
walkexpr(&n->list->n, init); conv(n->right, types[TINT]),
l = n->list->n; nodintconst(t->type->width));
if((t = l->type) == T) goto ret;
;
case ORUNESTR:
// sys_intstring(v)
n = mkcall("intstring", n->type, init, conv(n->left, types[TINT64])); // TODO(rsc): int64?!
goto ret;
case OARRAYBYTESTR:
// arraystring([]byte) string;
n = mkcall("arraystring", n->type, init, n->left);
goto ret;
case OARRAYRUNESTR:
// arraystring([]byte) string;
n = mkcall("arraystringi", n->type, init, n->left);
goto ret;
case OCMPIFACE:
// ifaceeq(i1 any-1, i2 any-2) (ret bool);
if(!eqtype(n->left->type, n->right->type))
fatal("ifaceeq %O %T %T", n->op, n->left->type, n->right->type);
if(isnilinter(n->left->type))
fn = syslook("efaceeq", 1);
else else
n = callnew(t); fn = syslook("ifaceeq", 1);
argtype(fn, n->right->type);
argtype(fn, n->left->type);
r = mkcall1(fn, n->type, init, n->left, n->right);
if(n->etype == ONE) {
r = nod(ONOT, r, N);
typecheck(&r, Erv);
}
n = r;
goto ret;
case OARRAYLIT:
n = arraylit(n, N, init);
goto ret;
case OMAPLIT:
n = maplit(n, N, init);
goto ret;
case OSTRUCTLIT:
n = structlit(n, N, init);
goto ret;
case OSEND:
n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, n->left, n->right);
goto ret;
case OSENDNB:
n = mkcall1(chanfn("chansend2", 2, n->left->type), n->type, init, n->left, n->right);
goto ret;
case OCONVIFACE:
walkexpr(&n->left, init);
n = ifacecvt(n->type, n->left, n->etype, init);
goto ret;
case OCONVSLICE:
// arrays2d(old *any, nel int) (ary []any)
fn = syslook("arrays2d", 1);
argtype(fn, n->left->type->type); // any-1
argtype(fn, n->type->type); // any-2
n = mkcall1(fn, n->type, init, n->left, nodintconst(n->left->type->type->bound));
goto ret; goto ret;
} }
fatal("missing switch %O", n->op); fatal("missing switch %O", n->op);
...@@ -917,6 +928,23 @@ ret: ...@@ -917,6 +928,23 @@ ret:
*np = n; *np = n;
} }
Node*
makenewvar(Type *t, NodeList **init, Node **nstar)
{
Node *nvar, *nas;
nvar = nod(OXXX, N, N);
tempname(nvar, t);
nas = nod(OAS, nvar, callnew(t->type));
typecheck(&nas, Etop);
walkexpr(&nas, init);
*init = list(*init, nas);
*nstar = nod(OIND, nvar, N);
typecheck(nstar, Erv);
return nvar;
}
void void
walkbool(Node **np) walkbool(Node **np)
{ {
...@@ -958,7 +986,6 @@ walkconv(Node **np, NodeList **init) ...@@ -958,7 +986,6 @@ walkconv(Node **np, NodeList **init)
t = n->type; t = n->type;
if(t == T) if(t == T)
return; return;
typecheck(&n->left, Erv);
walkexpr(&n->left, init); walkexpr(&n->left, init);
l = n->left; l = n->left;
if(l == N) if(l == N)
...@@ -969,110 +996,19 @@ walkconv(Node **np, NodeList **init) ...@@ -969,110 +996,19 @@ walkconv(Node **np, NodeList **init)
// if using .(T), interface assertion. // if using .(T), interface assertion.
if(n->op == ODOTTYPE) { if(n->op == ODOTTYPE) {
et = ifaceas1(t, l->type, 1); et = ifaceas1(t, l->type, 1);
if(et == I2Isame || et == E2Esame) if(et == I2Isame || et == E2Esame) {
goto nop; n->op = OCONVNOP;
if(et != Inone) {
n = ifacecvt(t, l, et);
*np = n;
return; return;
} }
goto bad; if(et != Inone) {
} n = ifacecvt(t, l, et, init);
// otherwise, conversion.
convlit1(&n->left, t, 1);
l = n->left;
if(l->type == T)
return;
// no-op conversion
if(cvttype(t, l->type) == 1) {
nop:
if(l->op == OLITERAL) {
*n = *l;
n->type = t;
return;
}
// leave OCONV node in place
// in case tree gets walked again.
// back end will ignore.
n->op = OCONVNOP;
return;
}
// to/from interface.
// ifaceas1 will generate a good error
// if the conversion is invalid.
if(t->etype == TINTER || l->type->etype == TINTER) {
n = ifacecvt(t, l, ifaceas1(t, l->type, 0));
*np = n;
return;
}
// simple fix-float
if(isint[l->type->etype] || isfloat[l->type->etype])
if(isint[t->etype] || isfloat[t->etype]) {
evconst(n);
return;
}
// to string
if(l->type != T)
if(istype(t, TSTRING)) {
et = l->type->etype;
if(isint[et]) {
n = stringop(n, nil);
*np = n;
return;
}
// can convert []byte and *[10]byte
if((isptr[et] && isfixedarray(l->type->type) && istype(l->type->type->type, TUINT8))
|| (isslice(l->type) && istype(l->type->type, TUINT8))) {
n->op = OARRAY;
n = stringop(n, nil);
*np = n;
return;
}
// can convert []int and *[10]int
if((isptr[et] && isfixedarray(l->type->type) && istype(l->type->type->type, TINT))
|| (isslice(l->type) && istype(l->type->type, TINT))) {
n->op = OARRAY;
n = stringop(n, nil);
*np = n;
return;
}
}
// convert dynamic to static generated by ONEW/OMAKE
if(isfixedarray(t) && isslice(l->type))
return;
// convert static array to dynamic array
if(isslice(t) && isptr[l->type->etype] && isfixedarray(l->type->type)) {
if(eqtype(t->type->type, l->type->type->type->type)) {
n = arrayop(n);
*np = n; *np = n;
return; return;
} }
goto bad;
} }
// convert to unsafe.pointer fatal("walkconv");
if(isptrto(n->type, TANY)) {
if(isptr[l->type->etype])
return;
if(l->type->etype == TUINTPTR)
return;
}
// convert from unsafe.pointer
if(isptrto(l->type, TANY)) {
if(isptr[t->etype])
return;
if(t->etype == TUINTPTR)
return;
}
bad: bad:
if(n->diag) if(n->diag)
...@@ -1279,6 +1215,7 @@ walkselect(Node *sel) ...@@ -1279,6 +1215,7 @@ walkselect(Node *sel)
break; break;
case OSEND: case OSEND:
case OSENDNB:
case ORECV: case ORECV:
break; break;
} }
...@@ -1325,14 +1262,15 @@ ascompatee1(int op, Node *l, Node *r, NodeList **init) ...@@ -1325,14 +1262,15 @@ ascompatee1(int op, Node *l, Node *r, NodeList **init)
* a expression. called in * a expression. called in
* expr = expr * expr = expr
*/ */
if(l->type != T && l->type->etype == TFORW)
return N;
if(r->type != T && r->type->etype ==TFORW)
return N;
convlit(&r, l->type); convlit(&r, l->type);
if(!ascompat(l->type, r->type)) { if(!ascompat(l->type, r->type)) {
badtype(op, l->type, r->type); badtype(op, l->type, r->type);
return N; return N;
} }
if(l->op == ONAME && l->class == PFUNC)
yyerror("cannot assign to function");
a = nod(OAS, l, r); a = nod(OAS, l, r);
a = convas(a, init); a = convas(a, init);
return a; return a;
...@@ -1653,7 +1591,7 @@ loop: ...@@ -1653,7 +1591,7 @@ loop:
} }
goto ret; goto ret;
} }
convlit(&r, l->type);
if(!ascompat(l->type, r->type)) { if(!ascompat(l->type, r->type)) {
badtype(op, l->type, r->type); badtype(op, l->type, r->type);
return nil; return nil;
...@@ -1676,49 +1614,6 @@ ret: ...@@ -1676,49 +1614,6 @@ ret:
return nn; return nn;
} }
/*
* do the export rules allow writing to this type?
* cannot be implicitly assigning to any type with
* an unavailable field.
*/
int
exportasok(Type *t)
{
Type *f;
Sym *s;
if(t == T)
return 1;
switch(t->etype) {
default:
// most types can't contain others; they're all fine.
break;
case TSTRUCT:
for(f=t->type; f; f=f->down) {
if(f->etype != TFIELD)
fatal("structas: not field");
s = f->sym;
// s == nil doesn't happen for embedded fields (they get the type symbol).
// it only happens for fields in a ... struct.
if(s != nil && !exportname(s->name) && strcmp(package, s->package) != 0) {
yyerror("implicit assignment of %T field '%s'", t, s->name);
return 0;
}
if(!exportasok(f->type))
return 0;
}
break;
case TARRAY:
if(t->bound < 0) // slices are pointers; that's fine
break;
if(!exportasok(t->type))
return 0;
break;
}
return 1;
}
/* /*
* can we assign var of type src to var of type dst? * can we assign var of type src to var of type dst?
* return 0 if not, 1 if conversion is trivial, 2 if conversion is non-trivial. * return 0 if not, 1 if conversion is trivial, 2 if conversion is non-trivial.
...@@ -1726,10 +1621,8 @@ exportasok(Type *t) ...@@ -1726,10 +1621,8 @@ exportasok(Type *t)
int int
ascompat(Type *dst, Type *src) ascompat(Type *dst, Type *src)
{ {
if(eqtype(dst, src)) { if(eqtype(dst, src))
exportasok(src);
return 1; return 1;
}
if(dst == T || src == T) if(dst == T || src == T)
return 0; return 0;
...@@ -1775,7 +1668,7 @@ ascompat(Type *dst, Type *src) ...@@ -1775,7 +1668,7 @@ ascompat(Type *dst, Type *src)
// generate code for print // generate code for print
static Node* static Node*
prcompat(Node *nn) walkprint(Node *nn, NodeList **init)
{ {
Node *r; Node *r;
Node *n; Node *n;
...@@ -1792,10 +1685,9 @@ prcompat(Node *nn) ...@@ -1792,10 +1685,9 @@ prcompat(Node *nn)
for(l=all; l; l=l->next) { for(l=all; l; l=l->next) {
if(notfirst) if(notfirst)
calls = list(calls, mkcall("printsp", T, nil)); calls = list(calls, mkcall("printsp", T, init));
notfirst = op == OPRINTN || op == OPANICN; notfirst = op == OPRINTN || op == OPANICN;
typecheck(&l->n, Erv);
n = l->n; n = l->n;
if(n->op == OLITERAL) { if(n->op == OLITERAL) {
switch(n->val.ctype) { switch(n->val.ctype) {
...@@ -1811,7 +1703,7 @@ prcompat(Node *nn) ...@@ -1811,7 +1703,7 @@ prcompat(Node *nn)
defaultlit(&n, types[TINT64]); defaultlit(&n, types[TINT64]);
defaultlit(&n, nil); defaultlit(&n, nil);
l->n = n; l->n = n;
if(n->type == T) if(n->type == T || n->type->etype == TFORW)
continue; continue;
et = n->type->etype; et = n->type->etype;
...@@ -1861,64 +1753,18 @@ prcompat(Node *nn) ...@@ -1861,64 +1753,18 @@ prcompat(Node *nn)
if(op == OPRINTN) if(op == OPRINTN)
calls = list(calls, mkcall("printnl", T, nil)); calls = list(calls, mkcall("printnl", T, nil));
typechecklist(calls, Etop); typechecklist(calls, Etop);
walkexprlist(calls, nil); walkexprlist(calls, init);
if(op == OPANIC || op == OPANICN) if(op == OPANIC || op == OPANICN)
r = mkcall("panicl", T, nil); r = mkcall("panicl", T, nil);
else else
r = nod(OEMPTY, N, N); r = nod(OEMPTY, N, N);
typecheck(&r, Etop); typecheck(&r, Etop);
walkexpr(&r, nil); walkexpr(&r, init);
r->ninit = calls; r->ninit = calls;
return r; return r;
} }
Node*
makecompat(Node *n)
{
Type *t;
Node *l, *r;
NodeList *args, *init;
//dump("makecompat", n);
args = n->list;
if(args == nil) {
yyerror("make requires type argument");
return n;
}
r = N;
l = args->n;
args = args->next;
init = nil;
walkexpr(&l, &init);
if(l->op != OTYPE) {
yyerror("cannot make(expr)");
return n;
}
t = l->type;
n->type = t;
n->list = args;
if(t != T)
switch(t->etype) {
case TARRAY:
if(!isslice(t))
goto bad;
return arrayop(n);
case TMAP:
return mapop(n, nil);
case TCHAN:
return chanop(n, nil);
}
bad:
if(!n->diag) {
n->diag = 1;
yyerror("cannot make(%T)", t);
}
return n;
}
Node* Node*
callnew(Type *t) callnew(Type *t)
{ {
...@@ -1930,93 +1776,6 @@ callnew(Type *t) ...@@ -1930,93 +1776,6 @@ callnew(Type *t)
return mkcall1(fn, ptrto(t), nil, nodintconst(t->width)); return mkcall1(fn, ptrto(t), nil, nodintconst(t->width));
} }
Node*
stringop(Node *n, NodeList **init)
{
Node *r, *fn;
switch(n->op) {
default:
fatal("stringop: unknown op %O", n->op);
case OEQ:
case ONE:
case OGE:
case OGT:
case OLE:
case OLT:
// sys_cmpstring(s1, s2) :: 0
r = mkcall("cmpstring", types[TINT], init,
conv(n->left, types[TSTRING]),
conv(n->right, types[TSTRING]));
r = nod(n->op, r, nodintconst(0));
typecheck(&r, Erv);
break;
case OADD:
// sys_catstring(s1, s2)
r = mkcall("catstring", n->type, init,
conv(n->left, types[TSTRING]),
conv(n->right, types[TSTRING]));
break;
case OASOP:
// sys_catstring(s1, s2)
switch(n->etype) {
default:
fatal("stringop: unknown op %O-%O", n->op, n->etype);
case OADD:
// s1 = sys_catstring(s1, s2)
if(n->etype != OADD)
fatal("stringop: not cat");
r = mkcall("catstring", n->left->type, init,
conv(n->left, types[TSTRING]),
conv(n->right, types[TSTRING]));
r = nod(OAS, n->left, r);
break;
}
break;
case OSLICE:
// sys_slicestring(s, lb, hb)
r = mkcall("slicestring", n->type, init,
conv(n->left, types[TSTRING]),
conv(n->right->left, types[TINT]),
conv(n->right->right, types[TINT]));
break;
case OINDEX:
// TODO(rsc): should be done in back end
// sys_indexstring(s, i)
r = mkcall("indexstring", n->type, init,
conv(n->left, types[TSTRING]),
conv(n->right, types[TINT]));
break;
case OCONV:
// sys_intstring(v)
r = mkcall("intstring", n->type, init,
conv(n->left, types[TINT64])); // TODO(rsc): int64?!
break;
case OARRAY:
// arraystring([]byte) string;
r = n->left;
fn = syslook("arraystring", 0);
if(r->type != T && r->type->type != T) {
if(istype(r->type->type, TINT) || istype(r->type->type->type, TINT)) {
// arraystring([]byte) string;
fn = syslook("arraystringi", 0);
}
}
r = mkcall1(fn, n->type, init, r);
break;
}
return r;
}
Type* Type*
fixmap(Type *t) fixmap(Type *t)
{ {
...@@ -2061,7 +1820,7 @@ mapop(Node *n, NodeList **init) ...@@ -2061,7 +1820,7 @@ mapop(Node *n, NodeList **init)
{ {
Node *r, *a, *l; Node *r, *a, *l;
Type *t; Type *t;
Node *fn, *hint; Node *fn;
int cl, cr; int cl, cr;
NodeList *args; NodeList *args;
...@@ -2070,49 +1829,9 @@ mapop(Node *n, NodeList **init) ...@@ -2070,49 +1829,9 @@ mapop(Node *n, NodeList **init)
default: default:
fatal("mapop: unknown op %O", n->op); fatal("mapop: unknown op %O", n->op);
case OMAKE:
cl = count(n->list);
if(cl > 1)
yyerror("too many arguments to make map");
// newmap(keysize int, valsize int,
// keyalg int, valalg int,
// hint int) (hmap map[any-1]any-2);
t = fixmap(n->type);
if(t == T)
break;
fn = syslook("newmap", 1);
argtype(fn, t->down); // any-1
argtype(fn, t->type); // any-2
if(cl == 1)
hint = n->list->n;
else
hint = nodintconst(0);
r = mkcall1(fn, n->type, init,
nodintconst(t->down->width), // key width
nodintconst(t->type->width), // val width
nodintconst(algtype(t->down)), // key algorithm
nodintconst(algtype(t->type)), // val algorithm
hint);
break;
case OINDEX:
// mapaccess1(hmap map[any]any, key any) (val any);
t = fixmap(n->left->type);
if(t == T)
break;
r = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right);
break;
case OAS: case OAS:
// mapassign1(hmap map[any-1]any-2, key any-3, val any-4); // mapassign1(hmap map[any-1]any-2, key any-3, val any-4);
if(n->left->op != OINDEX) if(n->left->op != OINDEXMAP)
goto shape; goto shape;
t = fixmap(n->left->left->type); t = fixmap(n->left->left->type);
...@@ -2135,7 +1854,7 @@ mapop(Node *n, NodeList **init) ...@@ -2135,7 +1854,7 @@ mapop(Node *n, NodeList **init)
assign2: assign2:
// mapassign2(hmap map[any]any, key any, val any, pres bool); // mapassign2(hmap map[any]any, key any, val any, pres bool);
l = n->list->n; l = n->list->n;
if(l->op != OINDEX) if(l->op != OINDEXMAP)
goto shape; goto shape;
t = fixmap(l->left->type); t = fixmap(l->left->type);
...@@ -2150,7 +1869,7 @@ mapop(Node *n, NodeList **init) ...@@ -2150,7 +1869,7 @@ mapop(Node *n, NodeList **init)
//dump("access2", n); //dump("access2", n);
r = n->rlist->n; r = n->rlist->n;
if(r->op != OINDEX) if(r->op != OINDEXMAP)
goto shape; goto shape;
t = fixmap(r->left->type); t = fixmap(r->left->type);
...@@ -2184,8 +1903,7 @@ mapop(Node *n, NodeList **init) ...@@ -2184,8 +1903,7 @@ mapop(Node *n, NodeList **init)
a = nod(OXXX, N, N); a = nod(OXXX, N, N);
*a = *n->left; // copy of map[tmpi] *a = *n->left; // copy of map[tmpi]
a->typecheck = 0; a->etype = 0;
a->type = T;
a = nod(n->etype, a, n->right); // m[tmpi] op right a = nod(n->etype, a, n->right); // m[tmpi] op right
r = nod(OAS, n->left, a); // map[tmpi] = map[tmpi] op right r = nod(OAS, n->left, a); // map[tmpi] = map[tmpi] op right
typecheck(&r, Etop); typecheck(&r, Etop);
...@@ -2200,59 +1918,17 @@ shape: ...@@ -2200,59 +1918,17 @@ shape:
return N; return N;
} }
Node* Node*
chanop(Node *n, NodeList **init) chanop(Node *n, NodeList **init)
{ {
Node *r, *a, *fn; Node *r, *fn;
Type *t; Type *t;
int cl, cr; int cl, cr;
r = n;
switch(n->op) {
default:
fatal("chanop: unknown op %O", n->op);
case OCLOSE:
// closechan(hchan *chan any);
t = fixchan(n->left->type);
if(t == T)
break;
fn = syslook("closechan", 1);
argtype(fn, t);
r = mkcall1(fn, T, init, n->left);
break;
case OCLOSED:
// closedchan(hchan *chan any) bool;
t = fixchan(n->left->type);
if(t == T)
break;
fn = syslook("closedchan", 1);
argtype(fn, t);
r = mkcall1(fn, n->type, init, n->left);
break;
case OMAKE:
cl = count(n->list);
if(cl > 1)
yyerror("too many arguments to make chan");
// newchan(elemsize int, elemalg int,
// hint int) (hmap *chan[any-1]);
t = fixchan(n->type);
if(t == T)
break;
if(cl == 1) r = n;
a = conv(n->list->n, types[TINT]); switch(n->op) {
else default:
a = nodintconst(0); fatal("chanop: unknown op %O", n->op);
r = mkcall1(chanfn("newchan", 1, t), n->type, init,
nodintconst(t->type->width),
nodintconst(algtype(t->type)),
a);
break;
case OAS2: case OAS2:
cl = count(n->list); cl = count(n->list);
...@@ -2278,45 +1954,6 @@ chanop(Node *n, NodeList **init) ...@@ -2278,45 +1954,6 @@ chanop(Node *n, NodeList **init)
r = n; r = n;
walkexpr(&r, init); walkexpr(&r, init);
break; break;
case ORECV:
// should not happen - nonblocking is OAS w/ ORECV now.
if(n->right != N) {
dump("recv2", n);
fatal("chanop recv2");
}
// chanrecv1(hchan *chan any) (elem any);
t = fixchan(n->left->type);
if(t == T)
break;
if(!(t->chan & Crecv)) {
yyerror("cannot receive from %T", t);
break;
}
r = mkcall1(chanfn("chanrecv1", 2, t), n->type, init, n->left);
break;
case OSEND:
t = fixchan(n->left->type);
if(t == T)
break;
if(!(t->chan & Csend)) {
yyerror("cannot send to %T", t);
break;
}
if(n->etype == 1) // clumsy hack
goto send2;
// chansend1(hchan *chan any, elem any);
r = mkcall1(chanfn("chansend1", 2, t), T, init, n->left, n->right);
break;
send2:
// chansend2(hchan *chan any, val any) (pres bool);
r = mkcall1(chanfn("chansend2", 2, t), n->type, init, n->left, n->right);
break;
} }
return r; return r;
...@@ -2325,6 +1962,7 @@ shape: ...@@ -2325,6 +1962,7 @@ shape:
return N; return N;
} }
Type* Type*
fixarray(Type *t) fixarray(Type *t)
{ {
...@@ -2344,104 +1982,6 @@ bad: ...@@ -2344,104 +1982,6 @@ bad:
} }
Node*
arrayop(Node *n)
{
Node *r, *nel, *max;
NodeList *args;
Type *t, *tl;
Node *fn;
int cl;
r = n;
switch(n->op) {
default:
fatal("darrayop: unknown op %O", n->op);
case OCONVNOP:
return n;
case OCONV:
// arrays2d(old *any, nel int) (ary []any)
if(n->left->type == T || !isptr[n->left->type->etype])
break;
t = fixarray(n->left->type->type);
tl = fixarray(n->type);
if(t == T || tl == T)
break;
fn = syslook("arrays2d", 1);
argtype(fn, t); // any-1
argtype(fn, tl->type); // any-2
n->left = mkcall1(fn, n->type, nil, n->left, nodintconst(t->bound));
typecheck(&n, Erv);
walkexpr(&n, nil);
return n;
case OAS:
n->right = arrayop(conv(n->right, n->left->type));
return n;
case OMAKE:
cl = count(n->list);
if(cl > 2)
yyerror("too many arguments to make array");
// newarray(nel int, max int, width int) (ary []any)
t = fixarray(n->type);
if(t == T)
break;
fn = syslook("newarray", 1);
argtype(fn, t->type); // any-1
nel = conv(n->list->n, types[TINT]);
if(cl < 2)
max = nodintconst(0);
else
max = conv(n->list->next->n, types[TINT]);
r = mkcall1(fn, n->type, nil,
nel, max, nodintconst(t->type->width));
break;
case OSLICE:
// arrayslices(old any, nel int, lb int, hb int, width int) (ary []any)
// arraysliced(old []any, lb int, hb int, width int) (ary []any)
t = fixarray(n->left->type);
if(t == T)
break;
if(t->bound >= 0) {
// static slice
args = list1(nod(OADDR, n->left, N)); // old
args = list(args, nodintconst(t->bound)); // nel
fn = syslook("arrayslices", 1);
argtype(fn, t); // any-1
argtype(fn, t->type); // any-2
} else {
// dynamic slice
args = list1(n->left); // old
fn = syslook("arraysliced", 1);
argtype(fn, t->type); // any-1
argtype(fn, t->type); // any-2
}
args = list(args, conv(n->right->left, types[TINT])); // lb
args = list(args, conv(n->right->right, types[TINT])); // hb
args = list(args, nodintconst(t->type->width)); // width
r = nod(OCALL, fn, N);
r->list = args;
typecheck(&r, Erv);
walkexpr(&r, nil);
break;
}
return r;
}
/* /*
* assigning src to dst involving interfaces? * assigning src to dst involving interfaces?
* return op to use. * return op to use.
...@@ -2520,7 +2060,7 @@ ifacename[] = ...@@ -2520,7 +2060,7 @@ ifacename[] =
}; };
Node* Node*
ifacecvt(Type *tl, Node *n, int et) ifacecvt(Type *tl, Node *n, int et, NodeList **init)
{ {
Type *tr; Type *tr;
Node *r, *on; Node *r, *on;
...@@ -2532,6 +2072,10 @@ ifacecvt(Type *tl, Node *n, int et) ...@@ -2532,6 +2072,10 @@ ifacecvt(Type *tl, Node *n, int et)
default: default:
fatal("ifacecvt: unknown op %d\n", et); fatal("ifacecvt: unknown op %d\n", et);
case I2Isame:
case E2Esame:
return n;
case T2I: case T2I:
// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any); // ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any);
args = list1(typename(tl)); // sigi args = list1(typename(tl)); // sigi
...@@ -2541,6 +2085,7 @@ ifacecvt(Type *tl, Node *n, int et) ...@@ -2541,6 +2085,7 @@ ifacecvt(Type *tl, Node *n, int et)
on = syslook("ifaceT2I", 1); on = syslook("ifaceT2I", 1);
argtype(on, tr); argtype(on, tr);
argtype(on, tl); argtype(on, tl);
dowidth(on->type);
break; break;
case I2T: case I2T:
...@@ -2586,45 +2131,10 @@ ifacecvt(Type *tl, Node *n, int et) ...@@ -2586,45 +2131,10 @@ ifacecvt(Type *tl, Node *n, int et)
r = nod(OCALL, on, N); r = nod(OCALL, on, N);
r->list = args; r->list = args;
typecheck(&r, Erv); typecheck(&r, Erv);
walkexpr(&r, nil); walkexpr(&r, init);
return r; return r;
} }
Node*
ifaceop(Node *n)
{
Node *r, *on;
NodeList *args;
switch(n->op) {
default:
fatal("ifaceop %O", n->op);
case OEQ:
case ONE:
// ifaceeq(i1 any-1, i2 any-2) (ret bool);
args = list1(n->left); // i1
args = list(args, n->right); // i2
if(!eqtype(n->left->type, n->right->type))
fatal("ifaceop %O %T %T", n->op, n->left->type, n->right->type);
if(isnilinter(n->left->type))
on = syslook("efaceeq", 1);
else
on = syslook("ifaceeq", 1);
argtype(on, n->right->type);
argtype(on, n->left->type);
r = nod(OCALL, on, N);
r->list = args;
if(n->op == ONE)
r = nod(ONOT, r, N);
typecheck(&r, Erv);
walkexpr(&r, nil);
return r;
}
}
Node* Node*
convas(Node *n, NodeList **init) convas(Node *n, NodeList **init)
{ {
...@@ -2634,6 +2144,7 @@ convas(Node *n, NodeList **init) ...@@ -2634,6 +2144,7 @@ convas(Node *n, NodeList **init)
if(n->op != OAS) if(n->op != OAS)
fatal("convas: not OAS %O", n->op); fatal("convas: not OAS %O", n->op);
n->typecheck = 1;
lt = T; lt = T;
rt = T; rt = T;
...@@ -2648,38 +2159,23 @@ convas(Node *n, NodeList **init) ...@@ -2648,38 +2159,23 @@ convas(Node *n, NodeList **init)
if(lt == T || rt == T) if(lt == T || rt == T)
goto out; goto out;
if(n->left->op == OINDEX) if(n->left->op == OINDEXMAP) {
if(istype(n->left->left->type, TMAP)) {
n = mapop(n, init); n = mapop(n, init);
goto out; goto out;
} }
if(n->left->op == OSEND)
if(n->left->type != T) {
n = chanop(n, init);
goto out;
}
if(eqtype(lt, rt)) if(eqtype(lt, rt))
goto out; goto out;
et = ifaceas(lt, rt, 0); et = ifaceas(lt, rt, 0);
if(et != Inone) { if(et != Inone) {
n->right = ifacecvt(lt, r, et); n->right = ifacecvt(lt, r, et, init);
goto out;
}
if(isslice(lt) && isptr[rt->etype] && isfixedarray(rt->type)) {
if(!eqtype(lt->type->type, rt->type->type->type))
goto bad;
n = arrayop(n);
goto out; goto out;
} }
if(ascompat(lt, rt)) if(ascompat(lt, rt))
goto out; goto out;
bad:
badtype(n->op, lt, rt); badtype(n->op, lt, rt);
out: out:
...@@ -2897,15 +2393,13 @@ multi: ...@@ -2897,15 +2393,13 @@ multi:
default: default:
goto badt; goto badt;
case OINDEX: case OINDEXMAP:
// check if rhs is a map index. // check if rhs is a map index.
// if so, types are valuetype,bool // if so, types are valuetype,bool
if(cl != 2) if(cl != 2)
goto badt; goto badt;
walkexpr(&nr->left, &init); walkexpr(&nr->left, &init);
t = nr->left->type; t = nr->left->type;
if(!istype(t, TMAP))
goto badt;
a = mixedoldnew(ll->n, t->type); a = mixedoldnew(ll->n, t->type);
n = list1(a); n = list1(a);
a = mixedoldnew(ll->next->n, types[TBOOL]); a = mixedoldnew(ll->next->n, types[TBOOL]);
...@@ -3387,38 +2881,13 @@ reorder4(NodeList *ll) ...@@ -3387,38 +2881,13 @@ reorder4(NodeList *ll)
return ll; return ll;
} }
static void
fielddup(Node *n, Node *hash[], ulong nhash)
{
uint h;
char *s;
Node *a;
if(n->op != ONAME)
fatal("fielddup: not ONAME");
s = n->sym->name;
h = stringhash(s)%nhash;
for(a=hash[h]; a!=N; a=a->ntest) {
if(strcmp(a->sym->name, s) == 0) {
yyerror("duplicate field name in struct literal: %s", s);
return;
}
}
n->ntest = hash[h];
hash[h] = n;
}
Node* Node*
structlit(Node *n, Node *var, NodeList **init) structlit(Node *n, Node *var, NodeList **init)
{ {
Iter savel; Type *t;
Type *l, *t;
Node *r, *a; Node *r, *a;
Node* hash[101];
NodeList *nl; NodeList *nl;
int nerr;
nerr = nerrors;
t = n->type; t = n->type;
if(t->etype != TSTRUCT) if(t->etype != TSTRUCT)
fatal("structlit: not struct"); fatal("structlit: not struct");
...@@ -3429,141 +2898,45 @@ structlit(Node *n, Node *var, NodeList **init) ...@@ -3429,141 +2898,45 @@ structlit(Node *n, Node *var, NodeList **init)
} }
nl = n->list; nl = n->list;
if(nl == nil || nl->n->op == OKEY)
goto keyval;
l = structfirst(&savel, &n->type);
for(; nl; nl=nl->next) {
r = nl->n;
// assignment to every field
if(l == T)
break;
if(r->op == OKEY) {
yyerror("mixture of value and field:value initializers");
return var;
}
// build list of var.field = expr if(count(n->list) < structcount(t)) {
a = nod(ODOT, var, newname(l->sym)); a = nod(OAS, var, N);
a = nod(OAS, a, r);
typecheck(&a, Etop); typecheck(&a, Etop);
walkexpr(&a, init); walkexpr(&a, init);
if(nerr != nerrors)
return var;
*init = list(*init, a); *init = list(*init, a);
l = structnext(&savel);
} }
if(l != T)
yyerror("struct literal expect expr of type %T", l);
if(nl != nil)
yyerror("struct literal too many expressions");
return var;
keyval:
memset(hash, 0, sizeof(hash));
a = nod(OAS, var, N);
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
for(; nl; nl=nl->next) { for(; nl; nl=nl->next) {
r = nl->n; r = nl->n;
// assignment to field:value elements
if(r->op != OKEY) {
yyerror("mixture of field:value and value initializers");
break;
}
// build list of var.field = expr // build list of var.field = expr
a = nod(ODOT, var, newname(r->left->sym)); a = nod(ODOT, var, newname(r->left->sym));
fielddup(a->right, hash, nelem(hash));
if(nerr != nerrors)
break;
a = nod(OAS, a, r->right); a = nod(OAS, a, r->right);
typecheck(&a, Etop); typecheck(&a, Etop);
walkexpr(&a, init); walkexpr(&a, init);
if(nerr != nerrors)
break;
*init = list(*init, a); *init = list(*init, a);
} }
return var; return var;
} }
static void
indexdup(Node *n, Node *hash[], ulong nhash)
{
uint h;
Node *a;
ulong b, c;
if(n->op != OLITERAL)
fatal("indexdup: not OLITERAL");
b = mpgetfix(n->val.u.xval);
h = b%nhash;
for(a=hash[h]; a!=N; a=a->ntest) {
c = mpgetfix(a->val.u.xval);
if(b == c) {
yyerror("duplicate index in array literal: %ld", b);
return;
}
}
n->ntest = hash[h];
hash[h] = n;
}
Node* Node*
arraylit(Node *n, Node *var, NodeList **init) arraylit(Node *n, Node *var, NodeList **init)
{ {
Type *t; Type *t;
Node *r, *a; Node *r, *a;
NodeList *l; NodeList *l;
long ninit, b;
Node* hash[101];
int nerr;
nerr = nerrors;
t = n->type; t = n->type;
if(t->etype != TARRAY)
fatal("arraylit: not array");
// find max index
ninit = 0;
b = 0;
for(l=n->list; l; l=l->next) {
r = l->n;
if(r->op == OKEY) {
evconst(r->left);
b = nonnegconst(r->left);
}
b++;
if(b > ninit)
ninit = b;
}
b = t->bound;
if(b == -100) {
// flag for [...]
b = ninit;
if(var == N)
t = shallow(t);
t->bound = b;
}
if(var == N) { if(var == N) {
var = nod(OXXX, N, N); var = nod(OXXX, N, N);
tempname(var, t); tempname(var, t);
} }
if(b < 0) { if(t->bound < 0) {
// slice // slice
a = nod(OMAKE, N, N); a = nod(OMAKE, N, N);
a->list = list(list1(typenod(t)), nodintconst(ninit)); a->list = list(list1(typenod(t)), n->right);
a = nod(OAS, var, a); a = nod(OAS, var, a);
typecheck(&a, Etop); typecheck(&a, Etop);
walkexpr(&a, init); walkexpr(&a, init);
...@@ -3571,7 +2944,7 @@ arraylit(Node *n, Node *var, NodeList **init) ...@@ -3571,7 +2944,7 @@ arraylit(Node *n, Node *var, NodeList **init)
} else { } else {
// if entire array isnt initialized, // if entire array isnt initialized,
// then clear the array // then clear the array
if(ninit < b) { if(count(n->list) < t->bound) {
a = nod(OAS, var, N); a = nod(OAS, var, N);
typecheck(&a, Etop); typecheck(&a, Etop);
walkexpr(&a, init); walkexpr(&a, init);
...@@ -3579,96 +2952,17 @@ arraylit(Node *n, Node *var, NodeList **init) ...@@ -3579,96 +2952,17 @@ arraylit(Node *n, Node *var, NodeList **init)
} }
} }
b = 0;
memset(hash, 0, sizeof(hash));
for(l=n->list; l; l=l->next) { for(l=n->list; l; l=l->next) {
r = l->n; r = l->n;
// build list of var[c] = expr // build list of var[c] = expr
if(r->op == OKEY) { a = nod(OINDEX, var, r->left);
b = nonnegconst(r->left); a = nod(OAS, a, r->right);
if(b < 0) {
yyerror("array index must be non-negative constant");
break;
}
r = r->right;
}
if(t->bound >= 0 && b > t->bound) {
yyerror("array index out of bounds");
break;
}
a = nodintconst(b);
indexdup(a, hash, nelem(hash));
if(nerr != nerrors)
break;
a = nod(OINDEX, var, a);
a = nod(OAS, a, r);
typecheck(&a, Etop); typecheck(&a, Etop);
walkexpr(&a, init); // add any assignments in r to top walkexpr(&a, init); // add any assignments in r to top
if(nerr != nerrors)
break;
*init = list(*init, a); *init = list(*init, a);
b++;
}
return var;
}
static void
keydup(Node *n, Node *hash[], ulong nhash)
{
uint h;
ulong b;
double d;
int i;
Node *a;
Node cmp;
char *s;
evconst(n);
if(n->op != OLITERAL)
return; // we dont check variables
switch(n->val.ctype) {
default: // unknown, bool, nil
b = 23;
break;
case CTINT:
b = mpgetfix(n->val.u.xval);
break;
case CTFLT:
d = mpgetflt(n->val.u.fval);
s = (char*)&d;
b = 0;
for(i=sizeof(d); i>0; i--)
b = b*PRIME1 + *s++;
break;
case CTSTR:
b = 0;
s = n->val.u.sval->s;
for(i=n->val.u.sval->len; i>0; i--)
b = b*PRIME1 + *s++;
break;
} }
h = b%nhash; return var;
memset(&cmp, 0, sizeof(cmp));
for(a=hash[h]; a!=N; a=a->ntest) {
cmp.op = OEQ;
cmp.left = n;
cmp.right = a;
evconst(&cmp);
b = cmp.val.u.bval;
if(b) {
// too lazy to print the literal
yyerror("duplicate key in map literal");
return;
}
}
n->ntest = hash[h];
hash[h] = n;
} }
Node* Node*
...@@ -3700,16 +2994,7 @@ maplit(Node *n, Node *var, NodeList **init) ...@@ -3700,16 +2994,7 @@ maplit(Node *n, Node *var, NodeList **init)
memset(hash, 0, sizeof(hash)); memset(hash, 0, sizeof(hash));
for(l=n->list; l; l=l->next) { for(l=n->list; l; l=l->next) {
r = l->n; r = l->n;
if(r->op != OKEY) {
yyerror("map literal must have key:value pairs");
break;
}
// build list of var[c] = expr // build list of var[c] = expr
keydup(r->left, hash, nelem(hash));
if(nerr != nerrors)
break;
a = nod(OINDEX, var, r->left); a = nod(OINDEX, var, r->left);
a = nod(OAS, a, r->right); a = nod(OAS, a, r->right);
typecheck(&a, Etop); typecheck(&a, Etop);
...@@ -3722,72 +3007,6 @@ maplit(Node *n, Node *var, NodeList **init) ...@@ -3722,72 +3007,6 @@ maplit(Node *n, Node *var, NodeList **init)
return var; return var;
} }
/*
* the address of n has been taken and might be used after
* the current function returns. mark any local vars
* as needing to move to the heap.
*/
void
addrescapes(Node *n)
{
char buf[100];
switch(n->op) {
default:
// probably a type error already.
// dump("addrescapes", n);
break;
case ONAME:
if(n->noescape)
break;
switch(n->class) {
case PPARAMOUT:
yyerror("cannot take address of out parameter %s", n->sym->name);
break;
case PAUTO:
case PPARAM:
// if func param, need separate temporary
// to hold heap pointer.
if(n->class == PPARAM) {
// expression to refer to stack copy
n->stackparam = nod(OPARAM, n, N);
n->stackparam->type = n->type;
n->stackparam->addable = 1;
n->stackparam->xoffset = n->xoffset;
}
n->class |= PHEAP;
n->addable = 0;
n->ullman = 2;
n->alloc = callnew(n->type);
n->xoffset = 0;
// create stack variable to hold pointer to heap
n->heapaddr = nod(0, N, N);
tempname(n->heapaddr, ptrto(n->type));
snprint(buf, sizeof buf, "&%S", n->sym);
n->heapaddr->sym = lookup(buf);
break;
}
break;
case OIND:
case ODOTPTR:
break;
case ODOT:
case OINDEX:
// ODOTPTR has already been introduced,
// so these are the non-pointer ODOT and OINDEX.
// In &x[0], if x is a slice, then x does not
// escape--the pointer inside x does, but that
// is always a heap pointer anyway.
if(!isslice(n->left->type))
addrescapes(n->left);
break;
}
}
/* /*
* walk through argin parameters. * walk through argin parameters.
* generate and return code to allocate * generate and return code to allocate
...@@ -3843,7 +3062,7 @@ vmkcall(Node *fn, Type *t, NodeList **init, va_list va) ...@@ -3843,7 +3062,7 @@ vmkcall(Node *fn, Type *t, NodeList **init, va_list va)
n = fn->type->intuple; n = fn->type->intuple;
for(i=0; i<n; i++) for(i=0; i<n; i++)
args = list(args, va_arg(va, Node*)); args = list(args, va_arg(va, Node*));
r = nod(OCALL, fn, N); r = nod(OCALL, fn, N);
r->list = args; r->list = args;
if(fn->type->outtuple > 0) if(fn->type->outtuple > 0)
...@@ -3860,7 +3079,7 @@ mkcall(char *name, Type *t, NodeList **init, ...) ...@@ -3860,7 +3079,7 @@ mkcall(char *name, Type *t, NodeList **init, ...)
{ {
Node *r; Node *r;
va_list va; va_list va;
va_start(va, init); va_start(va, init);
r = vmkcall(syslook(name, 0), t, init, va); r = vmkcall(syslook(name, 0), t, init, va);
va_end(va); va_end(va);
...@@ -3872,7 +3091,7 @@ mkcall1(Node *fn, Type *t, NodeList **init, ...) ...@@ -3872,7 +3091,7 @@ mkcall1(Node *fn, Type *t, NodeList **init, ...)
{ {
Node *r; Node *r;
va_list va; va_list va;
va_start(va, init); va_start(va, init);
r = vmkcall(fn, t, init, va); r = vmkcall(fn, t, init, va);
va_end(va); va_end(va);
...@@ -3887,7 +3106,6 @@ conv(Node *n, Type *t) ...@@ -3887,7 +3106,6 @@ conv(Node *n, Type *t)
n = nod(OCONV, n, N); n = nod(OCONV, n, N);
n->type = t; n->type = t;
typecheck(&n, Erv); typecheck(&n, Erv);
walkexpr(&n, nil);
return n; return n;
} }
......
...@@ -15,10 +15,10 @@ var ( ...@@ -15,10 +15,10 @@ var (
func main() { func main() {
cr = c; // ok cr = c; // ok
cs = c; // ok cs = c; // ok
c = cr; // ERROR "illegal types|incompatible" c = cr; // ERROR "illegal types|incompatible|cannot"
c = cs; // ERROR "illegal types|incompatible" c = cs; // ERROR "illegal types|incompatible|cannot"
cr = cs; // ERROR "illegal types|incompatible" cr = cs; // ERROR "illegal types|incompatible|cannot"
cs = cr; // ERROR "illegal types|incompatible" cs = cr; // ERROR "illegal types|incompatible|cannot"
c <- 0; // ok c <- 0; // ok
ok := c <- 0; // ok ok := c <- 0; // ok
......
...@@ -65,15 +65,15 @@ var ( ...@@ -65,15 +65,15 @@ var (
func f(int); func f(int);
func main() { func main() {
f(Int8); // ERROR "convert|wrong type" f(Int8); // ERROR "convert|wrong type|cannot"
f(Minus1); // ERROR "convert|wrong type" f(Minus1); // ERROR "convert|wrong type|cannot"
f(Uint8); // ERROR "convert|wrong type" f(Uint8); // ERROR "convert|wrong type|cannot"
f(Const); // OK f(Const); // OK
f(Float32); // ERROR "convert|wrong type" f(Float32); // ERROR "convert|wrong type|cannot"
f(Float); // ERROR "convert|wrong type" f(Float); // ERROR "convert|wrong type|cannot"
f(ConstFloat); // ERROR "truncate" f(ConstFloat); // ERROR "truncate"
f(ConstFloat - 0.5); // OK f(ConstFloat - 0.5); // OK
f(Big); // ERROR "convert|wrong type" f(Big); // ERROR "convert|wrong type|cannot"
f(String); // ERROR "convert|wrong type" f(String); // ERROR "convert|wrong type|cannot"
f(Bool); // ERROR "convert|wrong type" f(Bool); // ERROR "convert|wrong type|cannot"
} }
...@@ -21,5 +21,5 @@ var g = []int(nil) ...@@ -21,5 +21,5 @@ var g = []int(nil)
type H *[4]int type H *[4]int
type J []int type J []int
var h H var h H
var j1 J = h // ERROR "compat|illegal" var j1 J = h // ERROR "compat|illegal|cannot|cannot"
var j2 = J(h) var j2 = J(h)
...@@ -19,11 +19,11 @@ var x7 = float(1e1000); // ERROR "overflow" ...@@ -19,11 +19,11 @@ var x7 = float(1e1000); // ERROR "overflow"
// implicit conversions merit scrutiny // implicit conversions merit scrutiny
var s string; var s string;
var bad1 string = 1; // ERROR "conver|incompatible" var bad1 string = 1; // ERROR "conver|incompatible|invalid|cannot"
var bad2 = s + 1; // ERROR "conver|incompatible" var bad2 = s + 1; // ERROR "conver|incompatible|invalid"
var bad3 = s + 'a'; // ERROR "conver|incompatible" var bad3 = s + 'a'; // ERROR "conver|incompatible|invalid"
var bad4 = "a" + 1; // ERROR "literals|incompatible|convert" var bad4 = "a" + 1; // ERROR "literals|incompatible|convert|invalid"
var bad5 = "a" + 'a'; // ERROR "literals|incompatible|convert" var bad5 = "a" + 'a'; // ERROR "literals|incompatible|convert|invalid"
var bad6 int = 1.5; // ERROR "convert|truncate" var bad6 int = 1.5; // ERROR "convert|truncate"
var bad7 int = 1e100; // ERROR "overflow" var bad7 int = 1e100; // ERROR "overflow"
......
...@@ -6,12 +6,12 @@ ...@@ -6,12 +6,12 @@
package main package main
var a = []int { "a" }; // ERROR "conver|incompatible" var a = []int { "a" }; // ERROR "conver|incompatible|cannot"
var b = int { 1 }; // ERROR "compos" var b = int { 1 }; // ERROR "compos"
func f() int func f() int
func main() { func main() {
if f < 1 { } // ERROR "conver|incompatible" if f < 1 { } // ERROR "conver|incompatible|invalid"
} }
...@@ -9,7 +9,7 @@ package main ...@@ -9,7 +9,7 @@ package main
func putint(digits *string) { func putint(digits *string) {
var i byte; var i byte;
i = (*digits)[7]; // compiles i = (*digits)[7]; // compiles
i = digits[7]; // ERROR "illegal|is not" i = digits[7]; // ERROR "illegal|is not|invalid"
} }
func main() { func main() {
......
...@@ -7,5 +7,5 @@ ...@@ -7,5 +7,5 @@
package main package main
func main() { func main() {
var s string = nil; // ERROR "illegal|invalid" var s string = nil; // ERROR "illegal|invalid|cannot"
} }
...@@ -38,9 +38,9 @@ func main() { ...@@ -38,9 +38,9 @@ func main() {
assert(i != f3div2, "i != f3div2"); // ERROR "truncate" assert(i != f3div2, "i != f3div2"); // ERROR "truncate"
const g float64 = 1.0; const g float64 = 1.0;
i = g; // ERROR "convert|incompatible" i = g; // ERROR "convert|incompatible|cannot"
const h float64 = 3.14; const h float64 = 3.14;
i = h; // ERROR "convert|incompatible" i = h; // ERROR "convert|incompatible|cannot"
i = int(h); // ERROR "truncate" i = int(h); // ERROR "truncate"
} }
...@@ -10,16 +10,6 @@ type T func() ...@@ -10,16 +10,6 @@ type T func()
type I interface { type I interface {
f, g (); f, g ();
h T; // should only allow FunctionType here h T; // ERROR "syntax"
} }
type S struct {
}
func (s *S) f() {}
func (s *S) g() {}
func (s *S) h() {} // here we can't write (s *S) T either
func main() {
var i I = new(S);
}
...@@ -8,5 +8,5 @@ package main ...@@ -8,5 +8,5 @@ package main
func main() { func main() {
const a uint64 = 10; const a uint64 = 10;
var b int64 = a; // ERROR "convert" var b int64 = a; // ERROR "convert|cannot"
} }
...@@ -10,5 +10,5 @@ func main() { ...@@ -10,5 +10,5 @@ func main() {
type Slice []byte; type Slice []byte;
a := [...]byte{ 0 }; a := [...]byte{ 0 };
b := Slice(&a); // This should be OK. b := Slice(&a); // This should be OK.
c := Slice(a); // ERROR "invalid|illegal" c := Slice(a); // ERROR "invalid|illegal|cannot"
} }
...@@ -5,9 +5,10 @@ ...@@ -5,9 +5,10 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package main package main
var v1 = ([10]int)(nil) // ERROR "illegal|nil|invalid" var v1 = ([10]int)(nil); // ERROR "illegal|nil|invalid"
var v2 [10]int = nil // ERROR "illegal|nil|incompatible" var v2 [10]int = nil; // ERROR "illegal|nil|incompatible"
var v3 [10]int var v3 [10]int;
var v4 = nil; // ERROR "nil"
func main() { func main() {
v3 = nil; // ERROR "illegal|nil|incompatible" v3 = nil; // ERROR "illegal|nil|incompatible"
} }
...@@ -9,6 +9,6 @@ package main ...@@ -9,6 +9,6 @@ package main
var notmain func() var notmain func()
func main() { func main() {
var x = &main; // ERROR "address of function|invalid" var x = &main; // ERROR "address of|invalid"
main = notmain; // ERROR "assign to function|invalid" main = notmain; // ERROR "assign to|invalid"
} }
...@@ -132,13 +132,6 @@ throw: interface conversion ...@@ -132,13 +132,6 @@ throw: interface conversion
panic PC=xxx panic PC=xxx
=========== fixedbugs/bug121.go
fixedbugs/bug121.go:9: syntax error near T
fixedbugs/bug121.go:20: incomplete type I
fixedbugs/bug121.go:20: illegal types for operand: AS
I
*S
=========== fixedbugs/bug148.go =========== fixedbugs/bug148.go
2 3 2 3
interface is main.T, not main.T·bug148·1 interface is main.T, not main.T·bug148·1
......
...@@ -32,6 +32,6 @@ func AddInst(Inst) *Inst { ...@@ -32,6 +32,6 @@ func AddInst(Inst) *Inst {
func main() { func main() {
re := new(Regexp); re := new(Regexp);
print("call addinst\n"); print("call addinst\n");
var x Inst = AddInst(new(Start)); // ERROR "illegal|incompatible" var x Inst = AddInst(new(Start)); // ERROR "illegal|incompatible|is not"
print("return from addinst\n"); print("return from addinst\n");
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment