Implement ClassHierarchyBuilder.getLegacyLeastUpperBound
Change-Id: Id946a8e49ef414e5d2f6439d15e6cb134c9ccb83
Reviewed-on: https://dart-review.googlesource.com/c/93425
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
index a47bf6c..f902c31 100644
--- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
@@ -195,6 +195,43 @@
.substituteType(supertype.build(null));
}
+ InterfaceType getKernelLegacyLeastUpperBound(
+ InterfaceType type1, InterfaceType type2) {
+ if (type1 == type2) return type1;
+ ClassHierarchyNode node1 = getNodeFromKernelClass(type1.classNode);
+ ClassHierarchyNode node2 = getNodeFromKernelClass(type2.classNode);
+ Set<ClassHierarchyNode> nodes1 = node1.computeAllSuperNodes(this).toSet();
+ List<ClassHierarchyNode> nodes2 = node2.computeAllSuperNodes(this);
+ List<ClassHierarchyNode> common = <ClassHierarchyNode>[];
+
+ for (int i = 0; i < nodes2.length; i++) {
+ ClassHierarchyNode node = nodes2[i];
+ if (node == null) continue;
+ if (nodes1.contains(node)) {
+ DartType candidate1 = getKernelTypeAsInstanceOf(type1, node.cls.target);
+ DartType candidate2 = getKernelTypeAsInstanceOf(type2, node.cls.target);
+ if (candidate1 == candidate2) {
+ common.add(node);
+ }
+ }
+ }
+
+ if (common.length == 1) return objectKernelClass.rawType;
+ common.sort(ClassHierarchyNode.compareMaxInheritancePath);
+
+ for (int i = 0; i < common.length - 1; i++) {
+ ClassHierarchyNode node = common[i];
+ if (node.maxInheritancePath != common[i + 1].maxInheritancePath) {
+ return getKernelTypeAsInstanceOf(type1, node.cls.target);
+ } else {
+ do {
+ i++;
+ } while (node.maxInheritancePath == common[i + 1].maxInheritancePath);
+ }
+ }
+ return objectKernelClass.rawType;
+ }
+
static ClassHierarchyBuilder build(
KernelClassBuilder objectClass,
List<KernelClassBuilder> classes,
@@ -867,6 +904,27 @@
this.interfaces,
this.maxInheritancePath);
+ /// Returns a list of all supertypes of [cls], including this node.
+ List<ClassHierarchyNode> computeAllSuperNodes(
+ ClassHierarchyBuilder hierarchy) {
+ List<ClassHierarchyNode> result = new List<ClassHierarchyNode>(
+ 1 + superclasses.length + interfaces.length);
+ for (int i = 0; i < superclasses.length; i++) {
+ Declaration declaration = superclasses[i].declaration;
+ if (declaration is KernelClassBuilder) {
+ result[i] = hierarchy.getNodeFromClass(declaration);
+ }
+ }
+ for (int i = 0; i < interfaces.length; i++) {
+ Declaration declaration = interfaces[i].declaration;
+ if (declaration is KernelClassBuilder) {
+ result[i + superclasses.length] =
+ hierarchy.getNodeFromClass(declaration);
+ }
+ }
+ return result..last = this;
+ }
+
String toString([StringBuffer sb]) {
sb ??= new StringBuffer();
sb
@@ -922,6 +980,11 @@
..writeln();
}
}
+
+ static int compareMaxInheritancePath(
+ ClassHierarchyNode a, ClassHierarchyNode b) {
+ return b.maxInheritancePath.compareTo(a.maxInheritancePath);
+ }
}
class MergeResult {
@@ -1058,7 +1121,6 @@
@override
InterfaceType getLegacyLeastUpperBound(
InterfaceType type1, InterfaceType type2) {
- // TODO(ahe): Compute the actual LUB.
- return type1;
+ return hierarchy.getKernelLegacyLeastUpperBound(type1, type2);
}
}
diff --git a/pkg/front_end/test/fasta/types/fasta_legacy_upper_bound_test.dart b/pkg/front_end/test/fasta/types/fasta_legacy_upper_bound_test.dart
new file mode 100644
index 0000000..5e53470
--- /dev/null
+++ b/pkg/front_end/test/fasta/types/fasta_legacy_upper_bound_test.dart
@@ -0,0 +1,67 @@
+// 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 file.
+
+import "package:kernel/ast.dart" show DartType;
+
+import "package:kernel/core_types.dart" show CoreTypes;
+
+import "package:kernel/target/targets.dart" show NoneTarget, TargetFlags;
+
+import "package:front_end/src/api_prototype/compiler_options.dart"
+ show CompilerOptions;
+
+import "package:front_end/src/base/processed_options.dart"
+ show ProcessedOptions;
+
+import "package:front_end/src/fasta/compiler_context.dart" show CompilerContext;
+
+import "package:front_end/src/fasta/dill/dill_loader.dart" show DillLoader;
+
+import "package:front_end/src/fasta/dill/dill_target.dart" show DillTarget;
+
+import "package:front_end/src/fasta/kernel/kernel_builder.dart"
+ show ClassHierarchyBuilder, KernelClassBuilder;
+
+import "package:front_end/src/fasta/ticker.dart" show Ticker;
+
+import "legacy_upper_bound_helper.dart" show LegacyUpperBoundTest;
+
+class FastaLegacyUpperBoundTest extends LegacyUpperBoundTest {
+ final Ticker ticker;
+ final CompilerContext context;
+
+ ClassHierarchyBuilder hierarchy;
+
+ FastaLegacyUpperBoundTest(this.ticker, this.context);
+
+ @override
+ Future<void> parseComponent(String source) async {
+ await super.parseComponent(source);
+
+ DillTarget target = new DillTarget(
+ ticker,
+ await context.options.getUriTranslator(),
+ new NoneTarget(new TargetFlags()));
+ final DillLoader loader = target.loader;
+ loader.appendLibraries(component);
+ await target.buildOutlines();
+ KernelClassBuilder objectClass = loader.coreLibrary["Object"];
+ hierarchy = new ClassHierarchyBuilder(
+ objectClass, loader, new CoreTypes(component));
+ }
+
+ @override
+ DartType getLegacyLeastUpperBound(DartType a, DartType b) {
+ return hierarchy.getKernelLegacyLeastUpperBound(a, b);
+ }
+}
+
+main() {
+ final Ticker ticker = new Ticker();
+ final CompilerContext context = new CompilerContext(new ProcessedOptions(
+ options: new CompilerOptions()
+ ..packagesFileUri = Uri.base.resolve(".packages")));
+ context.runInContext<void>(
+ (_) => new FastaLegacyUpperBoundTest(ticker, context).test());
+}
diff --git a/pkg/front_end/test/fasta/types/kernel_type_parser.dart b/pkg/front_end/test/fasta/types/kernel_type_parser.dart
index 5d77b7f..5bf1d1c 100644
--- a/pkg/front_end/test/fasta/types/kernel_type_parser.dart
+++ b/pkg/front_end/test/fasta/types/kernel_type_parser.dart
@@ -49,6 +49,7 @@
KernelEnvironment libraryEnvironment =
new KernelEnvironment(uri, uri).extend(coreEnvironment.declarations);
Library library = parseLibrary(uri, source, environment: libraryEnvironment);
+ library.name = "lib";
return new Component(libraries: <Library>[coreLibrary, library]);
}