[CFE] Don't create new 'unknown' FunctionTypes for each TypeInferrerImpl

When compiling "compile.dart" this creates ~17% fewer FunctionTypes
(from almost 263k to a little over 217k).

Change-Id: I0090c287ce427b298897846de03679f562223e63
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/298581
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
index 1cab3a7..03d9a51 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
@@ -329,6 +329,10 @@
 /// kernel objects.
 class TypeInferenceEngineImpl extends TypeInferenceEngine {
   final Benchmarker? benchmarker;
+  final FunctionType unknownFunctionNonNullable =
+      new FunctionType(const [], const DynamicType(), Nullability.nonNullable);
+  final FunctionType unknownFunctionLegacy =
+      new FunctionType(const [], const DynamicType(), Nullability.legacy);
 
   TypeInferenceEngineImpl(Instrumentation? instrumentation, this.benchmarker)
       : super(instrumentation);
@@ -345,11 +349,28 @@
           new AssignedVariables<TreeNode, VariableDeclaration>();
     }
     if (benchmarker == null) {
-      return new TypeInferrerImpl(this, uri, false, thisType, library,
-          assignedVariables, dataForTesting);
+      return new TypeInferrerImpl(
+          this,
+          uri,
+          false,
+          thisType,
+          library,
+          assignedVariables,
+          dataForTesting,
+          unknownFunctionNonNullable,
+          unknownFunctionLegacy);
     }
-    return new TypeInferrerImplBenchmarked(this, uri, false, thisType, library,
-        assignedVariables, dataForTesting, benchmarker!);
+    return new TypeInferrerImplBenchmarked(
+        this,
+        uri,
+        false,
+        thisType,
+        library,
+        assignedVariables,
+        dataForTesting,
+        benchmarker!,
+        unknownFunctionNonNullable,
+        unknownFunctionLegacy);
   }
 
   @override
@@ -364,11 +385,28 @@
           new AssignedVariables<TreeNode, VariableDeclaration>();
     }
     if (benchmarker == null) {
-      return new TypeInferrerImpl(this, uri, true, thisType, library,
-          assignedVariables, dataForTesting);
+      return new TypeInferrerImpl(
+          this,
+          uri,
+          true,
+          thisType,
+          library,
+          assignedVariables,
+          dataForTesting,
+          unknownFunctionNonNullable,
+          unknownFunctionLegacy);
     }
-    return new TypeInferrerImplBenchmarked(this, uri, true, thisType, library,
-        assignedVariables, dataForTesting, benchmarker!);
+    return new TypeInferrerImplBenchmarked(
+        this,
+        uri,
+        true,
+        thisType,
+        library,
+        assignedVariables,
+        dataForTesting,
+        benchmarker!,
+        unknownFunctionNonNullable,
+        unknownFunctionLegacy);
   }
 }
 
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 11c94ce..22b51c9 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -139,11 +139,14 @@
       this.thisType,
       this.libraryBuilder,
       this.assignedVariables,
-      this.dataForTesting)
+      this.dataForTesting,
+      FunctionType unknownFunctionNonNullable,
+      FunctionType unknownFunctionLegacy)
       // ignore: unnecessary_null_comparison
       : assert(libraryBuilder != null),
-        unknownFunction = new FunctionType(
-            const [], const DynamicType(), libraryBuilder.nonNullable),
+        unknownFunction = libraryBuilder.isNonNullableByDefault
+            ? unknownFunctionNonNullable
+            : unknownFunctionLegacy,
         instrumentation = isTopLevel ? null : engine.instrumentation,
         typeSchemaEnvironment = engine.typeSchemaEnvironment,
         operations = new OperationsCfe(engine.typeSchemaEnvironment,
@@ -305,16 +308,27 @@
   final Benchmarker benchmarker;
 
   TypeInferrerImplBenchmarked(
-      TypeInferenceEngine engine,
-      Uri uriForInstrumentation,
-      bool topLevel,
-      InterfaceType? thisType,
-      SourceLibraryBuilder library,
-      AssignedVariables<TreeNode, VariableDeclaration> assignedVariables,
-      InferenceDataForTesting? dataForTesting,
-      this.benchmarker)
-      : impl = new TypeInferrerImpl(engine, uriForInstrumentation, topLevel,
-            thisType, library, assignedVariables, dataForTesting);
+    TypeInferenceEngine engine,
+    Uri uriForInstrumentation,
+    bool topLevel,
+    InterfaceType? thisType,
+    SourceLibraryBuilder library,
+    AssignedVariables<TreeNode, VariableDeclaration> assignedVariables,
+    InferenceDataForTesting? dataForTesting,
+    this.benchmarker,
+    FunctionType unknownFunctionNonNullable,
+    FunctionType unknownFunctionLegacy,
+  ) : impl = new TypeInferrerImpl(
+          engine,
+          uriForInstrumentation,
+          topLevel,
+          thisType,
+          library,
+          assignedVariables,
+          dataForTesting,
+          unknownFunctionNonNullable,
+          unknownFunctionLegacy,
+        );
 
   @override
   bool get isTopLevel => impl.isTopLevel;