Version 2.13.0-37.0.dev

Merge commit '4216dc8d122f410d38d70ef6fc9bcedc5f2a0f0e' into 'dev'
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 85e7a89..614454c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -1226,7 +1226,9 @@
         replacementNode = buildStaticInvocation(
             resolvedTarget,
             forest.createArguments(noLocation, arguments.positional,
-                types: arguments.types, named: arguments.named),
+                types: arguments.types,
+                named: arguments.named,
+                hasExplicitTypeArguments: hasExplicitTypeArguments(arguments)),
             constness:
                 isConst ? Constness.explicitConst : Constness.explicitNew,
             charOffset: fileOffset);
@@ -1298,7 +1300,10 @@
       }
       Arguments invocationArguments = forest.createArguments(
           noLocation, invocation.arguments.positional,
-          types: invocationTypeArguments, named: invocation.arguments.named);
+          types: invocationTypeArguments,
+          named: invocation.arguments.named,
+          hasExplicitTypeArguments:
+              hasExplicitTypeArguments(invocation.arguments));
       invocation.replaceWith(_resolveRedirectingFactoryTarget(invocation.target,
           invocationArguments, invocation.fileOffset, invocation.isConst));
     }
@@ -4162,7 +4167,8 @@
               isConst: isConst)
             ..fileOffset = charOffset;
           libraryBuilder.checkBoundsInFactoryInvocation(
-              node, typeEnvironment, uri);
+              node, typeEnvironment, uri,
+              inferred: !hasExplicitTypeArguments(arguments));
         } else {
           node = new TypeAliasedFactoryInvocationJudgment(
               typeAliasBuilder, target, arguments,
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index 4c6d8d9..30344fd 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -30,9 +30,18 @@
   const Forest();
 
   Arguments createArguments(int fileOffset, List<Expression> positional,
-      {List<DartType> types, List<NamedExpression> named}) {
-    return new ArgumentsImpl(positional, types: types, named: named)
-      ..fileOffset = fileOffset ?? TreeNode.noOffset;
+      {List<DartType> types,
+      List<NamedExpression> named,
+      bool hasExplicitTypeArguments = true}) {
+    if (!hasExplicitTypeArguments) {
+      ArgumentsImpl arguments =
+          new ArgumentsImpl(positional, types: <DartType>[], named: named);
+      arguments.types.addAll(types);
+      return arguments;
+    } else {
+      return new ArgumentsImpl(positional, types: types, named: named)
+        ..fileOffset = fileOffset ?? TreeNode.noOffset;
+    }
   }
 
   Arguments createArgumentsForExtensionMethod(
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 4ad0b97..be8f723 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -404,8 +404,7 @@
   ExpressionInferenceResult visitConstructorInvocation(
       ConstructorInvocation node, DartType typeContext) {
     inferrer.inferConstructorParameterTypes(node.target);
-    bool hasExplicitTypeArguments =
-        getExplicitTypeArguments(node.arguments) != null;
+    bool hadExplicitTypeArguments = hasExplicitTypeArguments(node.arguments);
     FunctionType functionType = replaceReturnType(
         node.target.function
             .computeThisFunctionType(inferrer.library.nonNullable),
@@ -415,7 +414,7 @@
         isConst: node.isConst, staticTarget: node.target);
     if (!inferrer.isTopLevel) {
       SourceLibraryBuilder library = inferrer.library;
-      if (!hasExplicitTypeArguments) {
+      if (!hadExplicitTypeArguments) {
         library.checkBoundsInConstructorInvocation(
             node, inferrer.typeSchemaEnvironment, inferrer.helper.uri,
             inferred: true);
@@ -692,8 +691,7 @@
 
   ExpressionInferenceResult visitFactoryConstructorInvocationJudgment(
       FactoryConstructorInvocationJudgment node, DartType typeContext) {
-    bool hadExplicitTypeArguments =
-        getExplicitTypeArguments(node.arguments) != null;
+    bool hadExplicitTypeArguments = hasExplicitTypeArguments(node.arguments);
 
     FunctionType functionType = replaceReturnType(
         node.target.function
@@ -740,7 +738,7 @@
       SourceLibraryBuilder library = inferrer.library;
       library.checkBoundsInType(result.inferredType,
           inferrer.typeSchemaEnvironment, inferrer.helper.uri, node.fileOffset,
-          inferred: true);
+          inferred: true, allowSuperBounded: false);
       if (inferrer.isNonNullableByDefault) {
         if (node.target == inferrer.coreTypes.listDefaultConstructor) {
           resultNode = inferrer.helper.wrapInProblem(node,
@@ -768,7 +766,7 @@
       SourceLibraryBuilder library = inferrer.library;
       library.checkBoundsInType(result.inferredType,
           inferrer.typeSchemaEnvironment, inferrer.helper.uri, node.fileOffset,
-          inferred: true);
+          inferred: true, allowSuperBounded: false);
       if (inferrer.isNonNullableByDefault) {
         if (node.target == inferrer.coreTypes.listDefaultConstructor) {
           resultNode = inferrer.helper.wrapInProblem(node,
diff --git a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
index b5160f0..89039e8 100644
--- a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
@@ -183,6 +183,10 @@
   }
 }
 
+bool hasExplicitTypeArguments(Arguments arguments) {
+  return getExplicitTypeArguments(arguments) != null;
+}
+
 /// Information associated with a class during type inference.
 class ClassInferenceInfo {
   /// The builder associated with this class.
diff --git a/pkg/front_end/test/compile_benchmark.dart b/pkg/front_end/test/compile_benchmark.dart
new file mode 100644
index 0000000..da61b76
--- /dev/null
+++ b/pkg/front_end/test/compile_benchmark.dart
@@ -0,0 +1,458 @@
+// @dart = 2.9
+
+import 'dart:convert';
+import 'dart:io';
+import 'dart:typed_data';
+
+import 'package:front_end/src/fasta/kernel/utils.dart';
+import 'package:kernel/kernel.dart';
+import 'package:kernel/binary/ast_from_binary.dart';
+
+import "simple_stats.dart";
+
+/// This pass all parameters after "--" to the compiler (via `compileEntryPoint`
+/// via the helper `compile_benchmark_helper.dart`). It is meant to "benchmark"/
+/// instrument the compiler to give insights into specific runs, i.e. specific
+/// compiles (compiling program `a` and program `b` might have different
+/// characteristics). Said another way, it will always instrument and give
+/// insights on *the compiler*, not the program it's asked to compile (not
+/// directly anyway -- if you want to know if that program successfully
+/// exercises a specific part of the compiler it _does_ do that).
+
+final Uri benchmarkHelper =
+    Platform.script.resolve("compile_benchmark_helper.dart");
+
+main(List<String> args) {
+  List<String> arguments;
+  bool tryToAnnotate = false;
+  bool tryToSlowDown = false;
+  bool timeInsteadOfCount = false;
+  for (int i = 0; i < args.length; i++) {
+    if (args[i] == "--tryToAnnotate") {
+      tryToAnnotate = true;
+    } else if (args[i] == "--tryToSlowDown") {
+      tryToSlowDown = true;
+    } else if (args[i] == "--timeInsteadOfCount") {
+      timeInsteadOfCount = true;
+    } else if (args[i] == "--") {
+      arguments = args.sublist(i + 1);
+      break;
+    } else {
+      throw "Unknown argument '${args[i]}'";
+    }
+  }
+  if (arguments == null || arguments.isEmpty) {
+    throw "No arguments given to compiler.\n"
+        "Give arguments as `dart compile_benchmark.dart -- "
+        "argument1 argument2 (etc)`";
+  }
+
+  Directory tmp = Directory.systemTemp.createTempSync("benchmark");
+  try {
+    // Compile the helper to get a dill we can compile with.
+    final Uri helperDill = tmp.uri.resolve("compile.dill");
+
+    print("Compiling $benchmarkHelper into $helperDill");
+    runXTimes(1, [
+      benchmarkHelper.toString(),
+      benchmarkHelper.toString(),
+      "-o",
+      helperDill.toString(),
+    ]);
+    File f = new File.fromUri(helperDill);
+    if (!f.existsSync()) throw "$f doesn't exist!";
+
+    List<int> dillData = new File.fromUri(helperDill).readAsBytesSync();
+    doWork(
+      tmp,
+      dillData,
+      arguments,
+      tryToAnnotate: tryToAnnotate,
+      tryToSlowDown: tryToSlowDown,
+      timeInsteadOfCount: timeInsteadOfCount,
+    );
+  } finally {
+    tmp.deleteSync(recursive: true);
+  }
+}
+
+/// Perform asked operations on the dill data provided.
+///
+/// Will save files into the provided tmp directory, do timing or counting
+/// instructions and run that with the arguments passed, and then do comparative
+/// runs of transformed/non-transformed versions of the dill. The possible
+/// transformations are:
+/// * [tryToAnnotate] which will add a `@pragma("vm:prefer-inline")` annotation
+///   to each procedure one at a time.
+/// * [tryToSlowDown] which will add a busywait for approximately 0.002 ms to
+///   each procedure one at a time. (Unsurprisingly this makes it slower
+///   proportional to the number of times the procedure is called, so the
+///   counting annotation is likely at least as useful).
+///
+void doWork(Directory tmp, List<int> dillData, List<String> arguments,
+    {bool tryToAnnotate: false,
+    bool tryToSlowDown: false,
+    bool timeInsteadOfCount: false}) {
+  File f = new File.fromUri(tmp.uri.resolve("a.dill"));
+  f.writeAsBytesSync(dillData);
+  Uri dillOrgInTmp = f.uri;
+  print("Wrote to $f");
+
+  List<Procedure> sortedProcedures;
+  if (timeInsteadOfCount) {
+    sortedProcedures = doTimingInstrumentation(dillData, tmp, arguments);
+  } else {
+    sortedProcedures = doCountingInstrumentation(dillData, tmp, arguments);
+  }
+  print("\n\n");
+
+  bool didSomething = false;
+
+  if (tryToAnnotate) {
+    didSomething = true;
+    for (Procedure p in sortedProcedures) {
+      print("Prefer inline $p (${p.location})");
+      Uri preferredInlined = preferInlineProcedure(
+          dillData,
+          tmp.uri,
+          (lib) => lib.importUri == p.enclosingLibrary.importUri,
+          p.enclosingClass?.name,
+          p.name.text);
+
+      print("\nOriginal runs:");
+      List<int> runtimesA =
+          runXTimes(5, [dillOrgInTmp.toString(), ...arguments]);
+
+      print("\nModified runs:");
+      List<int> runtimesB =
+          runXTimes(5, [preferredInlined.toString(), ...arguments]);
+
+      print(SimpleTTestStat.ttest(runtimesB, runtimesA));
+      print("\n------------\n");
+    }
+  }
+
+  if (tryToSlowDown) {
+    didSomething = true;
+    for (Procedure p in sortedProcedures) {
+      Uri busyWaiting = busyWaitProcedure(
+          dillData,
+          tmp.uri,
+          (lib) => lib.importUri == p.enclosingLibrary.importUri,
+          p.enclosingClass?.name,
+          p.name.text);
+      if (busyWaiting == null) continue;
+
+      print("Slow down $p (${p.location})");
+
+      print("\nOriginal runs:");
+      List<int> runtimesA =
+          runXTimes(2, [dillOrgInTmp.toString(), ...arguments]);
+
+      print("\nModified runs:");
+      List<int> runtimesB =
+          runXTimes(2, [busyWaiting.toString(), ...arguments]);
+
+      print(SimpleTTestStat.ttest(runtimesB, runtimesA));
+      print("\n------------\n");
+    }
+  }
+
+  if (!didSomething) {
+    runXTimes(10, [dillOrgInTmp.toString(), ...arguments]);
+  }
+}
+
+/// Instrument the [dillData] so that each procedure-call can be registered
+/// (in package:front_end) and we find out how many times each procedure is
+/// called for a specific run, then run it, print the result and return the
+/// procedures in sorted order (most calls first).
+List<Procedure> doCountingInstrumentation(
+    List<int> dillData, Directory tmp, List<String> arguments) {
+  Instrumented instrumented = instrumentCallsCount(dillData, tmp.uri);
+  List<dynamic> stdout = [];
+  runXTimes(1, [instrumented.dill.toString(), ...arguments], stdout);
+  List<int> procedureCountsTmp = new List<int>.from(jsonDecode(stdout.single));
+  List<IntPair> procedureCounts = [];
+  for (int i = 0; i < procedureCountsTmp.length; i += 2) {
+    procedureCounts
+        .add(new IntPair(procedureCountsTmp[i], procedureCountsTmp[i + 1]));
+  }
+  // Sort highest call-count first.
+  procedureCounts.sort((a, b) => b.value - a.value);
+  List<Procedure> sortedProcedures = [];
+  for (IntPair p in procedureCounts) {
+    if (p.value > 1000) {
+      Procedure procedure = instrumented.procedures[p.key];
+      String location = procedure.location.toString();
+      if (location.length > 50) {
+        location = location.substring(location.length - 50);
+      }
+      print("Called $procedure ${p.value} times ($location)");
+      sortedProcedures.add(procedure);
+    }
+  }
+  return sortedProcedures;
+}
+
+/// Instrument the [dillData] so that each (sync) procedure-call can be timed
+/// (time on stack, i.e. not only the procedure itself, but also the
+/// procedure-calls it makes) (in package:front_end) and we find out how long
+/// each procedure is on the stack for a specific run, then run it, print the
+/// result and return the procedures in sorted order (most time on stack first).
+List<Procedure> doTimingInstrumentation(
+    List<int> dillData, Directory tmp, List<String> arguments) {
+  Instrumented instrumented = instrumentCallsTiming(dillData, tmp.uri);
+  List<dynamic> stdout = [];
+  runXTimes(1, [instrumented.dill.toString(), ...arguments], stdout);
+  List<int> procedureTimeTmp = new List<int>.from(jsonDecode(stdout.single));
+  List<IntPair> procedureTime = [];
+  for (int i = 0; i < procedureTimeTmp.length; i += 2) {
+    procedureTime
+        .add(new IntPair(procedureTimeTmp[i], procedureTimeTmp[i + 1]));
+  }
+  // Sort highest time-on-stack first.
+  procedureTime.sort((a, b) => b.value - a.value);
+  List<Procedure> sortedProcedures = [];
+  for (IntPair p in procedureTime) {
+    if (p.value > 1000) {
+      Procedure procedure = instrumented.procedures[p.key];
+      String location = procedure.location.toString();
+      if (location.length > 50) {
+        location = location.substring(location.length - 50);
+      }
+      print("$procedure was on stack for ${p.value} microseconds ($location)");
+      sortedProcedures.add(procedure);
+    }
+  }
+  return sortedProcedures;
+}
+
+class IntPair {
+  final int key;
+  final int value;
+
+  IntPair(this.key, this.value);
+
+  String toString() {
+    return "IntPair[$key: $value]";
+  }
+}
+
+/// Adds the annotation `@pragma("vm:prefer-inline")` to the specified procedure
+/// and serialize the resulting dill into `b.dill` (return uri).
+///
+/// The annotation is copied from the [preferInlineMe] method in the helper.
+Uri preferInlineProcedure(List<int> dillData, Uri tmp,
+    bool libraryMatcher(Library lib), String className, String procedureName) {
+  Component component = new Component();
+  new BinaryBuilder(dillData, disableLazyReading: true)
+      .readComponent(component);
+  Procedure preferInlineMeProcedure = getProcedure(component,
+      (lib) => lib.fileUri == benchmarkHelper, null, "preferInlineMe");
+  ConstantExpression annotation = preferInlineMeProcedure.annotations.single;
+  Procedure markProcedure =
+      getProcedure(component, libraryMatcher, className, procedureName);
+  markProcedure.addAnnotation(
+      new ConstantExpression(annotation.constant, annotation.type));
+
+  Uint8List newDillData = serializeComponent(component);
+  File f = new File.fromUri(tmp.resolve("b.dill"));
+  f.writeAsBytesSync(newDillData);
+  return f.uri;
+}
+
+/// Makes the procedure specified call [busyWait] from the helper and serialize
+/// the resulting dill into `c.dill` (return uri).
+///
+/// This will make the procedure busy-wait approximately 0.002 ms for each
+/// invocation (+ whatever overhead and imprecision).
+Uri busyWaitProcedure(List<int> dillData, Uri tmp,
+    bool libraryMatcher(Library lib), String className, String procedureName) {
+  Component component = new Component();
+  new BinaryBuilder(dillData, disableLazyReading: true)
+      .readComponent(component);
+  Procedure busyWaitProcedure = getProcedure(
+      component, (lib) => lib.fileUri == benchmarkHelper, null, "busyWait");
+
+  Procedure markProcedure =
+      getProcedure(component, libraryMatcher, className, procedureName);
+  if (markProcedure.function.body == null) return null;
+
+  Statement orgBody = markProcedure.function.body;
+  markProcedure.function.body = new Block([
+    new ExpressionStatement(new StaticInvocation(
+        busyWaitProcedure, new Arguments([new IntLiteral(2 /* 0.002 ms */)]))),
+    orgBody
+  ])
+    ..parent = markProcedure.function;
+
+  Uint8List newDillData = serializeComponent(component);
+  File f = new File.fromUri(tmp.resolve("c.dill"));
+  f.writeAsBytesSync(newDillData);
+  return f.uri;
+}
+
+/// Instrument the [dillData] so that each procedure-call can be registered
+/// (in package:front_end) and we find out how many times each procedure is
+/// called for a specific run.
+///
+/// Uses the [registerCall] in the helper.
+/// Numbers each procedure, saves the instrumented dill and returns both the
+/// dill and the list of procedures so that procedure i in the list will be
+/// annotated with a call to `registerCall(i)`.
+Instrumented instrumentCallsCount(List<int> dillData, Uri tmp) {
+  Component component = new Component();
+  new BinaryBuilder(dillData, disableLazyReading: true)
+      .readComponent(component);
+  Procedure registerCallProcedure = getProcedure(
+      component, (lib) => lib.fileUri == benchmarkHelper, null, "registerCall");
+  RegisterCallTransformer registerCallTransformer =
+      new RegisterCallTransformer(registerCallProcedure);
+  component.accept(registerCallTransformer);
+
+  Uint8List newDillData = serializeComponent(component);
+  File f = new File.fromUri(tmp.resolve("counting.dill"));
+  f.writeAsBytesSync(newDillData);
+
+  return new Instrumented(f.uri, registerCallTransformer.procedures);
+}
+
+/// Instrument the [dillData] so that each (sync) procedure-call can be timed
+/// (time on stack, i.e. not only the procedure itself, but also the
+/// procedure-calls it makes) (in package:front_end) and we find out how long
+/// each procedure is on the stack for a specific run.
+///
+/// Uses [registerCallStart] and [registerCallEnd] from the helper.
+/// Numbers each sync procedure, saves the instrumented dill and returns both
+/// the dill and the list of procedures so that procedure i in the list will be
+/// annotated with a call-pair to `registerCallStart(i)` and
+/// `registerCallEnd(i)`.
+Instrumented instrumentCallsTiming(List<int> dillData, Uri tmp) {
+  Component component = new Component();
+  new BinaryBuilder(dillData, disableLazyReading: true)
+      .readComponent(component);
+  Procedure registerCallStartProcedure = getProcedure(component,
+      (lib) => lib.fileUri == benchmarkHelper, null, "registerCallStart");
+  Procedure registerCallEndProcedure = getProcedure(component,
+      (lib) => lib.fileUri == benchmarkHelper, null, "registerCallEnd");
+  RegisterTimeTransformer registerTimeTransformer = new RegisterTimeTransformer(
+      registerCallStartProcedure, registerCallEndProcedure);
+  component.accept(registerTimeTransformer);
+
+  Uint8List newDillData = serializeComponent(component);
+  File f = new File.fromUri(tmp.resolve("timing.dill"));
+  f.writeAsBytesSync(newDillData);
+
+  return new Instrumented(f.uri, registerTimeTransformer.procedures);
+}
+
+/// Class holding both the uri of a saved dill file and a list of procedures (in
+/// order) that has some reference to the annotation added to the dill file.
+class Instrumented {
+  final Uri dill;
+  final List<Procedure> procedures;
+
+  Instrumented(this.dill, this.procedures);
+}
+
+class RegisterCallTransformer extends RecursiveVisitor {
+  final Procedure registerCallProcedure;
+  RegisterCallTransformer(this.registerCallProcedure);
+  List<Procedure> procedures = [];
+
+  visitLibrary(Library node) {
+    if (node.importUri.scheme == "package" &&
+        node.importUri.pathSegments.first == "front_end") {
+      super.visitLibrary(node);
+    }
+  }
+
+  visitProcedure(Procedure node) {
+    if (node.function.body == null) return;
+    int procedureNum = procedures.length;
+    procedures.add(node);
+    Statement orgBody = node.function.body;
+    node.function.body = new Block([
+      new ExpressionStatement(new StaticInvocation(registerCallProcedure,
+          new Arguments([new IntLiteral(procedureNum)]))),
+      orgBody
+    ]);
+    node.function.body.parent = node.function;
+  }
+}
+
+class RegisterTimeTransformer extends RecursiveVisitor {
+  final Procedure registerCallStartProcedure;
+  final Procedure registerCallEndProcedure;
+
+  RegisterTimeTransformer(
+      this.registerCallStartProcedure, this.registerCallEndProcedure);
+
+  List<Procedure> procedures = [];
+
+  visitLibrary(Library node) {
+    if (node.importUri.scheme == "package" &&
+        node.importUri.pathSegments.first == "front_end") {
+      super.visitLibrary(node);
+    }
+  }
+
+  visitProcedure(Procedure node) {
+    if (node.function.body == null) return;
+    if (node.function.dartAsyncMarker != AsyncMarker.Sync) return;
+    int procedureNum = procedures.length;
+    procedures.add(node);
+    Statement orgBody = node.function.body;
+    // Rewrite as
+    // {
+    //    registerCallStartProcedure(x);
+    //    try {
+    //      originalBody
+    //    } finally {
+    //      registerCallEndProcedure(x);
+    //    }
+    // }
+    Block block = new Block([
+      new ExpressionStatement(new StaticInvocation(registerCallStartProcedure,
+          new Arguments([new IntLiteral(procedureNum)]))),
+      new TryFinally(
+        orgBody,
+        new ExpressionStatement(new StaticInvocation(registerCallEndProcedure,
+            new Arguments([new IntLiteral(procedureNum)]))),
+      )
+    ]);
+    node.function.body = block;
+    node.function.body.parent = node.function;
+  }
+}
+
+Procedure getProcedure(Component component, bool libraryMatcher(Library lib),
+    String className, String procedureName) {
+  Library lib = component.libraries.where(libraryMatcher).single;
+  List<Procedure> procedures = lib.procedures;
+  if (className != null) {
+    Class cls = lib.classes.where((c) => c.name == className).single;
+    procedures = cls.procedures;
+  }
+  // TODO: This will fail for getter/setter pairs. Fix that.
+  return procedures.where((p) => p.name.text == procedureName).single;
+}
+
+List<int> runXTimes(int x, List<String> arguments, [List<dynamic> stdout]) {
+  List<int> result = [];
+  Stopwatch stopwatch = new Stopwatch()..start();
+  for (int i = 0; i < x; i++) {
+    stopwatch.reset();
+    ProcessResult run = Process.runSync(Platform.resolvedExecutable, arguments,
+        runInShell: true);
+    int ms = stopwatch.elapsedMilliseconds;
+    result.add(ms);
+    print(ms);
+    if (run.exitCode != 0) throw "Got exit code ${run.exitCode}";
+    if (stdout != null) {
+      stdout.add(run.stdout);
+    }
+  }
+  return result;
+}
diff --git a/pkg/front_end/test/compile_benchmark_helper.dart b/pkg/front_end/test/compile_benchmark_helper.dart
new file mode 100644
index 0000000..1b187e8
--- /dev/null
+++ b/pkg/front_end/test/compile_benchmark_helper.dart
@@ -0,0 +1,100 @@
+// Copyright (c) 2017, 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 '../tool/_fasta/entry_points.dart' show compileEntryPoint;
+
+main(List<String> arguments) async {
+  await compileEntryPoint(arguments);
+  if (numCalls.isNotEmpty) {
+    print("[");
+    bool printed = false;
+    for (int i = 0; i < numCalls.length; i++) {
+      int value = numCalls[i];
+      if (value != null && value > 0) {
+        if (printed) print(",");
+        print("$i, $value");
+        printed = true;
+      }
+    }
+    print("]");
+  } else if (inCall.isNotEmpty) {
+    print("[");
+    bool printed = false;
+    for (int i = 0; i < inCall.length; i++) {
+      int value = inCall[i];
+      if (value == null) continue;
+      if (value != 0) throw "$i has value $value";
+      if (printed) print(",");
+      int time = callTimes[i];
+      print("$i, $time");
+      printed = true;
+    }
+    print("]");
+  }
+}
+
+List<int> numCalls = [];
+
+void registerCall(int procedureNum) {
+  while (numCalls.length <= procedureNum) {
+    if (numCalls.length < 8) {
+      numCalls.length = 8;
+    } else {
+      numCalls.length *= 2;
+    }
+  }
+  numCalls[procedureNum] ??= 0;
+  numCalls[procedureNum]++;
+}
+
+List<int> inCall = [];
+List<int> callTimes = [];
+Stopwatch stopwatch = new Stopwatch()..start();
+
+void registerCallStart(int procedureNum) {
+  while (inCall.length <= procedureNum) {
+    if (inCall.length < 8) {
+      inCall.length = 8;
+      callTimes.length = 8;
+    } else {
+      inCall.length *= 2;
+      callTimes.length *= 2;
+    }
+  }
+  inCall[procedureNum] ??= 0;
+  callTimes[procedureNum] ??= 0;
+  if (inCall[procedureNum]++ == 0) {
+    // First --- start a timer-ish.
+    callTimes[procedureNum] -= stopwatch.elapsedMicroseconds;
+  }
+}
+
+void registerCallEnd(int procedureNum) {
+  if (inCall[procedureNum]-- == 1) {
+    // Last --- stop the timer-ish.
+    callTimes[procedureNum] += stopwatch.elapsedMicroseconds;
+  }
+}
+
+@pragma("vm:prefer-inline")
+void preferInlineMe() {
+  // This makes it easier to get the annotation :).
+}
+
+int busyWait(int micro) {
+  int count = 0;
+  Stopwatch stopwatch = new Stopwatch()..start();
+  while (true) {
+    for (int i = 0; i < 1000; i++) {
+      count++;
+    }
+    int elapsed = stopwatch.elapsedMicroseconds;
+    if (elapsed >= micro) {
+      print("Bye from busywait after $count iterations ($elapsed vs $micro)!");
+      return count;
+    }
+  }
+}
diff --git a/pkg/front_end/test/simple_stats.dart b/pkg/front_end/test/simple_stats.dart
index b163e67..dd69a4e 100644
--- a/pkg/front_end/test/simple_stats.dart
+++ b/pkg/front_end/test/simple_stats.dart
@@ -7,9 +7,9 @@
 import 'dart:math' as math;
 
 class SimpleTTestStat {
-  static TTestResult ttest(List<int> a, List<int> b) {
-    int aSum = a.reduce((value, element) => (value + element));
-    int bSum = b.reduce((value, element) => (value + element));
+  static TTestResult ttest<E extends num>(List<E> a, List<E> b) {
+    E aSum = a.reduce((value, element) => (value + element));
+    E bSum = b.reduce((value, element) => (value + element));
     int aCount = a.length;
     int bCount = b.length;
     double aMean = aSum / aCount;
@@ -36,13 +36,13 @@
     }
   }
 
-  static double variance(List<int> data) {
-    int sum = data.reduce((value, element) => (value + element));
+  static double variance<E extends num>(List<E> data) {
+    E sum = data.reduce((value, element) => (value + element));
     int count = data.length;
     double average = sum / count;
 
     double diffSquareSum = 0;
-    for (int value in data) {
+    for (E value in data) {
       double diff = value - average;
       double squared = diff * diff;
       diffSquareSum += squared;
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 2ec515d..1b92362 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -86,6 +86,8 @@
 builddir
 bulk2
 bulkcompile
+busy
+busywait
 bye
 c's
 c59cdee365b94ce066344840f9e3412d642019b
@@ -99,6 +101,7 @@
 ccc
 cell
 cf
+characteristics
 charset
 checkme
 checkout
@@ -127,6 +130,7 @@
 commented
 commit
 companion
+comparative
 comparer
 compilations
 compiler's
@@ -362,6 +366,7 @@
 image
 images
 implementor
+imprecision
 in1
 in2
 inclosure
@@ -375,7 +380,9 @@
 inlinable
 inlineable
 inlines
+insights
 instance2
+instrument
 insufficient
 intdiv
 interactive
@@ -527,6 +534,7 @@
 out2
 outbound
 outlined
+overhead
 overlay
 ox
 pack
@@ -566,6 +574,7 @@
 property5b
 property8a
 property8b
+proportional
 protected
 proved
 provider
@@ -627,6 +636,7 @@
 rows
 runtimes
 rv
+saves
 scans
 scheduler
 screen
@@ -750,6 +760,7 @@
 unpatched
 unpaused
 unregistered
+unsurprisingly
 untransformed
 untrimmed
 unusual
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart
new file mode 100644
index 0000000..5b11f3d
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart
@@ -0,0 +1,20 @@
+// 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.
+
+class A<X extends A<X>> {}
+typedef B<X extends A<X>> = A<X>;
+
+class A2<X extends A2<X>> {
+  factory A2() => throw 42;
+}
+typedef B2<X extends A2<X>> = A2<X>;
+
+foo() {
+  B(); // Error.
+  A(); // Error.
+  B2(); // Error.
+  A2(); // Error.
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.textual_outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.textual_outline.expect
new file mode 100644
index 0000000..611ce04
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+class A<X extends A<X>> {}
+typedef B<X extends A<X>> = A<X>;
+class A2<X extends A2<X>> {
+  factory A2() => throw 42;
+}
+typedef B2<X extends A2<X>> = A2<X>;
+foo() {}
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.weak.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.weak.expect
new file mode 100644
index 0000000..29df1fe
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.weak.expect
@@ -0,0 +1,65 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:14:3: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'A'.
+//  - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   B(); // Error.
+//   ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class A<X extends A<X>> {}
+//         ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:15:3: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'A'.
+//  - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   A(); // Error.
+//   ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class A<X extends A<X>> {}
+//         ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:16:3: Error: Inferred type argument 'A2<Object?>' doesn't conform to the bound 'A2<X>' of the type variable 'X' on 'A2'.
+//  - 'A2' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   B2(); // Error.
+//   ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:8:10: Context: This is the type variable whose bound isn't conformed to.
+// class A2<X extends A2<X>> {
+//          ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:17:3: Error: Inferred type argument 'A2<Object?>' doesn't conform to the bound 'A2<X>' of the type variable 'X' on 'A2'.
+//  - 'A2' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   A2(); // Error.
+//   ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:8:10: Context: This is the type variable whose bound isn't conformed to.
+// class A2<X extends A2<X>> {
+//          ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef B<X extends self::A<X> = self::A<dynamic>> = self::A<X>;
+typedef B2<X extends self::A2<X> = self::A2<dynamic>> = self::A2<X>;
+class A<X extends self::A<self::A::X> = self::A<dynamic>> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X>
+    : super core::Object::•()
+    ;
+}
+class A2<X extends self::A2<self::A2::X> = self::A2<dynamic>> extends core::Object {
+  static factory •<X extends self::A2<self::A2::•::X> = self::A2<dynamic>>() → self::A2<self::A2::•::X>
+    return throw 42;
+}
+static method foo() → dynamic {
+  new self::A::•<self::A<core::Object?>>();
+  new self::A::•<self::A<core::Object?>>();
+  self::A2::•<self::A2<core::Object?>>();
+  self::A2::•<self::A2<core::Object?>>();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.weak.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.weak.transformed.expect
new file mode 100644
index 0000000..29df1fe
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.weak.transformed.expect
@@ -0,0 +1,65 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:14:3: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'A'.
+//  - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   B(); // Error.
+//   ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class A<X extends A<X>> {}
+//         ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:15:3: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'A'.
+//  - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   A(); // Error.
+//   ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class A<X extends A<X>> {}
+//         ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:16:3: Error: Inferred type argument 'A2<Object?>' doesn't conform to the bound 'A2<X>' of the type variable 'X' on 'A2'.
+//  - 'A2' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   B2(); // Error.
+//   ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:8:10: Context: This is the type variable whose bound isn't conformed to.
+// class A2<X extends A2<X>> {
+//          ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:17:3: Error: Inferred type argument 'A2<Object?>' doesn't conform to the bound 'A2<X>' of the type variable 'X' on 'A2'.
+//  - 'A2' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   A2(); // Error.
+//   ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:8:10: Context: This is the type variable whose bound isn't conformed to.
+// class A2<X extends A2<X>> {
+//          ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef B<X extends self::A<X> = self::A<dynamic>> = self::A<X>;
+typedef B2<X extends self::A2<X> = self::A2<dynamic>> = self::A2<X>;
+class A<X extends self::A<self::A::X> = self::A<dynamic>> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X>
+    : super core::Object::•()
+    ;
+}
+class A2<X extends self::A2<self::A2::X> = self::A2<dynamic>> extends core::Object {
+  static factory •<X extends self::A2<self::A2::•::X> = self::A2<dynamic>>() → self::A2<self::A2::•::X>
+    return throw 42;
+}
+static method foo() → dynamic {
+  new self::A::•<self::A<core::Object?>>();
+  new self::A::•<self::A<core::Object?>>();
+  self::A2::•<self::A2<core::Object?>>();
+  self::A2::•<self::A2<core::Object?>>();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index 68e7e6b..4c36c59 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -20,21 +20,12 @@
 regress/issue_39091_2: EmptyOutput
 regress/utf_16_le_content.crash: EmptyOutput
 
+
 extensions/extension_constructor: FormatterCrash
 extensions/extension_field_with_type_parameter_usage: FormatterCrash
 extensions/issue38600: FormatterCrash
 extensions/issue38712: FormatterCrash
 extensions/issue38745: FormatterCrash
-general_nnbd_opt_out/annotation_eof: FormatterCrash
-general_nnbd_opt_out/bad_setter_abstract: FormatterCrash
-general_nnbd_opt_out/bug31124: FormatterCrash
-general_nnbd_opt_out/clone_function_type: FormatterCrash
-general_nnbd_opt_out/constructor_initializer_invalid: FormatterCrash
-general_nnbd_opt_out/duplicated_declarations: FormatterCrash
-general_nnbd_opt_out/function_type_default_value: FormatterCrash
-general_nnbd_opt_out/incomplete_field_formal_parameter: FormatterCrash
-general_nnbd_opt_out/many_errors: FormatterCrash
-general_nnbd_opt_out/var_as_type_name: FormatterCrash
 general/annotation_eof: FormatterCrash
 general/bad_setter_abstract: FormatterCrash
 general/bug31124: FormatterCrash
@@ -62,21 +53,31 @@
 general/error_recovery/issue_43090.crash: FormatterCrash
 general/function_type_default_value: FormatterCrash
 general/incomplete_field_formal_parameter: FormatterCrash
-general/invalid_operator: FormatterCrash
 general/invalid_operator2: FormatterCrash
+general/invalid_operator: FormatterCrash
 general/issue42997: FormatterCrash
 general/issue43363: FormatterCrash
 general/many_errors: FormatterCrash
 general/null_safety_invalid_experiment_and_language_version: FormatterCrash
 general/type_parameters_on_void: FormatterCrash
 general/var_as_type_name: FormatterCrash
+general_nnbd_opt_out/annotation_eof: FormatterCrash
+general_nnbd_opt_out/bad_setter_abstract: FormatterCrash
+general_nnbd_opt_out/bug31124: FormatterCrash
+general_nnbd_opt_out/clone_function_type: FormatterCrash
+general_nnbd_opt_out/constructor_initializer_invalid: FormatterCrash
+general_nnbd_opt_out/duplicated_declarations: FormatterCrash
+general_nnbd_opt_out/function_type_default_value: FormatterCrash
+general_nnbd_opt_out/incomplete_field_formal_parameter: FormatterCrash
+general_nnbd_opt_out/many_errors: FormatterCrash
+general_nnbd_opt_out/var_as_type_name: FormatterCrash
 inference/unsafe_block_closure_inference_function_call_explicit_dynamic_param_via_expr1: FormatterCrash
 inference/unsafe_block_closure_inference_function_call_explicit_type_param_via_expr1: FormatterCrash
 late_lowering/covariant_late_field: FormatterCrash
 late_lowering/getter_vs_setter_type: FormatterCrash
 late_lowering/infer_late_field_type: FormatterCrash
-late_lowering/initializer_rewrite_from_opt_out: FormatterCrash
 late_lowering/initializer_rewrite: FormatterCrash
+late_lowering/initializer_rewrite_from_opt_out: FormatterCrash
 late_lowering/instance_field_with_initializer: FormatterCrash
 late_lowering/instance_field_without_initializer: FormatterCrash
 late_lowering/instance_final_field_without_initializer: FormatterCrash
@@ -103,19 +104,16 @@
 late_lowering/late_nullable_field_without_initializer: FormatterCrash
 late_lowering/late_override: FormatterCrash
 late_lowering/later: FormatterCrash
-late_lowering/override_getter_setter: FormatterCrash
 late_lowering/override: FormatterCrash
+late_lowering/override_getter_setter: FormatterCrash
 late_lowering/skip_late_final_uninitialized_instance_fields/main: FormatterCrash
 late_lowering/uninitialized_non_nullable_late_fields: FormatterCrash
-nnbd_mixed/inheritance_from_opt_in: FormatterCrash
-nnbd_mixed/issue41597: FormatterCrash
-nnbd_mixed/null_safety_invalid_language_version: FormatterCrash
 nnbd/abstract_field_errors: FormatterCrash
 nnbd/covariant_late_field: FormatterCrash
-nnbd/duplicates_instance_extension: FormatterCrash
 nnbd/duplicates_instance: FormatterCrash
-nnbd/duplicates_static_extension: FormatterCrash
+nnbd/duplicates_instance_extension: FormatterCrash
 nnbd/duplicates_static: FormatterCrash
+nnbd/duplicates_static_extension: FormatterCrash
 nnbd/field_vs_setter: FormatterCrash
 nnbd/forbidden_supers: FormatterCrash
 nnbd/getter_vs_setter_type_late: FormatterCrash
@@ -132,7 +130,11 @@
 nnbd/opt_out: FormatterCrash
 nnbd/potentially_non_nullable_field: FormatterCrash
 nnbd/uninitialized_non_nullable_late_fields: FormatterCrash
+nnbd_mixed/inheritance_from_opt_in: FormatterCrash
+nnbd_mixed/issue41597: FormatterCrash
+nnbd_mixed/null_safety_invalid_language_version: FormatterCrash
 nonfunction_type_aliases/issue41501: FormatterCrash
+nonfunction_type_aliases/issue42446: FormatterCrash
 rasta/bad_redirection: FormatterCrash
 rasta/issue_000032: FormatterCrash
 rasta/issue_000034: FormatterCrash
@@ -172,4 +174,3 @@
 variance/generic_covariance_sound_variance: FormatterCrash
 variance/mixin_type_parameter_modifier: FormatterCrash
 variance/unconstrained_inference: FormatterCrash
-
diff --git a/tools/VERSION b/tools/VERSION
index 6440191..99f3979 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 36
+PRERELEASE 37
 PRERELEASE_PATCH 0
\ No newline at end of file