mirror of
https://github.com/golang/go
synced 2024-11-22 02:04:40 -07:00
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 https://golang.org/cl/1736041
This commit is contained in:
parent
ceb868bf0a
commit
a212d174ac
@ -645,7 +645,7 @@ genembedtramp(Type *rcvr, Type *method, Sym *newnam)
|
|||||||
|
|
||||||
e = method->sym;
|
e = method->sym;
|
||||||
for(d=0; d<nelem(dotlist); d++) {
|
for(d=0; d<nelem(dotlist); d++) {
|
||||||
c = adddot1(e, rcvr, d, nil);
|
c = adddot1(e, rcvr, d, nil, 0);
|
||||||
if(c == 1)
|
if(c == 1)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -645,7 +645,7 @@ genembedtramp(Type *rcvr, Type *method, Sym *newnam)
|
|||||||
|
|
||||||
e = method->sym;
|
e = method->sym;
|
||||||
for(d=0; d<nelem(dotlist); d++) {
|
for(d=0; d<nelem(dotlist); d++) {
|
||||||
c = adddot1(e, rcvr, d, nil);
|
c = adddot1(e, rcvr, d, nil, 0);
|
||||||
if(c == 1)
|
if(c == 1)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -651,7 +651,7 @@ genembedtramp(Type *rcvr, Type *method, Sym *newnam)
|
|||||||
|
|
||||||
e = method->sym;
|
e = method->sym;
|
||||||
for(d=0; d<nelem(dotlist); d++) {
|
for(d=0; d<nelem(dotlist); d++) {
|
||||||
c = adddot1(e, rcvr, d, nil);
|
c = adddot1(e, rcvr, d, nil, 0);
|
||||||
if(c == 1)
|
if(c == 1)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1035,7 +1035,7 @@ int Tconv(Fmt *fp);
|
|||||||
int Tpretty(Fmt *fp, Type *t);
|
int Tpretty(Fmt *fp, Type *t);
|
||||||
int Zconv(Fmt *fp);
|
int Zconv(Fmt *fp);
|
||||||
Node* adddot(Node *n);
|
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);
|
Type* aindex(Node *b, Type *t);
|
||||||
int algtype(Type *t);
|
int algtype(Type *t);
|
||||||
void argtype(Node *on, Type *t);
|
void argtype(Node *on, Type *t);
|
||||||
@ -1066,7 +1066,7 @@ Type** getoutarg(Type *t);
|
|||||||
Type* getoutargx(Type *t);
|
Type* getoutargx(Type *t);
|
||||||
Type** getthis(Type *t);
|
Type** getthis(Type *t);
|
||||||
Type* getthisx(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);
|
void importdot(Pkg *opkg, Node *pack);
|
||||||
int is64(Type *t);
|
int is64(Type *t);
|
||||||
int isblank(Node *n);
|
int isblank(Node *n);
|
||||||
|
@ -348,7 +348,10 @@ exprfmt(Fmt *f, Node *n, int prec)
|
|||||||
fmtprint(f, "(%T)(", n->type);
|
fmtprint(f, "(%T)(", n->type);
|
||||||
else
|
else
|
||||||
fmtprint(f, "%T(", n->type);
|
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, ")");
|
fmtprint(f, ")");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -807,6 +807,7 @@ goopnames[] =
|
|||||||
[OAS] = "=",
|
[OAS] = "=",
|
||||||
[OAS2] = "=",
|
[OAS2] = "=",
|
||||||
[OBREAK] = "break",
|
[OBREAK] = "break",
|
||||||
|
[OCALL] = "function call",
|
||||||
[OCAP] = "cap",
|
[OCAP] = "cap",
|
||||||
[OCASE] = "case",
|
[OCASE] = "case",
|
||||||
[OCLOSED] = "closed",
|
[OCLOSED] = "closed",
|
||||||
@ -1814,6 +1815,7 @@ int
|
|||||||
assignop(Type *src, Type *dst, char **why)
|
assignop(Type *src, Type *dst, char **why)
|
||||||
{
|
{
|
||||||
Type *missing, *have;
|
Type *missing, *have;
|
||||||
|
int ptr;
|
||||||
|
|
||||||
if(why != nil)
|
if(why != nil)
|
||||||
*why = "";
|
*why = "";
|
||||||
@ -1839,17 +1841,24 @@ assignop(Type *src, Type *dst, char **why)
|
|||||||
|
|
||||||
// 3. dst is an interface type and src implements dst.
|
// 3. dst is an interface type and src implements dst.
|
||||||
if(dst->etype == TINTER && src->etype != TNIL) {
|
if(dst->etype == TINTER && src->etype != TNIL) {
|
||||||
if(implements(src, dst, &missing, &have))
|
if(implements(src, dst, &missing, &have, &ptr))
|
||||||
return OCONVIFACE;
|
return OCONVIFACE;
|
||||||
if(why != nil) {
|
if(why != nil) {
|
||||||
if(isptrto(src, TINTER))
|
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)
|
else if(have)
|
||||||
*why = smprint(": %T does not implement %T (wrong type for %S method)\n"
|
*why = smprint(":\n\t%T does not implement %T (missing %S method)\n"
|
||||||
"\thave %S%hhT\n\twant %S%hhT", src, dst, missing->sym,
|
"\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
|
||||||
have->sym, have->type, missing->sym, missing->type);
|
have->sym, have->type, missing->sym, missing->type);
|
||||||
else
|
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);
|
src, dst, missing->sym);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -2655,6 +2664,30 @@ setmaxarg(Type *t)
|
|||||||
maxarg = w;
|
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
|
* code to resolve elided DOTs
|
||||||
* in embedded types
|
* in embedded types
|
||||||
@ -2664,7 +2697,7 @@ setmaxarg(Type *t)
|
|||||||
// return count of fields+methods
|
// return count of fields+methods
|
||||||
// found with a given name
|
// found with a given name
|
||||||
static int
|
static int
|
||||||
lookdot0(Sym *s, Type *t, Type **save)
|
lookdot0(Sym *s, Type *t, Type **save, int ignorecase)
|
||||||
{
|
{
|
||||||
Type *f, *u;
|
Type *f, *u;
|
||||||
int c;
|
int c;
|
||||||
@ -2676,7 +2709,7 @@ lookdot0(Sym *s, Type *t, Type **save)
|
|||||||
c = 0;
|
c = 0;
|
||||||
if(u->etype == TSTRUCT || u->etype == TINTER) {
|
if(u->etype == TSTRUCT || u->etype == TINTER) {
|
||||||
for(f=u->type; f!=T; f=f->down)
|
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)
|
if(save)
|
||||||
*save = f;
|
*save = f;
|
||||||
c++;
|
c++;
|
||||||
@ -2685,7 +2718,7 @@ lookdot0(Sym *s, Type *t, Type **save)
|
|||||||
u = methtype(t);
|
u = methtype(t);
|
||||||
if(u != T) {
|
if(u != T) {
|
||||||
for(f=u->method; f!=T; f=f->down)
|
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)
|
if(save)
|
||||||
*save = f;
|
*save = f;
|
||||||
c++;
|
c++;
|
||||||
@ -2700,7 +2733,7 @@ lookdot0(Sym *s, Type *t, Type **save)
|
|||||||
// answer is in dotlist array and
|
// answer is in dotlist array and
|
||||||
// count of number of ways is returned.
|
// count of number of ways is returned.
|
||||||
int
|
int
|
||||||
adddot1(Sym *s, Type *t, int d, Type **save)
|
adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase)
|
||||||
{
|
{
|
||||||
Type *f, *u;
|
Type *f, *u;
|
||||||
int c, a;
|
int c, a;
|
||||||
@ -2710,7 +2743,7 @@ adddot1(Sym *s, Type *t, int d, Type **save)
|
|||||||
t->trecur = 1;
|
t->trecur = 1;
|
||||||
|
|
||||||
if(d == 0) {
|
if(d == 0) {
|
||||||
c = lookdot0(s, t, save);
|
c = lookdot0(s, t, save, ignorecase);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2727,7 +2760,7 @@ adddot1(Sym *s, Type *t, int d, Type **save)
|
|||||||
continue;
|
continue;
|
||||||
if(f->sym == S)
|
if(f->sym == S)
|
||||||
continue;
|
continue;
|
||||||
a = adddot1(s, f->type, d, save);
|
a = adddot1(s, f->type, d, save, ignorecase);
|
||||||
if(a != 0 && c == 0)
|
if(a != 0 && c == 0)
|
||||||
dotlist[d].field = f;
|
dotlist[d].field = f;
|
||||||
c += a;
|
c += a;
|
||||||
@ -2764,7 +2797,7 @@ adddot(Node *n)
|
|||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
for(d=0; d<nelem(dotlist); d++) {
|
for(d=0; d<nelem(dotlist); d++) {
|
||||||
c = adddot1(s, t, d, nil);
|
c = adddot1(s, t, d, nil, 0);
|
||||||
if(c > 0)
|
if(c > 0)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -2902,7 +2935,7 @@ expandmeth(Sym *s, Type *t)
|
|||||||
for(sl=slist; sl!=nil; sl=sl->link) {
|
for(sl=slist; sl!=nil; sl=sl->link) {
|
||||||
sl->field->sym->flags &= ~SymUniq;
|
sl->field->sym->flags &= ~SymUniq;
|
||||||
for(d=0; d<nelem(dotlist); d++) {
|
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)
|
if(c == 0)
|
||||||
continue;
|
continue;
|
||||||
if(c == 1) {
|
if(c == 1) {
|
||||||
@ -3035,7 +3068,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Type*
|
static Type*
|
||||||
ifacelookdot(Sym *s, Type *t, int *followptr)
|
ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase)
|
||||||
{
|
{
|
||||||
int i, c, d;
|
int i, c, d;
|
||||||
Type *m;
|
Type *m;
|
||||||
@ -3046,7 +3079,7 @@ ifacelookdot(Sym *s, Type *t, int *followptr)
|
|||||||
return T;
|
return T;
|
||||||
|
|
||||||
for(d=0; d<nelem(dotlist); d++) {
|
for(d=0; d<nelem(dotlist); d++) {
|
||||||
c = adddot1(s, t, d, &m);
|
c = adddot1(s, t, d, &m, ignorecase);
|
||||||
if(c > 1) {
|
if(c > 1) {
|
||||||
yyerror("%T.%S is ambiguous", t, s);
|
yyerror("%T.%S is ambiguous", t, s);
|
||||||
return T;
|
return T;
|
||||||
@ -3069,7 +3102,7 @@ ifacelookdot(Sym *s, Type *t, int *followptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
Type *t0, *im, *tm, *rcvr, *imtype;
|
||||||
int followptr;
|
int followptr;
|
||||||
@ -3090,11 +3123,13 @@ implements(Type *t, Type *iface, Type **m, Type **samename)
|
|||||||
goto found;
|
goto found;
|
||||||
*m = im;
|
*m = im;
|
||||||
*samename = tm;
|
*samename = tm;
|
||||||
|
*ptr = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*m = im;
|
*m = im;
|
||||||
*samename = nil;
|
*samename = nil;
|
||||||
|
*ptr = 0;
|
||||||
return 0;
|
return 0;
|
||||||
found:;
|
found:;
|
||||||
}
|
}
|
||||||
@ -3106,10 +3141,14 @@ implements(Type *t, Type *iface, Type **m, Type **samename)
|
|||||||
expandmeth(t->sym, t);
|
expandmeth(t->sym, t);
|
||||||
for(im=iface->type; im; im=im->down) {
|
for(im=iface->type; im; im=im->down) {
|
||||||
imtype = methodfunc(im->type, 0);
|
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)) {
|
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;
|
*m = im;
|
||||||
*samename = tm;
|
*samename = tm;
|
||||||
|
*ptr = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// if pointer receiver in method,
|
// if pointer receiver in method,
|
||||||
@ -3120,6 +3159,7 @@ implements(Type *t, Type *iface, Type **m, Type **samename)
|
|||||||
yyerror("interface pointer mismatch");
|
yyerror("interface pointer mismatch");
|
||||||
*m = im;
|
*m = im;
|
||||||
*samename = nil;
|
*samename = nil;
|
||||||
|
*ptr = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
#include "go.h"
|
#include "go.h"
|
||||||
|
|
||||||
static void implicitstar(Node**);
|
static void implicitstar(Node**);
|
||||||
static int onearg(Node*);
|
static int onearg(Node*, char*, ...);
|
||||||
static int twoarg(Node*);
|
static int twoarg(Node*);
|
||||||
static int lookdot(Node*, Type*, int);
|
static int lookdot(Node*, Type*, int);
|
||||||
static void typecheckaste(int, Type*, NodeList*, char*);
|
static void typecheckaste(int, Type*, NodeList*, char*);
|
||||||
@ -63,7 +63,7 @@ typechecklist(NodeList *l, int top)
|
|||||||
Node*
|
Node*
|
||||||
typecheck(Node **np, int top)
|
typecheck(Node **np, int top)
|
||||||
{
|
{
|
||||||
int et, op;
|
int et, op, ptr;
|
||||||
Node *n, *l, *r;
|
Node *n, *l, *r;
|
||||||
NodeList *args;
|
NodeList *args;
|
||||||
int lno, ok, ntop;
|
int lno, ok, ntop;
|
||||||
@ -532,7 +532,7 @@ reswitch:
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if(n->type != T && n->type->etype != TINTER)
|
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)
|
if(have)
|
||||||
yyerror("impossible type assertion: %+N cannot have dynamic type %T"
|
yyerror("impossible type assertion: %+N cannot have dynamic type %T"
|
||||||
" (wrong type for %S method)\n\thave %S%hhT\n\twant %S%hhT",
|
" (wrong type for %S method)\n\thave %S%hhT\n\twant %S%hhT",
|
||||||
@ -710,10 +710,10 @@ reswitch:
|
|||||||
ok |= Erv;
|
ok |= Erv;
|
||||||
// turn CALL(type, arg) into CONV(arg) w/ type
|
// turn CALL(type, arg) into CONV(arg) w/ type
|
||||||
n->left = N;
|
n->left = N;
|
||||||
if(onearg(n) < 0)
|
|
||||||
goto error;
|
|
||||||
n->op = OCONV;
|
n->op = OCONV;
|
||||||
n->type = l->type;
|
n->type = l->type;
|
||||||
|
if(onearg(n, "conversion to %T", l->type) < 0)
|
||||||
|
goto error;
|
||||||
goto doconv;
|
goto doconv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -770,7 +770,7 @@ reswitch:
|
|||||||
case OREAL:
|
case OREAL:
|
||||||
case OIMAG:
|
case OIMAG:
|
||||||
ok |= Erv;
|
ok |= Erv;
|
||||||
if(onearg(n) < 0)
|
if(onearg(n, "%#O", n->op) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
typecheck(&n->left, Erv);
|
typecheck(&n->left, Erv);
|
||||||
defaultlit(&n->left, T);
|
defaultlit(&n->left, T);
|
||||||
@ -850,7 +850,7 @@ reswitch:
|
|||||||
|
|
||||||
case OCLOSED:
|
case OCLOSED:
|
||||||
case OCLOSE:
|
case OCLOSE:
|
||||||
if(onearg(n) < 0)
|
if(onearg(n, "%#O", n->op) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
typecheck(&n->left, Erv);
|
typecheck(&n->left, Erv);
|
||||||
defaultlit(&n->left, T);
|
defaultlit(&n->left, T);
|
||||||
@ -1053,7 +1053,7 @@ reswitch:
|
|||||||
|
|
||||||
case OPANIC:
|
case OPANIC:
|
||||||
ok |= Etop;
|
ok |= Etop;
|
||||||
if(onearg(n) < 0)
|
if(onearg(n, "panic") < 0)
|
||||||
goto error;
|
goto error;
|
||||||
typecheck(&n->left, Erv);
|
typecheck(&n->left, Erv);
|
||||||
defaultlit(&n->left, T);
|
defaultlit(&n->left, T);
|
||||||
@ -1273,20 +1273,30 @@ implicitstar(Node **nn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
onearg(Node *n)
|
onearg(Node *n, char *f, ...)
|
||||||
{
|
{
|
||||||
|
va_list arg;
|
||||||
|
char *p;
|
||||||
|
|
||||||
if(n->left != N)
|
if(n->left != N)
|
||||||
return 0;
|
return 0;
|
||||||
if(n->list == nil) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
n->left = n->list->n;
|
|
||||||
if(n->list->next != nil) {
|
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;
|
n->list = nil;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
n->left = n->list->n;
|
||||||
n->list = nil;
|
n->list = nil;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1307,7 +1317,7 @@ twoarg(Node *n)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(n->list->next->next != nil) {
|
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;
|
n->list = nil;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -724,10 +724,8 @@ sub RunWeb {
|
|||||||
"firefox",
|
"firefox",
|
||||||
);
|
);
|
||||||
foreach my $b (@alt) {
|
foreach my $b (@alt) {
|
||||||
if (-f $b) {
|
if (system($b, $fname) == 0) {
|
||||||
if (system($b, $fname) == 0) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Color type, as per the PNG spec.
|
// Color type, as per the PNG spec.
|
||||||
@ -108,7 +109,7 @@ func (d *decoder) parseIHDR(r io.Reader, crc hash.Hash32, length uint32) os.Erro
|
|||||||
}
|
}
|
||||||
crc.Write(d.tmp[0:13])
|
crc.Write(d.tmp[0:13])
|
||||||
if d.tmp[8] != 8 {
|
if d.tmp[8] != 8 {
|
||||||
return UnsupportedError("bit depth")
|
return UnsupportedError("bit depth " + strconv.Itoa(int(d.tmp[8])))
|
||||||
}
|
}
|
||||||
if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 {
|
if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 {
|
||||||
return UnsupportedError("compression, filter or interlace method")
|
return UnsupportedError("compression, filter or interlace method")
|
||||||
|
@ -93,7 +93,13 @@ func (client *Client) input() {
|
|||||||
c := client.pending[seq]
|
c := client.pending[seq]
|
||||||
client.pending[seq] = c, false
|
client.pending[seq] = c, false
|
||||||
client.mutex.Unlock()
|
client.mutex.Unlock()
|
||||||
|
if c == nil {
|
||||||
|
err = os.NewError("invalid response sequence number")
|
||||||
|
break
|
||||||
|
}
|
||||||
err = client.codec.ReadResponseBody(c.Reply)
|
err = client.codec.ReadResponseBody(c.Reply)
|
||||||
|
// TODO(rsc): Should look at err, but breaks tests.
|
||||||
|
|
||||||
// Empty strings should turn into nil os.Errors
|
// Empty strings should turn into nil os.Errors
|
||||||
if response.Error != "" {
|
if response.Error != "" {
|
||||||
c.Error = os.ErrorString(response.Error)
|
c.Error = os.ErrorString(response.Error)
|
||||||
|
@ -58,7 +58,8 @@ func TestServer(t *testing.T) {
|
|||||||
|
|
||||||
cli, srv := net.Pipe()
|
cli, srv := net.Pipe()
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
go ServeConn(srv)
|
var ci rpc.ClientInfo
|
||||||
|
go ServeConn(srv, &ci)
|
||||||
dec := json.NewDecoder(cli)
|
dec := json.NewDecoder(cli)
|
||||||
|
|
||||||
// Send hand-coded requests to server, parse responses.
|
// Send hand-coded requests to server, parse responses.
|
||||||
@ -84,8 +85,9 @@ func TestServer(t *testing.T) {
|
|||||||
func TestClient(t *testing.T) {
|
func TestClient(t *testing.T) {
|
||||||
// Assume server is okay (TestServer is above).
|
// Assume server is okay (TestServer is above).
|
||||||
// Test client against server.
|
// Test client against server.
|
||||||
|
var ci rpc.ClientInfo
|
||||||
cli, srv := net.Pipe()
|
cli, srv := net.Pipe()
|
||||||
go ServeConn(srv)
|
go ServeConn(srv, &ci)
|
||||||
|
|
||||||
client := NewClient(cli)
|
client := NewClient(cli)
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
@ -118,6 +118,6 @@ func (c *serverCodec) Close() os.Error {
|
|||||||
// ServeConn runs the JSON-RPC server on a single connection.
|
// ServeConn runs the JSON-RPC server on a single connection.
|
||||||
// ServeConn blocks, serving the connection until the client hangs up.
|
// ServeConn blocks, serving the connection until the client hangs up.
|
||||||
// The caller typically invokes ServeConn in a go statement.
|
// The caller typically invokes ServeConn in a go statement.
|
||||||
func ServeConn(conn io.ReadWriteCloser) {
|
func ServeConn(conn io.ReadWriteCloser, ci *rpc.ClientInfo) {
|
||||||
rpc.ServeCodec(NewServerCodec(conn))
|
rpc.ServeCodec(NewServerCodec(conn), ci)
|
||||||
}
|
}
|
||||||
|
@ -158,6 +158,12 @@ type Response struct {
|
|||||||
Error string // error, if any.
|
Error string // error, if any.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClientInfo records information about an RPC client connection.
|
||||||
|
type ClientInfo struct {
|
||||||
|
LocalAddr string
|
||||||
|
RemoteAddr string
|
||||||
|
}
|
||||||
|
|
||||||
type serverType struct {
|
type serverType struct {
|
||||||
sync.Mutex // protects the serviceMap
|
sync.Mutex // protects the serviceMap
|
||||||
serviceMap map[string]*service
|
serviceMap map[string]*service
|
||||||
@ -208,7 +214,7 @@ func (server *serverType) register(rcvr interface{}) os.Error {
|
|||||||
}
|
}
|
||||||
// Method needs three ins: receiver, *args, *reply.
|
// Method needs three ins: receiver, *args, *reply.
|
||||||
// The args and reply must be structs until gobs are more general.
|
// The args and reply must be structs until gobs are more general.
|
||||||
if mtype.NumIn() != 3 {
|
if mtype.NumIn() != 3 && mtype.NumIn() != 4 {
|
||||||
log.Stderr("method", mname, "has wrong number of ins:", mtype.NumIn())
|
log.Stderr("method", mname, "has wrong number of ins:", mtype.NumIn())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -238,6 +244,13 @@ func (server *serverType) register(rcvr interface{}) os.Error {
|
|||||||
log.Stderr(mname, "reply type not public:", replyType)
|
log.Stderr(mname, "reply type not public:", replyType)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if mtype.NumIn() == 4 {
|
||||||
|
t := mtype.In(3)
|
||||||
|
if t != reflect.Typeof((*ClientInfo)(nil)) {
|
||||||
|
log.Stderr(mname, "last argument not *ClientInfo")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
// Method needs one out: os.Error.
|
// Method needs one out: os.Error.
|
||||||
if mtype.NumOut() != 1 {
|
if mtype.NumOut() != 1 {
|
||||||
log.Stderr("method", mname, "has wrong number of outs:", mtype.NumOut())
|
log.Stderr("method", mname, "has wrong number of outs:", mtype.NumOut())
|
||||||
@ -288,13 +301,19 @@ func sendResponse(sending *sync.Mutex, req *Request, reply interface{}, codec Se
|
|||||||
sending.Unlock()
|
sending.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) call(sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec) {
|
func (s *service) call(sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec, ci *ClientInfo) {
|
||||||
mtype.Lock()
|
mtype.Lock()
|
||||||
mtype.numCalls++
|
mtype.numCalls++
|
||||||
mtype.Unlock()
|
mtype.Unlock()
|
||||||
function := mtype.method.Func
|
function := mtype.method.Func
|
||||||
// Invoke the method, providing a new value for the reply.
|
// Invoke the method, providing a new value for the reply.
|
||||||
returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv})
|
var args []reflect.Value
|
||||||
|
if mtype.method.Type.NumIn() == 3 {
|
||||||
|
args = []reflect.Value{s.rcvr, argv, replyv}
|
||||||
|
} else {
|
||||||
|
args = []reflect.Value{s.rcvr, argv, replyv, reflect.NewValue(ci)}
|
||||||
|
}
|
||||||
|
returnValues := function.Call(args)
|
||||||
// The return value for the method is an os.Error.
|
// The return value for the method is an os.Error.
|
||||||
errInter := returnValues[0].Interface()
|
errInter := returnValues[0].Interface()
|
||||||
errmsg := ""
|
errmsg := ""
|
||||||
@ -329,7 +348,7 @@ func (c *gobServerCodec) Close() os.Error {
|
|||||||
return c.rwc.Close()
|
return c.rwc.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *serverType) input(codec ServerCodec) {
|
func (server *serverType) input(codec ServerCodec, ci *ClientInfo) {
|
||||||
sending := new(sync.Mutex)
|
sending := new(sync.Mutex)
|
||||||
for {
|
for {
|
||||||
// Grab the request header.
|
// Grab the request header.
|
||||||
@ -376,7 +395,7 @@ func (server *serverType) input(codec ServerCodec) {
|
|||||||
sendResponse(sending, req, replyv.Interface(), codec, err.String())
|
sendResponse(sending, req, replyv.Interface(), codec, err.String())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
go service.call(sending, mtype, req, argv, replyv, codec)
|
go service.call(sending, mtype, req, argv, replyv, codec, ci)
|
||||||
}
|
}
|
||||||
codec.Close()
|
codec.Close()
|
||||||
}
|
}
|
||||||
@ -387,7 +406,7 @@ func (server *serverType) accept(lis net.Listener) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit?
|
log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit?
|
||||||
}
|
}
|
||||||
go ServeConn(conn)
|
go ServeConn(conn, &ClientInfo{conn.LocalAddr().String(), conn.RemoteAddr().String()})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,14 +438,14 @@ type ServerCodec interface {
|
|||||||
// The caller typically invokes ServeConn in a go statement.
|
// The caller typically invokes ServeConn in a go statement.
|
||||||
// ServeConn uses the gob wire format (see package gob) on the
|
// ServeConn uses the gob wire format (see package gob) on the
|
||||||
// connection. To use an alternate codec, use ServeCodec.
|
// connection. To use an alternate codec, use ServeCodec.
|
||||||
func ServeConn(conn io.ReadWriteCloser) {
|
func ServeConn(conn io.ReadWriteCloser, ci *ClientInfo) {
|
||||||
ServeCodec(&gobServerCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(conn)})
|
ServeCodec(&gobServerCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(conn)}, ci)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeCodec is like ServeConn but uses the specified codec to
|
// ServeCodec is like ServeConn but uses the specified codec to
|
||||||
// decode requests and encode responses.
|
// decode requests and encode responses.
|
||||||
func ServeCodec(codec ServerCodec) {
|
func ServeCodec(codec ServerCodec, ci *ClientInfo) {
|
||||||
server.input(codec)
|
server.input(codec, ci)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accept accepts connections on the listener and serves requests
|
// Accept accepts connections on the listener and serves requests
|
||||||
@ -452,7 +471,11 @@ func serveHTTP(c *http.Conn, req *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
|
io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
|
||||||
ServeConn(conn)
|
ci := &ClientInfo{
|
||||||
|
LocalAddr: conn.(net.Conn).LocalAddr().String(),
|
||||||
|
RemoteAddr: c.RemoteAddr,
|
||||||
|
}
|
||||||
|
ServeConn(conn, ci)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleHTTP registers an HTTP handler for RPC messages.
|
// HandleHTTP registers an HTTP handler for RPC messages.
|
||||||
|
@ -48,7 +48,6 @@
|
|||||||
# ./gc.go
|
# ./gc.go
|
||||||
# ./gc1.go
|
# ./gc1.go
|
||||||
./hashmap.go
|
./hashmap.go
|
||||||
./hilbert.go
|
|
||||||
./helloworld.go
|
./helloworld.go
|
||||||
./if.go
|
./if.go
|
||||||
./if1.go
|
./if1.go
|
||||||
@ -332,7 +331,6 @@ fixedbugs/bug149.go
|
|||||||
fixedbugs/bug150.go
|
fixedbugs/bug150.go
|
||||||
fixedbugs/bug151.go
|
fixedbugs/bug151.go
|
||||||
fixedbugs/bug152.go
|
fixedbugs/bug152.go
|
||||||
fixedbugs/bug153.go
|
|
||||||
# fixedbugs/bug154.go # needs floating point
|
# fixedbugs/bug154.go # needs floating point
|
||||||
fixedbugs/bug155.go
|
fixedbugs/bug155.go
|
||||||
fixedbugs/bug156.go
|
fixedbugs/bug156.go
|
||||||
|
Loading…
Reference in New Issue
Block a user