blob: c6602953c54889c20d69eea638dbee14066bed30 [file] [log] [blame]
// 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 ODCLTYPE:
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 OCOLAS:
case ODCLVAR:
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 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;
walktype(n->left, 0);
if(!isptrto(n->left->type, TSTRING)) {
badtype(OSLICE, n->left->type, N);
return;
}
if(n->right->op != OLIST)
fatal("slice not a list");
// 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;
}