1
0
mirror of https://github.com/golang/go synced 2024-11-25 11:57:58 -07:00

better handling of mistaken top-level variable

references during the parsing of :=.  the base
problem is that when reading

	a,b,c,d

the parser makes those refer to existing variables,
which might create a few stub top-level ones
for undefined names, but then if a := is the next
token, we need to undo those stubs.

this was causing problems in multifile packages
in which one file used a := variable named rpc
and the other imported a package named rpc.

R=ken
OCL=35446
CL=35446
This commit is contained in:
Russ Cox 2009-10-07 14:55:12 -07:00
parent 4fd7a908bb
commit d515063588
5 changed files with 27 additions and 35 deletions

View File

@ -463,9 +463,15 @@ oldname(Sym *s)
n->op = ONONAME; n->op = ONONAME;
s->def = n; s->def = n;
} }
if(n->oldref < 100)
n->oldref++;
if(n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) { if(n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) {
// inner func is referring to var // inner func is referring to var in outer func.
// in outer func. //
// TODO(rsc): If there is an outer variable x and we
// are parsing x := 5 inside the closure, until we get to
// the := it looks like a reference to the outer x so we'll
// make x a closure variable unnecessarily.
if(n->closure == N || n->closure->funcdepth != funcdepth) { if(n->closure == N || n->closure->funcdepth != funcdepth) {
// create new closure var. // create new closure var.
c = nod(ONAME, N, N); c = nod(ONAME, N, N);
@ -554,6 +560,12 @@ 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

@ -202,6 +202,7 @@ 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;
// most nodes // most nodes
Node* left; Node* left;
@ -247,7 +248,6 @@ struct Node
Node* outer; // outer PPARAMREF in nested closure Node* outer; // outer PPARAMREF in nested closure
Node* closure; // ONAME/PHEAP <-> ONAME/PPARAMREF Node* closure; // ONAME/PHEAP <-> ONAME/PPARAMREF
char* pline;
Sym* sym; // various Sym* sym; // various
int32 vargen; // unique name for OTYPE/ONAME int32 vargen; // unique name for OTYPE/ONAME
int32 lineno; int32 lineno;
@ -696,8 +696,6 @@ EXTERN int noargnames;
EXTERN int funcdepth; EXTERN int funcdepth;
EXTERN int typecheckok; EXTERN int typecheckok;
EXTERN char* importline;
/* /*
* y.tab.c * y.tab.c
*/ */

View File

@ -178,7 +178,6 @@ import_stmt:
pack = nod(OPACK, N, N); pack = nod(OPACK, N, N);
pack->sym = import; pack->sym = import;
pack->lineno = $1; pack->lineno = $1;
pack->pline = importline;
if(my == S) if(my == S)
my = import; my = import;
@ -189,15 +188,10 @@ import_stmt:
if(my->name[0] == '_' && my->name[1] == '\0') if(my->name[0] == '_' && my->name[1] == '\0')
break; break;
// TODO(rsc): this line is needed for a package if(my->def) {
// which does bytes := in a function, which creates lineno = $1;
// an ONONAME for bytes, but then a different file redeclare(my, "as imported package name");
// imports "bytes". more generally we need to figure out }
// what it means if one file imports "bytes" and another
// declares a top-level name.
if(my->def && my->def->op == ONONAME)
my->def = N;
my->def = pack; my->def = pack;
my->lastlineno = $1; my->lastlineno = $1;
import->block = 1; // at top level import->block = 1; // at top level
@ -223,8 +217,6 @@ import_here:
$$ = parserline(); $$ = parserline();
pkgimportname = S; pkgimportname = S;
pkgmyname = $1; pkgmyname = $1;
if($1->def && ($1->name[0] != '_' || $1->name[1] != '\0'))
redeclare($1, "as imported package name");
importfile(&$2, $$); importfile(&$2, $$);
} }
| '.' LLITERAL | '.' LLITERAL

View File

@ -267,13 +267,7 @@ importfile(Val *f, int line)
int32 c; int32 c;
int len; int len;
// Once we push the new file, we will not be able // TODO(rsc): don't bother reloading imports more than once
// to print the current lineno correctly with %L.
// In case that line is the line of the import (likely),
// save the text for use in error messages.
importline = smprint("%L", line);
// TODO: don't bother reloading imports more than once
if(f->ctype != CTSTR) { if(f->ctype != CTSTR) {
yyerror("import statement not a string"); yyerror("import statement not a string");
@ -300,12 +294,10 @@ importfile(Val *f, int line)
// assume .a files move (get installed) // assume .a files move (get installed)
// so don't record the full path. // so don't record the full path.
p = file + len - f->u.sval->len - 2; p = file + len - f->u.sval->len - 2;
linehist(p, 0, 0);
linehist(p, -1, 1); // acts as #pragma lib linehist(p, -1, 1); // acts as #pragma lib
} else { } else {
// assume .6 files don't move around // assume .6 files don't move around
// so do record the full path // so do record the full path
linehist(file, 0, 0);
linehist(file, -1, 0); linehist(file, -1, 0);
} }
@ -339,8 +331,6 @@ importfile(Val *f, int line)
void void
unimportfile(void) unimportfile(void)
{ {
linehist(nil, 0, 0);
if(curio.bin != nil) { if(curio.bin != nil) {
Bterm(curio.bin); Bterm(curio.bin);
curio.bin = nil; curio.bin = nil;
@ -357,7 +347,6 @@ void
cannedimports(char *file, char *cp) cannedimports(char *file, char *cp)
{ {
lexlineno++; // if sys.6 is included on line 1, lexlineno++; // if sys.6 is included on line 1,
linehist(file, 0, 0); // the debugger gets confused
pushedio = curio; pushedio = curio;
curio.bin = nil; curio.bin = nil;
@ -1018,7 +1007,7 @@ getc(void)
if(c != 0) { if(c != 0) {
curio.peekc = curio.peekc1; curio.peekc = curio.peekc1;
curio.peekc1 = 0; curio.peekc1 = 0;
if(c == '\n') if(c == '\n' && pushedio.bin == nil)
lexlineno++; lexlineno++;
return c; return c;
} }
@ -1038,7 +1027,8 @@ getc(void)
return EOF; return EOF;
case '\n': case '\n':
lexlineno++; if(pushedio.bin == nil)
lexlineno++;
break; break;
} }
return c; return c;
@ -1049,7 +1039,7 @@ ungetc(int c)
{ {
curio.peekc1 = curio.peekc; curio.peekc1 = curio.peekc;
curio.peekc = c; curio.peekc = c;
if(c == '\n') if(c == '\n' && pushedio.bin == nil)
lexlineno--; lexlineno--;
} }
@ -1487,7 +1477,7 @@ mkpackage(char* pkg)
// name, so that the name cannot be redeclared // name, so that the name cannot be redeclared
// as a non-package in other files. // as a non-package in other files.
if(!s->def->used) { if(!s->def->used) {
print("%s: imported and not used: %s\n", s->def->pline, s->def->sym->name); print("%L: imported and not used: %s\n", s->def->lineno, s->def->sym->name);
nerrors++; nerrors++;
} }
s->def = N; s->def = N;
@ -1497,7 +1487,7 @@ mkpackage(char* pkg)
// throw away top-level name left over // throw away top-level name left over
// from previous import . "x" // from previous import . "x"
if(s->def->pack != N && !s->def->pack->used) { if(s->def->pack != N && !s->def->pack->used) {
print("%s: imported and not used: %s\n", s->def->pack->pline, s->def->pack->sym->name); print("%L: imported and not used: %s\n", s->def->pack->lineno, s->def->pack->sym->name);
nerrors++; nerrors++;
s->def->pack->used = 1; s->def->pack->used = 1;
} }

View File

@ -269,7 +269,7 @@ importdot(Sym *opkg, Node *pack)
} }
if(n == 0) { if(n == 0) {
// can't possibly be used - there were no symbols // can't possibly be used - there were no symbols
print("%L: imported and not used: %s\n", pack->pline, pack->sym->name); print("%L: imported and not used: %s\n", pack->lineno, pack->sym->name);
nerrors++; nerrors++;
} }
} }