Commit ab8ed7f8 authored by Luuk van Dijk's avatar Luuk van Dijk

gc: renamed walkdef to typecheckdef and moved from walk to typedef.

also inlined a typechecking function in dcl away.

R=rsc
CC=golang-dev
https://golang.org/cl/4550115
parent f4f58368
......@@ -438,20 +438,6 @@ newtype(Sym *s)
return t;
}
/*
* type check top level declarations
*/
void
dclchecks(void)
{
NodeList *l;
for(l=externdcl; l; l=l->next) {
if(l->n->op != ONAME)
continue;
typecheck(&l->n, Erv);
}
}
/*
* := declarations
......
......@@ -862,7 +862,6 @@ NodeList* checkarglist(NodeList *all, int input);
Node* colas(NodeList *left, NodeList *right);
void colasdefn(NodeList *left, Node *defn);
NodeList* constiter(NodeList *vl, Node *t, NodeList *cl);
void dclchecks(void);
Node* dclname(Sym *s);
void declare(Node *n, int ctxt);
Type* dostruct(NodeList *l, int et);
......@@ -1166,6 +1165,11 @@ int exportassignok(Type *t, char *desc);
int islvalue(Node *n);
Node* typecheck(Node **np, int top);
void typechecklist(NodeList *l, int top);
Node* typecheckdef(Node *n);
void resumetypecopy(void);
void copytype(Node *n, Type *t);
void defertypecopy(Node *n, Type *t);
void queuemethod(Node *n);
/*
* unsafe.c
......@@ -1177,15 +1181,10 @@ Node* unsafenmagic(Node *n);
*/
Node* callnew(Type *t);
Node* chanfn(char *name, int n, Type *t);
void copytype(Node *n, Type *t);
void defertypecopy(Node *n, Type *t);
Node* mkcall(char *name, Type *t, NodeList **init, ...);
Node* mkcall1(Node *fn, Type *t, NodeList **init, ...);
void queuemethod(Node *n);
void resumetypecopy(void);
int vmatch1(Node *l, Node *r);
void walk(Node *fn);
Node* walkdef(Node *n);
void walkexpr(Node **np, NodeList **init);
void walkexprlist(NodeList *l, NodeList **init);
void walkexprlistsafe(NodeList *l, NodeList **init);
......
......@@ -274,7 +274,9 @@ main(int argc, char *argv[])
funccompile(l->n, 1);
}
dclchecks();
for(l=externdcl; l; l=l->next)
if(l->n->op == ONAME)
typecheck(&l->n, Erv);
if(nerrors)
errorexit();
......
......@@ -8,7 +8,6 @@
* evaluates compile time constants.
* marks variables that escape the local frame.
* rewrites n->op to be more specific in some cases.
* sets n->walk to walking function.
*/
#include "go.h"
......@@ -33,6 +32,8 @@ static void stringtoarraylit(Node**);
static Node* resolve(Node*);
static Type* getforwtype(Node*);
static NodeList* typecheckdefstack;
/*
* resolve ONONAME to definition, if any.
*/
......@@ -159,7 +160,7 @@ typecheck(Node **np, int top)
if(n->op == OTYPE && (ft = getforwtype(n->ntype)) != T)
defertypecopy(n, ft);
walkdef(n);
typecheckdef(n);
n->realtype = n->type;
if(n->op == ONONAME)
goto error;
......@@ -2523,3 +2524,294 @@ getforwtype(Node *n)
}
}
}
static int ntypecheckdeftype;
static NodeList *methodqueue;
static void
domethod(Node *n)
{
Node *nt;
nt = n->type->nname;
typecheck(&nt, Etype);
if(nt->type == T) {
// type check failed; leave empty func
n->type->etype = TFUNC;
n->type->nod = N;
return;
}
*n->type = *nt->type;
n->type->nod = N;
checkwidth(n->type);
}
typedef struct NodeTypeList NodeTypeList;
struct NodeTypeList {
Node *n;
Type *t;
NodeTypeList *next;
};
static NodeTypeList *dntq;
static NodeTypeList *dntend;
void
defertypecopy(Node *n, Type *t)
{
NodeTypeList *ntl;
if(n == N || t == T)
return;
ntl = mal(sizeof *ntl);
ntl->n = n;
ntl->t = t;
ntl->next = nil;
if(dntq == nil)
dntq = ntl;
else
dntend->next = ntl;
dntend = ntl;
}
void
resumetypecopy(void)
{
NodeTypeList *l;
for(l=dntq; l; l=l->next)
copytype(l->n, l->t);
}
void
copytype(Node *n, Type *t)
{
*n->type = *t;
t = n->type;
t->sym = n->sym;
t->local = n->local;
t->vargen = n->vargen;
t->siggen = 0;
t->method = nil;
t->nod = N;
t->printed = 0;
t->deferwidth = 0;
}
static void
typecheckdeftype(Node *n)
{
int maplineno, embedlineno, lno;
Type *t;
NodeList *l;
ntypecheckdeftype++;
lno = lineno;
setlineno(n);
n->type->sym = n->sym;
n->typecheck = 1;
typecheck(&n->ntype, Etype);
if((t = n->ntype->type) == T) {
n->diag = 1;
goto ret;
}
if(n->type == T) {
n->diag = 1;
goto ret;
}
maplineno = n->type->maplineno;
embedlineno = n->type->embedlineno;
// copy new type and clear fields
// that don't come along.
// anything zeroed here must be zeroed in
// typedcl2 too.
copytype(n, t);
// double-check use of type as map key.
if(maplineno) {
lineno = maplineno;
maptype(n->type, types[TBOOL]);
}
if(embedlineno) {
lineno = embedlineno;
if(isptr[t->etype])
yyerror("embedded type cannot be a pointer");
}
ret:
lineno = lno;
// if there are no type definitions going on, it's safe to
// try to resolve the method types for the interfaces
// we just read.
if(ntypecheckdeftype == 1) {
while((l = methodqueue) != nil) {
methodqueue = nil;
for(; l; l=l->next)
domethod(l->n);
}
}
ntypecheckdeftype--;
}
void
queuemethod(Node *n)
{
if(ntypecheckdeftype == 0) {
domethod(n);
return;
}
methodqueue = list(methodqueue, n);
}
Node*
typecheckdef(Node *n)
{
int lno;
Node *e;
Type *t;
NodeList *l;
lno = lineno;
setlineno(n);
if(n->op == ONONAME) {
if(!n->diag) {
n->diag = 1;
if(n->lineno != 0)
lineno = n->lineno;
yyerror("undefined: %S", n->sym);
}
return n;
}
if(n->walkdef == 1)
return n;
l = mal(sizeof *l);
l->n = n;
l->next = typecheckdefstack;
typecheckdefstack = l;
if(n->walkdef == 2) {
flusherrors();
print("typecheckdef loop:");
for(l=typecheckdefstack; l; l=l->next)
print(" %S", l->n->sym);
print("\n");
fatal("typecheckdef loop");
}
n->walkdef = 2;
if(n->type != T || n->sym == S) // builtin or no name
goto ret;
switch(n->op) {
default:
fatal("typecheckdef %O", n->op);
case OLITERAL:
if(n->ntype != N) {
typecheck(&n->ntype, Etype);
n->type = n->ntype->type;
n->ntype = N;
if(n->type == T) {
n->diag = 1;
goto ret;
}
}
e = n->defn;
n->defn = N;
if(e == N) {
lineno = n->lineno;
dump("typecheckdef nil defn", n);
yyerror("xxx");
}
typecheck(&e, Erv | Eiota);
if(e->type != T && e->op != OLITERAL) {
yyerror("const initializer must be constant");
goto ret;
}
if(isconst(e, CTNIL)) {
yyerror("const initializer cannot be nil");
goto ret;
}
t = n->type;
if(t != T) {
if(!okforconst[t->etype]) {
yyerror("invalid constant type %T", t);
goto ret;
}
if(!isideal(e->type) && !eqtype(t, e->type)) {
yyerror("cannot use %+N as type %T in const initializer", e, t);
goto ret;
}
convlit(&e, t);
}
n->val = e->val;
n->type = e->type;
break;
case ONAME:
if(n->ntype != N) {
typecheck(&n->ntype, Etype);
n->type = n->ntype->type;
if(n->type == T) {
n->diag = 1;
goto ret;
}
}
if(n->type != T)
break;
if(n->defn == N) {
if(n->etype != 0) // like OPRINTN
break;
if(nerrors > 0) {
// Can have undefined variables in x := foo
// that make x have an n->ndefn == nil.
// If there are other errors anyway, don't
// bother adding to the noise.
break;
}
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
break;
case OTYPE:
if(curfn)
defercheckwidth();
n->walkdef = 1;
n->type = typ(TFORW);
n->type->sym = n->sym;
typecheckdeftype(n);
if(curfn)
resumecheckwidth();
break;
case OPACK:
// nothing to see here
break;
}
ret:
if(typecheckdefstack->n != n)
fatal("typecheckdefstack mismatch");
l = typecheckdefstack;
typecheckdefstack = l->next;
lineno = lno;
n->walkdef = 1;
return n;
}
......@@ -21,8 +21,6 @@ static Node* addstr(Node*, NodeList**);
static Node* appendslice(Node*, NodeList**);
static Node* append(Node*, NodeList**);
static NodeList* walkdefstack;
// can this code branch reach the end
// without an unconditional RETURN
// this is hard, so it is conservative
......@@ -100,296 +98,6 @@ walk(Node *fn)
}
}
static int nwalkdeftype;
static NodeList *methodqueue;
static void
domethod(Node *n)
{
Node *nt;
nt = n->type->nname;
typecheck(&nt, Etype);
if(nt->type == T) {
// type check failed; leave empty func
n->type->etype = TFUNC;
n->type->nod = N;
return;
}
*n->type = *nt->type;
n->type->nod = N;
checkwidth(n->type);
}
typedef struct NodeTypeList NodeTypeList;
struct NodeTypeList {
Node *n;
Type *t;
NodeTypeList *next;
};
static NodeTypeList *dntq;
static NodeTypeList *dntend;
void
defertypecopy(Node *n, Type *t)
{
NodeTypeList *ntl;
if(n == N || t == T)
return;
ntl = mal(sizeof *ntl);
ntl->n = n;
ntl->t = t;
ntl->next = nil;
if(dntq == nil)
dntq = ntl;
else
dntend->next = ntl;
dntend = ntl;
}
void
resumetypecopy(void)
{
NodeTypeList *l;
for(l=dntq; l; l=l->next)
copytype(l->n, l->t);
}
void
copytype(Node *n, Type *t)
{
*n->type = *t;
t = n->type;
t->sym = n->sym;
t->local = n->local;
t->vargen = n->vargen;
t->siggen = 0;
t->method = nil;
t->nod = N;
t->printed = 0;
t->deferwidth = 0;
}
static void
walkdeftype(Node *n)
{
int maplineno, embedlineno, lno;
Type *t;
NodeList *l;
nwalkdeftype++;
lno = lineno;
setlineno(n);
n->type->sym = n->sym;
n->typecheck = 1;
typecheck(&n->ntype, Etype);
if((t = n->ntype->type) == T) {
n->diag = 1;
goto ret;
}
if(n->type == T) {
n->diag = 1;
goto ret;
}
maplineno = n->type->maplineno;
embedlineno = n->type->embedlineno;
// copy new type and clear fields
// that don't come along.
// anything zeroed here must be zeroed in
// typedcl2 too.
copytype(n, t);
// double-check use of type as map key.
if(maplineno) {
lineno = maplineno;
maptype(n->type, types[TBOOL]);
}
if(embedlineno) {
lineno = embedlineno;
if(isptr[t->etype])
yyerror("embedded type cannot be a pointer");
}
ret:
lineno = lno;
// if there are no type definitions going on, it's safe to
// try to resolve the method types for the interfaces
// we just read.
if(nwalkdeftype == 1) {
while((l = methodqueue) != nil) {
methodqueue = nil;
for(; l; l=l->next)
domethod(l->n);
}
}
nwalkdeftype--;
}
void
queuemethod(Node *n)
{
if(nwalkdeftype == 0) {
domethod(n);
return;
}
methodqueue = list(methodqueue, n);
}
Node*
walkdef(Node *n)
{
int lno;
Node *e;
Type *t;
NodeList *l;
lno = lineno;
setlineno(n);
if(n->op == ONONAME) {
if(!n->diag) {
n->diag = 1;
if(n->lineno != 0)
lineno = n->lineno;
yyerror("undefined: %S", n->sym);
}
return n;
}
if(n->walkdef == 1)
return n;
l = mal(sizeof *l);
l->n = n;
l->next = walkdefstack;
walkdefstack = l;
if(n->walkdef == 2) {
flusherrors();
print("walkdef loop:");
for(l=walkdefstack; l; l=l->next)
print(" %S", l->n->sym);
print("\n");
fatal("walkdef loop");
}
n->walkdef = 2;
if(n->type != T || n->sym == S) // builtin or no name
goto ret;
switch(n->op) {
default:
fatal("walkdef %O", n->op);
case OLITERAL:
if(n->ntype != N) {
typecheck(&n->ntype, Etype);
n->type = n->ntype->type;
n->ntype = N;
if(n->type == T) {
n->diag = 1;
goto ret;
}
}
e = n->defn;
n->defn = N;
if(e == N) {
lineno = n->lineno;
dump("walkdef nil defn", n);
yyerror("xxx");
}
typecheck(&e, Erv | Eiota);
if(e->type != T && e->op != OLITERAL) {
yyerror("const initializer must be constant");
goto ret;
}
if(isconst(e, CTNIL)) {
yyerror("const initializer cannot be nil");
goto ret;
}
t = n->type;
if(t != T) {
if(!okforconst[t->etype]) {
yyerror("invalid constant type %T", t);
goto ret;
}
if(!isideal(e->type) && !eqtype(t, e->type)) {
yyerror("cannot use %+N as type %T in const initializer", e, t);
goto ret;
}
convlit(&e, t);
}
n->val = e->val;
n->type = e->type;
break;
case ONAME:
if(n->ntype != N) {
typecheck(&n->ntype, Etype);
n->type = n->ntype->type;
if(n->type == T) {
n->diag = 1;
goto ret;
}
}
if(n->type != T)
break;
if(n->defn == N) {
if(n->etype != 0) // like OPRINTN
break;
if(nerrors > 0) {
// Can have undefined variables in x := foo
// that make x have an n->ndefn == nil.
// If there are other errors anyway, don't
// bother adding to the noise.
break;
}
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
break;
case OTYPE:
if(curfn)
defercheckwidth();
n->walkdef = 1;
n->type = typ(TFORW);
n->type->sym = n->sym;
walkdeftype(n);
if(curfn)
resumecheckwidth();
break;
case OPACK:
// nothing to see here
break;
}
ret:
if(walkdefstack->n != n)
fatal("walkdefstack mismatch");
l = walkdefstack;
walkdefstack = l->next;
lineno = lno;
n->walkdef = 1;
return n;
}
void
walkstmtlist(NodeList *l)
......
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