diff options
author | Russ Cox <rsc@golang.org> | 2010-06-20 11:45:53 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2010-06-20 11:45:53 -0700 |
commit | 3d434f2574c951249e9b317d3313617963673269 (patch) | |
tree | 9a814e6cb257c3224f01cfa0d9e827b687a5bc45 /src/cmd/gc | |
parent | 58da368d8786780b73dc3d094c5f81c34df07a10 (diff) | |
download | golang-3d434f2574c951249e9b317d3313617963673269.tar.gz |
gc: better error messages for interface failures, conversions
x.go:13: cannot use t (type T) as type Reader in assignment:
T does not implement Reader (Read method requires pointer receiver)
x.go:19: cannot use q (type Q) as type Reader in assignment:
Q does not implement Reader (missing Read method)
have read()
want Read()
x.go:22: cannot use z (type int) as type Reader in assignment:
int does not implement Reader (missing Read method)
x.go:24: too many arguments to conversion to complex: complex(1, 3)
R=ken2
CC=golang-dev
http://codereview.appspot.com/1736041
Diffstat (limited to 'src/cmd/gc')
-rw-r--r-- | src/cmd/gc/go.h | 4 | ||||
-rw-r--r-- | src/cmd/gc/print.c | 5 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 74 | ||||
-rw-r--r-- | src/cmd/gc/typecheck.c | 36 |
4 files changed, 86 insertions, 33 deletions
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 1cf459cd8..5279e659a 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -1035,7 +1035,7 @@ int Tconv(Fmt *fp); int Tpretty(Fmt *fp, Type *t); int Zconv(Fmt *fp); Node* adddot(Node *n); -int adddot1(Sym *s, Type *t, int d, Type **save); +int adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase); Type* aindex(Node *b, Type *t); int algtype(Type *t); void argtype(Node *on, Type *t); @@ -1066,7 +1066,7 @@ Type** getoutarg(Type *t); Type* getoutargx(Type *t); Type** getthis(Type *t); Type* getthisx(Type *t); -int implements(Type *t, Type *iface, Type **m, Type **samename); +int implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr); void importdot(Pkg *opkg, Node *pack); int is64(Type *t); int isblank(Node *n); diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c index 97d92e1dc..8738eb41b 100644 --- a/src/cmd/gc/print.c +++ b/src/cmd/gc/print.c @@ -348,7 +348,10 @@ exprfmt(Fmt *f, Node *n, int prec) fmtprint(f, "(%T)(", n->type); else fmtprint(f, "%T(", n->type); - exprfmt(f, n->left, 0); + if(n->left == N) + exprlistfmt(f, n->list); + else + exprfmt(f, n->left, 0); fmtprint(f, ")"); break; diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 567ac5a49..b47ccbf73 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -807,6 +807,7 @@ goopnames[] = [OAS] = "=", [OAS2] = "=", [OBREAK] = "break", + [OCALL] = "function call", [OCAP] = "cap", [OCASE] = "case", [OCLOSED] = "closed", @@ -1814,6 +1815,7 @@ int assignop(Type *src, Type *dst, char **why) { Type *missing, *have; + int ptr; if(why != nil) *why = ""; @@ -1839,17 +1841,24 @@ assignop(Type *src, Type *dst, char **why) // 3. dst is an interface type and src implements dst. if(dst->etype == TINTER && src->etype != TNIL) { - if(implements(src, dst, &missing, &have)) + if(implements(src, dst, &missing, &have, &ptr)) return OCONVIFACE; if(why != nil) { if(isptrto(src, TINTER)) - *why = smprint(": %T is pointer to interface, not interface", src); + *why = smprint(":\n\t%T is pointer to interface, not interface", src); + else if(have && have->sym == missing->sym) + *why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n" + "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym, + have->sym, have->type, missing->sym, missing->type); + else if(ptr) + *why = smprint(":\n\t%T does not implement %T (%S method requires pointer receiver)", + src, dst, missing->sym); else if(have) - *why = smprint(": %T does not implement %T (wrong type for %S method)\n" - "\thave %S%hhT\n\twant %S%hhT", src, dst, missing->sym, + *why = smprint(":\n\t%T does not implement %T (missing %S method)\n" + "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym, have->sym, have->type, missing->sym, missing->type); else - *why = smprint(": %T does not implement %T (missing %S method)", + *why = smprint(":\n\t%T does not implement %T (missing %S method)", src, dst, missing->sym); } return 0; @@ -2655,6 +2664,30 @@ setmaxarg(Type *t) maxarg = w; } +/* unicode-aware case-insensitive strcmp */ + +static int +cistrcmp(char *p, char *q) +{ + Rune rp, rq; + + while(*p || *q) { + if(*p == 0) + return +1; + if(*q == 0) + return -1; + p += chartorune(&rp, p); + q += chartorune(&rq, q); + rp = tolowerrune(rp); + rq = tolowerrune(rq); + if(rp < rq) + return -1; + if(rp > rq) + return +1; + } + return 0; +} + /* * code to resolve elided DOTs * in embedded types @@ -2664,7 +2697,7 @@ setmaxarg(Type *t) // return count of fields+methods // found with a given name static int -lookdot0(Sym *s, Type *t, Type **save) +lookdot0(Sym *s, Type *t, Type **save, int ignorecase) { Type *f, *u; int c; @@ -2676,7 +2709,7 @@ lookdot0(Sym *s, Type *t, Type **save) c = 0; if(u->etype == TSTRUCT || u->etype == TINTER) { for(f=u->type; f!=T; f=f->down) - if(f->sym == s) { + if(f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0)) { if(save) *save = f; c++; @@ -2685,7 +2718,7 @@ lookdot0(Sym *s, Type *t, Type **save) u = methtype(t); if(u != T) { for(f=u->method; f!=T; f=f->down) - if(f->sym == s && f->embedded == 0) { + if(f->embedded == 0 && (f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0))) { if(save) *save = f; c++; @@ -2700,7 +2733,7 @@ lookdot0(Sym *s, Type *t, Type **save) // answer is in dotlist array and // count of number of ways is returned. int -adddot1(Sym *s, Type *t, int d, Type **save) +adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase) { Type *f, *u; int c, a; @@ -2710,7 +2743,7 @@ adddot1(Sym *s, Type *t, int d, Type **save) t->trecur = 1; if(d == 0) { - c = lookdot0(s, t, save); + c = lookdot0(s, t, save, ignorecase); goto out; } @@ -2727,7 +2760,7 @@ adddot1(Sym *s, Type *t, int d, Type **save) continue; if(f->sym == S) continue; - a = adddot1(s, f->type, d, save); + a = adddot1(s, f->type, d, save, ignorecase); if(a != 0 && c == 0) dotlist[d].field = f; c += a; @@ -2764,7 +2797,7 @@ adddot(Node *n) goto ret; for(d=0; d<nelem(dotlist); d++) { - c = adddot1(s, t, d, nil); + c = adddot1(s, t, d, nil, 0); if(c > 0) goto out; } @@ -2902,7 +2935,7 @@ expandmeth(Sym *s, Type *t) for(sl=slist; sl!=nil; sl=sl->link) { sl->field->sym->flags &= ~SymUniq; for(d=0; d<nelem(dotlist); d++) { - c = adddot1(sl->field->sym, t, d, &f); + c = adddot1(sl->field->sym, t, d, &f, 0); if(c == 0) continue; if(c == 1) { @@ -3035,7 +3068,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam) } static Type* -ifacelookdot(Sym *s, Type *t, int *followptr) +ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase) { int i, c, d; Type *m; @@ -3046,7 +3079,7 @@ ifacelookdot(Sym *s, Type *t, int *followptr) return T; for(d=0; d<nelem(dotlist); d++) { - c = adddot1(s, t, d, &m); + c = adddot1(s, t, d, &m, ignorecase); if(c > 1) { yyerror("%T.%S is ambiguous", t, s); return T; @@ -3069,7 +3102,7 @@ ifacelookdot(Sym *s, Type *t, int *followptr) } int -implements(Type *t, Type *iface, Type **m, Type **samename) +implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr) { Type *t0, *im, *tm, *rcvr, *imtype; int followptr; @@ -3090,11 +3123,13 @@ implements(Type *t, Type *iface, Type **m, Type **samename) goto found; *m = im; *samename = tm; + *ptr = 0; return 0; } } *m = im; *samename = nil; + *ptr = 0; return 0; found:; } @@ -3106,10 +3141,14 @@ implements(Type *t, Type *iface, Type **m, Type **samename) expandmeth(t->sym, t); for(im=iface->type; im; im=im->down) { imtype = methodfunc(im->type, 0); - tm = ifacelookdot(im->sym, t, &followptr); + tm = ifacelookdot(im->sym, t, &followptr, 0); if(tm == T || !eqtype(methodfunc(tm->type, 0), imtype)) { +print("try case\n"); + if(tm == T) + tm = ifacelookdot(im->sym, t, &followptr, 1); *m = im; *samename = tm; + *ptr = 0; return 0; } // if pointer receiver in method, @@ -3120,6 +3159,7 @@ implements(Type *t, Type *iface, Type **m, Type **samename) yyerror("interface pointer mismatch"); *m = im; *samename = nil; + *ptr = 1; return 0; } } diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 83537177c..457b82b4c 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -14,7 +14,7 @@ #include "go.h" static void implicitstar(Node**); -static int onearg(Node*); +static int onearg(Node*, char*, ...); static int twoarg(Node*); static int lookdot(Node*, Type*, int); static void typecheckaste(int, Type*, NodeList*, char*); @@ -63,7 +63,7 @@ typechecklist(NodeList *l, int top) Node* typecheck(Node **np, int top) { - int et, op; + int et, op, ptr; Node *n, *l, *r; NodeList *args; int lno, ok, ntop; @@ -532,7 +532,7 @@ reswitch: goto error; } if(n->type != T && n->type->etype != TINTER) - if(!implements(n->type, t, &missing, &have)) { + if(!implements(n->type, t, &missing, &have, &ptr)) { if(have) yyerror("impossible type assertion: %+N cannot have dynamic type %T" " (wrong type for %S method)\n\thave %S%hhT\n\twant %S%hhT", @@ -710,10 +710,10 @@ reswitch: ok |= Erv; // turn CALL(type, arg) into CONV(arg) w/ type n->left = N; - if(onearg(n) < 0) - goto error; n->op = OCONV; n->type = l->type; + if(onearg(n, "conversion to %T", l->type) < 0) + goto error; goto doconv; } @@ -770,7 +770,7 @@ reswitch: case OREAL: case OIMAG: ok |= Erv; - if(onearg(n) < 0) + if(onearg(n, "%#O", n->op) < 0) goto error; typecheck(&n->left, Erv); defaultlit(&n->left, T); @@ -850,7 +850,7 @@ reswitch: case OCLOSED: case OCLOSE: - if(onearg(n) < 0) + if(onearg(n, "%#O", n->op) < 0) goto error; typecheck(&n->left, Erv); defaultlit(&n->left, T); @@ -1053,7 +1053,7 @@ reswitch: case OPANIC: ok |= Etop; - if(onearg(n) < 0) + if(onearg(n, "panic") < 0) goto error; typecheck(&n->left, Erv); defaultlit(&n->left, T); @@ -1273,20 +1273,30 @@ implicitstar(Node **nn) } static int -onearg(Node *n) +onearg(Node *n, char *f, ...) { + va_list arg; + char *p; + if(n->left != N) return 0; if(n->list == nil) { - yyerror("missing argument to %#O - %#N", n->op, n); + va_start(arg, f); + p = vsmprint(f, arg); + va_end(arg); + yyerror("missing argument to %s: %#N", p, n); return -1; } - n->left = n->list->n; if(n->list->next != nil) { - yyerror("too many arguments to %#O", n->op); + va_start(arg, f); + p = vsmprint(f, arg); + va_end(arg); + yyerror("too many arguments to %s: %#N", p, n); + n->left = n->list->n; n->list = nil; return -1; } + n->left = n->list->n; n->list = nil; return 0; } @@ -1307,7 +1317,7 @@ twoarg(Node *n) return -1; } if(n->list->next->next != nil) { - yyerror("too many arguments to %#O", n->op); + yyerror("too many arguments to %#O - %#N", n->op, n); n->list = nil; return -1; } |