summaryrefslogtreecommitdiff
path: root/src/cmd/gc
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2010-06-20 11:45:53 -0700
committerRuss Cox <rsc@golang.org>2010-06-20 11:45:53 -0700
commit3d434f2574c951249e9b317d3313617963673269 (patch)
tree9a814e6cb257c3224f01cfa0d9e827b687a5bc45 /src/cmd/gc
parent58da368d8786780b73dc3d094c5f81c34df07a10 (diff)
downloadgolang-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.h4
-rw-r--r--src/cmd/gc/print.c5
-rw-r--r--src/cmd/gc/subr.c74
-rw-r--r--src/cmd/gc/typecheck.c36
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;
}