return memcmp(a->s, b->s, a->len) == 0;
}
+typedef struct TypePairList TypePairList;
+struct TypePairList
+{
+ Type *t1;
+ Type *t2;
+ TypePairList *next;
+};
+
+static int
+onlist(TypePairList *l, Type *t1, Type *t2)
+{
+ for(; l; l=l->next)
+ if((l->t1 == t1 && l->t2 == t2) || (l->t1 == t2 && l->t2 == t1))
+ return 1;
+ return 0;
+}
+
+static int eqtype1(Type*, Type*, TypePairList*);
+
// Return 1 if t1 and t2 are identical, following the spec rules.
//
// Any cyclic type must go through a named type, and if one is
int
eqtype(Type *t1, Type *t2)
{
+ return eqtype1(t1, t2, nil);
+}
+
+static int
+eqtype1(Type *t1, Type *t2, TypePairList *assumed_equal)
+{
+ TypePairList l;
+
if(t1 == t2)
return 1;
if(t1 == T || t2 == T || t1->etype != t2->etype)
return 0;
}
+ if(onlist(assumed_equal, t1, t2))
+ return 1;
+ l.next = assumed_equal;
+ l.t1 = t1;
+ l.t2 = t2;
+
switch(t1->etype) {
case TINTER:
case TSTRUCT:
for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
if(t1->etype != TFIELD || t2->etype != TFIELD)
fatal("struct/interface missing field: %T %T", t1, t2);
- if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype(t1->type, t2->type) || !eqnote(t1->note, t2->note))
- return 0;
+ if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype1(t1->type, t2->type, &l) || !eqnote(t1->note, t2->note))
+ goto no;
}
- return t1 == T && t2 == T;
+ if(t1 == T && t2 == T)
+ goto yes;
+ goto no;
case TFUNC:
// Loop over structs: receiver, in, out.
for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) {
if(ta->etype != TFIELD || tb->etype != TFIELD)
fatal("func struct missing field: %T %T", ta, tb);
- if(ta->isddd != tb->isddd || !eqtype(ta->type, tb->type))
- return 0;
+ if(ta->isddd != tb->isddd || !eqtype1(ta->type, tb->type, &l))
+ goto no;
}
if(ta != T || tb != T)
- return 0;
+ goto no;
}
- return t1 == T && t2 == T;
+ if(t1 == T && t2 == T)
+ goto yes;
+ goto no;
case TARRAY:
if(t1->bound != t2->bound)
- return 0;
+ goto no;
break;
case TCHAN:
if(t1->chan != t2->chan)
- return 0;
+ goto no;
break;
}
- return eqtype(t1->down, t2->down) && eqtype(t1->type, t2->type);
+ if(eqtype1(t1->down, t2->down, &l) && eqtype1(t1->type, t2->type, &l))
+ goto yes;
+ goto no;
+
+yes:
+ assumed_equal = l.next;
+ return 1;
+
+no:
+ assumed_equal = l.next;
+ return 0;
}
// Are t1 and t2 equal struct types when field names are ignored?