Commit 087bec3d authored by Luuk van Dijk's avatar Luuk van Dijk

gc: Clean up dostruct/stotype, detect broken fields and propagate up to...

gc: Clean up dostruct/stotype, detect broken fields and propagate up to structs and functions to supress spurious errors.

Fixes #1556.

R=rsc
CC=golang-dev
https://golang.org/cl/5351042
parent dfe03bb2
...@@ -709,181 +709,264 @@ ok: ...@@ -709,181 +709,264 @@ ok:
* they don't belong here, but where do they belong? * they don't belong here, but where do they belong?
*/ */
static void
checkembeddedtype(Type *t)
{
if (t == T)
return;
/* if(t->sym == S && isptr[t->etype]) {
* turn a parsed struct into a type t = t->type;
*/ if(t->etype == TINTER)
static Type** yyerror("embedded type cannot be a pointer to interface");
stotype(NodeList *l, int et, Type **t, int funarg) }
if(isptr[t->etype])
yyerror("embedded type cannot be a pointer");
else if(t->etype == TFORW && t->embedlineno == 0)
t->embedlineno = lineno;
}
static Type*
structfield(Node *n)
{ {
Type *f, *t1, *t2, **t0; Type *f;
Strlit *note;
int lno; int lno;
Node *n, *left;
char *what;
t0 = t;
lno = lineno; lno = lineno;
what = "field"; lineno = n->lineno;
if(et == TINTER)
what = "method";
for(; l; l=l->next) { if(n->op != ODCLFIELD)
n = l->n; fatal("structfield: oops %N\n", n);
lineno = n->lineno;
if(n->op != ODCLFIELD) f = typ(TFIELD);
fatal("stotype: oops %N\n", n); f->isddd = n->isddd;
left = n->left;
if(funarg && isblank(left)) if(n->right != N) {
left = N; typecheck(&n->right, Etype);
if(n->right != N) { n->type = n->right->type;
if(et == TINTER && left != N) { if(n->left != N)
// queue resolution of method type for later. n->left->type = n->type;
// right now all we need is the name list. if(n->embedded)
// avoids cycles for recursive interface types. checkembeddedtype(n->type);
n->type = typ(TINTERMETH); }
n->type->nname = n->right; n->right = N;
n->right = N;
left->type = n->type; f->type = n->type;
queuemethod(n); if(f->type == T)
} else { f->broke = 1;
typecheck(&n->right, Etype);
n->type = n->right->type; switch(n->val.ctype) {
if(n->type == T) case CTSTR:
continue; f->note = n->val.u.sval;
if(left != N) break;
left->type = n->type; default:
n->right = N; yyerror("field annotation must be string");
if(n->embedded && n->type != T) { // fallthrough
t1 = n->type; case CTxxx:
if(t1->sym == S && isptr[t1->etype]) { f->note = nil;
t1 = t1->type; break;
if(t1->etype == TINTER) }
yyerror("embedded type cannot be a pointer to interface");
} // tofunarg will undo this for _ arguments
if(isptr[t1->etype]) if(n->left && n->left->op == ONAME) {
yyerror("embedded type cannot be a pointer"); f->nname = n->left;
else if(t1->etype == TFORW && t1->embedlineno == 0) f->embedded = n->embedded;
t1->embedlineno = lineno; f->sym = f->nname->sym;
if(importpkg && !exportname(f->sym->name))
f->sym = pkglookup(f->sym->name, structpkg);
}
lineno = lno;
return f;
}
static void
checkdupfields(Type *t, char* what)
{
Type* t1;
int lno;
lno = lineno;
for( ; t; t=t->down)
if(t->sym && t->nname && !isblank(t->nname))
for(t1=t->down; t1; t1=t1->down)
if(t1->sym == t->sym) {
lineno = t->nname->lineno;
yyerror("duplicate %s %s", what, t->sym->name);
break;
} }
}
}
if(n->type == T) { lineno = lno;
// assume error already printed }
continue;
}
switch(n->val.ctype) { /*
case CTSTR: * convert a parsed id/type list into
if(et != TSTRUCT) * a type for struct/interface/arglist
yyerror("interface method cannot have annotation"); */
note = n->val.u.sval; Type*
break; tostruct(NodeList *l)
default: {
if(et != TSTRUCT) Type *t, *f, **tp;
yyerror("interface method cannot have annotation"); t = typ(TSTRUCT);
else
yyerror("field annotation must be string"); for(tp = &t->type; l; l=l->next,tp = &(*tp)->down)
case CTxxx: *tp = structfield(l->n);
note = nil;
break; for(f=t->type; f && !t->broke; f=f->down)
if(f->broke)
t->broke = 1;
checkdupfields(t->type, "field");
if (!t->broke)
checkwidth(t);
return t;
}
static Type*
tofunargs(NodeList *l)
{
Type *t, *f, **tp;
t = typ(TSTRUCT);
t->funarg = 1;
for(tp = &t->type; l; l=l->next) {
f = structfield(l->n);
// Unlink the name for _ arguments.
if(l->n->left && l->n->left->op == ONAME && isblank(l->n->left)) {
f->nname = nil;
f->sym = nil;
f->embedded = 0;
} }
if(et == TINTER && left == N) { // esc.c needs to find f given a PPARAM to add the tag.
// embedded interface - inline the methods if(l->n->left && l->n->left->class == PPARAM)
if(n->type->etype != TINTER) { l->n->left->paramfld = f;
if(n->type->etype == TFORW)
yyerror("interface type loop involving %T", n->type); *tp = f;
else tp = &f->down;
yyerror("interface contains embedded non-interface %T", n->type); }
continue;
} for(f=t->type; f && !t->broke; f=f->down)
for(t1=n->type->type; t1!=T; t1=t1->down) { if(f->broke)
f = typ(TFIELD); t->broke = 1;
f->type = t1->type;
f->width = BADWIDTH; checkdupfields(t->type, "argument");
f->nname = newname(t1->sym); return t;
f->sym = t1->sym; }
for(t2=*t0; t2!=T; t2=t2->down) {
if(t2->sym == f->sym) { static Type*
yyerror("duplicate method %s", t2->sym->name); interfacefield(Node *n)
break; {
} Type *f;
} int lno;
*t = f;
t = &f->down; lno = lineno;
lineno = n->lineno;
if(n->op != ODCLFIELD)
fatal("interfacefield: oops %N\n", n);
if (n->val.ctype != CTxxx)
yyerror("interface method cannot have annotation");
f = typ(TFIELD);
f->isddd = n->isddd;
if(n->right != N) {
if(n->left != N) {
// queue resolution of method type for later.
// right now all we need is the name list.
// avoids cycles for recursive interface types.
n->type = typ(TINTERMETH);
n->type->nname = n->right;
n->left->type = n->type;
queuemethod(n);
if(n->left->op == ONAME) {
f->nname = n->left;
f->embedded = n->embedded;
f->sym = f->nname->sym;
if(importpkg && !exportname(f->sym->name))
f->sym = pkglookup(f->sym->name, structpkg);
} }
continue;
}
f = typ(TFIELD); } else {
f->type = n->type;
f->note = note; typecheck(&n->right, Etype);
f->width = BADWIDTH; n->type = n->right->type;
f->isddd = n->isddd;
// esc.c needs to find f given a PPARAM to add the tag. if(n->embedded)
if(funarg && n->left && n->left->class == PPARAM) checkembeddedtype(n->type);
n->left->paramfld = f;
if(n->type)
if(left != N && left->op == ONAME) { switch(n->type->etype) {
f->nname = left; case TINTER:
f->embedded = n->embedded; break;
f->sym = f->nname->sym; case TFORW:
if(importpkg && !exportname(f->sym->name)) yyerror("interface type loop involving %T", n->type);
f->sym = pkglookup(f->sym->name, structpkg); f->broke = 1;
if(f->sym && !isblank(f->nname)) { break;
for(t1=*t0; t1!=T; t1=t1->down) { default:
if(t1->sym == f->sym) { yyerror("interface contains embedded non-interface %T", n->type);
yyerror("duplicate %s %s", what, t1->sym->name); f->broke = 1;
break; break;
}
} }
}
} }
*t = f;
t = &f->down;
} }
*t = T; n->right = N;
f->type = n->type;
if(f->type == T)
f->broke = 1;
lineno = lno; lineno = lno;
return t; return f;
} }
Type* Type*
dostruct(NodeList *l, int et) tointerface(NodeList *l)
{ {
Type *t; Type *t, *f, **tp, *t1;
int funarg;
/* t = typ(TINTER);
* convert a parsed id/type list into
* a type for struct/interface/arglist
*/
funarg = 0; for(tp = &t->type; l; l=l->next) {
if(et == TFUNC) { f = interfacefield(l->n);
funarg = 1; if (l->n->left == N && f->type->etype == TINTER) {
et = TSTRUCT; // embedded interface, inline methods
} for(t1=f->type->type; t1; t1=t1->down) {
t = typ(et); f = typ(TFIELD);
t->funarg = funarg; f->type = t1->type;
stotype(l, et, &t->type, funarg); f->broke = t1->broke;
if(t->type == T && l != nil) { f->sym = t1->sym;
t->broke = 1; if(f->sym)
return t; f->nname = newname(f->sym);
*tp = f;
tp = &f->down;
}
} else {
*tp = f;
tp = &f->down;
}
} }
if(et == TINTER)
t = sortinter(t); for(f=t->type; f && !t->broke; f=f->down)
if(!funarg) if(f->broke)
checkwidth(t); t->broke = 1;
checkdupfields(t->type, "method");
t = sortinter(t);
checkwidth(t);
return t; return t;
} }
Node* Node*
embedded(Sym *s) embedded(Sym *s)
{ {
...@@ -1038,9 +1121,12 @@ functype(Node *this, NodeList *in, NodeList *out) ...@@ -1038,9 +1121,12 @@ functype(Node *this, NodeList *in, NodeList *out)
rcvr = nil; rcvr = nil;
if(this) if(this)
rcvr = list1(this); rcvr = list1(this);
t->type = dostruct(rcvr, TFUNC); t->type = tofunargs(rcvr);
t->type->down = dostruct(out, TFUNC); t->type->down = tofunargs(out);
t->type->down->down = dostruct(in, TFUNC); t->type->down->down = tofunargs(in);
if (t->type->broke || t->type->down->broke || t->type->down->down->broke)
t->broke = 1;
if(this) if(this)
t->thistuple = 1; t->thistuple = 1;
...@@ -1212,9 +1298,9 @@ addmethod(Sym *sf, Type *t, int local) ...@@ -1212,9 +1298,9 @@ addmethod(Sym *sf, Type *t, int local)
} }
if(d == T) if(d == T)
stotype(list1(n), 0, &pa->method, 0); pa->method = structfield(n);
else else
stotype(list1(n), 0, &d->down, 0); d->down = structfield(n);
return; return;
} }
......
...@@ -935,7 +935,6 @@ void colasdefn(NodeList *left, Node *defn); ...@@ -935,7 +935,6 @@ void colasdefn(NodeList *left, Node *defn);
NodeList* constiter(NodeList *vl, Node *t, NodeList *cl); NodeList* constiter(NodeList *vl, Node *t, NodeList *cl);
Node* dclname(Sym *s); Node* dclname(Sym *s);
void declare(Node *n, int ctxt); void declare(Node *n, int ctxt);
Type* dostruct(NodeList *l, int et);
void dumpdcl(char *st); void dumpdcl(char *st);
Node* embedded(Sym *s); Node* embedded(Sym *s);
Node* fakethis(void); Node* fakethis(void);
...@@ -956,6 +955,8 @@ void popdcl(void); ...@@ -956,6 +955,8 @@ void popdcl(void);
void poptodcl(void); void poptodcl(void);
void redeclare(Sym *s, char *where); void redeclare(Sym *s, char *where);
void testdclstack(void); void testdclstack(void);
Type* tointerface(NodeList *l);
Type* tostruct(NodeList *l);
Node* typedcl0(Sym *s); Node* typedcl0(Sym *s);
Node* typedcl1(Node *n, Node *t, int local); Node* typedcl1(Node *n, Node *t, int local);
void typedcl2(Type *pt, Type *t); void typedcl2(Type *pt, Type *t);
......
...@@ -1792,11 +1792,11 @@ hidden_type_misc: ...@@ -1792,11 +1792,11 @@ hidden_type_misc:
} }
| LSTRUCT '{' ohidden_structdcl_list '}' | LSTRUCT '{' ohidden_structdcl_list '}'
{ {
$$ = dostruct($3, TSTRUCT); $$ = tostruct($3);
} }
| LINTERFACE '{' ohidden_interfacedcl_list '}' | LINTERFACE '{' ohidden_interfacedcl_list '}'
{ {
$$ = dostruct($3, TINTER); $$ = tointerface($3);
} }
| '*' hidden_type | '*' hidden_type
{ {
......
...@@ -1052,6 +1052,11 @@ assignop(Type *src, Type *dst, char **why) ...@@ -1052,6 +1052,11 @@ assignop(Type *src, Type *dst, char **why)
if(dst->etype == TINTER && src->etype != TNIL) { if(dst->etype == TINTER && src->etype != TNIL) {
if(implements(src, dst, &missing, &have, &ptr)) if(implements(src, dst, &missing, &have, &ptr))
return OCONVIFACE; return OCONVIFACE;
// we'll have complained about this method anyway, supress spurious messages.
if(have && have->sym == missing->sym && (have->type->broke || missing->type->broke))
return OCONVIFACE;
if(why != nil) { if(why != nil) {
if(isptrto(src, TINTER)) if(isptrto(src, TINTER))
*why = smprint(":\n\t%T is pointer to interface, not interface", src); *why = smprint(":\n\t%T is pointer to interface, not interface", src);
......
...@@ -311,7 +311,7 @@ reswitch: ...@@ -311,7 +311,7 @@ reswitch:
case OTSTRUCT: case OTSTRUCT:
ok |= Etype; ok |= Etype;
n->op = OTYPE; n->op = OTYPE;
n->type = dostruct(n->list, TSTRUCT); n->type = tostruct(n->list);
if(n->type == T) if(n->type == T)
goto error; goto error;
n->list = nil; n->list = nil;
...@@ -320,7 +320,7 @@ reswitch: ...@@ -320,7 +320,7 @@ reswitch:
case OTINTER: case OTINTER:
ok |= Etype; ok |= Etype;
n->op = OTYPE; n->op = OTYPE;
n->type = dostruct(n->list, TINTER); n->type = tointerface(n->list);
if(n->type == T) if(n->type == T)
goto error; goto error;
break; break;
......
...@@ -16,6 +16,6 @@ type I2 interface { ...@@ -16,6 +16,6 @@ type I2 interface {
} }
var i1 I1 = i2 // GC_ERROR "missing m method|need type assertion" var i1 I1 = i2
var i2 I2 var i2 I2
var i2a I2 = i1 var i2a I2 = i1
// errchk $G $D/$F.go
// Copyright 2011 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.
// issue 1556
package foo
type I interface {
m() int
}
type T int
var _ I = T(0)
func (T) m(buf []byte) (a int, b xxxx) { // ERROR "xxxx"
return 0, nil
}
\ No newline at end of file
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