1
0
mirror of https://github.com/golang/go synced 2024-11-11 20:20:23 -07:00

gc: less aggressive name binding, for better line numbers in errors

Cleans up a few other corner cases too.

R=ken2
CC=golang-dev
https://golang.org/cl/1592045
This commit is contained in:
Russ Cox 2010-06-12 11:17:24 -07:00
parent 53a529ab2b
commit 76da2780c3
9 changed files with 155 additions and 82 deletions

View File

@ -430,24 +430,13 @@ newname(Sym *s)
/* /*
* this generates a new name node for a name * this generates a new name node for a name
* being declared. if at the top level, it might return * being declared.
* an ONONAME node created by an earlier reference.
*/ */
Node* Node*
dclname(Sym *s) dclname(Sym *s)
{ {
Node *n; Node *n;
// top-level name: might already have been
// referred to, in which case s->def is already
// set to an ONONAME.
if(dclcontext == PEXTERN && s->block <= 1) {
if(s->def == N)
oldname(s);
if(s->def->op == ONONAME)
return s->def;
}
n = newname(s); n = newname(s);
n->op = ONONAME; // caller will correct it n->op = ONONAME; // caller will correct it
return n; return n;
@ -484,12 +473,12 @@ oldname(Sym *s)
if(n == N) { if(n == N) {
// maybe a top-level name will come along // maybe a top-level name will come along
// to give this a definition later. // to give this a definition later.
// walkdef will check s->def again once
// all the input source has been processed.
n = newname(s); n = newname(s);
n->op = ONONAME; n->op = ONONAME;
s->def = n; n->iota = iota; // save current iota value in const declarations
} }
if(n->oldref < 100)
n->oldref++;
if(curfn != nil && n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) { if(curfn != nil && n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) {
// inner func is referring to var in outer func. // inner func is referring to var in outer func.
// //
@ -587,11 +576,6 @@ colasdefn(NodeList *left, Node *defn)
if(n->sym->block == block) if(n->sym->block == block)
continue; continue;
// If we created an ONONAME just for this :=,
// delete it, to avoid confusion with top-level imports.
if(n->op == ONONAME && n->oldref < 100 && --n->oldref == 0)
n->sym->def = N;
nnew++; nnew++;
n = newname(n->sym); n = newname(n->sym);
declare(n, dclcontext); declare(n, dclcontext);

View File

@ -120,7 +120,7 @@ dumpexportconst(Sym *s)
switch(n->val.ctype) { switch(n->val.ctype) {
default: default:
fatal("dumpexportconst: unknown ctype: %S", s); fatal("dumpexportconst: unknown ctype: %S %d", s, n->val.ctype);
case CTINT: case CTINT:
Bprint(bout, "%B\n", n->val.u.xval); Bprint(bout, "%B\n", n->val.u.xval);
break; break;

View File

@ -201,7 +201,6 @@ struct Node
uchar etype; // op for OASOP, etype for OTYPE, exclam for export uchar etype; // op for OASOP, etype for OTYPE, exclam for export
uchar class; // PPARAM, PAUTO, PEXTERN, etc uchar class; // PPARAM, PAUTO, PEXTERN, etc
uchar method; // OCALLMETH name uchar method; // OCALLMETH name
uchar iota; // OLITERAL made from iota
uchar embedded; // ODCLFIELD embedded type uchar embedded; // ODCLFIELD embedded type
uchar colas; // OAS resulting from := uchar colas; // OAS resulting from :=
uchar diag; // already printed error about this uchar diag; // already printed error about this
@ -214,7 +213,6 @@ struct Node
uchar initorder; uchar initorder;
uchar dodata; // compile literal assignment as data statement uchar dodata; // compile literal assignment as data statement
uchar used; uchar used;
uchar oldref;
uchar isddd; uchar isddd;
uchar pun; // dont registerize variable ONAME uchar pun; // dont registerize variable ONAME
@ -270,6 +268,7 @@ struct Node
int32 lineno; int32 lineno;
vlong xoffset; vlong xoffset;
int32 ostk; int32 ostk;
int32 iota;
}; };
#define N ((Node*)0) #define N ((Node*)0)
@ -721,7 +720,7 @@ EXTERN int incannedimport;
EXTERN int statuniqgen; // name generator for static temps EXTERN int statuniqgen; // name generator for static temps
EXTERN int loophack; EXTERN int loophack;
EXTERN uint32 iota; EXTERN int32 iota;
EXTERN NodeList* lastconst; EXTERN NodeList* lastconst;
EXTERN Node* lasttype; EXTERN Node* lasttype;
EXTERN int32 maxarg; EXTERN int32 maxarg;
@ -1079,7 +1078,7 @@ void anylit(Node*, Node*, NodeList**);
int oaslit(Node*, NodeList**); int oaslit(Node*, NodeList**);
void heapmoves(void); void heapmoves(void);
void walkdeflist(NodeList*); void walkdeflist(NodeList*);
void walkdef(Node*); Node* walkdef(Node*);
void typechecklist(NodeList*, int); void typechecklist(NodeList*, int);
void typecheckswitch(Node*); void typecheckswitch(Node*);
void typecheckselect(Node*); void typecheckselect(Node*);
@ -1089,6 +1088,7 @@ Node* typecheck(Node**, int);
int islvalue(Node*); int islvalue(Node*);
void queuemethod(Node*); void queuemethod(Node*);
int exportassignok(Type*, char*); int exportassignok(Type*, char*);
Node* resolve(Node*);
/* /*
* const.c * const.c

View File

@ -194,12 +194,7 @@ import_stmt:
} }
if(my->name[0] == '_' && my->name[1] == '\0') if(my->name[0] == '_' && my->name[1] == '\0')
break; break;
if(my->def) {
// Can end up with my->def->op set to ONONAME
// if one package refers to p without importing it.
// Don't want to give an error on a good import
// in another file.
if(my->def && my->def->op != ONONAME) {
lineno = $1; lineno = $1;
redeclare(my, "as imported package name"); redeclare(my, "as imported package name");
} }
@ -307,27 +302,28 @@ common_dcl:
{ {
$$ = nil; $$ = nil;
} }
| LCONST constdcl | lconst constdcl
{ {
$$ = $2; $$ = $2;
iota = 0; iota = -100000;
lastconst = nil; lastconst = nil;
} }
| LCONST '(' constdcl osemi ')' | lconst '(' constdcl osemi ')'
{ {
$$ = $3; $$ = $3;
iota = 0; iota = -100000;
lastconst = nil; lastconst = nil;
} }
| LCONST '(' constdcl ';' constdcl_list osemi ')' | lconst '(' constdcl ';' constdcl_list osemi ')'
{ {
$$ = concat($3, $5); $$ = concat($3, $5);
iota = 0; iota = -100000;
lastconst = nil; lastconst = nil;
} }
| LCONST '(' ')' | lconst '(' ')'
{ {
$$ = nil; $$ = nil;
iota = -100000;
} }
| LTYPE typedcl | LTYPE typedcl
{ {
@ -342,6 +338,12 @@ common_dcl:
$$ = nil; $$ = nil;
} }
lconst:
LCONST
{
iota = 0;
}
vardcl: vardcl:
dcl_name_list ntype dcl_name_list ntype
{ {

View File

@ -1444,11 +1444,6 @@ lexinit(void)
} }
} }
s = lookup("iota");
s->def = nod(ONONAME, N, N);
s->def->iota = 1;
s->def->sym = s;
// logically, the type of a string literal. // logically, the type of a string literal.
// types[TSTRING] is the named type string // types[TSTRING] is the named type string
// (the type of x in var x string or var x = "hello"). // (the type of x in var x string or var x = "hello").
@ -1491,13 +1486,12 @@ lexfini(void)
s->lexical = lex; s->lexical = lex;
etype = syms[i].etype; etype = syms[i].etype;
if(etype != Txxx && (etype != TANY || debug['A'])) if(etype != Txxx && (etype != TANY || debug['A']) && s->def == N)
if(s->def != N && s->def->op == ONONAME) s->def = typenod(types[etype]);
*s->def = *typenod(types[etype]);
etype = syms[i].op; etype = syms[i].op;
if(etype != OXXX && s->def != N && s->def->op == ONONAME) { if(etype != OXXX && s->def == N) {
s->def->op = ONAME; s->def = nod(ONAME, N, N);
s->def->sym = s; s->def->sym = s;
s->def->etype = etype; s->def->etype = etype;
s->def->builtin = 1; s->def->builtin = 1;
@ -1506,29 +1500,35 @@ lexfini(void)
for(i=0; typedefs[i].name; i++) { for(i=0; typedefs[i].name; i++) {
s = lookup(typedefs[i].name); s = lookup(typedefs[i].name);
if(s->def != N && s->def->op == ONONAME) if(s->def == N)
*s->def = *typenod(types[typedefs[i].etype]); s->def = typenod(types[typedefs[i].etype]);
} }
// there's only so much table-driven we can handle. // there's only so much table-driven we can handle.
// these are special cases. // these are special cases.
types[TNIL] = typ(TNIL); types[TNIL] = typ(TNIL);
s = lookup("nil"); s = lookup("nil");
if(s->def != N && s->def->op == ONONAME) { if(s->def == N) {
v.ctype = CTNIL; v.ctype = CTNIL;
*s->def = *nodlit(v); s->def = nodlit(v);
s->def->sym = s;
}
s = lookup("iota");
if(s->def == N) {
s->def = nod(OIOTA, N, N);
s->def->sym = s; s->def->sym = s;
} }
s = lookup("true"); s = lookup("true");
if(s->def != N && s->def->op == ONONAME) { if(s->def == N) {
*s->def = *nodbool(1); s->def = nodbool(1);
s->def->sym = s; s->def->sym = s;
} }
s = lookup("false"); s = lookup("false");
if(s->def != N && s->def->op == ONONAME) { if(s->def == N) {
*s->def = *nodbool(0); s->def = nodbool(0);
s->def->sym = s; s->def->sym = s;
} }

View File

@ -1529,13 +1529,19 @@ treecopy(Node *n)
break; break;
case ONONAME: case ONONAME:
if(n->iota) { if(n->sym == lookup("iota")) {
m = nod(OIOTA, n, nodintconst(iota)); // Not sure yet whether this is the real iota,
// but make a copy of the Node* just in case,
// so that all the copies of this const definition
// don't have the same iota value.
m = nod(OXXX, N, N);
*m = *n;
m->iota = iota;
break; break;
} }
// fall through // fall through
case OLITERAL:
case ONAME: case ONAME:
case OLITERAL:
case OTYPE: case OTYPE:
m = n; m = n;
break; break;

View File

@ -33,6 +33,23 @@ static void checkassign(Node*);
static void checkassignlist(NodeList*); static void checkassignlist(NodeList*);
static void stringtoarraylit(Node**); static void stringtoarraylit(Node**);
/*
* resolve ONONAME to definition, if any.
*/
Node*
resolve(Node *n)
{
Node *r;
if(n != N && n->op == ONONAME && (r = n->sym->def) != N) {
if(r->op != OIOTA)
n = r;
else if(n->iota >= 0)
n = nodintconst(n->iota);
}
return n;
}
void void
typechecklist(NodeList *l, int top) typechecklist(NodeList *l, int top)
{ {
@ -64,6 +81,10 @@ typecheck(Node **np, int top)
n = *np; n = *np;
if(n == N) if(n == N)
return N; return N;
// Resolve definition of name and value of iota lazily.
n = resolve(n);
*np = n;
// Skip typecheck if already done. // Skip typecheck if already done.
// But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed. // But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
@ -85,10 +106,9 @@ typecheck(Node **np, int top)
} }
n->typecheck = 2; n->typecheck = 2;
redo:
lno = setlineno(n); lno = setlineno(n);
if(n->sym) { if(n->sym) {
if(n->op == ONAME && n->etype != 0) { if(n->op == ONAME && n->etype != 0 && !(top & Ecall)) {
yyerror("use of builtin %S not in function call", n->sym); yyerror("use of builtin %S not in function call", n->sym);
goto error; goto error;
} }
@ -96,6 +116,7 @@ redo:
if(n->op == ONONAME) if(n->op == ONONAME)
goto error; goto error;
} }
*np = n;
reswitch: reswitch:
ok = 0; ok = 0;
@ -138,15 +159,6 @@ reswitch:
yyerror("use of package %S not in selector", n->sym); yyerror("use of package %S not in selector", n->sym);
goto error; goto error;
case OIOTA:
// looked like iota during parsing but might
// have been redefined. decide.
if(n->left->op != ONONAME)
n = n->left;
else
n = n->right;
goto redo;
case ODDD: case ODDD:
break; break;
@ -679,6 +691,12 @@ reswitch:
* call and call like * call and call like
*/ */
case OCALL: case OCALL:
l = n->left;
if(l->op == ONAME && (r = unsafenmagic(l, n->list)) != N) {
n = r;
goto reswitch;
}
typecheck(&n->left, Erv | Etype | Ecall);
l = n->left; l = n->left;
if(l->op == ONAME && l->etype != 0) { if(l->op == ONAME && l->etype != 0) {
// builtin: OLEN, OCAP, etc. // builtin: OLEN, OCAP, etc.
@ -687,11 +705,6 @@ 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);
defaultlit(&n->left, T); defaultlit(&n->left, T);
l = n->left; l = n->left;
if(l->op == OTYPE) { if(l->op == OTYPE) {
@ -895,7 +908,7 @@ reswitch:
case OCONV: case OCONV:
doconv: doconv:
ok |= Erv; ok |= Erv;
typecheck(&n->left, Erv | (top & Eindir)); typecheck(&n->left, Erv | (top & (Eindir | Eiota)));
convlit1(&n->left, n->type, 1); convlit1(&n->left, n->type, 1);
if((t = n->left->type) == T || n->type == T) if((t = n->left->type) == T || n->type == T)
goto error; goto error;
@ -1929,6 +1942,7 @@ typecheckas(Node *n)
// if the variable has a type (ntype) then typechecking // if the variable has a type (ntype) then typechecking
// will not look at defn, so it is okay (and desirable, // will not look at defn, so it is okay (and desirable,
// so that the conversion below happens). // so that the conversion below happens).
n->left = resolve(n->left);
if(n->left->defn != n || n->left->ntype) if(n->left->defn != n || n->left->ntype)
typecheck(&n->left, Erv | Easgn); typecheck(&n->left, Erv | Easgn);
@ -1976,6 +1990,7 @@ typecheckas2(Node *n)
for(ll=n->list; ll; ll=ll->next) { for(ll=n->list; ll; ll=ll->next) {
// delicate little dance. // delicate little dance.
ll->n = resolve(ll->n);
if(ll->n->defn != n || ll->n->ntype) if(ll->n->defn != n || ll->n->ntype)
typecheck(&ll->n, Erv | Easgn); typecheck(&ll->n, Erv | Easgn);
} }

View File

@ -9,6 +9,8 @@ static Node* conv(Node*, Type*);
static Node* mapfn(char*, Type*); static Node* mapfn(char*, Type*);
static Node* makenewvar(Type*, NodeList**, Node**); static Node* makenewvar(Type*, NodeList**, Node**);
static NodeList* walkdefstack;
// can this code branch reach the end // can this code branch reach the end
// without an undcontitional RETURN // without an undcontitional RETURN
// this is hard, so it is conservative // this is hard, so it is conservative
@ -186,13 +188,14 @@ queuemethod(Node *n)
methodqueue = list(methodqueue, n); methodqueue = list(methodqueue, n);
} }
void Node*
walkdef(Node *n) walkdef(Node *n)
{ {
int lno; int lno;
NodeList *init; NodeList *init;
Node *e; Node *e;
Type *t; Type *t;
NodeList *l;
lno = lineno; lno = lineno;
setlineno(n); setlineno(n);
@ -204,14 +207,24 @@ walkdef(Node *n)
lineno = n->lineno; lineno = n->lineno;
yyerror("undefined: %S", n->sym); yyerror("undefined: %S", n->sym);
} }
return; return n;
} }
if(n->walkdef == 1) if(n->walkdef == 1)
return; return n;
l = mal(sizeof *l);
l->n = n;
l->next = walkdefstack;
walkdefstack = l;
if(n->walkdef == 2) { if(n->walkdef == 2) {
// TODO(rsc): better loop message flusherrors();
fatal("loop"); print("walkdef loop:");
for(l=walkdefstack; l; l=l->next)
print(" %S", l->n->sym);
print("\n");
fatal("walkdef loop");
} }
n->walkdef = 2; n->walkdef = 2;
@ -266,8 +279,11 @@ walkdef(Node *n)
} }
if(n->type != T) if(n->type != T)
break; break;
if(n->defn == N) if(n->defn == N) {
if(n->etype != 0) // like OPRINTN
break;
fatal("var without type, init: %S", n->sym); fatal("var without type, init: %S", n->sym);
}
if(n->defn->op == ONAME) { if(n->defn->op == ONAME) {
typecheck(&n->defn, Erv); typecheck(&n->defn, Erv);
n->type = n->defn->type; n->type = n->defn->type;
@ -289,8 +305,14 @@ walkdef(Node *n)
} }
ret: ret:
if(walkdefstack->n != n)
fatal("walkdefstack mismatch");
l = walkdefstack;
walkdefstack = l->next;
lineno = lno; lineno = lno;
n->walkdef = 1; n->walkdef = 1;
return n;
} }
void void

44
test/undef.go Normal file
View File

@ -0,0 +1,44 @@
// errchk $G -e $D/$F.go
// Copyright 2010 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.
// Check line numbers in error messages.
package main
var (
_ = x // ERROR "undefined: x"
_ = x // ERROR "undefined: x"
_ = x // ERROR "undefined: x"
)
type T struct {
y int
}
func foo() *T { return &T{y: 99} }
func bar() int { return y } // ERROR "undefined: y"
type T1 struct {
y1 int
}
func foo1() *T1 { return &T1{y1: 99} }
var y1 = 2
func bar1() int { return y1 }
func f1(val interface{}) {
switch v := val.(type) {
default:
println(v)
}
}
func f2(val interface{}) {
switch val.(type) {
default:
println(v) // ERROR "undefined: v"
}
}