| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| #include "go.h" |
| |
| static Node* sw1(Node*, Node*); |
| static Node* sw2(Node*, Node*); |
| static Node* sw3(Node*, Node*); |
| static Node* curfn; |
| |
| void |
| walk(Node *fn) |
| { |
| curfn = fn; |
| walktype(fn->nbody, 1); |
| } |
| |
| void |
| walktype(Node *n, int top) |
| { |
| Node *t, *r; |
| Sym *s; |
| long lno; |
| int et; |
| |
| /* |
| * walk the whole tree of the body of a function. |
| * the types expressions are calculated. |
| * compile-time constants are evaluated. |
| */ |
| |
| lno = dynlineno; |
| |
| loop: |
| if(n == N) |
| goto ret; |
| if(n->op != ONAME) |
| dynlineno = n->lineno; // for diagnostics |
| |
| t = N; |
| et = Txxx; |
| |
| switch(n->op) { |
| default: |
| fatal("walktype: switch 1 unknown op %N", n); |
| goto ret; |
| |
| case OPANIC: |
| case OPRINT: |
| walktype(n->left, 0); |
| prcompat(&n->left); |
| goto ret; |
| |
| case OLITERAL: |
| n->addable = 1; |
| ullmancalc(n); |
| goto ret; |
| |
| case ONAME: |
| n->addable = 1; |
| ullmancalc(n); |
| if(n->type == N) { |
| s = n->sym; |
| if(s->undef == 0) { |
| yyerror("walktype: %N undeclared", n); |
| s->undef = 1; |
| } |
| } |
| goto ret; |
| |
| case OLIST: |
| walktype(n->left, top); |
| n = n->right; |
| goto loop; |
| |
| case OFOR: |
| if(!top) |
| goto nottop; |
| walktype(n->ninit, 1); |
| walktype(n->ntest, 1); |
| walktype(n->nincr, 1); |
| n = n->nbody; |
| goto loop; |
| |
| case OSWITCH: |
| if(!top) |
| goto nottop; |
| |
| if(n->ntest == N) |
| n->ntest = booltrue; |
| walktype(n->ninit, 1); |
| walktype(n->ntest, 1); |
| walktype(n->nbody, 1); |
| |
| // find common type |
| if(n->ntest->type == N) |
| n->ntest->type = walkswitch(n->ntest, n->nbody, sw1); |
| |
| // if that fails pick a type |
| if(n->ntest->type == N) |
| n->ntest->type = walkswitch(n->ntest, n->nbody, sw2); |
| |
| // set the type on all literals |
| if(n->ntest->type != N) |
| walkswitch(n->ntest, n->nbody, sw3); |
| |
| n = n->nincr; |
| goto loop; |
| |
| case OEMPTY: |
| if(!top) |
| goto nottop; |
| goto ret; |
| |
| case OIF: |
| if(!top) |
| goto nottop; |
| walktype(n->ninit, 1); |
| walktype(n->ntest, 1); |
| walktype(n->nelse, 1); |
| n = n->nbody; |
| goto loop; |
| |
| case OCALL: |
| case OCALLPTR: |
| case OCALLMETH: |
| case OCALLINTER: |
| walktype(n->left, 0); |
| if(n->left == N) |
| goto ret; |
| t = n->left->type; |
| if(t == N) |
| goto ret; |
| |
| if(n->left->op == ODOTMETH) |
| n->op = OCALLMETH; |
| if(n->left->op == ODOTINTER) |
| n->op = OCALLINTER; |
| |
| if(t->etype == TPTR) { |
| t = t->type; |
| n->op = OCALLPTR; |
| } |
| |
| if(t->etype != TFUNC) { |
| yyerror("call of a non-function %T", t); |
| goto ret; |
| } |
| |
| n->type = *getoutarg(t); |
| switch(t->outtuple) { |
| default: |
| n->kaka = PCALL_MULTI; |
| if(!top) |
| yyerror("function call must be single valued (%d)", et); |
| break; |
| case 0: |
| n->kaka = PCALL_NIL; |
| break; |
| case 1: |
| n->kaka = PCALL_SINGLE; |
| n->type = n->type->type->type; |
| break; |
| } |
| |
| r = n->right; |
| walktype(r, 0); |
| ascompatte(n->op, getinarg(t), &n->right); |
| goto ret; |
| |
| case OAS: |
| if(!top) |
| goto nottop; |
| |
| n->kaka = PAS_SINGLE; |
| r = n->left; |
| if(r != N && r->op == OLIST) |
| n->kaka = PAS_MULTI; |
| |
| walktype(r, 0); |
| |
| r = n->right; |
| if(r == N) |
| goto ret; |
| |
| if(r->op == OCALL && n->kaka == PAS_MULTI) { |
| walktype(r, 1); |
| if(r->kaka == PCALL_MULTI) { |
| ascompatet(n->op, &n->left, &r->type); |
| n->kaka = PAS_CALLM; |
| goto ret; |
| } |
| } |
| |
| walktype(n->right, 0); |
| ascompatee(n->op, &n->left, &n->right); |
| |
| if(n->kaka == PAS_SINGLE) { |
| t = n->right->type; |
| if(t != N && t->etype == TSTRUCT) |
| n->kaka = PAS_STRUCT; |
| } |
| goto ret; |
| |
| case OBREAK: |
| case OCONTINUE: |
| case OGOTO: |
| case OLABEL: |
| goto ret; |
| |
| case OXCASE: |
| yyerror("case statement out of place"); |
| n->op = OCASE; |
| |
| case OCASE: |
| n = n->left; |
| goto loop; |
| |
| case OXFALL: |
| yyerror("fallthrough statement out of place"); |
| n->op = OFALL; |
| |
| case OFALL: |
| goto ret; |
| |
| case OCONV: |
| walktype(n->left, 0); |
| if(n->left == N) |
| goto ret; |
| convlit(n->left, n->type); |
| if(eqtype(n->type, n->left->type, 0)) |
| *n = *n->left; |
| goto ret; |
| |
| case ORETURN: |
| walktype(n->left, 0); |
| ascompatte(n->op, getoutarg(curfn->type), &n->left); |
| goto ret; |
| |
| case ONOT: |
| walktype(n->left, 0); |
| if(n->left == N || n->left->type == N) |
| goto ret; |
| et = n->left->type->etype; |
| break; |
| |
| case OASOP: |
| if(!top) |
| goto nottop; |
| |
| case OLSH: |
| case ORSH: |
| case OMOD: |
| case OAND: |
| case OOR: |
| case OXOR: |
| case OANDAND: |
| case OOROR: |
| case OEQ: |
| case ONE: |
| case OLT: |
| case OLE: |
| case OGE: |
| case OGT: |
| case OADD: |
| case OSUB: |
| case OMUL: |
| case ODIV: |
| case OCAT: |
| walktype(n->left, 0); |
| walktype(n->right, 0); |
| if(n->left == N || n->right == N) |
| goto ret; |
| convlit(n->left, n->right->type); |
| convlit(n->right, n->left->type); |
| evconst(n); |
| if(n->op == OLITERAL) |
| goto ret; |
| if(n->left->type == N || n->right->type == N) |
| goto ret; |
| if(!ascompat(n->left->type, n->right->type)) |
| goto badt; |
| break; |
| |
| case OPLUS: |
| case OMINUS: |
| case OCOM: |
| walktype(n->left, 0); |
| if(n->left == N) |
| goto ret; |
| evconst(n); |
| ullmancalc(n); |
| if(n->op == OLITERAL) |
| goto ret; |
| break; |
| |
| case OLEN: |
| walktype(n->left, 0); |
| evconst(n); |
| ullmancalc(n); |
| t = n->left->type; |
| if(t != N && t->etype == TPTR) |
| t = t->type; |
| if(t == N) |
| goto ret; |
| switch(t->etype) { |
| default: |
| goto badt; |
| case TSTRING: |
| break; |
| } |
| n->type = types[TINT32]; |
| goto ret; |
| |
| case OINDEX: |
| case OINDEXPTR: |
| case OINDEXSTR: |
| case OINDEXMAP: |
| case OINDEXPTRMAP: |
| walktype(n->left, 0); |
| walktype(n->right, 0); |
| ullmancalc(n); |
| if(n->left == N || n->right == N) |
| goto ret; |
| t = n->left->type; |
| if(t == N) |
| goto ret; |
| |
| // map - left and right sides must match |
| if(t->etype == TMAP || isptrto(t, TMAP)) { |
| n->ullman = UINF; |
| n->op = OINDEXMAP; |
| if(isptrto(t, TMAP)) { |
| n->op = OINDEXPTRMAP; |
| t = t->type; |
| if(t == N) |
| goto ret; |
| } |
| convlit(n->right, t->down); |
| if(!ascompat(t->down, n->right->type)) |
| goto badt; |
| n->type = t->type; |
| goto ret; |
| } |
| |
| // right side must be an int |
| if(n->right->type == N) |
| convlit(n->right, types[TINT32]); |
| if(n->left->type == N || n->right->type == N) |
| goto ret; |
| if(!isint[n->right->type->etype]) |
| goto badt; |
| |
| // left side is string |
| if(isptrto(t, TSTRING)) { |
| n->op = OINDEXSTR; |
| n->type = types[TUINT8]; |
| goto ret; |
| } |
| |
| // left side is ptr to string |
| if(isptrto(t, TPTR) && isptrto(t->type, TSTRING)) { |
| n->op = OINDEXPTRSTR; |
| n->type = types[TUINT8]; |
| goto ret; |
| } |
| |
| // left side is array |
| if(t->etype == TPTR) { |
| t = t->type; |
| n->op = OINDEXPTR; |
| } |
| if(t->etype != TARRAY && t->etype != TDARRAY) |
| goto badt; |
| n->type = t->type; |
| goto ret; |
| |
| case OSLICE: |
| walkslice(n); |
| goto ret; |
| |
| case ODOT: |
| case ODOTPTR: |
| case ODOTMETH: |
| case ODOTINTER: |
| walkdot(n); |
| goto ret; |
| |
| case OADDR: |
| walktype(n->left, 0); |
| if(n->left == N) |
| goto ret; |
| t = n->left->type; |
| if(t == N) |
| goto ret; |
| n->type = ptrto(t); |
| goto ret; |
| |
| case OIND: |
| walktype(n->left, 0); |
| if(n->left == N) |
| goto ret; |
| t = n->left->type; |
| if(t == N) |
| goto ret; |
| if(t->etype != TPTR) |
| goto badt; |
| n->type = t->type; |
| goto ret; |
| |
| case ONEW: |
| if(n->left != N) |
| yyerror("dont know what new(,e) means"); |
| goto ret; |
| } |
| |
| /* |
| * ======== second switch ======== |
| */ |
| |
| switch(n->op) { |
| default: |
| fatal("walktype: switch 2 unknown op %N", n); |
| goto ret; |
| |
| case OASOP: |
| break; |
| |
| case ONOT: |
| case OANDAND: |
| case OOROR: |
| et = n->left->type->etype; |
| if(et != TBOOL) |
| goto badt; |
| t = types[TBOOL]; |
| break; |
| |
| case OEQ: |
| case ONE: |
| et = n->left->type->etype; |
| if(!okforeq[et]) |
| goto badt; |
| t = types[TBOOL]; |
| break; |
| |
| case OLT: |
| case OLE: |
| case OGE: |
| case OGT: |
| et = n->left->type->etype; |
| if(!okforadd[et]) |
| if(!isptrto(n->left->type, TSTRING)) |
| goto badt; |
| t = types[TBOOL]; |
| break; |
| |
| case OCAT: |
| case OADD: |
| if(isptrto(n->left->type, TSTRING)) { |
| n->op = OCAT; |
| break; |
| } |
| |
| case OSUB: |
| case OMUL: |
| case ODIV: |
| case OPLUS: |
| case OMINUS: |
| et = n->left->type->etype; |
| if(!okforadd[et]) |
| goto badt; |
| break; |
| |
| case OLSH: |
| case ORSH: |
| case OAND: |
| case OOR: |
| case OXOR: |
| case OMOD: |
| case OCOM: |
| et = n->left->type->etype; |
| if(!okforand[et]) |
| goto badt; |
| break; |
| } |
| |
| if(t == N) |
| t = n->left->type; |
| n->type = t; |
| ullmancalc(n); |
| goto ret; |
| |
| nottop: |
| fatal("walktype: not top %O", n->op); |
| |
| badt: |
| if(n->right == N) { |
| if(n->left == N) { |
| badtype(n->op, N, N); |
| goto ret; |
| } |
| badtype(n->op, n->left->type, N); |
| goto ret; |
| } |
| badtype(n->op, n->left->type, n->right->type); |
| goto ret; |
| |
| ret: |
| dynlineno = lno; |
| } |
| |
| /* |
| * return the first type |
| */ |
| Node* |
| sw1(Node *c, Node *place) |
| { |
| if(place == N) |
| return c->type; |
| return place; |
| } |
| |
| /* |
| * return a suitable type |
| */ |
| Node* |
| sw2(Node *c, Node *place) |
| { |
| return types[TINT32]; // botch |
| } |
| |
| /* |
| * check that selected type |
| * is compat with all the cases |
| */ |
| Node* |
| sw3(Node *c, Node *place) |
| { |
| if(place == N) |
| return c->type; |
| if(c->type == N) |
| c->type = place; |
| convlit(c, place); |
| if(!ascompat(place, c->type)) |
| badtype(OSWITCH, place, c->type); |
| return place; |
| } |
| |
| Node* |
| walkswitch(Node *test, Node *body, Node*(*call)(Node*, Node*)) |
| { |
| Node *n, *c; |
| Node *place; |
| |
| place = call(test, N); |
| |
| n = body; |
| if(n->op == OLIST) |
| n = n->left; |
| |
| for(; n!=N; n=n->right) { |
| if(n->op != OCASE) |
| fatal("walkswitch: not case %O\n", n->op); |
| for(c=n->left; c!=N; c=c->right) { |
| if(c->op != OLIST) { |
| place = call(c, place); |
| break; |
| } |
| place = call(c->left, place); |
| } |
| } |
| return place; |
| } |
| |
| int |
| casebody(Node *n) |
| { |
| Node *oc, *ot, *t; |
| Iter save; |
| |
| |
| /* |
| * look to see if statements at top level have |
| * case labels attached to them. convert the illegal |
| * ops XFALL and XCASE into legal ops FALL and CASE. |
| * all unconverted ops will thus be caught as illegal |
| */ |
| |
| oc = N; // last case statement |
| ot = N; // last statement (look for XFALL) |
| |
| t = listfirst(&save, &n); |
| |
| if(t->op != OXCASE) |
| return 0; |
| |
| loop: |
| if(t == N) { |
| if(oc == N) |
| return 0; |
| return 1; |
| } |
| if(t->op == OXCASE) { |
| /* rewrite and link top level cases */ |
| t->op = OCASE; |
| if(oc != N) |
| oc->right = t; |
| oc = t; |
| |
| /* rewrite top fall that preceed case */ |
| if(ot != N && ot->op == OXFALL) |
| ot->op = OFALL; |
| } |
| |
| /* if first statement is not case then return 0 */ |
| if(oc == N) |
| return 0; |
| |
| ot = t; |
| t = listnext(&save); |
| goto loop; |
| } |
| |
| /* |
| * allowable type combinations for |
| * normal binary operations. |
| */ |
| |
| Node* |
| lookdot(Node *n, Node *t, int d) |
| { |
| Node *r, *f, *c; |
| Sym *s; |
| int o; |
| |
| r = N; |
| s = n->sym; |
| if(d > 0) |
| goto deep; |
| |
| o = 0; |
| for(f=t->type; f!=N; f=f->down) { |
| f->kaka = o; |
| o++; |
| |
| if(f->sym == S) |
| continue; |
| if(f->sym != s) |
| continue; |
| if(r != N) { |
| yyerror("ambiguous DOT reference %s", s->name); |
| break; |
| } |
| r = f; |
| } |
| return r; |
| |
| deep: |
| /* deeper look after shallow failed */ |
| for(f=t->type; f!=N; f=f->down) { |
| // only look at unnamed sub-structures |
| // BOTCH no such thing -- all are assigned temp names |
| if(f->sym != S) |
| continue; |
| c = f->type; |
| if(c->etype != TSTRUCT) |
| continue; |
| c = lookdot(n, c, d-1); |
| if(c == N) |
| continue; |
| if(r != N) { |
| yyerror("ambiguous unnamed DOT reference %s", s->name); |
| break; |
| } |
| r = c; |
| } |
| return r; |
| } |
| |
| void |
| walkdot(Node *n) |
| { |
| Node *t, *f; |
| int i; |
| |
| if(n->left == N || n->right == N) |
| return; |
| |
| walktype(n->left, 0); |
| if(n->right->op != ONAME) { |
| yyerror("rhs of . must be a name"); |
| return; |
| } |
| |
| t = n->left->type; |
| if(t == N) |
| return; |
| |
| if(t->etype == TPTR) { |
| t = t->type; |
| if(t == N) |
| return; |
| n->op = ODOTPTR; |
| } |
| |
| if(n->right->op != ONAME) |
| fatal("walkdot: not name %O", n->right->op); |
| |
| switch(t->etype) { |
| default: |
| badtype(ODOT, t, N); |
| return; |
| |
| case TSTRUCT: |
| case TINTER: |
| for(i=0; i<5; i++) { |
| f = lookdot(n->right, t, i); |
| if(f != N) |
| break; |
| } |
| if(f == N) { |
| yyerror("undefined DOT reference %N", n->right); |
| break; |
| } |
| n->right = f->nname; // substitute real name |
| n->type = f->type; |
| if(n->type->etype == TFUNC) { |
| n->op = ODOTMETH; |
| if(t->etype == TINTER) { |
| n->op = ODOTINTER; |
| n->kaka = f->kaka; |
| } |
| } |
| break; |
| } |
| } |
| |
| void |
| walkslice(Node *n) |
| { |
| Node *l, *r; |
| |
| if(n->left == N || n->right == N) |
| return; |
| if(n->right->op != OLIST) |
| fatal("slice not a list"); |
| |
| walktype(n->left, 0); |
| if(isptrto(n->left->type, TSTRING)) { |
| n->op = OSLICESTR; |
| goto ok; |
| } |
| if(isptrto(n->left->type->type, TPTR) && isptrto(n->left->type->type, TSTRING)) { |
| n->op = OSLICEPTRSTR; |
| goto ok; |
| } |
| |
| badtype(OSLICE, n->left->type, N); |
| return; |
| |
| ok: |
| // check for type errors |
| walktype(n->right, 0); |
| l = n->right->left; |
| r = n->right->right; |
| convlit(l, types[TINT32]); |
| convlit(r, types[TINT32]); |
| if(l == N || r == N || |
| l->type == N || r->type == N) |
| return; |
| if(!isint[l->type->etype] || !isint[l->type->etype]) { |
| badtype(OSLICE, l->type, r->type); |
| return; |
| } |
| |
| // now convert to int32 |
| n->right->left = nod(OCONV, n->right->left, N); |
| n->right->left->type = types[TINT32]; |
| n->right->right = nod(OCONV, n->right->right, N); |
| n->right->right->type = types[TINT32]; |
| walktype(n->right, 0); |
| |
| n->type = n->left->type; |
| } |
| |
| /* |
| * test tuple type list against each other |
| * called in four contexts |
| * 1. a,b = c,d ...ee |
| * 2. a,b = fn() ...et |
| * 3. call(fn()) ...tt |
| * 4. call(a,b) ...te |
| */ |
| void |
| ascompatee(int op, Node **nl, Node **nr) |
| { |
| Node *l, *r; |
| Iter savel, saver; |
| int sa, na; |
| |
| l = listfirst(&savel, nl); |
| r = listfirst(&saver, nr); |
| na = 0; // number of assignments - looking for multi |
| sa = 0; // one of the assignments is a structure assignment |
| |
| loop: |
| if(l == N || r == N) { |
| if(l != r) |
| yyerror("error in shape across assignment"); |
| if(sa != 0 && na > 1) |
| yyerror("cant do multi-struct assignments"); |
| return; |
| } |
| |
| convlit(r, l->type); |
| |
| if(!ascompat(l->type, r->type)) { |
| badtype(op, l->type, r->type); |
| return; |
| } |
| if(l->type != N && l->type->etype == TSTRUCT) |
| sa = 1; |
| |
| l = listnext(&savel); |
| r = listnext(&saver); |
| na++; |
| goto loop; |
| } |
| |
| void |
| ascompatet(int op, Node **nl, Node **nr) |
| { |
| Node *l, *r; |
| Iter savel, saver; |
| |
| l = listfirst(&savel, nl); |
| r = structfirst(&saver, nr); |
| |
| loop: |
| if(l == N || r == N) { |
| if(l != r) |
| yyerror("error in shape across assignment"); |
| return; |
| } |
| |
| if(!ascompat(l->type, r->type)) { |
| badtype(op, l->type, r->type); |
| return; |
| } |
| |
| l = listnext(&savel); |
| r = structnext(&saver); |
| |
| goto loop; |
| } |
| |
| void |
| ascompatte(int op, Node **nl, Node **nr) |
| { |
| Node *l, *r; |
| Iter savel, saver; |
| |
| l = structfirst(&savel, nl); |
| r = listfirst(&saver, nr); |
| |
| loop: |
| if(l == N || r == N) { |
| if(l != r) |
| yyerror("error in shape across assignment"); |
| return; |
| } |
| |
| convlit(r, l->type); |
| |
| if(!ascompat(l->type, r->type)) { |
| badtype(op, l->type, r->type); |
| return; |
| } |
| |
| l = structnext(&savel); |
| r = listnext(&saver); |
| |
| goto loop; |
| } |
| |
| void |
| ascompattt(int op, Node **nl, Node **nr) |
| { |
| Node *l, *r; |
| Iter savel, saver; |
| |
| l = structfirst(&savel, nl); |
| r = structfirst(&saver, nr); |
| |
| loop: |
| if(l == N || r == N) { |
| if(l != r) |
| yyerror("error in shape across assignment"); |
| return; |
| } |
| |
| if(!ascompat(l->type, r->type)) { |
| badtype(op, l->type, r->type); |
| return; |
| } |
| |
| l = structnext(&savel); |
| r = structnext(&saver); |
| |
| goto loop; |
| } |
| |
| /* |
| * can we assign var of type t2 to var of type t1 |
| */ |
| int |
| ascompat(Node *t1, Node *t2) |
| { |
| if(eqtype(t1, t2, 0)) |
| return 1; |
| // if(eqtype(t1, nilptr, 0)) |
| // return 1; |
| // if(eqtype(t2, nilptr, 0)) |
| // return 1; |
| if(isinter(t1)) |
| if(isptrto(t2, TSTRUCT) || isinter(t2)) |
| return 1; |
| if(isinter(t2)) |
| if(isptrto(t1, TSTRUCT)) |
| return 1; |
| return 0; |
| } |
| |
| void |
| prcompat(Node **n) |
| { |
| Node *l, *t; |
| Iter save; |
| int w; |
| |
| l = listfirst(&save, n); |
| |
| loop: |
| if(l == N) |
| return; |
| |
| t = N; |
| w = whatis(l); |
| switch(w) { |
| default: |
| badtype((*n)->op, l->type, N); |
| break; |
| case Wtint: |
| case Wtfloat: |
| case Wtbool: |
| case Wtstr: |
| break; |
| case Wlitint: |
| t = types[TINT32]; |
| break; |
| case Wlitfloat: |
| t = types[TFLOAT64]; |
| break; |
| case Wlitbool: |
| t = types[TBOOL]; |
| break; |
| case Wlitstr: |
| t = types[TSTRING]; |
| break; |
| } |
| |
| if(t != N) |
| convlit(l, t); |
| |
| l = listnext(&save); |
| goto loop; |
| } |