Version 2.13.0-85.0.dev

Merge commit 'e74b2391ed16034b0901f56bcf412c8d6ae8ae70' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes.dart
index acc5edc..bea98e1 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes.dart
@@ -131,11 +131,11 @@
     return message.compareTo(message);
   }
 
-  FormattedMessage withFormatting(String formatted, int line, int column,
-      Severity severity, List<FormattedMessage> relatedInformation,
+  FormattedMessage withFormatting(PlainAndColorizedString formatted, int line,
+      int column, Severity severity, List<FormattedMessage> relatedInformation,
       {List<Uri>? involvedFiles}) {
-    return new FormattedMessage(
-        this, formatted, line, column, severity, relatedInformation,
+    return new FormattedMessage(this, formatted.plain, formatted.colorized,
+        line, column, severity, relatedInformation,
         involvedFiles: involvedFiles);
   }
 
@@ -162,10 +162,20 @@
       'messageObject=$messageObject)';
 }
 
+class PlainAndColorizedString {
+  final String plain;
+  final String colorized;
+
+  const PlainAndColorizedString(this.plain, this.colorized);
+  const PlainAndColorizedString.plainOnly(this.plain) : this.colorized = plain;
+}
+
 class FormattedMessage implements DiagnosticMessage {
   final LocatedMessage locatedMessage;
 
-  final String formatted;
+  final String formattedPlain;
+
+  final String formattedColorized;
 
   final int line;
 
@@ -178,8 +188,14 @@
 
   final List<Uri>? involvedFiles;
 
-  const FormattedMessage(this.locatedMessage, this.formatted, this.line,
-      this.column, this.severity, this.relatedInformation,
+  const FormattedMessage(
+      this.locatedMessage,
+      this.formattedPlain,
+      this.formattedColorized,
+      this.line,
+      this.column,
+      this.severity,
+      this.relatedInformation,
       {this.involvedFiles});
 
   Code<dynamic> get code => locatedMessage.code;
@@ -200,18 +216,22 @@
 
   @override
   Iterable<String> get ansiFormatted sync* {
-    yield formatted;
+    yield formattedColorized;
     if (relatedInformation != null) {
       for (FormattedMessage m in relatedInformation!) {
-        yield m.formatted;
+        yield m.formattedColorized;
       }
     }
   }
 
   @override
-  Iterable<String> get plainTextFormatted {
-    // TODO(ahe): Implement this correctly.
-    return ansiFormatted;
+  Iterable<String> get plainTextFormatted sync* {
+    yield formattedPlain;
+    if (relatedInformation != null) {
+      for (FormattedMessage m in relatedInformation!) {
+        yield m.formattedPlain;
+      }
+    }
   }
 
   Map<String, Object?> toJson() {
diff --git a/pkg/compiler/lib/src/ir/closure.dart b/pkg/compiler/lib/src/ir/closure.dart
index a9d5604..f129216 100644
--- a/pkg/compiler/lib/src/ir/closure.dart
+++ b/pkg/compiler/lib/src/ir/closure.dart
@@ -230,7 +230,7 @@
   final VariableUseKind kind;
   final ir.Member member;
   final ir.LocalFunction localFunction;
-  final ir.MethodInvocation invocation;
+  final ir.Expression invocation;
   final ir.Instantiation instantiation;
 
   const VariableUse._simple(this.kind)
diff --git a/pkg/compiler/lib/src/ir/scope_visitor.dart b/pkg/compiler/lib/src/ir/scope_visitor.dart
index 7a06792..1fa89f1 100644
--- a/pkg/compiler/lib/src/ir/scope_visitor.dart
+++ b/pkg/compiler/lib/src/ir/scope_visitor.dart
@@ -934,6 +934,11 @@
   }
 
   @override
+  EvaluationComplexity visitStaticTearOff(ir.StaticTearOff node) {
+    return _evaluateImplicitConstant(node);
+  }
+
+  @override
   EvaluationComplexity visitStaticSet(ir.StaticSet node) {
     node.value = _handleExpression(node.value);
     return const EvaluationComplexity.lazy();
@@ -1029,6 +1034,108 @@
     if (receiverComplexity.combine(complexity).isConstant &&
         interfaceTarget is ir.Procedure &&
         interfaceTarget.kind == ir.ProcedureKind.Operator) {
+      // Only operator invocations can be part of constant expressions so we
+      // only try to compute an implicit constant when the receiver and all
+      // arguments are constant - and are used in an operator call.
+      return _evaluateImplicitConstant(node);
+    }
+    return const EvaluationComplexity.lazy();
+  }
+
+  @override
+  EvaluationComplexity visitInstanceInvocation(ir.InstanceInvocation node) {
+    node.receiver = _handleExpression(node.receiver);
+    EvaluationComplexity receiverComplexity = _lastExpressionComplexity;
+    if (node.arguments.types.isNotEmpty) {
+      ir.TreeNode receiver = node.receiver;
+      assert(
+          !(receiver is ir.VariableGet &&
+              receiver.variable.parent is ir.LocalFunction),
+          "Unexpected local function invocation ${node} "
+          "(${node.runtimeType}).");
+      VariableUse usage = new VariableUse.instanceTypeArgument(node);
+      visitNodesInContext(node.arguments.types, usage);
+    }
+    EvaluationComplexity complexity = visitArguments(node.arguments);
+    ir.Member interfaceTarget = node.interfaceTarget;
+    if (receiverComplexity.combine(complexity).isConstant &&
+        interfaceTarget is ir.Procedure &&
+        interfaceTarget.kind == ir.ProcedureKind.Operator) {
+      // Only operator invocations can be part of constant expressions so we
+      // only try to compute an implicit constant when the receiver and all
+      // arguments are constant - and are used in an operator call.
+      return _evaluateImplicitConstant(node);
+    }
+    return const EvaluationComplexity.lazy();
+  }
+
+  @override
+  EvaluationComplexity visitDynamicInvocation(ir.DynamicInvocation node) {
+    node.receiver = _handleExpression(node.receiver);
+    if (node.arguments.types.isNotEmpty) {
+      ir.TreeNode receiver = node.receiver;
+      assert(
+          !(receiver is ir.VariableGet &&
+              receiver.variable.parent is ir.LocalFunction),
+          "Unexpected local function invocation ${node} "
+          "(${node.runtimeType}).");
+      VariableUse usage = new VariableUse.instanceTypeArgument(node);
+      visitNodesInContext(node.arguments.types, usage);
+    }
+    visitArguments(node.arguments);
+    return const EvaluationComplexity.lazy();
+  }
+
+  @override
+  EvaluationComplexity visitFunctionInvocation(ir.FunctionInvocation node) {
+    node.receiver = _handleExpression(node.receiver);
+    if (node.arguments.types.isNotEmpty) {
+      assert(
+          !(node.receiver is ir.VariableGet &&
+              ((node.receiver as ir.VariableGet).variable.parent
+                  is ir.LocalFunction)),
+          "Unexpected local function invocation ${node} "
+          "(${node.runtimeType}).");
+      VariableUse usage = new VariableUse.instanceTypeArgument(node);
+      visitNodesInContext(node.arguments.types, usage);
+    }
+    visitArguments(node.arguments);
+    return const EvaluationComplexity.lazy();
+  }
+
+  @override
+  EvaluationComplexity visitLocalFunctionInvocation(
+      ir.LocalFunctionInvocation node) {
+    if (node.arguments.types.isNotEmpty) {
+      assert(
+          node.variable.parent is ir.LocalFunction,
+          "Unexpected variable in local function invocation ${node} "
+          "(${node.runtimeType}).");
+      VariableUse usage =
+          new VariableUse.localTypeArgument(node.variable.parent, node);
+      visitNodesInContext(node.arguments.types, usage);
+    }
+    visitArguments(node.arguments);
+    return const EvaluationComplexity.lazy();
+  }
+
+  @override
+  EvaluationComplexity visitEqualsNull(ir.EqualsNull node) {
+    node.expression = _handleExpression(node.expression);
+    EvaluationComplexity receiverComplexity = _lastExpressionComplexity;
+    if (receiverComplexity.isConstant) {
+      return _evaluateImplicitConstant(node);
+    }
+    return const EvaluationComplexity.lazy();
+  }
+
+  @override
+  EvaluationComplexity visitEqualsCall(ir.EqualsCall node) {
+    node.left = _handleExpression(node.left);
+    EvaluationComplexity leftComplexity = _lastExpressionComplexity;
+    node.right = _handleExpression(node.right);
+    EvaluationComplexity rightComplexity = _lastExpressionComplexity;
+    if (leftComplexity.combine(rightComplexity).isConstant) {
       return _evaluateImplicitConstant(node);
     }
     return const EvaluationComplexity.lazy();
@@ -1045,6 +1152,38 @@
   }
 
   @override
+  EvaluationComplexity visitInstanceGet(ir.InstanceGet node) {
+    node.receiver = _handleExpression(node.receiver);
+    EvaluationComplexity complexity = _lastExpressionComplexity;
+    if (complexity.isConstant && node.name.name == 'length') {
+      return _evaluateImplicitConstant(node);
+    }
+    return const EvaluationComplexity.lazy();
+  }
+
+  @override
+  EvaluationComplexity visitInstanceTearOff(ir.InstanceTearOff node) {
+    node.receiver = _handleExpression(node.receiver);
+    return const EvaluationComplexity.lazy();
+  }
+
+  @override
+  EvaluationComplexity visitDynamicGet(ir.DynamicGet node) {
+    node.receiver = _handleExpression(node.receiver);
+    EvaluationComplexity complexity = _lastExpressionComplexity;
+    if (complexity.isConstant && node.name.name == 'length') {
+      return _evaluateImplicitConstant(node);
+    }
+    return const EvaluationComplexity.lazy();
+  }
+
+  @override
+  EvaluationComplexity visitFunctionTearOff(ir.FunctionTearOff node) {
+    node.receiver = _handleExpression(node.receiver);
+    return const EvaluationComplexity.lazy();
+  }
+
+  @override
   EvaluationComplexity visitPropertySet(ir.PropertySet node) {
     node.receiver = _handleExpression(node.receiver);
     node.value = _handleExpression(node.value);
@@ -1052,6 +1191,20 @@
   }
 
   @override
+  EvaluationComplexity visitInstanceSet(ir.InstanceSet node) {
+    node.receiver = _handleExpression(node.receiver);
+    node.value = _handleExpression(node.value);
+    return const EvaluationComplexity.lazy();
+  }
+
+  @override
+  EvaluationComplexity visitDynamicSet(ir.DynamicSet node) {
+    node.receiver = _handleExpression(node.receiver);
+    node.value = _handleExpression(node.value);
+    return const EvaluationComplexity.lazy();
+  }
+
+  @override
   EvaluationComplexity visitNot(ir.Not node) {
     node.operand = _handleExpression(node.operand);
     EvaluationComplexity complexity = _lastExpressionComplexity;
diff --git a/pkg/compiler/lib/src/serialization/node_indexer.dart b/pkg/compiler/lib/src/serialization/node_indexer.dart
index 52b27ac..6846687 100644
--- a/pkg/compiler/lib/src/serialization/node_indexer.dart
+++ b/pkg/compiler/lib/src/serialization/node_indexer.dart
@@ -112,18 +112,90 @@
   }
 
   @override
+  void visitInstanceGet(ir.InstanceGet node) {
+    registerNode(node);
+    super.visitInstanceGet(node);
+  }
+
+  @override
+  void visitInstanceTearOff(ir.InstanceTearOff node) {
+    registerNode(node);
+    super.visitInstanceTearOff(node);
+  }
+
+  @override
+  void visitDynamicGet(ir.DynamicGet node) {
+    registerNode(node);
+    super.visitDynamicGet(node);
+  }
+
+  @override
+  void visitFunctionTearOff(ir.FunctionTearOff node) {
+    registerNode(node);
+    super.visitFunctionTearOff(node);
+  }
+
+  @override
   void visitPropertySet(ir.PropertySet node) {
     registerNode(node);
     super.visitPropertySet(node);
   }
 
   @override
+  void visitInstanceSet(ir.InstanceSet node) {
+    registerNode(node);
+    super.visitInstanceSet(node);
+  }
+
+  @override
+  void visitDynamicSet(ir.DynamicSet node) {
+    registerNode(node);
+    super.visitDynamicSet(node);
+  }
+
+  @override
   void visitMethodInvocation(ir.MethodInvocation node) {
     registerNode(node);
     super.visitMethodInvocation(node);
   }
 
   @override
+  void visitInstanceInvocation(ir.InstanceInvocation node) {
+    registerNode(node);
+    super.visitInstanceInvocation(node);
+  }
+
+  @override
+  void visitDynamicInvocation(ir.DynamicInvocation node) {
+    registerNode(node);
+    super.visitDynamicInvocation(node);
+  }
+
+  @override
+  void visitFunctionInvocation(ir.FunctionInvocation node) {
+    registerNode(node);
+    super.visitFunctionInvocation(node);
+  }
+
+  @override
+  void visitLocalFunctionInvocation(ir.LocalFunctionInvocation node) {
+    registerNode(node);
+    super.visitLocalFunctionInvocation(node);
+  }
+
+  @override
+  void visitEqualsNull(ir.EqualsNull node) {
+    registerNode(node);
+    super.visitEqualsNull(node);
+  }
+
+  @override
+  void visitEqualsCall(ir.EqualsCall node) {
+    registerNode(node);
+    super.visitEqualsCall(node);
+  }
+
+  @override
   void visitStaticInvocation(ir.StaticInvocation node) {
     registerNode(node);
     super.visitStaticInvocation(node);
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 5b4f99f..235fefb 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -7134,6 +7134,33 @@
   }
 
   @override
+  visitInstanceGet(ir.InstanceGet node) {
+    registerCall();
+    registerRegularNode();
+    registerReductiveNode();
+    skipReductiveNodes(() => visit(node.name));
+    visit(node.receiver);
+  }
+
+  @override
+  visitInstanceTearOff(ir.InstanceTearOff node) {
+    registerCall();
+    registerRegularNode();
+    registerReductiveNode();
+    skipReductiveNodes(() => visit(node.name));
+    visit(node.receiver);
+  }
+
+  @override
+  visitDynamicGet(ir.DynamicGet node) {
+    registerCall();
+    registerRegularNode();
+    registerReductiveNode();
+    skipReductiveNodes(() => visit(node.name));
+    visit(node.receiver);
+  }
+
+  @override
   visitPropertySet(ir.PropertySet node) {
     registerCall();
     registerRegularNode();
@@ -7144,6 +7171,26 @@
   }
 
   @override
+  visitInstanceSet(ir.InstanceSet node) {
+    registerCall();
+    registerRegularNode();
+    registerReductiveNode();
+    skipReductiveNodes(() => visit(node.name));
+    visit(node.receiver);
+    visit(node.value);
+  }
+
+  @override
+  visitDynamicSet(ir.DynamicSet node) {
+    registerCall();
+    registerRegularNode();
+    registerReductiveNode();
+    skipReductiveNodes(() => visit(node.name));
+    visit(node.receiver);
+    visit(node.value);
+  }
+
+  @override
   visitVariableGet(ir.VariableGet node) {
     if (discountParameters && node.variable.parent is ir.FunctionNode) return;
     registerRegularNode();
@@ -7201,6 +7248,63 @@
     _processArguments(node.arguments, null);
   }
 
+  @override
+  visitInstanceInvocation(ir.InstanceInvocation node) {
+    registerRegularNode();
+    registerReductiveNode();
+    registerCall();
+    visit(node.receiver);
+    skipReductiveNodes(() => visit(node.name));
+    _processArguments(node.arguments, null);
+  }
+
+  @override
+  visitDynamicInvocation(ir.DynamicInvocation node) {
+    registerRegularNode();
+    registerReductiveNode();
+    registerCall();
+    visit(node.receiver);
+    skipReductiveNodes(() => visit(node.name));
+    _processArguments(node.arguments, null);
+  }
+
+  @override
+  visitFunctionInvocation(ir.FunctionInvocation node) {
+    registerRegularNode();
+    registerReductiveNode();
+    registerCall();
+    visit(node.receiver);
+    skipReductiveNodes(() => visit(node.name));
+    _processArguments(node.arguments, null);
+  }
+
+  @override
+  visitLocalFunctionInvocation(ir.LocalFunctionInvocation node) {
+    registerRegularNode();
+    registerReductiveNode();
+    registerCall();
+    _processArguments(node.arguments, null);
+    // Account for the implicit access to the local variable:
+    registerRegularNode();
+    registerReductiveNode();
+  }
+
+  @override
+  visitEqualsNull(ir.EqualsNull node) {
+    registerRegularNode();
+    registerReductiveNode();
+    visit(node.expression);
+  }
+
+  @override
+  visitEqualsCall(ir.EqualsCall node) {
+    registerRegularNode();
+    registerReductiveNode();
+    registerCall();
+    visit(node.left);
+    visit(node.right);
+  }
+
   _processArguments(ir.Arguments arguments, ir.FunctionNode target) {
     registerRegularNode();
     if (arguments.types.isNotEmpty) {
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
index 58af2ac..a4c69bd 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
@@ -9,7 +9,8 @@
 import 'package:_fe_analyzer_shared/src/messages/diagnostic_message.dart'
     show DiagnosticMessage, DiagnosticMessageHandler;
 
-import 'package:_fe_analyzer_shared/src/messages/codes.dart' show Message, Code;
+import 'package:_fe_analyzer_shared/src/messages/codes.dart'
+    show Code, Message, PlainAndColorizedString;
 
 import 'package:dev_compiler/dev_compiler.dart';
 import 'package:dev_compiler/src/js_ast/js_ast.dart' as js_ast;
@@ -44,8 +45,8 @@
   return Message(Code<String>('Expression Compiler Internal error'),
           message: msg)
       .withLocation(uri, 0, 0)
-      .withFormatting(
-          'Internal error: $msg', line, col, Severity.internalProblem, []);
+      .withFormatting(PlainAndColorizedString.plainOnly('Internal error: $msg'),
+          line, col, Severity.internalProblem, []);
 }
 
 /// Dart scope
diff --git a/pkg/front_end/lib/src/api_prototype/terminal_color_support.dart b/pkg/front_end/lib/src/api_prototype/terminal_color_support.dart
index ab69e10..124a899 100644
--- a/pkg/front_end/lib/src/api_prototype/terminal_color_support.dart
+++ b/pkg/front_end/lib/src/api_prototype/terminal_color_support.dart
@@ -4,110 +4,18 @@
 
 library front_end.terminal_color_support;
 
-import 'dart:convert' show jsonEncode;
-
-import 'dart:io' show Platform, Process, ProcessResult, stderr, stdout;
-
 import 'package:_fe_analyzer_shared/src/messages/diagnostic_message.dart'
     show DiagnosticMessage;
 
-import 'package:_fe_analyzer_shared/src/util/colors.dart'
-    show ALL_CODES, TERMINAL_CAPABILITIES;
+import 'package:_fe_analyzer_shared/src/util/colors.dart' show enableColors;
 
-/// True if we should enable colors in output.
-///
-/// We enable colors only when both [stdout] and [stderr] support ANSI escapes.
-final bool enableTerminalColors = _computeEnableColors();
+export 'package:_fe_analyzer_shared/src/util/colors.dart' show enableColors;
 
 void printDiagnosticMessage(
     DiagnosticMessage message, void Function(String) println) {
-  if (enableTerminalColors) {
+  if (enableColors) {
     message.ansiFormatted.forEach(println);
   } else {
     message.plainTextFormatted.forEach(println);
   }
 }
-
-/// On Windows, colors are enabled if both stdout and stderr supports ANSI
-/// escapes.  On other platforms, we rely on the external programs `tty` and
-/// `tput` to compute if ANSI colors are supported.
-bool _computeEnableColors() {
-  const bool debug =
-      const bool.fromEnvironment("front_end.debug_compute_enable_colors");
-
-  if (Platform.isWindows) {
-    if (!stdout.supportsAnsiEscapes || !stderr.supportsAnsiEscapes) {
-      // In this case, either [stdout] or [stderr] did not support the property
-      // `supportsAnsiEscapes`. Since we do not have another way to determine
-      // support for colors, we disable them.
-      if (debug) {
-        print("Not enabling colors as ANSI is not supported.");
-      }
-      return false;
-    }
-    if (debug) {
-      print("Enabling colors as OS is Windows.");
-    }
-    return true;
-  }
-
-  // We have to check if the terminal actually supports colors. Currently, to
-  // avoid linking the Dart VM with ncurses, ANSI escape support is reduced to
-  // `Platform.environment['TERM'].contains("xterm")`.
-
-  // Check if stdin is a terminal (TTY).
-  ProcessResult result =
-      Process.runSync("/bin/sh", ["-c", "tty > /dev/null 2> /dev/null"]);
-
-  if (result.exitCode != 0) {
-    if (debug) {
-      print("Not enabling colors, stdin isn't a terminal.");
-    }
-    return false;
-  }
-
-  // The `-S` option of `tput` allows us to query multiple capabilities at
-  // once.
-  result = Process.runSync(
-      "/bin/sh", ["-c", "printf '%s' '$TERMINAL_CAPABILITIES' | tput -S"]);
-
-  if (result.exitCode != 0) {
-    if (debug) {
-      print("Not enabling colors, running tput failed.");
-    }
-    return false;
-  }
-
-  List<String> lines = result.stdout.split("\n");
-
-  if (lines.length != 2) {
-    if (debug) {
-      print("Not enabling colors, unexpected output from tput: "
-          "${jsonEncode(result.stdout)}.");
-    }
-    return false;
-  }
-
-  String numberOfColors = lines[0];
-  if ((int.tryParse(numberOfColors) ?? -1) < 8) {
-    if (debug) {
-      print("Not enabling colors, less than 8 colors supported: "
-          "${jsonEncode(numberOfColors)}.");
-    }
-    return false;
-  }
-
-  String allCodes = lines[1].trim();
-  if (ALL_CODES != allCodes) {
-    if (debug) {
-      print("Not enabling colors, color codes don't match: "
-          "${jsonEncode(ALL_CODES)} != ${jsonEncode(allCodes)}.");
-    }
-    return false;
-  }
-
-  if (debug) {
-    print("Enabling colors.");
-  }
-  return true;
-}
diff --git a/pkg/front_end/lib/src/api_unstable/vm.dart b/pkg/front_end/lib/src/api_unstable/vm.dart
index 5aa7e6d..5fe07cd 100644
--- a/pkg/front_end/lib/src/api_unstable/vm.dart
+++ b/pkg/front_end/lib/src/api_unstable/vm.dart
@@ -36,7 +36,7 @@
 export '../api_prototype/standard_file_system.dart' show StandardFileSystem;
 
 export '../api_prototype/terminal_color_support.dart'
-    show printDiagnosticMessage;
+    show printDiagnosticMessage, enableColors;
 
 export '../base/nnbd_mode.dart' show NnbdMode;
 
diff --git a/pkg/front_end/lib/src/base/processed_options.dart b/pkg/front_end/lib/src/base/processed_options.dart
index 94a7d0d..1ea8dc4 100644
--- a/pkg/front_end/lib/src/base/processed_options.dart
+++ b/pkg/front_end/lib/src/base/processed_options.dart
@@ -45,6 +45,7 @@
         FormattedMessage,
         LocatedMessage,
         Message,
+        PlainAndColorizedString,
         messageCantInferPackagesFromManyInputs,
         messageCantInferPackagesFromPackageUri,
         messageCompilingWithSoundNullSafety,
@@ -216,7 +217,7 @@
     int offset = message.charOffset;
     Uri uri = message.uri;
     Location location = offset == -1 ? null : getLocation(uri, offset);
-    String formatted =
+    PlainAndColorizedString formatted =
         command_line_reporting.format(message, severity, location: location);
     List<FormattedMessage> formattedContext;
     if (context != null && context.isNotEmpty) {
diff --git a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
index 4c89f92..ae2dc15 100644
--- a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
@@ -198,6 +198,8 @@
     origin.procedure.isExternal = _procedure.isExternal;
     origin.procedure.function = _procedure.function;
     origin.procedure.function.parent = origin.procedure;
+    origin.procedure.isRedirectingFactoryConstructor =
+        _procedure.isRedirectingFactoryConstructor;
     return 1;
   }
 }
@@ -712,6 +714,7 @@
     bodyInternal = new RedirectingFactoryBody(target, typeArguments);
     function.body = bodyInternal;
     bodyInternal?.parent = function;
+    procedure.isRedirectingFactoryConstructor = true;
     if (isPatch) {
       if (function.typeParameters != null) {
         Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{};
diff --git a/pkg/front_end/lib/src/fasta/command_line_reporting.dart b/pkg/front_end/lib/src/fasta/command_line_reporting.dart
index 2b05cc6..9ff9cf4 100644
--- a/pkg/front_end/lib/src/fasta/command_line_reporting.dart
+++ b/pkg/front_end/lib/src/fasta/command_line_reporting.dart
@@ -21,7 +21,7 @@
     show $CARET, $SPACE, $TAB;
 
 import 'package:_fe_analyzer_shared/src/util/colors.dart'
-    show enableColors, green, magenta, red, yellow;
+    show green, magenta, red, yellow;
 
 import 'package:_fe_analyzer_shared/src/util/relativize.dart'
     show isWindows, relativizeUri;
@@ -34,7 +34,7 @@
 
 import 'crash.dart' show Crash, safeToString;
 
-import 'fasta_codes.dart' show LocatedMessage;
+import 'fasta_codes.dart' show LocatedMessage, PlainAndColorizedString;
 
 import 'messages.dart' show getLocation, getSourceLine;
 
@@ -42,10 +42,10 @@
 
 const bool hideWarnings = false;
 
-/// Formats [message] as a string that is suitable for output from a
-/// command-line tool. This includes source snippets and different colors based
-/// on [severity].
-String format(LocatedMessage message, Severity severity,
+/// Formats [message] as two strings that is suitable for output from a
+/// command-line tool. This includes source snippets and - in the colorized
+/// version - different colors based on [severity].
+PlainAndColorizedString format(LocatedMessage message, Severity severity,
     {Location location, Map<Uri, Source> uriToSource}) {
   try {
     int length = message.length;
@@ -55,34 +55,34 @@
       length = 1;
     }
     String prefix = severityPrefixes[severity];
-    String messageText =
+    String messageTextTmp =
         prefix == null ? message.message : "$prefix: ${message.message}";
     if (message.tip != null) {
-      messageText += "\n${message.tip}";
+      messageTextTmp += "\n${message.tip}";
     }
-    if (enableColors) {
-      switch (severity) {
-        case Severity.error:
-        case Severity.internalProblem:
-          messageText = red(messageText);
-          break;
+    final String messageTextPlain = messageTextTmp;
+    String messageTextColorized;
+    switch (severity) {
+      case Severity.error:
+      case Severity.internalProblem:
+        messageTextColorized = red(messageTextPlain);
+        break;
 
-        case Severity.warning:
-          messageText = magenta(messageText);
-          break;
+      case Severity.warning:
+        messageTextColorized = magenta(messageTextPlain);
+        break;
 
-        case Severity.context:
-          messageText = green(messageText);
-          break;
+      case Severity.context:
+        messageTextColorized = green(messageTextPlain);
+        break;
 
-        case Severity.info:
-          messageText = yellow(messageText);
-          break;
+      case Severity.info:
+        messageTextColorized = yellow(messageTextPlain);
+        break;
 
-        case Severity.ignored:
-        default:
-          return unhandled("$severity", "format", -1, null);
-      }
+      case Severity.ignored:
+      default:
+        return unhandled("$severity", "format", -1, null);
     }
 
     if (message.uri != null) {
@@ -94,10 +94,17 @@
         location = null;
       }
       String sourceLine = getSourceLine(location, uriToSource);
-      return formatErrorMessage(
-          sourceLine, location, length, path, messageText);
+      return new PlainAndColorizedString(
+        formatErrorMessage(
+            sourceLine, location, length, path, messageTextPlain),
+        formatErrorMessage(
+            sourceLine, location, length, path, messageTextColorized),
+      );
     } else {
-      return messageText;
+      return new PlainAndColorizedString(
+        messageTextPlain,
+        messageTextColorized,
+      );
     }
   } catch (error, trace) {
     print("Crash when formatting: "
diff --git a/pkg/front_end/lib/src/fasta/compiler_context.dart b/pkg/front_end/lib/src/fasta/compiler_context.dart
index a1d2005..913a4e1 100644
--- a/pkg/front_end/lib/src/fasta/compiler_context.dart
+++ b/pkg/front_end/lib/src/fasta/compiler_context.dart
@@ -8,6 +8,7 @@
 
 import 'dart:async' show Zone, runZoned;
 
+import 'package:_fe_analyzer_shared/src/messages/codes.dart';
 import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
 
 import 'package:_fe_analyzer_shared/src/util/colors.dart' as colors;
@@ -79,16 +80,10 @@
   }
 
   /// Format [message] as a text string that can be included in generated code.
-  String format(LocatedMessage message, Severity severity) {
+  PlainAndColorizedString format(LocatedMessage message, Severity severity) {
     return command_line_reporting.format(message, severity);
   }
 
-  /// Format [message] as a text string that can be included in generated code.
-  // TODO(askesc): Remove this and direct callers directly to format.
-  String formatWithoutLocation(Message message, Severity severity) {
-    return command_line_reporting.format(message.withoutLocation(), severity);
-  }
-
   // TODO(ahe): Remove this.
   void logError(Object message, Severity severity) {
     errors.add(message);
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 15637c2..e5da386 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -5981,7 +5981,8 @@
           wasHandled: true, context: context);
     }
     String text = libraryBuilder.loader.target.context
-        .format(message.withLocation(uri, charOffset, length), Severity.error);
+        .format(message.withLocation(uri, charOffset, length), Severity.error)
+        .plain;
     InvalidExpression expression = new InvalidExpression(text)
       ..fileOffset = charOffset;
     return expression;
@@ -6456,7 +6457,8 @@
     addProblemErrorIfConst(message, charOffset, length,
         wasHandled: wasHandled, context: context);
     String text = libraryBuilder.loader.target.context
-        .format(message.withLocation(uri, charOffset, length), Severity.error);
+        .format(message.withLocation(uri, charOffset, length), Severity.error)
+        .plain;
     InvalidExpression expression = new InvalidExpression(text)
       ..fileOffset = charOffset;
     return expression;
diff --git a/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart b/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
index 0d82df2..cdbabbe 100644
--- a/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
@@ -6,22 +6,7 @@
 
 library fasta.redirecting_factory_body;
 
-import 'package:kernel/ast.dart'
-    show
-        DartType,
-        Expression,
-        ExpressionStatement,
-        Field,
-        FunctionNode,
-        InvalidExpression,
-        Let,
-        Member,
-        NullLiteral,
-        Procedure,
-        StaticGet,
-        StringLiteral,
-        TypeParameterType,
-        VariableDeclaration;
+import 'package:kernel/ast.dart';
 
 import 'package:kernel/type_algebra.dart' show Substitution;
 
@@ -44,6 +29,10 @@
 /// information in a factory method body.
 const String letName = "#redirecting_factory";
 
+/// Name used for a synthesized let variable used to encode type arguments to
+/// the redirection target in a factory method body.
+const String varNamePrefix = "#typeArg";
+
 class RedirectingFactoryBody extends ExpressionStatement {
   RedirectingFactoryBody.internal(Expression value,
       [List<DartType> typeArguments])
@@ -104,8 +93,38 @@
       ..parent = function;
   }
 
+  static bool hasRedirectingFactoryBodyShape(Procedure factory) {
+    if (factory.function.body is! ExpressionStatement) return false;
+    Expression body = (factory.function.body as ExpressionStatement).expression;
+    if (body is Let &&
+        body.variable.name == letName &&
+        body.variable.type is DynamicType &&
+        body.variable.initializer is StaticGet) {
+      Expression currentArgument = body.body;
+      int argumentCount = 0;
+      while (currentArgument is! InvalidExpression) {
+        Expression argument = currentArgument;
+        if (argument is Let) {
+          String argumentName = "${varNamePrefix}${argumentCount}";
+          if (argument.variable.name != argumentName) {
+            return false;
+          }
+          if (argument.variable.initializer is! NullLiteral) {
+            return false;
+          }
+          currentArgument = argument.body;
+          ++argumentCount;
+        } else {
+          return false;
+        }
+      }
+      return true;
+    } else {
+      return false;
+    }
+  }
+
   static Expression encodeTypeArguments(List<DartType> typeArguments) {
-    String varNamePrefix = "#typeArg";
     Expression result = new InvalidExpression(null);
     if (typeArguments == null) {
       return result;
diff --git a/pkg/front_end/lib/src/fasta/kernel/verifier.dart b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
index 468697e..9a23516 100644
--- a/pkg/front_end/lib/src/fasta/kernel/verifier.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
@@ -29,7 +29,10 @@
 import '../type_inference/type_schema.dart' show UnknownType;
 
 import 'redirecting_factory_body.dart'
-    show RedirectingFactoryBody, getRedirectingFactoryBody;
+    show
+        RedirectingFactoryBody,
+        getRedirectingFactoryBody,
+        isRedirectingFactory;
 
 List<LocatedMessage> verifyComponent(Component component,
     {bool isOutline, bool afterConst, bool skipPlatform: false}) {
@@ -220,7 +223,11 @@
   @override
   void visitLibrary(Library node) {
     // Issue(http://dartbug.com/32530)
-    if (skipPlatform && node.importUri.scheme == 'dart') {
+    // 'dart:test' is used in the unit tests and isn't an actual part of the
+    // platform.
+    if (skipPlatform &&
+        node.importUri.scheme == 'dart' &&
+        node.importUri.path != 'test') {
       return;
     }
 
@@ -260,6 +267,22 @@
   void visitProcedure(Procedure node) {
     enterTreeNode(node);
     fileUri = checkLocation(node, node.name.text, node.fileUri);
+
+    // TODO(dmitryas): Investigate why some redirecting factory bodies retain
+    // the shape, but aren't of the RedirectingFactoryBody type.
+    bool hasBody = isRedirectingFactory(node) ||
+        RedirectingFactoryBody.hasRedirectingFactoryBodyShape(node);
+    bool hasFlag = node.isRedirectingFactoryConstructor;
+    if (hasBody != hasFlag) {
+      String hasBodyString = hasBody ? "has" : "doesn't have";
+      String hasFlagString = hasFlag ? "has" : "doesn't have";
+      problem(
+          node,
+          "Procedure '${node.name}' ${hasBodyString} a body "
+          "of a redirecting factory, but ${hasFlagString} the "
+          "'isRedirectingFactoryConstructor' bit set.");
+    }
+
     super.visitProcedure(node);
     exitTreeNode(node);
   }
@@ -422,7 +445,11 @@
 
   @override
   visitLibrary(Library node) {
-    if (skipPlatform && node.importUri.scheme == 'dart') {
+    // 'dart:test' is used in the unit tests and isn't an actual part of the
+    // platform.
+    if (skipPlatform &&
+        node.importUri.scheme == 'dart' &&
+        node.importUri.path != "test") {
       return;
     }
 
diff --git a/pkg/front_end/test/desugar_test.dart b/pkg/front_end/test/desugar_test.dart
index 3ebad1e..7aa716d 100644
--- a/pkg/front_end/test/desugar_test.dart
+++ b/pkg/front_end/test/desugar_test.dart
@@ -54,13 +54,11 @@
   var component = new ir.Component();
   new BinaryBuilder(new File.fromUri(componentUri).readAsBytesSync())
       .readComponent(component);
-  checkIsRedirectingFactory(component, 'collection', 'HashMap', 'identity',
-      isPatch: true);
+  checkIsRedirectingFactory(component, 'collection', 'HashMap', 'identity');
 }
 
 void checkIsRedirectingFactory(ir.Component component, String uriPath,
-    String className, String constructorName,
-    {bool isPatch: false}) {
+    String className, String constructorName) {
   var lib =
       component.libraries.firstWhere((l) => l.importUri.path.endsWith(uriPath));
   var cls = lib.classes.firstWhere((c) => c.name == className);
@@ -69,8 +67,7 @@
   Expect.isTrue(
       member.kind == ir.ProcedureKind.Factory, "$member is not a factory");
   Expect.isTrue(api.isRedirectingFactory(member));
-  // TODO: this should always be true. Issue #33495
-  Expect.equals(!isPatch, member.isRedirectingFactoryConstructor);
+  Expect.isTrue(member.isRedirectingFactoryConstructor);
 }
 
 const aSource = '''
diff --git a/pkg/front_end/test/lint_test.status b/pkg/front_end/test/lint_test.status
index 2728954..691adfa 100644
--- a/pkg/front_end/test/lint_test.status
+++ b/pkg/front_end/test/lint_test.status
@@ -14,6 +14,7 @@
 front_end/lib/src/api_prototype/front_end/Exports: Fail
 front_end/lib/src/api_prototype/incremental_kernel_generator/Exports: Fail
 front_end/lib/src/api_prototype/language_version/Exports: Fail
+front_end/lib/src/api_prototype/terminal_color_support/Exports: Fail
 front_end/lib/src/api_unstable/bazel_worker/ImportsTwice: Fail
 front_end/lib/src/fasta/fasta_codes/Exports: Fail
 front_end/lib/src/fasta/incremental_compiler/ImportsTwice: Fail
diff --git a/pkg/front_end/test/messages_json_test.dart b/pkg/front_end/test/messages_json_test.dart
index e8fe28a..7f87ca4 100644
--- a/pkg/front_end/test/messages_json_test.dart
+++ b/pkg/front_end/test/messages_json_test.dart
@@ -27,18 +27,34 @@
     LocatedMessage locatedMessage1 =
         new LocatedMessage(Uri.parse("what:ever/fun_1.dart"), 117, 2, message);
     FormattedMessage formattedMessage2 = new FormattedMessage(
-        null, "Formatted string #2", 13, 2, Severity.error, []);
+        null,
+        "Formatted string Plain #2",
+        "Formatted string Colorized #2",
+        13,
+        2,
+        Severity.error, []);
     FormattedMessage formattedMessage3 = new FormattedMessage(
-        null, "Formatted string #3", 313, 32, Severity.error, []);
+        null,
+        "Formatted string Plain #3",
+        "Formatted string Colorized #3",
+        313,
+        32,
+        Severity.error, []);
 
     FormattedMessage formattedMessage1 = new FormattedMessage(
-        locatedMessage1, "Formatted string", 42, 86, severity, [
+        locatedMessage1,
+        "Formatted string Plain",
+        "Formatted string Colorized",
+        42,
+        86,
+        severity, [
       formattedMessage2,
       formattedMessage3
-    ], involvedFiles: [
-      Uri.parse("what:ever/foo.dart"),
-      Uri.parse("what:ever/bar.dart")
-    ]);
+    ],
+        involvedFiles: [
+          Uri.parse("what:ever/foo.dart"),
+          Uri.parse("what:ever/bar.dart")
+        ]);
     expect(formattedMessage1.codeName, "MyCodeName");
 
     DiagnosticMessageFromJson diagnosticMessageFromJson =
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 60a1dd6..8fe1b6b 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -210,6 +210,7 @@
 codec
 codes
 collision
+colorized
 com
 combinations
 combinator
diff --git a/pkg/front_end/test/static_types/cfe_allowed.json b/pkg/front_end/test/static_types/cfe_allowed.json
index 63088f0..ca079c1 100644
--- a/pkg/front_end/test/static_types/cfe_allowed.json
+++ b/pkg/front_end/test/static_types/cfe_allowed.json
@@ -1,7 +1,4 @@
 {
-  "pkg/front_end/lib/src/api_prototype/terminal_color_support.dart": {
-    "Dynamic invocation of 'split'.": 1
-  },
   "pkg/front_end/lib/src/base/libraries_specification.dart": {
     "Dynamic invocation of 'toList'.": 1,
     "Dynamic invocation of 'map'.": 1,
diff --git a/pkg/front_end/test/utils/validating_instrumentation.dart b/pkg/front_end/test/utils/validating_instrumentation.dart
index 184e7cb..1c1af83 100644
--- a/pkg/front_end/test/utils/validating_instrumentation.dart
+++ b/pkg/front_end/test/utils/validating_instrumentation.dart
@@ -228,11 +228,14 @@
 
   String _formatProblem(
       Uri uri, int offset, String desc, StackTrace stackTrace) {
-    return CompilerContext.current.format(
-        templateUnspecified
-            .withArguments('$desc${stackTrace == null ? '' : '\n$stackTrace'}')
-            .withLocation(uri, offset, noLength),
-        Severity.internalProblem);
+    return CompilerContext.current
+        .format(
+            templateUnspecified
+                .withArguments(
+                    '$desc${stackTrace == null ? '' : '\n$stackTrace'}')
+                .withLocation(uri, offset, noLength),
+            Severity.internalProblem)
+        .plain;
   }
 
   String _makeExpectationComment(String property, InstrumentationValue value) {
diff --git a/pkg/front_end/testcases/general/issue45101/libraries.json b/pkg/front_end/testcases/general/issue45101/libraries.json
new file mode 100644
index 0000000..154c73c
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45101/libraries.json
@@ -0,0 +1,12 @@
+{
+  "none": {
+    "libraries": {
+      "test": {
+        "patches": [
+          "patch_lib.dart"
+        ],
+        "uri": "origin_lib.dart"
+      }
+    }
+  }
+}
diff --git a/pkg/front_end/testcases/general/issue45101/main.dart b/pkg/front_end/testcases/general/issue45101/main.dart
new file mode 100644
index 0000000..171b59b
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45101/main.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// @dart=2.9
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45101/main.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue45101/main.dart.textual_outline.expect
new file mode 100644
index 0000000..9ededd9
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45101/main.dart.textual_outline.expect
@@ -0,0 +1,4 @@
+// @dart = 2.9
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45101/main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue45101/main.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..9ededd9
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45101/main.dart.textual_outline_modelled.expect
@@ -0,0 +1,4 @@
+// @dart = 2.9
+import 'dart:test';
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45101/main.dart.weak.expect b/pkg/front_end/testcases/general/issue45101/main.dart.weak.expect
new file mode 100644
index 0000000..8c7b289
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45101/main.dart.weak.expect
@@ -0,0 +1,60 @@
+library;
+import self as self;
+
+import "dart:test";
+
+static method main() → dynamic {}
+
+library;
+import self as self2;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+import "dart:_internal";
+
+class _ArraySize<T extends core::Object* = dynamic> extends core::Object implements self2::Array<self2::_ArraySize::T*> /*hasConstConstructor*/  { // from org-dartlang-testcase:///patch_lib.dart
+  final field core::int* foo;
+  const constructor •(core::int* foo) → self2::_ArraySize<self2::_ArraySize::T*>*
+    : self2::_ArraySize::foo = foo, super core::Object::•()
+    ;
+  abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+  abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+  abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+  abstract member-signature method toString() → core::String*; -> core::Object::toString
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+  abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+@#C1
+@#C4
+class Array<T extends core::Object* = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self2::Array::•];
+  @#C1
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ •<T extends core::Object* = dynamic>(core::int* foo) → self2::Array<self2::Array::•::T*>*
+    let dynamic #redirecting_factory = self2::_ArraySize::• in let self2::Array::•::T* #typeArg0 = null in invalid-expression;
+  abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+  abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+  abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+  abstract member-signature method toString() → core::String*; -> core::Object::toString
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+  abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+
+constants  {
+  #C1 = _in::_Patch {}
+  #C2 = "vm:entry-point"
+  #C3 = null
+  #C4 = core::pragma {name:#C2, options:#C3}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///origin_lib.dart:
+- pragma._ (from org-dartlang-sdk:///sdk/lib/core/annotations.dart:188:9)
diff --git a/pkg/front_end/testcases/general/issue45101/main.dart.weak.outline.expect b/pkg/front_end/testcases/general/issue45101/main.dart.weak.outline.expect
new file mode 100644
index 0000000..c56c375
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45101/main.dart.weak.outline.expect
@@ -0,0 +1,56 @@
+library;
+import self as self;
+
+import "dart:test";
+
+static method main() → dynamic
+  ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+import "dart:_internal";
+
+class _ArraySize<T extends core::Object* = dynamic> extends core::Object implements self2::Array<self2::_ArraySize::T*> /*hasConstConstructor*/  { // from org-dartlang-testcase:///patch_lib.dart
+  final field core::int* foo;
+  const constructor •(core::int* foo) → self2::_ArraySize<self2::_ArraySize::T*>*
+    : self2::_ArraySize::foo = foo, super core::Object::•()
+    ;
+  abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+  abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+  abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+  abstract member-signature method toString() → core::String*; -> core::Object::toString
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+  abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+@_in::patch
+@core::pragma::_("vm:entry-point")
+class Array<T extends core::Object* = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self2::Array::•];
+  @_in::patch
+  external static factory •<T extends core::Object* = dynamic>(core::int* foo) → self2::Array<self2::Array::•::T*>*
+    let dynamic #redirecting_factory = self2::_ArraySize::• in let self2::Array::•::T* #typeArg0 = null in invalid-expression;
+  abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+  abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+  abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+  abstract member-signature method toString() → core::String*; -> core::Object::toString
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+  abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+
+
+Extra constant evaluation status:
+Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:10:1 -> InstanceConstant(const _Patch{})
+Evaluated: ConstructorInvocation @ (unknown position in org-dartlang-testcase:///origin_lib.dart) -> InstanceConstant(const pragma{pragma.name: "vm:entry-point", pragma.options: null})
+Evaluated: StaticGet @ (unknown position in org-dartlang-testcase:///origin_lib.dart) -> InstanceConstant(const _Patch{})
+Extra constant evaluation: evaluated: 9, effectively constant: 3
diff --git a/pkg/front_end/testcases/general/issue45101/main.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue45101/main.dart.weak.transformed.expect
new file mode 100644
index 0000000..8c7b289
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45101/main.dart.weak.transformed.expect
@@ -0,0 +1,60 @@
+library;
+import self as self;
+
+import "dart:test";
+
+static method main() → dynamic {}
+
+library;
+import self as self2;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+import "dart:_internal";
+
+class _ArraySize<T extends core::Object* = dynamic> extends core::Object implements self2::Array<self2::_ArraySize::T*> /*hasConstConstructor*/  { // from org-dartlang-testcase:///patch_lib.dart
+  final field core::int* foo;
+  const constructor •(core::int* foo) → self2::_ArraySize<self2::_ArraySize::T*>*
+    : self2::_ArraySize::foo = foo, super core::Object::•()
+    ;
+  abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+  abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+  abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+  abstract member-signature method toString() → core::String*; -> core::Object::toString
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+  abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+@#C1
+@#C4
+class Array<T extends core::Object* = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self2::Array::•];
+  @#C1
+  static factory /* from org-dartlang-testcase:///patch_lib.dart */ •<T extends core::Object* = dynamic>(core::int* foo) → self2::Array<self2::Array::•::T*>*
+    let dynamic #redirecting_factory = self2::_ArraySize::• in let self2::Array::•::T* #typeArg0 = null in invalid-expression;
+  abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+  abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+  abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+  abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+  abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+  abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+  abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+  abstract member-signature method toString() → core::String*; -> core::Object::toString
+  abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+  abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+
+constants  {
+  #C1 = _in::_Patch {}
+  #C2 = "vm:entry-point"
+  #C3 = null
+  #C4 = core::pragma {name:#C2, options:#C3}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///origin_lib.dart:
+- pragma._ (from org-dartlang-sdk:///sdk/lib/core/annotations.dart:188:9)
diff --git a/pkg/front_end/testcases/general/issue45101/origin_lib.dart b/pkg/front_end/testcases/general/issue45101/origin_lib.dart
new file mode 100644
index 0000000..2aabe5a
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45101/origin_lib.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// @dart=2.9
+
+class Array<T> {
+  external const factory Array(int foo);
+}
diff --git a/pkg/front_end/testcases/general/issue45101/patch_lib.dart b/pkg/front_end/testcases/general/issue45101/patch_lib.dart
new file mode 100644
index 0000000..b5a1fd5
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45101/patch_lib.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// @dart=2.9
+// ignore: import_internal_library
+import 'dart:_internal';
+
+@patch
+@pragma("vm:entry-point")
+class Array<T> {
+  // ...
+
+  @patch
+  const factory Array(int foo) = _ArraySize<T>;
+}
+
+class _ArraySize<T> implements Array<T> {
+  final int foo;
+
+  const _ArraySize(this.foo);
+}
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect
index 910440d..fa7c510 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.expect
@@ -24,4 +24,4 @@
 
 Constructor coverage from constants:
 org-dartlang-testcase:///ffi_struct_inline_array.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:107:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/ffi_patch.dart:133:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
index 494a391..77d29d6 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.strong.transformed.expect
@@ -50,4 +50,4 @@
 
 Constructor coverage from constants:
 org-dartlang-testcase:///ffi_struct_inline_array.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:107:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/ffi_patch.dart:133:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect
index e502c15..5125b89 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.expect
@@ -24,4 +24,4 @@
 
 Constructor coverage from constants:
 org-dartlang-testcase:///ffi_struct_inline_array.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:107:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/ffi_patch.dart:133:9)
diff --git a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
index c9607e0..bd41225 100644
--- a/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/ffi_struct_inline_array.dart.weak.transformed.expect
@@ -50,4 +50,4 @@
 
 Constructor coverage from constants:
 org-dartlang-testcase:///ffi_struct_inline_array.dart:
-- _ArraySize. (from org-dartlang-sdk:///sdk/lib/ffi/ffi.dart:107:9)
+- _ArraySize. (from org-dartlang-sdk:///sdk/lib/_internal/vm/lib/ffi_patch.dart:133:9)
diff --git a/pkg/front_end/tool/_fasta/command_line.dart b/pkg/front_end/tool/_fasta/command_line.dart
index 754f7f2..e38ab78 100644
--- a/pkg/front_end/tool/_fasta/command_line.dart
+++ b/pkg/front_end/tool/_fasta/command_line.dart
@@ -24,6 +24,7 @@
 
 import 'package:front_end/src/api_prototype/standard_file_system.dart'
     show StandardFileSystem;
+import 'package:front_end/src/api_prototype/terminal_color_support.dart';
 import 'package:front_end/src/base/nnbd_mode.dart';
 
 import 'package:front_end/src/base/processed_options.dart'
@@ -39,9 +40,10 @@
 import 'package:front_end/src/fasta/fasta_codes.dart'
     show
         Message,
-        templateFastaCLIArgumentRequired,
+        PlainAndColorizedString,
         messageFastaUsageLong,
         messageFastaUsageShort,
+        templateFastaCLIArgumentRequired,
         templateUnspecified;
 
 import 'package:front_end/src/fasta/problems.dart' show DebugAbort;
@@ -440,10 +442,18 @@
     problem = e;
   }
 
-  return CompilerContext.runWithOptions<T>(options, (c) {
+  return CompilerContext.runWithOptions<T>(options, (CompilerContext c) {
     if (problem != null) {
       print(computeUsage(programName, options.verbose).message);
-      print(c.formatWithoutLocation(problem.message, Severity.error));
+      PlainAndColorizedString formatted =
+          c.format(problem.message.withoutLocation(), Severity.error);
+      String formattedText;
+      if (enableColors) {
+        formattedText = formatted.colorized;
+      } else {
+        formattedText = formatted.plain;
+      }
+      print(formattedText);
       exit(1);
     }
 
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index 0fcaf18..4c46e9e 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -93,7 +93,8 @@
     int nullSafety,
     List<String> experimentalFlags,
     Uri packagesUri,
-    List<String> errors,
+    List<String> errorsPlain,
+    List<String> errorsColorized,
     String invocationModes,
     String verbosityLevel) {
   final expFlags = <String>[];
@@ -113,8 +114,10 @@
     ..verbose = verbose
     ..omitPlatform = true
     ..explicitExperimentalFlags = parseExperimentalFlags(
-        parseExperimentalArguments(expFlags),
-        onError: (msg) => errors.add(msg))
+        parseExperimentalArguments(expFlags), onError: (msg) {
+      errorsPlain.add(msg);
+      errorsColorized.add(msg);
+    })
     ..environmentDefines = new EnvironmentMap()
     ..nnbdMode = (nullSafety == kNullSafetyOptionStrong)
         ? NnbdMode.Strong
@@ -128,7 +131,8 @@
           // TODO(sigmund): support emitting code with errors as long as they
           // are handled in the generated code.
           printToStdErr = false; // errors are printed by VM
-          errors.addAll(message.plainTextFormatted);
+          errorsPlain.addAll(message.plainTextFormatted);
+          errorsColorized.addAll(message.ansiFormatted);
           break;
         case Severity.warning:
           printToStdErr = true;
@@ -168,7 +172,8 @@
   final bool supportCodeCoverage;
   final bool supportHotReload;
 
-  final List<String> errors = <String>[];
+  final List<String> errorsPlain = <String>[];
+  final List<String> errorsColorized = <String>[];
 
   CompilerOptions options;
 
@@ -202,7 +207,8 @@
         nullSafety,
         experimentalFlags,
         packagesUri,
-        errors,
+        errorsPlain,
+        errorsColorized,
         invocationModes,
         verbosityLevel);
   }
@@ -212,7 +218,7 @@
       final CompilerResult compilerResult = await compileInternal(script);
       final Component component = compilerResult.component;
 
-      if (errors.isEmpty) {
+      if (errorsPlain.isEmpty) {
         // Record dependencies only if compilation was error free.
         _recordDependencies(isolateGroupId, component, options.packagesFileUri);
       }
@@ -333,7 +339,8 @@
     if (generator == null) {
       generator = new IncrementalCompiler(options, script);
     }
-    errors.clear();
+    errorsPlain.clear();
+    errorsColorized.clear();
     final component = await generator.compile(entryPoint: script);
     return new CompilerResult(component, const {},
         generator.getClassHierarchy(), generator.getCoreTypes());
@@ -609,7 +616,8 @@
     return;
   }
 
-  compiler.errors.clear();
+  compiler.errorsPlain.clear();
+  compiler.errorsColorized.clear();
 
   CompilationResult result;
   try {
@@ -622,10 +630,13 @@
       return;
     }
 
-    if (compiler.errors.isNotEmpty) {
+    assert(compiler.errorsPlain.length == compiler.errorsColorized.length);
+    // Any error will be printed verbatim in observatory, so we always use the
+    // plain version (i.e. the one without ANSI escape codes in it).
+    if (compiler.errorsPlain.isNotEmpty) {
       // TODO(sigmund): the compiler prints errors to the console, so we
       // shouldn't print those messages again here.
-      result = new CompilationResult.errors(compiler.errors, null);
+      result = new CompilationResult.errors(compiler.errorsPlain, null);
     } else {
       Component component = createExpressionEvaluationComponent(procedure);
       result = new CompilationResult.ok(serializeComponent(component));
@@ -811,7 +822,8 @@
       // resolve it against the working directory.
       packagesUri = Uri.directory(workingDirectory).resolveUri(packagesUri);
     }
-    final List<String> errors = <String>[];
+    final List<String> errorsPlain = <String>[];
+    final List<String> errorsColorized = <String>[];
     var options = setupCompilerOptions(
         fileSystem,
         platformKernelPath,
@@ -819,7 +831,8 @@
         nullSafety,
         experimentalFlags,
         packagesUri,
-        errors,
+        errorsPlain,
+        errorsColorized,
         invocationModes,
         verbosityLevel);
 
@@ -872,14 +885,22 @@
     CompilerResult compilerResult = await compiler.compile(script);
     Set<Library> loadedLibraries = compilerResult.loadedLibraries;
 
-    if (compiler.errors.isNotEmpty) {
+    assert(compiler.errorsPlain.length == compiler.errorsColorized.length);
+    // http://dartbug.com/45137
+    // enableColors calls `stdout.supportsAnsiEscapes` which - on Windows -
+    // does something with line endings. To avoid this when no error
+    // messages are do be printed anyway, we are carefull not to call it unless
+    // neccessary.
+    if (compiler.errorsColorized.isNotEmpty) {
+      final List<String> errors =
+          (enableColors) ? compiler.errorsColorized : compiler.errorsPlain;
       if (compilerResult.component != null) {
         result = new CompilationResult.errors(
-            compiler.errors,
+            errors,
             serializeComponent(compilerResult.component,
                 filter: (lib) => !loadedLibraries.contains(lib)));
       } else {
-        result = new CompilationResult.errors(compiler.errors, null);
+        result = new CompilationResult.errors(errors, null);
       }
     } else {
       // We serialize the component excluding vm_platform.dill because the VM has
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 1bb096e..e3708c8 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -229,7 +229,8 @@
 
     bool has_field_initializers = false;
     for (intptr_t i = 0; i < list_length; ++i) {
-      if (PeekTag() == kRedirectingInitializer) {
+      if (PeekTag() == kRedirectingInitializer ||
+          PeekTag() == kRedirectingFactoryConstructor) {
         is_redirecting_constructor = true;
       } else if (PeekTag() == kFieldInitializer) {
         has_field_initializers = true;
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 06aeae2..1da5a95 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -433,15 +433,18 @@
 }
 
 const String& TranslationHelper::DartProcedureName(NameIndex procedure) {
-  ASSERT(IsProcedure(procedure));
+  ASSERT(IsProcedure(procedure) || IsConstructor(procedure));
   if (IsSetter(procedure)) {
     return DartSetterName(procedure);
   } else if (IsGetter(procedure)) {
     return DartGetterName(procedure);
   } else if (IsFactory(procedure)) {
     return DartFactoryName(procedure);
-  } else {
+  } else if (IsMethod(procedure)) {
     return DartMethodName(procedure);
+  } else {
+    ASSERT(IsConstructor(procedure));
+    return DartConstructorName(procedure);
   }
 }
 
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index ed93ed2..38dbcda 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -122,6 +122,15 @@
       throw RangeError.range(index, 0, _size);
     }
   }
+
+  @patch
+  const factory Array(int dimension1) = _ArraySize<T>;
+}
+
+class _ArraySize<T extends NativeType> implements Array<T> {
+  final int dimension1;
+
+  const _ArraySize(this.dimension1);
 }
 
 /// Returns an integer encoding the ABI used for size and alignment
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index e747811..8510065 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -97,14 +97,7 @@
   /// ```
   ///
   /// Do not invoke in normal code.
-  const factory Array(int dimension1) = _ArraySize<T>;
-}
-
-// TODO(http://dartbug.com/45101): Move to ffi_patch.dart.
-class _ArraySize<T extends NativeType> implements Array<T> {
-  final int dimension1;
-
-  const _ArraySize(this.dimension1);
+  external const factory Array(int dimension1);
 }
 
 /// Extension on [Pointer] specialized for the type argument [NativeFunction].
diff --git a/tests/ffi/structs_test.dart b/tests/ffi/structs_test.dart
index 77026a4..18448c0 100644
--- a/tests/ffi/structs_test.dart
+++ b/tests/ffi/structs_test.dart
@@ -4,7 +4,7 @@
 //
 // Dart test program for testing dart:ffi struct pointers.
 //
-// VMOptions=--deterministic --optimization-counter-threshold=50 --enable-inlining-annotations
+// VMOptions=--deterministic --optimization-counter-threshold=50
 
 import 'dart:ffi';
 
diff --git a/tests/ffi_2/structs_test.dart b/tests/ffi_2/structs_test.dart
index 77026a4..18448c0 100644
--- a/tests/ffi_2/structs_test.dart
+++ b/tests/ffi_2/structs_test.dart
@@ -4,7 +4,7 @@
 //
 // Dart test program for testing dart:ffi struct pointers.
 //
-// VMOptions=--deterministic --optimization-counter-threshold=50 --enable-inlining-annotations
+// VMOptions=--deterministic --optimization-counter-threshold=50
 
 import 'dart:ffi';
 
diff --git a/tests/standalone/io/https_connection_closed_during_handshake_test.dart b/tests/standalone/io/https_connection_closed_during_handshake_test.dart
index 7918ee2..0d82100 100644
--- a/tests/standalone/io/https_connection_closed_during_handshake_test.dart
+++ b/tests/standalone/io/https_connection_closed_during_handshake_test.dart
@@ -50,8 +50,11 @@
 
   asyncStart();
 
-  final serverProcess = await Process.start(
-      Platform.executable, [Platform.script.toFilePath(), 'server']);
+  final serverProcess = await Process.start(Platform.executable, [
+    ...Platform.executableArguments,
+    Platform.script.toFilePath(),
+    'server'
+  ]);
   final serverPortCompleter = Completer<int>();
 
   serverProcess.stdout
diff --git a/tests/standalone_2/io/https_connection_closed_during_handshake_test.dart b/tests/standalone_2/io/https_connection_closed_during_handshake_test.dart
index 789f529..0d82100 100644
--- a/tests/standalone_2/io/https_connection_closed_during_handshake_test.dart
+++ b/tests/standalone_2/io/https_connection_closed_during_handshake_test.dart
@@ -47,10 +47,14 @@
     print('server: exiting');
     exit(1);
   }
+
   asyncStart();
 
-  final serverProcess = await Process.start(
-      Platform.executable, [Platform.script.toFilePath(), 'server']);
+  final serverProcess = await Process.start(Platform.executable, [
+    ...Platform.executableArguments,
+    Platform.script.toFilePath(),
+    'server'
+  ]);
   final serverPortCompleter = Completer<int>();
 
   serverProcess.stdout
diff --git a/tools/VERSION b/tools/VERSION
index f8cb69e..f2eb8a7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 84
+PRERELEASE 85
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/gn.py b/tools/gn.py
index ce133c3..336b1df 100755
--- a/tools/gn.py
+++ b/tools/gn.py
@@ -575,13 +575,17 @@
 
 def Main(argv):
     starttime = time.time()
+
     args = parse_args(argv)
+    if args is None:
+        return 1
 
     result = RunGnOnConfiguredConfigurations(args)
 
-    endtime = time.time()
     if args.verbose:
+        endtime = time.time()
         print("GN Time: %.3f seconds" % (endtime - starttime))
+
     return result