Version 2.19.0-14.0.dev

Merge commit '4f787e4a09c0e56301a022ee4e64918e03d50a0c' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/analysis/context_locator.dart b/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
index 6c92619..4aa5964c 100644
--- a/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
@@ -378,10 +378,12 @@
     Workspace? workspace;
     workspace = BazelWorkspace.find(resourceProvider, rootPath,
         lookForBuildFileSubstitutes: false);
-    workspace ??= GnWorkspace.find(resourceProvider, rootPath);
-    workspace ??=
-        PackageBuildWorkspace.find(resourceProvider, packages, rootPath);
-    workspace ??= PubWorkspace.find(resourceProvider, packages, rootPath);
+    workspace = _mostSpecificWorkspace(
+        workspace, GnWorkspace.find(resourceProvider, rootPath));
+    workspace = _mostSpecificWorkspace(workspace,
+        PackageBuildWorkspace.find(resourceProvider, packages, rootPath));
+    workspace = _mostSpecificWorkspace(
+        workspace, PubWorkspace.find(resourceProvider, packages, rootPath));
     workspace ??= BasicWorkspace.find(resourceProvider, packages, rootPath);
     return workspace;
   }
@@ -555,6 +557,20 @@
 
     return true;
   }
+
+  /// Pick a workspace with the most specific root. If the root of [first] is
+  /// non-null and is within the root of [second], return [second]. If any of
+  /// [first] and [second] is null, return the other one. If the roots aren't
+  /// within each other, return [first].
+  static Workspace? _mostSpecificWorkspace(
+      Workspace? first, Workspace? second) {
+    if (first == null) return second;
+    if (second == null) return first;
+    if (isWithin(first.root, second.root)) {
+      return second;
+    }
+    return first;
+  }
 }
 
 /// The packages [file] found for the [parent].
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index f6b584e..8351847 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -85,7 +85,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 236;
+  static const int DATA_VERSION = 237;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index e37b820..1d27313 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -4387,7 +4387,7 @@
 class LibraryExportElementImpl extends _ExistingElementImpl
     implements LibraryExportElement {
   @override
-  List<NamespaceCombinator> combinators = const [];
+  final List<NamespaceCombinator> combinators;
 
   @override
   final int exportKeywordOffset;
@@ -4396,6 +4396,7 @@
   final DirectiveUri uri;
 
   LibraryExportElementImpl({
+    required this.combinators,
     required this.exportKeywordOffset,
     required this.uri,
   }) : super(null, exportKeywordOffset);
@@ -4434,7 +4435,7 @@
 class LibraryImportElementImpl extends _ExistingElementImpl
     implements LibraryImportElement {
   @override
-  List<NamespaceCombinator> combinators = const [];
+  final List<NamespaceCombinator> combinators;
 
   @override
   final int importKeywordOffset;
@@ -4448,6 +4449,7 @@
   Namespace? _namespace;
 
   LibraryImportElementImpl({
+    required this.combinators,
     required this.importKeywordOffset,
     required this.prefix,
     required this.uri,
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index b4242a8..429b980 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -824,17 +824,13 @@
   LibraryExportElementImpl _readExportElement({
     required LibraryOrAugmentationElementImpl container,
   }) {
-    final uri = _readDirectiveUri(
-      container: container,
-    );
-    // TODO(scheglov) pass to the constructor
-    final combinators = _reader.readTypedList(_readNamespaceCombinator);
-
-    final element = LibraryExportElementImpl(
+    return LibraryExportElementImpl(
+      combinators: _reader.readTypedList(_readNamespaceCombinator),
       exportKeywordOffset: -1,
-      uri: uri,
-    )..combinators = combinators;
-    return element;
+      uri: _readDirectiveUri(
+        container: container,
+      ),
+    );
   }
 
   ExportLocation _readExportLocation() {
@@ -986,19 +982,16 @@
   LibraryImportElementImpl _readImportElement({
     required LibraryOrAugmentationElementImpl container,
   }) {
-    final uri = _readDirectiveUri(
-      container: container,
-    );
-    final prefix = _readImportElementPrefix(
-      container: container,
-    );
-    final combinators = _reader.readTypedList(_readNamespaceCombinator);
-
     final element = LibraryImportElementImpl(
+      combinators: _reader.readTypedList(_readNamespaceCombinator),
       importKeywordOffset: -1,
-      uri: uri,
-      prefix: prefix,
-    )..combinators = combinators;
+      prefix: _readImportElementPrefix(
+        container: container,
+      ),
+      uri: _readDirectiveUri(
+        container: container,
+      ),
+    );
     ImportElementFlags.read(_reader, element);
     return element;
   }
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index 004008b..81ed6aa 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -274,8 +274,8 @@
   void _writeExportElement(LibraryExportElement element) {
     element as LibraryExportElementImpl;
     _resolutionSink._writeAnnotationList(element.metadata);
-    _writeDirectiveUri(element.uri);
     _sink.writeList(element.combinators, _writeNamespaceCombinator);
+    _writeDirectiveUri(element.uri);
   }
 
   void _writeExportLocation(ExportLocation location) {
@@ -342,9 +342,9 @@
   void _writeImportElement(LibraryImportElement element) {
     element as LibraryImportElementImpl;
     _resolutionSink._writeAnnotationList(element.metadata);
-    _writeDirectiveUri(element.uri);
-    _writeImportElementPrefix(element.prefix);
     _sink.writeList(element.combinators, _writeNamespaceCombinator);
+    _writeImportElementPrefix(element.prefix);
+    _writeDirectiveUri(element.uri);
     ImportElementFlags.write(_sink, element);
   }
 
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index b18aafb..e1511dd 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -615,9 +615,10 @@
     }
 
     return LibraryExportElementImpl(
+      combinators: combinators,
       exportKeywordOffset: state.unlinked.exportKeywordOffset,
       uri: uri,
-    )..combinators = combinators;
+    );
   }
 
   LibraryImportElementImpl _buildImport({
@@ -702,12 +703,11 @@
     }
 
     return LibraryImportElementImpl(
+      combinators: combinators,
       importKeywordOffset: state.unlinked.importKeywordOffset,
-      uri: uri,
       prefix: importPrefix,
-    )
-      ..combinators = combinators
-      ..isSynthetic = state.isSyntheticDartCore;
+      uri: uri,
+    )..isSynthetic = state.isSyntheticDartCore;
   }
 
   PrefixElementImpl _buildPrefix({
diff --git a/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart b/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
index 9f757d0..70b8c34 100644
--- a/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
@@ -290,6 +290,35 @@
     expect(outerRoot.packagesFile, outerPackagesFile);
   }
 
+  void
+      test_locateRoots_multiple_dirAndNestedDir_outerIsBazel_innerConfigurationFiles() {
+    var outerRootFolder = newFolder('/outer');
+    newFile('$outerRootFolder/WORKSPACE', '');
+    newBazelBuildFile('$outerRootFolder', '');
+    var innerRootFolder = newFolder('/outer/examples/inner');
+    var innerOptionsFile = newAnalysisOptionsYamlFile('$innerRootFolder', '');
+    var innerPackagesFile = newPackageConfigJsonFile('$innerRootFolder', '');
+    newPubspecYamlFile('$innerRootFolder', '');
+
+    var roots = contextLocator.locateRoots(
+      includedPaths: [outerRootFolder.path, innerRootFolder.path],
+    );
+    expect(roots, hasLength(2));
+
+    var outerRoot = findRoot(roots, outerRootFolder);
+    expect(outerRoot.includedPaths, unorderedEquals([outerRootFolder.path]));
+    expect(outerRoot.excludedPaths, unorderedEquals([innerRootFolder.path]));
+    expect(outerRoot.optionsFile, isNull);
+    expect(outerRoot.packagesFile, isNull);
+
+    var innerRoot = findRoot(roots, innerRootFolder);
+    expect(innerRoot.workspace.root, equals(innerRootFolder.path));
+    expect(innerRoot.includedPaths, unorderedEquals([innerRootFolder.path]));
+    expect(innerRoot.excludedPaths, isEmpty);
+    expect(innerRoot.optionsFile, innerOptionsFile);
+    expect(innerRoot.packagesFile, innerPackagesFile);
+  }
+
   void test_locateRoots_multiple_dirAndNestedFile_excludedByOptions() {
     var rootPath = convertPath('/home/test');
     var rootFolder = newFolder(rootPath);
diff --git a/pkg/dev_compiler/tool/ddb b/pkg/dev_compiler/tool/ddb
index 799e176..8efa3e5 100755
--- a/pkg/dev_compiler/tool/ddb
+++ b/pkg/dev_compiler/tool/ddb
@@ -3,23 +3,20 @@
 // 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
-
-//
-// Compiles code with DDC and runs the resulting code with either node or
-// chrome.
-//
-// The first script supplied should be the one with `main()`.
-//
-// Saves the output in the same directory as the sources for convenient
-// inspection, modification or rerunning the code.
+/// Compiles code with DDC and runs the resulting code with either node or
+/// chrome.
+///
+/// The first script supplied should be the one with `main()`.
+///
+/// Saves the output in the same directory as the sources for convenient
+/// inspection, modification or rerunning the code.
 
 import 'dart:io';
 
 import 'package:args/args.dart' show ArgParser;
-import 'package:path/path.dart' as p;
 import 'package:dev_compiler/src/compiler/module_builder.dart'
     as module_builder;
+import 'package:path/path.dart' as p;
 
 enum NullSafety { strict, weak, disabled }
 
@@ -113,14 +110,14 @@
     printUsage();
     exit(1);
   }
-  var arch = options['arch'] as String;
+  var arch = options['arch'] as String?;
   var debug = options['debug'] as bool ||
       options['observe'] as bool ||
       options.wasParsed('vm-service-port');
   var summarizeText = options['summarize-text'] as bool;
-  var binary = options['binary'] as String;
-  var experiments = options['enable-experiment'] as List;
-  var summaries = options['summary'] as List;
+  var binary = options['binary'] as String?;
+  var experiments = options['enable-experiment'] as List<String>;
+  var summaries = options['summary'] as List<String>;
   var port = int.parse(options['port'] as String);
   var mode = options['mode'] as String;
   var compile = mode == 'compile' || mode == 'all';
@@ -133,7 +130,7 @@
   var weakNullSafetyErrors = options['weak-null-safety-errors'] as bool;
   var canaryFeatures = options['canary'] as bool;
   var entry = p.canonicalize(options.rest.first);
-  var out = (options['out'] as String) ?? p.setExtension(entry, '.js');
+  var out = (options['out'] as String?) ?? p.setExtension(entry, '.js');
   var libRoot = p.dirname(entry);
   var basename = p.basenameWithoutExtension(entry);
   var libname =
@@ -180,8 +177,9 @@
     var vmServicePort = options.wasParsed('vm-service-port')
         ? '=${options['vm-service-port']}'
         : '';
+    var vmOptions = options['compile-vm-options'] as String?;
     var args = <String>[
-      ...?options['compile-vm-options']?.split(' '),
+      ...?vmOptions?.split(' '),
       if (debug) ...[
         if (observe) ...[
           '--enable-vm-service$vmServicePort',
@@ -200,10 +198,11 @@
   }
 
   String mod;
-  bool chrome = false;
-  bool node = false;
-  bool d8 = false;
-  switch (options['runtime'] as String) {
+  var chrome = false;
+  var node = false;
+  var d8 = false;
+  var runtime = options['runtime'] as String?;
+  switch (runtime) {
     case 'node':
       node = true;
       mod = 'common';
@@ -216,6 +215,8 @@
       chrome = true;
       mod = 'amd';
       break;
+    default:
+      throw Exception('Unexpected runtime: $runtime');
   }
 
   var sdkRoot = p.dirname(p.dirname(ddcPath));
@@ -386,14 +387,15 @@
 };
 
 /// Returns the location of the Dart SDK's build directory.
-String resolveBuildDir(String sdkRoot, String architecture) {
+String resolveBuildDir(String sdkRoot, String? architecture) {
   String platformString;
   String archString;
   if (Platform.isMacOS) {
     platformString = 'xcodebuild';
-    String resolvedArchitecture = architecture;
+    var resolvedArchitecture = architecture;
     if (architecture == null) {
-      final uname = Process.runSync('uname', ['-m']).stdout.trim();
+      var result = Process.runSync('uname', ['-m']).stdout as String;
+      final uname = result.trim();
       resolvedArchitecture = _resolvedUnames[uname] ?? uname;
     }
     if (resolvedArchitecture == 'x64') {
diff --git a/pkg/dev_compiler/web/source_map_stack_trace.dart b/pkg/dev_compiler/web/source_map_stack_trace.dart
index cb74f58..984b178 100644
--- a/pkg/dev_compiler/web/source_map_stack_trace.dart
+++ b/pkg/dev_compiler/web/source_map_stack_trace.dart
@@ -2,8 +2,7 @@
 // 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 'package:collection/collection.dart' show IterableNullableExtension;
 import 'package:path/path.dart' as p;
 import 'package:source_maps/source_maps.dart';
 import 'package:stack_trace/stack_trace.dart';
@@ -17,7 +16,7 @@
 /// [roots] are the paths (usually `http:` URI strings) that DDC applications
 /// are served from.  This is used to identify sdk and package URIs.
 StackTrace mapStackTrace(Mapping sourceMap, StackTrace stackTrace,
-    {List<String> roots}) {
+    {required List<String?> roots}) {
   if (stackTrace is Chain) {
     return Chain(stackTrace.traces.map((trace) {
       return Trace.from(mapStackTrace(sourceMap, trace, roots: roots));
@@ -35,8 +34,8 @@
 
     // Subtract 1 because stack traces use 1-indexed lines and columns and
     // source maps uses 0-indexed.
-    var span = sourceMap.spanFor(frame.line - 1, column - 1,
-        uri: frame.uri?.toString());
+    var span = sourceMap.spanFor(frame.line! - 1, column - 1,
+        uri: frame.uri.toString());
 
     // If we can't find a source span, ignore the frame. It's probably something
     // internal that the user doesn't care about.
@@ -68,8 +67,8 @@
     }
 
     return Frame(Uri.parse(sourceUrl), span.start.line + 1,
-        span.start.column + 1, _prettifyMember(frame.member));
-  }).where((frame) => frame != null));
+        span.start.column + 1, _prettifyMember(frame.member!));
+  }).whereNotNull());
 }
 
 final escapedPipe = '\$124';
diff --git a/pkg/dev_compiler/web/stack_trace_mapper.dart b/pkg/dev_compiler/web/stack_trace_mapper.dart
index 51df77d..6083d88 100644
--- a/pkg/dev_compiler/web/stack_trace_mapper.dart
+++ b/pkg/dev_compiler/web/stack_trace_mapper.dart
@@ -2,8 +2,6 @@
 // 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
-
 /// Standalone utility that manages loading source maps for all Dart scripts
 /// on the page compiled with DDC.
 ///
@@ -49,7 +47,7 @@
 @anonymous
 class DartStackTraceUtility {
   external factory DartStackTraceUtility(
-      {StackTraceMapper mapper, SetSourceMapProvider setSourceMapProvider});
+      {StackTraceMapper? mapper, SetSourceMapProvider? setSourceMapProvider});
 }
 
 @JS('JSON.stringify')
@@ -70,8 +68,8 @@
   List toJson() => _bundle.toJson();
 
   @override
-  SourceMapSpan spanFor(int line, int column,
-      {Map<String, SourceFile> files, String uri}) {
+  SourceMapSpan? spanFor(int line, int column,
+      {Map<String, SourceFile>? files, String? uri}) {
     if (uri == null) {
       throw ArgumentError.notNull('uri');
     }
@@ -91,24 +89,25 @@
     // TODO(jacobr): we shouldn't have to filter out invalid sourceUrl entries
     // here.
     if (span == null || span.start.sourceUrl == null) return null;
-    var pathSegments = span.start.sourceUrl.pathSegments;
+    var pathSegments = span.start.sourceUrl!.pathSegments;
     if (pathSegments.isNotEmpty && pathSegments.last == 'null') return null;
     return span;
   }
 }
 
-LazyMapping _mapping;
+LazyMapping? _mapping;
 
 List<String> roots = rootDirectories.map((s) => '$s').toList();
 
 String mapper(String rawStackTrace) {
-  if (_mapping == null) {
+  var mapping = _mapping;
+  if (mapping == null) {
     // This should not happen if the user has waited for the ReadyCallback
     // to start the application.
     throw StateError('Source maps are not done loading.');
   }
   var trace = Trace.parse(rawStackTrace);
-  return mapStackTrace(_mapping, trace, roots: roots).toString();
+  return mapStackTrace(mapping, trace, roots: roots).toString();
 }
 
 void setSourceMapProvider(SourceMapProvider provider) {
diff --git a/runtime/tools/dartfuzz/gen_api_table.dart b/runtime/tools/dartfuzz/gen_api_table.dart
index c7f55a0..79b157c 100644
--- a/runtime/tools/dartfuzz/gen_api_table.dart
+++ b/runtime/tools/dartfuzz/gen_api_table.dart
@@ -482,7 +482,7 @@
   // Supertypes or type parameters are specialized in a consistent manner.
   // TODO(ajcbik): inspect type structure semantically, not by display name
   //               and unify DartFuzz's DartType with analyzer DartType.
-  switch (type.displayName) {
+  switch (type.asCode) {
     case 'AbstractClassInstantiationError':
       return abstractClassInstantiationErrorEncoding;
     case 'ArgumentError':
diff --git a/runtime/tools/dartfuzz/gen_type_table.dart b/runtime/tools/dartfuzz/gen_type_table.dart
index da456c5..2e7f683 100644
--- a/runtime/tools/dartfuzz/gen_type_table.dart
+++ b/runtime/tools/dartfuzz/gen_type_table.dart
@@ -122,6 +122,8 @@
   return constName;
 }
 
+String typeConstName(DartType tp) => getConstName(tp.asCode);
+
 // Returns true if the given type fails the filter criteria.
 bool shouldFilterType(String typName, {bool fp = true, bool flatTp = false}) {
   if (!fp && fpTypes.contains(typName)) {
@@ -694,13 +696,13 @@
   // Generate one static DartType instance for all instantiable types.
   // TODO (felih): maybe add void type?
   allTypes.forEach((baseType) {
-    var constName = getConstName(baseType.displayName);
+    var constName = typeConstName(baseType);
     instTypes.add(constName);
     if (!subclass) {
       print('  static const $constName = '
-          "DartType._withName('${baseType.displayName}', false);");
+          "DartType._withName('${baseType.asCode}', false);");
       print('  static const ${constName}_NULLABLE = '
-          "DartType._withName('${baseType.displayName}', true);");
+          "DartType._withName('${baseType.asCode}', true);");
     }
   });
 
@@ -896,7 +898,7 @@
 // See comment on filterOpterator.
 void filterOperators(Set<InterfaceType> allTypes) {
   for (var tp in allTypes) {
-    var typName = getConstName(tp.displayName);
+    var typName = typeConstName(tp);
     if (!binOps.containsKey(typName)) continue;
     for (var op in binOps[typName]!.keys) {
       binOps[typName]![op] = filterOperator(binOps[typName]![op]!);
@@ -911,8 +913,8 @@
 bool isExcludedMethod(InterfaceType tp, MethodElement method) {
   // TODO(bkonyi): Enable operator / for these types after we resolve
   // https://github.com/dart-lang/sdk/issues/39890
-  if (((tp.displayName == 'Float32x4') && (method.name == '/')) ||
-      ((tp.displayName == 'Float64x2') && (method.name == '/'))) {
+  if (((tp.element.name == 'Float32x4') && (method.name == '/')) ||
+      ((tp.element.name == 'Float64x2') && (method.name == '/'))) {
     return true;
   }
   return false;
@@ -935,7 +937,7 @@
     // 'castFrom' or 'parse'.
     if (method.isStatic &&
         (method.name == 'castFrom' || method.name == 'parse')) {
-      fromLiteral.add(getConstName(tp.displayName));
+      fromLiteral.add(typeConstName(tp));
     }
     // Hack: dartfuzz.dart already handles subscripts, therefore we exclude
     // them from the generated type table.
@@ -944,7 +946,7 @@
       // TODO (felih): Include support for type 'dynamic'.
       var skip = false;
       for (var p in method.parameters) {
-        if (getConstName(p.type.displayName) == 'DYNAMIC') {
+        if (typeConstName(p.type) == 'DYNAMIC') {
           skip = true;
           break;
         }
@@ -953,14 +955,14 @@
       if (method.parameters.length == 1) {
         // Get binary operators.
 
-        var retTypName = getConstName(method.returnType.displayName);
+        var retTypName = typeConstName(method.returnType);
         if (method.returnType.nullabilitySuffix != NullabilitySuffix.none) {
           retTypName += '_NULLABLE';
         }
         binOps[retTypName] ??= <String, Set<List<String>>>{};
         binOps[retTypName]![method.name] ??= <List<String>>{};
 
-        var rhsTypName = getConstName(method.parameters[0].type.displayName);
+        var rhsTypName = typeConstName(method.parameters[0].type);
         if (method.parameters[0].type.nullabilitySuffix !=
             NullabilitySuffix.none) {
           rhsTypName += '_NULLABLE';
@@ -1007,7 +1009,7 @@
   // The analyzer's DartType doesn't provide conversions to change nullability.
   // Comparing by name isn't correct in general, but it works for the core
   // libraries because there are no simple name conflicts.
-  return a.displayName == b.displayName;
+  return a.asCode == b.asCode;
 }
 
 // Extract all binary and unary operators for all types.
@@ -1023,7 +1025,7 @@
   fromLiteral.add('STRING');
   // Get binary, unary and assignment operators.
   for (var tp in allTypes) {
-    var typName = getConstName(tp.displayName);
+    var typName = typeConstName(tp);
     // Manually add basic assignment operators which each type supports.
     assignOps[typName] ??= <String, Set<String>>{};
     assignOps[typName]!['='] = {typName};
@@ -1063,7 +1065,7 @@
 
   // Get constructors.
   for (var tp in allTypes) {
-    var typName = getConstName(tp.displayName);
+    var typName = typeConstName(tp);
     // Skip types that are constructable from a literal.
     if (fromLiteral.contains(typName)) {
       continue;
@@ -1073,7 +1075,7 @@
       var params = <String>[];
       var canConstruct = true;
       for (var p in constructor.parameters) {
-        var tstr = getConstName(p.type.displayName);
+        var tstr = typeConstName(p.type);
         if (tstr == 'DYNAMIC' || tstr == 'OBJECT') {
           tstr = 'INT';
         } else if (!allTypes
@@ -1105,7 +1107,7 @@
   // Constructor exclude list
   // TODO(bkonyi): Enable Float32x4.fromInt32x4Bits after we resolve
   // https://github.com/dart-lang/sdk/issues/39890
-  if ((tp.displayName == 'Float32x4') && (cons.name == 'fromInt32x4Bits')) {
+  if ((tp.element.name == 'Float32x4') && (cons.name == 'fromInt32x4Bits')) {
     return true;
   }
   return false;
@@ -1116,17 +1118,17 @@
 void analyzeTypes(Set<InterfaceType> allTypes) {
   // Extract basic floating point types.
   for (var tp in allTypes) {
-    if (tp.displayName.contains('Float') ||
-        tp.displayName.contains('float') ||
-        tp.displayName.contains('double') ||
-        tp.displayName.contains('Double')) {
-      fpTypes.add(getConstName(tp.displayName));
+    if (tp.asCode.contains('Float') ||
+        tp.asCode.contains('float') ||
+        tp.asCode.contains('double') ||
+        tp.asCode.contains('Double')) {
+      fpTypes.add(typeConstName(tp));
     }
   }
 
   // Analyze all types to extract information useful for dart code generation.
   for (var tp in allTypes) {
-    final typName = getConstName(tp.displayName);
+    final typName = typeConstName(tp);
 
     // Find topmost interface type, e.g. List<int> is interface for Int8List.
     var iTyp = tp;
@@ -1141,7 +1143,7 @@
 
     if (iTyp.typeArguments.length == 1) {
       // Analyze Array, List and Set types.
-      var argName = getConstName(iTyp.typeArguments[0].displayName);
+      var argName = typeConstName(iTyp.typeArguments[0]);
       subscriptsTo[typName] = argName;
       elementOf[argName] ??= <String>{};
       elementOf[argName]!.add(typName);
@@ -1158,8 +1160,8 @@
     } else if (iTyp.typeArguments.length == 2) {
       if (isIndexable(iTyp)) {
         // Analyze Map and MapEntry types.
-        var argName0 = getConstName(iTyp.typeArguments[0].displayName);
-        var argName1 = getConstName(iTyp.typeArguments[1].displayName);
+        var argName0 = typeConstName(iTyp.typeArguments[0]);
+        var argName1 = typeConstName(iTyp.typeArguments[1]);
         subscriptsTo[typName] = argName1;
         elementOf[argName1] ??= <String>{};
         elementOf[argName1]!.add(typName);
@@ -1235,7 +1237,7 @@
       );
       newITypes.add(ptx);
       if (iType.typeArguments.isNotEmpty) {
-        complexTypes.add(getConstName(ptx.displayName));
+        complexTypes.add(typeConstName(ptx));
       }
     });
   });
@@ -1257,7 +1259,7 @@
         newITypes.add(ptx);
         if (iType1.typeArguments.isNotEmpty ||
             iType2.typeArguments.isNotEmpty) {
-          complexTypes.add(getConstName(ptx.displayName));
+          complexTypes.add(typeConstName(ptx));
         }
       });
     });
@@ -1284,7 +1286,7 @@
   // complex types like Int8List.
   var filteredITypes = <InterfaceType>{};
   for (var iType in iTypes) {
-    if (iTypeFilter.contains(iType.displayName)) {
+    if (iTypeFilter.contains(iType.element.name)) {
       filteredITypes.add(iType);
     }
   }
@@ -1409,7 +1411,7 @@
 Set<String> getInterfaces(InterfaceType tp) {
   var iTypes = <String>{};
   for (var iTyp in tp.interfaces) {
-    var ifTypName = getConstName(iTyp.displayName);
+    var ifTypName = typeConstName(iTyp);
     iTypes.add(ifTypName);
     iTypes = iTypes.union(getInterfaces(iTyp));
   }
@@ -1419,7 +1421,7 @@
 // Get interface and inheritance relationships for all types.
 void getInterfaceRels(Set<InterfaceType> allTypes) {
   for (var tp in allTypes) {
-    var typName = getConstName(tp.displayName);
+    var typName = typeConstName(tp);
     for (var ifTypName in getInterfaces(tp)) {
       interfaceRels[ifTypName] ??= <String>{};
       interfaceRels[ifTypName]!.add(typName);
@@ -1428,7 +1430,7 @@
       }
     }
     for (var it in tp.element.allSupertypes) {
-      var ifTypName = getConstName(it.displayName);
+      var ifTypName = typeConstName(it);
       interfaceRels[ifTypName] ??= <String>{};
       interfaceRels[ifTypName]!.add(typName);
     }
@@ -1438,7 +1440,7 @@
   // do tp1 = oneof(interfaceRels[tp2]) in dartfuzz with a chance of
   // tp1 == tp1.
   for (var tp in allTypes) {
-    var typName = getConstName(tp.displayName);
+    var typName = typeConstName(tp);
     if (interfaceRels.containsKey(typName)) {
       interfaceRels[typName]!.add(typName);
     }
diff --git a/runtime/tools/dartfuzz/gen_util.dart b/runtime/tools/dartfuzz/gen_util.dart
index f27f17c..19446f9 100644
--- a/runtime/tools/dartfuzz/gen_util.dart
+++ b/runtime/tools/dartfuzz/gen_util.dart
@@ -5,6 +5,7 @@
 import 'dart:io';
 
 import 'package:analyzer/dart/analysis/session.dart';
+import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
 
@@ -46,3 +47,33 @@
     return collection.contexts[0].currentSession;
   }
 }
+
+extension DartTypeExtension on DartType {
+  /// Returns an approximation of the [DartType] code, suitable for this tool.
+  String get asCode {
+    final type = this;
+    if (type is DynamicType) {
+      return 'dynamic';
+    } else if (type is FunctionType) {
+      final parameters = type.parameters.map((e) => e.type.asCode);
+      return type.returnType.asCode + ' Function($parameters)';
+    } else if (type is InterfaceType) {
+      final typeArguments = type.typeArguments;
+      if (typeArguments.isEmpty ||
+          typeArguments.every((t) => t is DynamicType)) {
+        return type.element.name;
+      } else {
+        final typeArgumentsStr = typeArguments.map((t) => t.asCode).join(', ');
+        return '${type.element.name}<$typeArgumentsStr>';
+      }
+    } else if (type is NeverType) {
+      return 'Never';
+    } else if (type is TypeParameterType) {
+      return type.element.name;
+    } else if (type is VoidType) {
+      return 'void';
+    } else {
+      throw UnimplementedError('(${type.runtimeType}) $type');
+    }
+  }
+}
diff --git a/tools/VERSION b/tools/VERSION
index f20d368..9586891 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 19
 PATCH 0
-PRERELEASE 13
+PRERELEASE 14
 PRERELEASE_PATCH 0
\ No newline at end of file