[CFE] Avoid crash with experimental invalidation when same file is imported with both package and file uri

If importing the same file both by package-uri and file-uri it becomes
two different libraries in the compiler. They both have the same file
uri though.
When invalidating such a file by file uri they will both be invalidated.
When having experimental invalidation enabled it will - for each of
those invalidated libraries - get the source, compare it to the current
on-disk source, and - if the outline hasn't changed - remove the old
source to avoid having something wrong in memory. When trying to process
the second version of the file the old source has been removed and we
thus will crash if using a bang on the output from the uriToSource
lookup.
This CL avoids the crash by postponing the removal of the old source
until we're sure we'll return successfully. This is also more correct
in general as we might otherwise remove sources where we're (for later
reasons) going to bail out.

Change-Id: If5d767764a958b2dbb09cc011745e13e572038a5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/241745
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
This commit is contained in:
Jens Johansen 2022-04-21 09:12:47 +00:00 committed by Commit Bot
parent 3aa8f2519b
commit 64a169ec7e
4 changed files with 78 additions and 4 deletions

View file

@ -1237,9 +1237,6 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
if (before != now) {
return null;
}
// TODO(jensj): We should only do this when we're sure we're going to
// do it!
CompilerContext.current.uriToSource.remove(builder.fileUri);
missingSources ??= new Set<Uri>();
missingSources.add(builder.fileUri);
LibraryBuilder? partOfLibrary = builder.partOfLibrary;
@ -1322,8 +1319,13 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
reusedResult.notReusedLibraries.clear();
reusedResult.notReusedLibraries.addAll(rebuildBodies!);
// Now we know we're going to do it --- remove old sources.
for (Uri fileUri in missingSources!) {
CompilerContext.current.uriToSource.remove(fileUri);
}
return new ExperimentalInvalidation(
rebuildBodies, originalNotReusedLibraries, missingSources!);
rebuildBodies, originalNotReusedLibraries, missingSources);
}
/// Get UriTranslator, and figure out if the packages file was (potentially)

View file

@ -0,0 +1,40 @@
# Copyright (c) 2022, 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.
# Importing a package also via file uri gives two libraries with the same
# file uri --- that shouldn't crash experimental invalidation though.
type: newworld
worlds:
- entry: package:foo/main.dart
experiments: alternative-invalidation-strategy
checkEntries: false
sources:
.dart_tool/package_config.json: |
{
"configVersion": 2,
"packages": [
{
"name": "foo",
"rootUri": "../foo",
"languageVersion": "2.12"
}
]
}
foo/main.dart: |
import "package:foo/lib.dart";
foo/lib.dart: |
import "org-dartlang-test:///foo/main.dart";
expectedLibraryCount: 3 # main twice --- one for the package and one for the file uri.
- entry: package:foo/main.dart
experiments: alternative-invalidation-strategy
checkEntries: false
worldType: updated
expectInitializeFromDill: false
invalidate:
- foo/main.dart
expectedLibraryCount: 3
expectsRebuildBodiesOnly: true
checkInvalidatedFiles: false

View file

@ -0,0 +1,16 @@
main = <No Member>;
library from "package:foo/lib.dart" as lib {
import "org-dartlang-test:///foo/main.dart";
}
library from "package:foo/main.dart" as main {
import "package:foo/lib.dart";
}
library from "org-dartlang-test:///foo/main.dart" as main2 {
import "package:foo/lib.dart";
}

View file

@ -0,0 +1,16 @@
main = <No Member>;
library from "package:foo/lib.dart" as lib {
import "org-dartlang-test:///foo/main.dart";
}
library from "package:foo/main.dart" as main {
import "package:foo/lib.dart";
}
library from "org-dartlang-test:///foo/main.dart" as main2 {
import "package:foo/lib.dart";
}