Version 2.15.0-223.0.dev

Merge commit '2bbb5dc9071f67aaf4808a1cc70c482ccbfafb7e' into 'dev'
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
index fa46af3..0a1e1c2 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
@@ -416,7 +416,7 @@
 
   Future<Library> _getLibrary(Uri libraryUri) async {
     return await _compiler.context.runInContext((_) async {
-      var builder = _compiler.userCode.loader.builders[libraryUri];
+      var builder = _compiler.userCode.loader.lookupLibraryBuilder(libraryUri);
       if (builder != null) {
         var library =
             _compiler.userCode.loader.read(libraryUri, -1, accessor: builder);
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
index 8d60ebc..edf5ede 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
@@ -396,7 +396,7 @@
         } else {
           unhandled("${node.runtimeType}", "finalizeExports", -1, fileUri);
         }
-        LibraryBuilder? library = loader.builders[libraryUri];
+        LibraryBuilder? library = loader.lookupLibraryBuilder(libraryUri);
         if (library == null) {
           internalProblem(
               templateUnspecified
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
index 3a4bdc0..86a4c3b 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
@@ -47,8 +47,7 @@
 class DillLoader extends Loader {
   SourceLoader? currentSourceLoader;
 
-  @override
-  final Map<Uri, DillLibraryBuilder> builders = <Uri, DillLibraryBuilder>{};
+  final Map<Uri, DillLibraryBuilder> _builders = <Uri, DillLibraryBuilder>{};
 
   final Queue<DillLibraryBuilder> _unparsedLibraries =
       new Queue<DillLibraryBuilder>();
@@ -87,10 +86,6 @@
   @override
   LibraryBuilder get coreLibrary => _coreLibrary!;
 
-  void set coreLibrary(LibraryBuilder value) {
-    _coreLibrary = value;
-  }
-
   Ticker get ticker => target.ticker;
 
   /// Look up a library builder by the [uri], or if such doesn't exist, create
@@ -105,7 +100,7 @@
   /// directive. If [accessor] isn't allowed to access [uri], it's a
   /// compile-time error.
   DillLibraryBuilder read(Uri uri, int charOffset, {LibraryBuilder? accessor}) {
-    DillLibraryBuilder builder = builders.putIfAbsent(uri, () {
+    DillLibraryBuilder builder = _builders.putIfAbsent(uri, () {
       DillLibraryBuilder library = target.createLibraryBuilder(uri);
       assert(library.loader == this);
       if (uri.scheme == "dart") {
@@ -165,7 +160,7 @@
   void _logSummary(Template<SummaryTemplate> template) {
     ticker.log((Duration elapsed, Duration sinceStart) {
       int libraryCount = 0;
-      for (DillLibraryBuilder library in builders.values) {
+      for (DillLibraryBuilder library in libraryBuilders) {
         assert(library.loader == this);
         libraryCount++;
       }
@@ -305,9 +300,8 @@
   }
 
   void finalizeExports({bool suppressFinalizationErrors: false}) {
-    for (LibraryBuilder builder in builders.values) {
-      DillLibraryBuilder library = builder as DillLibraryBuilder;
-      library.markAsReadyToFinalizeExports(
+    for (DillLibraryBuilder builder in libraryBuilders) {
+      builder.markAsReadyToFinalizeExports(
           suppressFinalizationErrors: suppressFinalizationErrors);
     }
   }
@@ -315,9 +309,10 @@
   @override
   ClassBuilder computeClassBuilderFromTargetClass(Class cls) {
     Library kernelLibrary = cls.enclosingLibrary;
-    LibraryBuilder? library = builders[kernelLibrary.importUri];
+    LibraryBuilder? library = lookupLibraryBuilder(kernelLibrary.importUri);
     if (library == null) {
-      library = currentSourceLoader?.builders[kernelLibrary.importUri];
+      library =
+          currentSourceLoader?.lookupLibraryBuilder(kernelLibrary.importUri);
     }
     return library!.lookupLocalMember(cls.name, required: true) as ClassBuilder;
   }
@@ -326,4 +321,28 @@
   TypeBuilder computeTypeBuilder(DartType type) {
     return type.accept(new TypeBuilderComputer(this));
   }
+
+  bool containsLibraryBuilder(Uri importUri) =>
+      _builders.containsKey(importUri);
+
+  @override
+  DillLibraryBuilder? lookupLibraryBuilder(Uri importUri) =>
+      _builders[importUri];
+
+  Iterable<DillLibraryBuilder> get libraryBuilders => _builders.values;
+
+  Iterable<Uri> get libraryImportUris => _builders.keys;
+
+  void registerLibraryBuilder(DillLibraryBuilder libraryBuilder) {
+    Uri importUri = libraryBuilder.importUri;
+    libraryBuilder.loader = this;
+    if (importUri.scheme == "dart" && importUri.path == "core") {
+      _coreLibrary = libraryBuilder;
+    }
+    _builders[importUri] = libraryBuilder;
+  }
+
+  DillLibraryBuilder? deregisterLibraryBuilder(Uri importUri) {
+    return _builders.remove(importUri);
+  }
 }
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_target.dart b/pkg/front_end/lib/src/fasta/dill/dill_target.dart
index 28ccfbc..459831a 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_target.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_target.dart
@@ -97,8 +97,7 @@
   ///
   /// The [DillLibraryBuilder] is pulled from [_knownLibraryBuilders].
   DillLibraryBuilder createLibraryBuilder(Uri uri) {
-    DillLibraryBuilder libraryBuilder =
-        _knownLibraryBuilders.remove(uri) as DillLibraryBuilder;
+    DillLibraryBuilder libraryBuilder = _knownLibraryBuilders.remove(uri)!;
     // ignore: unnecessary_null_comparison
     assert(libraryBuilder != null, "No library found for $uri.");
     return libraryBuilder;
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index a188b12..febaaf8 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -102,6 +102,7 @@
 
 import 'dill/dill_library_builder.dart' show DillLibraryBuilder;
 
+import 'dill/dill_loader.dart' show DillLoader;
 import 'dill/dill_target.dart' show DillTarget;
 
 import 'export.dart' show Export;
@@ -283,7 +284,7 @@
       // non-null.
       if (userCode != null) {
         ticker.logMs("Decided to reuse ${reusedLibraries.length}"
-            " of ${userCode!.loader.builders.length} libraries");
+            " of ${userCode!.loader.libraryBuilders.length} libraries");
       }
 
       // For modular compilation we can be asked to load components and track
@@ -368,7 +369,7 @@
       // calculation has the potential to work.
       // ignore: unnecessary_null_comparison
       if (componentWithDill == null) {
-        userCode!.loader.builders.clear();
+        userCode!.loader.clearLibraryBuilders();
         userCode = userCodeOld;
         dillLoadedData!.loader.currentSourceLoader = userCode!.loader;
       } else {
@@ -415,14 +416,16 @@
     Set<Library> newDillLibraryBuilders = new Set<Library>();
     userBuilders ??= <Uri, LibraryBuilder>{};
     Map<LibraryBuilder, List<LibraryBuilder>>? convertedLibraries;
-    for (MapEntry<Uri, LibraryBuilder> entry
-        in userCode!.loader.builders.entries) {
-      if (entry.value is SourceLibraryBuilder) {
-        SourceLibraryBuilder builder = entry.value as SourceLibraryBuilder;
+    for (LibraryBuilder builder in userCode!.loader.libraryBuilders) {
+      if (builder is SourceLibraryBuilder) {
         DillLibraryBuilder dillBuilder =
             dillLoadedData!.loader.appendLibrary(builder.library);
-        userCode!.loader.builders[entry.key] = dillBuilder;
-        userBuilders![entry.key] = dillBuilder;
+        userCode!.loader.registerLibraryBuilder(
+            // TODO(johnniwinther): Why do we need to create
+            //  [DillLibraryBuilder]s for the patch library file uris?
+            dillBuilder,
+            builder.isPatch ? builder.fileUri : null);
+        userBuilders![builder.importUri] = dillBuilder;
         newDillLibraryBuilders.add(builder.library);
         if (userCode!.loader.first == builder) {
           userCode!.loader.first = dillBuilder;
@@ -439,8 +442,7 @@
       // We suppress finalization errors because they have already been
       // reported.
       dillLoadedData!.buildOutlines(suppressFinalizationErrors: true);
-      assert(_checkEquivalentScopes(
-          userCode!.loader.builders, dillLoadedData!.loader.builders));
+      assert(_checkEquivalentScopes(userCode!.loader, dillLoadedData!.loader));
 
       if (experimentalInvalidation != null) {
         /// If doing experimental invalidation that means that some of the old
@@ -485,18 +487,19 @@
     return newDillLibraryBuilders;
   }
 
-  bool _checkEquivalentScopes(Map<Uri, LibraryBuilder> sourceLibraries,
-      Map<Uri, LibraryBuilder> dillLibraries) {
-    sourceLibraries.forEach((Uri uri, LibraryBuilder sourceLibraryBuilder) {
+  bool _checkEquivalentScopes(
+      SourceLoader sourceLoader, DillLoader dillLoader) {
+    for (LibraryBuilder sourceLibraryBuilder in sourceLoader.libraryBuilders) {
       if (sourceLibraryBuilder is SourceLibraryBuilder) {
+        Uri uri = sourceLibraryBuilder.importUri;
         DillLibraryBuilder dillLibraryBuilder =
-            dillLibraries[uri] as DillLibraryBuilder;
+            dillLoader.lookupLibraryBuilder(uri)!;
         assert(
             _hasEquivalentScopes(sourceLibraryBuilder, dillLibraryBuilder) ==
                 null,
             _hasEquivalentScopes(sourceLibraryBuilder, dillLibraryBuilder));
       }
-    });
+    }
     return true;
   }
 
@@ -634,7 +637,7 @@
       // evaluator - that comes from dill - are marked.
       Set<Library> librariesUsedByConstantEvaluator = userCode!.librariesUsed;
 
-      for (LibraryBuilder builder in dillLoadedData!.loader.builders.values) {
+      for (LibraryBuilder builder in dillLoadedData!.loader.libraryBuilders) {
         if (builder is DillLibraryBuilder) {
           if (builder.isBuiltAndMarked ||
               librariesUsedByConstantEvaluator.contains(builder.library)) {
@@ -840,11 +843,7 @@
     List<bool> seenModes = [false, false, false, false];
     for (LibraryBuilder library in reusedLibraries) {
       seenModes[library.library.nonNullableByDefaultCompiledMode.index] = true;
-      userCode!.loader.builders[library.importUri] = library;
-      if (library.importUri.scheme == "dart" &&
-          library.importUri.path == "core") {
-        userCode!.loader.coreLibrary = library;
-      }
+      userCode!.loader.registerLibraryBuilder(library);
     }
     // Check compilation mode up against what we've seen here and set
     // `hasInvalidNnbdModeLibrary` accordingly.
@@ -906,10 +905,12 @@
               ? firstEntryPoint
               : null);
     }
-    if (userCode!.loader.first == null &&
-        userCode!.loader.builders[firstEntryPointImportUri] != null) {
-      userCode!.loader.first =
-          userCode!.loader.builders[firstEntryPointImportUri];
+    if (userCode!.loader.first == null) {
+      LibraryBuilder? libraryBuilder =
+          userCode!.loader.lookupLibraryBuilder(firstEntryPointImportUri);
+      if (libraryBuilder != null) {
+        userCode!.loader.first = libraryBuilder;
+      }
     }
   }
 
@@ -919,7 +920,7 @@
   void resetTrackingOfUsedLibraries(ClassHierarchy? hierarchy) {
     if (trackNeededDillLibraries) {
       // Reset dill loaders and kernel class hierarchy.
-      for (LibraryBuilder builder in dillLoadedData!.loader.builders.values) {
+      for (LibraryBuilder builder in dillLoadedData!.loader.libraryBuilders) {
         if (builder is DillLibraryBuilder) {
           if (builder.isBuiltAndMarked) {
             // Clear cached calculations in classes which upon calculation can
@@ -976,13 +977,9 @@
       // Make sure the dill loader is on the same page.
       DillTarget oldDillLoadedData = dillLoadedData!;
       dillLoadedData = new DillTarget(ticker, uriTranslator, c.options.target);
-      for (LibraryBuilder library in oldDillLoadedData.loader.builders.values) {
-        (library as DillLibraryBuilder).loader = dillLoadedData!.loader;
-        dillLoadedData!.loader.builders[library.importUri] = library;
-        if (library.importUri.scheme == "dart" &&
-            library.importUri.path == "core") {
-          dillLoadedData!.loader.coreLibrary = library;
-        }
+      for (DillLibraryBuilder library
+          in oldDillLoadedData.loader.libraryBuilders) {
+        dillLoadedData!.loader.registerLibraryBuilder(library);
       }
       dillLoadedData!.loader.first = oldDillLoadedData.loader.first;
       dillLoadedData!.loader.libraries
@@ -1006,7 +1003,7 @@
       incrementalSerializer?.invalidate(builder.fileUri);
 
       LibraryBuilder? dillBuilder =
-          dillLoadedData!.loader.builders.remove(builder.importUri);
+          dillLoadedData!.loader.deregisterLibraryBuilder(builder.importUri);
       if (dillBuilder != null) {
         removedDillBuilders = true;
         userBuilders?.remove(builder.importUri);
@@ -1287,13 +1284,14 @@
       dillLoadedData!.buildOutlines(suppressFinalizationErrors: true);
       userBuilders = <Uri, LibraryBuilder>{};
       platformBuilders = <LibraryBuilder>[];
-      dillLoadedData!.loader.builders.forEach((uri, builder) {
+      for (DillLibraryBuilder builder
+          in dillLoadedData!.loader.libraryBuilders) {
         if (builder.importUri.scheme == "dart") {
           platformBuilders!.add(builder);
         } else {
-          userBuilders![uri] = builder;
+          userBuilders![builder.importUri] = builder;
         }
-      });
+      }
       if (userBuilders!.isEmpty) userBuilders = null;
     }
     data.initializationBytes = null;
@@ -1382,7 +1380,7 @@
         Library library = c.enclosingLibrary;
         // Only add if loaded from a dill file (and wasn't a 'dill' that was
         // converted from source builders to dill builders).
-        if (dillLoadedData!.loader.builders.containsKey(library.importUri) &&
+        if (dillLoadedData!.loader.containsLibraryBuilder(library.importUri) &&
             (previousSourceBuilders == null ||
                 !previousSourceBuilders!.contains(library))) {
           neededDillLibraries!.add(library);
@@ -1393,10 +1391,10 @@
       // if all bets are off: Add everything (except for the libraries we just
       // converted from source builders to dill builders).
       neededDillLibraries = new Set<Library>();
-      for (LibraryBuilder builder in dillLoadedData!.loader.builders.values) {
-        if (builder is DillLibraryBuilder &&
-            (previousSourceBuilders == null ||
-                !previousSourceBuilders!.contains(builder.library))) {
+      for (DillLibraryBuilder builder
+          in dillLoadedData!.loader.libraryBuilders) {
+        if (previousSourceBuilders == null ||
+            !previousSourceBuilders!.contains(builder.library)) {
           neededDillLibraries!.add(builder.library);
         }
       }
@@ -1426,7 +1424,7 @@
       for (Component module in modulesToLoad!) {
         bool usedComponent = false;
         for (Library lib in module.libraries) {
-          if (!dillLoadedData!.loader.builders.containsKey(lib.importUri)) {
+          if (!dillLoadedData!.loader.containsLibraryBuilder(lib.importUri)) {
             dillLoadedData!.loader.libraries.add(lib);
             dillLoadedData!.registerLibrary(lib);
             reusedLibraries.add(dillLoadedData!.loader.read(lib.importUri, -1));
@@ -1444,13 +1442,14 @@
         dillLoadedData!.buildOutlines(suppressFinalizationErrors: true);
         userBuilders = <Uri, LibraryBuilder>{};
         platformBuilders = <LibraryBuilder>[];
-        dillLoadedData!.loader.builders.forEach((uri, builder) {
+        for (DillLibraryBuilder builder
+            in dillLoadedData!.loader.libraryBuilders) {
           if (builder.importUri.scheme == "dart") {
             platformBuilders!.add(builder);
           } else {
-            userBuilders![uri] = builder;
+            userBuilders![builder.importUri] = builder;
           }
-        });
+        }
         if (userBuilders!.isEmpty) {
           userBuilders = null;
         }
@@ -1518,7 +1517,7 @@
       // a new error.
       Set<LibraryBuilder> builders = {};
       SourceLoader loader = userCode!.loader;
-      for (LibraryBuilder builder in loader.builders.values) {
+      for (LibraryBuilder builder in loader.libraryBuilders) {
         if (strongModeNNBDPackageOptOutUris.contains(builder.fileUri)) {
           builders.add(builder);
         }
@@ -1634,11 +1633,11 @@
     bool removedDillBuilders = false;
     for (Uri uri in potentiallyReferencedLibraries.keys) {
       if (uri.scheme == "package") continue;
-      LibraryBuilder? builder = userCode!.loader.builders.remove(uri);
+      LibraryBuilder? builder = userCode!.loader.deregisterLibraryBuilder(uri);
       if (builder != null) {
         Library lib = builder.library;
         removedLibraries.add(lib);
-        if (dillLoadedData!.loader.builders.remove(uri) != null) {
+        if (dillLoadedData!.loader.deregisterLibraryBuilder(uri) != null) {
           removedDillBuilders = true;
         }
         cleanupSourcesForBuilder(null, builder, uriTranslator,
@@ -1666,7 +1665,7 @@
   /// This method syncs the [libraries] list with the data in [builders].
   void makeDillLoaderLibrariesUpToDateWithBuildersMap() {
     dillLoadedData!.loader.libraries.clear();
-    for (LibraryBuilder builder in dillLoadedData!.loader.builders.values) {
+    for (LibraryBuilder builder in dillLoadedData!.loader.libraryBuilders) {
       dillLoadedData!.loader.libraries.add(builder.library);
     }
   }
@@ -1695,7 +1694,7 @@
       if (userCode?.loader != null) {
         Uri? partImportUri = uriToSource[partFileUri]?.importUri;
         if (partImportUri != null &&
-            userCode!.loader.builders.containsKey(partImportUri)) {
+            userCode!.loader.containsLibraryBuilder(partImportUri)) {
           continue;
         }
       } else if (reusedResult != null) {
@@ -2201,7 +2200,9 @@
 
     if (userCode != null) {
       // userCode already contains the builders from userBuilders.
-      userCode!.loader.builders.forEach(addBuilderAndInvalidateUris);
+      for (LibraryBuilder libraryBuilder in userCode!.loader.libraryBuilders) {
+        addBuilderAndInvalidateUris(libraryBuilder.importUri, libraryBuilder);
+      }
     } else {
       // userCode was null so we explicitly have to add the builders from
       // userBuilders (which cannot be null as we checked initially that one of
@@ -2291,8 +2292,8 @@
   @override
   void invalidateAllSources() {
     if (userCode != null) {
-      Set<Uri> uris = new Set<Uri>.from(userCode!.loader.builders.keys);
-      uris.removeAll(dillLoadedData!.loader.builders.keys);
+      Set<Uri> uris = new Set<Uri>.from(userCode!.loader.libraryImportUris);
+      uris.removeAll(dillLoadedData!.loader.libraryImportUris);
       if (previousSourceBuilders != null) {
         for (Library library in previousSourceBuilders!) {
           uris.add(library.importUri);
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 452d6e7..af63914 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -1267,10 +1267,10 @@
   void ensureLoaded(Member? member) {
     if (member == null) return;
     Library ensureLibraryLoaded = member.enclosingLibrary;
-    LibraryBuilder? builder =
-        libraryBuilder.loader.builders[ensureLibraryLoaded.importUri] ??
-            libraryBuilder.loader.target.dillTarget.loader
-                .builders[ensureLibraryLoaded.importUri];
+    LibraryBuilder? builder = libraryBuilder.loader
+            .lookupLibraryBuilder(ensureLibraryLoaded.importUri) ??
+        libraryBuilder.loader.target.dillTarget.loader
+            .lookupLibraryBuilder(ensureLibraryLoaded.importUri);
     if (builder is DillLibraryBuilder) {
       builder.ensureLoaded();
     }
@@ -1285,10 +1285,10 @@
   bool isLoaded(Member? member) {
     if (member == null) return true;
     Library ensureLibraryLoaded = member.enclosingLibrary;
-    LibraryBuilder? builder =
-        libraryBuilder.loader.builders[ensureLibraryLoaded.importUri] ??
-            libraryBuilder.loader.target.dillTarget.loader
-                .builders[ensureLibraryLoaded.importUri];
+    LibraryBuilder? builder = libraryBuilder.loader
+            .lookupLibraryBuilder(ensureLibraryLoaded.importUri) ??
+        libraryBuilder.loader.target.dillTarget.loader
+            .lookupLibraryBuilder(ensureLibraryLoaded.importUri);
     if (builder is DillLibraryBuilder) {
       return builder.isBuiltAndMarked;
     }
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart
index 67be0a6..af210a0 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_constants.dart
@@ -20,9 +20,9 @@
   @override
   void report(LocatedMessage message, [List<LocatedMessage>? context]) {
     // Try to find library.
-    LibraryBuilder? builder = loader.builders[message.uri];
+    LibraryBuilder? builder = loader.lookupLibraryBuilder(message.uri!);
     if (builder == null) {
-      for (LibraryBuilder candidate in loader.builders.values) {
+      for (LibraryBuilder candidate in loader.libraryBuilders) {
         if (candidate.fileUri == message.uri) {
           // Found it.
           builder = candidate;
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index ca85431..a98493d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -401,7 +401,7 @@
       Library? referencesFrom,
       bool? referenceIsPartOwner) {
     if (dillTarget.isLoaded) {
-      DillLibraryBuilder? builder = dillTarget.loader.builders[uri];
+      DillLibraryBuilder? builder = dillTarget.loader.lookupLibraryBuilder(uri);
       if (builder != null) {
         if (!builder.isNonNullableByDefault &&
             (loader.nnbdMode == NnbdMode.Strong ||
@@ -455,7 +455,7 @@
   /// Returns classes defined in libraries in [loader].
   List<SourceClassBuilder> collectMyClasses() {
     List<SourceClassBuilder> result = <SourceClassBuilder>[];
-    for (LibraryBuilder library in loader.builders.values) {
+    for (LibraryBuilder library in loader.libraryBuilders) {
       if (library.loader == loader) {
         Iterator<Builder> iterator = library.iterator;
         while (iterator.moveNext()) {
@@ -714,7 +714,7 @@
 
   void installDefaultSupertypes() {
     Class objectClass = this.objectClass;
-    for (LibraryBuilder library in loader.builders.values) {
+    for (LibraryBuilder library in loader.libraryBuilders) {
       if (library.loader == loader) {
         Iterator<Builder> iterator = library.iterator;
         while (iterator.moveNext()) {
@@ -1086,7 +1086,7 @@
       ...backendTarget.extraIndexedLibraries
     ]) {
       Uri uri = Uri.parse(platformLibrary);
-      LibraryBuilder? libraryBuilder = loader.builders[uri];
+      LibraryBuilder? libraryBuilder = loader.lookupLibraryBuilder(uri);
       if (libraryBuilder == null) {
         // TODO(ahe): This is working around a bug in kernel_driver_test or
         // kernel_driver.
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
index 341c589..52d0a58 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
@@ -181,7 +181,8 @@
     } else if (kernelClassOrTypeDef is Typedef) {
       kernelLibrary = kernelClassOrTypeDef.enclosingLibrary;
     }
-    LibraryBuilder library = loader.builders[kernelLibrary!.importUri]!;
+    LibraryBuilder library =
+        loader.lookupLibraryBuilder(kernelLibrary!.importUri)!;
     return new NamedTypeBuilder(
         parameter.name!,
         new NullabilityBuilder.fromNullability(node.nullability),
diff --git a/pkg/front_end/lib/src/fasta/loader.dart b/pkg/front_end/lib/src/fasta/loader.dart
index 5b07db1..4173b42 100644
--- a/pkg/front_end/lib/src/fasta/loader.dart
+++ b/pkg/front_end/lib/src/fasta/loader.dart
@@ -21,7 +21,7 @@
 abstract class Loader {
   TargetImplementation get target;
 
-  Map<Uri, LibraryBuilder> get builders;
+  LibraryBuilder? lookupLibraryBuilder(Uri importUri);
 
   /// Register [message] as a problem with a severity determined by the
   /// intrinsic severity of the message.
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 19782a3..0306312 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -681,7 +681,7 @@
     if (!loader.target.uriTranslator.isLibrarySupported(dottedName)) return "";
 
     LibraryBuilder? imported =
-        loader.builders[new Uri(scheme: "dart", path: dottedName)];
+        loader.lookupLibraryBuilder(new Uri(scheme: "dart", path: dottedName));
 
     if (imported == null) {
       LibraryBuilder coreLibrary = loader.read(
@@ -689,8 +689,8 @@
               new Uri(scheme: "dart", path: "core").toString(), -1),
           -1,
           accessor: loader.first);
-      imported = coreLibrary
-          .loader.builders[new Uri(scheme: 'dart', path: dottedName)];
+      imported = coreLibrary.loader
+          .lookupLibraryBuilder(new Uri(scheme: 'dart', path: dottedName));
     }
     return imported != null && !imported.isSynthetic ? "true" : "";
   }
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 4c38811..696a640 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -141,8 +141,7 @@
 
   final SourceLoaderDataForTesting? dataForTesting;
 
-  @override
-  final Map<Uri, LibraryBuilder> builders = <Uri, LibraryBuilder>{};
+  final Map<Uri, LibraryBuilder> _builders = <Uri, LibraryBuilder>{};
 
   final Queue<LibraryBuilder> _unparsedLibraries = new Queue<LibraryBuilder>();
 
@@ -203,6 +202,32 @@
       : dataForTesting =
             retainDataForTesting ? new SourceLoaderDataForTesting() : null;
 
+  bool containsLibraryBuilder(Uri importUri) =>
+      _builders.containsKey(importUri);
+
+  @override
+  LibraryBuilder? lookupLibraryBuilder(Uri importUri) => _builders[importUri];
+
+  Iterable<LibraryBuilder> get libraryBuilders => _builders.values;
+
+  Iterable<Uri> get libraryImportUris => _builders.keys;
+
+  void registerLibraryBuilder(LibraryBuilder libraryBuilder, [Uri? uri]) {
+    uri ??= libraryBuilder.importUri;
+    if (uri.scheme == "dart" && uri.path == "core") {
+      coreLibrary = libraryBuilder;
+    }
+    _builders[uri] = libraryBuilder;
+  }
+
+  LibraryBuilder? deregisterLibraryBuilder(Uri importUri) {
+    return _builders.remove(importUri);
+  }
+
+  void clearLibraryBuilders() {
+    _builders.clear();
+  }
+
   @override
   LibraryBuilder get coreLibrary => _coreLibrary!;
 
@@ -229,7 +254,7 @@
       LibraryBuilder? origin,
       Library? referencesFrom,
       bool? referenceIsPartOwner}) {
-    LibraryBuilder builder = builders.putIfAbsent(uri, () {
+    LibraryBuilder builder = _builders.putIfAbsent(uri, () {
       if (fileUri != null &&
           (fileUri!.scheme == "dart" ||
               fileUri!.scheme == "package" ||
@@ -382,7 +407,7 @@
 
   Future<Null> buildBodies() async {
     assert(_coreLibrary != null);
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         currentUriForCrashReporting = library.importUri;
         await buildBody(library);
@@ -395,7 +420,7 @@
   void logSummary(Template<SummaryTemplate> template) {
     ticker.log((Duration elapsed, Duration sinceStart) {
       int libraryCount = 0;
-      for (LibraryBuilder library in builders.values) {
+      for (LibraryBuilder library in libraryBuilders) {
         if (library.loader == this) libraryCount++;
       }
       double ms = elapsed.inMicroseconds / Duration.microsecondsPerMillisecond;
@@ -912,7 +937,7 @@
   void resolveParts() {
     List<Uri> parts = <Uri>[];
     List<SourceLibraryBuilder> libraries = <SourceLibraryBuilder>[];
-    builders.forEach((Uri uri, LibraryBuilder library) {
+    _builders.forEach((Uri uri, LibraryBuilder library) {
       if (library.loader == this) {
         if (library.isPart) {
           parts.add(uri);
@@ -927,16 +952,17 @@
     }
     for (Uri uri in parts) {
       if (usedParts.contains(uri)) {
-        builders.remove(uri);
+        _builders.remove(uri);
       } else {
-        SourceLibraryBuilder part = builders[uri] as SourceLibraryBuilder;
+        SourceLibraryBuilder part =
+            lookupLibraryBuilder(uri) as SourceLibraryBuilder;
         part.addProblem(messagePartOrphan, 0, 1, part.fileUri);
         part.validatePart(null, null);
       }
     }
     ticker.logMs("Resolved parts");
 
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         library.applyPatches();
       }
@@ -947,7 +973,7 @@
   void computeLibraryScopes() {
     Set<LibraryBuilder> exporters = new Set<LibraryBuilder>();
     Set<LibraryBuilder> exportees = new Set<LibraryBuilder>();
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         SourceLibraryBuilder sourceLibrary = library as SourceLibraryBuilder;
         sourceLibrary.buildInitialScopes();
@@ -981,7 +1007,7 @@
         }
       }
     } while (wasChanged);
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         SourceLibraryBuilder sourceLibrary = library as SourceLibraryBuilder;
         sourceLibrary.addImportsToScope();
@@ -1000,7 +1026,7 @@
 
   void debugPrintExports() {
     // TODO(sigmund): should be `covariant SourceLibraryBuilder`.
-    builders.forEach((Uri uri, dynamic l) {
+    _builders.forEach((Uri uri, dynamic l) {
       SourceLibraryBuilder library = l;
       Set<Builder> members = new Set<Builder>();
       Iterator<Builder> iterator = library.iterator;
@@ -1024,7 +1050,7 @@
 
   void resolveTypes() {
     int typeCount = 0;
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         SourceLibraryBuilder sourceLibrary = library as SourceLibraryBuilder;
         typeCount += sourceLibrary.resolveTypes();
@@ -1035,7 +1061,7 @@
 
   void finishDeferredLoadTearoffs() {
     int count = 0;
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         count += library.finishDeferredLoadTearoffs();
       }
@@ -1045,7 +1071,7 @@
 
   void finishNoSuchMethodForwarders() {
     int count = 0;
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         count += library.finishForwarders();
       }
@@ -1055,7 +1081,7 @@
 
   void resolveConstructors() {
     int count = 0;
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         count += library.resolveConstructors(null);
       }
@@ -1065,7 +1091,7 @@
 
   void installTypedefTearOffs() {
     if (target.backendTarget.isTypedefTearOffLoweringEnabled) {
-      for (LibraryBuilder library in builders.values) {
+      for (LibraryBuilder library in libraryBuilders) {
         if (library.loader == this && library is SourceLibraryBuilder) {
           library.installTypedefTearOffs();
         }
@@ -1075,7 +1101,7 @@
 
   void finishTypeVariables(ClassBuilder object, TypeBuilder dynamicType) {
     int count = 0;
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         count += library.finishTypeVariables(object, dynamicType);
       }
@@ -1085,7 +1111,7 @@
 
   void computeVariances() {
     int count = 0;
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         count += library.computeVariances();
       }
@@ -1096,7 +1122,7 @@
   void computeDefaultTypes(TypeBuilder dynamicType, TypeBuilder nullType,
       TypeBuilder bottomType, ClassBuilder objectClass) {
     int count = 0;
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         count += library.computeDefaultTypes(
             dynamicType, nullType, bottomType, objectClass);
@@ -1107,7 +1133,7 @@
 
   void finishNativeMethods() {
     int count = 0;
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         count += library.finishNativeMethods();
       }
@@ -1117,7 +1143,7 @@
 
   void finishPatchMethods() {
     int count = 0;
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         count += library.finishPatchMethods();
       }
@@ -1156,7 +1182,7 @@
   List<SourceClassBuilder> handleHierarchyCycles(ClassBuilder objectClass) {
     // Compute the initial work list of all classes declared in this loader.
     List<SourceClassBuilder> workList = <SourceClassBuilder>[];
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         Iterator<Builder> members = library.iterator;
         while (members.moveNext()) {
@@ -1355,7 +1381,7 @@
 
   /// Builds the core AST structure needed for the outline of the component.
   void buildComponent() {
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         SourceLibraryBuilder sourceLibrary = library as SourceLibraryBuilder;
         Library target = sourceLibrary.build(coreLibrary);
@@ -1375,7 +1401,7 @@
   Component computeFullComponent() {
     Set<Library> libraries = new Set<Library>();
     List<Library> workList = <Library>[];
-    for (LibraryBuilder libraryBuilder in builders.values) {
+    for (LibraryBuilder libraryBuilder in libraryBuilders) {
       if (!libraryBuilder.isPatch &&
           (libraryBuilder.loader == this ||
               libraryBuilder.importUri.scheme == "dart" ||
@@ -1422,7 +1448,7 @@
   }
 
   void computeShowHideElements() {
-    for (LibraryBuilder libraryBuilder in builders.values) {
+    for (LibraryBuilder libraryBuilder in libraryBuilders) {
       if (libraryBuilder.loader == this &&
           libraryBuilder is SourceLibraryBuilder) {
         libraryBuilder.computeShowHideElements(_builderHierarchy!);
@@ -1470,7 +1496,7 @@
   }
 
   void checkTypes() {
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library is SourceLibraryBuilder) {
         if (library.loader == this) {
           library
@@ -1551,7 +1577,7 @@
       List<SynthesizedFunctionNode> synthesizedFunctionNodes) {
     List<DelayedActionPerformer> delayedActionPerformers =
         <DelayedActionPerformer>[];
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         (library as SourceLibraryBuilder).buildOutlineExpressions();
         Iterator<Builder> iterator = library.iterator;
@@ -1608,7 +1634,7 @@
     builderHierarchy.computeTypes();
 
     List<FieldBuilder> allImplicitlyTypedFields = <FieldBuilder>[];
-    for (LibraryBuilder library in builders.values) {
+    for (LibraryBuilder library in libraryBuilders) {
       if (library.loader == this) {
         List<FieldBuilder>? implicitlyTypedFields =
             library.takeImplicitlyTypedFields();
@@ -1704,7 +1730,7 @@
   void checkMainMethods() {
     DartType? listOfString;
 
-    for (LibraryBuilder libraryBuilder in builders.values) {
+    for (LibraryBuilder libraryBuilder in libraryBuilders) {
       if (libraryBuilder.loader == this &&
           libraryBuilder.isNonNullableByDefault) {
         Builder? mainBuilder =
@@ -1833,7 +1859,7 @@
     hierarchy = null;
     _builderHierarchy = null;
     _typeInferenceEngine = null;
-    builders.clear();
+    _builders.clear();
     libraries.clear();
     first = null;
     sourceBytes.clear();
@@ -1847,7 +1873,7 @@
   @override
   ClassBuilder computeClassBuilderFromTargetClass(Class cls) {
     Library kernelLibrary = cls.enclosingLibrary;
-    LibraryBuilder? library = builders[kernelLibrary.importUri];
+    LibraryBuilder? library = lookupLibraryBuilder(kernelLibrary.importUri);
     if (library == null) {
       return target.dillTarget.loader.computeClassBuilderFromTargetClass(cls);
     }
diff --git a/pkg/front_end/lib/src/testing/id_testing_utils.dart b/pkg/front_end/lib/src/testing/id_testing_utils.dart
index 02297a9..4c4f476 100644
--- a/pkg/front_end/lib/src/testing/id_testing_utils.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_utils.dart
@@ -124,7 +124,7 @@
     InternalCompilerResult compilerResult, Library library,
     {bool required: true}) {
   SourceLoader loader = compilerResult.kernelTargetForTesting!.loader;
-  LibraryBuilder? builder = loader.builders[library.importUri];
+  LibraryBuilder? builder = loader.lookupLibraryBuilder(library.importUri);
   if (builder == null && required) {
     throw new ArgumentError("DeclarationBuilder for $library not found.");
   }
diff --git a/pkg/front_end/test/crashing_test_case_minimizer_impl.dart b/pkg/front_end/test/crashing_test_case_minimizer_impl.dart
index e8e1ed7..dfd6efa 100644
--- a/pkg/front_end/test/crashing_test_case_minimizer_impl.dart
+++ b/pkg/front_end/test/crashing_test_case_minimizer_impl.dart
@@ -1767,7 +1767,8 @@
 
   bool _knownByCompiler(Uri uri) {
     LibraryBuilder? libraryBuilder = _latestCrashingIncrementalCompiler!
-        .userCode!.loader.builders[_getImportUri(uri)];
+        .userCode!.loader
+        .lookupLibraryBuilder(_getImportUri(uri));
     if (libraryBuilder != null) {
       return true;
     }
@@ -1785,13 +1786,14 @@
   bool _isUriNnbd(Uri uri, {bool crashOnFail: true}) {
     Uri asImportUri = _getImportUri(uri);
     LibraryBuilder? libraryBuilder = _latestCrashingIncrementalCompiler!
-        .userCode!.loader.builders[asImportUri];
+        .userCode!.loader
+        .lookupLibraryBuilder(asImportUri);
     if (libraryBuilder != null) {
       return libraryBuilder.isNonNullableByDefault;
     }
     print("Couldn't lookup $uri");
     for (LibraryBuilder libraryBuilder in _latestCrashingIncrementalCompiler!
-        .userCode!.loader.builders.values) {
+        .userCode!.loader.libraryBuilders) {
       if (libraryBuilder.importUri == uri) {
         print("Found $uri as ${libraryBuilder.importUri} (!= ${asImportUri})");
         return libraryBuilder.isNonNullableByDefault;
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index b933c35..0c88143 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -1343,7 +1343,7 @@
     // Create lookup-table from file uri to whatever.
     Map<Uri, LibraryBuilder> builders = {};
     for (LibraryBuilder builder
-        in incrementalCompiler.userCode!.loader.builders.values) {
+        in incrementalCompiler.userCode!.loader.libraryBuilders) {
       if (builder.importUri.scheme == "dart" && !builder.isSynthetic) continue;
       builders[builder.fileUri] = builder;
       for (LibraryPart part in builder.library.parts) {
diff --git a/pkg/front_end/test/incremental_suite.dart b/pkg/front_end/test/incremental_suite.dart
index 30745c3..2ce5c81 100644
--- a/pkg/front_end/test/incremental_suite.dart
+++ b/pkg/front_end/test/incremental_suite.dart
@@ -1941,7 +1941,7 @@
         .computeDelta(entryPoints: entryPoints, fullComponent: fullComponent);
 
     // We should at least have the SDK builders available. Slight smoke test.
-    if (!dillLoadedData!.loader.builders.keys
+    if (!dillLoadedData!.loader.libraryImportUris
         .map((uri) => uri.toString())
         .contains("dart:core")) {
       throw "Loaders builder should contain the sdk, "
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 44c927d..5746a68 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -317,6 +317,7 @@
 deps
 dereferenced
 dereferencing
+deregister
 descent
 deserializer
 deserializers
diff --git a/tools/VERSION b/tools/VERSION
index 87e5deb..e386a00 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 222
+PRERELEASE 223
 PRERELEASE_PATCH 0
\ No newline at end of file