[CFE] Fix dangling reference to part imported as library
Before this CL: If a library (say lib.dart) imports a file (say part.dart) that's actually a part (of some other library (say main.dart)) an error is given, but the "fake library" shortly representing the part is still "linked" into the libraries dependency list. This means that the component returned from a compilation is different from the combination of libraries one can get to if walking all LibraryDependency's. This also means that if we serialize the component we can't load it back in (https://github.com/dart-lang/sdk/issues/46706). It furthermore means that we have two different entities with the same fileUri and importUri. This CL rewrites a such import of a part to instead be an import of the "parent", i.e. if a library lib.dart imports part.dart that's a part of main.dart an error is issued, and the import is rewritten to be an import of main.dart instead. The same thing happens to exports. This alleviates the problems (i.e. no crashing if trying to load the dill, no referenec to a otherwise non-existing library etc), and has the added benefit of probably being what the user wants: Anything defined in part.dart (that isn't private) is still in scope from lib.dart. Change-Id: I17aca9db4edbf25b23d3ef301cf65589eeeb1635 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/213344 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Jens Johansen <jensj@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
fd2d014112
commit
17503caa05
@@ -1067,6 +1067,17 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
|
||||
export.exporter.addProblem(
|
||||
messagePartExport, export.charOffset, "export".length, null,
|
||||
context: context);
|
||||
if (library != null) {
|
||||
// Recovery: Export the main library instead.
|
||||
export.exported = library;
|
||||
SourceLibraryBuilder exporter =
|
||||
export.exporter as SourceLibraryBuilder;
|
||||
for (Export export2 in exporter.exports) {
|
||||
if (export2.exported == this) {
|
||||
export2.exported = library;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1228,6 +1239,12 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
|
||||
part.scope.becomePartOf(scope);
|
||||
// TODO(ahe): Include metadata from part?
|
||||
|
||||
// Recovery: Take on all exporters (i.e. if a library has erroneously
|
||||
// exported the part it has (in validatePart) been recovered to import the
|
||||
// main library (this) instead --- to make it complete (and set up scopes
|
||||
// correctly) the exporters in this has to be updated too).
|
||||
exporters.addAll(part.exporters);
|
||||
|
||||
nativeMethods.addAll(part.nativeMethods);
|
||||
boundlessTypeVariables.addAll(part.boundlessTypeVariables);
|
||||
// Check that the targets are different. This is not normally a problem
|
||||
@@ -1245,6 +1262,11 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
|
||||
_implicitlyTypedFields!.addAll(partImplicitlyTypedFields);
|
||||
}
|
||||
}
|
||||
if (library != part.library) {
|
||||
// Mark the part library as synthetic as it's not an actual library
|
||||
// (anymore).
|
||||
part.library.isSynthetic = true;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
assert(part is DillLibraryBuilder);
|
||||
@@ -1273,15 +1295,21 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
|
||||
void addImportsToScope() {
|
||||
bool explicitCoreImport = this == loader.coreLibrary;
|
||||
for (Import import in imports) {
|
||||
if (import.imported == loader.coreLibrary) {
|
||||
explicitCoreImport = true;
|
||||
}
|
||||
if (import.imported?.isPart ?? false) {
|
||||
addProblem(
|
||||
templatePartOfInLibrary.withArguments(import.imported!.fileUri),
|
||||
import.charOffset,
|
||||
noLength,
|
||||
fileUri);
|
||||
if (import.imported?.partOfLibrary != null) {
|
||||
// Recovery: Rewrite to import the "part owner" library.
|
||||
// Note that the part will not have a partOfLibrary if it claims to be
|
||||
// a part, but isn't mentioned as a part by the (would-be) "parent".
|
||||
import.imported = import.imported?.partOfLibrary;
|
||||
}
|
||||
}
|
||||
if (import.imported == loader.coreLibrary) {
|
||||
explicitCoreImport = true;
|
||||
}
|
||||
import.finalizeImports(this);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# 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
|
||||
errors: true
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'lib.dart';
|
||||
part 'part.dart';
|
||||
void main() {}
|
||||
part.dart: |
|
||||
part of "main.dart";
|
||||
void partMethod() {}
|
||||
lib.dart: |
|
||||
import 'part.dart';
|
||||
import 'part.dart';
|
||||
import 'part.dart';
|
||||
void libMethod() {
|
||||
partMethod();
|
||||
}
|
||||
expectedLibraryCount: 2
|
||||
- entry: main.dart
|
||||
invalidate:
|
||||
- lib.dart
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'lib.dart';
|
||||
part 'part.dart';
|
||||
void main() {}
|
||||
part.dart: |
|
||||
part of "main.dart";
|
||||
void partMethod() {}
|
||||
lib.dart: |
|
||||
void libMethod() {}
|
||||
expectedLibraryCount: 2
|
||||
@@ -0,0 +1,37 @@
|
||||
main = main::main;
|
||||
library from "org-dartlang-test:///lib.dart" as lib {
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// org-dartlang-test:///lib.dart:1:1: Error: Can't import 'org-dartlang-test:///part.dart', because it has a 'part of' declaration.
|
||||
// Try removing the 'part of' declaration, or using 'org-dartlang-test:///part.dart' as a part.
|
||||
// import 'part.dart';
|
||||
// ^
|
||||
//
|
||||
// org-dartlang-test:///lib.dart:2:1: Error: Can't import 'org-dartlang-test:///part.dart', because it has a 'part of' declaration.
|
||||
// Try removing the 'part of' declaration, or using 'org-dartlang-test:///part.dart' as a part.
|
||||
// import 'part.dart';
|
||||
// ^
|
||||
//
|
||||
// org-dartlang-test:///lib.dart:3:1: Error: Can't import 'org-dartlang-test:///part.dart', because it has a 'part of' declaration.
|
||||
// Try removing the 'part of' declaration, or using 'org-dartlang-test:///part.dart' as a part.
|
||||
// import 'part.dart';
|
||||
// ^
|
||||
//
|
||||
|
||||
import "org-dartlang-test:///main.dart";
|
||||
import "org-dartlang-test:///main.dart";
|
||||
import "org-dartlang-test:///main.dart";
|
||||
|
||||
static method libMethod() → void {
|
||||
main::partMethod();
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///lib.dart";
|
||||
|
||||
part part.dart;
|
||||
static method main() → void {}
|
||||
static method /* from org-dartlang-test:///part.dart */ partMethod() → void {}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
main = main::main;
|
||||
library from "org-dartlang-test:///lib.dart" as lib {
|
||||
|
||||
static method libMethod() → void {}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///lib.dart";
|
||||
|
||||
part part.dart;
|
||||
static method main() → void {}
|
||||
static method /* from org-dartlang-test:///part.dart */ partMethod() → void {}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
# 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
|
||||
errors: true
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'lib.dart' as lib;
|
||||
part 'part.dart';
|
||||
void main() {
|
||||
lib.partMethod();
|
||||
}
|
||||
part.dart: |
|
||||
part of "main.dart";
|
||||
void partMethod() {}
|
||||
lib.dart: |
|
||||
export 'part.dart';
|
||||
export 'part.dart';
|
||||
export 'part.dart';
|
||||
void libMethod() {}
|
||||
expectedLibraryCount: 2
|
||||
- entry: main.dart
|
||||
invalidate:
|
||||
- lib.dart
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'lib.dart' as lib;
|
||||
part 'part.dart';
|
||||
void main() {
|
||||
lib.partMethod();
|
||||
}
|
||||
part.dart: |
|
||||
part of "main.dart";
|
||||
void partMethod() {}
|
||||
lib.dart: |
|
||||
void libMethod() {}
|
||||
void partMethod() {}
|
||||
expectedLibraryCount: 2
|
||||
@@ -0,0 +1,39 @@
|
||||
main = main::main;
|
||||
library from "org-dartlang-test:///lib.dart" as lib {
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// org-dartlang-test:///lib.dart:1:1: Error: Can't export this file because it contains a 'part of' declaration.
|
||||
// export 'part.dart';
|
||||
// ^^^^^^
|
||||
// org-dartlang-test:///part.dart: Context: This is the file that can't be exported.
|
||||
//
|
||||
// org-dartlang-test:///lib.dart:2:1: Error: Can't export this file because it contains a 'part of' declaration.
|
||||
// export 'part.dart';
|
||||
// ^^^^^^
|
||||
// org-dartlang-test:///part.dart: Context: This is the file that can't be exported.
|
||||
//
|
||||
// org-dartlang-test:///lib.dart:3:1: Error: Can't export this file because it contains a 'part of' declaration.
|
||||
// export 'part.dart';
|
||||
// ^^^^^^
|
||||
// org-dartlang-test:///part.dart: Context: This is the file that can't be exported.
|
||||
//
|
||||
additionalExports = (main::main,
|
||||
main::partMethod)
|
||||
|
||||
export "org-dartlang-test:///main.dart";
|
||||
export "org-dartlang-test:///main.dart";
|
||||
export "org-dartlang-test:///main.dart";
|
||||
|
||||
static method libMethod() → void {}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///lib.dart" as lib;
|
||||
|
||||
part part.dart;
|
||||
static method main() → void {
|
||||
main::partMethod();
|
||||
}
|
||||
static method /* from org-dartlang-test:///part.dart */ partMethod() → void {}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
main = main::main;
|
||||
library from "org-dartlang-test:///lib.dart" as lib {
|
||||
|
||||
static method libMethod() → void {}
|
||||
static method partMethod() → void {}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///lib.dart" as lib;
|
||||
|
||||
part part.dart;
|
||||
static method main() → void {
|
||||
lib::partMethod();
|
||||
}
|
||||
static method /* from org-dartlang-test:///part.dart */ partMethod() → void {}
|
||||
}
|
||||
@@ -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
|
||||
errors: true
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'lib.dart' as lib;
|
||||
void main() {}
|
||||
part.dart: |
|
||||
// Notice that main.dart didn't claim this as a part!
|
||||
part of "main.dart";
|
||||
void partMethod() {}
|
||||
lib.dart: |
|
||||
import 'part.dart';
|
||||
import 'part.dart';
|
||||
import 'part.dart';
|
||||
void libMethod() {}
|
||||
expectedLibraryCount: 3
|
||||
- entry: main.dart
|
||||
invalidate:
|
||||
- lib.dart
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'lib.dart' as lib;
|
||||
void main() {}
|
||||
lib.dart: |
|
||||
void libMethod() {}
|
||||
expectedLibraryCount: 2
|
||||
@@ -0,0 +1,45 @@
|
||||
main = main::main;
|
||||
library from "org-dartlang-test:///lib.dart" as lib {
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// org-dartlang-test:///lib.dart:1:1: Error: Can't import 'org-dartlang-test:///part.dart', because it has a 'part of' declaration.
|
||||
// Try removing the 'part of' declaration, or using 'org-dartlang-test:///part.dart' as a part.
|
||||
// import 'part.dart';
|
||||
// ^
|
||||
//
|
||||
// org-dartlang-test:///lib.dart:2:1: Error: Can't import 'org-dartlang-test:///part.dart', because it has a 'part of' declaration.
|
||||
// Try removing the 'part of' declaration, or using 'org-dartlang-test:///part.dart' as a part.
|
||||
// import 'part.dart';
|
||||
// ^
|
||||
//
|
||||
// org-dartlang-test:///lib.dart:3:1: Error: Can't import 'org-dartlang-test:///part.dart', because it has a 'part of' declaration.
|
||||
// Try removing the 'part of' declaration, or using 'org-dartlang-test:///part.dart' as a part.
|
||||
// import 'part.dart';
|
||||
// ^
|
||||
//
|
||||
|
||||
import "org-dartlang-test:///part.dart";
|
||||
import "org-dartlang-test:///part.dart";
|
||||
import "org-dartlang-test:///part.dart";
|
||||
|
||||
static method libMethod() → void {}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///lib.dart" as lib;
|
||||
|
||||
static method main() → void {}
|
||||
}
|
||||
library from "org-dartlang-test:///part.dart" as part {
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// org-dartlang-test:///part.dart:1:1: Error: This part doesn't have a containing library.
|
||||
// Try removing the 'part of' declaration.
|
||||
// // Notice that main.dart didn't claim this as a part!
|
||||
// ^
|
||||
//
|
||||
|
||||
static method partMethod() → void {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
main = main::main;
|
||||
library from "org-dartlang-test:///lib.dart" as lib {
|
||||
|
||||
static method libMethod() → void {}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///lib.dart" as lib;
|
||||
|
||||
static method main() → void {}
|
||||
}
|
||||
@@ -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
|
||||
errors: true
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'lib.dart' as lib;
|
||||
void main() {
|
||||
lib.partMethod();
|
||||
}
|
||||
part.dart: |
|
||||
// Notice that main.dart didn't claim this as a part!
|
||||
part of "main.dart";
|
||||
void partMethod() {}
|
||||
lib.dart: |
|
||||
export 'part.dart';
|
||||
export 'part.dart';
|
||||
export 'part.dart';
|
||||
void libMethod() {}
|
||||
expectedLibraryCount: 3
|
||||
- entry: main.dart
|
||||
invalidate:
|
||||
- lib.dart
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'lib.dart' as lib;
|
||||
void main() {
|
||||
lib.partMethod();
|
||||
}
|
||||
lib.dart: |
|
||||
void libMethod() {}
|
||||
void partMethod() {}
|
||||
expectedLibraryCount: 2
|
||||
@@ -0,0 +1,48 @@
|
||||
main = main::main;
|
||||
library from "org-dartlang-test:///lib.dart" as lib {
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// org-dartlang-test:///lib.dart:1:1: Error: Can't export this file because it contains a 'part of' declaration.
|
||||
// export 'part.dart';
|
||||
// ^^^^^^
|
||||
// org-dartlang-test:///part.dart: Context: This is the file that can't be exported.
|
||||
//
|
||||
// org-dartlang-test:///lib.dart:2:1: Error: Can't export this file because it contains a 'part of' declaration.
|
||||
// export 'part.dart';
|
||||
// ^^^^^^
|
||||
// org-dartlang-test:///part.dart: Context: This is the file that can't be exported.
|
||||
//
|
||||
// org-dartlang-test:///lib.dart:3:1: Error: Can't export this file because it contains a 'part of' declaration.
|
||||
// export 'part.dart';
|
||||
// ^^^^^^
|
||||
// org-dartlang-test:///part.dart: Context: This is the file that can't be exported.
|
||||
//
|
||||
additionalExports = (part::partMethod)
|
||||
|
||||
export "org-dartlang-test:///part.dart";
|
||||
export "org-dartlang-test:///part.dart";
|
||||
export "org-dartlang-test:///part.dart";
|
||||
|
||||
static method libMethod() → void {}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///lib.dart" as lib;
|
||||
|
||||
static method main() → void {
|
||||
part::partMethod();
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///part.dart" as part {
|
||||
//
|
||||
// Problems in library:
|
||||
//
|
||||
// org-dartlang-test:///part.dart:1:1: Error: This part doesn't have a containing library.
|
||||
// Try removing the 'part of' declaration.
|
||||
// // Notice that main.dart didn't claim this as a part!
|
||||
// ^
|
||||
//
|
||||
|
||||
static method partMethod() → void {}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
main = main::main;
|
||||
library from "org-dartlang-test:///lib.dart" as lib {
|
||||
|
||||
static method libMethod() → void {}
|
||||
static method partMethod() → void {}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///lib.dart" as lib;
|
||||
|
||||
static method main() → void {
|
||||
lib::partMethod();
|
||||
}
|
||||
}
|
||||
@@ -1126,7 +1126,7 @@ class BinaryPrinter implements Visitor<void>, BinarySink {
|
||||
writeOffset(node.fileOffset);
|
||||
writeByte(node.flags);
|
||||
writeAnnotationList(node.annotations);
|
||||
writeLibraryReference(node.targetLibrary, allowNull: true);
|
||||
writeLibraryReference(node.targetLibrary, allowNull: false);
|
||||
writeStringReference(node.name ?? '');
|
||||
writeNodeList(node.combinators);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user