mirror of
https://github.com/golang/go
synced 2024-11-21 18:34:44 -07:00
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
This commit is contained in:
parent
f4f5836840
commit
ab8ed7f8dd
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user