Add SetTypeMask.
Change-Id: I9f202506c364cc1387efa8cea4cca6038f350470
Reviewed-on: https://dart-review.googlesource.com/c/92146
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
index 4a118d1..abd60ae 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
@@ -29,6 +29,7 @@
part 'flat_type_mask.dart';
part 'forwarding_type_mask.dart';
part 'map_type_mask.dart';
+part 'set_type_mask.dart';
part 'type_mask.dart';
part 'union_type_mask.dart';
part 'value_type_mask.dart';
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart
new file mode 100644
index 0000000..fb0a7e2
--- /dev/null
+++ b/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart
@@ -0,0 +1,116 @@
+// 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.
+
+part of masks;
+
+/// A [SetTypeMask] is a [TypeMask] for a specific allocation site of a set
+/// (currently only the internal Set class) that will get specialized once the
+/// [TypeGraphInferrer] phase finds an element type for it.
+class SetTypeMask extends AllocationTypeMask {
+ /// Tag used for identifying serialized [SetTypeMask] objects in a debugging
+ /// data stream.
+ static const String tag = 'set-type-mask';
+
+ final TypeMask forwardTo;
+
+ // The [Node] where this type mask was created.
+ final ir.TreeNode allocationNode;
+
+ // The [Entity] where this type mask was created.
+ final MemberEntity allocationElement;
+
+ // The element type of this set.
+ final TypeMask elementType;
+
+ SetTypeMask(this.forwardTo, this.allocationNode, this.allocationElement,
+ this.elementType);
+
+ /// Deserializes a [SetTypeMask] object from [source].
+ factory SetTypeMask.readFromDataSource(
+ DataSource source, JClosedWorld closedWorld) {
+ source.begin(tag);
+ TypeMask forwardTo = new TypeMask.readFromDataSource(source, closedWorld);
+ ir.TreeNode allocationNode = source.readTreeNodeOrNull();
+ MemberEntity allocationElement = source.readMemberOrNull();
+ TypeMask elementType = new TypeMask.readFromDataSource(source, closedWorld);
+ source.end(tag);
+ return new SetTypeMask(
+ forwardTo, allocationNode, allocationElement, elementType);
+ }
+
+ /// Serializes this [SetTypeMask] to [sink].
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(TypeMaskKind.set);
+ sink.begin(tag);
+ forwardTo.writeToDataSink(sink);
+ sink.writeTreeNodeOrNull(allocationNode);
+ sink.writeMemberOrNull(allocationElement);
+ elementType.writeToDataSink(sink);
+ sink.end(tag);
+ }
+
+ @override
+ TypeMask nullable() => isNullable
+ ? this
+ : new SetTypeMask(
+ forwardTo.nullable(), allocationNode, allocationElement, elementType);
+
+ @override
+ TypeMask nonNullable() => isNullable
+ ? new SetTypeMask(forwardTo.nonNullable(), allocationNode,
+ allocationElement, elementType)
+ : this;
+
+ @override
+ bool get isSet => true;
+
+ @override
+ bool get isExact => true;
+
+ @override
+ bool equalsDisregardNull(other) {
+ if (other is! SetTypeMask) return false;
+ return super.equalsDisregardNull(other) &&
+ allocationNode == other.allocationNode &&
+ elementType == other.elementType;
+ }
+
+ @override
+ TypeMask intersection(TypeMask other, JClosedWorld closedWorld) {
+ TypeMask forwardIntersection = forwardTo.intersection(other, closedWorld);
+ if (forwardIntersection.isEmptyOrNull) return forwardIntersection;
+ return forwardIntersection.isNullable ? nullable() : nonNullable();
+ }
+
+ @override
+ TypeMask union(dynamic other, JClosedWorld closedWorld) {
+ if (this == other) {
+ return this;
+ } else if (equalsDisregardNull(other)) {
+ return other.isNullable ? other : this;
+ } else if (other.isEmptyOrNull) {
+ return other.isNullable ? this.nullable() : this;
+ } else if (other.isSet &&
+ elementType != null &&
+ other.elementType != null) {
+ TypeMask newElementType =
+ elementType.union(other.elementType, closedWorld);
+ TypeMask newForwardTo = forwardTo.union(other.forwardTo, closedWorld);
+ return new SetTypeMask(newForwardTo, null, null, newElementType);
+ } else {
+ return forwardTo.union(other, closedWorld);
+ }
+ }
+
+ @override
+ bool operator ==(other) => super == other;
+
+ @override
+ int get hashCode =>
+ computeHashCode(allocationNode, isNullable, elementType, forwardTo);
+
+ @override
+ String toString() => 'Set($forwardTo, element: $elementType)';
+}
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
index 2b5cae6..cb54ce7 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
@@ -98,6 +98,7 @@
flat,
union,
container,
+ set,
map,
dictionary,
value,
@@ -230,6 +231,8 @@
return new UnionTypeMask.readFromDataSource(source, closedWorld);
case TypeMaskKind.container:
return new ContainerTypeMask.readFromDataSource(source, closedWorld);
+ case TypeMaskKind.set:
+ return new SetTypeMask.readFromDataSource(source, closedWorld);
case TypeMaskKind.map:
return new MapTypeMask.readFromDataSource(source, closedWorld);
case TypeMaskKind.dictionary:
diff --git a/tests/compiler/dart2js/analyses/dart2js_allowed.json b/tests/compiler/dart2js/analyses/dart2js_allowed.json
index 5f6fdad..8ebdcf1 100644
--- a/tests/compiler/dart2js/analyses/dart2js_allowed.json
+++ b/tests/compiler/dart2js/analyses/dart2js_allowed.json
@@ -90,6 +90,13 @@
"Dynamic access of 'allocationNode'.": 1,
"Dynamic access of 'allocationElement'.": 1
},
+ "pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart": {
+ "Dynamic access of 'isNullable'.": 2,
+ "Dynamic access of 'isEmptyOrNull'.": 1,
+ "Dynamic access of 'isSet'.": 1,
+ "Dynamic access of 'elementType'.": 2,
+ "Dynamic access of 'forwardTo'.": 1
+ },
"pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart": {
"Dynamic access of 'isForwarding'.": 1,
"Dynamic access of 'forwardTo'.": 1
@@ -278,4 +285,4 @@
"Dynamic access of 'superclass'.": 1,
"Dynamic access of 'needsTearOff'.": 1
}
-}
+}
\ No newline at end of file