blob: eeadbf2896249d17cc3b875d5bada9535c39998d [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 void implicitstar(Node**);
static int onearg(Node*);
static int lookdot(Node*, Type*);
static int convert(Node**, Type*, int);
void
typechecklist(NodeList *l, int top)
{
for(; l; l=l->next)
typecheck(&l->n, top);
}
/*
* 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.
* replaces *np with a new pointer in some cases.
* returns the final value of *np as a convenience.
*/
Node*
typecheck(Node **np, int top)
{
int et, op, nerr, len;
NodeList *ll;
Node *n, *l, *r;
NodeList *args;
int i, lno, ok;
Type *t;
n = *np;
if(n == N || n->typecheck == 1)
return n;
if(n->typecheck == 2)
fatal("typecheck loop");
n->typecheck = 2;
if(n->sym && n->walkdef != 1)
walkdef(n);
lno = setlineno(n);
reswitch:
ok = 0;
switch(n->op) {
default:
// until typecheck is complete, do nothing.
dump("typecheck", n);
fatal("typecheck %O", n->op);
/*
* names
*/
case OLITERAL:
ok |= Erv;
goto ret;
case ONONAME:
ok |= Elv | Erv;
goto ret;
case ONAME:
if(n->etype != 0) {
yyerror("must call builtin %S", n->sym);
goto error;
}
ok |= Erv;
if(n->class != PFUNC)
ok |= Elv;
goto ret;
/*
* types (OIND is with exprs)
*/
case OTYPE:
ok |= Etype;
if(n->type == T)
goto error;
break;
case OTARRAY:
ok |= Etype;
t = typ(TARRAY);
l = n->left;
r = n->right;
if(l == nil) {
t->bound = -1;
} else {
typecheck(&l, Erv | Etype);
switch(l->op) {
default:
yyerror("invalid array bound %#N", l);
goto error;
case OLITERAL:
if(consttype(l) == CTINT) {
t->bound = mpgetfix(l->val.u.xval);
if(t->bound < 0) {
yyerror("array bound must be non-negative");
goto error;
}
}
break;
case OTYPE:
if(l->type == T)
goto error;
if(l->type->etype != TDDD) {
yyerror("invalid array bound %T", l->type);
goto error;
}
t->bound = -100;
break;
}
}
typecheck(&r, Etype);
if(r->type == T)
goto error;
t->type = r->type;
n->op = OTYPE;
n->type = t;
n->left = N;
n->right = N;
checkwidth(t);
break;
case OTMAP:
ok |= Etype;
l = typecheck(&n->left, Etype);
r = typecheck(&n->right, Etype);
if(l->type == T || r->type == T)
goto error;
n->op = OTYPE;
n->type = maptype(l->type, r->type);
n->left = N;
n->right = N;
break;
case OTCHAN:
ok |= Etype;
l = typecheck(&n->left, Etype);
if(l->type == T)
goto error;
t = typ(TCHAN);
t->type = l->type;
t->chan = n->etype;
n->op = OTYPE;
n->type = t;
n->left = N;
n->etype = 0;
break;
case OTSTRUCT:
ok |= Etype;
n->op = OTYPE;
n->type = dostruct(n->list, TSTRUCT);
if(n->type == T)
goto error;
n->list = nil;
break;
case OTINTER:
ok |= Etype;
n->op = OTYPE;
n->type = dostruct(n->list, TINTER);
if(n->type == T)
goto error;
n->type = sortinter(n->type);
break;
case OTFUNC:
ok |= Etype;
n->op = OTYPE;
n->type = functype(n->left, n->list, n->rlist);
if(n->type == T)
goto error;
break;
/*
* type or expr
*/
case OIND:
l = typecheck(&n->left, top | Etype);
if((t = l->type) == T)
goto error;
if(l->op == OTYPE) {
ok |= Etype;
n->op = OTYPE;
n->type = ptrto(l->type);
n->left = N;
goto ret;
}
if(!isptr[t->etype]) {
yyerror("invalid indirect %#N (non-pointer type %T)", n, t);
goto error;
}
n->type = t->type;
goto ret;
/*
* arithmetic exprs
*/
case OASOP:
ok |= Etop;
l = typecheck(&n->left, Elv);
r = typecheck(&n->right, Erv);
if(l->type == T || r->type == T)
goto error;
op = n->etype;
goto arith;
case OADD:
case OAND:
case OANDAND:
case OANDNOT:
case ODIV:
case OEQ:
case OGE:
case OGT:
case OLE:
case OLT:
case OLSH:
case ORSH:
case OMOD:
case OMUL:
case ONE:
case OOR:
case OOROR:
case OSUB:
case OXOR:
ok |= Erv;
l = typecheck(&n->left, Erv);
r = typecheck(&n->right, Erv);
if(l->type == T || r->type == T)
goto error;
op = n->op;
arith:
if(op == OLSH || op == ORSH)
goto shift;
// ideal mixed with non-ideal
defaultlit2(&l, &r, 0);
n->left = l;
n->right = r;
t = l->type;
if(t->etype == TIDEAL)
t = r->type;
et = t->etype;
if(et == TIDEAL)
et = TINT;
if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
badbinary:
defaultlit2(&l, &r, 1);
yyerror("invalid operation: %#N (type %T %#O %T)", n, l->type, op, r->type);
goto error;
}
if(!okfor[op][et])
goto badbinary;
// okfor allows any array == array;
// restrict to slice == nil and nil == slice.
if(l->type->etype == TARRAY && !isslice(l->type))
goto badbinary;
if(r->type->etype == TARRAY && !isslice(r->type))
goto badbinary;
if(isslice(l->type) && !isnil(l) && !isnil(r))
goto badbinary;
t = l->type;
if(iscmp[n->op]) {
t = types[TBOOL];
evconst(n);
if(n->op != OLITERAL) {
defaultlit2(&l, &r, 1);
n->left = l;
n->right = r;
}
}
n->type = t;
goto ret;
shift:
defaultlit(&r, types[TUINT]);
n->right = r;
t = r->type;
if(!isint[t->etype] || issigned[t->etype]) {
yyerror("invalid operation: %#N (shift count type %T)", n, r->type);
goto error;
}
// no defaultlit for left
// the outer context gives the type
n->type = l->type;
goto ret;
case OCOM:
case OMINUS:
case ONOT:
case OPLUS:
ok |= Erv;
l = typecheck(&n->left, Erv);
if((t = l->type) == T)
goto error;
if(!okfor[n->op][t->etype]) {
yyerror("invalid operation: %#O %T", n->op, t);
goto error;
}
n->type = t;
goto ret;
/*
* exprs
*/
case OADDR:
l = typecheck(&n->left, Elv);
if((t = l->type) == T)
goto error;
n->type = ptrto(t);
goto ret;
case OCOMPOS:
l = typecheck(&n->right /* sic */, Etype /* TODO | Edotarray */);
if((t = l->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;
n->type = t;
goto ret;
case ODOT:
l = typecheck(&n->left, Erv);
if((t = l->type) == T)
goto error;
if(n->right->op != ONAME) {
yyerror("rhs of . must be a name"); // impossible
goto error;
}
if(isptr[t->etype]) {
t = t->type;
if(t == T)
goto error;
n->op = ODOTPTR;
}
if(!lookdot(n, t)) {
yyerror("%#N undefined (%S in type %T)", n, n->right->sym, t);
goto error;
}
switch(n->op) {
case ODOTINTER:
case ODOTMETH:
ok |= Ecall;
break;
default:
ok |= Erv;
// TODO ok |= Elv sometimes
break;
}
goto ret;
case ODOTTYPE:
typecheck(&n->left, Erv);
defaultlit(&n->left, T);
l = n->left;
if((t = l->type) == T)
goto error;
if(!isinter(t)) {
yyerror("invalid type assertion: %#N (non-interface type %T on left)", n, t);
goto error;
}
if(n->right != N) {
typecheck(&n->right, Etype);
n->type = n->right->type;
n->right = N;
if(n->type == T)
goto error;
}
goto ret;
case OINDEX:
typecheck(&n->left, Erv);
defaultlit(&n->left, T);
implicitstar(&n->left);
l = n->left;
typecheck(&n->right, Erv);
r = n->right;
if((t = l->type) == T || r->type == T)
goto error;
switch(t->etype) {
default:
yyerror("invalid operation: %#N (index of type %T)", n, t);
goto error;
case TARRAY:
ok |= Erv | Elv;
defaultlit(&n->right, types[TUINT]);
n->type = t->type;
break;
case TMAP:
ok |= Erv | Elv;
defaultlit(&n->right, t->down);
n->type = t->type;
break;
case TSTRING:
ok |= Erv;
defaultlit(&n->right, types[TUINT]);
n->type = types[TUINT8];
break;
}
goto ret;
case ORECV:
typecheck(&n->left, Erv);
defaultlit(&n->left, T);
l = n->left;
if((t = l->type) == T)
goto error;
if(t->etype != TCHAN) {
yyerror("invalid operation: %#N (recv from non-chan type %T)", n, t);
goto error;
}
if(!(t->chan & Crecv)) {
yyerror("invalid operation: %#N (recv from send-only type %T)", n, t);
goto error;
}
n->type = t->type;
ok |= Erv;
goto ret;
case OSEND:
l = typecheck(&n->left, Erv);
typecheck(&n->right, Erv);
defaultlit(&n->left, T);
l = n->left;
if((t = l->type) == T)
goto error;
if(!(t->chan & Csend)) {
yyerror("invalid operation: %#N (send to recv-only type %T)", n, t);
goto error;
}
defaultlit(&n->right, t->type);
r = n->right;
if((t = r->type) == T)
goto error;
// TODO: more aggressive
ok |= Etop | Erv;
n->type = types[TBOOL];
goto ret;
case OSLICE:
ok |= Erv;
typecheck(&n->left, top);
typecheck(&n->right->left, Erv);
typecheck(&n->right->right, Erv);
defaultlit(&n->left, T);
defaultlit(&n->right->left, types[TUINT]);
defaultlit(&n->right->right, types[TUINT]);
implicitstar(&n->left);
if(n->right->left == N || n->right->right == N) {
yyerror("missing slice bounds?");
goto error;
}
if((t = n->right->left->type) == T)
goto error;
if(!isint[t->etype]) {
yyerror("invalid array index %#N (type %T)", n->right->left, t);
goto error;
}
if((t = n->right->right->type) == T)
goto error;
if(!isint[t->etype]) {
yyerror("invalid array index %#N (type %T)", n->right->right, t);
goto error;
}
l = n->left;
if((t = l->type) == T)
goto error;
// TODO(rsc): 64-bit slice index needs to be checked
// for overflow in generated code
switch(t->etype) {
default:
yyerror("invalid operation: %#N (slice of type %T)", n, t);
goto error;
case TARRAY:
ok |= Elv;
n = arrayop(n, Erv);
break;
case TSTRING:
n = stringop(n, Erv, nil);
break;
}
goto ret;
/*
* call and call like
*/
case OCALL:
l = n->left;
if(l->op == ONAME && l->etype != 0) {
// builtin: OLEN, OCAP, etc.
n->op = l->etype;
n->left = n->right;
n->right = N;
goto reswitch;
}
l = typecheck(&n->left, Erv | Etype | Ecall);
typechecklist(n->list, Erv);
if((t = l->type) == T)
{
yyerror("skip %#N", n);
goto error;
}
if(l->op == OTYPE) {
ok |= Erv;
// turn CALL(type, arg) into CONV(arg) w/ type
n->left = N;
if(onearg(n) < 0)
goto error;
n->op = OCONV;
n->type = l->type;
goto doconv;
}
// TODO: check args
if(t->outtuple == 0) {
ok |= Etop;
goto ret;
}
if(t->outtuple == 1) {
ok |= Erv;
t = getoutargx(l->type)->type;
if(t->etype == TFIELD)
t = t->type;
n->type = t;
goto ret;
}
// multiple return
// ok |= Emulti;
n->type = getoutargx(l->type);
goto ret;
case OCAP:
case OLEN:
if(onearg(n) < 0)
goto error;
typecheck(&n->left, Erv);
defaultlit(&n->left, T);
implicitstar(&n->left);
l = n->left;
if((t = l->type) == T)
goto error;
switch(n->op) {
case OCAP:
if(!okforcap[t->etype])
goto badcall1;
break;
case OLEN:
if(!okforlen[t->etype])
goto badcall1;
break;
}
// might be constant
switch(t->etype) {
case TSTRING:
if(isconst(l, CTSTR))
nodconst(n, types[TINT], l->val.u.sval->len);
break;
case TARRAY:
if(t->bound >= 0)
nodconst(n, types[TINT], t->bound);
break;
}
n->type = types[TINT];
goto ret;
case OCLOSED:
ok |= Erv;
case OCLOSE:
ok |= Etop;
if(onearg(n) < 0)
goto error;
typecheck(&n->left, Erv);
defaultlit(&n->left, T);
l = n->left;
if((t = l->type) == T)
goto error;
if(t->etype != TCHAN) {
yyerror("invalid operation: %#N (non-chan type %T)", n, t);
goto error;
}
if(n->op == OCLOSED)
n->type = types[TBOOL];
goto ret;
case OCONV:
doconv:
typecheck(&n->left, Erv);
defaultlit(&n->left, n->type);
if((t = n->left->type) == T)
goto error;
switch(convert(&n->left, n->type, 1)) {
case -1:
goto error;
case 0:
n = n->left;
break;
case OCONV:
break;
}
goto ret;
case OMAKE:
args = n->list;
if(args == nil) {
yyerror("missing argument to make");
goto error;
}
l = args->n;
args = args->next;
typecheck(&l, Etype);
if((t = l->type) == T)
goto error;
switch(t->etype) {
default:
badmake:
yyerror("cannot make type %T", t);
goto error;
case TARRAY:
if(!isslice(t))
goto badmake;
if(args == nil) {
yyerror("missing len argument to make(%T)", t);
goto error;
}
l = args->n;
args = args->next;
typecheck(&l, Erv);
defaultlit(&l, types[TUINT]);
r = N;
if(args != nil) {
r = args->n;
args = args->next;
typecheck(&r, Erv);
defaultlit(&r, types[TUINT]);
}
if(l->type == T || (r && r->type == T))
goto error;
if(!isint[l->type->etype]) {
yyerror("non-integer len argument to make(%T)", t);
goto error;
}
if(r && !isint[r->type->etype]) {
yyerror("non-integer cap argument to make(%T)", t);
goto error;
}
n->left = l;
n->right = r;
break;
case TMAP:
if(args != nil) {
l = args->n;
args = args->next;
typecheck(&l, Erv);
defaultlit(&l, types[TUINT]);
if(l->type == T)
goto error;
if(!isint[l->type->etype]) {
yyerror("non-integer size argument to make(%T)", t);
goto error;
}
n->left = l;
}
break;
case TCHAN:
l = N;
if(args != nil) {
l = args->n;
args = args->next;
typecheck(&l, Erv);
defaultlit(&l, types[TUINT]);
if(l->type == T)
goto error;
if(!isint[l->type->etype]) {
yyerror("non-integer buffer argument to make(%T)", t);
goto error;
}
n->left = l;
}
break;
}
if(args != nil) {
yyerror("too many arguments to make(%T)", t);
goto error;
}
n->type = t;
goto ret;
case ONEW:
args = n->list;
if(args == nil) {
yyerror("missing argument to new");
goto error;
}
l = args->n;
typecheck(&l, Etype);
if((t = l->type) == T)
goto error;
if(args->next != nil) {
yyerror("too many arguments to new(%T)", t);
goto error;
}
n->left = l;
n->type = ptrto(t);
goto ret;
case OPANIC:
case OPANICN:
case OPRINT:
case OPRINTN:
typechecklist(n->list, Erv);
goto ret;
/*
* statements
*/
case OAS:
typecheck(&n->left, Elv);
typecheck(&n->right, Erv);
goto ret;
case OAS2:
typechecklist(n->list, Elv);
typechecklist(n->rlist, Erv);
goto ret;
case OBREAK:
case OCONTINUE:
case ODCL:
case OEMPTY:
case OGOTO:
case OLABEL:
case OXFALL:
goto ret;
case ODEFER:
case OPROC:
typecheck(&n->left, Etop);
goto ret;
case OFOR:
typechecklist(n->ninit, Etop);
typecheck(&n->ntest, Erv); // TODO Ebool
typecheck(&n->nincr, Etop);
typechecklist(n->nbody, Etop);
goto ret;
case OIF:
typechecklist(n->ninit, Etop);
typecheck(&n->ntest, Erv); // TODO Ebool
typechecklist(n->nbody, Etop);
typechecklist(n->nelse, Etop);
goto ret;
case ORETURN:
typechecklist(n->list, Erv);
// TODO convert
goto ret;
case OSELECT:
typechecklist(n->ninit, Etop);
typecheck(&n->ntest, Erv);
typechecklist(n->list, Etop);
goto ret;
case OSWITCH:
typechecklist(n->ninit, Etop);
typecheck(&n->ntest, Erv);
typechecklist(n->list, Etop);
goto ret;
case OTYPECASE:
typecheck(&n->left, Elv);
goto ret;
case OTYPESW:
typecheck(&n->right, Erv);
goto ret;
case OXCASE:
typechecklist(n->list, Erv);
typechecklist(n->nbody, Etop);
goto ret;
}
ret:
evconst(n);
if(n->op == OTYPE && !(top & Etype)) {
yyerror("type %T is not an expression", n->type);
goto error;
}
if((top & (Elv|Erv|Etype)) == Etype && n->op != OTYPE) {
yyerror("%O is not a type", n->op);
goto error;
}
if((ok & Ecall) && !(top & Ecall)) {
yyerror("must call method %#N", n);
goto error;
}
/* TODO
if(n->type == T)
fatal("typecheck nil type");
*/
goto out;
badcall1:
yyerror("invalid argument %#N (type %T) for %#O", n->left, n->left->type, n->op);
goto error;
error:
n->type = T;
out:
lineno = lno;
n->typecheck = 1;
*np = n;
return n;
}
static void
implicitstar(Node **nn)
{
Type *t;
Node *n;
// insert implicit * if needed
n = *nn;
t = n->type;
if(t == T || !isptr[t->etype])
return;
t = t->type;
if(t == T)
return;
if(!isfixedarray(t))
return;
n = nod(OIND, n, N);
typecheck(&n, Erv);
*nn = n;
}
static int
onearg(Node *n)
{
if(n->left != N)
return 0;
if(n->list == nil) {
yyerror("missing argument to %#O - %#N", n->op, n);
return -1;
}
n->left = n->list->n;
if(n->list->next != nil) {
yyerror("too many arguments to %#O", n->op);
n->list = nil;
return -1;
}
n->list = nil;
return 0;
}
static Type*
lookdot1(Sym *s, Type *t, Type *f)
{
Type *r;
r = T;
for(; f!=T; f=f->down) {
if(f->sym != s)
continue;
if(r != T) {
yyerror("ambiguous DOT reference %T.%S", t, s);
break;
}
r = f;
}
return r;
}
static int
lookdot(Node *n, Type *t)
{
Type *f1, *f2, *tt, *rcvr;
Sym *s;
s = n->right->sym;
f1 = T;
if(t->etype == TSTRUCT || t->etype == TINTER)
f1 = lookdot1(s, t, t->type);
f2 = methtype(n->left->type);
if(f2 != T)
f2 = lookdot1(s, f2, f2->method);
if(f1 != T) {
if(f2 != T)
yyerror("ambiguous DOT reference %S as both field and method",
n->right->sym);
n->xoffset = f1->width;
n->type = f1->type;
if(t->etype == TINTER) {
if(isptr[n->left->type->etype]) {
n->left = nod(OIND, n->left, N); // implicitstar
typecheck(&n->left, Elv);
}
n->op = ODOTINTER;
}
return 1;
}
if(f2 != T) {
tt = n->left->type;
rcvr = getthisx(f2->type)->type->type;
if(!eqtype(rcvr, tt)) {
if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
typecheck(&n->left, Elv);
addrescapes(n->left);
n->left = nod(OADDR, n->left, N);
typecheck(&n->left, Erv);
} else if(tt->etype == tptr && eqtype(tt->type, rcvr)) {
n->left = nod(OIND, n->left, N);
typecheck(&n->left, Erv);
} else {
// method is attached to wrong type?
fatal("method mismatch: %T for %T", rcvr, tt);
}
}
n->right = methodname(n->right, n->left->type);
n->xoffset = f2->width;
n->type = f2->type;
n->op = ODOTMETH;
return 1;
}
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
convert(Node **np, Type *t, int explicit)
{
int et;
Node *n, *n1;
Type *tt;
n = *np;
if(n->type == t)
return 0;
if(eqtype(n->type, t))
return OCONV;
// XXX wtf?
convlit1(&n, t, explicit);
if(n->type == T)
return -1;
// no-op conversion
if(cvttype(t, n->type) == 1) {
if(n->op == OLITERAL) {
// can convert literal in place
n1 = nod(OXXX, N, N);
*n1 = *n;
n1->type = t;
*np = n1;
return 0;
}
return OCONV;
}
if(!explicit) {
yyerror("cannot use %#N (type %T) as type %T", n, n->type, t);
return -1;
}
// simple fix-float
if(isint[n->type->etype] || isfloat[n->type->etype])
if(isint[t->etype] || isfloat[t->etype]) {
// evconst(n); // XXX is this needed?
return OCONV;
}
// 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
if(istype(t, TSTRING)) {
// integer rune
et = n->type->etype;
if(isint[et]) {
// xxx;
return OCONVRUNE;
}
// []byte and *[10]byte -> string
tt = T;
if(isptr[et] && isfixedarray(n->type->type))
tt = n->type->type->type;
else if(isslice(n->type))
tt = n->type->type;
if(tt) {
if(tt->etype == TUINT8)
return OCONVSTRB;
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
if(isptrto(t, TANY)
&& (isptr[n->type->etype] || n->type->etype == TUINTPTR))
return OCONV;
// convert from unsafe pointer
if(isptrto(n->type, TANY)
&& (isptr[t->etype] || t->etype == TUINTPTR))
return OCONV;
yyerror("cannot convert %#N (type %T) to type %T", n, n->type, t);
return -1;
}