Expression compilation fix

Previously, when loading from a dill file and not invalidating anything
compilation expression would fail.
This CL introduces a forced invalidation of the entrypoint when loading
for the first time, just as is done when requesting a full component.

Closes #33087.

Bug: 33087
Change-Id: I0d9b84393f3b046a0359e3a94bb1bcb8ab650308
Reviewed-on: https://dart-review.googlesource.com/61920
Reviewed-by: Kevin Millikin <kmillikin@google.com>
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index a1382d0..4bdff1a 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -171,7 +171,7 @@
       }
 
       Set<Uri> invalidatedUris = this.invalidatedUris.toSet();
-      if (fullComponent) {
+      if (data.includeUserLoadedLibraries || fullComponent) {
         invalidatedUris.add(entryPoint);
       }
 
diff --git a/pkg/front_end/test/fasta/expression_test.dart b/pkg/front_end/test/fasta/expression_test.dart
index 91f716e..b2b315c 100644
--- a/pkg/front_end/test/fasta/expression_test.dart
+++ b/pkg/front_end/test/fasta/expression_test.dart
@@ -298,6 +298,8 @@
       File dillFile = new File.fromUri(dillFileUri);
       if (!await dillFile.exists()) {
         await writeComponentToFile(component, dillFileUri);
+        context.fileSystem.entityForUri(dillFileUri).writeAsBytesSync(
+            await new File.fromUri(dillFileUri).readAsBytes());
       }
 
       var dillCompiler =
diff --git a/pkg/front_end/test/incremental_load_from_dill_test.dart b/pkg/front_end/test/incremental_load_from_dill_test.dart
index 4adb1d6..45c3553 100644
--- a/pkg/front_end/test/incremental_load_from_dill_test.dart
+++ b/pkg/front_end/test/incremental_load_from_dill_test.dart
@@ -256,9 +256,12 @@
       compiler = new TestIncrementalCompiler(options, entry, initializeFrom);
     }
 
+    List<Uri> invalidated = new List<Uri>();
     if (world["invalidate"] != null) {
       for (String filename in world["invalidate"]) {
-        compiler.invalidate(base.resolve(filename));
+        Uri uri = base.resolve(filename);
+        invalidated.add(uri);
+        compiler.invalidate(uri);
       }
     }
 
@@ -283,18 +286,20 @@
           "$expectInitializeFromDill but was ${compiler.initializedFromDill}";
     }
     if (world["checkInvalidatedFiles"] != false) {
+      Set<Uri> filteredInvalidated =
+          compiler.getFilteredInvalidatedImportUrisForTesting(invalidated);
       if (world["invalidate"] != null) {
-        Expect.equals(world["invalidate"].length,
-            compiler.invalidatedImportUrisForTesting?.length ?? 0);
+        Expect.equals(
+            world["invalidate"].length, filteredInvalidated?.length ?? 0);
         List expectedInvalidatedUri = world["expectedInvalidatedUri"];
         if (expectedInvalidatedUri != null) {
           Expect.setEquals(
               expectedInvalidatedUri
                   .map((s) => Uri.parse(substituteVariables(s, base))),
-              compiler.invalidatedImportUrisForTesting);
+              filteredInvalidated);
         }
       } else {
-        Expect.isNull(compiler.invalidatedImportUrisForTesting);
+        Expect.isNull(filteredInvalidated);
         Expect.isNull(world["expectedInvalidatedUri"]);
       }
     }
@@ -389,8 +394,10 @@
   bool result = compiler.initializedFromDill;
   new File.fromUri(output)
       .writeAsBytesSync(util.postProcess(initializedComponent));
-  int actuallyInvalidatedCount =
-      compiler.invalidatedImportUrisForTesting?.length ?? 0;
+  int actuallyInvalidatedCount = compiler
+          .getFilteredInvalidatedImportUrisForTesting(invalidateUris)
+          ?.length ??
+      0;
   if (result && actuallyInvalidatedCount < invalidateUris.length) {
     Expect.fail("Expected at least ${invalidateUris.length} invalidated uris, "
         "got $actuallyInvalidatedCount");
@@ -410,8 +417,10 @@
 
   Component partialComponent = await compiler.computeDelta();
   util.throwOnEmptyMixinBodies(partialComponent);
-  actuallyInvalidatedCount =
-      (compiler.invalidatedImportUrisForTesting?.length ?? 0);
+  actuallyInvalidatedCount = (compiler
+          .getFilteredInvalidatedImportUrisForTesting(invalidateUris)
+          ?.length ??
+      0);
   if (actuallyInvalidatedCount < invalidateUris.length) {
     Expect.fail("Expected at least ${invalidateUris.length} invalidated uris, "
         "got $actuallyInvalidatedCount");
@@ -442,8 +451,28 @@
 
 class TestIncrementalCompiler extends IncrementalCompiler {
   Set<Uri> invalidatedImportUrisForTesting;
+  final Uri entryPoint;
 
-  TestIncrementalCompiler(CompilerOptions options, Uri entryPoint,
+  /// Filter out the automatically added entryPoint, unless it's explicitly
+  /// specified as being invalidated.
+  /// This is not perfect, but works for what it's currently used for.
+  Set<Uri> getFilteredInvalidatedImportUrisForTesting(
+      List<Uri> invalidatedUris) {
+    if (invalidatedImportUrisForTesting == null) return null;
+    Set<String> invalidatedFilenames =
+        invalidatedUris.map((uri) => uri.pathSegments.last).toSet();
+    if (invalidatedFilenames.contains(entryPoint.pathSegments.last)) {
+      return invalidatedImportUrisForTesting;
+    }
+
+    Set<Uri> result = new Set<Uri>();
+    for (Uri uri in invalidatedImportUrisForTesting) {
+      if (invalidatedFilenames.contains(uri.pathSegments.last)) result.add(uri);
+    }
+    return result;
+  }
+
+  TestIncrementalCompiler(CompilerOptions options, this.entryPoint,
       [Uri initializeFrom])
       : super(new CompilerContext(new ProcessedOptions(options, [entryPoint])),
             initializeFrom);