Commit b648716e authored by Russ Cox's avatar Russ Cox

forward declarations not necessary.

still to do:
	* initializer cycle detection
	* nicer error for type checking cycles

R=ken
OCL=32855
CL=32880
parent e98dde27
...@@ -18,7 +18,7 @@ OFILES=\ ...@@ -18,7 +18,7 @@ OFILES=\
align.$O\ align.$O\
bits.$O\ bits.$O\
builtin.$O\ builtin.$O\
compat.$O\ closure.$O\
const.$O\ const.$O\
dcl.$O\ dcl.$O\
export.$O\ export.$O\
......
...@@ -61,10 +61,23 @@ widstruct(Type *t, uint32 o, int flag) ...@@ -61,10 +61,23 @@ widstruct(Type *t, uint32 o, int flag)
if(f->etype != TFIELD) if(f->etype != TFIELD)
fatal("widstruct: not TFIELD: %lT", f); fatal("widstruct: not TFIELD: %lT", f);
dowidth(f->type); dowidth(f->type);
if(f->type->width < 0 || f->type->width > 100000000)
fatal("invalid width %lld", f->type->width);
w = f->type->width; w = f->type->width;
m = arrayelemwidth(f->type); m = arrayelemwidth(f->type);
o = rnd(o, m); o = rnd(o, m);
f->width = o; // really offset for TFIELD f->width = o; // really offset for TFIELD
if(f->nname != N) {
// this same stackparam logic is in addrescapes
// in typecheck.c. usually addrescapes runs after
// widstruct, in which case we could drop this,
// but function closure functions are the exception.
if(f->nname->stackparam) {
f->nname->stackparam->xoffset = o;
f->nname->xoffset = 0;
} else
f->nname->xoffset = o;
}
o += w; o += w;
} }
// final width is rounded // final width is rounded
...@@ -91,6 +104,9 @@ dowidth(Type *t) ...@@ -91,6 +104,9 @@ dowidth(Type *t)
if(t == T) if(t == T)
return; return;
if(t->width > 0)
return;
if(t->width == -2) { if(t->width == -2) {
yyerror("invalid recursive type %T", t); yyerror("invalid recursive type %T", t);
t->width = 0; t->width = 0;
...@@ -99,7 +115,6 @@ dowidth(Type *t) ...@@ -99,7 +115,6 @@ dowidth(Type *t)
t->width = -2; t->width = -2;
et = t->etype; et = t->etype;
switch(et) { switch(et) {
case TFUNC: case TFUNC:
...@@ -165,13 +180,16 @@ dowidth(Type *t) ...@@ -165,13 +180,16 @@ dowidth(Type *t)
break; break;
case TFORW: // should have been filled in case TFORW: // should have been filled in
case TFORWSTRUCT: case TFORWSTRUCT:
yyerror("incomplete type %T", t); yyerror("undefined type %T", t);
w = widthptr; w = widthptr;
break; break;
case TANY: // implemented as pointer case TANY:
w = widthptr; // dummy type; should be replaced before use.
fatal("dowidth any");
break; break;
case TSTRING: case TSTRING:
if(sizeof_String == 0)
fatal("early dowidth string");
w = sizeof_String; w = sizeof_String;
break; break;
case TARRAY: case TARRAY:
...@@ -413,6 +431,9 @@ typeinit(void) ...@@ -413,6 +431,9 @@ typeinit(void)
// string is same as slice wo the cap // string is same as slice wo the cap
sizeof_String = rnd(Array_nel+types[TUINT32]->width, maxround); sizeof_String = rnd(Array_nel+types[TUINT32]->width, maxround);
dowidth(types[TSTRING]);
dowidth(idealstring);
} }
/* /*
......
// 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.
/*
* function literals aka closures
*/
#include "go.h"
void
closurehdr(Node *ntype)
{
Node *n, *name;
NodeList *l;
n = nod(OCLOSURE, N, N);
n->ntype = ntype;
n->funcdepth = funcdepth;
funchdr(n);
// steal ntype's argument names and
// leave a fresh copy in their place.
// references to these variables need to
// refer to the variables in the external
// function declared below; see walkclosure.
n->list = ntype->list;
n->rlist = ntype->rlist;
ntype->list = nil;
ntype->rlist = nil;
for(l=n->list; l; l=l->next) {
name = l->n->left;
if(name)
name = newname(name->sym);
ntype->list = list(ntype->list, nod(ODCLFIELD, name, l->n->right));
}
for(l=n->rlist; l; l=l->next) {
name = l->n->left;
if(name)
name = newname(name->sym);
ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, name, l->n->right));
}
}
Node*
closurebody(NodeList *body)
{
Node *func, *v;
NodeList *l;
if(body == nil)
body = list1(nod(OEMPTY, N, N));
func = curfn;
l = func->dcl;
func->nbody = body;
funcbody(func);
// closure-specific variables are hanging off the
// ordinary ones in the symbol table; see oldname.
// unhook them.
// make the list of pointers for the closure call.
for(l=func->cvars; l; l=l->next) {
v = l->n;
v->closure->closure = v->outer;
v->heapaddr = nod(OADDR, oldname(v->sym), N);
}
return func;
}
void
typecheckclosure(Node *func)
{
Node *oldfn;
NodeList *l;
Node *v;
oldfn = curfn;
typecheck(&func->ntype, Etype);
func->type = func->ntype->type;
if(func->type != T) {
curfn = func;
typechecklist(func->nbody, Etop);
curfn = oldfn;
}
// type check the & of closed variables outside the closure,
// so that the outer frame also grabs them and knows they
// escape.
func->enter = nil;
for(l=func->cvars; l; l=l->next) {
v = l->n;
if(v->type == T) {
// if v->type is nil, it means v looked like it was
// going to be used in the closure but wasn't.
// this happens because when parsing a, b, c := f()
// the a, b, c gets parsed as references to older
// a, b, c before the parser figures out this is a
// declaration.
v->op = 0;
continue;
}
typecheck(&v->heapaddr, Erv);
func->enter = list(func->enter, v->heapaddr);
v->heapaddr = N;
}
}
Node*
walkclosure(Node *func, NodeList **init)
{
int narg;
Node *xtype, *v, *addr, *xfunc, *call, *clos;
NodeList *l, *in;
static int closgen;
/*
* wrap body in external function
* with extra closure parameters.
*/
xtype = nod(OTFUNC, N, N);
// each closure variable has a corresponding
// address parameter.
narg = 0;
for(l=func->cvars; l; l=l->next) {
v = l->n;
if(v->op == 0)
continue;
addr = nod(ONAME, N, N);
snprint(namebuf, sizeof namebuf, "&%s", v->sym->name);
addr->sym = lookup(namebuf);
addr->ntype = nod(OIND, typenod(v->type), N);
addr->class = PPARAM;
addr->addable = 1;
addr->ullman = 1;
narg++;
v->heapaddr = addr;
xtype->list = list(xtype->list, nod(ODCLFIELD, addr, addr->ntype));
}
// then a dummy arg where the closure's caller pc sits
xtype->list = list(xtype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
// then the function arguments
xtype->list = concat(xtype->list, func->list);
xtype->rlist = concat(xtype->rlist, func->rlist);
// create the function
xfunc = nod(ODCLFUNC, N, N);
snprint(namebuf, sizeof namebuf, "_f%.3ld·%s", ++closgen, filename);
xfunc->nname = newname(lookup(namebuf));
xfunc->nname->ntype = xtype;
declare(xfunc->nname, PFUNC);
xfunc->nname->funcdepth = func->funcdepth;
xfunc->funcdepth = func->funcdepth;
xfunc->nbody = func->nbody;
xfunc->dcl = func->dcl;
if(xfunc->nbody == nil)
fatal("empty body - won't generate any code");
typecheck(&xfunc, Etop);
closures = list(closures, xfunc);
// prepare call of sys.closure that turns external func into func literal value.
clos = syslook("closure", 1);
clos->type = T;
clos->ntype = nod(OTFUNC, N, N);
in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // siz
in = list(in, nod(ODCLFIELD, N, xtype));
for(l=func->cvars; l; l=l->next) {
if(l->n->op == 0)
continue;
in = list(in, nod(ODCLFIELD, N, l->n->heapaddr->ntype));
}
clos->ntype->list = in;
clos->ntype->rlist = list1(nod(ODCLFIELD, N, typenod(func->type)));
typecheck(&clos, Erv);
call = nod(OCALL, clos, N);
if(narg*widthptr > 100)
yyerror("closure needs too many variables; runtime will reject it");
in = list1(nodintconst(narg*widthptr));
in = list(in, xfunc->nname);
in = concat(in, func->enter);
call->list = in;
typecheck(&call, Erv);
walkexpr(&call, init);
return call;
}
...@@ -337,6 +337,7 @@ evconst(Node *n) ...@@ -337,6 +337,7 @@ evconst(Node *n)
case OMAKEMAP: case OMAKEMAP:
case OMAKESLICE: case OMAKESLICE:
case OMAKECHAN: case OMAKECHAN:
case ODCLCONST:
return; return;
} }
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "go.h" #include "go.h"
#include "y.tab.h" #include "y.tab.h"
static void funcargs(Node*);
int int
dflag(void) dflag(void)
{ {
...@@ -50,6 +52,8 @@ pushdcl(Sym *s) ...@@ -50,6 +52,8 @@ pushdcl(Sym *s)
d = push(); d = push();
dcopy(d, s); dcopy(d, s);
if(dflag())
print("\t%L push %S %p\n", lineno, s, s->def);
return d; return d;
} }
...@@ -67,7 +71,7 @@ popdcl(void) ...@@ -67,7 +71,7 @@ popdcl(void)
s = pkglookup(d->name, d->package); s = pkglookup(d->name, d->package);
dcopy(s, d); dcopy(s, d);
if(dflag()) if(dflag())
print("\t%L pop %S\n", lineno, s); print("\t%L pop %S %p\n", lineno, s, s->def);
} }
if(d == S) if(d == S)
fatal("popdcl: no mark"); fatal("popdcl: no mark");
...@@ -157,15 +161,21 @@ declare(Node *n, int ctxt) ...@@ -157,15 +161,21 @@ declare(Node *n, int ctxt)
gen = 0; gen = 0;
if(ctxt == PEXTERN) { if(ctxt == PEXTERN) {
externdcl = list(externdcl, n); externdcl = list(externdcl, n);
if(dflag())
print("\t%L global decl %S %p\n", lineno, s, n);
} else { } else {
if(autodcl != nil) if(curfn == nil && ctxt == PAUTO)
autodcl = list(autodcl, n); fatal("automatic outside function");
if(curfn != nil)
curfn->dcl = list(curfn->dcl, n);
if(n->op == OTYPE) if(n->op == OTYPE)
gen = ++typegen; gen = ++typegen;
else if(n->op == ONAME) else if(n->op == ONAME)
gen = ++vargen; gen = ++vargen;
pushdcl(s); pushdcl(s);
} }
if(ctxt == PAUTO)
n->xoffset = BADWIDTH;
if(s->block == block) { if(s->block == block) {
what = "???"; what = "???";
...@@ -181,7 +191,7 @@ declare(Node *n, int ctxt) ...@@ -181,7 +191,7 @@ declare(Node *n, int ctxt)
break; break;
} }
yyerror("%s %S redeclared in this block", what, s); yyerror("%s %S redeclared in this block %d", what, s, block);
print("\tprevious declaration at %L\n", s->lastlineno); print("\tprevious declaration at %L\n", s->lastlineno);
} }
s->block = block; s->block = block;
...@@ -205,6 +215,7 @@ addvar(Node *n, Type *t, int ctxt) ...@@ -205,6 +215,7 @@ addvar(Node *n, Type *t, int ctxt)
n->type = t; n->type = t;
} }
// TODO: cut use of below in sigtype and then delete
void void
addtyp(Type *n, int ctxt) addtyp(Type *n, int ctxt)
{ {
...@@ -220,35 +231,11 @@ addtyp(Type *n, int ctxt) ...@@ -220,35 +231,11 @@ addtyp(Type *n, int ctxt)
typelist = list(typelist, def); typelist = list(typelist, def);
} }
/*
* declare (possible list) n of type t.
* append ODCL nodes to *init
*/
void
dodclvar(Node *n, Type *t, NodeList **init)
{
if(n == N)
return;
if(t != T && (t->etype == TIDEAL || t->etype == TNIL))
fatal("dodclvar %T", t);
dowidth(t);
// in case of type checking error,
// use "undefined" type for variable type,
// to avoid fatal in addvar.
if(t == T)
t = typ(TFORW);
addvar(n, t, dclcontext);
if(funcdepth > 0)
*init = list(*init, nod(ODCL, n, N));
}
/* /*
* introduce a type named n * introduce a type named n
* but it is an unknown type for now * but it is an unknown type for now
*/ */
// TODO(rsc): cut use of this in sigtype and then delete
Type* Type*
dodcltype(Type *n) dodcltype(Type *n)
{ {
...@@ -282,6 +269,7 @@ found: ...@@ -282,6 +269,7 @@ found:
/* /*
* now we know what n is: it's t * now we know what n is: it's t
*/ */
// TODO(rsc): cut use of this in sigtype and then delete
void void
updatetype(Type *n, Type *t) updatetype(Type *n, Type *t)
{ {
...@@ -409,7 +397,7 @@ constiter(NodeList *vl, Node *t, NodeList *cl) ...@@ -409,7 +397,7 @@ constiter(NodeList *vl, Node *t, NodeList *cl)
Node *v, *c; Node *v, *c;
NodeList *vv; NodeList *vv;
vv = vl; vv = nil;
if(cl == nil) { if(cl == nil) {
if(t != N) if(t != N)
yyerror("constdcl cannot have type without expr"); yyerror("constdcl cannot have type without expr");
...@@ -435,6 +423,8 @@ constiter(NodeList *vl, Node *t, NodeList *cl) ...@@ -435,6 +423,8 @@ constiter(NodeList *vl, Node *t, NodeList *cl)
v->ntype = t; v->ntype = t;
v->defn = c; v->defn = c;
vv = list(vv, nod(ODCLCONST, v, N));
} }
if(cl != nil) if(cl != nil)
yyerror("extra expr in const dcl"); yyerror("extra expr in const dcl");
...@@ -451,6 +441,9 @@ newname(Sym *s) ...@@ -451,6 +441,9 @@ newname(Sym *s)
{ {
Node *n; Node *n;
if(s == S)
fatal("newname nil");
n = nod(ONAME, N, N); n = nod(ONAME, N, N);
n->sym = s; n->sym = s;
n->type = T; n->type = T;
...@@ -473,13 +466,14 @@ dclname(Sym *s) ...@@ -473,13 +466,14 @@ dclname(Sym *s)
// top-level name: might already have been // top-level name: might already have been
// referred to, in which case s->def is already // referred to, in which case s->def is already
// set to an ONONAME. // set to an ONONAME.
if(dclcontext == PEXTERN && s->block == 0) { if(dclcontext == PEXTERN && s->block <= 1) {
// toss predefined name like "close" // toss predefined name like "close"
// TODO(rsc): put close in at the end. // TODO(rsc): put close in at the end.
if(s->def != N && s->def->etype) if(s->def != N && s->def->etype)
s->def = N; s->def = N;
if(s->def == N) if(s->def == N)
oldname(s); oldname(s);
if(s->def->op == ONONAME)
return s->def; return s->def;
} }
...@@ -524,20 +518,19 @@ oldname(Sym *s) ...@@ -524,20 +518,19 @@ oldname(Sym *s)
// inner func is referring to var // inner func is referring to var
// in outer func. // in outer func.
if(n->closure == N || n->closure->funcdepth != funcdepth) { if(n->closure == N || n->closure->funcdepth != funcdepth) {
typecheck(&n, Erv);
// create new closure var. // create new closure var.
c = nod(ONAME, N, N); c = nod(ONAME, N, N);
c->sym = s; c->sym = s;
c->class = PPARAMREF; c->class = PPARAMREF;
c->type = n->type; c->defn = n;
c->addable = 0; c->addable = 0;
c->ullman = 2; c->ullman = 2;
c->funcdepth = funcdepth; c->funcdepth = funcdepth;
c->outer = n->closure; c->outer = n->closure;
n->closure = c; n->closure = c;
c->closure = n; c->closure = n;
if(funclit != N) c->xoffset = 0;
funclit->cvars = list(funclit->cvars, c); curfn->cvars = list(curfn->cvars, c);
} }
// return ref to closure var, not original // return ref to closure var, not original
return n->closure; return n->closure;
...@@ -644,6 +637,231 @@ colas(NodeList *left, NodeList *right) ...@@ -644,6 +637,231 @@ colas(NodeList *left, NodeList *right)
return as; return as;
} }
/*
* declare the function proper
* and declare the arguments.
* called in extern-declaration context
* returns in auto-declaration context.
*/
void
funchdr(Node *n)
{
Node *nt;
if(n->nname != N) {
// TODO(rsc): remove once forward declarations are gone
if(n->nname->sym->def && n->nname->sym->def->class == PFUNC) {
nt = n->nname->ntype;
n->nname = n->nname->sym->def;
n->nname->ntype = nt;
n->nname->type = T;
} else {
n->nname->op = ONAME;
declare(n->nname, PFUNC);
}
}
// change the declaration context from extern to auto
if(funcdepth == 0 && dclcontext != PEXTERN)
fatal("funchdr: dclcontext");
dclcontext = PAUTO;
markdcl();
funcdepth++;
n->outer = curfn;
curfn = n;
if(n->nname)
funcargs(n->nname->ntype);
else
funcargs(n->ntype);
}
static void
funcargs(Node *nt)
{
Node *n;
NodeList *l;
if(nt->op != OTFUNC)
fatal("funcargs %O", nt->op);
// declare the receiver and in arguments.
// no n->defn because type checking of func header
// will fill in the types before we can demand them.
if(nt->left != N) {
n = nt->left;
if(n->op != ODCLFIELD)
fatal("funcargs1 %O", n->op);
if(n->left != N) {
n->left->op = ONAME;
n->left->ntype = n->right;
declare(n->left, PPARAM);
}
}
for(l=nt->list; l; l=l->next) {
n = l->n;
if(n->op != ODCLFIELD)
fatal("funcargs2 %O", n->op);
if(n->left != N) {
n->left->op = ONAME;
n->left->ntype = n->right;
declare(n->left, PPARAM);
}
}
// declare the out arguments.
for(l=nt->rlist; l; l=l->next) {
n = l->n;
if(n->op != ODCLFIELD)
fatal("funcargs3 %O", n->op);
if(n->left != N) {
n->left->op = ONAME;
n->left->ntype = n->right;
declare(n->left, PPARAMOUT);
}
}
}
/*
* finish the body.
* called in auto-declaration context.
* returns in extern-declaration context.
*/
void
funcbody(Node *n)
{
// change the declaration context from auto to extern
if(dclcontext != PAUTO)
fatal("funcbody: dclcontext");
popdcl();
funcdepth--;
curfn = n->outer;
n->outer = N;
if(funcdepth == 0)
dclcontext = PEXTERN;
}
/*
* forward declarations of types
* TODO(rsc): delete!
*/
/*
* new type being defined with name s.
*/
Node*
typedcl0(Sym *s)
{
Node *o, *ot, *n;
int et;
// TODO(rsc): throw away once forward declarations are gone
if((o = s->def) != N && o != N && o->op == OTYPE && s->block == block) {
if((ot = o->ntype) != N && ot->op == OTYPE && ot->type != T)
if((et = ot->type->etype) == TFORWSTRUCT || et == TFORWINTER) {
// local forward declaration exists!
// use it instead of the node we just created.
if(ot->walkdef || ot->typecheck)
fatal("someone looked at the fwd decl");
return o;
}
if(o->type && ((et = o->type->etype) == TFORWSTRUCT || et == TFORWINTER)) {
// imported forward declaration exists.
// attach the fwd type to the node we just
// created, so that when we define the type in walkdef
// we will overwrite the fwd version.
o->nincr = nod(OXXX, N, N);
o->nincr->type = o->type;
o->type = T;
o->walkdef = 0;
o->typecheck = 0;
autoexport(o, PEXTERN);
return o;
}
}
// make a new one
n = dclname(s);
n->op = OTYPE;
declare(n, dclcontext);
return n;
}
/*
* node n, which was returned by typedcl0
* is being declared to have uncompiled type t. if n was previously forward
* declared, update the forward declaration and undo the dclname.
* extra tricky because we have to deal with imported forward declarations.
* return the ODCLTYPE node to use.
*/
Node*
typedcl1(Node *n, Node *t, int local)
{
n->ntype = t;
n->local = local;
return nod(ODCLTYPE, n, N);
}
/*
* node n, which was returned by dclname (newname for imports)
* is being forward declared as et (TFORWSTRUCT or TFORWINTER).
* if n was previously forward declared, scream.
* return the ODCLTYPE node to use.
*/
Node*
fwdtype(Node *n, int et)
{
n->op = OTYPE;
n->ntype = typenod(typ(et));
return nod(ODCLTYPE, n, N);
}
/*
* typedcl1 but during imports
*/
void
typedcl2(Type *pt, Type *t)
{
Node *n;
if(pt->etype == TFORW)
goto ok;
if(pt->etype == TFORWSTRUCT && t->etype == TSTRUCT)
goto ok;
if(pt->etype == TFORWINTER && t->etype == TINTER)
goto ok;
if(pt->etype == TSTRUCT && t->etype == TFORWSTRUCT)
return;
if(pt->etype == TINTER && t->etype == TFORWINTER)
return;
if(!cvttype(pt, t)) {
yyerror("redeclaration of %T during imports\n\t%lT [%p]\n\t%lT [%p]", pt, pt, pt, t, t);
return;
}
return;
ok:
n = pt->nod;
*pt = *t;
pt->method = nil;
pt->nod = n;
pt->sym = n->sym;
declare(n, PEXTERN);
switch(pt->etype) {
case TFORWINTER:
case TFORWSTRUCT:
// allow re-export in case it gets defined
pt->sym->flags &= ~(SymExport|SymPackage);
pt->sym->flags &= ~SymImported;
break;
default:
checkwidth(pt);
break;
}
}
/* /*
* structs, functions, and methods. * structs, functions, and methods.
...@@ -675,6 +893,8 @@ stotype(NodeList *l, int et, Type **t) ...@@ -675,6 +893,8 @@ stotype(NodeList *l, int et, Type **t)
if(n->right != N) { if(n->right != N) {
typecheck(&n->right, Etype); typecheck(&n->right, Etype);
n->type = n->right->type; n->type = n->right->type;
if(n->left != N)
n->left->type = n->type;
n->right = N; n->right = N;
if(n->embedded && n->type != T) { if(n->embedded && n->type != T) {
t1 = n->type; t1 = n->type;
...@@ -791,14 +1011,15 @@ embedded(Sym *s) ...@@ -791,14 +1011,15 @@ embedded(Sym *s)
} }
n = newname(lookup(name)); n = newname(lookup(name));
n = nod(ODCLFIELD, n, N); n = nod(ODCLFIELD, n, oldname(s));
n->embedded = 1; n->embedded = 1;
if(s == S)
return n;
n->right = oldname(s);
return n; return n;
} }
/*
* check that the list of declarations is either all anonymous or all named
*/
static Node* static Node*
findtype(NodeList *l) findtype(NodeList *l)
{ {
...@@ -808,59 +1029,11 @@ findtype(NodeList *l) ...@@ -808,59 +1029,11 @@ findtype(NodeList *l)
return N; return N;
} }
static Node*
xanondcl(Node *nt)
{
Node *n;
Type *t;
typecheck(&nt, Etype);
t = nt->type;
if(nt->op != OTYPE) {
yyerror("%S is not a type", nt->sym);
t = types[TINT32];
}
n = nod(ODCLFIELD, N, N);
n->type = t;
return n;
}
static Node*
namedcl(Node *nn, Node *nt)
{
Node *n;
Type *t;
if(nn->op == OKEY)
nn = nn->left;
if(nn->sym == S) {
typecheck(&nn, Etype);
yyerror("cannot mix anonymous %T with named arguments", nn->type);
return xanondcl(nn);
}
t = types[TINT32];
if(nt == N)
yyerror("missing type for argument %S", nn->sym);
else {
typecheck(&nt, Etype);
if(nt->op != OTYPE)
yyerror("%S is not a type", nt->sym);
else
t = nt->type;
}
n = nod(ODCLFIELD, newname(nn->sym), N);
n->type = t;
return n;
}
/*
* check that the list of declarations is either all anonymous or all named
*/
NodeList* NodeList*
checkarglist(NodeList *all) checkarglist(NodeList *all)
{ {
int named; int named;
Node *r; Node *n, *t, *nextt;
NodeList *l; NodeList *l;
named = 0; named = 0;
...@@ -870,17 +1043,51 @@ checkarglist(NodeList *all) ...@@ -870,17 +1043,51 @@ checkarglist(NodeList *all)
break; break;
} }
} }
if(named) {
n = N;
for(l=all; l; l=l->next) {
n = l->n;
if(n->op != OKEY && n->sym == S) {
yyerror("mixed named and unnamed function parameters");
break;
}
}
if(l == nil && n != N && n->op != OKEY)
yyerror("final function parameter must have type");
}
nextt = nil;
for(l=all; l; l=l->next) { for(l=all; l; l=l->next) {
if(named) // can cache result from findtype to avoid
l->n = namedcl(l->n, findtype(l)); // quadratic behavior here, but unlikely to matter.
else n = l->n;
l->n = xanondcl(l->n); if(named) {
if(l->next != nil) { if(n->op == OKEY) {
r = l->n; t = n->right;
if(r != N && r->type != T && r->type->etype == TDDD) n = n->left;
yyerror("only last argument can have type ..."); nextt = nil;
} else {
if(nextt == nil)
nextt = findtype(l);
t = nextt;
} }
} else {
t = n;
n = N;
}
if(n != N && n->sym == S) {
t = n;
n = N;
}
if(n != N) {
if(n->op == ONONAME && n->sym->def == n)
n->sym->def = N;
n = newname(n->sym);
}
n = nod(ODCLFIELD, n, t);
if(l->next != nil && n->right != N && n->right->op == OTYPE && isddd(n->right->type))
yyerror("only last argument can have type ...");
l->n = n;
} }
return all; return all;
} }
...@@ -891,8 +1098,7 @@ fakethis(void) ...@@ -891,8 +1098,7 @@ fakethis(void)
{ {
Node *n; Node *n;
n = nod(ODCLFIELD, N, N); n = nod(ODCLFIELD, N, typenod(ptrto(typ(TSTRUCT))));
n->type = ptrto(typ(TSTRUCT));
return n; return n;
} }
...@@ -943,8 +1149,8 @@ functype(Node *this, NodeList *in, NodeList *out) ...@@ -943,8 +1149,8 @@ functype(Node *this, NodeList *in, NodeList *out)
t->thistuple = 1; t->thistuple = 1;
t->outtuple = count(out); t->outtuple = count(out);
t->intuple = count(in); t->intuple = count(in);
t->outnamed = t->outtuple > 0 && out->n->left != N;
checkwidth(t);
return t; return t;
} }
...@@ -1003,7 +1209,6 @@ methodsym(Sym *nsym, Type *t0) ...@@ -1003,7 +1209,6 @@ methodsym(Sym *nsym, Type *t0)
t0 = ptrto(t); t0 = ptrto(t);
snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name); snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name);
//print("methodname %s\n", buf);
return pkglookup(buf, s->package); return pkglookup(buf, s->package);
bad: bad:
...@@ -1022,42 +1227,52 @@ methodname(Node *n, Type *t) ...@@ -1022,42 +1227,52 @@ methodname(Node *n, Type *t)
return newname(s); return newname(s);
} }
Node*
methodname1(Node *n, Node *t)
{
char *star;
char buf[NSYMB];
star = "";
if(t->op == OIND) {
star = "*";
t = t->left;
}
if(t->sym == S)
return n;
snprint(buf, sizeof(buf), "%s%S·%S", star, t->sym, n->sym);
return newname(pkglookup(buf, t->sym->package));
}
/* /*
* add a method, declared as a function, * add a method, declared as a function,
* n is fieldname, pa is base type, t is function type * n is fieldname, pa is base type, t is function type
*/ */
void void
addmethod(Node *n, Type *t, int local) addmethod(Sym *sf, Type *t, int local)
{ {
Type *f, *d, *pa; Type *f, *d, *pa;
Sym *sf; Node *n;
pa = nil; pa = nil;
sf = nil;
// get field sym // get field sym
if(n == N)
goto bad;
if(n->op != ONAME)
goto bad;
sf = n->sym;
if(sf == S) if(sf == S)
goto bad; fatal("no method symbol");
// get parent type sym // get parent type sym
pa = *getthis(t); // ptr to this structure pa = getthisx(t)->type; // ptr to this structure
if(pa == T) if(pa == T) {
goto bad; yyerror("missing receiver");
pa = pa->type; // ptr to this field return;
if(pa == T) }
goto bad;
pa = pa->type; // ptr to this type
if(pa == T)
goto bad;
pa = pa->type;
f = methtype(pa); f = methtype(pa);
if(f == T) if(f == T) {
goto bad; yyerror("invalid receiver type %T", pa);
return;
}
pa = f; pa = f;
if(pkgimportname != S && !exportname(sf->name)) if(pkgimportname != S && !exportname(sf->name))
...@@ -1093,295 +1308,35 @@ addmethod(Node *n, Type *t, int local) ...@@ -1093,295 +1308,35 @@ addmethod(Node *n, Type *t, int local)
else else
stotype(list1(n), 0, &d->down); stotype(list1(n), 0, &d->down);
return; return;
bad:
yyerror("invalid receiver type %T", pa);
} }
/*
* declare the function proper.
* and declare the arguments
* called in extern-declaration context
* returns in auto-declaration context.
*/
void void
funchdr(Node *n) funccompile(Node *n)
{ {
Node *on; stksize = BADWIDTH;
Sym *s; maxarg = 0;
s = n->nname->sym; if(n->type == T) {
on = s->def; if(nerrors == 0)
if(on != N && (on->op != ONAME || on->builtin)) fatal("funccompile missing type");
on = N; return;
// check for same types
if(on != N) {
if(eqtype(n->type, on->type)) {
if(!eqargs(n->type, on->type)) {
yyerror("function arg names changed: %S", s);
print("\t%T\n\t%T\n", on->type, n->type);
}
} else {
yyerror("function redeclared: %S", s);
print("\t%T\n\t%T\n", on->type, n->type);
on = N;
}
}
// check for forward declaration
if(on == N) {
// initial declaration or redeclaration
// declare fun name, argument types and argument names
n->nname->type = n->type;
if(n->type->thistuple == 0)
addvar(n->nname, n->type, PFUNC);
else
n->nname->class = PFUNC;
} else {
// identical redeclaration
// steal previous names
n->nname = on;
n->type = on->type;
n->class = on->class;
n->sym = s;
} }
// change the declaration context from extern to auto // assign parameter offsets
autodcl = list1(nod(OXXX, N, N)); checkwidth(n->type);
if(funcdepth == 0 && dclcontext != PEXTERN) if(curfn)
fatal("funchdr: dclcontext"); fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym);
curfn = n;
typechecklist(n->nbody, Etop);
curfn = nil;
stksize = 0;
dclcontext = PAUTO; dclcontext = PAUTO;
markdcl(); funcdepth = n->funcdepth + 1;
funcargs(n->type);
}
void
funcargs(Type *ft)
{
Type *t;
Iter save;
int all;
funcdepth++;
// declare the this/in arguments
t = funcfirst(&save, ft);
while(t != T) {
if(t->nname != N) {
t->nname->xoffset = t->width;
addvar(t->nname, t->type, PPARAM);
}
t = funcnext(&save);
}
// declare the outgoing arguments
all = 0;
t = structfirst(&save, getoutarg(ft));
while(t != T) {
if(t->nname != N)
t->nname->xoffset = t->width;
if(t->nname != N) {
addvar(t->nname, t->type, PPARAMOUT);
all |= 1;
} else
all |= 2;
t = structnext(&save);
}
// this test is remarkedly similar to checkarglist
if(all == 3)
yyerror("cannot mix anonymous and named output arguments");
ft->outnamed = 0;
if(all == 1)
ft->outnamed = 1;
}
/*
* compile the function.
* called in auto-declaration context.
* returns in extern-declaration context.
*/
void
funcbody(Node *n)
{
compile(n); compile(n);
curfn = nil;
// change the declaration context from auto to extern funcdepth = 0;
if(dclcontext != PAUTO)
fatal("funcbody: dclcontext");
popdcl();
funcdepth--;
if(funcdepth == 0)
dclcontext = PEXTERN; dclcontext = PEXTERN;
} }
Node*
funclit0(Node *t)
{
Node *n;
n = nod(OXXX, N, N);
n->outer = funclit;
n->dcl = autodcl;
funclit = n;
// new declaration context
autodcl = list1(nod(OEMPTY, N, N));
typecheck(&t, Etype);
funcargs(t->type);
return t;
}
Node*
funclit1(Node *ntype, NodeList *body)
{
Node *func;
Type *type;
Node *a, *d, *f, *n, *clos;
Type *ft, *t;
Iter save;
int narg, shift;
NodeList *args, *l, *in, *out;
static int closgen;
type = ntype->type;
popdcl();
func = funclit;
funclit = func->outer;
// build up type of func f that we're going to compile.
// as we referred to variables from the outer function,
// we accumulated a list of PHEAP names in func->cvars.
narg = 0;
// add PHEAP versions as function arguments.
in = nil;
for(l=func->cvars; l; l=l->next) {
a = l->n;
d = nod(ODCLFIELD, a, N);
d->type = ptrto(a->type);
in = list(in, d);
// while we're here, set up a->heapaddr for back end
n = nod(ONAME, N, N);
snprint(namebuf, sizeof namebuf, "&%s", a->sym->name);
n->sym = lookup(namebuf);
n->type = ptrto(a->type);
n->class = PPARAM;
n->xoffset = narg*types[tptr]->width;
n->addable = 1;
n->ullman = 1;
narg++;
a->heapaddr = n;
a->xoffset = 0;
// unlink from actual ONAME in symbol table
a->closure->closure = a->outer;
}
// add a dummy arg for the closure's caller pc
d = nod(ODCLFIELD, N, N);
d->type = types[TUINTPTR];
in = list(in, d);
// slide param offset to make room for ptrs above.
// narg+1 to skip over caller pc.
shift = (narg+1)*types[tptr]->width;
// now the original arguments.
for(t=structfirst(&save, getinarg(type)); t; t=structnext(&save)) {
d = nod(ODCLFIELD, t->nname, N);
d->type = t->type;
in = list(in, d);
a = t->nname;
if(a != N) {
if(a->stackparam != N)
a = a->stackparam;
a->xoffset += shift;
}
}
// out arguments
out = nil;
for(t=structfirst(&save, getoutarg(type)); t; t=structnext(&save)) {
d = nod(ODCLFIELD, t->nname, N);
d->type = t->type;
out = list(out, d);
a = t->nname;
if(a != N) {
if(a->stackparam != N)
a = a->stackparam;
a->xoffset += shift;
}
}
ft = functype(N, in, out);
ft->outnamed = type->outnamed;
// declare function.
snprint(namebuf, sizeof(namebuf), "_f%.3ld·%s", ++closgen, filename);
f = newname(lookup(namebuf));
addvar(f, ft, PFUNC);
f->funcdepth = 0;
// compile function
n = nod(ODCLFUNC, N, N);
n->nname = f;
n->type = ft;
if(body == nil)
body = list1(nod(OEMPTY, N, N));
n->nbody = body;
compile(n);
funcdepth--;
autodcl = func->dcl;
// build up type for this instance of the closure func.
in = nil;
d = nod(ODCLFIELD, N, N); // siz
d->type = types[TINT];
in = list(in, d);
d = nod(ODCLFIELD, N, N); // f
d->type = ft;
in = list(in, d);
for(l=func->cvars; l; l=l->next) {
a = l->n;
d = nod(ODCLFIELD, N, N); // arg
d->type = ptrto(a->type);
in = list(in, d);
}
d = nod(ODCLFIELD, N, N);
d->type = type;
out = list1(d);
clos = syslook("closure", 1);
clos->type = functype(N, in, out);
// literal expression is sys.closure(siz, f, arg0, arg1, ...)
// which builds a function that calls f after filling in arg0,
// arg1, ... for the PHEAP arguments above.
args = nil;
if(narg*widthptr > 100)
yyerror("closure needs too many variables; runtime will reject it");
a = nodintconst(narg*widthptr);
args = list(args, a); // siz
args = list(args, f); // f
for(l=func->cvars; l; l=l->next) {
a = l->n;
d = oldname(a->sym);
args = list(args, nod(OADDR, d, N));
}
typechecklist(args, Erv);
n = nod(OCALL, clos, N);
n->list = args;
return n;
}
...@@ -61,6 +61,8 @@ autoexport(Node *n, int ctxt) ...@@ -61,6 +61,8 @@ autoexport(Node *n, int ctxt)
return; return;
if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN) if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN)
return; return;
if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left) // method
return;
if(exportname(n->sym->name) || strcmp(n->sym->name, "init") == 0) if(exportname(n->sym->name) || strcmp(n->sym->name, "init") == 0)
exportsym(n); exportsym(n);
else else
...@@ -347,7 +349,6 @@ importvar(Sym *s, Type *t, int ctxt) ...@@ -347,7 +349,6 @@ importvar(Sym *s, Type *t, int ctxt)
warn("redeclare import var %S from %T to %T", warn("redeclare import var %S from %T to %T",
s, s->def->type, t); s, s->def->type, t);
} }
checkwidth(t);
n = newname(s); n = newname(s);
n->type = t; n->type = t;
declare(n, ctxt); declare(n, ctxt);
...@@ -357,56 +358,19 @@ importvar(Sym *s, Type *t, int ctxt) ...@@ -357,56 +358,19 @@ importvar(Sym *s, Type *t, int ctxt)
} }
void void
importtype(Sym *s, Type *t) importtype(Type *pt, Type *t)
{ {
Node *n; typedcl2(pt, t);
Type *tt;
importsym(s, OTYPE);
n = s->def;
if(n != N && n->op == OTYPE) {
if(cvttype(t, n->type))
return;
if(t->etype == TFORWSTRUCT && n->type->etype == TSTRUCT)
return;
if(t->etype == TFORWINTER && n->type->etype == TINTER)
return;
if(n->type->etype != TFORW && n->type->etype != TFORWSTRUCT && n->type->etype != TFORWINTER) {
yyerror("redeclare import type %S from %lT to %lT", s, n->type, t);
n = s->def = typenod(typ(0));
}
}
if(n == N || n->op != OTYPE) {
tt = typ(0);
tt->sym = s;
n = typenod(tt);
s->def = n;
}
if(n->type == T)
n->type = typ(0);
*n->type = *t;
n->type->sym = s;
n->type->nod = n;
switch(n->type->etype) {
case TFORWINTER:
case TFORWSTRUCT:
// allow re-export in case it gets defined
s->flags &= ~(SymExport|SymPackage);
s->flags &= ~SymImported;
break;
default:
checkwidth(n->type);
}
if(debug['E']) if(debug['E'])
print("import type %S %lT\n", s, t); print("import type %T %lT\n", pt, t);
} }
void void
importmethod(Sym *s, Type *t) importmethod(Sym *s, Type *t)
{ {
checkwidth(t); checkwidth(t);
addmethod(newname(s), t, 0); addmethod(s, t, 0);
} }
/* /*
......
...@@ -25,14 +25,25 @@ allocparams(void) ...@@ -25,14 +25,25 @@ allocparams(void)
NodeList *l; NodeList *l;
Node *n; Node *n;
uint32 w; uint32 w;
Sym *s;
if(stksize < 0)
fatal("allocparams not during code generation");
/* /*
* allocate (set xoffset) the stack * allocate (set xoffset) the stack
* slots for all automatics. * slots for all automatics.
* allocated starting at -w down. * allocated starting at -w down.
*/ */
for(l=autodcl; l; l=l->next) { for(l=curfn->dcl; l; l=l->next) {
n = l->n; n = l->n;
if(n->op == ONAME && n->class == PHEAP-1) {
// heap address variable; finish the job
// started in addrescapes.
s = n->sym;
tempname(n, n->type);
n->sym = s;
}
if(n->op != ONAME || n->class != PAUTO) if(n->op != ONAME || n->class != PAUTO)
continue; continue;
typecheck(&n, Erv); // only needed for unused variables typecheck(&n, Erv); // only needed for unused variables
...@@ -42,9 +53,10 @@ allocparams(void) ...@@ -42,9 +53,10 @@ allocparams(void)
w = n->type->width; w = n->type->width;
if(n->class & PHEAP) if(n->class & PHEAP)
w = widthptr; w = widthptr;
if(w >= 100000000)
fatal("bad width");
stksize += w; stksize += w;
stksize = rnd(stksize, w); stksize = rnd(stksize, w);
n->xoffset = -stksize; n->xoffset = -stksize;
} }
} }
...@@ -161,6 +173,9 @@ gen(Node *n) ...@@ -161,6 +173,9 @@ gen(Node *n)
case OFALL: case OFALL:
case OXCASE: case OXCASE:
case OXFALL: case OXFALL:
case ODCLCONST:
case ODCLFUNC:
case ODCLTYPE:
break; break;
case OEMPTY: case OEMPTY:
...@@ -511,3 +526,90 @@ cgen_as(Node *nl, Node *nr) ...@@ -511,3 +526,90 @@ cgen_as(Node *nl, Node *nr)
ret: ret:
; ;
} }
/*
* gather series of offsets
* >=0 is direct addressed field
* <0 is pointer to next field (+1)
*/
int
dotoffset(Node *n, int *oary, Node **nn)
{
int i;
switch(n->op) {
case ODOT:
if(n->xoffset == BADWIDTH) {
dump("bad width in dotoffset", n);
fatal("bad width in dotoffset");
}
i = dotoffset(n->left, oary, nn);
if(i > 0) {
if(oary[i-1] >= 0)
oary[i-1] += n->xoffset;
else
oary[i-1] -= n->xoffset;
break;
}
if(i < 10)
oary[i++] = n->xoffset;
break;
case ODOTPTR:
if(n->xoffset == BADWIDTH) {
dump("bad width in dotoffset", n);
fatal("bad width in dotoffset");
}
i = dotoffset(n->left, oary, nn);
if(i < 10)
oary[i++] = -(n->xoffset+1);
break;
default:
*nn = n;
return 0;
}
if(i >= 10)
*nn = N;
return i;
}
/*
* make a new off the books
*/
void
tempname(Node *n, Type *t)
{
Sym *s;
uint32 w;
if(stksize < 0)
fatal("tempname not during code generation");
if(t == T) {
yyerror("tempname called with nil type");
t = types[TINT32];
}
// give each tmp a different name so that there
// a chance to registerizer them
snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
statuniqgen++;
s = lookup(namebuf);
memset(n, 0, sizeof(*n));
n->op = ONAME;
n->sym = s;
n->type = t;
n->class = PAUTO;
n->addable = 1;
n->ullman = 1;
n->noescape = 1;
dowidth(t);
w = t->width;
stksize += w;
stksize = rnd(stksize, w);
n->xoffset = -stksize;
}
...@@ -144,6 +144,7 @@ struct Type ...@@ -144,6 +144,7 @@ struct Type
uchar funarg; uchar funarg;
uchar copyany; uchar copyany;
uchar local; // created in this file uchar local; // created in this file
uchar deferwidth;
Node* nod; // canonical OTYPE node Node* nod; // canonical OTYPE node
...@@ -195,6 +196,7 @@ struct Node ...@@ -195,6 +196,7 @@ struct Node
uchar builtin; // built-in name, like len or close uchar builtin; // built-in name, like len or close
uchar walkdef; uchar walkdef;
uchar typecheck; uchar typecheck;
uchar local;
// most nodes // most nodes
Node* left; Node* left;
...@@ -217,17 +219,15 @@ struct Node ...@@ -217,17 +219,15 @@ struct Node
// func // func
Node* nname; Node* nname;
Node* shortname;
NodeList* enter; NodeList* enter;
NodeList* exit; NodeList* exit;
NodeList* cvars; // closure params NodeList* cvars; // closure params
NodeList* dcl; // outer autodcl NodeList* dcl; // autodcl for this func/closure
// OLITERAL/OREGISTER // OLITERAL/OREGISTER
Val val; Val val;
// OTFUNC
Node* rcvr;
// ONAME // ONAME
Node* ntype; Node* ntype;
Node* defn; Node* defn;
...@@ -327,11 +327,12 @@ enum ...@@ -327,11 +327,12 @@ enum
OCAP, OCAP,
OCLOSE, OCLOSE,
OCLOSED, OCLOSED,
OCLOSURE,
OCMPIFACE, OCMPSTR, OCMPIFACE, OCMPSTR,
OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
OCOMPSLICE, OCOMPMAP, OCOMPSLICE, OCOMPMAP,
OCONV, OCONVNOP, OCONVA2S, OCONVIFACE, OCONVSLICE, OCONV, OCONVNOP, OCONVA2S, OCONVIFACE, OCONVSLICE,
ODCL, ODCLFUNC, ODCLFIELD, ODCLARG, ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE,
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
ODOTTYPE, ODOTTYPE,
OEQ, ONE, OLT, OLE, OGE, OGT, OEQ, ONE, OLT, OLE, OGE, OGT,
...@@ -624,8 +625,8 @@ EXTERN Mpint* maxintval[NTYPE]; ...@@ -624,8 +625,8 @@ EXTERN Mpint* maxintval[NTYPE];
EXTERN Mpflt* minfltval[NTYPE]; EXTERN Mpflt* minfltval[NTYPE];
EXTERN Mpflt* maxfltval[NTYPE]; EXTERN Mpflt* maxfltval[NTYPE];
EXTERN NodeList* autodcl;
EXTERN NodeList* externdcl; EXTERN NodeList* externdcl;
EXTERN NodeList* closures;
EXTERN NodeList* exportlist; EXTERN NodeList* exportlist;
EXTERN NodeList* typelist; EXTERN NodeList* typelist;
EXTERN int dclcontext; // PEXTERN/PAUTO EXTERN int dclcontext; // PEXTERN/PAUTO
...@@ -639,7 +640,6 @@ EXTERN NodeList* lastconst; ...@@ -639,7 +640,6 @@ EXTERN NodeList* lastconst;
EXTERN Node* lasttype; EXTERN Node* lasttype;
EXTERN int32 maxarg; EXTERN int32 maxarg;
EXTERN int32 stksize; // stack size for current frame EXTERN int32 stksize; // stack size for current frame
EXTERN int32 initstksize; // stack size for init function
EXTERN int32 blockgen; // max block number EXTERN int32 blockgen; // max block number
EXTERN int32 block; // current block number EXTERN int32 block; // current block number
EXTERN int hasdefer; // flag that curfn has defer statetment EXTERN int hasdefer; // flag that curfn has defer statetment
...@@ -662,8 +662,8 @@ EXTERN int exporting; ...@@ -662,8 +662,8 @@ EXTERN int exporting;
EXTERN int noargnames; EXTERN int noargnames;
EXTERN int funcdepth; EXTERN int funcdepth;
EXTERN int typecheckok;
EXTERN Node* funclit;
/* /*
* y.tab.c * y.tab.c
...@@ -859,21 +859,20 @@ int simsimtype(Type*); ...@@ -859,21 +859,20 @@ int simsimtype(Type*);
* dcl.c * dcl.c
*/ */
void declare(Node*, int); void declare(Node*, int);
void dodclvar(Node*, Type*, NodeList**);
Type* dodcltype(Type*); Type* dodcltype(Type*);
void updatetype(Type*, Type*); void updatetype(Type*, Type*);
void defaultlit(Node**, Type*); void defaultlit(Node**, Type*);
void defaultlit2(Node**, Node**, int); void defaultlit2(Node**, Node**, int);
int structcount(Type*); int structcount(Type*);
void addmethod(Node*, Type*, int); void addmethod(Sym*, Type*, int);
Node* methodname(Node*, Type*); Node* methodname(Node*, Type*);
Node* methodname1(Node*, Node*);
Sym* methodsym(Sym*, Type*); Sym* methodsym(Sym*, Type*);
Type* functype(Node*, NodeList*, NodeList*); Type* functype(Node*, NodeList*, NodeList*);
char* thistypenam(Node*); char* thistypenam(Node*);
void funcnam(Type*, char*); void funcnam(Type*, char*);
Node* renameinit(Node*); Node* renameinit(Node*);
void funchdr(Node*); void funchdr(Node*);
void funcargs(Type*);
void funcbody(Node*); void funcbody(Node*);
Node* typenod(Type*); Node* typenod(Type*);
Type* dostruct(NodeList*, int); Type* dostruct(NodeList*, int);
...@@ -906,10 +905,23 @@ Node* embedded(Sym*); ...@@ -906,10 +905,23 @@ Node* embedded(Sym*);
NodeList* variter(NodeList*, Node*, NodeList*); NodeList* variter(NodeList*, Node*, NodeList*);
NodeList* constiter(NodeList*, Node*, NodeList*); NodeList* constiter(NodeList*, Node*, NodeList*);
Node* funclit0(Node*);
Node* funclit1(Node*, NodeList*);
Node* unsafenmagic(Node*, NodeList*); Node* unsafenmagic(Node*, NodeList*);
void dclchecks(void); void dclchecks(void);
void funccompile(Node*);
Node* typedcl0(Sym*);
Node* typedcl1(Node*, Node*, int);
Node* fwdtype(Node*, int);
void typedcl2(Type*, Type*);
/*
* closure.c
*/
void closurehdr(Node*);
Node* closurebody(NodeList*);
void typecheckclosure(Node*);
Node* walkclosure(Node*, NodeList**);
/* /*
* sinit.c * sinit.c
...@@ -932,10 +944,11 @@ void dumpexportvar(Sym*); ...@@ -932,10 +944,11 @@ void dumpexportvar(Sym*);
void dumpexportconst(Sym*); void dumpexportconst(Sym*);
void importconst(Sym *s, Type *t, Node *v); void importconst(Sym *s, Type *t, Node *v);
void importmethod(Sym *s, Type *t); void importmethod(Sym *s, Type *t);
void importtype(Sym *s, Type *t); void importtype(Type *s, Type *t);
void importvar(Sym *s, Type *t, int ctxt); void importvar(Sym *s, Type *t, int ctxt);
void checkimports(void); void checkimports(void);
Type* pkgtype(Sym*); Type* pkgtype(Sym*);
Sym* importsym(Sym*, int);
/* /*
* walk.c * walk.c
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
%type <node> for_body for_header for_stmt if_header if_stmt %type <node> for_body for_header for_stmt if_header if_stmt
%type <node> keyval labelname name %type <node> keyval labelname name
%type <node> name_or_type non_expr_type %type <node> name_or_type non_expr_type
%type <node> new_name dcl_name oexpr %type <node> new_name dcl_name oexpr typedclname
%type <node> onew_name %type <node> onew_name
%type <node> osimple_stmt pexpr %type <node> osimple_stmt pexpr
%type <node> pseudocall range_stmt select_stmt %type <node> pseudocall range_stmt select_stmt
...@@ -72,8 +72,7 @@ ...@@ -72,8 +72,7 @@
%type <node> convtype dotdotdot %type <node> convtype dotdotdot
%type <node> indcl interfacetype structtype ptrtype %type <node> indcl interfacetype structtype ptrtype
%type <type> new_type typedclname %type <node> chantype non_chan_type othertype non_fn_type fntype
%type <node> chantype non_chan_type othertype non_fn_type fntype fnlitdcl
%type <sym> hidden_importsym hidden_pkg_importsym %type <sym> hidden_importsym hidden_pkg_importsym
...@@ -85,7 +84,7 @@ ...@@ -85,7 +84,7 @@
%type <list> hidden_interfacedcl_list ohidden_interfacedcl_list %type <list> hidden_interfacedcl_list ohidden_interfacedcl_list
%type <list> hidden_structdcl_list ohidden_structdcl_list %type <list> hidden_structdcl_list ohidden_structdcl_list
%type <type> hidden_type hidden_type1 hidden_type2 %type <type> hidden_type hidden_type1 hidden_type2 hidden_pkgtype
%left LOROR %left LOROR
%left LANDAND %left LANDAND
...@@ -121,13 +120,28 @@ file: ...@@ -121,13 +120,28 @@ file:
imports imports
xdcl_list xdcl_list
{ {
NodeList *l;
if(nsyntaxerrors == 0)
testdclstack();
typecheckok = 1;
if(debug['f']) if(debug['f'])
frame(1); frame(1);
defercheckwidth();
typechecklist($4, Etop); typechecklist($4, Etop);
resumecheckwidth();
for(l=$4; l; l=l->next)
if(l->n->op == ODCLFUNC)
funccompile(l->n);
if(nerrors == 0) if(nerrors == 0)
fninit($4); fninit($4);
if(nsyntaxerrors == 0) while(closures) {
testdclstack(); l = closures;
closures = nil;
for(; l; l=l->next)
funccompile(l->n);
}
dclchecks(); dclchecks();
} }
...@@ -266,16 +280,10 @@ import_done: ...@@ -266,16 +280,10 @@ import_done:
* declarations * declarations
*/ */
xdcl: xdcl:
{ stksize = initstksize; } common_dcl common_dcl
{
$$ = $2;
initstksize = stksize;
}
| xfndcl | xfndcl
{ {
if($1 != N && $1->nname != N && $1->type->thistuple == 0) $$ = list1($1);
autoexport($1->nname, dclcontext);
$$ = nil;
} }
| ';' | ';'
{ {
...@@ -305,26 +313,23 @@ common_dcl: ...@@ -305,26 +313,23 @@ common_dcl:
} }
| LCONST constdcl | LCONST constdcl
{ {
$$ = nil; $$ = $2;
iota = 0; iota = 0;
lastconst = nil; lastconst = nil;
walkdeflist($2);
} }
| LCONST '(' constdcl osemi ')' | LCONST '(' constdcl osemi ')'
{ {
$$ = nil; $$ = $3;
iota = 0; iota = 0;
lastconst = nil; lastconst = nil;
yyoptsemi(0); yyoptsemi(0);
walkdeflist($3);
} }
| LCONST '(' constdcl ';' constdcl_list osemi ')' | LCONST '(' constdcl ';' constdcl_list osemi ')'
{ {
$$ = nil; $$ = concat($3, $5);
iota = 0; iota = 0;
lastconst = nil; lastconst = nil;
yyoptsemi(0); yyoptsemi(0);
walkdeflist(concat($3, $5));
} }
| LCONST '(' ')' | LCONST '(' ')'
{ {
...@@ -333,15 +338,13 @@ common_dcl: ...@@ -333,15 +338,13 @@ common_dcl:
} }
| LTYPE typedcl | LTYPE typedcl
{ {
$$ = nil; $$ = list1($2);
// $$ = list1($2);
if(yylast == LSEMIBRACE) if(yylast == LSEMIBRACE)
yyoptsemi(0); yyoptsemi(0);
} }
| LTYPE '(' typedcl_list osemi ')' | LTYPE '(' typedcl_list osemi ')'
{ {
$$ = nil; $$ = $3;
// $$ = $3;
yyoptsemi(0); yyoptsemi(0);
} }
| LTYPE '(' ')' | LTYPE '(' ')'
...@@ -392,28 +395,29 @@ constdcl1: ...@@ -392,28 +395,29 @@ constdcl1:
} }
typedclname: typedclname:
new_type sym
{ {
$$ = dodcltype($1); // different from dclname because the name
defercheckwidth(); // becomes visible right here, not at the end
// of the declaration.
$$ = typedcl0($1);
} }
typedcl: typedcl:
typedclname ntype typedclname ntype
{ {
typecheck(&$2, Etype); $$ = typedcl1($1, $2, 1);
updatetype($1, $2->type);
resumecheckwidth();
} }
// TODO(rsc): delete
| typedclname LSTRUCT | typedclname LSTRUCT
{ {
updatetype($1, typ(TFORWSTRUCT)); $$ = fwdtype($1, TFORWSTRUCT);
resumecheckwidth();
} }
// TODO(rsc): delete
| typedclname LINTERFACE | typedclname LINTERFACE
{ {
updatetype($1, typ(TFORWINTER)); $$ = fwdtype($1, TFORWINTER);
resumecheckwidth();
} }
simple_stmt: simple_stmt:
...@@ -814,9 +818,6 @@ uexpr: ...@@ -814,9 +818,6 @@ uexpr:
pseudocall: pseudocall:
pexpr '(' oexpr_or_type_list ')' pexpr '(' oexpr_or_type_list ')'
{ {
$$ = unsafenmagic($1, $3);
if($$)
break;
$$ = nod(OCALL, $1, N); $$ = nod(OCALL, $1, N);
$$->list = $3; $$->list = $3;
} }
...@@ -918,12 +919,6 @@ dcl_name: ...@@ -918,12 +919,6 @@ dcl_name:
$$ = dclname($1); $$ = dclname($1);
} }
new_type:
sym
{
$$ = newtype($1);
}
onew_name: onew_name:
{ {
$$ = N; $$ = N;
...@@ -940,7 +935,7 @@ name: ...@@ -940,7 +935,7 @@ name:
} }
labelname: labelname:
name new_name
convtype: convtype:
'[' oexpr ']' ntype '[' oexpr ']' ntype
...@@ -1104,14 +1099,10 @@ keyval: ...@@ -1104,14 +1099,10 @@ keyval:
* all in one place to show how crappy it all is * all in one place to show how crappy it all is
*/ */
xfndcl: xfndcl:
LFUNC LFUNC fndcl fnbody
{
maxarg = 0;
stksize = 0;
} fndcl fnbody
{ {
$$ = $3; $$ = $2;
$$->nbody = $4; $$->nbody = $3;
funcbody($$); funcbody($$);
} }
...@@ -1127,13 +1118,13 @@ fndcl: ...@@ -1127,13 +1118,13 @@ fndcl:
n = nod(OTFUNC, N, N); n = nod(OTFUNC, N, N);
n->list = $3; n->list = $3;
n->rlist = $5; n->rlist = $5;
typecheck(&n, Etype); // TODO: check if nname already has an ntype
$$->type = n->type; $$->nname->ntype = n;
funchdr($$); funchdr($$);
} }
| '(' oarg_type_list ')' new_name '(' oarg_type_list ')' fnres | '(' oarg_type_list ')' new_name '(' oarg_type_list ')' fnres
{ {
Node *rcvr; Node *rcvr, *t;
rcvr = $2->n; rcvr = $2->n;
if($2->next != nil || $2->n->op != ODCLFIELD) { if($2->next != nil || $2->n->op != ODCLFIELD) {
...@@ -1142,12 +1133,13 @@ fndcl: ...@@ -1142,12 +1133,13 @@ fndcl:
} }
$$ = nod(ODCLFUNC, N, N); $$ = nod(ODCLFUNC, N, N);
$$->nname = $4; $$->nname = methodname1($4, rcvr->right);
$$->nname = methodname($4, rcvr->type); t = nod(OTFUNC, rcvr, N);
$$->type = functype(rcvr, $6, $8); t->list = $6;
t->rlist = $8;
$$->nname->ntype = t;
$$->shortname = $4;
funchdr($$); funchdr($$);
if(rcvr != N)
addmethod($4, $$->type, 1);
} }
fntype: fntype:
...@@ -1158,19 +1150,6 @@ fntype: ...@@ -1158,19 +1150,6 @@ fntype:
$$->rlist = $5; $$->rlist = $5;
} }
fnlitdcl:
fntype
{
markdcl();
$$ = funclit0($$);
}
fnliteral:
fnlitdcl '{' stmt_list '}'
{
$$ = funclit1($1, $3);
}
fnbody: fnbody:
{ {
$$ = nil; $$ = nil;
...@@ -1197,6 +1176,19 @@ fnres: ...@@ -1197,6 +1176,19 @@ fnres:
$$ = $2; $$ = $2;
} }
fnlitdcl:
fntype
{
closurehdr($1);
}
fnliteral:
fnlitdcl '{' stmt_list '}'
{
$$ = closurebody($3);
}
/* /*
* lists of things * lists of things
* note that they are left recursive * note that they are left recursive
...@@ -1590,15 +1582,16 @@ hidden_import: ...@@ -1590,15 +1582,16 @@ hidden_import:
{ {
importconst($2, $3, $5); importconst($2, $3, $5);
} }
| LTYPE hidden_pkg_importsym hidden_type | LTYPE hidden_pkgtype hidden_type
{ {
importtype($2, $3); importtype($2, $3);
} }
| LTYPE hidden_pkg_importsym LSTRUCT // TODO(rsc): delete
| LTYPE hidden_pkgtype LSTRUCT
{ {
importtype($2, typ(TFORWSTRUCT)); importtype($2, typ(TFORWSTRUCT));
} }
| LTYPE hidden_pkg_importsym LINTERFACE | LTYPE hidden_pkgtype LINTERFACE
{ {
importtype($2, typ(TFORWINTER)); importtype($2, typ(TFORWINTER));
} }
...@@ -1615,6 +1608,13 @@ hidden_import: ...@@ -1615,6 +1608,13 @@ hidden_import:
importmethod($5, functype($3->n, $7, $9)); importmethod($5, functype($3->n, $7, $9));
} }
hidden_pkgtype:
hidden_pkg_importsym
{
$$ = pkgtype($1);
importsym($1, OTYPE);
}
hidden_type: hidden_type:
hidden_type1 hidden_type1
| hidden_type2 | hidden_type2
...@@ -1690,13 +1690,11 @@ hidden_type2: ...@@ -1690,13 +1690,11 @@ hidden_type2:
hidden_dcl: hidden_dcl:
sym hidden_type sym hidden_type
{ {
$$ = nod(ODCLFIELD, newname($1), N); $$ = nod(ODCLFIELD, newname($1), typenod($2));
$$->type = $2;
} }
| '?' hidden_type | '?' hidden_type
{ {
$$ = nod(ODCLFIELD, N, N); $$ = nod(ODCLFIELD, N, typenod($2));
$$->type = $2;
} }
hidden_structdcl: hidden_structdcl:
...@@ -1734,11 +1732,7 @@ hidden_funres: ...@@ -1734,11 +1732,7 @@ hidden_funres:
} }
| hidden_type1 | hidden_type1
{ {
Node *n; $$ = list1(nod(ODCLFIELD, N, typenod($1)));
n = nod(ODCLFIELD, N, N);
n->type = $1;
$$ = list1(n);
} }
hidden_constant: hidden_constant:
......
...@@ -50,10 +50,20 @@ anyinit(NodeList *n) ...@@ -50,10 +50,20 @@ anyinit(NodeList *n)
{ {
uint32 h; uint32 h;
Sym *s; Sym *s;
NodeList *l;
// are there any init statements
if(n != nil) // are there any interesting init statements
for(l=n; l; l=l->next) {
switch(l->n->op) {
case ODCLFUNC:
case ODCLCONST:
case ODCLTYPE:
case OEMPTY:
break;
default:
return 1; return 1;
}
}
// is this main // is this main
if(strcmp(package, "main") == 0) if(strcmp(package, "main") == 0)
...@@ -93,6 +103,7 @@ fninit(NodeList *n) ...@@ -93,6 +103,7 @@ fninit(NodeList *n)
return; return;
} }
n = initfix(n);
if(!anyinit(n)) if(!anyinit(n))
return; return;
...@@ -106,7 +117,6 @@ fninit(NodeList *n) ...@@ -106,7 +117,6 @@ fninit(NodeList *n)
// (2) // (2)
maxarg = 0; maxarg = 0;
stksize = initstksize;
snprint(namebuf, sizeof(namebuf), "Init·%s", filename); snprint(namebuf, sizeof(namebuf), "Init·%s", filename);
...@@ -118,7 +128,7 @@ fninit(NodeList *n) ...@@ -118,7 +128,7 @@ fninit(NodeList *n)
fn = nod(ODCLFUNC, N, N); fn = nod(ODCLFUNC, N, N);
initsym = lookup(namebuf); initsym = lookup(namebuf);
fn->nname = newname(initsym); fn->nname = newname(initsym);
fn->type = functype(N, nil, nil); fn->nname->ntype = nod(OTFUNC, N, N);
funchdr(fn); funchdr(fn);
// (3) // (3)
...@@ -181,12 +191,14 @@ fninit(NodeList *n) ...@@ -181,12 +191,14 @@ fninit(NodeList *n)
exportsym(fn->nname); exportsym(fn->nname);
fn->nbody = r; fn->nbody = r;
//dump("b", fn); //dump("b", fn);
//dump("r", fn->nbody); //dump("r", fn->nbody);
popdcl();
initflag = 1; // flag for loader static initialization initflag = 1; // flag for loader static initialization
compile(fn); funcbody(fn);
typecheck(&fn, Etop);
funccompile(fn);
initflag = 0; initflag = 0;
} }
......
...@@ -310,6 +310,7 @@ importfile(Val *f) ...@@ -310,6 +310,7 @@ importfile(Val *f)
curio.peekc = 0; curio.peekc = 0;
curio.peekc1 = 0; curio.peekc1 = 0;
curio.infile = file; curio.infile = file;
typecheckok = 1;
for(;;) { for(;;) {
c = getc(); c = getc();
if(c == EOF) if(c == EOF)
...@@ -343,6 +344,7 @@ unimportfile(void) ...@@ -343,6 +344,7 @@ unimportfile(void)
curio = pushedio; curio = pushedio;
pushedio.bin = nil; pushedio.bin = nil;
inimportsys = 0; inimportsys = 0;
typecheckok = 0;
} }
void void
...@@ -362,6 +364,7 @@ cannedimports(char *file, char *cp) ...@@ -362,6 +364,7 @@ cannedimports(char *file, char *cp)
curio.cp = cp; curio.cp = cp;
pkgmyname = S; pkgmyname = S;
typecheckok = 1;
inimportsys = 1; inimportsys = 1;
} }
...@@ -1308,6 +1311,7 @@ lexinit(void) ...@@ -1308,6 +1311,7 @@ lexinit(void)
t = typ(etype); t = typ(etype);
t->sym = s; t->sym = s;
if(etype != TANY && etype != TSTRING)
dowidth(t); dowidth(t);
types[etype] = t; types[etype] = t;
} }
......
...@@ -389,6 +389,7 @@ dcommontype(Sym *s, int ot, Type *t) ...@@ -389,6 +389,7 @@ dcommontype(Sym *s, int ot, Type *t)
Type *elem; Type *elem;
char *p; char *p;
dowidth(t);
s1 = dextratype(t); s1 = dextratype(t);
// empty interface pointing at this type. // empty interface pointing at this type.
......
...@@ -69,6 +69,12 @@ initlin(NodeList *l) ...@@ -69,6 +69,12 @@ initlin(NodeList *l)
for(; l; l=l->next) { for(; l; l=l->next) {
n = l->n; n = l->n;
switch(n->op) {
case ODCLFUNC:
case ODCLCONST:
case ODCLTYPE:
continue;
}
initlin(n->ninit); initlin(n->ninit);
n->ninit = nil; n->ninit = nil;
xxx.list = list(xxx.list, n); xxx.list = list(xxx.list, n);
......
...@@ -380,6 +380,7 @@ typ(int et) ...@@ -380,6 +380,7 @@ typ(int et)
t = mal(sizeof(*t)); t = mal(sizeof(*t));
t->etype = et; t->etype = et;
t->width = BADWIDTH;
return t; return t;
} }
...@@ -471,7 +472,6 @@ aindex(Node *b, Type *t) ...@@ -471,7 +472,6 @@ aindex(Node *b, Type *t)
r = typ(TARRAY); r = typ(TARRAY);
r->type = t; r->type = t;
r->bound = bound; r->bound = bound;
checkwidth(r);
return r; return r;
} }
...@@ -517,7 +517,12 @@ dodump(Node *n, int dep) ...@@ -517,7 +517,12 @@ dodump(Node *n, int dep)
break; break;
case OTYPE: case OTYPE:
print("%O %T\n", n->op, n->type); print("%O %S type=%T\n", n->op, n->sym, n->type);
if(n->type == T && n->ntype) {
indent(dep);
print("%O-ntype\n", n->op);
dodump(n->ntype, dep+1);
}
break; break;
case OIF: case OIF:
...@@ -577,7 +582,7 @@ dodump(Node *n, int dep) ...@@ -577,7 +582,7 @@ dodump(Node *n, int dep)
break; break;
} }
if(n->ntype != nil) { if(0 && n->ntype != nil) {
indent(dep); indent(dep);
print("%O-ntype\n", n->op); print("%O-ntype\n", n->op);
dodump(n->ntype, dep+1); dodump(n->ntype, dep+1);
...@@ -1930,7 +1935,9 @@ frame(int context) ...@@ -1930,7 +1935,9 @@ frame(int context)
int flag; int flag;
p = "stack"; p = "stack";
l = autodcl; l = nil;
if(curfn)
l = curfn->dcl;
if(context) { if(context) {
p = "external"; p = "external";
l = externdcl; l = externdcl;
...@@ -2202,42 +2209,6 @@ brrev(int a) ...@@ -2202,42 +2209,6 @@ brrev(int a)
return a; return a;
} }
/*
* make a new off the books
*/
void
tempname(Node *n, Type *t)
{
Sym *s;
uint32 w;
if(t == T) {
yyerror("tempname called with nil type");
t = types[TINT32];
}
// give each tmp a different name so that there
// a chance to registerizer them
snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
statuniqgen++;
s = lookup(namebuf);
memset(n, 0, sizeof(*n));
n->op = ONAME;
n->sym = s;
n->type = t;
n->class = PAUTO;
n->addable = 1;
n->ullman = 1;
n->noescape = 1;
dowidth(t);
w = t->width;
stksize += w;
stksize = rnd(stksize, w);
n->xoffset = -stksize;
}
Node* Node*
staticname(Type *t) staticname(Type *t)
{ {
...@@ -2297,58 +2268,14 @@ setmaxarg(Type *t) ...@@ -2297,58 +2268,14 @@ setmaxarg(Type *t)
{ {
int32 w; int32 w;
dowidth(t);
w = t->argwid; w = t->argwid;
if(t->argwid >= 100000000)
fatal("bad argwid %T", t);
if(w > maxarg) if(w > maxarg)
maxarg = w; maxarg = w;
} }
/*
* gather series of offsets
* >=0 is direct addressed field
* <0 is pointer to next field (+1)
*/
int
dotoffset(Node *n, int *oary, Node **nn)
{
int i;
switch(n->op) {
case ODOT:
if(n->xoffset == BADWIDTH) {
dump("bad width in dotoffset", n);
fatal("bad width in dotoffset");
}
i = dotoffset(n->left, oary, nn);
if(i > 0) {
if(oary[i-1] >= 0)
oary[i-1] += n->xoffset;
else
oary[i-1] -= n->xoffset;
break;
}
if(i < 10)
oary[i++] = n->xoffset;
break;
case ODOTPTR:
if(n->xoffset == BADWIDTH) {
dump("bad width in dotoffset", n);
fatal("bad width in dotoffset");
}
i = dotoffset(n->left, oary, nn);
if(i < 10)
oary[i++] = -(n->xoffset+1);
break;
default:
*nn = n;
return 0;
}
if(i >= 10)
*nn = N;
return i;
}
/* /*
* code to resolve elided DOTs * code to resolve elided DOTs
* in embedded types * in embedded types
...@@ -2644,8 +2571,7 @@ structargs(Type **tl, int mustname) ...@@ -2644,8 +2571,7 @@ structargs(Type **tl, int mustname)
snprint(buf, sizeof buf, ".anon%d", gen++); snprint(buf, sizeof buf, ".anon%d", gen++);
n = newname(lookup(buf)); n = newname(lookup(buf));
} }
a = nod(ODCLFIELD, n, N); a = nod(ODCLFIELD, n, typenod(t->type));
a->type = t->type;
args = list(args, a); args = list(args, a);
} }
return args; return args;
...@@ -2677,7 +2603,7 @@ structargs(Type **tl, int mustname) ...@@ -2677,7 +2603,7 @@ structargs(Type **tl, int mustname)
void void
genwrapper(Type *rcvr, Type *method, Sym *newnam) genwrapper(Type *rcvr, Type *method, Sym *newnam)
{ {
Node *this, *fn, *call, *n; Node *this, *fn, *call, *n, *t;
NodeList *l, *args, *in, *out; NodeList *l, *args, *in, *out;
if(debug['r']) if(debug['r'])
...@@ -2687,14 +2613,17 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam) ...@@ -2687,14 +2613,17 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
dclcontext = PEXTERN; dclcontext = PEXTERN;
markdcl(); markdcl();
this = nod(ODCLFIELD, newname(lookup(".this")), N); this = nod(ODCLFIELD, newname(lookup(".this")), typenod(rcvr));
this->type = rcvr; this->left->ntype = this->right;
in = structargs(getinarg(method->type), 1); in = structargs(getinarg(method->type), 1);
out = structargs(getoutarg(method->type), 0); out = structargs(getoutarg(method->type), 0);
fn = nod(ODCLFUNC, N, N); fn = nod(ODCLFUNC, N, N);
fn->nname = newname(newnam); fn->nname = newname(newnam);
fn->type = functype(this, in, out); t = nod(OTFUNC, this, N);
t->list = in;
t->rlist = out;
fn->nname->ntype = t;
funchdr(fn); funchdr(fn);
// arg list // arg list
...@@ -2716,6 +2645,8 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam) ...@@ -2716,6 +2645,8 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
dumplist("genwrapper body", fn->nbody); dumplist("genwrapper body", fn->nbody);
funcbody(fn); funcbody(fn);
typecheck(&fn, Etop);
funccompile(fn);
} }
/* /*
...@@ -3044,6 +2975,9 @@ checkwidth(Type *t) ...@@ -3044,6 +2975,9 @@ checkwidth(Type *t)
dowidth(t); dowidth(t);
return; return;
} }
if(t->deferwidth)
return;
t->deferwidth = 1;
l = tlfree; l = tlfree;
if(l != nil) if(l != nil)
...@@ -3075,6 +3009,7 @@ resumecheckwidth(void) ...@@ -3075,6 +3009,7 @@ resumecheckwidth(void)
defercalc = 0; defercalc = 0;
for(l = tlq; l != nil; l = tlq) { for(l = tlq; l != nil; l = tlq) {
l->t->deferwidth = 0;
dowidth(l->t); dowidth(l->t);
tlq = l->next; tlq = l->next;
l->next = tlfree; l->next = tlfree;
......
...@@ -27,6 +27,7 @@ static void typecheckcomplit(Node**); ...@@ -27,6 +27,7 @@ static void typecheckcomplit(Node**);
static void addrescapes(Node*); static void addrescapes(Node*);
static void typecheckas2(Node*); static void typecheckas2(Node*);
static void typecheckas(Node*); static void typecheckas(Node*);
static void typecheckfunc(Node*);
static void checklvalue(Node*, char*); static void checklvalue(Node*, char*);
static void checkassign(Node*); static void checkassign(Node*);
static void checkassignlist(NodeList*); static void checkassignlist(NodeList*);
...@@ -53,6 +54,10 @@ typecheck(Node **np, int top) ...@@ -53,6 +54,10 @@ typecheck(Node **np, int top)
int lno, ok; int lno, ok;
Type *t; Type *t;
// cannot type check until all the source has been parsed
if(!typecheckok)
fatal("early typecheck");
n = *np; n = *np;
if(n == N) if(n == N)
return N; return N;
...@@ -392,9 +397,10 @@ reswitch: ...@@ -392,9 +397,10 @@ reswitch:
if(t == T) if(t == T)
goto error; goto error;
n->op = ODOTPTR; n->op = ODOTPTR;
checkwidth(t);
} }
if(!lookdot(n, t)) { if(!lookdot(n, t)) {
yyerror("%#N undefined (type %T has no field %S)", n, t, n->right->sym); yyerror("%#N undefined (type %p %T has no field %S)", n, t, t, n->right->sym);
goto error; goto error;
} }
switch(n->op) { switch(n->op) {
...@@ -566,6 +572,10 @@ reswitch: ...@@ -566,6 +572,10 @@ reswitch:
n->right = N; n->right = N;
goto reswitch; goto reswitch;
} }
if(l->op == ONAME && (r = unsafenmagic(l, n->list)) != N) {
n = r;
goto reswitch;
}
typecheck(&n->left, Erv | Etype | Ecall); typecheck(&n->left, Erv | Etype | Ecall);
defaultlit(&n->left, T); defaultlit(&n->left, T);
l = n->left; l = n->left;
...@@ -575,7 +585,7 @@ reswitch: ...@@ -575,7 +585,7 @@ reswitch:
typechecklist(n->list, Erv); typechecklist(n->list, Erv);
if((t = l->type) == T) if((t = l->type) == T)
goto error; goto error;
dowidth(t); checkwidth(t);
switch(l->op) { switch(l->op) {
case OTYPE: case OTYPE:
...@@ -818,6 +828,13 @@ reswitch: ...@@ -818,6 +828,13 @@ reswitch:
typechecklist(n->list, Erv); typechecklist(n->list, Erv);
goto ret; goto ret;
case OCLOSURE:
ok |= Erv;
typecheckclosure(n);
if(n->type == T)
goto error;
goto ret;
/* /*
* statements * statements
*/ */
...@@ -905,9 +922,40 @@ reswitch: ...@@ -905,9 +922,40 @@ reswitch:
typechecklist(n->list, Erv); typechecklist(n->list, Erv);
typechecklist(n->nbody, Etop); typechecklist(n->nbody, Etop);
goto ret; goto ret;
case ODCLFUNC:
ok |= Etop;
typecheckfunc(n);
goto ret;
case ODCLCONST:
ok |= Etop;
typecheck(&n->left, Erv);
goto ret;
case ODCLTYPE:
ok |= Etop;
typecheck(&n->left, Etype);
goto ret;
} }
ret: ret:
t = n->type;
if(t && !t->funarg && n->op != OTYPE) {
switch(t->etype) {
case TFUNC: // might have TANY; wait until its called
case TANY:
case TFORW:
case TFORWINTER:
case TFORWSTRUCT:
case TIDEAL:
case TNIL:
break;
default:
checkwidth(t);
}
}
evconst(n); evconst(n);
if(n->op == OTYPE && !(top & Etype)) { if(n->op == OTYPE && !(top & Etype)) {
yyerror("type %T is not an expression", n->type); yyerror("type %T is not an expression", n->type);
...@@ -921,11 +969,12 @@ ret: ...@@ -921,11 +969,12 @@ ret:
yyerror("must call %#N", n); yyerror("must call %#N", n);
goto error; goto error;
} }
if((top & (Ecall|Erv|Etype)) && !(ok & (Erv|Etype|Ecall))) { // TODO(rsc): simplify
if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) {
yyerror("%#N used as value", n); yyerror("%#N used as value", n);
goto error; goto error;
} }
if((top & Etop) && !(ok & Etop)) { if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) {
yyerror("%#N not used", n); yyerror("%#N not used", n);
goto error; goto error;
} }
...@@ -1016,6 +1065,7 @@ lookdot(Node *n, Type *t) ...@@ -1016,6 +1065,7 @@ lookdot(Node *n, Type *t)
s = n->right->sym; s = n->right->sym;
dowidth(t);
f1 = T; f1 = T;
if(t->etype == TSTRUCT || t->etype == TINTER) if(t->etype == TSTRUCT || t->etype == TINTER)
f1 = lookdot1(s, t, t->type); f1 = lookdot1(s, t, t->type);
...@@ -1042,6 +1092,7 @@ lookdot(Node *n, Type *t) ...@@ -1042,6 +1092,7 @@ lookdot(Node *n, Type *t)
if(f2 != T) { if(f2 != T) {
tt = n->left->type; tt = n->left->type;
dowidth(tt);
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)) {
...@@ -1609,12 +1660,18 @@ addrescapes(Node *n) ...@@ -1609,12 +1660,18 @@ addrescapes(Node *n)
case PPARAM: case PPARAM:
// if func param, need separate temporary // if func param, need separate temporary
// to hold heap pointer. // to hold heap pointer.
// the function type has already been checked
// (we're in the function body)
// so the param already has a valid xoffset.
if(n->class == PPARAM) { if(n->class == PPARAM) {
// expression to refer to stack copy // expression to refer to stack copy
n->stackparam = nod(OPARAM, n, N); n->stackparam = nod(OPARAM, n, N);
n->stackparam->type = n->type; n->stackparam->type = n->type;
n->stackparam->addable = 1; n->stackparam->addable = 1;
if(n->xoffset == BADWIDTH)
fatal("addrescapes before param assignment");
n->stackparam->xoffset = n->xoffset; n->stackparam->xoffset = n->xoffset;
n->xoffset = 0;
} }
n->class |= PHEAP; n->class |= PHEAP;
...@@ -1624,10 +1681,12 @@ addrescapes(Node *n) ...@@ -1624,10 +1681,12 @@ addrescapes(Node *n)
n->xoffset = 0; n->xoffset = 0;
// create stack variable to hold pointer to heap // create stack variable to hold pointer to heap
n->heapaddr = nod(0, N, N); n->heapaddr = nod(ONAME, N, N);
tempname(n->heapaddr, ptrto(n->type)); n->heapaddr->type = ptrto(n->type);
snprint(buf, sizeof buf, "&%S", n->sym); snprint(buf, sizeof buf, "&%S", n->sym);
n->heapaddr->sym = lookup(buf); n->heapaddr->sym = lookup(buf);
n->heapaddr->class = PHEAP-1; // defer tempname to allocparams
curfn->dcl = list(curfn->dcl, n->heapaddr);
break; break;
} }
break; break;
...@@ -1846,3 +1905,21 @@ out: ...@@ -1846,3 +1905,21 @@ out:
if(ll->n->typecheck == 0) if(ll->n->typecheck == 0)
typecheck(&ll->n, Erv); typecheck(&ll->n, Erv);
} }
/*
* type check function definition
*/
static void
typecheckfunc(Node *n)
{
Type *t, *rcvr;
typecheck(&n->nname, Erv);
if((t = n->nname->type) == T)
return;
n->type = t;
rcvr = getthisx(t)->type;
if(rcvr != nil && n->shortname != N)
addmethod(n->shortname->sym, t, 1);
}
...@@ -52,16 +52,9 @@ loop: ...@@ -52,16 +52,9 @@ loop:
case OGOTO: case OGOTO:
case ORETURN: case ORETURN:
return 0;
case OCALL:
if(n->left->op == ONAME) {
switch(n->left->etype) {
case OPANIC: case OPANIC:
case OPANICN: case OPANICN:
return 0; return 0;
}
}
break; break;
} }
...@@ -118,7 +111,7 @@ walkdeflist(NodeList *l) ...@@ -118,7 +111,7 @@ walkdeflist(NodeList *l)
void void
walkdef(Node *n) walkdef(Node *n)
{ {
int lno; int lno, maplineno;
NodeList *init; NodeList *init;
Node *e; Node *e;
Type *t; Type *t;
...@@ -147,6 +140,9 @@ walkdef(Node *n) ...@@ -147,6 +140,9 @@ walkdef(Node *n)
init = nil; init = nil;
switch(n->op) { switch(n->op) {
default:
fatal("walkdef %O", n->op);
case OLITERAL: case OLITERAL:
if(n->ntype != N) { if(n->ntype != N) {
typecheck(&n->ntype, Etype); typecheck(&n->ntype, Etype);
...@@ -189,8 +185,48 @@ walkdef(Node *n) ...@@ -189,8 +185,48 @@ walkdef(Node *n)
break; break;
if(n->defn == N) if(n->defn == N)
fatal("var without type, init: %S", n->sym); fatal("var without type, init: %S", n->sym);
if(n->defn->op == ONAME) {
typecheck(&n->defn, Erv);
n->type = n->defn->type;
break;
}
typecheck(&n->defn, Etop); // fills in n->type typecheck(&n->defn, Etop); // fills in n->type
break; break;
case OTYPE:
n->walkdef = 1;
if(n->nincr != N) // fwd decl hack
n->type = n->nincr->type;
else
n->type = typ(TFORW);
n->type->sym = n->sym;
n->typecheck = 1;
typecheck(&n->ntype, Etype);
if((t = n->ntype->type) == T) {
n->diag = 1;
goto ret;
}
// copy new type and clear fields
// that don't come along
maplineno = n->type->maplineno;
*n->type = *t;
t = n->type;
t->sym = n->sym;
t->local = n->local;
t->vargen = n->vargen;
t->siggen = 0;
t->printed = 0;
t->method = nil;
t->nod = N;
// double-check use of type as map key
// TODO(rsc): also use of type as receiver?
if(maplineno) {
lineno = maplineno;
maptype(n->type, types[TBOOL]);
}
break;
} }
ret: ret:
...@@ -265,6 +301,8 @@ walkstmt(Node **np) ...@@ -265,6 +301,8 @@ walkstmt(Node **np)
case OFALL: case OFALL:
case OGOTO: case OGOTO:
case OLABEL: case OLABEL:
case ODCLCONST:
case ODCLTYPE:
break; break;
case OBLOCK: case OBLOCK:
...@@ -919,6 +957,10 @@ walkexpr(Node **np, NodeList **init) ...@@ -919,6 +957,10 @@ walkexpr(Node **np, NodeList **init)
argtype(fn, n->type->type); // any-2 argtype(fn, n->type->type); // any-2
n = mkcall1(fn, n->type, init, n->left, nodintconst(n->left->type->type->bound)); n = mkcall1(fn, n->type, init, n->left, nodintconst(n->left->type->type->bound));
goto ret; goto ret;
case OCLOSURE:
n = walkclosure(n, init);
goto ret;
} }
fatal("missing switch %O", n->op); fatal("missing switch %O", n->op);
...@@ -1658,6 +1700,7 @@ ifacecvt(Type *tl, Node *n, int et, NodeList **init) ...@@ -1658,6 +1700,7 @@ ifacecvt(Type *tl, Node *n, int et, NodeList **init)
break; break;
} }
dowidth(on->type);
r = nod(OCALL, on, N); r = nod(OCALL, on, N);
r->list = args; r->list = args;
typecheck(&r, Erv | Efnstruct); typecheck(&r, Erv | Efnstruct);
......
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