diff --git a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart index f1d4ff2d411..d577befd927 100644 --- a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart +++ b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart @@ -51,6 +51,31 @@ import 'dill_loader.dart' show DillLoader; import 'dill_type_alias_builder.dart' show DillTypeAliasBuilder; +class LazyLibraryScope extends Scope { + DillLibraryBuilder libraryBuilder; + + LazyLibraryScope(Map local, + Map setters, Scope parent, String debugName, + {bool isModifiable: true}) + : super(local, setters, parent, debugName, isModifiable: isModifiable); + + LazyLibraryScope.top({bool isModifiable: false}) + : this({}, {}, null, "top", + isModifiable: isModifiable); + + Map get local { + if (libraryBuilder == null) throw new StateError("No library builder."); + libraryBuilder.ensureLoaded(); + return super.local; + } + + Map get setters { + if (libraryBuilder == null) throw new StateError("No library builder."); + libraryBuilder.ensureLoaded(); + return super.setters; + } +} + class DillLibraryBuilder extends LibraryBuilder { final Library library; @@ -64,8 +89,38 @@ class DillLibraryBuilder extends LibraryBuilder { bool exportsAlreadyFinalized = false; + // TODO(jensj): These 4 booleans could potentially be merged into a single + // state field. + bool isReadyToBuild = false; + bool isReadyToFinalizeExports = false; + bool isBuilt = false; + bool isBuiltAndMarked = false; + DillLibraryBuilder(this.library, this.loader) - : super(library.fileUri, new Scope.top(), new Scope.top()); + : super(library.fileUri, new LazyLibraryScope.top(), + new LazyLibraryScope.top()) { + LazyLibraryScope lazyScope = scope; + lazyScope.libraryBuilder = this; + LazyLibraryScope lazyExportScope = exportScope; + lazyExportScope.libraryBuilder = this; + } + + void ensureLoaded() { + if (!isReadyToBuild) throw new StateError("Not ready to build."); + isBuiltAndMarked = true; + if (isBuilt) return; + isBuilt = true; + library.classes.forEach(addClass); + library.procedures.forEach(addMember); + library.typedefs.forEach(addTypedef); + library.fields.forEach(addMember); + + if (isReadyToFinalizeExports) { + finalizeExports(); + } else { + throw new StateError("Not ready to finalize exports."); + } + } @override bool get isSynthetic => library.isSynthetic; @@ -174,6 +229,14 @@ class DillLibraryBuilder extends LibraryBuilder { return library.name ?? ""; } + void markAsReadyToBuild() { + isReadyToBuild = true; + } + + void markAsReadyToFinalizeExports() { + isReadyToFinalizeExports = true; + } + void finalizeExports() { if (exportsAlreadyFinalized) return; exportsAlreadyFinalized = true; diff --git a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart index aa5785bddc6..ea0fc73f11e 100644 --- a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart +++ b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart @@ -61,10 +61,7 @@ class DillLoader extends Loader { if (builder.library == null) { unhandled("null", "builder.library", 0, builder.fileUri); } - builder.library.classes.forEach(builder.addClass); - builder.library.procedures.forEach(builder.addMember); - builder.library.typedefs.forEach(builder.addTypedef); - builder.library.fields.forEach(builder.addMember); + builder.markAsReadyToBuild(); } Future buildBody(DillLibraryBuilder builder) { @@ -74,7 +71,7 @@ class DillLoader extends Loader { void finalizeExports() { builders.forEach((Uri uri, LibraryBuilder builder) { DillLibraryBuilder library = builder; - library.finalizeExports(); + library.markAsReadyToFinalizeExports(); }); } diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart index 6c84d0b229d..1d2713eaa52 100644 --- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart +++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart @@ -15,7 +15,8 @@ import 'package:kernel/binary/ast_from_binary.dart' CanonicalNameSdkError, InvalidKernelVersionError; -import 'package:kernel/class_hierarchy.dart' show ClassHierarchy; +import 'package:kernel/class_hierarchy.dart' + show ClassHierarchy, ClosedWorldClassHierarchy; import 'package:kernel/kernel.dart' show @@ -32,6 +33,7 @@ import 'package:kernel/kernel.dart' ProcedureKind, ReturnStatement, Source, + Supertype, TreeNode, TypeParameter; @@ -68,6 +70,8 @@ import 'fasta_codes.dart' import 'hybrid_file_system.dart' show HybridFileSystem; +import 'kernel/kernel_builder.dart' show ClassHierarchyBuilder; + import 'kernel/kernel_library_builder.dart' show KernelLibraryBuilder; import 'kernel/kernel_shadow_ast.dart' show VariableDeclarationJudgment; @@ -90,6 +94,8 @@ class IncrementalCompiler implements IncrementalKernelGenerator { final Ticker ticker; final bool outlineOnly; + bool trackNeededDillLibraries = false; + Set neededDillLibraries; Set invalidatedUris = new Set(); @@ -301,6 +307,19 @@ class IncrementalCompiler implements IncrementalKernelGenerator { uriTranslator); userCode.loader.hierarchy = hierarchy; + if (trackNeededDillLibraries) { + // Reset dill loaders and kernel class hierarchy. + for (LibraryBuilder builder in dillLoadedData.loader.builders.values) { + if (builder is DillLibraryBuilder) { + builder.isBuiltAndMarked = false; + } + } + + if (hierarchy is ClosedWorldClassHierarchy) { + hierarchy.resetUsed(); + } + } + for (LibraryBuilder library in reusedLibraries) { userCode.loader.builders[library.uri] = library; if (library.uri.scheme == "dart" && library.uri.path == "core") { @@ -324,8 +343,23 @@ class IncrementalCompiler implements IncrementalKernelGenerator { componentWithDill = await userCode.buildComponent(verify: c.options.verify); } + hierarchy ??= userCode.loader.hierarchy; recordNonFullComponentForTesting(componentWithDill); + if (trackNeededDillLibraries) { + // Which dill builders were built? + neededDillLibraries = new Set(); + for (LibraryBuilder builder in dillLoadedData.loader.builders.values) { + if (builder is DillLibraryBuilder) { + if (builder.isBuiltAndMarked) { + neededDillLibraries.add(builder.library); + } + } + } + + updateNeededDillLibraresWithHierarchy( + hierarchy, userCode.loader.builderHierarchy); + } if (componentWithDill != null) { this.invalidatedUris.clear(); @@ -388,6 +422,76 @@ class IncrementalCompiler implements IncrementalKernelGenerator { }); } + /// Allows for updating the list of needed libraries. + /// + /// Useful if a class hierarchy has been used externally. + /// Currently there are two different class hierarchies which is unfortunate. + /// For now this method allows the 'ClassHierarchyBuilder' to be null. + /// + /// TODO(jensj,CFE in general): Eventually we should get to a point where we + /// only have one class hierarchy. + /// TODO(jensj): This could probably be a utility method somewhere instead + /// (though handling of the case where all bets are off should probably still + /// live locally). + void updateNeededDillLibraresWithHierarchy( + ClassHierarchy hierarchy, ClassHierarchyBuilder builderHierarchy) { + if (hierarchy is ClosedWorldClassHierarchy && !hierarchy.allBetsOff) { + neededDillLibraries ??= new Set(); + Set classes = new Set(); + List worklist = new List(); + // Get all classes touched by kernel class hierarchy. + List usedClasses = hierarchy.getUsedClasses(); + worklist.addAll(usedClasses); + classes.addAll(usedClasses); + + // Get all classes touched by fasta class hierarchy. + if (builderHierarchy != null) { + for (Class c in builderHierarchy.nodes.keys) { + if (classes.add(c)) worklist.add(c); + } + } + + // Get all supers etc. + while (worklist.isNotEmpty) { + Class c = worklist.removeLast(); + for (Supertype supertype in c.implementedTypes) { + if (classes.add(supertype.classNode)) { + worklist.add(supertype.classNode); + } + } + if (c.mixedInType != null) { + if (classes.add(c.mixedInType.classNode)) { + worklist.add(c.mixedInType.classNode); + } + } + if (c.supertype != null) { + if (classes.add(c.supertype.classNode)) { + worklist.add(c.supertype.classNode); + } + } + } + + // Add any libraries that was used or was in the "parent-chain" of a + // used class. + for (Class c in classes) { + Library library = c.enclosingLibrary; + // Only add if loaded from a dill file. + if (dillLoadedData.loader.builders.containsKey(library.importUri)) { + neededDillLibraries.add(library); + } + } + } else { + // Cannot track in other kernel class hierarchies or + // if all bets are off: Add everything. + neededDillLibraries = new Set(); + for (LibraryBuilder builder in dillLoadedData.loader.builders.values) { + if (builder is DillLibraryBuilder) { + neededDillLibraries.add(builder.library); + } + } + } + } + /// Internal method. void invalidateNotKeptUserBuilders(Set invalidatedUris) { if (modulesToLoad != null && userBuilders != null) { diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart index 8f8605e7cdf..aaea6ab83f3 100644 --- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart +++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart @@ -8,6 +8,8 @@ import 'dart:core' hide MapEntry; import '../constant_context.dart' show ConstantContext; +import '../dill/dill_library_builder.dart' show DillLibraryBuilder; + import '../fasta_codes.dart' as fasta; import '../fasta_codes.dart' show LocatedMessage, Message, noLength, Template; @@ -133,7 +135,7 @@ const noLocation = null; const invalidCollectionElement = const Object(); abstract class BodyBuilder extends ScopeListener - implements ExpressionGeneratorHelper { + implements ExpressionGeneratorHelper, EnsureLoaded { // TODO(ahe): Rename [library] to 'part'. @override final KernelLibraryBuilder library; @@ -903,6 +905,44 @@ abstract class BodyBuilder extends ScopeListener finishVariableMetadata(); } + /// Ensure that the containing library of the [member] has been loaded. + /// + /// This is for instance important for lazy dill library builders where this + /// method has to be called to ensure that + /// a) The library has been fully loaded (and for instance any internal + /// transformation needed has been performed); and + /// b) The library is correctly marked as being used to allow for proper + /// 'dependency pruning'. + void ensureLoaded(Member member) { + if (member == null) return; + Library ensureLibraryLoaded = member.enclosingLibrary; + LibraryBuilder builder = + library.loader.builders[ensureLibraryLoaded.importUri] ?? + library.loader.target.dillTarget.loader + .builders[ensureLibraryLoaded.importUri]; + if (builder is DillLibraryBuilder) { + builder.ensureLoaded(); + } + } + + /// Check if the containing library of the [member] has been loaded. + /// + /// This is designed for use with asserts. + /// See [ensureLoaded] for a description of what 'loaded' means and the ideas + /// behind that. + bool isLoaded(Member member) { + if (member == null) return true; + Library ensureLibraryLoaded = member.enclosingLibrary; + LibraryBuilder builder = + library.loader.builders[ensureLibraryLoaded.importUri] ?? + library.loader.target.dillTarget.loader + .builders[ensureLibraryLoaded.importUri]; + if (builder is DillLibraryBuilder) { + return builder.isBuiltAndMarked; + } + return true; + } + void resolveRedirectingFactoryTargets() { for (StaticInvocation invocation in redirectingFactoryInvocations) { // If the invocation was invalid, it or its parent has already been @@ -927,7 +967,7 @@ abstract class BodyBuilder extends ScopeListener Expression replacementNode; RedirectionTarget redirectionTarget = - getRedirectionTarget(initialTarget, legacyMode: legacyMode); + getRedirectionTarget(initialTarget, this, legacyMode: legacyMode); Member resolvedTarget = redirectionTarget?.target; if (resolvedTarget == null) { @@ -3355,7 +3395,7 @@ abstract class BodyBuilder extends ScopeListener int charLength: noLength}) { // The argument checks for the initial target of redirecting factories // invocations are skipped in Dart 1. - if (!legacyMode || !isRedirectingFactory(target)) { + if (!legacyMode || !isRedirectingFactory(target, helper: this)) { List typeParameters = target.function.typeParameters; if (target is Constructor) { assert(!target.enclosingClass.isAbstract); @@ -3664,7 +3704,7 @@ abstract class BodyBuilder extends ScopeListener (target is Procedure && target.kind == ProcedureKind.Factory)) { Expression invocation; - if (legacyMode && isRedirectingFactory(target)) { + if (legacyMode && isRedirectingFactory(target, helper: this)) { // In legacy mode the checks that are done in [buildStaticInvocation] // on the initial target of a redirecting factory invocation should // be skipped. So we build the invocation nodes directly here without @@ -3690,7 +3730,8 @@ abstract class BodyBuilder extends ScopeListener charLength: nameToken.length); } - if (invocation is StaticInvocation && isRedirectingFactory(target)) { + if (invocation is StaticInvocation && + isRedirectingFactory(target, helper: this)) { redirectingFactoryInvocations.add(invocation); } @@ -5408,6 +5449,11 @@ abstract class BodyBuilder extends ScopeListener } } +abstract class EnsureLoaded { + void ensureLoaded(Member member); + bool isLoaded(Member member); +} + class Operator { final Token token; String get name => token.stringValue; diff --git a/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart b/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart index bcd7ccaa0df..99a1bb6e9dd 100644 --- a/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart +++ b/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart @@ -23,6 +23,8 @@ import 'package:kernel/ast.dart' import 'package:kernel/type_algebra.dart' show Substitution; +import 'body_builder.dart' show EnsureLoaded; + const String letName = "#redirecting_factory"; class RedirectingFactoryBody extends ExpressionStatement { @@ -114,7 +116,8 @@ class RedirectingFactoryBody extends ExpressionStatement { } } -bool isRedirectingFactory(Member member) { +bool isRedirectingFactory(Member member, {EnsureLoaded helper}) { + assert(helper == null || helper.isLoaded(member)); return member is Procedure && member.function.body is RedirectingFactoryBody; } @@ -129,7 +132,8 @@ class RedirectionTarget { RedirectionTarget(this.target, this.typeArguments); } -RedirectionTarget getRedirectionTarget(Procedure member, {bool legacyMode}) { +RedirectionTarget getRedirectionTarget(Procedure member, EnsureLoaded helper, + {bool legacyMode}) { List typeArguments = []..length = member.function.typeParameters.length; for (int i = 0; i < typeArguments.length; i++) { @@ -142,11 +146,14 @@ RedirectionTarget getRedirectionTarget(Procedure member, {bool legacyMode}) { Member tortoise = member; RedirectingFactoryBody tortoiseBody = getRedirectingFactoryBody(tortoise); Member hare = tortoiseBody?.target; + helper.ensureLoaded(hare); RedirectingFactoryBody hareBody = getRedirectingFactoryBody(hare); while (tortoise != hare) { - if (tortoiseBody?.isUnresolved ?? true) + if (tortoiseBody?.isUnresolved ?? true) { return new RedirectionTarget(tortoise, typeArguments); + } Member nextTortoise = tortoiseBody.target; + helper.ensureLoaded(nextTortoise); List nextTypeArguments = tortoiseBody.typeArguments; if (!legacyMode && nextTypeArguments == null) { nextTypeArguments = []; @@ -173,7 +180,9 @@ RedirectionTarget getRedirectionTarget(Procedure member, {bool legacyMode}) { tortoise = nextTortoise; tortoiseBody = getRedirectingFactoryBody(tortoise); + helper.ensureLoaded(hareBody?.target); hare = getRedirectingFactoryBody(hareBody?.target)?.target; + helper.ensureLoaded(hare); hareBody = getRedirectingFactoryBody(hare); } return null; diff --git a/pkg/front_end/test/fasta/ambiguous_export_test.dart b/pkg/front_end/test/fasta/ambiguous_export_test.dart index 8123c39da11..abe0fcc947f 100644 --- a/pkg/front_end/test/fasta/ambiguous_export_test.dart +++ b/pkg/front_end/test/fasta/ambiguous_export_test.dart @@ -32,7 +32,7 @@ main() async { target.loader.appendLibraries(component); DillLibraryBuilder builder = target.loader.read(library.importUri, -1); await target.loader.buildOutline(builder); - builder.finalizeExports(); + builder.markAsReadyToFinalizeExports(); var mainExport = builder.exportScope.local["main"]; Expect.isTrue(mainExport is InvalidTypeBuilder); }); diff --git a/pkg/front_end/test/incremental_load_from_dill_test.dart b/pkg/front_end/test/incremental_load_from_dill_test.dart index 3c68a615dfd..4a7025c29af 100644 --- a/pkg/front_end/test/incremental_load_from_dill_test.dart +++ b/pkg/front_end/test/incremental_load_from_dill_test.dart @@ -405,6 +405,7 @@ Future newWorldTest(List worlds, Map modules, bool omitPlatform) async { } } bool outlineOnly = world["outlineOnly"] == true; + bool skipOutlineBodyCheck = world["skipOutlineBodyCheck"] == true; if (brandNewWorld) { if (world["fromComponent"] == true) { compiler = new TestIncrementalCompiler.fromComponent( @@ -427,6 +428,7 @@ Future newWorldTest(List worlds, Map modules, bool omitPlatform) async { if (modulesToUse != null) { compiler.setModulesToLoadOnNextComputeDelta(modulesToUse); compiler.invalidateAllSources(); + compiler.trackNeededDillLibraries = true; } Stopwatch stopwatch = new Stopwatch()..start(); @@ -434,7 +436,7 @@ Future newWorldTest(List worlds, Map modules, bool omitPlatform) async { entryPoints: entries, fullComponent: brandNewWorld ? false : (noFullComponent ? false : true), simulateTransformer: world["simulateTransformer"]); - if (outlineOnly) { + if (outlineOnly && !skipOutlineBodyCheck) { for (Library lib in component.libraries) { for (Class c in lib.classes) { for (Procedure p in c.procedures) { @@ -457,6 +459,7 @@ Future newWorldTest(List worlds, Map modules, bool omitPlatform) async { print("Compile took ${stopwatch.elapsedMilliseconds} ms"); checkExpectedContent(world, component); + checkNeededDillLibraries(world, compiler.neededDillLibraries, base); if (!noFullComponent) { Set allLibraries = new Set(); @@ -657,6 +660,36 @@ void checkExpectedContent(YamlMap world, Component component) { } } +void checkNeededDillLibraries( + YamlMap world, Set neededDillLibraries, Uri base) { + if (world["neededDillLibraries"] != null) { + List actualContent = new List(); + for (Library lib in neededDillLibraries) { + if (lib.importUri.scheme == "dart") continue; + actualContent.add(lib.importUri); + } + + List expectedContent = new List(); + for (String entry in world["neededDillLibraries"]) { + expectedContent.add(base.resolve(entry)); + } + + doThrow() { + throw "Expected and actual content not the same.\n" + "Expected $expectedContent.\n" + "Got $actualContent"; + } + + if (actualContent.length != expectedContent.length) doThrow(); + Set notInExpected = + actualContent.toSet().difference(expectedContent.toSet()); + Set notInActual = + expectedContent.toSet().difference(actualContent.toSet()); + if (notInExpected.isNotEmpty) doThrow(); + if (notInActual.isNotEmpty) doThrow(); + } +} + String componentToStringSdkFiltered(Component node) { Component c = new Component(); List dartUris = new List(); diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules.yaml index 74d1d072e2d..47752b22c07 100644 --- a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules.yaml +++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules.yaml @@ -78,6 +78,9 @@ worlds: modules: - example_0.1.0 expectedLibraryCount: 3 + neededDillLibraries: + # Needs 'b.dart' only! + - package:example/b.dart expectedContent: org-dartlang-test:///main.dart: - Procedure main @@ -103,6 +106,8 @@ worlds: - example_0.1.0 - foo_1 expectedLibraryCount: 4 + neededDillLibraries: + - package:foo/foo.dart expectedContent: org-dartlang-test:///main.dart: - Procedure main @@ -131,6 +136,8 @@ worlds: - example_0.1.1 - foo_2 expectedLibraryCount: 5 + neededDillLibraries: + - package:foo/foo.dart expectedContent: org-dartlang-test:///main.dart: - Procedure main diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_2.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_2.yaml index f2a10a82120..201d9c03d5e 100644 --- a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_2.yaml +++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_2.yaml @@ -43,6 +43,9 @@ worlds: - foo - example_1 expectedLibraryCount: 3 + neededDillLibraries: + - package:foo/foo.dart + - package:example/a.dart expectedContent: org-dartlang-test:///main.dart: - Procedure main @@ -62,6 +65,9 @@ worlds: - foo - example_2 expectedLibraryCount: 3 + neededDillLibraries: + - package:foo/foo.dart + - package:example/a.dart expectedContent: org-dartlang-test:///main.dart: - Procedure main diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_3.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_3.yaml index c009ea1474d..a98a4f57fc4 100644 --- a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_3.yaml +++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_3.yaml @@ -39,6 +39,8 @@ worlds: package:foo/foo.dart: - Field foo - Field lalala_SimulateTransformer + neededDillLibraries: + - package:foo/foo.dart - entry: main.dart worldType: updated expectInitializeFromDill: false @@ -54,6 +56,8 @@ worlds: modules: - foo2 expectedLibraryCount: 2 + neededDillLibraries: + - package:foo/foo.dart expectedContent: org-dartlang-test:///main.dart: - Procedure main diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_4.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_4.yaml new file mode 100644 index 00000000000..6869e85d6da --- /dev/null +++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_4.yaml @@ -0,0 +1,78 @@ +# Copyright (c) 2019, 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. + +# Compile an application with a number of modules. +# Try out "trickery" in the module dependencies to force needing more or less +# dill libraries. + +type: newworld +strong: true +modules: + moduleB: + moduleB/b.dart: | + import 'package:moduleC/c.dart'; + export 'package:moduleC/c.dart' show baz; + + var mya2 = new A2(); + + class A2 extends A3 { + int bar = 42; + } + moduleB/.packages: | + moduleB:. + moduleC:../moduleC + moduleD:../moduleD + moduleC: + moduleC/c.dart: | + import 'package:moduleD/d.dart'; + + String baz = "42"; + String baz2 = baz3; + + class A3 { + int foo = 42; + } + moduleC/.packages: | + moduleC:. + moduleD:../moduleD + moduleD: + moduleD/d.dart: | + String baz3 = "baz3"; + moduleD/.packages: | + moduleD:. +worlds: + - entry: a.dart + fromComponent: true + sources: + a.dart: | + import "package:moduleB/b.dart"; + + String foo = baz; + var x = mya2.bar; + .packages: | + moduleB:moduleB + moduleC:moduleC + moduleD:moduleD + modules: + - moduleB + - moduleC + - moduleD + expectedLibraryCount: 4 + neededDillLibraries: + # 'd.dart' not needed. + - package:moduleB/b.dart + - package:moduleC/c.dart + expectedContent: + org-dartlang-test:///a.dart: + - Field foo + - Field x + package:moduleB/b.dart: + - Class A2 + - Field mya2 + package:moduleC/c.dart: + - Class A3 + - Field baz + - Field baz2 + package:moduleD/d.dart: + - Field baz3 \ No newline at end of file diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_5.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_5.yaml new file mode 100644 index 00000000000..449b3195dd9 --- /dev/null +++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_5.yaml @@ -0,0 +1,80 @@ +# Copyright (c) 2019, 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. + +# Compile an application with a number of modules. +# Try out "trickery" in the module dependencies to force needing more or less +# dill libraries. + +type: newworld +strong: true +modules: + moduleB: + moduleB/b.dart: | + import 'package:moduleC/c.dart'; + + var bVar = 42; + var bVarFromC = baz2; + var mya2 = new A2(); + + class A2 extends A3 { + int bar = 42; + } + moduleB/.packages: | + moduleB:. + moduleC:../moduleC + moduleD:../moduleD + moduleC: + moduleC/c.dart: | + import 'package:moduleD/d.dart'; + + String baz = "42"; + String baz2 = baz3; + + class A3 { + int foo = 42; + } + moduleC/.packages: | + moduleC:. + moduleD:../moduleD + moduleD: + moduleD/d.dart: | + String baz3 = "baz3"; + moduleD/.packages: | + moduleD:. +worlds: + - entry: a.dart + fromComponent: true + sources: + a.dart: | + import "package:moduleB/b.dart"; + + var foo = bVar; + var foo2 = bVarFromC; + .packages: | + moduleB:moduleB + moduleC:moduleC + moduleD:moduleD + modules: + - moduleB + - moduleC + - moduleD + expectedLibraryCount: 4 + neededDillLibraries: + # Only b.dart needed. + - package:moduleB/b.dart + expectedContent: + org-dartlang-test:///a.dart: + - Field foo + - Field foo2 + package:moduleB/b.dart: + - Class A2 + - Field bVar + - Field bVarFromC + - Field mya2 + package:moduleC/c.dart: + - Class A3 + - Field baz + - Field baz2 + package:moduleD/d.dart: + - Field baz3 \ No newline at end of file diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_6.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_6.yaml new file mode 100644 index 00000000000..89367ec7454 --- /dev/null +++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_6.yaml @@ -0,0 +1,86 @@ +# Copyright (c) 2019, 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. + +# Compile an application with a number of modules. +# Try out "trickery" in the module dependencies to force needing more or less +# dill libraries. + +type: newworld +strong: true +modules: + moduleB: + moduleB/b.dart: | + import 'package:moduleC/c.dart'; + + var bVar = 42; + var bVarFromC = baz2; + var mya2 = new A2(); + + class A2 extends A3 { + int bar = 42; + } + moduleB/.packages: | + moduleB:. + moduleC:../moduleC + moduleD:../moduleD + moduleC: + moduleC/c.dart: | + import 'package:moduleD/d.dart'; + + String baz = "42"; + String baz2 = baz3; + + class A3 { + int foo = 42; + } + moduleC/.packages: | + moduleC:. + moduleD:../moduleD + moduleD: + moduleD/d.dart: | + String baz3 = "baz3"; + moduleD/.packages: | + moduleD:. +worlds: + - entry: a.dart + fromComponent: true + sources: + a.dart: | + import "package:moduleB/b.dart"; + + var foo = bVar; + var foo2 = bVarFromC; + + class A1 extends A2 { + String fooMethod() => "42!"; + } + .packages: | + moduleB:moduleB + moduleC:moduleC + moduleD:moduleD + modules: + - moduleB + - moduleC + - moduleD + expectedLibraryCount: 4 + neededDillLibraries: + # A class in 'a.dart' has a super in 'c.dart'. + - package:moduleB/b.dart + - package:moduleC/c.dart + expectedContent: + org-dartlang-test:///a.dart: + - Field foo + - Field foo2 + - Class A1 + package:moduleB/b.dart: + - Class A2 + - Field bVar + - Field bVarFromC + - Field mya2 + package:moduleC/c.dart: + - Class A3 + - Field baz + - Field baz2 + package:moduleD/d.dart: + - Field baz3 \ No newline at end of file diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_7.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_7.yaml new file mode 100644 index 00000000000..3ad421d05a9 --- /dev/null +++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_7.yaml @@ -0,0 +1,123 @@ +# Copyright (c) 2019, 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. + +# Compile an application with a number of modules. +# Try out "trickery" in the module dependencies to force needing more or less +# dill libraries. + +type: newworld +strong: true +modules: + module: + module/lib1.dart: | + import 'lib3.dart'; + + class Class1 { + Class3a get c3a {} + } + module/lib2.dart: | + import 'lib4.dart'; + + class Class2 { + void cl4() { + Class4 class4 = new Class4(); + print(class4); + } + } + module/lib3.dart: | + class Class3a { + Class3b get c3b {} + } + + class Class3b { + String str() {} + } + module/lib4.dart: | + class Class4 {} + module/.packages: | + module:. +worlds: + - entry: compileme.dart + fromComponent: true + sources: + compileme.dart: | + import 'package:module/lib1.dart'; + import 'package:module/lib2.dart'; + + main() { + Class2 class2 = new Class2(); + print(class2); + } + + class Foo { + Class1 class1() { + Class1 class1 = new Class1(); + class1.c3a.c3b.str(); + return class1; + } + } + .packages: | + module:module + modules: + - module + expectedLibraryCount: 5 + neededDillLibraries: + - package:module/lib1.dart + - package:module/lib2.dart + - package:module/lib3.dart + expectedContent: + org-dartlang-test:///compileme.dart: + - Class Foo + - Procedure main + package:module/lib1.dart: + - Class Class1 + package:module/lib2.dart: + - Class Class2 + package:module/lib3.dart: + - Class Class3a + - Class Class3b + package:module/lib4.dart: + - Class Class4 + - entry: compileme.dart + outlineOnly: true + skipOutlineBodyCheck: true + sources: + compileme.dart: | + import 'package:module/lib1.dart'; + import 'package:module/lib2.dart'; + + main() { + Class2 class2 = new Class2(); + print(class2); + } + + class Foo { + Class1 class1() { + Class1 class1 = new Class1(); + class1.c3a.c3b.str(); + return class1; + } + } + .packages: | + module:module + modules: + - module + expectedLibraryCount: 5 + neededDillLibraries: + # This is the outline version. It doesn't use lib3.dart. + - package:module/lib1.dart + - package:module/lib2.dart + expectedContent: + org-dartlang-test:///compileme.dart: + - Class Foo + - Procedure main + package:module/lib1.dart: + - Class Class1 + package:module/lib2.dart: + - Class Class2 + package:module/lib3.dart: + - Class Class3a + - Class Class3b + package:module/lib4.dart: + - Class Class4 diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_8.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_8.yaml new file mode 100644 index 00000000000..dbe8c91d712 --- /dev/null +++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_8.yaml @@ -0,0 +1,61 @@ +# Copyright (c) 2019, 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. + +# Compile an application with a number of modules. +# Try out "trickery" in the module dependencies to force needing more or less +# dill libraries. + +type: newworld +strong: true +modules: + module: + module/lib1.dart: | + import 'lib2.dart'; + + abstract class XSet { + factory XSet.identity() = XLinkedHashSet.identity; + } + module/lib2.dart: | + import 'lib1.dart'; + import 'lib3.dart'; + + class XLinkedHashSet implements XSet { + factory XLinkedHashSet.identity() = XIdentityHashSet; + } + module/lib3.dart: | + import 'lib2.dart'; + + class XIdentityHashSet implements XLinkedHashSet { + XIdentityHashSet(); + } + module/.packages: | + module:. +worlds: + - entry: compileme.dart + fromComponent: true + sources: + compileme.dart: | + import 'package:module/lib1.dart'; + + main() { + XSet history = new XSet.identity(); + } + .packages: | + module:module + modules: + - module + expectedLibraryCount: 4 + neededDillLibraries: + - package:module/lib1.dart + - package:module/lib2.dart + - package:module/lib3.dart + expectedContent: + org-dartlang-test:///compileme.dart: + - Procedure main + package:module/lib1.dart: + - Class XSet + package:module/lib2.dart: + - Class XLinkedHashSet + package:module/lib3.dart: + - Class XIdentityHashSet diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/crash_test_1.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/crash_test_1.yaml new file mode 100644 index 00000000000..404e5a520b3 --- /dev/null +++ b/pkg/front_end/testcases/incremental_initialize_from_dill/crash_test_1.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2019, 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. + +# This have crashed at one point (assertion error). + +type: newworld +strong: true +worlds: + - entry: main.dart + sources: + main.dart: | + class C { + C(); + factory C.e4() async = C; + } + + void main() { + var c = new C.e4(); + } + expectedLibraryCount: 1 + errors: true diff --git a/pkg/kernel/lib/class_hierarchy.dart b/pkg/kernel/lib/class_hierarchy.dart index ed156b124aa..7be58d15c99 100644 --- a/pkg/kernel/lib/class_hierarchy.dart +++ b/pkg/kernel/lib/class_hierarchy.dart @@ -332,17 +332,18 @@ class _ClassInfoSubtype { class _ClosedWorldClassHierarchySubtypes implements ClassHierarchySubtypes { final ClosedWorldClassHierarchy hierarchy; final List _classesByTopDownIndex; - final Map _infoFor = {}; + final Map _infoMap = {}; bool invalidated = false; _ClosedWorldClassHierarchySubtypes(this.hierarchy) - : _classesByTopDownIndex = new List(hierarchy._infoFor.length) { - if (hierarchy._infoFor.isNotEmpty) { - for (Class class_ in hierarchy._infoFor.keys) { - _infoFor[class_] = new _ClassInfoSubtype(hierarchy._infoFor[class_]); + : _classesByTopDownIndex = new List(hierarchy._infoMap.length) { + hierarchy.allBetsOff = true; + if (hierarchy._infoMap.isNotEmpty) { + for (Class class_ in hierarchy._infoMap.keys) { + _infoMap[class_] = new _ClassInfoSubtype(hierarchy._infoMap[class_]); } - _topDownSortVisit(_infoFor[hierarchy._infoFor.keys.first]); + _topDownSortVisit(_infoMap[hierarchy._infoMap.keys.first]); } } @@ -356,17 +357,17 @@ class _ClosedWorldClassHierarchySubtypes implements ClassHierarchySubtypes { _classesByTopDownIndex[index] = subInfo.classInfo.classNode; var subtypeSetBuilder = new _IntervalListBuilder()..addSingleton(index); for (_ClassInfo subtype in subInfo.classInfo.directExtenders) { - _ClassInfoSubtype subtypeInfo = _infoFor[subtype.classNode]; + _ClassInfoSubtype subtypeInfo = _infoMap[subtype.classNode]; _topDownSortVisit(subtypeInfo); subtypeSetBuilder.addIntervalList(subtypeInfo.subtypeIntervalList); } for (_ClassInfo subtype in subInfo.classInfo.directMixers) { - _ClassInfoSubtype subtypeInfo = _infoFor[subtype.classNode]; + _ClassInfoSubtype subtypeInfo = _infoMap[subtype.classNode]; _topDownSortVisit(subtypeInfo); subtypeSetBuilder.addIntervalList(subtypeInfo.subtypeIntervalList); } for (_ClassInfo subtype in subInfo.classInfo.directImplementers) { - _ClassInfoSubtype subtypeInfo = _infoFor[subtype.classNode]; + _ClassInfoSubtype subtypeInfo = _infoMap[subtype.classNode]; _topDownSortVisit(subtypeInfo); subtypeSetBuilder.addIntervalList(subtypeInfo.subtypeIntervalList); } @@ -399,7 +400,7 @@ class _ClosedWorldClassHierarchySubtypes implements ClassHierarchySubtypes { ClassSet getSubtypesOf(Class class_) { if (invalidated) throw "This datastructure has been invalidated"; Set result = new Set(); - Uint32List list = _infoFor[class_].subtypeIntervalList; + Uint32List list = _infoMap[class_].subtypeIntervalList; for (int i = 0; i < list.length; i += 2) { int from = list[i]; int to = list[i + 1]; @@ -433,17 +434,49 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { } /// The insert order is important. - final Map _infoFor = + final Map _infoMap = new LinkedHashMap(); + + _ClassInfo infoFor(Class c) { + _ClassInfo info = _infoMap[c]; + info?.used = true; + return info; + } + + List getUsedClasses() { + List result = new List(); + for (_ClassInfo classInfo in _infoMap.values) { + if (classInfo.used) { + result.add(classInfo.classNode); + } + } + return result; + } + + void resetUsed() { + for (_ClassInfo classInfo in _infoMap.values) { + classInfo.used = false; + } + allBetsOff = false; + } + final Set knownLibraries = new Set(); + bool allBetsOff = false; /// Recorded errors for classes we have already calculated the class hierarchy /// for, but will have to be reissued when re-using the calculation. final Map> _recordedAmbiguousSupertypes = new LinkedHashMap>(); - Iterable get classes => _infoFor.keys; - int get numberOfClasses => _infoFor.length; + Iterable get classes { + allBetsOff = true; + return _infoMap.keys; + } + + int get numberOfClasses { + allBetsOff = true; + return _infoMap.length; + } _ClosedWorldClassHierarchySubtypes _cachedClassHierarchySubtypes; @@ -461,24 +494,25 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { @override Iterable getOrderedClasses(Iterable unordered) { var unorderedSet = unordered.toSet(); - return _infoFor.keys.where(unorderedSet.contains); + for (Class c in unordered) _infoMap[c]?.used = true; + return _infoMap.keys.where(unorderedSet.contains); } @override bool isSubclassOf(Class subclass, Class superclass) { if (identical(subclass, superclass)) return true; - return _infoFor[subclass].isSubclassOf(_infoFor[superclass]); + return infoFor(subclass).isSubclassOf(infoFor(superclass)); } @override bool isSubtypeOf(Class subtype, Class superclass) { if (identical(subtype, superclass)) return true; - return _infoFor[subtype].isSubtypeOf(_infoFor[superclass]); + return infoFor(subtype).isSubtypeOf(infoFor(superclass)); } @override bool isUsedAsMixin(Class class_) { - return _infoFor[class_].directMixers.isNotEmpty; + return infoFor(class_).directMixers.isNotEmpty; } List<_ClassInfo> _getRankedSuperclassInfos(_ClassInfo info) { @@ -494,7 +528,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { lastInfo = nextInfo; var classNode = nextInfo.classNode; void addToHeap(Supertype supertype) { - heap.add(_infoFor[supertype.classNode]); + heap.add(infoFor(supertype.classNode)); } if (classNode.supertype != null) addToHeap(classNode.supertype); @@ -526,8 +560,8 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { // Compute the list of superclasses for both types, with the above // optimization. - _ClassInfo info1 = _infoFor[type1.classNode]; - _ClassInfo info2 = _infoFor[type2.classNode]; + _ClassInfo info1 = infoFor(type1.classNode); + _ClassInfo info2 = infoFor(type2.classNode); List<_ClassInfo> classes1; List<_ClassInfo> classes2; if (identical(info1, info2) || info1.isSubtypeOf(info2)) { @@ -603,11 +637,11 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { @override Supertype getClassAsInstanceOf(Class class_, Class superclass) { if (identical(class_, superclass)) return class_.asThisSupertype; - _ClassInfo info = _infoFor[class_]; + _ClassInfo info = infoFor(class_); if (info == null) { throw "${class_.fileUri}: No class info for ${class_.name}"; } - _ClassInfo superInfo = _infoFor[superclass]; + _ClassInfo superInfo = infoFor(superclass); if (superInfo == null) { throw "${superclass.fileUri}: No class info for ${superclass.name}"; } @@ -626,7 +660,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { @override Member getDispatchTarget(Class class_, Name name, {bool setter: false}) { - _ClassInfo info = _infoFor[class_]; + _ClassInfo info = infoFor(class_); List list = setter ? info.implementedSetters : info.implementedGettersAndCalls; return ClassHierarchy.findMemberByName(list, name); @@ -634,7 +668,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { @override List getDispatchTargets(Class class_, {bool setters: false}) { - _ClassInfo info = _infoFor[class_]; + _ClassInfo info = infoFor(class_); return setters ? info.implementedSetters : info.implementedGettersAndCalls; } @@ -646,12 +680,12 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { @override List getInterfaceMembers(Class class_, {bool setters: false}) { - return _buildInterfaceMembers(class_, _infoFor[class_], setters: setters); + return _buildInterfaceMembers(class_, infoFor(class_), setters: setters); } @override List getDeclaredMembers(Class class_, {bool setters: false}) { - var info = _infoFor[class_]; + var info = infoFor(class_); return setters ? info.declaredSetters : info.declaredGettersAndCalls; } @@ -659,7 +693,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { void forEachOverridePair(Class class_, callback(Member declaredMember, Member interfaceMember, bool isSetter), {bool crossGettersSetters: false}) { - _ClassInfo info = _infoFor[class_]; + _ClassInfo info = infoFor(class_); for (var supertype in class_.supers) { var superclass = supertype.classNode; var superGetters = getInterfaceMembers(superclass); @@ -697,7 +731,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { @override List genericSupertypesOf(Class class_) { - final supertypes = _infoFor[class_].genericSuperTypes; + final supertypes = infoFor(class_).genericSuperTypes; if (supertypes == null) return const []; // Multiple supertypes can arise from ambiguous supertypes. The first // supertype is the real one; the others are purely informational. @@ -712,18 +746,18 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { for (Library lib in removedLibraries) { if (!knownLibraries.contains(lib)) continue; for (Class class_ in lib.classes) { - _ClassInfo info = _infoFor[class_]; + _ClassInfo info = _infoMap[class_]; if (class_.supertype != null) { - _infoFor[class_.supertype.classNode]?.directExtenders?.remove(info); + _infoMap[class_.supertype.classNode]?.directExtenders?.remove(info); } if (class_.mixedInType != null) { - _infoFor[class_.mixedInType.classNode]?.directMixers?.remove(info); + _infoMap[class_.mixedInType.classNode]?.directMixers?.remove(info); } for (var supertype in class_.implementedTypes) { - _infoFor[supertype.classNode]?.directImplementers?.remove(info); + _infoMap[supertype.classNode]?.directImplementers?.remove(info); } - _infoFor.remove(class_); + _infoMap.remove(class_); _recordedAmbiguousSupertypes.remove(class_); } knownLibraries.remove(lib); @@ -776,7 +810,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { Set<_ClassInfo> processedClasses = new Set<_ClassInfo>(); List<_ClassInfo> worklist = <_ClassInfo>[]; for (Class class_ in classes) { - _ClassInfo info = _infoFor[class_]; + _ClassInfo info = infoFor(class_); worklist.add(info); } @@ -791,7 +825,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { infos.addAll(processedClasses); } else { for (Class class_ in classes) { - _ClassInfo info = _infoFor[class_]; + _ClassInfo info = infoFor(class_); infos.add(info); } } @@ -816,11 +850,11 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { } bool sanityCheckAlsoKnowsParentAndLibrary() { - for (Class c in _infoFor.keys) { + for (Class c in _infoMap.keys) { if (!knownLibraries.contains(c.enclosingLibrary)) { throw new StateError("Didn't know library of $c (from ${c.fileUri})"); } - if (c.supertype != null && _infoFor[c.supertype.classNode] == null) { + if (c.supertype != null && _infoMap[c.supertype.classNode] == null) { throw new StateError("Didn't know parent of $c (from ${c.fileUri})"); } } @@ -837,7 +871,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { if (type.classNode == superclass) { return superclass.asThisSupertype; } - var map = _infoFor[type.classNode]?.genericSuperTypes; + var map = infoFor(type.classNode)?.genericSuperTypes; return map == null ? null : map[superclass]?.first; } @@ -850,7 +884,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { knownLibraries.add(library); } - _initializeTopologicallySortedClasses(_infoFor.keys, 0); + _initializeTopologicallySortedClasses(_infoMap.keys, 0); } /// - Build index of direct children. @@ -864,15 +898,15 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { Iterable classes, int expectedStartingTopologicalIndex) { int i = expectedStartingTopologicalIndex; for (Class class_ in classes) { - _ClassInfo info = _infoFor[class_]; + _ClassInfo info = _infoMap[class_]; if (class_.supertype != null) { - _infoFor[class_.supertype.classNode].directExtenders.add(info); + _infoMap[class_.supertype.classNode].directExtenders.add(info); } if (class_.mixedInType != null) { - _infoFor[class_.mixedInType.classNode].directMixers.add(info); + _infoMap[class_.mixedInType.classNode].directMixers.add(info); } for (var supertype in class_.implementedTypes) { - _infoFor[supertype.classNode].directImplementers.add(info); + _infoMap[supertype.classNode].directImplementers.add(info); } _collectSupersForClass(class_); @@ -909,7 +943,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { int _topSortIndex = 0; int _topologicalSortVisit(Class classNode, Set beingVisited, {List orderedList}) { - var info = _infoFor[classNode]; + var info = _infoMap[classNode]; if (info != null) { return info.depth; } @@ -943,7 +977,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { _buildImplementedMembers(classNode, info); info.topologicalIndex = _topSortIndex++; - _infoFor[classNode] = info; + _infoMap[classNode] = info; orderedList?.add(classNode); beingVisited.remove(classNode); return info.depth = superDepth + 1; @@ -951,7 +985,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { void _buildDeclaredMembers(Class classNode, _ClassInfo info) { if (classNode.mixedInType != null) { - _ClassInfo mixedInfo = _infoFor[classNode.mixedInType.classNode]; + _ClassInfo mixedInfo = _infoMap[classNode.mixedInType.classNode]; List declaredGettersAndCalls = []; for (Member mixinMember in mixedInfo.declaredGettersAndCalls) { @@ -1004,7 +1038,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { if (classNode.supertype == null) { inheritedMembers = inheritedSetters = const []; } else { - _ClassInfo superInfo = _infoFor[classNode.supertype.classNode]; + _ClassInfo superInfo = _infoMap[classNode.supertype.classNode]; inheritedMembers = superInfo.implementedGettersAndCalls; inheritedSetters = superInfo.implementedSetters; } @@ -1030,7 +1064,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { void inheritFrom(Supertype type) { if (type == null) return; List inherited = _buildInterfaceMembers( - type.classNode, _infoFor[type.classNode], + type.classNode, _infoMap[type.classNode], setters: setters); inherited = _getUnshadowedInheritedMembers(declared, inherited); allInheritedMembers = @@ -1136,7 +1170,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { } void _recordSuperTypes(_ClassInfo subInfo, Supertype supertype) { - _ClassInfo superInfo = _infoFor[supertype.classNode]; + _ClassInfo superInfo = _infoMap[supertype.classNode]; if (supertype.typeArguments.isEmpty) { if (superInfo.genericSuperTypes == null) return; // Copy over the super type entries. @@ -1169,7 +1203,7 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { /// Note that the super class and super types of the class must already have /// had their supers collected. void _collectSupersForClass(Class class_) { - _ClassInfo info = _infoFor[class_]; + _ClassInfo info = _infoMap[class_]; var superclassSetBuilder = new _IntervalListBuilder() ..addSingleton(info.topologicalIndex); @@ -1177,20 +1211,20 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { ..addSingleton(info.topologicalIndex); if (class_.supertype != null) { - _ClassInfo supertypeInfo = _infoFor[class_.supertype.classNode]; + _ClassInfo supertypeInfo = _infoMap[class_.supertype.classNode]; superclassSetBuilder .addIntervalList(supertypeInfo.superclassIntervalList); supertypeSetBuilder.addIntervalList(supertypeInfo.supertypeIntervalList); } if (class_.mixedInType != null) { - _ClassInfo mixedInTypeInfo = _infoFor[class_.mixedInType.classNode]; + _ClassInfo mixedInTypeInfo = _infoMap[class_.mixedInType.classNode]; supertypeSetBuilder .addIntervalList(mixedInTypeInfo.supertypeIntervalList); } for (Supertype supertype in class_.implementedTypes) { - _ClassInfo supertypeInfo = _infoFor[supertype.classNode]; + _ClassInfo supertypeInfo = _infoMap[supertype.classNode]; supertypeSetBuilder.addIntervalList(supertypeInfo.supertypeIntervalList); } @@ -1205,8 +1239,8 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { /// internal data structure is. List getExpenseHistogram() { var result = []; - for (Class class_ in _infoFor.keys) { - var info = _infoFor[class_]; + for (Class class_ in _infoMap.keys) { + var info = _infoMap[class_]; int intervals = info.supertypeIntervalList.length ~/ 2; if (intervals >= result.length) { int oldLength = result.length; @@ -1226,8 +1260,8 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { double getCompressionRatio() { int intervals = 0; int sizes = 0; - for (Class class_ in _infoFor.keys) { - var info = _infoFor[class_]; + for (Class class_ in _infoMap.keys) { + var info = _infoMap[class_]; intervals += (info.superclassIntervalList.length + info.supertypeIntervalList.length) ~/ 2; @@ -1241,8 +1275,8 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { /// Returns the number of entries in hash tables storing hierarchy data. int getSuperTypeHashTableSize() { int sum = 0; - for (Class class_ in _infoFor.keys) { - sum += _infoFor[class_].genericSuperTypes?.length ?? 0; + for (Class class_ in _infoMap.keys) { + sum += _infoMap[class_].genericSuperTypes?.length ?? 0; } return sum; } @@ -1334,6 +1368,7 @@ int _intervalListSize(Uint32List intervalList) { } class _ClassInfo { + bool used = false; final Class classNode; int topologicalIndex = 0; int depth = 0;