[kernel] Add SetConstant node to Kernel.

Change-Id: I83da1afc9f15009c650a871a51ca8171b482d4df
Reviewed-on: https://dart-review.googlesource.com/c/94863
Reviewed-by: Kevin Millikin <kmillikin@google.com>
diff --git a/pkg/compiler/lib/src/ir/visitors.dart b/pkg/compiler/lib/src/ir/visitors.dart
index 739df67..fabd55d 100644
--- a/pkg/compiler/lib/src/ir/visitors.dart
+++ b/pkg/compiler/lib/src/ir/visitors.dart
@@ -717,6 +717,12 @@
   }
 
   @override
+  ConstantValue visitSetConstant(ir.SetConstant node) {
+    // TODO(johnniwinther, fishythefish): Create a set constant value.
+    throw new UnsupportedError("Set literal constants not implemented.");
+  }
+
+  @override
   ConstantValue visitMapConstant(ir.MapConstant node) {
     List<ConstantValue> keys = [];
     List<ConstantValue> values = [];
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index fc31457..302d6ef 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -5150,6 +5150,14 @@
   }
 
   @override
+  visitSetConstant(node) {
+    // Set literals are currently desugared in the frontend.
+    // Implement this method before flipping the supportsSetLiterals flag
+    // in DevCompilerTarget to true.
+    throw "Set literal constants not supported.";
+  }
+
+  @override
   visitInstanceConstant(node) {
     entryToProperty(entry) {
       var field = entry.key.asField.name.name;
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart b/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
index c0be105..43815bf 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
@@ -25,6 +25,7 @@
         NullConstant,
         PartialInstantiationConstant,
         Procedure,
+        SetConstant,
         StringConstant,
         SymbolConstant,
         TearOffConstant,
@@ -266,6 +267,19 @@
     result.add("]");
   }
 
+  void visitSetConstant(SetConstant node) {
+    result.add("<");
+    node.typeArgument.accept(this);
+    result.add(">{");
+    bool first = true;
+    for (Constant constant in node.entries) {
+      if (!first) result.add(", ");
+      constant.accept(this);
+      first = false;
+    }
+    result.add("}");
+  }
+
   void visitMapConstant(MapConstant node) {
     result.add("<");
     node.keyType.accept(this);
diff --git a/pkg/front_end/test/type_labeler_test.dart b/pkg/front_end/test/type_labeler_test.dart
index f24c86d..d303273 100644
--- a/pkg/front_end/test/type_labeler_test.dart
+++ b/pkg/front_end/test/type_labeler_test.dart
@@ -230,6 +230,12 @@
   Constant listBoolConst = new ListConstant(boolType, [falseConst, trueConst]);
   check({listBoolConst: "<bool>[false, true]"}, 0);
 
+  Constant setConst = new SetConstant(dynamicType, [intConst, doubleConst]);
+  check({setConst: "<dynamic>{2, 2.5}"}, 0);
+
+  Constant setBoolConst = new SetConstant(boolType, [falseConst, trueConst]);
+  check({setBoolConst: "<bool>{false, true}"}, 0);
+
   Constant mapConst = new MapConstant(boolType, numType, [
     new ConstantMapEntry(trueConst, intConst),
     new ConstantMapEntry(falseConst, doubleConst)
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index 5071104..5fab418 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -137,7 +137,7 @@
 
 type ComponentFile {
   UInt32 magic = 0x90ABCDEF;
-  UInt32 formatVersion = 19;
+  UInt32 formatVersion = 20;
   List<String> problemsAsJson; // Described in problems.md.
   Library[] libraries;
   UriSource sourceMap;
@@ -917,6 +917,12 @@
   List<ConstantReference> values;
 }
 
+type SetConstant extends Constant {
+  Byte tag = 13; // Note: tag is out of order.
+  DartType type;
+  List<ConstantReference> values;
+}
+
 type InstanceConstant extends Constant {
   Byte tag = 8;
   CanonicalNameReference class;
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index fbf28c4..939af1f 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -5346,6 +5346,38 @@
       types.literalListType(typeArgument);
 }
 
+class SetConstant extends Constant {
+  final DartType typeArgument;
+  final List<Constant> entries;
+
+  SetConstant(this.typeArgument, this.entries);
+
+  visitChildren(Visitor v) {
+    typeArgument.accept(v);
+    for (final Constant constant in entries) {
+      constant.acceptReference(v);
+    }
+  }
+
+  accept(ConstantVisitor v) => v.visitSetConstant(this);
+  acceptReference(Visitor v) => v.visitSetConstantReference(this);
+
+  String toString() => '${this.runtimeType}<$typeArgument>($entries)';
+
+  int _cachedHashCode;
+  int get hashCode {
+    return _cachedHashCode ??= typeArgument.hashCode ^ listHashCode(entries);
+  }
+
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      (other is SetConstant &&
+          other.typeArgument == typeArgument &&
+          listEquals(other.entries, entries));
+
+  DartType getType(TypeEnvironment types) => types.literalSetType(typeArgument);
+}
+
 class InstanceConstant extends Constant {
   final Reference classReference;
   final List<DartType> typeArguments;
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index b423a75..29fc2cc 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -239,6 +239,15 @@
           entries[i] = readConstantReference();
         }
         return new ListConstant(typeArgument, entries);
+      case ConstantTag.SetConstant:
+        final DartType typeArgument = readDartType();
+        final int length = readUInt();
+        final List<Constant> entries =
+            new List<Constant>.filled(length, null, growable: true);
+        for (int i = 0; i < length; i++) {
+          entries[i] = readConstantReference();
+        }
+        return new SetConstant(typeArgument, entries);
       case ConstantTag.InstanceConstant:
         final Reference classReference = readClassReference();
         final int typeArgumentCount = readUInt();
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index e9b56f0..383e6ba 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -219,6 +219,11 @@
       writeDartType(constant.typeArgument);
       writeUInt30(constant.entries.length);
       constant.entries.forEach(writeConstantReference);
+    } else if (constant is SetConstant) {
+      writeByte(ConstantTag.SetConstant);
+      writeDartType(constant.typeArgument);
+      writeUInt30(constant.entries.length);
+      constant.entries.forEach(writeConstantReference);
     } else if (constant is InstanceConstant) {
       writeByte(ConstantTag.InstanceConstant);
       writeClassReference(constant.classNode);
@@ -2120,6 +2125,16 @@
   }
 
   @override
+  void visitSetConstant(SetConstant node) {
+    throw new UnsupportedError('serialization of SetConstants');
+  }
+
+  @override
+  void visitSetConstantReference(SetConstant node) {
+    throw new UnsupportedError('serialization of SetConstant references');
+  }
+
+  @override
   void visitMapConstant(MapConstant node) {
     throw new UnsupportedError('serialization of MapConstants');
   }
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index b4bf895..ff6e228 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -139,7 +139,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 = 19;
+  static const int BinaryFormatVersion = 20;
 }
 
 abstract class ConstantTag {
@@ -151,9 +151,11 @@
   static const int SymbolConstant = 5;
   static const int MapConstant = 6;
   static const int ListConstant = 7;
+  static const int SetConstant = 13;
   static const int InstanceConstant = 8;
   static const int PartialInstantiationConstant = 9;
   static const int TearOffConstant = 10;
   static const int TypeLiteralConstant = 11;
   static const int UnevaluatedConstant = 12;
+  // 13 is occupied by [SetConstant]
 }
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index aaca753..94d2f55 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -1948,6 +1948,15 @@
     endLine('${node.runtimeType}<${node.typeArgument}>($entries)');
   }
 
+  visitSetConstant(SetConstant node) {
+    final String name = syntheticNames.nameConstant(node);
+    write('  $name = ');
+    final String entries = node.entries.map((Constant constant) {
+      return syntheticNames.nameConstant(constant);
+    }).join(', ');
+    endLine('${node.runtimeType}<${node.typeArgument}>($entries)');
+  }
+
   visitMapConstant(MapConstant node) {
     final String name = syntheticNames.nameConstant(node);
     write('  $name = ');
diff --git a/pkg/kernel/lib/text/text_serialization_verifier.dart b/pkg/kernel/lib/text/text_serialization_verifier.dart
index 02ce55f..2625376 100644
--- a/pkg/kernel/lib/text/text_serialization_verifier.dart
+++ b/pkg/kernel/lib/text/text_serialization_verifier.dart
@@ -288,6 +288,12 @@
   }
 
   @override
+  void visitSetConstantReference(SetConstant node) {
+    storeLastSeenUriAndOffset(node);
+    node.visitChildren(this);
+  }
+
+  @override
   void visitMapConstantReference(MapConstant node) {
     storeLastSeenUriAndOffset(node);
     node.visitChildren(this);
@@ -372,6 +378,12 @@
   }
 
   @override
+  void visitSetConstant(SetConstant node) {
+    storeLastSeenUriAndOffset(node);
+    node.visitChildren(this);
+  }
+
+  @override
   void visitMapConstant(MapConstant node) {
     storeLastSeenUriAndOffset(node);
     node.visitChildren(this);
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index 4d2b2bb..53ea440 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -292,6 +292,7 @@
   R visitSymbolConstant(SymbolConstant node) => defaultConstant(node);
   R visitMapConstant(MapConstant node) => defaultConstant(node);
   R visitListConstant(ListConstant node) => defaultConstant(node);
+  R visitSetConstant(SetConstant node) => defaultConstant(node);
   R visitInstanceConstant(InstanceConstant node) => defaultConstant(node);
   R visitPartialInstantiationConstant(PartialInstantiationConstant node) =>
       defaultConstant(node);
@@ -346,6 +347,7 @@
   R visitSymbolConstant(SymbolConstant node) => defaultConstant(node);
   R visitMapConstant(MapConstant node) => defaultConstant(node);
   R visitListConstant(ListConstant node) => defaultConstant(node);
+  R visitSetConstant(SetConstant node) => defaultConstant(node);
   R visitInstanceConstant(InstanceConstant node) => defaultConstant(node);
   R visitPartialInstantiationConstant(PartialInstantiationConstant node) =>
       defaultConstant(node);
@@ -375,6 +377,8 @@
       defaultConstantReference(node);
   R visitListConstantReference(ListConstant node) =>
       defaultConstantReference(node);
+  R visitSetConstantReference(SetConstant node) =>
+      defaultConstantReference(node);
   R visitInstanceConstantReference(InstanceConstant node) =>
       defaultConstantReference(node);
   R visitPartialInstantiationConstantReference(
diff --git a/runtime/vm/compiler/frontend/constant_evaluator.cc b/runtime/vm/compiler/frontend/constant_evaluator.cc
index a16e229..1be64ab 100644
--- a/runtime/vm/compiler/frontend/constant_evaluator.cc
+++ b/runtime/vm/compiler/frontend/constant_evaluator.cc
@@ -1205,6 +1205,11 @@
         temp_instance_ = H.Canonicalize(temp_array_);
         break;
       }
+      case kSetConstant:
+        // Set literals are currently desugared in the frontend and will not
+        // reach the VM. See http://dartbug.com/35124 for discussion.
+        UNREACHABLE();
+        break;
       case kInstanceConstant: {
         const NameIndex index = helper_.ReadCanonicalNameReference();
         if (ShouldSkipConstant(index)) {
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index 0cc7f0e..7129b5f 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -20,7 +20,7 @@
 
 // Both version numbers are inclusive.
 static const uint32_t kMinSupportedKernelFormatVersion = 18;
-static const uint32_t kMaxSupportedKernelFormatVersion = 19;
+static const uint32_t kMaxSupportedKernelFormatVersion = 20;
 
 // Keep in sync with package:kernel/lib/binary/tag.dart
 #define KERNEL_TAG_LIST(V)                                                     \
@@ -147,6 +147,7 @@
   kSymbolConstant = 5,
   kMapConstant = 6,
   kListConstant = 7,
+  kSetConstant = 13,
   kInstanceConstant = 8,
   kPartialInstantiationConstant = 9,
   kTearOffConstant = 10,