[CFE] Incremental compiler and part as entry
This CL fixes the incremental compiler in the case where it gets a
part as an entry point.
Change-Id: I79f1735e0056f259500e2ef52d9b23047f2b812f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/178999
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Johnni Winther <johnniwinther@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 b3acb30..e629ce0 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -230,7 +230,19 @@
Set<Uri> invalidatedUris = this.invalidatedUris.toSet();
invalidateNotKeptUserBuilders(invalidatedUris);
ReusageResult reusedResult =
- computeReusedLibraries(invalidatedUris, uriTranslator);
+ computeReusedLibraries(invalidatedUris, uriTranslator, entryPoints);
+
+ // Use the reused libraries to re-write entry-points.
+ if (reusedResult.arePartsUsedAsEntryPoints()) {
+ for (int i = 0; i < entryPoints.length; i++) {
+ Uri entryPoint = entryPoints[i];
+ Uri redirect =
+ reusedResult.getLibraryUriForPartUsedAsEntryPoint(entryPoint);
+ if (redirect != null) {
+ entryPoints[i] = redirect;
+ }
+ }
+ }
// Experimental invalidation initialization (e.g. figure out if we can).
ExperimentalInvalidation experimentalInvalidation =
@@ -1440,18 +1452,26 @@
/// any saved component problems for such builders.
List<Library> computeTransitiveClosure(
List<Library> inputLibraries,
- List<Uri> entries,
+ List<Uri> entryPoints,
List<LibraryBuilder> reusedLibraries,
ClassHierarchy hierarchy,
UriTranslator uriTranslator,
Map<Uri, Source> uriToSource,
[List<Library> inputLibrariesFiltered]) {
List<Library> result = <Library>[];
+ Map<Uri, Uri> partUriToLibraryImportUri = <Uri, Uri>{};
Map<Uri, Library> libraryMap = <Uri, Library>{};
Map<Uri, Library> potentiallyReferencedLibraries = <Uri, Library>{};
Map<Uri, Library> potentiallyReferencedInputLibraries = <Uri, Library>{};
for (Library library in inputLibraries) {
libraryMap[library.importUri] = library;
+ if (library.parts.isNotEmpty) {
+ for (int partIndex = 0; partIndex < library.parts.length; partIndex++) {
+ LibraryPart part = library.parts[partIndex];
+ Uri partUri = getPartUri(library.importUri, part);
+ partUriToLibraryImportUri[partUri] = library.importUri;
+ }
+ }
if (library.importUri.scheme == "dart") {
result.add(library);
inputLibrariesFiltered?.add(library);
@@ -1460,9 +1480,6 @@
potentiallyReferencedInputLibraries[library.importUri] = library;
}
}
-
- List<Uri> worklist = <Uri>[];
- worklist.addAll(entries);
for (LibraryBuilder libraryBuilder in reusedLibraries) {
if (libraryBuilder.importUri.scheme == "dart" &&
!libraryBuilder.isSynthetic) {
@@ -1473,6 +1490,19 @@
libraryMap[libraryBuilder.importUri] = lib;
}
+ List<Uri> worklist = <Uri>[];
+ for (Uri entry in entryPoints) {
+ if (libraryMap.containsKey(entry)) {
+ worklist.add(entry);
+ } else {
+ // If the entry is a part redirect to the "main" entry.
+ Uri partTranslation = partUriToLibraryImportUri[entry];
+ if (partTranslation != null) {
+ worklist.add(partTranslation);
+ }
+ }
+ }
+
LibraryGraph graph = new LibraryGraph(libraryMap);
Set<Uri> partsUsed = new Set<Uri>();
while (worklist.isNotEmpty && potentiallyReferencedLibraries.isNotEmpty) {
@@ -1928,8 +1958,8 @@
}
/// Internal method.
- ReusageResult computeReusedLibraries(
- Set<Uri> invalidatedUris, UriTranslator uriTranslator) {
+ ReusageResult computeReusedLibraries(Set<Uri> invalidatedUris,
+ UriTranslator uriTranslator, List<Uri> entryPoints) {
Set<Uri> seenUris = new Set<Uri>();
List<LibraryBuilder> reusedLibraries = <LibraryBuilder>[];
for (int i = 0; i < platformBuilders.length; i++) {
@@ -1938,7 +1968,7 @@
reusedLibraries.add(builder);
}
if (userCode == null && userBuilders == null) {
- return new ReusageResult(const {}, const {}, false, reusedLibraries);
+ return new ReusageResult.reusedLibrariesOnly(reusedLibraries);
}
bool invalidatedBecauseOfPackageUpdate = false;
Set<LibraryBuilder> directlyInvalidated = new Set<LibraryBuilder>();
@@ -1946,6 +1976,7 @@
// Maps all non-platform LibraryBuilders from their import URI.
Map<Uri, LibraryBuilder> builders = <Uri, LibraryBuilder>{};
+ Map<Uri, LibraryBuilder> partUriToParent = <Uri, LibraryBuilder>{};
// Invalidated URIs translated back to their import URI (package:, dart:,
// etc.).
@@ -1989,7 +2020,10 @@
invalidatedImportUris.add(uri);
}
if (libraryBuilder is SourceLibraryBuilder) {
+ // TODO(jensj): This shouldn't be possible anymore.
for (LibraryBuilder part in libraryBuilder.parts) {
+ partUriToParent[part.importUri] = libraryBuilder;
+ partUriToParent[part.fileUri] = libraryBuilder;
if (isInvalidated(part.importUri, part.fileUri)) {
invalidatedImportUris.add(part.importUri);
builders[part.importUri] = part;
@@ -2000,6 +2034,8 @@
Uri partUri = getPartUri(libraryBuilder.importUri, part);
Uri fileUri = getPartFileUri(
libraryBuilder.library.fileUri, part, uriTranslator);
+ partUriToParent[partUri] = libraryBuilder;
+ partUriToParent[fileUri] = libraryBuilder;
if (isInvalidated(partUri, fileUri)) {
invalidatedImportUris.add(partUri);
@@ -2078,8 +2114,21 @@
reusedLibraries.add(builder);
}
- return new ReusageResult(notReusedLibraries, directlyInvalidated,
- invalidatedBecauseOfPackageUpdate, reusedLibraries);
+ ReusageResult result = new ReusageResult(
+ notReusedLibraries,
+ directlyInvalidated,
+ invalidatedBecauseOfPackageUpdate,
+ reusedLibraries);
+
+ for (Uri entryPoint in entryPoints) {
+ LibraryBuilder parent = partUriToParent[entryPoint];
+ if (reusedLibraries.contains(parent)) {
+ result.registerLibraryUriForPartUsedAsEntryPoint(
+ entryPoint, parent.importUri);
+ }
+ }
+
+ return result;
}
@override
@@ -2153,13 +2202,32 @@
final Set<LibraryBuilder> directlyInvalidated;
final bool invalidatedBecauseOfPackageUpdate;
final List<LibraryBuilder> reusedLibraries;
+ final Map<Uri, Uri> _reusedLibrariesPartsToParentForEntryPoints;
+
+ ReusageResult.reusedLibrariesOnly(this.reusedLibraries)
+ : notReusedLibraries = const {},
+ directlyInvalidated = const {},
+ invalidatedBecauseOfPackageUpdate = false,
+ _reusedLibrariesPartsToParentForEntryPoints = const {};
ReusageResult(this.notReusedLibraries, this.directlyInvalidated,
this.invalidatedBecauseOfPackageUpdate, this.reusedLibraries)
- : assert(notReusedLibraries != null),
+ : _reusedLibrariesPartsToParentForEntryPoints = {},
+ assert(notReusedLibraries != null),
assert(directlyInvalidated != null),
assert(invalidatedBecauseOfPackageUpdate != null),
assert(reusedLibraries != null);
+
+ void registerLibraryUriForPartUsedAsEntryPoint(
+ Uri entryPoint, Uri importUri) {
+ _reusedLibrariesPartsToParentForEntryPoints[entryPoint] = importUri;
+ }
+
+ bool arePartsUsedAsEntryPoints() =>
+ _reusedLibrariesPartsToParentForEntryPoints.isNotEmpty;
+
+ Uri getLibraryUriForPartUsedAsEntryPoint(Uri entryPoint) =>
+ _reusedLibrariesPartsToParentForEntryPoints[entryPoint];
}
class ExperimentalInvalidation {
diff --git a/pkg/front_end/test/incremental_load_from_dill_suite.dart b/pkg/front_end/test/incremental_load_from_dill_suite.dart
index 70a5360..84c74bc 100644
--- a/pkg/front_end/test/incremental_load_from_dill_suite.dart
+++ b/pkg/front_end/test/incremental_load_from_dill_suite.dart
@@ -831,18 +831,20 @@
}
if (!noFullComponent) {
- List<Library> entryLib = component.libraries
- .where((Library lib) =>
- entries.contains(lib.importUri) ||
- entries.contains(lib.fileUri))
- .toList();
- if (entryLib.length != entries.length) {
- return new Result<TestData>(
- data,
- UnexpectedEntryToLibraryCount,
- "Expected the entries to become libraries. "
- "Got ${entryLib.length} libraries for the expected "
- "${entries.length} entries.");
+ if (world["checkEntries"] != false) {
+ List<Library> entryLib = component.libraries
+ .where((Library lib) =>
+ entries.contains(lib.importUri) ||
+ entries.contains(lib.fileUri))
+ .toList();
+ if (entryLib.length != entries.length) {
+ return new Result<TestData>(
+ data,
+ UnexpectedEntryToLibraryCount,
+ "Expected the entries to become libraries. "
+ "Got ${entryLib.length} libraries for the expected "
+ "${entries.length} entries.");
+ }
}
}
if (compiler.initializedFromDill != expectInitializeFromDill) {
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml
new file mode 100644
index 0000000..aba97dff
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml
@@ -0,0 +1,32 @@
+# 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: main.dart
+ checkEntries: false
+ sources:
+ main.dart: |
+ part of 'lib.dart';
+ partMethod() {}
+ lib.dart: |
+ part 'main.dart';
+ main() {}
+ expectedLibraryCount: 1
+
+ - entry: main.dart
+ checkEntries: false
+ worldType: updated
+ expectInitializeFromDill: false
+ invalidate:
+ - main.dart
+ expectedLibraryCount: 1
+
+ - entry: main.dart
+ checkEntries: false
+ worldType: updated
+ expectInitializeFromDill: false
+ invalidate:
+ - lib.dart
+ expectedLibraryCount: 1
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.1.expect
new file mode 100644
index 0000000..1d3c1ac
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.1.expect
@@ -0,0 +1,7 @@
+main = lib::main;
+library from "org-dartlang-test:///lib.dart" as lib {
+
+ part main.dart;
+ static method main() → dynamic {}
+ static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.2.expect
new file mode 100644
index 0000000..1d3c1ac
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.2.expect
@@ -0,0 +1,7 @@
+main = lib::main;
+library from "org-dartlang-test:///lib.dart" as lib {
+
+ part main.dart;
+ static method main() → dynamic {}
+ static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.3.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.3.expect
new file mode 100644
index 0000000..1d3c1ac
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_entry.yaml.world.3.expect
@@ -0,0 +1,7 @@
+main = lib::main;
+library from "org-dartlang-test:///lib.dart" as lib {
+
+ part main.dart;
+ static method main() → dynamic {}
+ static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml
new file mode 100644
index 0000000..e599398
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml
@@ -0,0 +1,34 @@
+# 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: package:foo/main.dart
+ checkEntries: false
+ sources:
+ .packages: |
+ foo:.
+ main.dart: |
+ part of 'lib.dart';
+ partMethod() {}
+ lib.dart: |
+ part 'main.dart';
+ main() {}
+ expectedLibraryCount: 1
+
+ - entry: package:foo/main.dart
+ checkEntries: false
+ worldType: updated
+ expectInitializeFromDill: false
+ invalidate:
+ - main.dart
+ expectedLibraryCount: 1
+
+ - entry: package:foo/main.dart
+ checkEntries: false
+ worldType: updated
+ expectInitializeFromDill: false
+ invalidate:
+ - lib.dart
+ expectedLibraryCount: 1
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.1.expect
new file mode 100644
index 0000000..c9c3c86
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.1.expect
@@ -0,0 +1,7 @@
+main = lib::main;
+library from "package:foo/lib.dart" as lib {
+
+ part main.dart;
+ static method main() → dynamic {}
+ static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.2.expect
new file mode 100644
index 0000000..c9c3c86
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.2.expect
@@ -0,0 +1,7 @@
+main = lib::main;
+library from "package:foo/lib.dart" as lib {
+
+ part main.dart;
+ static method main() → dynamic {}
+ static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.3.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.3.expect
new file mode 100644
index 0000000..c9c3c86
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry.yaml.world.3.expect
@@ -0,0 +1,7 @@
+main = lib::main;
+library from "package:foo/lib.dart" as lib {
+
+ part main.dart;
+ static method main() → dynamic {}
+ static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml
new file mode 100644
index 0000000..3d91b09
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml
@@ -0,0 +1,37 @@
+# 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: main.dart
+ warnings: true
+ checkEntries: false
+ sources:
+ .packages: |
+ foo:.
+ main.dart: |
+ part of 'lib.dart';
+ partMethod() {}
+ lib.dart: |
+ part 'main.dart';
+ main() {}
+ expectedLibraryCount: 1
+
+ - entry: main.dart
+ warnings: true
+ checkEntries: false
+ worldType: updated
+ expectInitializeFromDill: false
+ invalidate:
+ - main.dart
+ expectedLibraryCount: 1
+
+ - entry: main.dart
+ warnings: true
+ checkEntries: false
+ worldType: updated
+ expectInitializeFromDill: false
+ invalidate:
+ - lib.dart
+ expectedLibraryCount: 1
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.1.expect
new file mode 100644
index 0000000..e826847
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.1.expect
@@ -0,0 +1,12 @@
+main = lib::main;
+//
+// Problems in component:
+//
+// org-dartlang-test:///main.dart: Warning: Interpreting this as package URI, 'package:foo/main.dart'.
+//
+library from "package:foo/lib.dart" as lib {
+
+ part main.dart;
+ static method main() → dynamic {}
+ static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.2.expect
new file mode 100644
index 0000000..e826847
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.2.expect
@@ -0,0 +1,12 @@
+main = lib::main;
+//
+// Problems in component:
+//
+// org-dartlang-test:///main.dart: Warning: Interpreting this as package URI, 'package:foo/main.dart'.
+//
+library from "package:foo/lib.dart" as lib {
+
+ part main.dart;
+ static method main() → dynamic {}
+ static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.3.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.3.expect
new file mode 100644
index 0000000..e826847
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/part_as_package_entry_2.yaml.world.3.expect
@@ -0,0 +1,12 @@
+main = lib::main;
+//
+// Problems in component:
+//
+// org-dartlang-test:///main.dart: Warning: Interpreting this as package URI, 'package:foo/main.dart'.
+//
+library from "package:foo/lib.dart" as lib {
+
+ part main.dart;
+ static method main() → dynamic {}
+ static method /* from org-dartlang-test:///main.dart */ partMethod() → dynamic {}
+}