[CFE] Fix not getting rid of NNBD error in package in incremental compiler

This fixes the issue of the error not going away, but can (see added
test) give a wrong error message when in the process of fixing the issues.

A follow-up CL will (try to) correct the wrong error message.

Change-Id: I3547fe5fb5cfd179897996029a00a4995a967e54
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/170422
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
This commit is contained in:
Jens Johansen 2020-11-05 08:47:42 +00:00 committed by commit-bot@chromium.org
parent 44f3881be6
commit 60a5c58196
16 changed files with 374 additions and 47 deletions

View file

@ -131,9 +131,11 @@ class LocatedMessage implements Comparable<LocatedMessage> {
}
FormattedMessage withFormatting(String formatted, int line, int column,
Severity severity, List<FormattedMessage> relatedInformation) {
Severity severity, List<FormattedMessage> relatedInformation,
{List<Uri> involvedFiles}) {
return new FormattedMessage(
this, formatted, line, column, severity, relatedInformation);
this, formatted, line, column, severity, relatedInformation,
involvedFiles: involvedFiles);
}
@override
@ -173,8 +175,11 @@ class FormattedMessage implements DiagnosticMessage {
final List<FormattedMessage> relatedInformation;
final List<Uri> involvedFiles;
const FormattedMessage(this.locatedMessage, this.formatted, this.line,
this.column, this.severity, this.relatedInformation);
this.column, this.severity, this.relatedInformation,
{this.involvedFiles});
Code<dynamic> get code => locatedMessage.code;
@ -212,7 +217,8 @@ class FormattedMessage implements DiagnosticMessage {
"ansiFormatted": ansiFormatted.toList(),
"plainTextFormatted": plainTextFormatted.toList(),
"severity": severity.index,
"uri": uri.toString(),
"uri": uri?.toString(),
"involvedFiles": involvedFiles?.map((u) => u.toString())?.toList(),
};
}
@ -234,8 +240,10 @@ class DiagnosticMessageFromJson implements DiagnosticMessage {
final Uri uri;
DiagnosticMessageFromJson(
this.ansiFormatted, this.plainTextFormatted, this.severity, this.uri);
final List<Uri> involvedFiles;
DiagnosticMessageFromJson(this.ansiFormatted, this.plainTextFormatted,
this.severity, this.uri, this.involvedFiles);
factory DiagnosticMessageFromJson.fromJson(String jsonString) {
Map<String, Object> decoded = json.decode(jsonString);
@ -244,10 +252,15 @@ class DiagnosticMessageFromJson implements DiagnosticMessage {
List<String> plainTextFormatted =
new List<String>.from(decoded["plainTextFormatted"]);
Severity severity = Severity.values[decoded["severity"]];
Uri uri = Uri.parse(decoded["uri"]);
Uri uri = decoded["uri"] == null ? null : Uri.parse(decoded["uri"]);
List<Uri> involvedFiles = decoded["involvedFiles"] == null
? null
: new List<String>.from(decoded["involvedFiles"])
.map((e) => Uri.parse(e))
.toList();
return new DiagnosticMessageFromJson(
ansiFormatted, plainTextFormatted, severity, uri);
ansiFormatted, plainTextFormatted, severity, uri, involvedFiles);
}
Map<String, Object> toJson() {
@ -256,7 +269,8 @@ class DiagnosticMessageFromJson implements DiagnosticMessage {
"ansiFormatted": ansiFormatted.toList(),
"plainTextFormatted": plainTextFormatted.toList(),
"severity": severity.index,
"uri": uri.toString(),
"uri": uri?.toString(),
"involvedFiles": involvedFiles?.map((u) => u.toString())?.toList(),
};
}

View file

@ -34,13 +34,17 @@ abstract class DiagnosticMessage {
Iterable<String> get plainTextFormatted;
Severity get severity;
Iterable<Uri> get involvedFiles;
}
/// This method is subject to change.
Uri getMessageUri(DiagnosticMessage message) {
return message is FormattedMessage
? message.uri
: message is DiagnosticMessageFromJson ? message.uri : null;
: message is DiagnosticMessageFromJson
? message.uri
: null;
}
/// This method is subject to change.

View file

@ -207,7 +207,8 @@ class ProcessedOptions {
this.ticker = new Ticker(isVerbose: options?.verbose ?? false);
FormattedMessage format(
LocatedMessage message, Severity severity, List<LocatedMessage> context) {
LocatedMessage message, Severity severity, List<LocatedMessage> context,
{List<Uri> involvedFiles}) {
int offset = message.charOffset;
Uri uri = message.uri;
Location location = offset == -1 ? null : getLocation(uri, offset);
@ -221,11 +222,12 @@ class ProcessedOptions {
}
}
return message.withFormatting(formatted, location?.line ?? -1,
location?.column ?? -1, severity, formattedContext);
location?.column ?? -1, severity, formattedContext,
involvedFiles: involvedFiles);
}
void report(LocatedMessage message, Severity severity,
{List<LocatedMessage> context}) {
{List<LocatedMessage> context, List<Uri> involvedFiles}) {
if (command_line_reporting.isHidden(severity)) return;
if (command_line_reporting.isCompileTimeError(severity)) {
CompilerContext.current.logError(message, severity);
@ -233,7 +235,8 @@ class ProcessedOptions {
if (CompilerContext.current.options.setExitCodeOnProblem) {
exitCode = 1;
}
reportDiagnosticMessage(format(message, severity, context));
reportDiagnosticMessage(
format(message, severity, context, involvedFiles: involvedFiles));
if (command_line_reporting.shouldThrowOn(severity)) {
if (fatalDiagnosticCount++ < _raw.skipForDebugging) {
// Skip this one. The interesting one comes later.

View file

@ -65,8 +65,9 @@ class CompilerContext {
/// Report [message], for example, by printing it.
void report(LocatedMessage message, Severity severity,
{List<LocatedMessage> context}) {
options.report(message, severity, context: context);
{List<LocatedMessage> context, List<Uri> involvedFiles}) {
options.report(message, severity,
context: context, involvedFiles: involvedFiles);
}
/// Report [message], for example, by printing it.

View file

@ -1390,16 +1390,7 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
}
// Save any new component-problems.
if (componentWithDill?.problemsAsJson != null) {
for (String jsonString in componentWithDill.problemsAsJson) {
DiagnosticMessageFromJson message =
new DiagnosticMessageFromJson.fromJson(jsonString);
List<DiagnosticMessageFromJson> messages =
remainingComponentProblems[message.uri] ??=
new List<DiagnosticMessageFromJson>();
messages.add(message);
}
}
_addProblemsAsJsonToRemainingProblems(componentWithDill?.problemsAsJson);
return new List<String>.from(issuedProblems);
}
@ -1657,14 +1648,36 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
/// Internal method.
void saveComponentProblems(IncrementalCompilerData data) {
if (data.component.problemsAsJson != null) {
for (String jsonString in data.component.problemsAsJson) {
List<String> problemsAsJson = data.component.problemsAsJson;
_addProblemsAsJsonToRemainingProblems(problemsAsJson);
}
void _addProblemsAsJsonToRemainingProblems(List<String> problemsAsJson) {
if (problemsAsJson != null) {
for (String jsonString in problemsAsJson) {
DiagnosticMessageFromJson message =
new DiagnosticMessageFromJson.fromJson(jsonString);
List<DiagnosticMessageFromJson> messages =
remainingComponentProblems[message.uri] ??=
new List<DiagnosticMessageFromJson>();
messages.add(message);
assert(message.uri != null ||
(message.involvedFiles != null &&
message.involvedFiles.isNotEmpty));
if (message.uri != null) {
List<DiagnosticMessageFromJson> messages =
remainingComponentProblems[message.uri] ??=
new List<DiagnosticMessageFromJson>();
messages.add(message);
}
if (message.involvedFiles != null) {
// This indexes the same message under several uris - this way it will
// be issued as long as it's a problem. It will because of
// deduplication when we re-issue these (in reissueComponentProblems)
// only be reported once.
for (Uri uri in message.involvedFiles) {
List<DiagnosticMessageFromJson> messages =
remainingComponentProblems[uri] ??=
new List<DiagnosticMessageFromJson>();
messages.add(message);
}
}
}
}
}

View file

@ -280,11 +280,13 @@ abstract class Loader {
{bool wasHandled: false,
List<LocatedMessage> context,
Severity severity,
bool problemOnLibrary: false}) {
bool problemOnLibrary: false,
List<Uri> involvedFiles}) {
return addMessage(message, charOffset, length, fileUri, severity,
wasHandled: wasHandled,
context: context,
problemOnLibrary: problemOnLibrary);
problemOnLibrary: problemOnLibrary,
involvedFiles: involvedFiles);
}
/// All messages reported by the compiler (errors, warnings, etc.) are routed
@ -302,7 +304,8 @@ abstract class Loader {
Uri fileUri, Severity severity,
{bool wasHandled: false,
List<LocatedMessage> context,
bool problemOnLibrary: false}) {
bool problemOnLibrary: false,
List<Uri> involvedFiles}) {
severity = target.fixSeverity(severity, message, fileUri);
if (severity == Severity.ignored) return null;
String trace = """
@ -321,13 +324,14 @@ severity: $severity
}
target.context.report(
message.withLocation(fileUri, charOffset, length), severity,
context: context);
context: context, involvedFiles: involvedFiles);
if (severity == Severity.error) {
(wasHandled ? handledErrors : unhandledErrors)
.add(message.withLocation(fileUri, charOffset, length));
}
FormattedMessage formattedMessage = target.createFormattedMessage(
message, charOffset, length, fileUri, context, severity);
message, charOffset, length, fileUri, context, severity,
involvedFiles: involvedFiles);
if (!problemOnLibrary) {
allComponentProblems.add(formattedMessage);
}

View file

@ -385,13 +385,18 @@ class SourceLoader extends Loader {
}
}
if (libraryByPackage.isNotEmpty) {
List<Uri> involvedFiles = [];
List<String> dependencies = [];
libraryByPackage.forEach((String name, List<LibraryBuilder> libraries) {
if (name != null) {
dependencies.add('package:$name');
for (LibraryBuilder libraryBuilder in libraries) {
involvedFiles.add(libraryBuilder.fileUri);
}
} else {
for (LibraryBuilder libraryBuilder in libraries) {
dependencies.add(libraryBuilder.importUri.toString());
involvedFiles.add(libraryBuilder.fileUri);
}
}
});
@ -401,7 +406,8 @@ class SourceLoader extends Loader {
templateStrongModeNNBDPackageOptOut.withArguments(dependencies),
-1,
-1,
null);
null,
involvedFiles: involvedFiles);
_strongOptOutLibraries = null;
}
}

View file

@ -180,12 +180,14 @@ abstract class TargetImplementation extends Target {
int length,
Uri fileUri,
List<LocatedMessage> messageContext,
Severity severity) {
Severity severity,
{List<Uri> involvedFiles}) {
ProcessedOptions processedOptions = context.options;
return processedOptions.format(
message.withLocation(fileUri, charOffset, length),
severity,
messageContext);
messageContext,
involvedFiles: involvedFiles);
}
Severity fixSeverity(Severity severity, Message message, Uri fileUri) {

View file

@ -23,12 +23,13 @@ main() {
null, "Formatted string #3", 313, 32, Severity.error, []);
FormattedMessage formattedMessage1 = new FormattedMessage(
locatedMessage1,
"Formatted string",
42,
86,
severity,
[formattedMessage2, formattedMessage3]);
locatedMessage1, "Formatted string", 42, 86, severity, [
formattedMessage2,
formattedMessage3
], involvedFiles: [
Uri.parse("what:ever/foo.dart"),
Uri.parse("what:ever/bar.dart")
]);
DiagnosticMessageFromJson diagnosticMessageFromJson =
new DiagnosticMessageFromJson.fromJson(
@ -62,6 +63,15 @@ void compareMessages(DiagnosticMessage a, DiagnosticMessage b) {
expect(a.severity, b.severity);
expect(getMessageUri(a), getMessageUri(b));
List<Uri> uriList1 = a.involvedFiles?.toList();
List<Uri> uriList2 = b.involvedFiles?.toList();
expect(uriList1?.length, uriList2?.length);
if (uriList1 != null) {
for (int i = 0; i < uriList1.length; i++) {
expect(uriList1[i], uriList2[i]);
}
}
}
void expect(Object actual, Object expect) {

View file

@ -279,6 +279,7 @@ dec
decl
decoupled
decreases
deduplication
deemed
deepest
deeply

View file

@ -0,0 +1,150 @@
# Copyright (c) 2020, 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.
# If issuing a "compiling with strong mode but [...]" error, we should be able
# to get rid of it if the error is fixed.
type: newworld
worlds:
- entry: package:baz/main.dart
experiments: non-nullable
nnbdMode: strong
errors: true
sources:
.dart_tool/package_config.json: |
{
"configVersion": 2,
"packages": [
{
"name": "foo",
"rootUri": "../foo",
"packageUri": "lib/",
"languageVersion": "2.8"
},
{
"name": "bar",
"rootUri": "../bar",
"packageUri": "lib/",
"languageVersion": "2.8"
},
{
"name": "baz",
"rootUri": "../baz",
"packageUri": ""
}
]
}
foo/lib/foo.dart: |
// This file is in weak mode.
int x = null;
bar/lib/bar.dart: |
// This file is in weak mode.
int y = null;
baz/main.dart: |
// This file wants to be strong.
import "package:foo/foo.dart" as foo;
import "package:bar/bar.dart" as bar;
main() {
print(foo.x);
print(bar.y);
}
expectedLibraryCount: 3
# Update "nothing" so we still want the error.
- entry: package:baz/main.dart
experiments: non-nullable
nnbdMode: strong
worldType: updated
expectInitializeFromDill: false
errors: true
invalidate:
- baz/main.dart
sources:
baz/main.dart: |
// This file wants to be strong.
import "package:foo/foo.dart" as foo;
import "package:bar/bar.dart" as bar;
main() {
print(foo.x);
print(bar.y);
print("done");
}
expectedLibraryCount: 3
# Update ONE package to be strong.
- entry: package:baz/main.dart
experiments: non-nullable
nnbdMode: strong
worldType: updated
expectInitializeFromDill: false
errors: true
invalidate:
# .dart_tool/package_config.json is invalidated implicitly.
- foo/lib/foo.dart
sources:
.dart_tool/package_config.json: |
{
"configVersion": 2,
"packages": [
{
"name": "foo",
"rootUri": "../foo",
"packageUri": "lib/"
},
{
"name": "bar",
"rootUri": "../bar",
"packageUri": "lib/",
"languageVersion": "2.8"
},
{
"name": "baz",
"rootUri": "../baz",
"packageUri": ""
}
]
}
foo/lib/foo.dart: |
// This file is in strong mode.
int x = 42;
expectedLibraryCount: 3
# Update the last package to be strong.
- entry: package:baz/main.dart
experiments: non-nullable
nnbdMode: strong
worldType: updated
expectInitializeFromDill: false
errors: false
invalidate:
# .dart_tool/package_config.json is invalidated implicitly.
- bar/lib/bar.dart
sources:
.dart_tool/package_config.json: |
{
"configVersion": 2,
"packages": [
{
"name": "foo",
"rootUri": "../foo",
"packageUri": "lib/"
},
{
"name": "bar",
"rootUri": "../bar",
"packageUri": "lib/"
},
{
"name": "baz",
"rootUri": "../baz",
"packageUri": ""
}
]
}
bar/lib/bar.dart: |
// This file is in strong mode.
int y = 42;
expectedLibraryCount: 3

View file

@ -0,0 +1,31 @@
main = main::main;
//
// Problems in component:
//
// Error: This project cannot run with sound null safety, because one or more project dependencies do not
// support null safety:
//
// - package:foo
// - package:bar
//
// Run 'pub outdated --mode=null-safety' to determine if versions of your
// dependencies supporting null safety are available.
//
library from "package:bar/bar.dart" as bar {
static field dart.core::int* y = null;
}
library from "package:baz/main.dart" as main {
import "package:foo/foo.dart" as foo;
import "package:bar/bar.dart" as bar;
static method main() → dynamic {
dart.core::print(foo::x);
dart.core::print(bar::y);
}
}
library from "package:foo/foo.dart" as foo {
static field dart.core::int* x = null;
}

View file

@ -0,0 +1,32 @@
main = main::main;
//
// Problems in component:
//
// Error: This project cannot run with sound null safety, because one or more project dependencies do not
// support null safety:
//
// - package:foo
// - package:bar
//
// Run 'pub outdated --mode=null-safety' to determine if versions of your
// dependencies supporting null safety are available.
//
library from "package:bar/bar.dart" as bar {
static field dart.core::int* y = null;
}
library from "package:baz/main.dart" as main {
import "package:foo/foo.dart" as foo;
import "package:bar/bar.dart" as bar;
static method main() → dynamic {
dart.core::print(foo::x);
dart.core::print(bar::y);
dart.core::print("done");
}
}
library from "package:foo/foo.dart" as foo {
static field dart.core::int* x = null;
}

View file

@ -0,0 +1,32 @@
main = main::main;
//
// Problems in component:
//
// Error: This project cannot run with sound null safety, because one or more project dependencies do not
// support null safety:
//
// - package:foo
// - package:bar
//
// Run 'pub outdated --mode=null-safety' to determine if versions of your
// dependencies supporting null safety are available.
//
library from "package:bar/bar.dart" as bar {
static field dart.core::int* y = null;
}
library from "package:baz/main.dart" as main {
import "package:foo/foo.dart" as foo;
import "package:bar/bar.dart" as bar;
static method main() → dynamic {
dart.core::print(foo::x);
dart.core::print(bar::y);
dart.core::print("done");
}
}
library from "package:foo/foo.dart" as foo {
static field dart.core::int x = 42;
}

View file

@ -0,0 +1,20 @@
main = main::main;
library from "package:bar/bar.dart" as bar {
static field dart.core::int y = 42;
}
library from "package:baz/main.dart" as main {
import "package:foo/foo.dart" as foo;
import "package:bar/bar.dart" as bar;
static method main() → dynamic {
dart.core::print(foo::x);
dart.core::print(bar::y);
dart.core::print("done");
}
}
library from "package:foo/foo.dart" as foo {
static field dart.core::int x = 42;
}

View file

@ -17,7 +17,11 @@ problem-texts as reported by the compiler.
`severity`: An integer representing severity. This should match the index in
`package:_fe_analyzer_shared/src/messages/severity.dart`.
`uri`: A uri that this problems relates to.
`uri`: A possibly null uri that this problems relates to. This is the main uri.
Normally this is not null (but it can be).
`involvedFiles`: A possibly null list of uris involved in this message.
Normally this is null.
These values are subject to change, but this file will be updated along with any
such changes. On the code-side these are defined in