[dartdevc] fix #36001, non-generic classes and recursive supertypes

When two non-generic class had supertypes with mutually recursive type
arguments, the resulting module failed at startup. The compiler detected
the recursion and attempted to defer the supertype type argument
evaluation, but did not defer it long enough. The fix is to move these
deferrals after all classes are declared.

Longer term, a better fix will be #31003 which removes the need to
evaluate supertype type arguments during module initialization.

Change-Id: Ic8c5819521b3fedfcc207e932f11ae11cb03222d
Reviewed-on: https://dart-review.googlesource.com/c/93924
Commit-Queue: Mark Zhou <markzipan@google.com>
Auto-Submit: Jenny Messerly <jmesserly@google.com>
Reviewed-by: Mark Zhou <markzipan@google.com>
diff --git a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
index c2037fb..bdfd8556 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -336,6 +336,9 @@
     compilationUnits.forEach(visitCompilationUnit);
     assert(_deferredProperties.isEmpty);
 
+    moduleItems.addAll(afterClassDefItems);
+    afterClassDefItems.clear();
+
     // Visit directives (for exports)
     compilationUnits.forEach(_emitExportDirectives);
 
@@ -884,7 +887,7 @@
       classDef = _defineClassTypeArguments(
           classElem, typeFormals, classDef, className, deferredSupertypes);
     } else {
-      body.addAll(deferredSupertypes);
+      afterClassDefItems.addAll(deferredSupertypes);
     }
 
     body = [classDef];
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
index a39888c..66e0628 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
@@ -28,6 +28,12 @@
   /// The list of output module items, in the order they need to be emitted in.
   final moduleItems = <JS.ModuleItem>[];
 
+  /// Like [moduleItems] but for items that should be emitted after classes.
+  ///
+  /// This is used for deferred supertypes of mutually recursive non-generic
+  /// classes.
+  final afterClassDefItems = <JS.ModuleItem>[];
+
   /// When compiling the body of a `operator []=` method, this will be non-null
   /// and will indicate the the value that should be returned from any `return;`
   /// statements.
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index cd0af30e..a56cbc2 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -314,6 +314,9 @@
     // This is done by forward declaring items.
     libraries.forEach(_emitLibrary);
 
+    moduleItems.addAll(afterClassDefItems);
+    afterClassDefItems.clear();
+
     // Visit directives (for exports)
     libraries.forEach(_emitExports);
 
@@ -569,7 +572,7 @@
       classDef = _defineClassTypeArguments(
           c, typeFormals, classDef, className, deferredSupertypes);
     } else {
-      body.addAll(deferredSupertypes);
+      afterClassDefItems.addAll(deferredSupertypes);
     }
 
     body = [classDef];