Version 2.17.0-78.0.dev
Merge commit '1044d83ab779e39b774439ae9976d2aab90aa27c' into 'dev'
diff --git a/pkg/front_end/test/fasta/expression_suite.dart b/pkg/front_end/test/fasta/expression_suite.dart
index 8ada32c..8e867b7 100644
--- a/pkg/front_end/test/fasta/expression_suite.dart
+++ b/pkg/front_end/test/fasta/expression_suite.dart
@@ -38,7 +38,17 @@
show IncrementalCompiler;
import "package:kernel/ast.dart"
- show Component, DartType, DynamicType, Procedure, TypeParameter;
+ show
+ Class,
+ Component,
+ Constructor,
+ DartType,
+ DynamicType,
+ Field,
+ Library,
+ Member,
+ Procedure,
+ TypeParameter;
import 'package:kernel/target/targets.dart' show TargetFlags;
@@ -65,7 +75,11 @@
@override
final List<Step> steps;
- Context(this.compilerContext, this.errors, bool updateExpectations)
+ final bool fuzz;
+ final Set<Uri> fuzzedLibraries = {};
+ int fuzzCompiles = 0;
+
+ Context(this.compilerContext, this.errors, bool updateExpectations, this.fuzz)
: steps = <Step>[
const ReadTest(),
const CompileExpression(),
@@ -399,6 +413,118 @@
List<int> list = serializeProcedure(compiledProcedure);
assert(list.length > 0);
}
+
+ if (context.fuzz) {
+ await fuzz(compiler, compilerResult, context);
+ }
+ }
+
+ Future<void> fuzz(IncrementalCompiler compiler,
+ IncrementalCompilerResult compilerResult, Context context) async {
+ for (Library lib in compilerResult.classHierarchy!.knownLibraries) {
+ if (!context.fuzzedLibraries.add(lib.importUri)) continue;
+
+ for (Member m in lib.members) {
+ await fuzzMember(m, compiler, lib.importUri, context);
+ }
+
+ for (Class c in lib.classes) {
+ for (Member m in c.members) {
+ await fuzzMember(m, compiler, lib.importUri, context);
+ }
+ }
+ }
+ }
+
+ Future<void> fuzzMember(Member m, IncrementalCompiler compiler,
+ Uri libraryUri, Context context) async {
+ String expression = m.name.text;
+ if (m is Field || (m is Procedure && m.isGetter)) {
+ // fields and getters are fine as-is
+ } else if (m is Procedure && !m.isGetter) {
+ expression = "$expression()";
+ } else if (m is Constructor) {
+ if (m.parent is! Class) {
+ return;
+ }
+ Class parent = m.parent as Class;
+ if (m.name.text != "") {
+ expression = "${parent.name}.${m.name.text}()";
+ } else {
+ expression = "${parent.name}()";
+ }
+ } else {
+ print("Ignoring $m (${m.runtimeType})");
+ return;
+ }
+
+ String? className;
+ if (m.parent is Class && m is! Constructor) {
+ Class parent = m.parent as Class;
+ className = parent.name;
+ }
+
+ await fuzzTryCompile(compiler, "$expression", libraryUri, className,
+ !m.isInstanceMember, context);
+ if (className != null && !m.isInstanceMember) {
+ await fuzzTryCompile(compiler, "$className.$expression", libraryUri, null,
+ !m.isInstanceMember, context);
+ }
+ await fuzzTryCompile(compiler, "$expression.toString()", libraryUri,
+ className, !m.isInstanceMember, context);
+ if (className != null && !m.isInstanceMember) {
+ await fuzzTryCompile(compiler, "$className.$expression.toString()",
+ libraryUri, null, !m.isInstanceMember, context);
+ }
+ await fuzzTryCompile(compiler, "$expression.toString() == '42'", libraryUri,
+ className, !m.isInstanceMember, context);
+ if (className != null && !m.isInstanceMember) {
+ await fuzzTryCompile(
+ compiler,
+ "$className.$expression.toString() == '42'",
+ libraryUri,
+ null,
+ !m.isInstanceMember,
+ context);
+ }
+ await fuzzTryCompile(
+ compiler,
+ "() { var x = $expression.toString(); x == '42'; }()",
+ libraryUri,
+ className,
+ !m.isInstanceMember,
+ context);
+ if (className != null && !m.isInstanceMember) {
+ await fuzzTryCompile(
+ compiler,
+ "() { var x = $className.$expression.toString(); x == '42'; }()",
+ libraryUri,
+ null,
+ !m.isInstanceMember,
+ context);
+ }
+ }
+
+ Future<void> fuzzTryCompile(IncrementalCompiler compiler, String expression,
+ Uri libraryUri, String? className, bool isStatic, Context context) async {
+ context.fuzzCompiles++;
+ print("Fuzz compile #${context.fuzzCompiles} "
+ "('$expression' in $libraryUri $className)");
+ Procedure? compiledProcedure = await compiler.compileExpression(
+ expression,
+ {},
+ [],
+ "debugExpr",
+ libraryUri,
+ className: className,
+ isStatic: isStatic,
+ );
+ context.takeErrors();
+ if (compiledProcedure != null) {
+ // Confirm we can serialize generated procedure.
+ List<int> list = serializeProcedure(compiledProcedure);
+ assert(list.length > 0);
+ }
}
@override
@@ -430,6 +556,7 @@
path: test.entryPoint!.path + ".dill");
Uint8List dillData = await serializeComponent(component);
context.fileSystem.entityForUri(dillFileUri).writeAsBytesSync(dillData);
+ Set<Uri> beforeFuzzedLibraries = context.fuzzedLibraries.toSet();
await compileExpression(
test, sourceCompiler, sourceCompilerResult, context);
@@ -444,6 +571,8 @@
// Since it compiled successfully from source, the bootstrap-from-Dill
// should also succeed without errors.
assert(errors.isEmpty);
+ context.fuzzedLibraries.clear();
+ context.fuzzedLibraries.addAll(beforeFuzzedLibraries);
await compileExpression(test, dillCompiler, dillCompilerResult, context);
}
return new Result.pass(tests);
@@ -492,13 +621,15 @@
final bool updateExpectations = environment["updateExpectations"] == "true";
+ final bool fuzz = environment["fuzz"] == "true";
+
final CompilerContext compilerContext = new CompilerContext(options);
// Disable colors to ensure that expectation files are the same across
// platforms and independent of stdin/stderr.
colors.enableColors = false;
- return new Context(compilerContext, errors, updateExpectations);
+ return new Context(compilerContext, errors, updateExpectations, fuzz);
}
void main([List<String> arguments = const []]) =>
diff --git a/pkg/front_end/test/fasta/tool_git_test.dart b/pkg/front_end/test/fasta/tool_git_test.dart
index 6e4b231..092e026 100644
--- a/pkg/front_end/test/fasta/tool_git_test.dart
+++ b/pkg/front_end/test/fasta/tool_git_test.dart
@@ -114,7 +114,7 @@
"dump-ir": {
"exitCode": 2,
"stdout": "",
- "stderr": "Usage: dump-ir dillfile [output]\n",
+ "stderr": "Usage: dump-ir dillFile [output]\n",
},
};
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 2fe783e..5226583 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -28,6 +28,7 @@
affecting
afterwards
agree
+agreeing
ahe
ai
aiki
@@ -174,6 +175,7 @@
char
charcode
chars
+checkout
checkpoint
chloestefantsova
chunks
@@ -492,6 +494,7 @@
futureor
g
gardening
+gb
gen
generation
getable
@@ -560,6 +563,7 @@
ideographic
idn
ids
+idx
iff
il
imitate
@@ -652,6 +656,7 @@
jvm
k
kallentu
+kb
kernel's
kill
klass
@@ -766,6 +771,7 @@
nameless
namer
natively
+nativewrappers
nbsp
nc
ncs
@@ -836,6 +842,7 @@
overlooked
overshadowed
oversight
+overview
overwrite
overwriting
ownership
@@ -1178,6 +1185,7 @@
starter
stated
statics
+stats
stderr
stdin
stdio
@@ -1452,6 +1460,7 @@
xdc
xdfff
xef
+xff
xi
xj
xk
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 33568c9..3300b99 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -188,6 +188,7 @@
descriptors
deviation
dfast
+dfuzz
di
diagnosticable
dictionaries
@@ -195,7 +196,6 @@
differentiate
dijkstra
dijkstras
-dillfile
dinteractive
dirname
disagree
diff --git a/pkg/front_end/test/weekly_tester.dart b/pkg/front_end/test/weekly_tester.dart
index 2fe9bbf..077210e 100644
--- a/pkg/front_end/test/weekly_tester.dart
+++ b/pkg/front_end/test/weekly_tester.dart
@@ -124,6 +124,24 @@
}
}
+ {
+ // Expression suite with fuzzing.
+ Uri expressionSuite =
+ Platform.script.resolve("fasta/expression_suite.dart");
+ if (!new File.fromUri(expressionSuite).existsSync()) {
+ exitCode = 1;
+ print("Couldn't find $expressionSuite");
+ } else {
+ startedProcesses.add(await run(
+ [
+ expressionSuite.toString(),
+ "-Dfuzz=true",
+ ],
+ "expression suite",
+ ));
+ }
+ }
+
// Wait for everything to finish.
List<int> exitCodes =
await Future.wait(startedProcesses.map((e) => e.process.exitCode));
diff --git a/pkg/front_end/testing.json b/pkg/front_end/testing.json
index 9b60daf..81a46c2 100644
--- a/pkg/front_end/testing.json
+++ b/pkg/front_end/testing.json
@@ -319,7 +319,8 @@
"pattern": [
"_fe_analyzer_shared/lib/.*\\.dart$",
"front_end/lib/.*\\.dart$",
- "kernel/lib/.*\\.dart$"
+ "kernel/lib/.*\\.dart$",
+ "kernel/bin/.*\\.dart$"
],
"exclude": [
"kernel/lib/vm/.*\\.dart$",
diff --git a/pkg/front_end/tool/fasta b/pkg/front_end/tool/fasta
index 29d5544..1a3d971 100755
--- a/pkg/front_end/tool/fasta
+++ b/pkg/front_end/tool/fasta
@@ -46,7 +46,7 @@
set -- "$@" /dev/fd/1
fi
if [ "$#" != "3" ]; then
- stop "Usage: $1 dillfile [output]"
+ stop "Usage: $1 dillFile [output]"
fi
;;
testing)
diff --git a/pkg/front_end/tool/fasta.dart b/pkg/front_end/tool/fasta.dart
index 3e02026..14f8503 100644
--- a/pkg/front_end/tool/fasta.dart
+++ b/pkg/front_end/tool/fasta.dart
@@ -63,7 +63,7 @@
case 'dump-ir':
script = '${kernelBin}/dump.dart';
if (remainingArguments.isEmpty || remainingArguments.length > 2) {
- stop("Usage: $command dillfile [output]");
+ stop("Usage: $command dillFile [output]");
}
break;
case 'testing':
diff --git a/pkg/kernel/bin/compare_hierarchies.dart b/pkg/kernel/bin/compare_hierarchies.dart
new file mode 100644
index 0000000..e6e35ca
--- /dev/null
+++ b/pkg/kernel/bin/compare_hierarchies.dart
@@ -0,0 +1,163 @@
+#!/usr/bin/env dart
+// 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 file.
+
+import 'dart:io';
+
+import 'package:kernel/class_hierarchy.dart';
+import 'package:kernel/core_types.dart';
+import 'package:kernel/kernel.dart';
+import 'package:kernel/src/tool/command_line_util.dart';
+
+void usage() {
+ print("Compares the hierarchies of two dill files.");
+ print("");
+ print("Usage: dart <script> dillFile1.dill dillFile2.dill "
+ "[import:uri#classToIgnore|another:uri#andClassToIgnore]");
+ exit(1);
+}
+
+void main(List<String> args) {
+ CommandLineHelper.requireVariableArgumentCount([2, 3], args, usage);
+ CommandLineHelper.requireFileExists(args[0]);
+ CommandLineHelper.requireFileExists(args[1]);
+ Component binary1 = CommandLineHelper.tryLoadDill(args[0]);
+ Component binary2 = CommandLineHelper.tryLoadDill(args[1]);
+ Map<Uri, Set<String>> ignoresMap = {};
+ if (args.length >= 3) {
+ List<String> ignores = args[2].split("|");
+ for (String ignore in ignores) {
+ List<String> uriClassName = ignore.split("#");
+ if (uriClassName.length != 2) {
+ print("Ignoring '$ignore' as it doesn't conform to "
+ "'importUri#className'");
+ continue;
+ }
+ Uri uri = Uri.parse(uriClassName[0]);
+ String className = uriClassName[1];
+ (ignoresMap[uri] ??= {}).add(className);
+ }
+ }
+
+ print("(1): ${args[0]}");
+ print("(2): ${args[1]}");
+ print("");
+
+ ClosedWorldClassHierarchy ch1 =
+ new ClassHierarchy(binary1, new CoreTypes(binary1))
+ as ClosedWorldClassHierarchy;
+ ClosedWorldClassHierarchy ch2 =
+ new ClassHierarchy(binary2, new CoreTypes(binary2))
+ as ClosedWorldClassHierarchy;
+
+ Map<Uri, Library> libMap1 = createLibMap(binary1);
+ Map<Uri, Library> libMap2 = createLibMap(binary2);
+ Set<Uri> agreeingImportUris = new Set<Uri>.from(libMap1.keys)
+ ..retainAll(libMap2.keys);
+
+ for (Uri uri in agreeingImportUris) {
+ Library lib1 = libMap1[uri]!;
+ Library lib2 = libMap2[uri]!;
+ Map<String, Class> libClass1 =
+ createPublicClassMap(lib1, ignored: ignoresMap[uri]);
+ Map<String, Class> libClass2 =
+ createPublicClassMap(lib2, ignored: ignoresMap[uri]);
+ Set<String> agreeingClasses = new Set<String>.from(libClass1.keys)
+ ..retainAll(libClass2.keys);
+ if (agreeingClasses.length != libClass1.length ||
+ libClass1.length != libClass2.length) {
+ print("Missing classes in lib $uri");
+ Set<String> missing = new Set<String>.from(libClass1.keys)
+ ..removeAll(libClass2.keys);
+ if (missing.isNotEmpty) {
+ print("In (1) but not in (2): ${missing.toList()}");
+ }
+ missing = new Set<String>.from(libClass2.keys)..removeAll(libClass1.keys);
+ if (missing.isNotEmpty) {
+ print("In (2) but not in (1): ${missing.toList()}");
+ }
+ print("");
+ }
+
+ for (String className in agreeingClasses) {
+ Class c1 = libClass1[className]!;
+ Class c2 = libClass2[className]!;
+ Set<ClassReference> c1Supertypes = createClassReferenceSet(
+ ch1.getAllSupertypeClassesForTesting(c1),
+ onlyPublic: true,
+ ignoresMap: ignoresMap);
+ Set<ClassReference> c2Supertypes = createClassReferenceSet(
+ ch2.getAllSupertypeClassesForTesting(c2),
+ onlyPublic: true,
+ ignoresMap: ignoresMap);
+ Set<ClassReference> missing = new Set<ClassReference>.from(c1Supertypes)
+ ..removeAll(c2Supertypes);
+ if (missing.isNotEmpty) {
+ print("$c1 in $lib1 from (1) has these extra supertypes: "
+ "${missing.toList()}");
+ }
+ missing = new Set<ClassReference>.from(c2Supertypes)
+ ..removeAll(c1Supertypes);
+ if (missing.isNotEmpty) {
+ print("$c2 in $lib2 from (2) has these extra supertypes: "
+ "${missing.toList()}");
+ }
+ }
+ }
+}
+
+Map<Uri, Library> createLibMap(Component c) {
+ Map<Uri, Library> map = {};
+ for (Library lib in c.libraries) {
+ map[lib.importUri] = lib;
+ }
+ return map;
+}
+
+Map<String, Class> createPublicClassMap(Library lib,
+ {required Set<String>? ignored}) {
+ Map<String, Class> map = {};
+ for (Class c in lib.classes) {
+ if (c.name.startsWith("_")) continue;
+ if (ignored?.contains(c.name) ?? false) continue;
+ map[c.name] = c;
+ }
+ return map;
+}
+
+Set<ClassReference> createClassReferenceSet(List<Class> classes,
+ {required bool onlyPublic, required Map<Uri, Set<String>> ignoresMap}) {
+ Set<ClassReference> result = {};
+ for (Class c in classes) {
+ if (onlyPublic && c.name.startsWith("_")) continue;
+ Set<String>? ignored = ignoresMap[c.enclosingLibrary.importUri];
+ if (ignored?.contains(c.name) ?? false) continue;
+ result.add(new ClassReference(c.name, c.enclosingLibrary.importUri));
+ }
+ return result;
+}
+
+class ClassReference {
+ final String name;
+ final Uri libImportUri;
+
+ const ClassReference(this.name, this.libImportUri);
+
+ @override
+ int get hashCode => name.hashCode * 13 + libImportUri.hashCode * 17;
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+ if (other is! ClassReference) return false;
+ if (name != other.name) return false;
+ if (libImportUri != other.libImportUri) return false;
+ return true;
+ }
+
+ @override
+ String toString() {
+ return "$name ($libImportUri)";
+ }
+}
diff --git a/pkg/kernel/bin/dill_forensic.dart b/pkg/kernel/bin/dill_forensic.dart
index c95d02a..b68b32f 100755
--- a/pkg/kernel/bin/dill_forensic.dart
+++ b/pkg/kernel/bin/dill_forensic.dart
@@ -12,16 +12,16 @@
void main(List<String> args) {
if (args.length != 1) {
- throw "Usage: dart <script> <dillfile>";
+ throw "Usage: dart <script> <dillFile>";
}
File file = new File(args.single);
if (!file.existsSync()) {
throw "Given file doesn't exist.\n"
- "Usage: dart <script> <dillfile>";
+ "Usage: dart <script> <dillFile>";
}
Uint8List bytes = file.readAsBytesSync();
List<Component> components = splitAndRead(bytes);
- print("Sucessfully read ${components.length} sub-components.");
+ print("Successfully read ${components.length} sub-components.");
for (int i = 0; i < components.length; i++) {
Component component = components[i];
@@ -77,7 +77,7 @@
tagOffsets.add(bytes.length);
// Warning: O(n²) algorithm (though, as the tag is assumed to be rather unique
- // in normal cases it will probably much better in practise
+ // in normal cases it will probably much better in practice
// (and n will be low)).
int fromIndex = 0;
while (fromIndex < tagOffsets.length - 1) {
diff --git a/pkg/kernel/lib/class_hierarchy.dart b/pkg/kernel/lib/class_hierarchy.dart
index cf9320c..440da58 100644
--- a/pkg/kernel/lib/class_hierarchy.dart
+++ b/pkg/kernel/lib/class_hierarchy.dart
@@ -491,6 +491,25 @@
return result;
}
+ List<Class> getAllSupertypeClassesForTesting(Class class_) {
+ List<Class?> allClassesByIndex =
+ new List<Class?>.filled(_infoMap.length, null);
+ for (MapEntry<Class, _ClassInfo> c in _infoMap.entries) {
+ allClassesByIndex[c.value.topologicalIndex] = c.key;
+ }
+
+ List<Class> result = [];
+ Uint32List list = _infoMap[class_]!.supertypeIntervalList;
+ for (int i = 0; i < list.length; i += 2) {
+ int from = list[i];
+ int to = list[i + 1];
+ for (int j = from; j < to; j++) {
+ result.add(allClassesByIndex[j]!);
+ }
+ }
+ return result;
+ }
+
_ClassInfo infoFor(Class cls) {
_ClassInfo? info = _infoMap[cls];
if (info == null) {
diff --git a/tools/VERSION b/tools/VERSION
index 02fd046..9a2d9f1 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 17
PATCH 0
-PRERELEASE 77
+PRERELEASE 78
PRERELEASE_PATCH 0
\ No newline at end of file