[cfe] Add ConstructorTearOff Kernel AST node

TEST=Adding new node id. Conflicts should be detected by existing tests.

Change-Id: I49791188345b6b8cfc7cad2fef9983d499d326ef
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/202764
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 51181ce..0d34217 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -5807,6 +5807,11 @@
   }
 
   @override
+  js_ast.Expression visitConstructorTearOff(ConstructorTearOff node) {
+    throw UnsupportedError('Constructor tear off');
+  }
+
+  @override
   js_ast.Expression visitIsExpression(IsExpression node) {
     return _emitIsExpression(node.operand, node.type);
   }
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 388009a..58f6cf1 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -3407,6 +3407,11 @@
   }
 
   @override
+  Constant visitConstructorTearOff(ConstructorTearOff node) {
+    return defaultExpression(node);
+  }
+
+  @override
   Constant visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) {
     return createErrorConstant(node,
         templateConstEvalDeferredLibrary.withArguments(node.import.name!));
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index f489134..4d5889c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -196,6 +196,12 @@
   }
 
   @override
+  ExpressionInferenceResult visitConstructorTearOff(
+      ConstructorTearOff node, DartType typeContext) {
+    return _unhandledExpression(node, typeContext);
+  }
+
+  @override
   ExpressionInferenceResult visitListConcatenation(
       ListConcatenation node, DartType typeContext) {
     return _unhandledExpression(node, typeContext);
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index f6a69db..816ad78 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -3067,6 +3067,7 @@
 tools
 top
 topologically
+torn
 tortoise
 total
 totally
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index 3007964..dfed538 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -147,7 +147,7 @@
 
 type ComponentFile {
   UInt32 magic = 0x90ABCDEF;
-  UInt32 formatVersion = 65;
+  UInt32 formatVersion = 66;
   Byte[10] shortSdkHash;
   List<String> problemsAsJson; // Described in problems.md.
   Library[] libraries;
@@ -700,6 +700,13 @@
   MemberReference target;
 }
 
+type ConstructorTearOff extends Expression {
+  Byte tag = 60;
+  FileOffset fileOffset;
+  ConstructorReference constructor;
+  Option<List<DartType>> typeArguments;
+}
+
 type StaticSet extends Expression {
   Byte tag = 27;
   FileOffset fileOffset;
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index ef44a1d..2389f01 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -8600,6 +8600,57 @@
   }
 }
 
+/// Tearing off a constructor of a class.
+class ConstructorTearOff extends Expression {
+  /// The reference to the constructor being torn off.
+  Reference constructorReference;
+
+  ConstructorTearOff(Constructor constructor)
+      : this.byReference(getNonNullableMemberReferenceGetter(constructor));
+
+  ConstructorTearOff.byReference(this.constructorReference);
+
+  Constructor get constructor => constructorReference.asConstructor;
+
+  void set constructor(Constructor constructor) {
+    constructorReference = getNonNullableMemberReferenceGetter(constructor);
+  }
+
+  @override
+  DartType getStaticTypeInternal(StaticTypeContext context) {
+    return constructorReference.asConstructor.function
+        .computeFunctionType(Nullability.nonNullable);
+  }
+
+  @override
+  R accept<R>(ExpressionVisitor<R> v) => v.visitConstructorTearOff(this);
+
+  @override
+  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
+      v.visitConstructorTearOff(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
+    constructor.acceptReference(v);
+  }
+
+  @override
+  void transformChildren(Transformer v) {}
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {}
+
+  @override
+  String toString() {
+    return "ConstructorTearOff(${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.writeMemberName(constructorReference);
+  }
+}
+
 // ------------------------------------------------------------------------
 //                              STATEMENTS
 // ------------------------------------------------------------------------
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index aaebe62..54b51cc 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -1966,6 +1966,8 @@
         return _readStaticTearOff();
       case Tag.StaticSet:
         return _readStaticSet();
+      case Tag.ConstructorTearOff:
+        return _readConstructorTearOff();
       case Tag.MethodInvocation:
         return _readMethodInvocation();
       case Tag.InstanceInvocation:
@@ -2195,6 +2197,13 @@
       ..fileOffset = offset;
   }
 
+  Expression _readConstructorTearOff() {
+    int offset = readOffset();
+    Reference constructorReference = readNonNullMemberReference();
+    return new ConstructorTearOff.byReference(constructorReference)
+      ..fileOffset = offset;
+  }
+
   Expression _readStaticTearOff() {
     int offset = readOffset();
     return new StaticTearOff.byReference(readNonNullMemberReference())
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 04666b1..01e46ba 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -1591,6 +1591,13 @@
   }
 
   @override
+  void visitConstructorTearOff(ConstructorTearOff node) {
+    writeByte(Tag.ConstructorTearOff);
+    writeOffset(node.fileOffset);
+    writeNonNullReference(node.constructorReference);
+  }
+
+  @override
   void visitStaticTearOff(StaticTearOff node) {
     writeByte(Tag.StaticTearOff);
     writeOffset(node.fileOffset);
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index e47ad48..9c0d0f9 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -76,6 +76,7 @@
   static const int BigIntLiteral = 57;
   static const int ConstListLiteral = 58;
   static const int ConstMapLiteral = 59;
+  static const int ConstructorTearOff = 60;
 
   static const int SetLiteral = 109;
   static const int ConstSetLiteral = 110;
@@ -174,7 +175,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 = 65;
+  static const int BinaryFormatVersion = 66;
 }
 
 abstract class ConstantTag {
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index da80fd1..efbe399 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -735,6 +735,11 @@
   TreeNode visitFunctionTearOff(FunctionTearOff node) {
     return new FunctionTearOff(clone(node.receiver));
   }
+
+  @override
+  TreeNode visitConstructorTearOff(ConstructorTearOff node) {
+    return new ConstructorTearOff.byReference(node.constructorReference);
+  }
 }
 
 /// Visitor that return a clone of a tree, maintaining references to cloned
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index 61b0504..ac9470e 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -2893,6 +2893,9 @@
   int visitStaticSet(StaticSet node) => EXPRESSION;
 
   @override
+  int visitConstructorTearOff(ConstructorTearOff node) => PRIMARY;
+
+  @override
   int visitLet(Let node) => EXPRESSION;
 
   @override
diff --git a/pkg/kernel/lib/type_checker.dart b/pkg/kernel/lib/type_checker.dart
index 7f5e6c9..777875d 100644
--- a/pkg/kernel/lib/type_checker.dart
+++ b/pkg/kernel/lib/type_checker.dart
@@ -520,6 +520,12 @@
   }
 
   @override
+  DartType visitConstructorTearOff(ConstructorTearOff node) {
+    return node.constructorReference.asConstructor.function
+        .computeFunctionType(Nullability.nonNullable);
+  }
+
+  @override
   DartType visitListLiteral(ListLiteral node) {
     for (int i = 0; i < node.expressions.length; ++i) {
       node.expressions[i] =
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index b9ca9ac..ae31864b 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -81,6 +81,7 @@
   R visitLoadLibrary(LoadLibrary node) => defaultExpression(node);
   R visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) =>
       defaultExpression(node);
+  R visitConstructorTearOff(ConstructorTearOff node) => defaultExpression(node);
 }
 
 abstract class StatementVisitor<R> {
@@ -255,6 +256,7 @@
   R visitLoadLibrary(LoadLibrary node) => defaultExpression(node);
   R visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node) =>
       defaultExpression(node);
+  R visitConstructorTearOff(ConstructorTearOff node) => defaultExpression(node);
 
   // Statements
   R defaultStatement(Statement node) => defaultTreeNode(node);
@@ -430,6 +432,8 @@
   R visitLoadLibrary(LoadLibrary node, A arg) => defaultExpression(node, arg);
   R visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node, A arg) =>
       defaultExpression(node, arg);
+  R visitConstructorTearOff(ConstructorTearOff node, A arg) =>
+      defaultExpression(node, arg);
 
   // Statements
   R defaultStatement(Statement node, A arg) => defaultTreeNode(node, arg);
@@ -1542,6 +1546,8 @@
   R visitLoadLibrary(LoadLibrary node, T arg) => defaultExpression(node, arg);
   R visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node, T arg) =>
       defaultExpression(node, arg);
+  R visitConstructorTearOff(ConstructorTearOff node, T arg) =>
+      defaultExpression(node, arg);
 }
 
 abstract class StatementVisitor1<R, T> {
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index d55aa4e..1c55440 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -20,8 +20,8 @@
 static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
 
 // Both version numbers are inclusive.
-static const uint32_t kMinSupportedKernelFormatVersion = 65;
-static const uint32_t kMaxSupportedKernelFormatVersion = 65;
+static const uint32_t kMinSupportedKernelFormatVersion = 66;
+static const uint32_t kMaxSupportedKernelFormatVersion = 66;
 
 // Keep in sync with package:kernel/lib/binary/tag.dart
 #define KERNEL_TAG_LIST(V)                                                     \
@@ -96,6 +96,7 @@
   V(ConstListLiteral, 58)                                                      \
   V(ConstSetLiteral, 110)                                                      \
   V(ConstMapLiteral, 59)                                                       \
+  V(ConstructorTearOff, 60)                                                    \
   V(ExpressionStatement, 61)                                                   \
   V(Block, 62)                                                                 \
   V(EmptyStatement, 63)                                                        \