Rune - Change regsave burden for syscalls
[rune.git] / librune / collapse.c
1 /*
2  * COLLAPSE.C   - Collapse Declarations and Types
3  *
4  * (c)Copyright 1993-2014, Matthew Dillon, All Rights Reserved.  See the  
5  *    COPYRIGHT file at the base of the distribution.
6  *
7  * This module is essentially optional but if we do not collapse duplicates
8  * the generated output will be massive to say the least.
9  *
10  * We can reach the entire tree by resolving the top-level import
11  * statement's DeclBlock.
12  */
13
14 #include "defs.h"
15 #include <dlfcn.h>
16
17 #if 0
18 static void CollapseClasses(Stmt *st);
19 #endif
20
21 static void collapseStmt(Stmt *st);
22 static void collapseDecl(Declaration *d, int dynamic);
23 static void collapseExp(Exp *exp);
24 static void collapseSemGroup(SemGroup *sg);
25 static void collapseType(Type **typep, Type *adjtype);
26
27 void
28 CollapseProject(Stmt *st)
29 {
30         Type *type;
31         int i;
32
33         dassert_stmt(st, st->st_Op == ST_Import);
34
35         /*
36          * All of our base types should collapse to themselves.  Easiest
37          * to just call it so the proper flags get set, otherwise they
38          * might not get generated.
39          */
40         for (i = 0; BaseTypeAry[i]; ++i) {
41                 type = BaseTypeAry[i];
42                 collapseType(&type, NULL);
43                 dassert(type == BaseTypeAry[i]);
44         }
45
46         /*
47          * General project
48          */
49         /*CollapseClasses(st);*/
50         collapseStmt(st);
51 }
52
53 #if 0
54 /*
55  * CollapseClasses()
56  */
57 static
58 void
59 CollapseClasses(Stmt *st)
60 {
61         /*
62          * Collapse interlock.
63          */
64         if (st == NULL)
65                 return;
66         if (st->st_Flags & (STF_COLLAPSING | STF_COLLAPSED))
67                 return;
68
69         if (st->st_Op == ST_Class && st->st_ClassStmt.es_Super) {
70                 collapseType(&st->st_ClassStmt.es_Super, NULL);
71                 collapseDecl(st->st_ClassStmt.es_Decl, 0);
72         }
73
74         /*
75          * If this is an ST_Import we must recurse through it.  The only
76          * statements under an Import should be Modules.  Well, really just
77          * one module.  And under that module we only care about ST_Import
78          * and ST_Class statements.
79          *
80          * If this is a shared import the statement list will be empty (later
81          * it may be used for import refinement, I dunno).  This is what we
82          * want since we should only resolve a shared import once.
83          */
84         if (st->st_Op == ST_Import) {
85                 Stmt *scan;
86
87                 st->st_Flags |= STF_COLLAPSING;
88                 RUNE_FOREACH(scan, &st->st_List, st_Node) {
89                         Stmt *scan2;
90
91                         dassert_stmt(scan, scan->st_Op == ST_Module);
92                         RUNE_FOREACH(scan2, &scan->st_List, st_Node) {
93                                 if (scan2->st_Op == ST_Import ||
94                                     scan2->st_Op == ST_Class) {
95                                         CollapseClasses(scan2);
96                                 }
97                         }
98                 }
99 #if 0
100                 if (st->st_ImportStmt.es_DLL) {
101                         void (*func)(void) = dlsym(st->st_ImportStmt.es_DLL,
102                                                    "resolveClasses");
103                         if (func)
104                                 func();
105                 }
106 #endif
107                 st->st_Flags &= ~STF_COLLAPSING;
108                 st->st_Flags |= STF_COLLAPSED;
109         }
110 }
111 #endif
112
113 /*
114  * collapseStmt() - Collapse all types, declarations, and semantic refs
115  *
116  *      Collapses all types, declarations, and identifiers.  Additionally
117  *      this function collapses intermediate types for expressions. 
118  */
119 static
120 void
121 collapseStmt(Stmt *st)
122 {
123         Stmt *scan;
124
125         if (st == NULL)
126                 return;
127         if (st->st_Flags & (STF_COLLAPSING | STF_COLLAPSED))
128                 return;
129         st->st_Flags |= STF_COLLAPSING;
130
131         if (st->st_Flags & STF_SEMANTIC) {
132                 collapseSemGroup(st->st_MyGroup);
133 #if 0
134                 SemGroup *sg = st->st_MyGroup;
135                 Type *type;
136
137                 RUNE_FOREACH(type, &sg->sg_ClassList, ty_Node) {
138                         if (type->ty_Op == TY_UNRESOLVED) {
139                                 if (resolveSuperClass(type) == NULL) {
140                                         errorDottedId(
141                                                 type->ty_UnresType.et_DottedId,
142                                                 "Unable to resolve class");
143                                         dassert_stmt(st, 0);
144                                 }
145                         }
146                 }
147 #endif
148         }
149
150         /*
151          * Collapse statements.
152          */
153         switch(st->st_Op) {
154         case ST_Import:
155                 /*
156                  * This will just flag the import declaration as resolved
157                  * so the code generator dives it for generation.
158                  */
159                 if (st->st_ImportStmt.es_Decl)
160                         collapseDecl(st->st_ImportStmt.es_Decl, 0);
161                 /* fall through */
162         case ST_Module:
163                 /*
164                  * Recursively resolve contents
165                  */
166                 RUNE_FOREACH(scan, &st->st_List, st_Node) {
167                         collapseStmt(scan);
168                 }
169                 break;
170         case ST_Class:
171                 collapseType(&st->st_ClassStmt.es_Super, NULL);
172                 collapseDecl(st->st_ClassStmt.es_Decl, 0);
173                 break;
174         case ST_Typedef:
175                 collapseDecl(st->st_TypedefStmt.es_Decl, 0);
176                 break;
177         case ST_Decl:
178                 /*
179                  * Resolve declarations, skipping any whos context was
180                  * moved to a class (e.g. a declaration at the top level
181                  * of a file like Fd.setfd(...) also exists in the Fd class).
182                  */
183                 {
184                         Declaration *d = st->st_DeclStmt.es_Decl;
185                         int i;
186
187                         for (i = 0; i < st->st_DeclStmt.es_DeclCount; ++i) {
188                                 if (st->st_MyGroup != d->d_MyGroup)
189                                         /*printf("SKIPA %s\n", d->d_Id)*/;
190                                 else
191                                         collapseDecl(d, 0);
192                                 d = RUNE_NEXT(d, d_Node);
193                         }
194                 }
195                 break;
196         case ST_Block:
197                 RUNE_FOREACH(scan, &st->st_List, st_Node) {
198                         collapseStmt(scan);
199                 }
200                 break;
201         case ST_Nop:
202                 break;
203         case ST_Loop:
204                 collapseStmt(st->st_LoopStmt.es_Init);
205                 collapseExp(st->st_LoopStmt.es_BCond);
206                 collapseExp(st->st_LoopStmt.es_ACond);
207                 collapseExp(st->st_LoopStmt.es_AExp);
208                 collapseStmt(st->st_LoopStmt.es_Body);
209                 break;
210         case ST_BreakCont:
211                 break;
212         case ST_Bad:
213                 break;
214         case ST_IfElse:
215                 /*
216                  * NOTE: BoolType global implies an rvalue.
217                  */
218                 collapseExp(st->st_IfStmt.es_Exp);
219                 collapseStmt(st->st_IfStmt.es_TrueStmt);
220                 collapseStmt(st->st_IfStmt.es_FalseStmt);
221                 break;
222         case ST_Return:
223                 collapseType(&st->st_RetStmt.es_ProcRetType, NULL);
224                 collapseExp(st->st_RetStmt.es_Exp);
225                 break;
226         case ST_Result:
227                 collapseType(&st->st_ResStmt.es_ProcRetType, NULL);
228                 collapseExp(st->st_ResStmt.es_Exp);
229                 break;
230         case ST_Switch:
231                 /*
232                  * NOTE: Switch type must be an rvalue.
233                  *
234                  * NOTE: It is possible to switch on a type.  See ST_Case
235                  *       below for more detail.
236                  */
237                 collapseExp(st->st_SwStmt.es_Exp);
238                 RUNE_FOREACH(scan, &st->st_List, st_Node) {
239                         collapseStmt(scan);
240                 }
241                 break;
242         case ST_Case:
243                 /*
244                  * Handle a case/default.  Note that when switching on a type,
245                  * each case expression must return a type.
246                  *
247                  * NOTE: Case type must be an rvalue.  We use the switch type
248                  *       to cast, so it will be.
249                  */
250                 {
251                         dassert_stmt(st, st->st_Parent->st_Op == ST_Switch);
252
253                         /*
254                          * Elements of the case/default
255                          */
256                         collapseExp(st->st_CaseStmt.es_Exp);
257                         RUNE_FOREACH(scan, &st->st_List, st_Node) {
258                                 collapseStmt(scan);
259                         }
260                 }
261                 break;
262         case ST_Exp:
263                 /*
264                  * NOTE: VoidType global implies an rvalue.
265                  *
266                  * NOTE: If resolveExp() doesn't cast to void for
267                  *       us, we will do it here.
268                  */
269                 collapseExp(st->st_ExpStmt.es_Exp);
270                 break;
271         case ST_Proc:
272                 RUNE_FOREACH(scan, &st->st_List, st_Node) {
273                         collapseStmt(scan);
274                 }
275                 break;
276         case ST_ThreadSched:
277                 break;
278         default:
279                 dassert_stmt(st, 0);
280                 break;
281         }
282         st->st_Flags &= ~STF_COLLAPSING;
283         st->st_Flags |= STF_COLLAPSED;
284 }
285
286 /*
287  * collapseDecl() - collapse a declaration
288  */
289 static
290 void
291 collapseDecl(Declaration *d, int dynamic)
292 {
293         SemGroup *sg = NULL;
294
295         if (d == NULL)  
296                 return;
297         if (d->d_Flags & (DF_COLLAPSING | DF_COLLAPSED))
298                 return;
299         if ((d->d_Flags & DF_RESOLVED) == 0)
300                 return;
301         d->d_Flags |= DF_COLLAPSING;
302         if (d->d_Flags & DF_ADDRUSED)
303                 d->d_InfoIndex = d->d_MyGroup->sg_InfoCount++;
304
305         switch(d->d_Op) {
306         case DOP_CLASS:
307                 collapseType(&d->d_ClassDecl.ed_Super, NULL);
308                 sg = d->d_ClassDecl.ed_SemGroup;
309                 collapseSemGroup(sg);
310                 d->d_MyGroup->sg_InfoCount += sg->sg_InfoCount;
311                 break;
312         case DOP_ALIAS:
313                 /*
314                  * Alias access is a barrier and always returns an rvalue.
315                  */
316                 collapseType(&d->d_AliasDecl.ed_Type, NULL);
317                 collapseExp(d->d_AliasDecl.ed_AssExp);
318                 break;
319         case DOP_TYPEDEF:
320                 collapseType(&d->d_TypedefDecl.ed_Type, NULL);
321                 break;
322         case DOP_IMPORT:
323                 /*
324                  * This only occurs when resolving an import's semantic group.
325                  * Since we are scanning statements in that context we do not
326                  * have to recurse here, collapseStmt() will do it for us.
327                  */
328                 break;
329         case DOP_PROC:
330                 /*
331                  * XXX global procedure, later on, make the argument a
332                  * type instead of storage?
333                  */
334                 collapseType(&d->d_ProcDecl.ed_Type, NULL);
335                 collapseStmt(d->d_ProcDecl.ed_ProcBody);        /* XXX */
336                 collapseStmt(d->d_ProcDecl.ed_OrigBody);        /* XXX */
337                 break;
338         case DOP_ARGS_STORAGE:
339         case DOP_STACK_STORAGE:
340         case DOP_GLOBAL_STORAGE:
341         case DOP_GROUP_STORAGE:
342                 collapseType(&d->d_StorDecl.ed_Type, NULL);
343                 collapseExp(d->d_StorDecl.ed_AssExp);
344                 break;
345         default:
346                 dassert_decl(d, 0);
347         }
348         d->d_Flags &= ~DF_COLLAPSING;
349         d->d_Flags |= DF_COLLAPSED | DF_LAYOUT;
350
351         if (dynamic) {
352                 Declaration *scan;
353
354                 for (scan = d->d_SubBase; scan; scan = scan->d_SubNext)
355                         collapseDecl(scan, 1);
356         }
357 }
358
359 /*
360  * collapseExp()
361  */
362 static
363 void
364 collapseExp(Exp *exp)
365 {
366         Exp *scan;
367
368         if (exp == NULL)
369                 return;
370         if (exp->ex_Flags & (EXF_COLLAPSING | EXF_COLLAPSED))
371                 return;
372         exp->ex_Flags |= EXF_COLLAPSING;
373
374         collapseType(&exp->ex_Type, NULL);
375         collapseDecl(exp->ex_Decl, 0);
376
377         switch(exp->ex_Token) {
378         case TOK_ASS:
379         case TOK_ANDAND:
380         case TOK_OROR:
381                 collapseExp(exp->ex_Lhs);
382                 collapseExp(exp->ex_Rhs);
383                 break;
384         case TOK_DECL:
385                 break;
386         case TOK_DOT:
387         case TOK_STRIND:
388                 collapseExp(exp->ex_Lhs);
389
390                 /*
391                  * Resolver might have turned RHS into a SEMGRP_ID, only
392                  * collapse if it hasn't. XXX
393                  */
394                 if (exp->ex_Rhs->ex_Token != TOK_SEMGRP_ID)
395                         collapseExp(exp->ex_Rhs);
396                 break;
397         case TOK_STRUCT_ID:
398                 break;
399         case TOK_OPER:
400                 collapseExp(exp->ex_Lhs);
401                 collapseExp(exp->ex_Rhs);
402                 break;
403         case TOK_PTRIND:
404                 collapseExp(exp->ex_Lhs);
405                 break;
406         case TOK_ADDR:
407                 collapseExp(exp->ex_Lhs);
408                 break;
409         case TOK_OBRACKET:
410                 collapseExp(exp->ex_Lhs);
411                 collapseExp(exp->ex_Rhs);
412                 break;
413         case TOK_OPAREN:
414                 dassert_exp(exp, 0);    /* XXX */
415                 break;
416         case TOK_DSTRING:
417         case TOK_SSTRING:
418         case TOK_BSTRING:
419         case TOK_INTEGER:
420         case TOK_FLOAT:
421         case TOK_VOIDEXP:
422         case TOK_SELF:
423         case TOK_DOLLAR:
424                 break;
425         case TOK_ID:
426         case TOK_CLASSID:
427                 break;
428         case TOK_NOT:
429                 collapseExp(exp->ex_Lhs);
430                 break;
431         case TOK_TYPE:
432                 break;
433         case TOK_CAST:
434                 collapseExp(exp->ex_Lhs);
435                 /* RHS was converted to type */
436                 break;
437         case TOK_INLINE_CALL:
438                 collapseExp(exp->ex_Lhs);
439                 collapseExp(exp->ex_Rhs);
440                 collapseStmt(exp->ex_AuxStmt);
441                 if (exp->ex_Lhs->ex_Token == TOK_STRIND &&
442                     exp->ex_Lhs->ex_Lhs->ex_Type &&
443                     exp->ex_Lhs->ex_Lhs->ex_Type->ty_Op == TY_REFTO) {
444                         collapseDecl(exp->ex_Lhs->ex_Decl, 1);
445                 }
446                 break;
447         case TOK_CALL:
448                 collapseExp(exp->ex_Lhs);
449                 collapseExp(exp->ex_Rhs);
450                 if (exp->ex_Lhs->ex_Token == TOK_STRIND &&
451                     exp->ex_Lhs->ex_Lhs->ex_Type &&
452                     exp->ex_Lhs->ex_Lhs->ex_Type->ty_Op == TY_REFTO) {
453                         collapseDecl(exp->ex_Lhs->ex_Decl, 1);
454                 }
455                 break;
456         case TOK_COMPOUND:
457         case TOK_BRACKETED:
458                 for (scan = exp->ex_Lhs; scan; scan = scan->ex_Next)
459                         collapseExp(scan);
460                 break;
461         case TOK_TYPEOF:
462                 /* fall through */
463         case TOK_SIZEOF:
464         case TOK_ARYSIZE:
465                 collapseExp(exp->ex_Lhs);
466                 break;
467         case TOK_ERR_EXP_REMOVED:
468                 break;
469         default:
470                 fprintf(stderr, "BADEXP %p %08x\n", exp, exp->ex_Token);
471                 /* dassert_exp(exp, 0); */
472                 break;
473         }
474
475         exp->ex_Flags &= ~EXF_COLLAPSING;
476         exp->ex_Flags |= EXF_COLLAPSED;
477 }
478
479 /*
480  * Collapse a SemGroup.  The SemGroup may be used even if not resolved
481  * if individual functions were picked out of it without instantiating
482  * it.
483  */
484 static
485 void
486 collapseSemGroup(SemGroup *sg)
487 {
488         Declaration *d;
489
490         if (sg == NULL)
491                 return;
492         if (sg->sg_Flags & (SGF_COLLAPSING | SGF_COLLAPSED))
493                 return;
494         if ((sg->sg_Flags & (SGF_RESOLVED | SGF_ALIGNRESOLVED)) == 0)
495                 return;
496         sg->sg_Flags |= SGF_COLLAPSING;
497
498         RUNE_FOREACH(d, &sg->sg_DeclList, d_Node) {
499                 if (d->d_Flags & DF_RESOLVED)
500                         collapseDecl(d, 0);
501         }
502         sg->sg_Flags &= ~SGF_COLLAPSING;
503         sg->sg_Flags |= SGF_COLLAPSED | SGF_LAYOUT;
504 }
505
506 /*
507  * Match basic type fields.  Note that the TF_RESOLVE* flags must also match.
508  * (that is, we do not match a resolved against an unresolved type).
509  */
510 static
511 int
512 matchbasicfields(Type *type, Type *scan)
513 {
514         if (type->ty_Op == scan->ty_Op &&
515             (type->ty_Flags & ~(TF_COLLAPSED | TF_LAYOUT)) ==
516              (scan->ty_Flags & ~(TF_COLLAPSED | TF_LAYOUT)) &&
517             type->ty_AssExp == scan->ty_AssExp &&
518             type->ty_Bytes == scan->ty_Bytes &&
519             type->ty_AlignMask == scan->ty_AlignMask &&
520             type->ty_SQFlags == scan->ty_SQFlags &&
521             type->ty_Visibility == scan->ty_Visibility &&
522             type->ty_TmpBytes == scan->ty_TmpBytes &&
523             type->ty_TmpAlignMask == scan->ty_TmpAlignMask) {
524                 return 1;
525         } else {
526                 return 0;
527         }
528 }
529
530 /*
531  * Resolve a type and attempt to remove duplicates that were present as
532  * semantic glue.
533  */
534 static
535 void
536 collapseType(Type **typep, Type *adjtype)
537 {
538         SemGroup *sg;
539         Type *type;
540         Type *scan;
541         Type *otype;
542
543         type = *typep;
544         if (type == NULL)
545                 return;
546         if ((type->ty_Flags & TF_RESOLVED) == 0)
547                 return;
548         if (type->ty_Flags & TF_COLLAPSED) {
549                 if (type->ty_Flags & TF_LAYOUT)
550                         return;
551                 /* re-execute (XXX cache in type->ty_CollapsedType) */
552         }
553         type->ty_Flags |= TF_COLLAPSED;
554
555         /*
556          * Otherwise try to collapse
557          */
558         otype = type;
559
560 #if 0
561         printf("; CHECKTYPE l=%p %s\n", type->ty_SQList, TypeToStr(type, NULL));
562 #endif
563
564         switch(type->ty_Op) {
565         case TY_CLASS:
566                 dassert(type->ty_SQList ==
567                         &type->ty_ClassType.et_SemGroup->sg_ClassList);
568                 collapseType(&type->ty_ClassType.et_Super, NULL);
569                 collapseSemGroup(type->ty_ClassType.et_SemGroup);
570                 if (type->ty_ClassType.et_Super) {
571                         dassert((type->ty_ClassType.et_Super->ty_Flags &
572                                 TF_LAYOUT) != 0);
573                 }
574                 if (type->ty_Flags & TF_ISINTERNAL) {
575                         scan = type;
576                         break;
577                 }
578
579                 sg = type->ty_ClassType.et_SemGroup;
580                 dassert(type->ty_SQList == &sg->sg_ClassList);
581                 RUNE_FOREACH(scan, &sg->sg_ClassList, ty_Node) {
582 #if 0
583                         printf(";      TEST %s\t", TypeToStr(scan, NULL));
584 #endif
585                         if (matchbasicfields(type, scan) &&
586                             type->ty_ClassType.et_SemGroup ==
587                              scan->ty_ClassType.et_SemGroup &&
588                             type->ty_ClassType.et_Super ==
589                              scan->ty_ClassType.et_Super) {
590                                 type = scan;
591                                 break;
592                         } else {
593 #if 0
594                                 if (type->ty_Op != scan->ty_Op)
595                                         printf(" op");
596                                 if ((type->ty_Flags & ~TF_COLLAPSED) !=
597                                     (scan->ty_Flags & ~TF_COLLAPSED))
598                                         printf(" flg");
599                                 if (type->ty_AssExp != scan->ty_AssExp)
600                                         printf(" ass");
601                                 if (type->ty_Bytes != scan->ty_Bytes)
602                                         printf(" bytes");
603                                 if (type->ty_AlignMask != scan->ty_AlignMask)
604                                         printf(" align");
605                                 if (type->ty_SQFlags != scan->ty_SQFlags)
606                                         printf(" sqflg");
607                                 if (type->ty_Visibility != scan->ty_Visibility)
608                                         printf(" vis[%d,%d]",
609                                                type->ty_Visibility,
610                                                scan->ty_Visibility);
611                                 if (type->ty_TmpBytes != scan->ty_TmpBytes)
612                                         printf(" tmpbytes");
613                                 if (type->ty_TmpAlignMask != scan->ty_TmpAlignMask)
614                                         printf(" tmpalign");
615                                 if (type->ty_ClassType.et_SemGroup !=
616                                     scan->ty_ClassType.et_SemGroup)
617                                         printf(" sg");
618                                 if (type->ty_ClassType.et_Super !=
619                                     scan->ty_ClassType.et_Super)
620                                         printf(" super");
621 #endif
622                         }
623 #if 0
624                         printf("\n");
625 #endif
626                 }
627                 break;
628         case TY_CPTRTO:
629         case TY_PTRTO:
630         case TY_REFTO:
631                 dassert(type->ty_SQList ==
632                         &type->ty_PtrType.et_Type->ty_QList);
633                 collapseType(&type->ty_PtrType.et_Type, type);
634                 if (type->ty_Flags & TF_ISINTERNAL) {
635                         scan = type;
636                         break;
637                 }
638                 RUNE_FOREACH(scan, &type->ty_PtrType.et_Type->ty_QList, ty_Node) {
639 #if 0
640                         printf(";      TEST %s\n", TypeToStr(scan, NULL));
641 #endif
642                         if (matchbasicfields(type, scan) &&
643                             type->ty_PtrType.et_Type ==
644                              scan->ty_PtrType.et_Type) {
645                                 type = scan;
646                                 break;
647                         }
648                 }
649                 break;
650         case TY_ARYOF:
651 #if 0
652                 dassert(type->ty_SQList ==
653                         &type->ty_AryType.et_Type->ty_QList);
654 #endif
655                 collapseType(&type->ty_AryType.et_Type, type);
656                 if (type->ty_Flags & TF_ISINTERNAL) {
657                         scan = type;
658                         break;
659                 }
660                 RUNE_FOREACH(scan, &type->ty_AryType.et_Type->ty_QList, ty_Node) {
661 #if 0
662                         printf(";      TEST %s\n", TypeToStr(scan, NULL));
663 #endif
664                         if (matchbasicfields(type, scan) &&
665                             type->ty_AryType.et_SemGroup ==
666                              scan->ty_AryType.et_SemGroup &&
667                             type->ty_AryType.et_Type ==
668                              scan->ty_AryType.et_Type &&
669                             type->ty_AryType.et_Count ==
670                              scan->ty_AryType.et_Count) {
671                                 type = scan;
672                                 break;
673                         }
674                 }
675                 break;
676         case TY_COMPOUND:
677                 collapseSemGroup(type->ty_CompType.et_SemGroup);
678                 dassert(type->ty_SQList == &CompoundTypeList);
679                 if (type->ty_Flags & TF_ISINTERNAL) {
680                         scan = type;
681                         break;
682                 }
683                 RUNE_FOREACH(scan, &CompoundTypeList, ty_Node) {
684 #if 0
685                         printf(";      TEST %s\n", TypeToStr(scan, NULL));
686 #endif
687                         if (matchbasicfields(type, scan) &&
688                             type->ty_CompType.et_SemGroup ==
689                              scan->ty_CompType.et_SemGroup) {
690                                 type = scan;
691                                 break;
692                         }
693                 }
694                 break;
695         case TY_ARGS:
696                 collapseSemGroup(type->ty_CompType.et_SemGroup);
697                 dassert(type->ty_SQList == &ArgsTypeList);
698                 if (type->ty_Flags & TF_ISINTERNAL) {
699                         scan = type;
700                         break;
701                 }
702                 RUNE_FOREACH(scan, &ArgsTypeList, ty_Node) {
703 #if 0
704                         printf(";      TEST %s\n", TypeToStr(scan, NULL));
705 #endif
706                         if (matchbasicfields(type, scan) &&
707                             type->ty_CompType.et_SemGroup ==
708                              scan->ty_CompType.et_SemGroup) {
709                                 type = scan;
710                                 break;
711                         }
712                 }
713                 break;
714         case TY_VAR:
715                 collapseSemGroup(type->ty_VarType.et_SemGroup);
716                 scan = type;    /* XXX */
717                 break;
718         case TY_PROC:
719                 /*
720                  * NOTE: Storage not tracked.
721                  */
722 #if 0
723                 dassert(type->ty_SQList ==
724                         &type->ty_ProcType.et_RetType->ty_QList);
725 #endif
726                 collapseType(&type->ty_ProcType.et_ArgsType, NULL);
727                 collapseType(&type->ty_ProcType.et_RetType, type);
728                 if (type->ty_Flags & TF_ISINTERNAL) {
729                         scan = type;
730                         break;
731                 }
732
733                 RUNE_FOREACH(scan, &type->ty_ProcType.et_RetType->ty_QList, ty_Node) {
734 #if 0
735                         printf(";      TEST %s\n", TypeToStr(scan, NULL));
736 #endif
737                         if (matchbasicfields(type, scan) &&
738                             type->ty_ProcType.et_ArgsType ==
739                              scan->ty_ProcType.et_ArgsType &&
740                             type->ty_ProcType.et_RetType ==
741                              scan->ty_ProcType.et_RetType &&
742                             type->ty_ProcType.et_ArgCount ==
743                              scan->ty_ProcType.et_ArgCount) {
744                                 type = scan;
745                                 break;
746                         }
747                 }
748                 break;
749         case TY_STORAGE:
750                 dassert(type->ty_SQList == &StorageTypeList);
751                 if (type->ty_Flags & TF_ISINTERNAL) {
752                         scan = type;
753                         break;
754                 }
755                 RUNE_FOREACH(scan, &StorageTypeList, ty_Node) {
756 #if 0
757                         printf(";      TEST %s\n", TypeToStr(scan, NULL));
758 #endif
759                         if (matchbasicfields(type, scan) &&
760                             type->ty_StorType.et_Bytes ==
761                              scan->ty_StorType.et_Bytes) {
762                                 type = scan;
763                                 break;
764                         }
765                 }
766                 break;
767         case TY_UNRESOLVED:
768                 scan = type;    /* XXX */
769                 break;
770         case TY_DYNAMIC:
771                 dassert(type->ty_SQList == &DynamicTypeList);
772                 if (type->ty_Flags & TF_ISINTERNAL) {
773                         scan = type;
774                         break;
775                 }
776                 RUNE_FOREACH(scan, &DynamicTypeList, ty_Node) {
777 #if 0
778                         printf(";      TEST %s\n", TypeToStr(scan, NULL));
779 #endif
780                         if (matchbasicfields(type, scan)) {
781                                 type = scan;
782                                 break;
783                         }
784                 }
785                 break;
786         case TY_IMPORT:
787                 scan = type;    /* XXX */
788                 break;
789         default:
790                 scan = NULL;
791                 dpanic("Unknown type %d (type=%p)", type->ty_Op, type);
792                 break;
793         }
794         dassert(scan != NULL);  /* we should find at least ourselves */
795
796         if (type != otype) {
797                 collapseType(&type, NULL);
798                 if (adjtype) {
799                         RUNE_REMOVE(adjtype->ty_SQList, adjtype, ty_Node);
800                         adjtype->ty_SQList = &type->ty_QList;
801                         RUNE_INSERT_TAIL(adjtype->ty_SQList, adjtype, ty_Node);
802                 }
803 #if 0
804                 printf("; COLLAPSE %s <- %s\n",
805                         TypeToStr(type, NULL), TypeToStr(otype, NULL));
806                 if (type->ty_Op == TY_CLASS && type->ty_ClassType.et_Super &&
807                     type->ty_ClassType.et_Super != otype->ty_ClassType.et_Super)
808                         printf(";  SUPERCLASS %s <- %s\n",
809                                 TypeToStr(type->ty_ClassType.et_Super, NULL), TypeToStr(otype->ty_ClassType.et_Super, NULL));
810 #endif
811
812                 *typep = type;
813         } else {
814 #if 0
815                 printf("; MATCHEDSAME\n");
816 #endif
817         }
818         type->ty_Flags |= TF_LAYOUT;
819 }