[cfe] Add mixin class flag to dill and binary.

Additionally, make class flags a uint because there are now more than 8 flags.

TEST=pkg/front_end/testcases/mixin_class/*

Change-Id: I4fe7babfa9911df0821cc73528e6b10b2ea3b92d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/275402
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Kallen Tu <kallentu@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index 0e3fbba..49aadfb 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -73,6 +73,8 @@
 
   bool get isMixin;
 
+  bool get isMixinClass;
+
   bool get isMixinDeclaration;
 
   bool get isMixinApplication;
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
index 6cd51b4..d061e58 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
@@ -58,6 +58,9 @@
   bool get isMacro => cls.isMacro;
 
   @override
+  bool get isMixinClass => cls.isMixinClass;
+
+  @override
   bool get isMixinDeclaration => cls.isMixinDeclaration;
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 3b0d8f9..9c0292e 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -112,7 +112,7 @@
   @override
   final bool isAugmentation;
 
-  // TODO(kallentu): Finish AST implementation for mixin classes.
+  @override
   final bool isMixinClass;
 
   @override
@@ -275,6 +275,7 @@
     // compile-time error.
     cls.isAbstract = isAbstract;
     cls.isMacro = isMacro;
+    cls.isMixinClass = isMixinClass;
     cls.isSealed = isSealed;
     if (interfaceBuilders != null) {
       for (int i = 0; i < interfaceBuilders!.length; ++i) {
diff --git a/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.strong.expect b/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.strong.expect
index 2a76063..2703a27 100644
--- a/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.strong.expect
+++ b/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.strong.expect
@@ -2,19 +2,19 @@
 import self as self;
 import "dart:core" as core;
 
-class A extends core::Object {
+mixin class A extends core::Object {
   synthetic constructor •() → self::A
     : super core::Object::•()
     ;
 }
-abstract class B extends core::Object {
+abstract mixin class B extends core::Object {
   synthetic constructor •() → self::B
     : super core::Object::•()
     ;
 }
 abstract class M extends core::Object /*isMixinDeclaration*/  {
 }
-class C = core::Object with self::M /*hasConstConstructor*/  {
+mixin class C = core::Object with self::M /*hasConstConstructor*/  {
   const synthetic constructor •() → self::C
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.strong.transformed.expect b/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.strong.transformed.expect
index 3e3e810..47a4901 100644
--- a/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.strong.transformed.expect
@@ -2,19 +2,19 @@
 import self as self;
 import "dart:core" as core;
 
-class A extends core::Object {
+mixin class A extends core::Object {
   synthetic constructor •() → self::A
     : super core::Object::•()
     ;
 }
-abstract class B extends core::Object {
+abstract mixin class B extends core::Object {
   synthetic constructor •() → self::B
     : super core::Object::•()
     ;
 }
 abstract class M extends core::Object /*isMixinDeclaration*/  {
 }
-class C extends core::Object implements self::M /*isEliminatedMixin,hasConstConstructor*/  {
+mixin class C extends core::Object implements self::M /*isEliminatedMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::C
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.expect b/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.expect
index 2a76063..2703a27 100644
--- a/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.expect
+++ b/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.expect
@@ -2,19 +2,19 @@
 import self as self;
 import "dart:core" as core;
 
-class A extends core::Object {
+mixin class A extends core::Object {
   synthetic constructor •() → self::A
     : super core::Object::•()
     ;
 }
-abstract class B extends core::Object {
+abstract mixin class B extends core::Object {
   synthetic constructor •() → self::B
     : super core::Object::•()
     ;
 }
 abstract class M extends core::Object /*isMixinDeclaration*/  {
 }
-class C = core::Object with self::M /*hasConstConstructor*/  {
+mixin class C = core::Object with self::M /*hasConstConstructor*/  {
   const synthetic constructor •() → self::C
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.modular.expect b/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.modular.expect
index 2a76063..2703a27 100644
--- a/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.modular.expect
@@ -2,19 +2,19 @@
 import self as self;
 import "dart:core" as core;
 
-class A extends core::Object {
+mixin class A extends core::Object {
   synthetic constructor •() → self::A
     : super core::Object::•()
     ;
 }
-abstract class B extends core::Object {
+abstract mixin class B extends core::Object {
   synthetic constructor •() → self::B
     : super core::Object::•()
     ;
 }
 abstract class M extends core::Object /*isMixinDeclaration*/  {
 }
-class C = core::Object with self::M /*hasConstConstructor*/  {
+mixin class C = core::Object with self::M /*hasConstConstructor*/  {
   const synthetic constructor •() → self::C
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.outline.expect b/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.outline.expect
index 76f8cc4..637bcf8 100644
--- a/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.outline.expect
@@ -2,17 +2,17 @@
 import self as self;
 import "dart:core" as core;
 
-class A extends core::Object {
+mixin class A extends core::Object {
   synthetic constructor •() → self::A
     ;
 }
-abstract class B extends core::Object {
+abstract mixin class B extends core::Object {
   synthetic constructor •() → self::B
     ;
 }
 abstract class M extends core::Object /*isMixinDeclaration*/  {
 }
-class C = core::Object with self::M /*hasConstConstructor*/  {
+mixin class C = core::Object with self::M /*hasConstConstructor*/  {
   const synthetic constructor •() → self::C
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.transformed.expect b/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.transformed.expect
index 3e3e810..47a4901 100644
--- a/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/mixin_class/mixin_class_declaration.dart.weak.transformed.expect
@@ -2,19 +2,19 @@
 import self as self;
 import "dart:core" as core;
 
-class A extends core::Object {
+mixin class A extends core::Object {
   synthetic constructor •() → self::A
     : super core::Object::•()
     ;
 }
-abstract class B extends core::Object {
+abstract mixin class B extends core::Object {
   synthetic constructor •() → self::B
     : super core::Object::•()
     ;
 }
 abstract class M extends core::Object /*isMixinDeclaration*/  {
 }
-class C extends core::Object implements self::M /*isEliminatedMixin,hasConstConstructor*/  {
+mixin class C extends core::Object implements self::M /*isEliminatedMixin,hasConstConstructor*/  {
   const synthetic constructor •() → self::C
     : super core::Object::•()
     ;
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index f95f4a0..fda11a5e 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -147,7 +147,7 @@
 
 type ComponentFile {
   UInt32 magic = 0x90ABCDEF;
-  UInt32 formatVersion = 90;
+  UInt32 formatVersion = 91;
   Byte[10] shortSdkHash;
   List<String> problemsAsJson; // Described in problems.md.
   Library[] libraries;
@@ -318,8 +318,9 @@
   FileOffset startFileOffset; // Offset of the start of the class including any annotations.
   FileOffset fileOffset; // Offset of the name of the class.
   FileOffset fileEndOffset;
-  Byte flags (isAbstract, isEnum, isAnonymousMixin, isEliminatedMixin,
-              isMixinDeclaration, hasConstConstructor, isMacro, isSealed);
+  UInt flags (isAbstract, isEnum, isAnonymousMixin, isEliminatedMixin,
+              isMixinDeclaration, hasConstConstructor, isMacro, isSealed,
+              isMixinClass);
   StringReference name;
   List<Expression> annotations;
   List<TypeParameter> typeParameters;
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index ea6aaf5..5080e6e 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -1026,6 +1026,7 @@
   static const int FlagHasConstConstructor = 1 << 5;
   static const int FlagMacro = 1 << 6;
   static const int FlagSealed = 1 << 7;
+  static const int FlagMixinClass = 1 << 8;
 
   int flags = 0;
 
@@ -1086,6 +1087,18 @@
         value ? (flags | FlagEliminatedMixin) : (flags & ~FlagEliminatedMixin);
   }
 
+  /// Whether this class is a mixin class.
+  ///
+  /// The `mixin` modifier was added to the class declaration which allows the
+  /// class to be used as a mixin. The class can be mixed in by other classes
+  /// outside of its library. Otherwise, classes are not able to be used as a
+  /// mixin outside of its library from version 3.0 and later.
+  bool get isMixinClass => flags & FlagMixinClass != 0;
+
+  void set isMixinClass(bool value) {
+    flags = value ? (flags | FlagMixinClass) : (flags & ~FlagMixinClass);
+  }
+
   /// True if this class was a mixin declaration in Dart.
   ///
   /// Mixins are declared in Dart with the `mixin` keyword.  They are compiled
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index 4f89c55..d717999 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -1478,7 +1478,7 @@
     int startFileOffset = readOffset();
     int fileOffset = readOffset();
     int fileEndOffset = readOffset();
-    int flags = readByte();
+    int flags = readUInt30();
     String name = readStringReference();
     if (node == null) {
       node = new Class(name: name, reference: reference, fileUri: fileUri)
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 9b33d64..4524b7ab 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -1273,7 +1273,7 @@
     writeOffset(node.fileOffset);
     writeOffset(node.fileEndOffset);
 
-    writeByte(node.flags);
+    writeUInt30(node.flags);
     writeStringReference(node.name);
 
     enterScope(memberScope: true);
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index d095dc4..2b60026 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -195,7 +195,7 @@
   /// Internal version of kernel binary format.
   /// Bump it when making incompatible changes in kernel binaries.
   /// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
-  static const int BinaryFormatVersion = 90;
+  static const int BinaryFormatVersion = 91;
 }
 
 abstract class ConstantTag {
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index a70b837..ca6cd58 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -1307,6 +1307,7 @@
     writeModifier(node.isAbstract, 'abstract');
     writeModifier(node.isMacro, 'macro');
     writeModifier(node.isSealed, 'sealed');
+    writeModifier(node.isMixinClass, 'mixin');
     writeWord('class');
     writeWord(getClassName(node));
     writeTypeParameterList(node.typeParameters);
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 040c11b..ceddc65 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -1287,7 +1287,7 @@
       if (++next_read_ == field) return;
       FALL_THROUGH;
     case kFlags:
-      flags_ = helper_->ReadFlags();  // read flags.
+      flags_ = helper_->ReadUInt();  // read flags.
       if (++next_read_ == field) return;
       FALL_THROUGH;
     case kNameIndex:
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 00295ac0..abb817d 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -759,6 +759,7 @@
     kHasConstConstructor = 1 << 5,
     kIsMacro = 1 << 6,
     kisSealed = 1 << 7,
+    kIsMixinClass = 1 << 8,
   };
 
   explicit ClassHelper(KernelReaderHelper* helper)
@@ -793,7 +794,7 @@
   intptr_t source_uri_index_ = 0;
   intptr_t annotation_count_ = 0;
   intptr_t procedure_count_ = 0;
-  uint8_t flags_ = 0;
+  uint32_t flags_ = 0;
 
  private:
   KernelReaderHelper* helper_;
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index 2ee2ca8..1c0b234 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -18,7 +18,7 @@
 // package:kernel/binary.md.
 
 static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
-static const uint32_t kSupportedKernelFormatVersion = 90;
+static const uint32_t kSupportedKernelFormatVersion = 91;
 
 // Keep in sync with package:kernel/lib/binary/tag.dart
 #define KERNEL_TAG_LIST(V)                                                     \