Finish handling SetLiterals in the inferrer and SSA builder kernels.
Change-Id: I9e8a537e57eb51195b57bb2dccb64c9730c553f9
Reviewed-on: https://dart-review.googlesource.com/c/92148
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index 204cdce..dbe357f 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -629,6 +629,26 @@
}
@override
+ TypeInformation visitSetLiteral(ir.SetLiteral node) {
+ return _inferrer.concreteTypes.putIfAbsent(node, () {
+ TypeInformation elementType;
+ for (ir.Expression element in node.expressions) {
+ TypeInformation type = visit(element);
+ elementType = elementType == null
+ ? _types.allocatePhi(null, null, type, isTry: false)
+ : _types.addPhiInput(null, elementType, type);
+ }
+ elementType = elementType == null
+ ? _types.nonNullEmpty()
+ : _types.simplifyPhi(null, null, elementType);
+ TypeInformation containerType =
+ node.isConst ? _types.constSetType : _types.setType;
+ return _types.allocateSet(
+ containerType, node, _analyzedMember, elementType);
+ });
+ }
+
+ @override
TypeInformation visitMapLiteral(ir.MapLiteral node) {
return _inferrer.concreteTypes.putIfAbsent(node, () {
List keyTypes = <TypeInformation>[];
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index 2eedb7b..021979d 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -1261,6 +1261,9 @@
bool checkMapNode(ir.Node node) => true;
@override
+ bool checkSetNode(ir.Node node) => true;
+
+ @override
bool checkListNode(ir.Node node) => true;
@override
diff --git a/pkg/compiler/lib/src/inferrer/type_system.dart b/pkg/compiler/lib/src/inferrer/type_system.dart
index dba941b..7d47272 100644
--- a/pkg/compiler/lib/src/inferrer/type_system.dart
+++ b/pkg/compiler/lib/src/inferrer/type_system.dart
@@ -36,6 +36,9 @@
/// Returns whether [node] is valid as a list allocation node.
bool checkListNode(ir.Node node);
+ /// Returns whether [node] is valid as a set allocation node.
+ bool checkSetNode(ir.Node node);
+
/// Returns whether [node] is valid as a map allocation node.
bool checkMapNode(ir.Node node);
@@ -64,6 +67,10 @@
final Map<ir.TreeNode, ListTypeInformation> allocatedLists =
new Map<ir.TreeNode, ListTypeInformation>();
+ /// [SetTypeInformation] for allocated Sets.
+ final Map<ir.TreeNode, SetTypeInformation> allocatedSets =
+ new Map<ir.TreeNode, SetTypeInformation>();
+
/// [MapTypeInformation] for allocated Maps.
final Map<ir.TreeNode, TypeInformation> allocatedMaps =
new Map<ir.TreeNode, TypeInformation>();
@@ -92,6 +99,7 @@
parameterTypeInformations.values,
memberTypeInformations.values,
allocatedLists.values,
+ allocatedSets.values,
allocatedMaps.values,
allocatedClosures,
concreteTypes.values,
@@ -502,6 +510,25 @@
return result;
}
+ TypeInformation allocateSet(
+ TypeInformation type, ir.Node node, MemberEntity enclosing,
+ [TypeInformation elementType]) {
+ assert(strategy.checkSetNode(node));
+ bool isConst = type.type == _abstractValueDomain.constSetType;
+
+ AbstractValue elementTypeMask =
+ isConst ? elementType.type : dynamicType.type;
+ AbstractValue mask = _abstractValueDomain.createSetValue(
+ type.type, node, enclosing, elementTypeMask);
+ ElementInSetTypeInformation element = new ElementInSetTypeInformation(
+ _abstractValueDomain, currentMember, elementType);
+ element.inferred = isConst;
+
+ allocatedTypes.add(element);
+ return allocatedSets[node] =
+ new SetTypeInformation(currentMember, mask, element);
+ }
+
TypeInformation allocateMap(
ConcreteTypeInformation type, ir.Node node, MemberEntity element,
[List<TypeInformation> keyTypes, List<TypeInformation> valueTypes]) {
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index e8d55ba..87234b3 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -2859,6 +2859,85 @@
}
@override
+ void visitSetLiteral(ir.SetLiteral node) {
+ if (node.isConst) {
+ stack.add(
+ graph.addConstant(_elementMap.getConstantValue(node), closedWorld));
+ return;
+ }
+
+ // The set literal constructors take the elements as a List.
+ List<HInstruction> elements = <HInstruction>[];
+ for (ir.Expression element in node.expressions) {
+ element.accept(this);
+ elements.add(pop());
+ }
+
+ // The constructor is a procedure because it's a factory.
+ FunctionEntity constructor;
+ List<HInstruction> inputs = <HInstruction>[];
+ if (elements.isEmpty) {
+ constructor = _commonElements.setLiteralConstructorEmpty;
+ } else {
+ constructor = _commonElements.setLiteralConstructor;
+ HLiteralList argList = buildLiteralList(elements);
+ add(argList);
+ inputs.add(argList);
+ }
+
+ assert(
+ constructor is ConstructorEntity && constructor.isFactoryConstructor);
+
+ InterfaceType type = localsHandler.substInContext(
+ _commonElements.setType(_elementMap.getDartType(node.typeArgument)));
+ ClassEntity cls = constructor.enclosingClass;
+
+ if (rtiNeed.classNeedsTypeArguments(cls)) {
+ List<HInstruction> typeInputs = <HInstruction>[];
+ type.typeArguments.forEach((DartType argument) {
+ typeInputs
+ .add(typeBuilder.analyzeTypeArgument(argument, sourceElement));
+ });
+
+ // We lift this common call pattern into a helper function to save space
+ // in the output.
+ if (typeInputs.every((HInstruction input) =>
+ input.isNull(abstractValueDomain).isDefinitelyTrue)) {
+ if (elements.isEmpty) {
+ constructor = _commonElements.setLiteralUntypedEmptyMaker;
+ } else {
+ constructor = _commonElements.setLiteralUntypedMaker;
+ }
+ } else {
+ inputs.addAll(typeInputs);
+ }
+ }
+
+ // If runtime type information is needed and the set literal has no type
+ // parameter, 'constructor' is a static function that forwards the call to
+ // the factory constructor without a type parameter.
+ assert(constructor.isFunction ||
+ (constructor is ConstructorEntity && constructor.isFactoryConstructor));
+
+ // The instruction type will always be a subtype of the setLiteralClass, but
+ // type inference might discover a more specific type or find nothing (in
+ // dart2js unit tests).
+
+ AbstractValue setType = abstractValueDomain
+ .createNonNullSubtype(_commonElements.setLiteralClass);
+ AbstractValue returnTypeMask =
+ _typeInferenceMap.getReturnTypeOf(constructor);
+ AbstractValue instructionType =
+ abstractValueDomain.intersection(setType, returnTypeMask);
+
+ addImplicitInstantiation(type);
+ _pushStaticInvocation(
+ constructor, inputs, instructionType, const <DartType>[],
+ sourceInformation: _sourceInformationBuilder.buildNew(node));
+ removeImplicitInstantiation(type);
+ }
+
+ @override
void visitMapLiteral(ir.MapLiteral node) {
if (node.isConst) {
stack.add(