Version 2.16.0-114.0.dev

Merge commit 'f9939de8b803622de7276a709ed3e18545196949' into 'dev'
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index a95dd25..31d90c59 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -754,9 +754,8 @@
         new Map<LibraryBuilder, List<LibraryBuilder>>.identity();
     if (experimentalInvalidation != null) {
       for (LibraryBuilder library in experimentalInvalidation.rebuildBodies) {
-        LibraryBuilder newBuilder = currentKernelTarget.loader.read(
-            library.importUri, -1,
-            accessorUri: currentKernelTarget.loader.firstUri,
+        LibraryBuilder newBuilder = currentKernelTarget.loader.readAsEntryPoint(
+            library.importUri,
             fileUri: library.fileUri,
             referencesFrom: library.library);
         List<LibraryBuilder> builders = [newBuilder];
@@ -1661,9 +1660,8 @@
     assert(_dillLoadedData != null && lastGoodKernelTarget != null);
 
     return await context.runInContext((_) async {
-      LibraryBuilder libraryBuilder = lastGoodKernelTarget!.loader.read(
-          libraryUri, -1,
-          accessorUri: lastGoodKernelTarget.loader.firstUri);
+      LibraryBuilder libraryBuilder =
+          lastGoodKernelTarget!.loader.readAsEntryPoint(libraryUri);
       _ticker.logMs("Loaded library $libraryUri");
 
       Class? cls;
@@ -2579,9 +2577,11 @@
       for (String jsonString in problemsAsJson) {
         DiagnosticMessageFromJson message =
             new DiagnosticMessageFromJson.fromJson(jsonString);
-        assert(message.uri != null ||
-            (message.involvedFiles != null &&
-                message.involvedFiles!.isNotEmpty));
+        assert(
+            message.uri != null ||
+                (message.involvedFiles != null &&
+                    message.involvedFiles!.isNotEmpty),
+            jsonString);
         if (message.uri != null) {
           List<DiagnosticMessageFromJson> messages =
               _remainingComponentProblems[message.uri!] ??=
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 031764f0..27f8d35 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -315,8 +315,7 @@
       Uri translatedEntryPoint =
           getEntryPointUri(entryPoint, issueProblem: true);
       result.add(translatedEntryPoint);
-      loader.read(translatedEntryPoint, -1,
-          accessorUri: loader.firstUri,
+      loader.readAsEntryPoint(translatedEntryPoint,
           fileUri: translatedEntryPoint != entryPoint ? entryPoint : null);
     }
     return result;
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 10714d1..b8b0563 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
@@ -738,11 +738,10 @@
         loader.lookupLibraryBuilder(new Uri(scheme: "dart", path: dottedName));
 
     if (imported == null) {
-      LibraryBuilder coreLibrary = loader.read(
-          resolve(this.importUri,
-              new Uri(scheme: "dart", path: "core").toString(), -1),
-          -1,
-          accessorUri: loader.firstUri);
+      LibraryBuilder coreLibrary = loader.readAsEntryPoint(resolve(
+          this.importUri,
+          new Uri(scheme: "dart", path: "core").toString(),
+          -1));
       imported = coreLibrary.loader
           .lookupLibraryBuilder(new Uri(scheme: 'dart', path: dottedName));
     }
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 eeb3f6f..4ec6c32 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -504,8 +504,68 @@
   /// compile-time error.
   LibraryBuilder read(Uri uri, int charOffset,
       {Uri? fileUri,
-      LibraryBuilder? accessor,
-      Uri? accessorUri,
+      required LibraryBuilder accessor,
+      LibraryBuilder? origin,
+      Library? referencesFrom,
+      bool? referenceIsPartOwner}) {
+    LibraryBuilder libraryBuilder = _read(uri,
+        fileUri: fileUri,
+        origin: origin,
+        referencesFrom: referencesFrom,
+        referenceIsPartOwner: referenceIsPartOwner);
+    libraryBuilder.recordAccess(charOffset, noLength, accessor.fileUri);
+    if (!_hasLibraryAccess(imported: uri, importer: accessor.importUri) &&
+        !accessor.isPatch) {
+      accessor.addProblem(messagePlatformPrivateLibraryAccess, charOffset,
+          noLength, accessor.fileUri);
+    }
+    return libraryBuilder;
+  }
+
+  /// Reads the library [uri] as an entry point. This is used for reading the
+  /// entry point library of a script or the explicitly mention libraries of
+  /// a modular or incremental compilation.
+  ///
+  /// This differs from [read] in that there is no accessor library, meaning
+  /// that access to platform private libraries cannot be granted.
+  LibraryBuilder readAsEntryPoint(Uri uri,
+      {Uri? fileUri, Library? referencesFrom}) {
+    LibraryBuilder libraryBuilder =
+        _read(uri, fileUri: fileUri, referencesFrom: referencesFrom);
+    // TODO(johnniwinther): Avoid using the first library, if present, as the
+    // accessor of [libraryBuilder]. Currently the incremental compiler doesn't
+    // handle errors reported without an accessor, since the messages are not
+    // associated with a library. This currently has the side effect that
+    // the first library is the accessor of itself.
+    LibraryBuilder? firstLibrary = first;
+    if (firstLibrary != null) {
+      libraryBuilder.recordAccess(-1, noLength, firstLibrary.fileUri);
+    }
+    if (!_hasLibraryAccess(imported: uri, importer: firstLibrary?.importUri)) {
+      if (firstLibrary != null) {
+        firstLibrary.addProblem(
+            messagePlatformPrivateLibraryAccess, -1, noLength, firstUri);
+      } else {
+        addProblem(messagePlatformPrivateLibraryAccess, -1, noLength, null);
+      }
+    }
+    return libraryBuilder;
+  }
+
+  bool _hasLibraryAccess({required Uri imported, required Uri? importer}) {
+    if (imported.scheme == "dart" && imported.path.startsWith("_")) {
+      if (importer == null) {
+        return false;
+      } else {
+        return target.backendTarget
+            .allowPlatformPrivateLibraryAccess(importer, imported);
+      }
+    }
+    return true;
+  }
+
+  LibraryBuilder _read(Uri uri,
+      {Uri? fileUri,
       LibraryBuilder? origin,
       Library? referencesFrom,
       bool? referenceIsPartOwner}) {
@@ -522,33 +582,18 @@
             referencesFrom,
             referenceIsPartOwner);
       }
-
       _builders[uri] = libraryBuilder;
     }
-    accessor ??= _builders[accessorUri];
-    if (accessor == null) {
-      // TODO(johnniwinther): Separate reading of imports/exports/parts from
-      // reading entry points.
-    } else {
-      libraryBuilder.recordAccess(charOffset, noLength, accessor.fileUri);
-      if (!accessor.isPatch &&
-          !accessor.isPart &&
-          !target.backendTarget
-              .allowPlatformPrivateLibraryAccess(accessor.importUri, uri)) {
-        accessor.addProblem(messagePlatformPrivateLibraryAccess, charOffset,
-            noLength, accessor.fileUri);
-      }
-    }
     return libraryBuilder;
   }
 
   void _ensureCoreLibrary() {
     if (_coreLibrary == null) {
-      read(Uri.parse("dart:core"), 0, accessorUri: firstUri);
+      readAsEntryPoint(Uri.parse("dart:core"));
       // TODO(askesc): When all backends support set literals, we no longer
       // need to index dart:collection, as it is only needed for desugaring of
       // const sets. We can remove it from this list at that time.
-      read(Uri.parse("dart:collection"), 0, accessorUri: firstUri);
+      readAsEntryPoint(Uri.parse("dart:collection"));
       assert(_coreLibrary != null);
     }
   }
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 9b57834..a132ce2 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -339,6 +339,7 @@
 dev
 device
 diff
+differs
 diffs
 digest
 digests
@@ -531,6 +532,7 @@
 goto
 gotos
 gradually
+granted
 graphs
 growability
 gt
diff --git a/pkg/front_end/testcases/incremental/change_main2.yaml b/pkg/front_end/testcases/incremental/change_main2.yaml
new file mode 100644
index 0000000..1ceabb1
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/change_main2.yaml
@@ -0,0 +1,45 @@
+# 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.md file.
+
+type: newworld
+worlds:
+  - entry: first.dart
+    experiments: alternative-invalidation-strategy
+    sources:
+      first.dart: |
+        import 'second.dart';
+
+        main() {
+          method1();
+          method2();
+        }
+        method1() {}
+      second.dart: |
+        import 'first.dart';
+
+        main() {
+          method1();
+          method2();
+        }
+        method2() {}
+    expectedLibraryCount: 2
+  - entry: second.dart
+    experiments: alternative-invalidation-strategy
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - second.dart
+    sources:
+      second.dart: |
+        import 'first.dart';
+
+        main() {
+          method1();
+          method2();
+        }
+        method2() {
+          print('method2');
+        }
+    expectedLibraryCount: 2
+    expectsRebuildBodiesOnly: true
diff --git a/pkg/front_end/testcases/incremental/change_main2.yaml.world.1.expect b/pkg/front_end/testcases/incremental/change_main2.yaml.world.1.expect
new file mode 100644
index 0000000..1e283df
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/change_main2.yaml.world.1.expect
@@ -0,0 +1,21 @@
+main = fir::main;
+library from "org-dartlang-test:///first.dart" as fir {
+
+  import "org-dartlang-test:///second.dart";
+
+  static method main() → dynamic {
+    fir::method1();
+    sec::method2();
+  }
+  static method method1() → dynamic {}
+}
+library from "org-dartlang-test:///second.dart" as sec {
+
+  import "org-dartlang-test:///first.dart";
+
+  static method main() → dynamic {
+    fir::method1();
+    sec::method2();
+  }
+  static method method2() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental/change_main2.yaml.world.2.expect b/pkg/front_end/testcases/incremental/change_main2.yaml.world.2.expect
new file mode 100644
index 0000000..d55656f
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/change_main2.yaml.world.2.expect
@@ -0,0 +1,23 @@
+main = sec::main;
+library from "org-dartlang-test:///first.dart" as fir {
+
+  import "org-dartlang-test:///second.dart";
+
+  static method main() → dynamic {
+    fir::method1();
+    sec::method2();
+  }
+  static method method1() → dynamic {}
+}
+library from "org-dartlang-test:///second.dart" as sec {
+
+  import "org-dartlang-test:///first.dart";
+
+  static method main() → dynamic {
+    fir::method1();
+    sec::method2();
+  }
+  static method method2() → dynamic {
+    dart.core::print("method2");
+  }
+}
diff --git a/pkg/front_end/testcases/incremental/part_main.yaml b/pkg/front_end/testcases/incremental/part_main.yaml
new file mode 100644
index 0000000..fc73d0d
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/part_main.yaml
@@ -0,0 +1,53 @@
+# Copyright (c) 2019, 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.md file.
+
+# Compile an application, change a file, but don't change the outline.
+
+type: newworld
+worlds:
+  - entry: first.dart
+    experiments: alternative-invalidation-strategy
+    sources:
+      first.dart: |
+        library first;
+
+        part 'second.dart';
+
+        main() {
+          method1();
+          method2();
+        }
+        method1() {}
+      second.dart: |
+        part of first;
+
+        method2() {}
+    expectedLibraryCount: 1
+  - entry: first.dart
+    experiments: alternative-invalidation-strategy
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      [second.dart, first.dart]
+    sources:
+      first.dart: |
+        library first;
+
+        part 'second.dart';
+
+        main() {
+          method1();
+          method2();
+        }
+        method1() {
+          print('method1');
+        }
+      second.dart: |
+        part of first;
+
+        method2() {
+          print('method2');
+        }
+    expectedLibraryCount: 1
+    expectsRebuildBodiesOnly: true
diff --git a/pkg/front_end/testcases/incremental/part_main.yaml.world.1.expect b/pkg/front_end/testcases/incremental/part_main.yaml.world.1.expect
new file mode 100644
index 0000000..547dc7c
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/part_main.yaml.world.1.expect
@@ -0,0 +1,11 @@
+main = fir::main;
+library first from "org-dartlang-test:///first.dart" as fir {
+
+  part second.dart;
+  static method main() → dynamic {
+    fir::method1();
+    fir::method2();
+  }
+  static method method1() → dynamic {}
+  static method /* from org-dartlang-test:///second.dart */ method2() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental/part_main.yaml.world.2.expect b/pkg/front_end/testcases/incremental/part_main.yaml.world.2.expect
new file mode 100644
index 0000000..8cd5855
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/part_main.yaml.world.2.expect
@@ -0,0 +1,15 @@
+main = fir::main;
+library first from "org-dartlang-test:///first.dart" as fir {
+
+  part second.dart;
+  static method main() → dynamic {
+    fir::method1();
+    fir::method2();
+  }
+  static method method1() → dynamic {
+    dart.core::print("method1");
+  }
+  static method /* from org-dartlang-test:///second.dart */ method2() → dynamic {
+    dart.core::print("method2");
+  }
+}
diff --git a/pkg/front_end/testcases/incremental/second_first.yaml b/pkg/front_end/testcases/incremental/second_first.yaml
new file mode 100644
index 0000000..80faceb
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/second_first.yaml
@@ -0,0 +1,43 @@
+# 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.md file.
+
+type: newworld
+worlds:
+  - entry: first.dart
+    experiments: alternative-invalidation-strategy
+    sources:
+      first.dart: |
+        import 'second.dart';
+
+        main() {
+          method1();
+          method2();
+        }
+        method1() {}
+      second.dart: |
+        method2() {}
+    expectedLibraryCount: 2
+  - entry: first.dart
+    experiments: alternative-invalidation-strategy
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+        [second.dart, first.dart]
+    sources:
+      first.dart: |
+        import 'second.dart';
+
+        main() {
+          method1();
+          method2();
+        }
+        method1() {
+          print('method1');
+        }
+      second.dart: |
+        method2() {
+          print('method2');
+        }
+    expectedLibraryCount: 2
+    expectsRebuildBodiesOnly: true
diff --git a/pkg/front_end/testcases/incremental/second_first.yaml.world.1.expect b/pkg/front_end/testcases/incremental/second_first.yaml.world.1.expect
new file mode 100644
index 0000000..b38f4b8
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/second_first.yaml.world.1.expect
@@ -0,0 +1,15 @@
+main = fir::main;
+library from "org-dartlang-test:///first.dart" as fir {
+
+  import "org-dartlang-test:///second.dart";
+
+  static method main() → dynamic {
+    fir::method1();
+    sec::method2();
+  }
+  static method method1() → dynamic {}
+}
+library from "org-dartlang-test:///second.dart" as sec {
+
+  static method method2() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental/second_first.yaml.world.2.expect b/pkg/front_end/testcases/incremental/second_first.yaml.world.2.expect
new file mode 100644
index 0000000..0b236b5
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/second_first.yaml.world.2.expect
@@ -0,0 +1,19 @@
+main = fir::main;
+library from "org-dartlang-test:///first.dart" as fir {
+
+  import "org-dartlang-test:///second.dart";
+
+  static method main() → dynamic {
+    fir::method1();
+    sec::method2();
+  }
+  static method method1() → dynamic {
+    dart.core::print("method1");
+  }
+}
+library from "org-dartlang-test:///second.dart" as sec {
+
+  static method method2() → dynamic {
+    dart.core::print("method2");
+  }
+}
diff --git a/pkg/front_end/tool/dart_doctest_impl.dart b/pkg/front_end/tool/dart_doctest_impl.dart
index 9be9af8..b03351a 100644
--- a/pkg/front_end/tool/dart_doctest_impl.dart
+++ b/pkg/front_end/tool/dart_doctest_impl.dart
@@ -800,9 +800,8 @@
     assert(dillTargetForTesting != null && kernelTargetForTesting != null);
 
     return await context.runInContext((_) async {
-      LibraryBuilder libraryBuilder = kernelTargetForTesting!.loader.read(
-          libraryUri, -1,
-          accessorUri: kernelTargetForTesting!.loader.firstUri);
+      LibraryBuilder libraryBuilder =
+          kernelTargetForTesting!.loader.readAsEntryPoint(libraryUri);
 
       kernelTargetForTesting!.loader.resetSeenMessages();
 
diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart
index 14f30a3..804f26a 100644
--- a/pkg/kernel/lib/target/targets.dart
+++ b/pkg/kernel/lib/target/targets.dart
@@ -268,13 +268,12 @@
   bool mayDefineRestrictedType(Uri uri) =>
       uri.isScheme('dart') && (uri.path == 'core' || uri.path == 'typed_data');
 
-  /// Whether a library is allowed to import a platform private library.
+  /// Whether a library is allowed to import the platform private library
+  /// [imported] from library [importer].
   ///
   /// By default only `dart:*` libraries are allowed. May be overridden for
   /// testing purposes.
   bool allowPlatformPrivateLibraryAccess(Uri importer, Uri imported) =>
-      imported.scheme != "dart" ||
-      !imported.path.startsWith("_") ||
       importer.scheme == "dart" ||
       (importer.scheme == "package" &&
           importer.path.startsWith("dart_internal/"));
diff --git a/runtime/platform/assert.h b/runtime/platform/assert.h
index b021375..53079e3 100644
--- a/runtime/platform/assert.h
+++ b/runtime/platform/assert.h
@@ -140,19 +140,19 @@
        tols.c_str());
 }
 
-static void Escape(std::ostringstream& dst, const char* src) {
+static void Escape(std::string& dst, const char* src) {
   char c;
   while ((c = *src++) != '\0') {
     if (c == '\n') {
-      dst << "\\n\"\n\"";
+      dst += "\\n\"\n\"";
     } else if (c == '\'') {
-      dst << "\\\'";
+      dst += "\\\'";
     } else if (c == '\"') {
-      dst << "\\\"";
+      dst += "\\\"";
     } else if (c == '\\') {
-      dst << "\\\\";
+      dst += "\\\\";
     } else {
-      dst << c;
+      dst += c;
     }
   }
 }
@@ -163,10 +163,9 @@
     Fail("expected:\n<\"%s\">\nbut was nullptr", expected);
   } else {
     if (strcmp(expected, actual) == 0) return;
-    std::ostringstream ess, ass;
-    Escape(ess, expected);
-    Escape(ass, actual);
-    std::string es = ess.str(), as = ass.str();
+    std::string es, as;
+    Escape(es, expected);
+    Escape(as, actual);
     Fail("expected:\n<\"%s\">\nbut was:\n<\"%s\">", es.c_str(), as.c_str());
   }
 }
diff --git a/tools/VERSION b/tools/VERSION
index 8e8f9ce..49eda3a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 16
 PATCH 0
-PRERELEASE 113
+PRERELEASE 114
 PRERELEASE_PATCH 0
\ No newline at end of file