diff options
author | Russ Cox <rsc@golang.org> | 2009-02-11 17:57:29 -0800 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2009-02-11 17:57:29 -0800 |
commit | 008493aa07f551d5d2c1ea9bb734f187f4760c9f (patch) | |
tree | 06bf06370e7d1abddc371dff7045434e94a0a692 /src/cmd/gc/subr.c | |
parent | f6d092aa89daccb517a89abaa9e077a683b57bf1 (diff) | |
download | golang-008493aa07f551d5d2c1ea9bb734f187f4760c9f.tar.gz |
require type assertions when narrowing.
R=ken
OCL=24350
CL=24914
Diffstat (limited to 'src/cmd/gc/subr.c')
-rw-r--r-- | src/cmd/gc/subr.c | 73 |
1 files changed, 59 insertions, 14 deletions
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 87bd2f20a..841f5c361 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -2735,12 +2735,13 @@ struct Icheck Type *dst; Type *src; int lineno; + int explicit; }; Icheck *icheck; Icheck *ichecktail; void -ifacecheck(Type *dst, Type *src, int lineno) +ifacecheck(Type *dst, Type *src, int lineno, int explicit) { Icheck *p; @@ -2752,6 +2753,7 @@ ifacecheck(Type *dst, Type *src, int lineno) p->dst = dst; p->src = src; p->lineno = lineno; + p->explicit = explicit; ichecktail = p; } @@ -2761,6 +2763,9 @@ ifacelookdot(Sym *s, Type *t) int c, d; Type *m; + if(t == T) + return T; + for(d=0; d<nelem(dotlist); d++) { c = adddot1(s, t, d, &m); if(c > 1) { @@ -2773,15 +2778,15 @@ ifacelookdot(Sym *s, Type *t) return T; } +// check whether non-interface type t +// satisifes inteface type iface. int -hasiface(Type *t, Type *iface, Type **m) +ifaceokT2I(Type *t, Type *iface, Type **m) { Type *im, *tm; int imhash; t = methtype(t); - if(t == T) - return 0; // if this is too slow, // could sort these first @@ -2805,26 +2810,66 @@ hasiface(Type *t, Type *iface, Type **m) return 1; } +// check whether interface type i1 satisifes interface type i2. +int +ifaceokI2I(Type *i1, Type *i2, Type **m) +{ + Type *m1, *m2; + + // if this is too slow, + // could sort these first + // and then do one loop. + + for(m2=i2->type; m2; m2=m2->down) { + for(m1=i1->type; m1; m1=m1->down) + if(m1->sym == m2->sym && typehash(m1, 0) == typehash(m2, 0)) + goto found; + *m = m2; + return 0; + found:; + } + return 1; +} + void runifacechecks(void) { Icheck *p; - int lno; - Type *m, *l, *r; + int lno, wrong, needexplicit; + Type *m, *t, *iface; lno = lineno; for(p=icheck; p; p=p->next) { lineno = p->lineno; - if(isinter(p->dst)) { - l = p->src; - r = p->dst; + wrong = 0; + needexplicit = 0; + m = nil; + if(isinter(p->dst) && isinter(p->src)) { + iface = p->dst; + t = p->src; + needexplicit = !ifaceokI2I(t, iface, &m); + } + else if(isinter(p->dst)) { + t = p->src; + iface = p->dst; + wrong = !ifaceokT2I(t, iface, &m); } else { - l = p->dst; - r = p->src; + t = p->dst; + iface = p->src; + wrong = !ifaceokT2I(t, iface, &m); + needexplicit = 1; + } + if(wrong) + yyerror("%T is not %T\n\tmissing %S%hhT", + t, iface, m->sym, m->type); + else if(!p->explicit && needexplicit) { + if(m) + yyerror("need explicit conversion to use %T as %T\n\tmissing %S%hhT", + p->src, p->dst, m->sym, m->type); + else + yyerror("need explicit conversion to use %T as %T", + p->src, p->dst); } - if(!hasiface(l, r, &m)) - yyerror("%T is not %T - missing %S%hhT", - l, r, m->sym, m->type); } lineno = lno; } |