1
0
mirror of https://github.com/golang/go synced 2024-11-21 22:34:48 -07:00

gc: changes in export format in preparation of inlining.

Includes minimal change to gcimporter to keep it working,

R=rsc, gri
CC=golang-dev
https://golang.org/cl/5431046
This commit is contained in:
Luuk van Dijk 2011-12-05 14:40:19 -05:00 committed by Russ Cox
parent 5cb1c82d96
commit 40b2fe004f
10 changed files with 405 additions and 276 deletions

View File

@ -8,6 +8,7 @@
#include "y.tab.h" #include "y.tab.h"
static void funcargs(Node*); static void funcargs(Node*);
static void funcargs2(Type*);
static int static int
dflag(void) dflag(void)
@ -547,13 +548,6 @@ ifacedcl(Node *n)
void void
funchdr(Node *n) funchdr(Node *n)
{ {
if(n->nname != N) {
n->nname->op = ONAME;
declare(n->nname, PFUNC);
n->nname->defn = n;
}
// change the declaration context from extern to auto // change the declaration context from extern to auto
if(funcdepth == 0 && dclcontext != PEXTERN) if(funcdepth == 0 && dclcontext != PEXTERN)
fatal("funchdr: dclcontext"); fatal("funchdr: dclcontext");
@ -564,10 +558,13 @@ funchdr(Node *n)
n->outer = curfn; n->outer = curfn;
curfn = n; curfn = n;
if(n->nname) if(n->nname)
funcargs(n->nname->ntype); funcargs(n->nname->ntype);
else else if (n->ntype)
funcargs(n->ntype); funcargs(n->ntype);
else
funcargs2(n->type);
} }
static void static void
@ -582,11 +579,11 @@ funcargs(Node *nt)
// declare the receiver and in arguments. // declare the receiver and in arguments.
// no n->defn because type checking of func header // no n->defn because type checking of func header
// will fill in the types before we can demand them. // will not fill in the types until later
if(nt->left != N) { if(nt->left != N) {
n = nt->left; n = nt->left;
if(n->op != ODCLFIELD) if(n->op != ODCLFIELD)
fatal("funcargs1 %O", n->op); fatal("funcargs receiver %O", n->op);
if(n->left != N) { if(n->left != N) {
n->left->op = ONAME; n->left->op = ONAME;
n->left->ntype = n->right; n->left->ntype = n->right;
@ -596,7 +593,7 @@ funcargs(Node *nt)
for(l=nt->list; l; l=l->next) { for(l=nt->list; l; l=l->next) {
n = l->n; n = l->n;
if(n->op != ODCLFIELD) if(n->op != ODCLFIELD)
fatal("funcargs2 %O", n->op); fatal("funcargs in %O", n->op);
if(n->left != N) { if(n->left != N) {
n->left->op = ONAME; n->left->op = ONAME;
n->left->ntype = n->right; n->left->ntype = n->right;
@ -609,7 +606,7 @@ funcargs(Node *nt)
for(l=nt->rlist; l; l=l->next) { for(l=nt->rlist; l; l=l->next) {
n = l->n; n = l->n;
if(n->op != ODCLFIELD) if(n->op != ODCLFIELD)
fatal("funcargs3 %O", n->op); fatal("funcargs out %O", n->op);
if(n->left != N) { if(n->left != N) {
n->left->op = ONAME; n->left->op = ONAME;
n->left->ntype = n->right; n->left->ntype = n->right;
@ -627,6 +624,48 @@ funcargs(Node *nt)
} }
} }
/*
* Same as funcargs, except run over an already constructed TFUNC.
* This happens during import, where the hidden_fndcl rule has
* used functype directly to parse the function's type.
*/
static void
funcargs2(Type *t)
{
Type *ft;
Node *n;
if(t->etype != TFUNC)
fatal("funcargs2 %T", t);
if(t->thistuple)
for(ft=getthisx(t)->type; ft; ft=ft->down) {
if(!ft->nname || !ft->nname->sym)
continue;
n = newname(ft->nname->sym);
n->type = ft->type;
declare(n, PPARAM);
}
if(t->intuple)
for(ft=getinargx(t)->type; ft; ft=ft->down) {
if(!ft->nname || !ft->nname->sym)
continue;
n = newname(ft->nname->sym);
n->type = ft->type;
declare(n, PPARAM);
}
if(t->outtuple)
for(ft=getoutargx(t)->type; ft; ft=ft->down) {
if(!ft->nname || !ft->nname->sym)
continue;
n = newname(ft->nname->sym);
n->type = ft->type;
declare(n, PPARAMOUT);
}
}
/* /*
* finish the body. * finish the body.
* called in auto-declaration context. * called in auto-declaration context.
@ -654,7 +693,7 @@ typedcl0(Sym *s)
{ {
Node *n; Node *n;
n = dclname(s); n = newname(s);
n->op = OTYPE; n->op = OTYPE;
declare(n, dclcontext); declare(n, dclcontext);
return n; return n;
@ -740,8 +779,6 @@ structfield(Node *n)
f->nname = n->left; f->nname = n->left;
f->embedded = n->embedded; f->embedded = n->embedded;
f->sym = f->nname->sym; f->sym = f->nname->sym;
if(importpkg && !exportname(f->sym->name))
f->sym = pkglookup(f->sym->name, structpkg);
} }
lineno = lno; lineno = lno;
@ -778,8 +815,12 @@ tostruct(NodeList *l)
Type *t, *f, **tp; Type *t, *f, **tp;
t = typ(TSTRUCT); t = typ(TSTRUCT);
for(tp = &t->type; l; l=l->next,tp = &(*tp)->down) for(tp = &t->type; l; l=l->next) {
*tp = structfield(l->n); f = structfield(l->n);
*tp = f;
tp = &f->down;
}
for(f=t->type; f && !t->broke; f=f->down) for(f=t->type; f && !t->broke; f=f->down)
if(f->broke) if(f->broke)
@ -803,7 +844,7 @@ tofunargs(NodeList *l)
for(tp = &t->type; l; l=l->next) { for(tp = &t->type; l; l=l->next) {
f = structfield(l->n); f = structfield(l->n);
f->funarg = 1;
// esc.c needs to find f given a PPARAM to add the tag. // esc.c needs to find f given a PPARAM to add the tag.
if(l->n->left && l->n->left->class == PPARAM) if(l->n->left && l->n->left->class == PPARAM)
l->n->left->paramfld = f; l->n->left->paramfld = f;
@ -944,7 +985,10 @@ embedded(Sym *s)
*utfrune(name, CenterDot) = 0; *utfrune(name, CenterDot) = 0;
} }
n = newname(lookup(name)); if(exportname(name) || s->pkg == builtinpkg) // old behaviour, tests pass, but is it correct?
n = newname(lookup(name));
else
n = newname(pkglookup(name, s->pkg));
n = nod(ODCLFIELD, n, oldname(s)); n = nod(ODCLFIELD, n, oldname(s));
n->embedded = 1; n->embedded = 1;
return n; return n;
@ -1009,6 +1053,17 @@ checkarglist(NodeList *all, int input)
t = n; t = n;
n = N; n = N;
} }
// during import l->n->op is OKEY, but l->n->left->sym == S
// means it was a '?', not that it was
// a lone type This doesn't matter for the exported
// declarations, which are parsed by rules that don't
// use checkargs, but can happen for func literals in
// the inline bodies.
// TODO(rsc) this can go when typefmt case TFIELD in exportmode fmt.c prints _ instead of ?
if(importpkg && n->sym == S)
n = N;
if(n != N && n->sym == S) { if(n != N && n->sym == S) {
t = n; t = n;
n = N; n = N;
@ -1137,7 +1192,6 @@ methodsym(Sym *nsym, Type *t0, int iface)
else else
p = smprint("%-hT.%s%s", t0, nsym->name, suffix); p = smprint("%-hT.%s%s", t0, nsym->name, suffix);
s = pkglookup(p, s->pkg); s = pkglookup(p, s->pkg);
//print("methodsym:%s -> %+S\n", p, s);
free(p); free(p);
return s; return s;
@ -1174,7 +1228,11 @@ methodname1(Node *n, Node *t)
p = smprint("(%s%S).%S", star, t->sym, n->sym); p = smprint("(%s%S).%S", star, t->sym, n->sym);
else else
p = smprint("%S.%S", t->sym, n->sym); p = smprint("%S.%S", t->sym, n->sym);
n = newname(pkglookup(p, t->sym->pkg));
if(exportname(t->sym->name))
n = newname(lookup(p));
else
n = newname(pkglookup(p, t->sym->pkg));
free(p); free(p);
return n; return n;
} }
@ -1234,8 +1292,6 @@ addmethod(Sym *sf, Type *t, int local)
} }
pa = f; pa = f;
if(importpkg && !exportname(sf->name))
sf = pkglookup(sf->name, importpkg);
n = nod(ODCLFIELD, newname(sf), N); n = nod(ODCLFIELD, newname(sf), N);
n->type = t; n->type = t;
@ -1258,10 +1314,16 @@ addmethod(Sym *sf, Type *t, int local)
return; return;
} }
f = structfield(n);
// during import unexported method names should be in the type's package
if(importpkg && f->sym && !exportname(f->sym->name) && f->sym->pkg != structpkg)
fatal("imported method name %+S in wrong package %s\n", f->sym, structpkg->name);
if(d == T) if(d == T)
pa->method = structfield(n); pa->method = f;
else else
d->down = structfield(n); d->down = f;
return; return;
} }

View File

@ -7,11 +7,9 @@
#include "go.h" #include "go.h"
#include "y.tab.h" #include "y.tab.h"
static void dumpsym(Sym*); static void dumpexporttype(Type*);
static void dumpexporttype(Type*);
static void dumpexportvar(Sym*);
static void dumpexportconst(Sym*);
// Mark n's symbol as exported
void void
exportsym(Node *n) exportsym(Node *n)
{ {
@ -27,6 +25,7 @@ exportsym(Node *n)
exportlist = list(exportlist, n); exportlist = list(exportlist, n);
} }
// Mark n's symbol as package-local
static void static void
packagesym(Node *n) packagesym(Node *n)
{ {
@ -178,7 +177,7 @@ dumpexporttype(Type *t)
Bprint(bout, "\ttype %#S %#lT\n", t->sym, t); Bprint(bout, "\ttype %#S %#lT\n", t->sym, t);
for(i=0; i<n; i++) { for(i=0; i<n; i++) {
f = m[i]; f = m[i];
Bprint(bout, "\tfunc (%#T) %#hS%#hT\n", getthisx(f->type)->type, f->sym, f->type); Bprint(bout, "\tfunc (%#T) %#hhS%#hT\n", getthisx(f->type)->type, f->sym, f->type);
} }
} }
@ -200,15 +199,18 @@ dumpsym(Sym *s)
default: default:
yyerror("unexpected export symbol: %O %S", s->def->op, s); yyerror("unexpected export symbol: %O %S", s->def->op, s);
break; break;
case OLITERAL: case OLITERAL:
dumpexportconst(s); dumpexportconst(s);
break; break;
case OTYPE: case OTYPE:
if(s->def->type->etype == TFORW) if(s->def->type->etype == TFORW)
yyerror("export of incomplete type %S", s); yyerror("export of incomplete type %S", s);
else else
dumpexporttype(s->def->type); dumpexporttype(s->def->type);
break; break;
case ONAME: case ONAME:
dumpexportvar(s); dumpexportvar(s);
break; break;
@ -286,12 +288,25 @@ pkgtype(Sym *s)
return s->def->type; return s->def->type;
} }
static int void
mypackage(Sym *s) importimport(Sym *s, Strlit *z)
{ {
// we import all definitions for runtime. // Informational: record package name
// lowercase ones can only be used by the compiler. // associated with import path, for use in
return s->pkg == localpkg || s->pkg == runtimepkg; // human-readable messages.
Pkg *p;
p = mkpkg(z);
if(p->name == nil) {
p->name = s->name;
pkglookup(s->name, nil)->npkg++;
} else if(strcmp(p->name, s->name) != 0)
yyerror("conflicting names %s and %s for package \"%Z\"", p->name, s->name, p->path);
if(!incannedimport && myimportpath != nil && strcmp(z->s, myimportpath) == 0) {
yyerror("import \"%Z\": package depends on \"%Z\" (import cycle)", importpkg->path, z);
errorexit();
}
} }
void void
@ -299,19 +314,17 @@ importconst(Sym *s, Type *t, Node *n)
{ {
Node *n1; Node *n1;
if(!exportname(s->name) && !mypackage(s))
return;
importsym(s, OLITERAL); importsym(s, OLITERAL);
convlit(&n, t); convlit(&n, t);
if(s->def != N) {
// TODO: check if already the same. if(s->def != N) // TODO: check if already the same.
return; return;
}
if(n->op != OLITERAL) { if(n->op != OLITERAL) {
yyerror("expression must be a constant"); yyerror("expression must be a constant");
return; return;
} }
if(n->sym != S) { if(n->sym != S) {
n1 = nod(OXXX, N, N); n1 = nod(OXXX, N, N);
*n1 = *n; *n1 = *n;
@ -325,13 +338,10 @@ importconst(Sym *s, Type *t, Node *n)
} }
void void
importvar(Sym *s, Type *t, int ctxt) importvar(Sym *s, Type *t)
{ {
Node *n; Node *n;
if(!exportname(s->name) && !initname(s->name) && !mypackage(s))
return;
importsym(s, ONAME); importsym(s, ONAME);
if(s->def != N && s->def->op == ONAME) { if(s->def != N && s->def->op == ONAME) {
if(eqtype(t, s->def->type)) if(eqtype(t, s->def->type))
@ -340,7 +350,7 @@ importvar(Sym *s, Type *t, int ctxt)
} }
n = newname(s); n = newname(s);
n->type = t; n->type = t;
declare(n, ctxt); declare(n, PEXTERN);
if(debug['E']) if(debug['E'])
print("import var %S %lT\n", s, t); print("import var %S %lT\n", s, t);
@ -351,38 +361,25 @@ importtype(Type *pt, Type *t)
{ {
Node *n; Node *n;
if(pt != T && t != T) { // override declaration in unsafe.go for Pointer.
// override declaration in unsafe.go for Pointer. // there is no way in Go code to define unsafe.Pointer
// there is no way in Go code to define unsafe.Pointer // so we have to supply it.
// so we have to supply it. if(incannedimport &&
if(incannedimport && strcmp(importpkg->name, "unsafe") == 0 &&
strcmp(importpkg->name, "unsafe") == 0 && strcmp(pt->nod->sym->name, "Pointer") == 0) {
strcmp(pt->nod->sym->name, "Pointer") == 0) { t = types[TUNSAFEPTR];
t = types[TUNSAFEPTR];
}
if(pt->etype == TFORW) {
n = pt->nod;
copytype(pt->nod, t);
// unzero nod
pt->nod = n;
pt->sym->lastlineno = parserline();
declare(n, PEXTERN);
checkwidth(pt);
} else if(!eqtype(pt->orig, t))
yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt->orig, t);
} }
if(pt->etype == TFORW) {
n = pt->nod;
copytype(pt->nod, t);
pt->nod = n; // unzero nod
pt->sym->lastlineno = parserline();
declare(n, PEXTERN);
checkwidth(pt);
} else if(!eqtype(pt->orig, t))
yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt->orig, t);
if(debug['E']) if(debug['E'])
print("import type %T %lT\n", pt, t); print("import type %T %lT\n", pt, t);
} }
void
importmethod(Sym *s, Type *t)
{
checkwidth(t);
addmethod(s, t, 0);
}

View File

@ -24,7 +24,7 @@
// %S Sym* Symbols // %S Sym* Symbols
// Flags: +,- #: mode (see below) // Flags: +,- #: mode (see below)
// "%hS" unqualified identifier in any mode // "%hS" unqualified identifier in any mode
// "%hhS" strip type qualifier off of method name // "%hhS" in export mode: unqualified identifier if exported, qualified if not
// //
// %T Type* Types // %T Type* Types
// Flags: +,- #: mode (see below) // Flags: +,- #: mode (see below)
@ -341,6 +341,9 @@ Jconv(Fmt *fp)
if(n->implicit != 0) if(n->implicit != 0)
fmtprint(fp, " implicit(%d)", n->implicit); fmtprint(fp, " implicit(%d)", n->implicit);
if(n->embedded != 0)
fmtprint(fp, " embedded(%d)", n->embedded);
if(!c && n->used != 0) if(!c && n->used != 0)
fmtprint(fp, " used(%d)", n->used); fmtprint(fp, " used(%d)", n->used);
return 0; return 0;
@ -488,7 +491,7 @@ symfmt(Fmt *fp, Sym *s)
if(s->pkg == localpkg) if(s->pkg == localpkg)
return fmtstrcpy(fp, s->name); return fmtstrcpy(fp, s->name);
// If the name was used by multiple packages, display the full path, // If the name was used by multiple packages, display the full path,
if(pkglookup(s->pkg->name, nil)->npkg > 1) if(s->pkg->name && pkglookup(s->pkg->name, nil)->npkg > 1)
return fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name); return fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name);
return fmtprint(fp, "%s.%s", s->pkg->name, s->name); return fmtprint(fp, "%s.%s", s->pkg->name, s->name);
case FDbg: case FDbg:
@ -502,11 +505,19 @@ symfmt(Fmt *fp, Sym *s)
} }
} }
if(fp->flags&FmtByte) { if(fp->flags&FmtByte) { // FmtByte (hh) implies FmtShort (h)
// skip leading "type." in method name // skip leading "type." in method name
p = utfrrune(s->name, '.'); p = utfrrune(s->name, '.');
if(p) if(p)
return fmtstrcpy(fp, p+1); p++;
else
p = s->name;
// exportname needs to see the name without the prefix too.
if((fmtmode == FExp && !exportname(p)) || fmtmode == FDbg)
return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, p);
return fmtstrcpy(fp, p);
} }
return fmtstrcpy(fp, s->name); return fmtstrcpy(fp, s->name);
@ -672,9 +683,9 @@ typefmt(Fmt *fp, Type *t)
fmtstrcpy(fp, "struct {"); fmtstrcpy(fp, "struct {");
for(t1=t->type; t1!=T; t1=t1->down) for(t1=t->type; t1!=T; t1=t1->down)
if(t1->down) if(t1->down)
fmtprint(fp, " %T;", t1); fmtprint(fp, " %lT;", t1);
else else
fmtprint(fp, " %T ", t1); fmtprint(fp, " %lT ", t1);
fmtstrcpy(fp, "}"); fmtstrcpy(fp, "}");
} }
return 0; return 0;
@ -682,21 +693,22 @@ typefmt(Fmt *fp, Type *t)
case TFIELD: case TFIELD:
if(!(fp->flags&FmtShort)) { if(!(fp->flags&FmtShort)) {
s = t->sym; s = t->sym;
switch(fmtmode) { // Take the name from the original, lest we substituted it with .anon%d
case FErr: if (t->nname && (fmtmode == FErr || fmtmode == FExp))
case FExp: s = t->nname->orig->sym;
// Take the name from the original, lest we substituted it with .anon%d
if (t->nname) if(s != S && !t->embedded) {
s = t->nname->orig->sym; if(fp->flags&FmtLong)
fmtprint(fp, "%hhS ", s); // qualify non-exported names (used on structs, not on funarg)
if((s == S || t->embedded)) { else
fmtprint(fp, "%S ", s);
} else if(fmtmode == FExp) {
// TODO(rsc) this breaks on the eliding of unused arguments in the backend
// when this is fixed, the special case in dcl.c checkarglist can go.
//if(t->funarg)
// fmtstrcpy(fp, "_ ");
//else
fmtstrcpy(fp, "? "); fmtstrcpy(fp, "? ");
break;
}
// fallthrough
default:
if(!(s == S || t->embedded))
fmtprint(fp, "%hS ", s);
} }
} }
@ -764,15 +776,7 @@ stmtfmt(Fmt *f, Node *n)
switch(n->op){ switch(n->op){
case ODCL: case ODCL:
switch(n->left->class) { fmtprint(f, "var %S %T", n->left->sym, n->left->type);
case PFUNC:
case PEXTERN:
fmtprint(f, "var %S %T", n->left->sym, n->left->type);
break;
default:
fmtprint(f, "var %hS %T", n->left->sym, n->left->type);
break;
}
break; break;
case ODCLFIELD: case ODCLFIELD:
@ -931,9 +935,15 @@ static int opprec[] = {
[ORECV] = 8, [ORECV] = 8,
[ORUNESTR] = 8, [ORUNESTR] = 8,
[OTPAREN] = 8, [OTPAREN] = 8,
[OSTRUCTLIT] = 8,
[OMAPLIT] = 8,
[OARRAYLIT] = 8,
[OINDEXMAP] = 8, [OINDEXMAP] = 8,
[OINDEX] = 8, [OINDEX] = 8,
[OSLICE] = 8,
[OSLICESTR] = 8,
[OSLICEARR] = 8,
[ODOTINTER] = 8, [ODOTINTER] = 8,
[ODOTMETH] = 8, [ODOTMETH] = 8,
[ODOTPTR] = 8, [ODOTPTR] = 8,
@ -1006,6 +1016,7 @@ static int
exprfmt(Fmt *f, Node *n, int prec) exprfmt(Fmt *f, Node *n, int prec)
{ {
int nprec; int nprec;
NodeList *l;
while(n && n->implicit) while(n && n->implicit)
n = n->left; n = n->left;
@ -1044,15 +1055,6 @@ exprfmt(Fmt *f, Node *n, int prec)
case ONAME: case ONAME:
case OPACK: case OPACK:
case ONONAME: case ONONAME:
if(fmtmode == FExp) {
switch(n->class&~PHEAP) {
case PEXTERN:
case PFUNC:
break;
default:
return fmtprint(f, "%hS", n->sym);
}
}
return fmtprint(f, "%S", n->sym); return fmtprint(f, "%S", n->sym);
case OTYPE: case OTYPE:
@ -1091,39 +1093,31 @@ exprfmt(Fmt *f, Node *n, int prec)
case OTFUNC: case OTFUNC:
return fmtprint(f, "<func>"); return fmtprint(f, "<func>");
case OPLUS:
case OMINUS:
if(n->left->op == n->op)
return fmtprint(f, "%#O %N", n->op, n->left);
// fallthrough
case OADDR:
case OCOM:
case OIND:
case ONOT:
case ORECV:
return fmtprint(f, "%#O%N", n->op, n->left);
case OCLOSURE: case OCLOSURE:
if(fmtmode == FErr) if(fmtmode == FErr)
return fmtstrcpy(f, "func literal"); return fmtstrcpy(f, "func literal");
// return fmtprint(f, "%T { %H }", n->type, n->nbody); this prints the list/rlist turned to types, not what we want return fmtprint(f, "%T { %H }", n->type, n->nbody);
if(!n->rlist)
return fmtprint(f, "func(%,H) { %H } ", n->list, n->nbody);
if(!n->rlist->next && !n->rlist->n->left)
return fmtprint(f, "func(%,H) %N { %H } ", n->list, n->rlist->n->right, n->nbody);
return fmtprint(f, "func(%,H) (%,H) { %H } ", n->list, n->rlist, n->nbody);
case OCOMPLIT: case OCOMPLIT:
return fmtstrcpy(f, "composite literal"); return fmtstrcpy(f, "composite literal");
case OPTRLIT: case OPTRLIT:
if(fmtmode == FErr) return fmtprint(f, "&%N", n->left);
return fmtprint(f, "&%T literal", n->type->type);
return fmtprint(f, "&%T{ %,H }", n->type->type, n->list); case OSTRUCTLIT:
if (fmtmode == FExp) { // requires special handling of field names
fmtprint(f, "%T{", n->type);
for(l=n->list; l; l=l->next)
if(l->next)
fmtprint(f, " %hhS:%N,", l->n->left->sym, l->n->right);
else
fmtprint(f, " %hhS:%N ", l->n->left->sym, l->n->right);
return fmtstrcpy(f, "}");
}
// fallthrough
case OARRAYLIT: case OARRAYLIT:
case OMAPLIT: case OMAPLIT:
case OSTRUCTLIT:
if(fmtmode == FErr) if(fmtmode == FErr)
return fmtprint(f, "%T literal", n->type); return fmtprint(f, "%T literal", n->type);
return fmtprint(f, "%T{ %,H }", n->type, n->list); return fmtprint(f, "%T{ %,H }", n->type, n->list);
@ -1211,6 +1205,21 @@ exprfmt(Fmt *f, Node *n, int prec)
return fmtprint(f, "make(%T, %,H)", n->type, n->list->next); return fmtprint(f, "make(%T, %,H)", n->type, n->list->next);
return fmtprint(f, "make(%T)", n->type); return fmtprint(f, "make(%T)", n->type);
// Unary
case OPLUS:
case OMINUS:
case OADDR:
case OCOM:
case OIND:
case ONOT:
case ORECV:
if(n->left->op == n->op)
fmtprint(f, "%#O ", n->op);
else
fmtprint(f, "%#O", n->op);
return exprfmt(f, n->left, nprec+1);
// Binary
case OADD: case OADD:
case OADDSTR: case OADDSTR:
case OAND: case OAND:
@ -1274,8 +1283,7 @@ indent(Fmt *fp)
{ {
int i; int i;
if(dumpdepth > 1) fmtstrcpy(fp, "\n");
fmtstrcpy(fp, "\n");
for(i = 0; i < dumpdepth; ++i) for(i = 0; i < dumpdepth; ++i)
fmtstrcpy(fp, ". "); fmtstrcpy(fp, ". ");
} }
@ -1324,7 +1332,6 @@ nodedump(Fmt *fp, Node *n)
case OTYPE: case OTYPE:
fmtprint(fp, "%O %S type=%T", n->op, n->sym, n->type); fmtprint(fp, "%O %S type=%T", n->op, n->sym, n->type);
if(recur && n->type == T && n->ntype) { if(recur && n->type == T && n->ntype) {
fmtstrcpy(fp, "\n");
indent(fp); indent(fp);
fmtprint(fp, "%O-ntype%N", n->op, n->ntype); fmtprint(fp, "%O-ntype%N", n->op, n->ntype);
} }
@ -1384,6 +1391,9 @@ Sconv(Fmt *fp)
if(s == S) if(s == S)
return fmtstrcpy(fp, "<S>"); return fmtstrcpy(fp, "<S>");
if(s->name[0] == '_' && s->name[1] == '\0')
return fmtstrcpy(fp, "_");
sf = fp->flags; sf = fp->flags;
sm = setfmode(&fp->flags); sm = setfmode(&fp->flags);
r = symfmt(fp, s); r = symfmt(fp, s);

View File

@ -135,7 +135,7 @@ struct Type
uchar printed; uchar printed;
uchar embedded; // TFIELD embedded type uchar embedded; // TFIELD embedded type
uchar siggen; uchar siggen;
uchar funarg; uchar funarg; // on TSTRUCT and TFIELD
uchar copyany; uchar copyany;
uchar local; // created in this file uchar local; // created in this file
uchar deferwidth; uchar deferwidth;
@ -325,9 +325,9 @@ struct NodeList
enum enum
{ {
SymExport = 1<<0, SymExport = 1<<0, // to be exported
SymPackage = 1<<1, SymPackage = 1<<1,
SymExported = 1<<2, SymExported = 1<<2, // already written out by export
SymUniq = 1<<3, SymUniq = 1<<3,
SymSiggen = 1<<4, SymSiggen = 1<<4,
}; };
@ -794,7 +794,7 @@ EXTERN NodeList* xtop;
EXTERN NodeList* externdcl; EXTERN NodeList* externdcl;
EXTERN NodeList* closures; EXTERN NodeList* closures;
EXTERN NodeList* exportlist; EXTERN NodeList* exportlist;
EXTERN NodeList* typelist; EXTERN NodeList* importlist; // imported functions and methods with inlinable bodies
EXTERN int dclcontext; // PEXTERN/PAUTO EXTERN int dclcontext; // PEXTERN/PAUTO
EXTERN int incannedimport; EXTERN int incannedimport;
EXTERN int statuniqgen; // name generator for static temps EXTERN int statuniqgen; // name generator for static temps
@ -950,11 +950,11 @@ void autoexport(Node *n, int ctxt);
void dumpexport(void); void dumpexport(void);
int exportname(char *s); int exportname(char *s);
void exportsym(Node *n); void exportsym(Node *n);
void importconst(Sym *s, Type *t, Node *n); void importconst(Sym *s, Type *t, Node *n);
void importmethod(Sym *s, Type *t); void importimport(Sym *s, Strlit *z);
Sym* importsym(Sym *s, int op); Sym* importsym(Sym *s, int op);
void importtype(Type *pt, Type *t); void importtype(Type *pt, Type *t);
void importvar(Sym *s, Type *t, int ctxt); void importvar(Sym *s, Type *t);
Type* pkgtype(Sym *s); Type* pkgtype(Sym *s);
/* /*
@ -983,7 +983,7 @@ Node* temp(Type*);
* init.c * init.c
*/ */
void fninit(NodeList *n); void fninit(NodeList *n);
Node* renameinit(Node *n); Sym* renameinit(void);
/* /*
* lex.c * lex.c

View File

@ -56,7 +56,7 @@ static void fixlbrace(int);
%type <node> case caseblock %type <node> case caseblock
%type <node> compound_stmt dotname embed expr complitexpr %type <node> compound_stmt dotname embed expr complitexpr
%type <node> expr_or_type %type <node> expr_or_type
%type <node> fndcl fnliteral %type <node> fndcl hidden_fndcl fnliteral
%type <node> for_body for_header for_stmt if_header if_stmt else non_dcl_stmt %type <node> for_body for_header for_stmt if_header if_stmt else non_dcl_stmt
%type <node> interfacedcl keyval labelname name %type <node> interfacedcl keyval labelname name
%type <node> name_or_type non_expr_type %type <node> name_or_type non_expr_type
@ -80,8 +80,8 @@ static void fixlbrace(int);
%type <sym> hidden_importsym hidden_pkg_importsym %type <sym> hidden_importsym hidden_pkg_importsym
%type <node> hidden_constant hidden_literal hidden_dcl %type <node> hidden_constant hidden_literal hidden_funarg
%type <node> hidden_interfacedcl hidden_structdcl hidden_opt_sym %type <node> hidden_interfacedcl hidden_structdcl
%type <list> hidden_funres %type <list> hidden_funres
%type <list> ohidden_funres %type <list> ohidden_funres
@ -235,7 +235,7 @@ import_here:
} }
import_package: import_package:
LPACKAGE sym import_safety ';' LPACKAGE LNAME import_safety ';'
{ {
if(importpkg->name == nil) { if(importpkg->name == nil) {
importpkg->name = $2->name; importpkg->name = $2->name;
@ -1004,7 +1004,17 @@ onew_name:
sym: sym:
LNAME LNAME
{
$$ = $1;
// during imports, unqualified non-exported identifiers are from builtinpkg
if(importpkg != nil && !exportname($1->name))
$$ = pkglookup($1->name, builtinpkg);
}
| hidden_importsym | hidden_importsym
| '?'
{
$$ = S;
}
hidden_importsym: hidden_importsym:
'@' LLITERAL '.' LNAME '@' LLITERAL '.' LNAME
@ -1186,38 +1196,43 @@ xfndcl:
} }
fndcl: fndcl:
dcl_name '(' oarg_type_list_ocomma ')' fnres sym '(' oarg_type_list_ocomma ')' fnres
{ {
Node *n; Node *t;
$$ = N;
$3 = checkarglist($3, 1); $3 = checkarglist($3, 1);
$$ = nod(ODCLFUNC, N, N);
$$->nname = $1; if(strcmp($1->name, "init") == 0) {
n = nod(OTFUNC, N, N); $1 = renameinit();
n->list = $3;
n->rlist = $5;
if(strcmp($1->sym->name, "init") == 0) {
$$->nname = renameinit($1);
if($3 != nil || $5 != nil) if($3 != nil || $5 != nil)
yyerror("func init must have no arguments and no return values"); yyerror("func init must have no arguments and no return values");
} }
if(strcmp(localpkg->name, "main") == 0 && strcmp($1->sym->name, "main") == 0) { if(strcmp(localpkg->name, "main") == 0 && strcmp($1->name, "main") == 0) {
if($3 != nil || $5 != nil) if($3 != nil || $5 != nil)
yyerror("func main must have no arguments and no return values"); yyerror("func main must have no arguments and no return values");
} }
// TODO: check if nname already has an ntype
$$->nname->ntype = n; t = nod(OTFUNC, N, N);
t->list = $3;
t->rlist = $5;
$$ = nod(ODCLFUNC, N, N);
$$->nname = newname($1);
$$->nname->defn = $$;
$$->nname->ntype = t; // TODO: check if nname already has an ntype
declare($$->nname, PFUNC);
funchdr($$); funchdr($$);
} }
| '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres | '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres
{ {
Node *rcvr, *t; Node *rcvr, *t;
Node *name;
$$ = N;
name = newname($4);
$2 = checkarglist($2, 0); $2 = checkarglist($2, 0);
$6 = checkarglist($6, 1); $6 = checkarglist($6, 1);
$$ = N;
if($2 == nil) { if($2 == nil) {
yyerror("method has no receiver"); yyerror("method has no receiver");
break; break;
@ -1234,13 +1249,51 @@ fndcl:
if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN)) if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN))
yyerror("cannot parenthesize receiver type"); yyerror("cannot parenthesize receiver type");
$$ = nod(ODCLFUNC, N, N);
$$->nname = methodname1(name, rcvr->right);
t = nod(OTFUNC, rcvr, N); t = nod(OTFUNC, rcvr, N);
t->list = $6; t->list = $6;
t->rlist = $8; t->rlist = $8;
$$ = nod(ODCLFUNC, N, N);
$$->shortname = newname($4);
$$->nname = methodname1($$->shortname, rcvr->right);
$$->nname->defn = $$;
$$->nname->ntype = t; $$->nname->ntype = t;
$$->shortname = name; declare($$->nname, PFUNC);
funchdr($$);
}
hidden_fndcl:
hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres
{
Sym *s;
Type *t;
$$ = N;
s = $1;
t = functype(N, $3, $5);
importsym(s, ONAME);
if(s->def != N && s->def->op == ONAME) {
if(eqtype(t, s->def->type))
break;
yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t);
}
$$ = newname(s);
$$->type = t;
declare($$, PFUNC);
funchdr($$);
}
| '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres
{
$$ = methodname1(newname($4), $2->n->right);
$$->type = functype($2->n, $6, $8);
checkwidth($$->type);
addmethod($4, $$->type, 0);
funchdr($$); funchdr($$);
} }
@ -1709,31 +1762,16 @@ oliteral:
| LLITERAL | LLITERAL
/* /*
* import syntax from header of * import syntax from package header
* an output package
*/ */
hidden_import: hidden_import:
LIMPORT sym LLITERAL ';' LIMPORT LNAME LLITERAL ';'
{ {
// Informational: record package name importimport($2, $3.u.sval);
// associated with import path, for use in
// human-readable messages.
Pkg *p;
p = mkpkg($3.u.sval);
if(p->name == nil) {
p->name = $2->name;
pkglookup($2->name, nil)->npkg++;
} else if(strcmp(p->name, $2->name) != 0)
yyerror("conflicting names %s and %s for package \"%Z\"", p->name, $2->name, p->path);
if(!incannedimport && myimportpath != nil && strcmp($3.u.sval->s, myimportpath) == 0) {
yyerror("import \"%Z\": package depends on \"%Z\" (import cycle)", importpkg->path, $3.u.sval);
errorexit();
}
} }
| LVAR hidden_pkg_importsym hidden_type ';' | LVAR hidden_pkg_importsym hidden_type ';'
{ {
importvar($2, $3, PEXTERN); importvar($2, $3);
} }
| LCONST hidden_pkg_importsym '=' hidden_constant ';' | LCONST hidden_pkg_importsym '=' hidden_constant ';'
{ {
@ -1747,17 +1785,24 @@ hidden_import:
{ {
importtype($2, $3); importtype($2, $3);
} }
| LFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres ';' | LFUNC hidden_fndcl fnbody ';'
{ {
importvar($2, functype(N, $4, $6), PFUNC); if($2 == N)
} break;
| LFUNC '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres ';'
{ funcbody($2);
if($3->next != nil || $3->n->op != ODCLFIELD) { importlist = list(importlist, $2);
yyerror("bad receiver in method");
YYERROR; if(debug['E']) {
print("import [%Z] func %lN \n", $2->sym->pkg->path, $2);
} }
importmethod($5, functype($3->n, $7, $9)); }
hidden_pkg_importsym:
hidden_importsym
{
$$ = $1;
structpkg = $$->pkg;
} }
hidden_pkgtype: hidden_pkgtype:
@ -1767,6 +1812,10 @@ hidden_pkgtype:
importsym($1, OTYPE); importsym($1, OTYPE);
} }
/*
* importing types
*/
hidden_type: hidden_type:
hidden_type_misc hidden_type_misc
| hidden_type_recv_chan | hidden_type_recv_chan
@ -1848,52 +1897,45 @@ hidden_type_func:
$$ = functype(nil, $3, $5); $$ = functype(nil, $3, $5);
} }
hidden_opt_sym: hidden_funarg:
sym sym hidden_type oliteral
{ {
$$ = newname($1); $$ = nod(ODCLFIELD, N, typenod($2));
} if($1)
| '?' $$->left = newname($1);
{
$$ = N;
}
hidden_dcl:
hidden_opt_sym hidden_type oliteral
{
$$ = nod(ODCLFIELD, $1, typenod($2));
$$->val = $3; $$->val = $3;
} }
| hidden_opt_sym LDDD hidden_type oliteral | sym LDDD hidden_type oliteral
{ {
Type *t; Type *t;
t = typ(TARRAY); t = typ(TARRAY);
t->bound = -1; t->bound = -1;
t->type = $3; t->type = $3;
$$ = nod(ODCLFIELD, $1, typenod(t));
$$ = nod(ODCLFIELD, N, typenod(t));
if($1)
$$->left = newname($1);
$$->isddd = 1; $$->isddd = 1;
$$->val = $4; $$->val = $4;
} }
hidden_structdcl: hidden_structdcl:
sym hidden_type oliteral sym hidden_type oliteral
{
$$ = nod(ODCLFIELD, newname($1), typenod($2));
$$->val = $3;
}
| '?' hidden_type oliteral
{ {
Sym *s; Sym *s;
s = $2->sym; if($1 != S) {
if(s == S && isptr[$2->etype]) $$ = nod(ODCLFIELD, newname($1), typenod($2));
s = $2->type->sym; $$->val = $3;
if(s && s->pkg == builtinpkg) } else {
s = lookup(s->name); s = $2->sym;
$$ = embedded(s); if(s == S && isptr[$2->etype])
$$->right = typenod($2); s = $2->type->sym;
$$->val = $3; $$ = embedded(s);
$$->right = typenod($2);
$$->val = $3;
}
} }
hidden_interfacedcl: hidden_interfacedcl:
@ -1918,6 +1960,10 @@ hidden_funres:
$$ = list1(nod(ODCLFIELD, N, typenod($1))); $$ = list1(nod(ODCLFIELD, N, typenod($1)));
} }
/*
* importing constants
*/
hidden_literal: hidden_literal:
LLITERAL LLITERAL
{ {
@ -1951,22 +1997,15 @@ hidden_constant:
$$ = nodcplxlit($2->val, $4->val); $$ = nodcplxlit($2->val, $4->val);
} }
hidden_pkg_importsym:
hidden_importsym
{
$$ = $1;
structpkg = $$->pkg;
}
hidden_import_list: hidden_import_list:
| hidden_import_list hidden_import | hidden_import_list hidden_import
hidden_funarg_list: hidden_funarg_list:
hidden_dcl hidden_funarg
{ {
$$ = list1($1); $$ = list1($1);
} }
| hidden_funarg_list ',' hidden_dcl | hidden_funarg_list ',' hidden_funarg
{ {
$$ = list($1, $3); $$ = list($1, $3);
} }

View File

@ -13,21 +13,13 @@
* package and also uncallable, the name, * package and also uncallable, the name,
* normally "pkg.init", is altered to "pkg.init·1". * normally "pkg.init", is altered to "pkg.init·1".
*/ */
Node* Sym*
renameinit(Node *n) renameinit(void)
{ {
Sym *s;
static int initgen; static int initgen;
s = n->sym;
if(s == S)
return n;
if(strcmp(s->name, "init") != 0)
return n;
snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen); snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
s = lookup(namebuf); return lookup(namebuf);
return newname(s);
} }
/* /*
@ -125,7 +117,9 @@ 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->nname->defn = fn;
fn->nname->ntype = nod(OTFUNC, N, N); fn->nname->ntype = nod(OTFUNC, N, N);
declare(fn->nname, PFUNC);
funchdr(fn); funchdr(fn);
// (3) // (3)

View File

@ -334,11 +334,11 @@ main(int argc, char *argv[])
if(nsavederrors+nerrors) if(nsavederrors+nerrors)
errorexit(); errorexit();
// Phase 3b: escape analysis. // Phase 4: escape analysis.
if(!debug['N']) if(!debug['N'])
escapes(); escapes();
// Phase 4: Compile function bodies. // Phase 5: Compile top level functions.
for(l=xtop; l; l=l->next) for(l=xtop; l; l=l->next)
if(l->n->op == ODCLFUNC) if(l->n->op == ODCLFUNC)
funccompile(l->n, 0); funccompile(l->n, 0);
@ -346,16 +346,15 @@ main(int argc, char *argv[])
if(nsavederrors+nerrors == 0) if(nsavederrors+nerrors == 0)
fninit(xtop); fninit(xtop);
// Phase 4b: Compile all closures. // Phase 5b: Compile all closures.
while(closures) { while(closures) {
l = closures; l = closures;
closures = nil; closures = nil;
for(; l; l=l->next) { for(; l; l=l->next)
funccompile(l->n, 1); funccompile(l->n, 1);
}
} }
// Phase 5: check external declarations. // Phase 6: check external declarations.
for(l=externdcl; l; l=l->next) for(l=externdcl; l; l=l->next)
if(l->n->op == ONAME) if(l->n->op == ONAME)
typecheck(&l->n, Erv); typecheck(&l->n, Erv);
@ -1423,7 +1422,7 @@ yylex(void)
// Track last two tokens returned by yylex. // Track last two tokens returned by yylex.
yyprev = yylast; yyprev = yylast;
yylast = lx; yylast = lx;
return lx; return lx;
} }
static int static int
@ -1680,12 +1679,12 @@ static struct
"type", LTYPE, Txxx, OXXX, "type", LTYPE, Txxx, OXXX,
"var", LVAR, Txxx, OXXX, "var", LVAR, Txxx, OXXX,
"append", LNAME, Txxx, OAPPEND, "append", LNAME, Txxx, OAPPEND,
"cap", LNAME, Txxx, OCAP, "cap", LNAME, Txxx, OCAP,
"close", LNAME, Txxx, OCLOSE, "close", LNAME, Txxx, OCLOSE,
"complex", LNAME, Txxx, OCOMPLEX, "complex", LNAME, Txxx, OCOMPLEX,
"copy", LNAME, Txxx, OCOPY, "copy", LNAME, Txxx, OCOPY,
"delete", LNAME, Txxx, ODELETE, "delete", LNAME, Txxx, ODELETE,
"imag", LNAME, Txxx, OIMAG, "imag", LNAME, Txxx, OIMAG,
"len", LNAME, Txxx, OLEN, "len", LNAME, Txxx, OLEN,
"make", LNAME, Txxx, OMAKE, "make", LNAME, Txxx, OMAKE,
@ -1710,6 +1709,7 @@ lexinit(void)
Sym *s, *s1; Sym *s, *s1;
Type *t; Type *t;
int etype; int etype;
Val v;
/* /*
* initialize basic types array * initialize basic types array
@ -1738,6 +1738,16 @@ lexinit(void)
s1->def = typenod(t); s1->def = typenod(t);
continue; continue;
} }
etype = syms[i].op;
if(etype != OXXX) {
s1 = pkglookup(syms[i].name, builtinpkg);
s1->lexical = LNAME;
s1->def = nod(ONAME, N, N);
s1->def->sym = s;
s1->def->etype = etype;
s1->def->builtin = 1;
}
} }
// logically, the type of a string literal. // logically, the type of a string literal.
@ -1765,6 +1775,19 @@ lexinit(void)
types[TBLANK] = typ(TBLANK); types[TBLANK] = typ(TBLANK);
s->def->type = types[TBLANK]; s->def->type = types[TBLANK];
nblank = s->def; nblank = s->def;
s = pkglookup("_", builtinpkg);
s->block = -100;
s->def = nod(ONAME, N, N);
s->def->sym = s;
types[TBLANK] = typ(TBLANK);
s->def->type = types[TBLANK];
types[TNIL] = typ(TNIL);
s = pkglookup("nil", builtinpkg);
v.ctype = CTNIL;
s->def = nodlit(v);
s->def->sym = s;
} }
static void static void
@ -1875,7 +1898,6 @@ lexfini(void)
if(s->def == N) if(s->def == N)
s->def = typenod(runetype); s->def = typenod(runetype);
types[TNIL] = typ(TNIL);
s = lookup("nil"); s = lookup("nil");
if(s->def == N) { if(s->def == N) {
v.ctype = CTNIL; v.ctype = CTNIL;

View File

@ -2287,8 +2287,6 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
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->nname = newname(newnam);
t = nod(OTFUNC, N, N); t = nod(OTFUNC, N, N);
l = list1(this); l = list1(this);
if(iface && rcvr->width < types[tptr]->width) { if(iface && rcvr->width < types[tptr]->width) {
@ -2305,7 +2303,12 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
} }
t->list = concat(l, in); t->list = concat(l, in);
t->rlist = out; t->rlist = out;
fn = nod(ODCLFUNC, N, N);
fn->nname = newname(newnam);
fn->nname->defn = fn;
fn->nname->ntype = t; fn->nname->ntype = t;
declare(fn->nname, PFUNC);
funchdr(fn); funchdr(fn);
// arg list // arg list

View File

@ -43,7 +43,7 @@ resolve(Node *n)
{ {
Node *r; Node *r;
if(n != N && n->op == ONONAME && (r = n->sym->def) != N) { if(n != N && n->op == ONONAME && n->sym != S && (r = n->sym->def) != N) {
if(r->op != OIOTA) if(r->op != OIOTA)
n = r; n = r;
else if(n->iota >= 0) else if(n->iota >= 0)
@ -114,7 +114,6 @@ typecheck(Node **np, int top)
NodeList *args; NodeList *args;
int lno, ok, ntop; int lno, ok, ntop;
Type *t, *tp, *ft, *missing, *have; Type *t, *tp, *ft, *missing, *have;
Sym *sym;
Val v; Val v;
char *why; char *why;
@ -567,15 +566,14 @@ reswitch:
case ODOT: case ODOT:
typecheck(&n->left, Erv|Etype); typecheck(&n->left, Erv|Etype);
defaultlit(&n->left, T); defaultlit(&n->left, T);
l = n->left; if((t = n->left->type) == T)
if((t = l->type) == T)
goto error; goto error;
if(n->right->op != ONAME) { if(n->right->op != ONAME) {
yyerror("rhs of . must be a name"); // impossible yyerror("rhs of . must be a name"); // impossible
goto error; goto error;
} }
sym = n->right->sym;
if(l->op == OTYPE) { if(n->left->op == OTYPE) {
if(!looktypedot(n, t, 0)) { if(!looktypedot(n, t, 0)) {
if(looktypedot(n, t, 1)) if(looktypedot(n, t, 1))
yyerror("%N undefined (cannot refer to unexported method %S)", n, n->right->sym); yyerror("%N undefined (cannot refer to unexported method %S)", n, n->right->sym);
@ -584,19 +582,18 @@ reswitch:
goto error; goto error;
} }
if(n->type->etype != TFUNC || n->type->thistuple != 1) { if(n->type->etype != TFUNC || n->type->thistuple != 1) {
yyerror("type %T has no method %hS", n->left->type, sym); yyerror("type %T has no method %hS", n->left->type, n->right->sym);
n->type = T; n->type = T;
goto error; goto error;
} }
n->op = ONAME; n->op = ONAME;
n->sym = methodsym(sym, l->type, 0); n->sym = n->right->sym;
n->type = methodfunc(n->type, l->type); n->type = methodfunc(n->type, n->left->type);
n->xoffset = 0; n->xoffset = 0;
n->class = PFUNC; n->class = PFUNC;
ok = Erv; ok = Erv;
goto ret; goto ret;
} }
tp = t;
if(isptr[t->etype] && t->type->etype != TINTER) { if(isptr[t->etype] && t->type->etype != TINTER) {
t = t->type; t = t->type;
if(t == T) if(t == T)
@ -608,7 +605,7 @@ reswitch:
if(lookdot(n, t, 1)) if(lookdot(n, t, 1))
yyerror("%N undefined (cannot refer to unexported field or method %S)", n, n->right->sym); yyerror("%N undefined (cannot refer to unexported field or method %S)", n, n->right->sym);
else else
yyerror("%N undefined (type %T has no field or method %S)", n, tp, n->right->sym); yyerror("%N undefined (type %T has no field or method %S)", n, n->left->type, n->right->sym);
goto error; goto error;
} }
switch(n->op) { switch(n->op) {
@ -2167,14 +2164,16 @@ typecheckcomplit(Node **np)
typecheck(&l->right, Erv); typecheck(&l->right, Erv);
continue; continue;
} }
// Sym might have resolved to name in other top-level // Sym might have resolved to name in other top-level
// package, because of import dot. Redirect to correct sym // package, because of import dot. Redirect to correct sym
// before we do the lookup. // before we do the lookup.
if(s->pkg != localpkg) if(s->pkg != localpkg && exportname(s->name))
s = lookup(s->name); s = lookup(s->name);
f = lookdot1(s, t, t->type, 0); f = lookdot1(s, t, t->type, 0);
if(f == nil) { if(f == nil) {
yyerror("unknown %T field '%s' in struct literal", t, s->name); yyerror("unknown %T field '%S' in struct literal", t, s);
continue; continue;
} }
l->left = newname(s); l->left = newname(s);

View File

@ -323,7 +323,7 @@ func (p *gcParser) parseMapType() Type {
return &Map{Key: key, Elt: elt} return &Map{Key: key, Elt: elt}
} }
// Name = identifier | "?" . // Name = identifier | "?" | ExportedName .
// //
func (p *gcParser) parseName() (name string) { func (p *gcParser) parseName() (name string) {
switch p.tok { switch p.tok {
@ -333,6 +333,9 @@ func (p *gcParser) parseName() (name string) {
case '?': case '?':
// anonymous // anonymous
p.next() p.next()
case '@':
// exported name prefixed with package path
_, name = p.parseExportedName()
default: default:
p.error("name expected") p.error("name expected")
} }
@ -747,7 +750,7 @@ func (p *gcParser) parseFuncDecl() {
} }
} }
// MethodDecl = "func" Receiver identifier Signature . // MethodDecl = "func" Receiver Name Signature .
// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" [ FuncBody ]. // Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" [ FuncBody ].
// //
func (p *gcParser) parseMethodDecl() { func (p *gcParser) parseMethodDecl() {
@ -755,7 +758,7 @@ func (p *gcParser) parseMethodDecl() {
p.expect('(') p.expect('(')
p.parseParameter() // receiver p.parseParameter() // receiver
p.expect(')') p.expect(')')
p.expect(scanner.Ident) p.parseName() // unexported method names in imports are qualified with their package.
p.parseSignature() p.parseSignature()
if p.tok == '{' { if p.tok == '{' {
p.parseFuncBody() p.parseFuncBody()