Node* chanop(Node*, int);
Node* arrayop(Node*, int);
Node* ifaceop(Type*, Node*, int);
-int ifaceas(Type*, Type*);
-int ifaceas1(Type*, Type*);
-void ifacecheck(Type*, Type*, int);
+int ifaceas(Type*, Type*, int);
+int ifaceas1(Type*, Type*, int);
+void ifacecheck(Type*, Type*, int, int);
void runifacechecks(void);
Node* convas(Node*);
void arrayconv(Type*, Node*);
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;
p->dst = dst;
p->src = src;
p->lineno = lineno;
+ p->explicit = explicit;
ichecktail = p;
}
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) {
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
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;
}
walktype(r->left, Erv);
if(r->left == N)
break;
- et = ifaceas1(r->type, r->left->type);
+ et = ifaceas1(r->type, r->left->type, 1);
switch(et) {
case I2T:
et = I2T2;
}
// interface assignment
- et = ifaceas(n->type, l->type);
+ et = ifaceas(n->type, l->type, 1);
if(et != Inone) {
indir(n, ifaceop(n->type, l, et));
goto ret;
* return op to use.
*/
int
-ifaceas1(Type *dst, Type *src)
+ifaceas1(Type *dst, Type *src, int explicit)
{
if(src == T || dst == T)
return Inone;
if(isinter(src)) {
if(eqtype(dst, src, 0))
return I2Isame;
+ if(!isnilinter(dst))
+ ifacecheck(dst, src, lineno, explicit);
return I2I;
}
if(isnilinter(dst))
return T2I;
- ifacecheck(dst, src, lineno);
+ ifacecheck(dst, src, lineno, explicit);
return T2I;
}
if(isinter(src)) {
- if(isnilinter(src))
- return I2T;
- ifacecheck(dst, src, lineno);
+ ifacecheck(dst, src, lineno, explicit);
return I2T;
}
return Inone;
* treat convert T to T as noop
*/
int
-ifaceas(Type *dst, Type *src)
+ifaceas(Type *dst, Type *src, int explicit)
{
int et;
- et = ifaceas1(dst, src);
+ et = ifaceas1(dst, src, explicit);
if(et == I2Isame)
et = Inone;
return et;
if(eqtype(lt, rt, 0))
goto out;
- et = ifaceas(lt, rt);
+ et = ifaceas(lt, rt, 0);
if(et != Inone) {
n->right = ifaceop(lt, r, et);
goto out;