Handle ir constants in inferrer
Change-Id: Ie7b6ff9e62b3b8c78f6c04359cb72f77b249440c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97240
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
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 dd872ab..d5c7392 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -25,6 +25,7 @@
import '../options.dart';
import '../universe/selector.dart';
import '../universe/side_effects.dart';
+import '../util/util.dart';
import 'inferrer_engine.dart';
import 'locals_handler.dart';
import 'type_graph_nodes.dart';
@@ -434,11 +435,16 @@
@override
TypeInformation visitInstantiation(ir.Instantiation node) {
+ return createInstantiationTypeInformation(visit(node.expression));
+ }
+
+ TypeInformation createInstantiationTypeInformation(
+ TypeInformation expressionType) {
// TODO(sra): Add a TypeInformation for Instantiations. Instantiated
// generic methods will need to be traced separately, and have the
// information gathered in tracing reflected back to the generic method. For
// now, pass along the uninstantiated method.
- return visit(node.expression);
+ return expressionType;
}
@override
@@ -455,6 +461,10 @@
@override
TypeInformation visitNullLiteral(ir.NullLiteral literal) {
+ return createNullTypeInformation();
+ }
+
+ TypeInformation createNullTypeInformation() {
return _types.nullType;
}
@@ -606,14 +616,21 @@
}
@override
- TypeInformation visitListLiteral(ir.ListLiteral listLiteral) {
+ TypeInformation visitListLiteral(ir.ListLiteral node) {
+ return createListTypeInformation(
+ node, node.expressions.map((e) => visit(e)),
+ isConst: node.isConst);
+ }
+
+ TypeInformation createListTypeInformation(
+ ir.TreeNode node, Iterable<TypeInformation> elementTypes,
+ {bool isConst}) {
// We only set the type once. We don't need to re-visit the children
// when re-analyzing the node.
- return _inferrer.concreteTypes.putIfAbsent(listLiteral, () {
+ return _inferrer.concreteTypes.putIfAbsent(node, () {
TypeInformation elementType;
int length = 0;
- for (ir.Expression element in listLiteral.expressions) {
- TypeInformation type = visit(element);
+ for (TypeInformation type in elementTypes) {
elementType = elementType == null
? _types.allocatePhi(null, null, type, isTry: false)
: _types.addPhiInput(null, elementType, type);
@@ -623,18 +640,24 @@
? _types.nonNullEmpty()
: _types.simplifyPhi(null, null, elementType);
TypeInformation containerType =
- listLiteral.isConst ? _types.constListType : _types.growableListType;
+ isConst ? _types.constListType : _types.growableListType;
return _types.allocateList(
- containerType, listLiteral, _analyzedMember, elementType, length);
+ containerType, node, _analyzedMember, elementType, length);
});
}
@override
TypeInformation visitSetLiteral(ir.SetLiteral node) {
+ return createSetTypeInformation(node, node.expressions.map((e) => visit(e)),
+ isConst: node.isConst);
+ }
+
+ TypeInformation createSetTypeInformation(
+ ir.TreeNode node, Iterable<TypeInformation> elementTypes,
+ {bool isConst}) {
return _inferrer.concreteTypes.putIfAbsent(node, () {
TypeInformation elementType;
- for (ir.Expression element in node.expressions) {
- TypeInformation type = visit(element);
+ for (TypeInformation type in elementTypes) {
elementType = elementType == null
? _types.allocatePhi(null, null, type, isTry: false)
: _types.addPhiInput(null, elementType, type);
@@ -643,7 +666,7 @@
? _types.nonNullEmpty()
: _types.simplifyPhi(null, null, elementType);
TypeInformation containerType =
- node.isConst ? _types.constSetType : _types.setType;
+ isConst ? _types.constSetType : _types.setType;
return _types.allocateSet(
containerType, node, _analyzedMember, elementType);
});
@@ -651,17 +674,24 @@
@override
TypeInformation visitMapLiteral(ir.MapLiteral node) {
+ return createMapTypeInformation(
+ node, node.entries.map((e) => new Pair(visit(e.key), visit(e.value))),
+ isConst: node.isConst);
+ }
+
+ TypeInformation createMapTypeInformation(ir.TreeNode node,
+ Iterable<Pair<TypeInformation, TypeInformation>> entryTypes,
+ {bool isConst}) {
return _inferrer.concreteTypes.putIfAbsent(node, () {
List keyTypes = <TypeInformation>[];
List valueTypes = <TypeInformation>[];
- for (ir.MapEntry entry in node.entries) {
- keyTypes.add(visit(entry.key));
- valueTypes.add(visit(entry.value));
+ for (Pair<TypeInformation, TypeInformation> entryType in entryTypes) {
+ keyTypes.add(entryType.a);
+ valueTypes.add(entryType.b);
}
- TypeInformation type =
- node.isConst ? _types.constMapType : _types.mapType;
+ TypeInformation type = isConst ? _types.constMapType : _types.mapType;
return _types.allocateMap(
type, node, _analyzedMember, keyTypes, valueTypes);
});
@@ -678,28 +708,45 @@
@override
TypeInformation visitBoolLiteral(ir.BoolLiteral node) {
- return _types.boolLiteralType(node.value);
+ return createBoolTypeInformation(node.value);
+ }
+
+ TypeInformation createBoolTypeInformation(bool value) {
+ return _types.boolLiteralType(value);
}
@override
- TypeInformation visitIntLiteral(ir.IntLiteral node) =>
- // The JavaScript backend may turn this literal into a double at
- // runtime.
- _types.getConcreteTypeFor(_closedWorld.abstractValueDomain
- .computeAbstractValueForConstant(
- constant_system.createIntFromInt(node.value)));
+ TypeInformation visitIntLiteral(ir.IntLiteral node) {
+ return createIntTypeInformation(node.value);
+ }
+
+ TypeInformation createIntTypeInformation(int value) {
+ // The JavaScript backend may turn this literal into a double at
+ // runtime.
+ return _types.getConcreteTypeFor(_closedWorld.abstractValueDomain
+ .computeAbstractValueForConstant(
+ constant_system.createIntFromInt(value)));
+ }
@override
- TypeInformation visitDoubleLiteral(ir.DoubleLiteral node) =>
- // The JavaScript backend may turn this literal into an integer at
- // runtime.
- _types.getConcreteTypeFor(_closedWorld.abstractValueDomain
- .computeAbstractValueForConstant(
- constant_system.createDouble(node.value)));
+ TypeInformation visitDoubleLiteral(ir.DoubleLiteral node) {
+ return createDoubleTypeInformation(node.value);
+ }
+
+ TypeInformation createDoubleTypeInformation(double value) {
+ // The JavaScript backend may turn this literal into a double at
+ // runtime.
+ return _types.getConcreteTypeFor(_closedWorld.abstractValueDomain
+ .computeAbstractValueForConstant(constant_system.createDouble(value)));
+ }
@override
TypeInformation visitStringLiteral(ir.StringLiteral node) {
- return _types.stringLiteralType(node.value);
+ return createStringTypeInformation(node.value);
+ }
+
+ TypeInformation createStringTypeInformation(String value) {
+ return _types.stringLiteralType(value);
}
@override
@@ -720,12 +767,20 @@
@override
TypeInformation visitSymbolLiteral(ir.SymbolLiteral node) {
+ return createSymbolLiteralTypeInformation();
+ }
+
+ TypeInformation createSymbolLiteralTypeInformation() {
return _types
.nonNullSubtype(_closedWorld.commonElements.symbolImplementationClass);
}
@override
TypeInformation visitTypeLiteral(ir.TypeLiteral node) {
+ return createTypeLiteralInformation();
+ }
+
+ TypeInformation createTypeLiteralInformation() {
return _types.typeType;
}
@@ -1065,7 +1120,11 @@
/// Try to find the length given to a fixed array constructor call.
int _findLength(ir.Arguments arguments) {
ir.Expression firstArgument = arguments.positional.first;
- if (firstArgument is ir.IntLiteral) {
+ if (firstArgument is ir.ConstantExpression &&
+ firstArgument.constant is ir.IntConstant) {
+ ir.IntConstant constant = firstArgument.constant;
+ return constant.value;
+ } else if (firstArgument is ir.IntLiteral) {
return firstArgument.value;
} else if (firstArgument is ir.StaticGet) {
MemberEntity member = _elementMap.getMember(firstArgument.target);
@@ -1231,8 +1290,14 @@
@override
TypeInformation visitStaticGet(ir.StaticGet node) {
- MemberEntity member = _elementMap.getMember(node.target);
AbstractValue mask = _memberData.typeOfSend(node);
+ assert(mask == null);
+ return createStaticGetTypeInformation(node, node.target, mask: mask);
+ }
+
+ TypeInformation createStaticGetTypeInformation(ir.Node node, ir.Member target,
+ {AbstractValue mask}) {
+ MemberEntity member = _elementMap.getMember(target);
return handleStaticInvoke(
node, new Selector.getter(member.memberName), mask, member, null);
}
@@ -1765,8 +1830,111 @@
@override
TypeInformation visitConstantExpression(ir.ConstantExpression node) {
- // TODO(johnniwinther,fishythefish): Compute the precise type information.
- return _types.dynamicType;
+ return node.constant.accept(new TypeInformationConstantVisitor(this, node));
+ }
+}
+
+class TypeInformationConstantVisitor
+ implements ir.ConstantVisitor<TypeInformation> {
+ final KernelTypeGraphBuilder builder;
+ final ir.ConstantExpression expression;
+
+ TypeInformationConstantVisitor(this.builder, this.expression);
+
+ @override
+ TypeInformation defaultConstant(ir.Constant node) {
+ throw new UnsupportedError("Unexpected constant: "
+ "${node} (${node.runtimeType})");
+ }
+
+ @override
+ TypeInformation visitNullConstant(ir.NullConstant node) {
+ return builder.createNullTypeInformation();
+ }
+
+ @override
+ TypeInformation visitBoolConstant(ir.BoolConstant node) {
+ return builder.createBoolTypeInformation(node.value);
+ }
+
+ @override
+ TypeInformation visitIntConstant(ir.IntConstant node) {
+ return builder.createIntTypeInformation(node.value);
+ }
+
+ @override
+ TypeInformation visitDoubleConstant(ir.DoubleConstant node) {
+ return builder.createDoubleTypeInformation(node.value);
+ }
+
+ @override
+ TypeInformation visitStringConstant(ir.StringConstant node) {
+ return builder.createStringTypeInformation(node.value);
+ }
+
+ @override
+ TypeInformation visitSymbolConstant(ir.SymbolConstant node) {
+ return builder.createSymbolLiteralTypeInformation();
+ }
+
+ @override
+ TypeInformation visitMapConstant(ir.MapConstant node) {
+ return builder.createMapTypeInformation(
+ new ConstantReference(expression, node),
+ node.entries
+ .map((e) => new Pair(e.key.accept(this), e.value.accept(this))),
+ isConst: true);
+ }
+
+ @override
+ TypeInformation visitListConstant(ir.ListConstant node) {
+ return builder.createListTypeInformation(
+ new ConstantReference(expression, node),
+ node.entries.map((e) => e.accept(this)),
+ isConst: true);
+ }
+
+ @override
+ TypeInformation visitSetConstant(ir.SetConstant node) {
+ return builder.createSetTypeInformation(
+ new ConstantReference(expression, node),
+ node.entries.map((e) => e.accept(this)),
+ isConst: true);
+ }
+
+ @override
+ TypeInformation visitInstanceConstant(ir.InstanceConstant node) {
+ node.fieldValues.forEach((ir.Reference reference, ir.Constant value) {
+ builder._inferrer.recordTypeOfField(
+ builder._elementMap.getField(reference.asField), value.accept(this));
+ });
+ return builder._types.getConcreteTypeFor(builder
+ ._closedWorld.abstractValueDomain
+ .createNonNullExact(builder._elementMap.getClass(node.classNode)));
+ }
+
+ @override
+ TypeInformation visitPartialInstantiationConstant(
+ ir.PartialInstantiationConstant node) {
+ return builder
+ .createInstantiationTypeInformation(node.tearOffConstant.accept(this));
+ }
+
+ @override
+ TypeInformation visitTearOffConstant(ir.TearOffConstant node) {
+ return builder.createStaticGetTypeInformation(node, node.procedure);
+ }
+
+ @override
+ TypeInformation visitTypeLiteralConstant(ir.TypeLiteralConstant node) {
+ return builder.createTypeLiteralInformation();
+ }
+
+ @override
+ TypeInformation visitUnevaluatedConstant(ir.UnevaluatedConstant node) {
+ // TODO(johnniwinther): These should have been replaced by their evaluated
+ // counterpart during impact building.
+ return builder._types.dynamicType;
}
}
@@ -1991,3 +2159,51 @@
return sb.toString();
}
}
+
+/// Class to represent a reference to a constant in allocation nodes.
+///
+/// This class is needed in order to support serialization of references to
+/// constant nodes. Since the constant nodes are not [ir.TreeNode]s we can only
+/// serialize the constants as values which would bypass by the canonicalization
+/// performed by the CFE. This class extends only as a trick to easily pass
+/// it through serialization.
+///
+/// By adding a reference to the constant expression in which the constant
+/// occurred, we can serialize references to constants in two steps: a reference
+/// to the constant expression followed by an index of the referred constant
+/// in the traversal order of the constant held by the constant expression.
+///
+/// This is used for list, map, and set literals.
+class ConstantReference extends ir.TreeNode {
+ final ir.ConstantExpression expression;
+ final ir.Constant constant;
+
+ ConstantReference(this.expression, this.constant);
+
+ @override
+ void visitChildren(ir.Visitor v) {
+ throw new UnsupportedError("ConstantReference.visitChildren");
+ }
+
+ @override
+ accept(ir.TreeVisitor v) {
+ throw new UnsupportedError("ConstantReference.accept");
+ }
+
+ @override
+ transformChildren(ir.Transformer v) {
+ throw new UnsupportedError("ConstantReference.transformChildren");
+ }
+
+ @override
+ int get hashCode => 13 * constant.hashCode;
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(this, other)) return true;
+ return other is ConstantReference && constant == other.constant;
+ }
+
+ @override
+ String toString() => 'ConstantReference(constant=$constant)';
+}
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index 5e12d5a..a33cffc 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -72,7 +72,7 @@
NoSuchMethodData get noSuchMethodData => closedWorld.noSuchMethodData;
TypeSystem get types;
- Map<ir.Node, TypeInformation> get concreteTypes;
+ Map<ir.TreeNode, TypeInformation> get concreteTypes;
InferredDataBuilder get inferredDataBuilder;
FunctionEntity get mainElement;
@@ -281,8 +281,8 @@
@override
final TypeSystem types;
@override
- final Map<ir.Node, TypeInformation> concreteTypes =
- new Map<ir.Node, TypeInformation>();
+ final Map<ir.TreeNode, TypeInformation> concreteTypes =
+ new Map<ir.TreeNode, TypeInformation>();
final Set<ConstructorEntity> generativeConstructorsExposingThis =
new Set<ConstructorEntity>();
diff --git a/pkg/compiler/lib/src/inferrer/type_system.dart b/pkg/compiler/lib/src/inferrer/type_system.dart
index aa827d3..c5c32cf 100644
--- a/pkg/compiler/lib/src/inferrer/type_system.dart
+++ b/pkg/compiler/lib/src/inferrer/type_system.dart
@@ -431,7 +431,7 @@
}
TypeInformation allocateList(
- TypeInformation type, ir.Node node, MemberEntity enclosing,
+ TypeInformation type, ir.TreeNode node, MemberEntity enclosing,
[TypeInformation elementType, int length]) {
assert(strategy.checkListNode(node));
ClassEntity typedDataClass = _closedWorld.commonElements.typedDataClass;
@@ -472,7 +472,7 @@
}
TypeInformation allocateSet(
- TypeInformation type, ir.Node node, MemberEntity enclosing,
+ TypeInformation type, ir.TreeNode node, MemberEntity enclosing,
[TypeInformation elementType]) {
assert(strategy.checkSetNode(node));
bool isConst = type.type == _abstractValueDomain.constSetType;
@@ -491,7 +491,7 @@
}
TypeInformation allocateMap(
- ConcreteTypeInformation type, ir.Node node, MemberEntity element,
+ ConcreteTypeInformation type, ir.TreeNode node, MemberEntity element,
[List<TypeInformation> keyTypes, List<TypeInformation> valueTypes]) {
assert(strategy.checkMapNode(node));
assert(keyTypes.length == valueTypes.length);
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart
index 17e4913..f2fda3d 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart
@@ -16,7 +16,7 @@
final TypeMask forwardTo;
@override
- final ir.TreeNode allocationNode;
+ final ir.Node allocationNode;
@override
final MemberEntity allocationElement;
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
index 827840c..ef15561 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
@@ -20,7 +20,7 @@
DictionaryTypeMask(
TypeMask forwardTo,
- ir.TreeNode allocationNode,
+ ir.Node allocationNode,
MemberEntity allocationElement,
TypeMask keyType,
TypeMask valueType,
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart
index 39f850c..8d86f0c 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart
@@ -154,8 +154,8 @@
}
abstract class AllocationTypeMask extends ForwardingTypeMask {
- // The [ir.TreeNode] where this type mask was created.
- ir.TreeNode get allocationNode;
+ // The [ir.Node] where this type mask was created.
+ ir.Node get allocationNode;
// The [Entity] where this type mask was created.
MemberEntity get allocationElement;
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
index b1d32eb..3b4d729 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
@@ -16,7 +16,7 @@
final TypeMask forwardTo;
@override
- final ir.TreeNode allocationNode;
+ final ir.Node allocationNode;
@override
final MemberEntity allocationElement;
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart
index f95bac6..0b1ffb6e 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/set_type_mask.dart
@@ -16,7 +16,7 @@
final TypeMask forwardTo;
@override
- final ir.TreeNode allocationNode;
+ final ir.Node allocationNode;
@override
final MemberEntity allocationElement;
diff --git a/pkg/compiler/lib/src/serialization/abstract_sink.dart b/pkg/compiler/lib/src/serialization/abstract_sink.dart
index 737c314..dfe4e9b 100644
--- a/pkg/compiler/lib/src/serialization/abstract_sink.dart
+++ b/pkg/compiler/lib/src/serialization/abstract_sink.dart
@@ -232,6 +232,12 @@
} else if (value is ir.TypeParameter) {
_writeEnumInternal(_TreeNodeKind.typeParameter);
_writeTypeParameter(value);
+ } else if (value is ConstantReference) {
+ _writeEnumInternal(_TreeNodeKind.constant);
+ _writeTreeNode(value.expression);
+ _ConstantNodeIndexerVisitor indexer = new _ConstantNodeIndexerVisitor();
+ value.expression.constant.accept(indexer);
+ _writeIntInternal(indexer.getIndex(value.constant));
} else {
_writeEnumInternal(_TreeNodeKind.node);
ir.TreeNode member = value;
diff --git a/pkg/compiler/lib/src/serialization/abstract_source.dart b/pkg/compiler/lib/src/serialization/abstract_source.dart
index b9660bd..f4160ce 100644
--- a/pkg/compiler/lib/src/serialization/abstract_source.dart
+++ b/pkg/compiler/lib/src/serialization/abstract_source.dart
@@ -518,6 +518,14 @@
return _readFunctionNode();
case _TreeNodeKind.typeParameter:
return _readTypeParameter();
+ case _TreeNodeKind.constant:
+ // TODO(johnniwinther): Support serialization within a member context
+ // and use this to temporarily cache constant node indices.
+ ir.ConstantExpression expression = _readTreeNode();
+ _ConstantNodeIndexerVisitor indexer = new _ConstantNodeIndexerVisitor();
+ expression.constant.accept(indexer);
+ ir.Constant constant = indexer.getConstant(_readIntInternal());
+ return new ConstantReference(expression, constant);
case _TreeNodeKind.node:
_MemberData data = _readMemberData();
int index = _readIntInternal();
diff --git a/pkg/compiler/lib/src/serialization/helpers.dart b/pkg/compiler/lib/src/serialization/helpers.dart
index 4bb57a4..40cc83d 100644
--- a/pkg/compiler/lib/src/serialization/helpers.dart
+++ b/pkg/compiler/lib/src/serialization/helpers.dart
@@ -48,7 +48,8 @@
node,
functionNode,
typeParameter,
- functionDeclarationVariable
+ functionDeclarationVariable,
+ constant,
}
/// Enum used for identifying [ir.FunctionNode] context in serialization.
diff --git a/pkg/compiler/lib/src/serialization/node_indexer.dart b/pkg/compiler/lib/src/serialization/node_indexer.dart
index f54ac9c..8e92ebf 100644
--- a/pkg/compiler/lib/src/serialization/node_indexer.dart
+++ b/pkg/compiler/lib/src/serialization/node_indexer.dart
@@ -193,4 +193,108 @@
registerNode(node);
super.visitSuperPropertyGet(node);
}
+
+ @override
+ void visitConstantExpression(ir.ConstantExpression node) {
+ registerNode(node);
+ super.visitConstantExpression(node);
+ }
+}
+
+/// Visitor that ascribes an index to all [ir.Constant]s that we potentially
+/// need to reference for serialization and deserialization.
+///
+/// Currently this is only list, map, and set constants, which are used as
+/// allocation identities in the global inference.
+class _ConstantNodeIndexerVisitor implements ir.ConstantVisitor<void> {
+ int _currentIndex = 0;
+ final Map<int, ir.Constant> _indexToNodeMap = {};
+ final Map<ir.Constant, int> _nodeToIndexMap = {};
+
+ void registerConstant(ir.Constant node) {
+ _indexToNodeMap[_currentIndex] = node;
+ _nodeToIndexMap[node] = _currentIndex;
+ _currentIndex++;
+ }
+
+ int getIndex(ir.Constant node) {
+ assert(_nodeToIndexMap.containsKey(node), "Constant without index: $node");
+ return _nodeToIndexMap[node];
+ }
+
+ ir.Constant getConstant(int index) {
+ assert(
+ _indexToNodeMap.containsKey(index), "Index without constant: $index");
+ return _indexToNodeMap[index];
+ }
+
+ @override
+ void visitUnevaluatedConstant(ir.UnevaluatedConstant node) {}
+
+ @override
+ void visitTypeLiteralConstant(ir.TypeLiteralConstant node) {}
+
+ @override
+ void visitTearOffConstant(ir.TearOffConstant node) {}
+
+ @override
+ void visitPartialInstantiationConstant(ir.PartialInstantiationConstant node) {
+ node.tearOffConstant.accept(this);
+ }
+
+ @override
+ void visitInstanceConstant(ir.InstanceConstant node) {
+ node.fieldValues.forEach((_, ir.Constant value) {
+ value.accept(this);
+ });
+ }
+
+ @override
+ void visitSetConstant(ir.SetConstant node) {
+ registerConstant(node);
+ for (ir.Constant element in node.entries) {
+ element.accept(this);
+ }
+ }
+
+ @override
+ void visitListConstant(ir.ListConstant node) {
+ registerConstant(node);
+ for (ir.Constant element in node.entries) {
+ element.accept(this);
+ }
+ }
+
+ @override
+ void visitMapConstant(ir.MapConstant node) {
+ registerConstant(node);
+ for (ir.ConstantMapEntry entry in node.entries) {
+ entry.key.accept(this);
+ entry.value.accept(this);
+ }
+ }
+
+ @override
+ void visitSymbolConstant(ir.SymbolConstant node) {}
+
+ @override
+ void visitStringConstant(ir.StringConstant node) {}
+
+ @override
+ void visitDoubleConstant(ir.DoubleConstant node) {}
+
+ @override
+ void visitIntConstant(ir.IntConstant node) {}
+
+ @override
+ void visitBoolConstant(ir.BoolConstant node) {}
+
+ @override
+ void visitNullConstant(ir.NullConstant node) {}
+
+ @override
+ void defaultConstant(ir.Constant node) {
+ throw new UnimplementedError(
+ "Unexpected constant: $node (${node.runtimeType})");
+ }
}
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
index b974951..65276b3 100644
--- a/pkg/compiler/lib/src/serialization/serialization.dart
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -15,6 +15,7 @@
import '../elements/entities.dart';
import '../elements/indexed.dart';
import '../elements/types.dart';
+import '../inferrer/builder_kernel.dart';
import '../ir/static_type_base.dart';
import '../js_model/closure.dart';
import '../js_model/locals.dart';
diff --git a/tests/compiler/dart2js/inference/data/call_method_function_typed_value.dart b/tests/compiler/dart2js/inference/data/call_method_function_typed_value.dart
index a70e567..9fc9e74 100644
--- a/tests/compiler/dart2js/inference/data/call_method_function_typed_value.dart
+++ b/tests/compiler/dart2js/inference/data/call_method_function_typed_value.dart
@@ -11,6 +11,8 @@
int
/*strong.[null|subclass=Object]*/
/*omit.[null|subclass=JSInt]*/
+ /*strongConst.[null|subclass=Object]*/
+ /*omitConst.[null|subclass=JSInt]*/
i) =>
2 /*invoke: [exact=JSUInt31]*/ * i;
diff --git a/tests/compiler/dart2js/inference/data/closure_tracer_28919.dart b/tests/compiler/dart2js/inference/data/closure_tracer_28919.dart
index 7f88ade..6bc222f 100644
--- a/tests/compiler/dart2js/inference/data/closure_tracer_28919.dart
+++ b/tests/compiler/dart2js/inference/data/closure_tracer_28919.dart
@@ -57,6 +57,8 @@
/*[null]*/ (int
/*strong.[null|subclass=Object]*/
/*omit.[null|subclass=JSInt]*/
+ /*strongConst.[null|subclass=Object]*/
+ /*omitConst.[null|subclass=JSInt]*/
x) {
res = x;
sum = x /*invoke: [null|subclass=JSInt]*/ + i;
diff --git a/tests/compiler/dart2js/inference/data/const_closure.dart b/tests/compiler/dart2js/inference/data/const_closure.dart
index 137c2b7..8425f4d 100644
--- a/tests/compiler/dart2js/inference/data/const_closure.dart
+++ b/tests/compiler/dart2js/inference/data/const_closure.dart
@@ -13,10 +13,12 @@
return a;
}
-/*element: foo1:[subclass=Closure]*/
+/*strong.element: foo1:[subclass=Closure]*/
+/*omit.element: foo1:[subclass=Closure]*/
const foo1 = method1;
-/*element: foo2:[subclass=Closure]*/
+/*strong.element: foo2:[subclass=Closure]*/
+/*omit.element: foo2:[subclass=Closure]*/
const foo2 = method2;
/*element: returnInt1:[null|subclass=Object]*/
diff --git a/tests/compiler/dart2js/inference/data/const_closure2.dart b/tests/compiler/dart2js/inference/data/const_closure2.dart
index 26b76ff..207a431 100644
--- a/tests/compiler/dart2js/inference/data/const_closure2.dart
+++ b/tests/compiler/dart2js/inference/data/const_closure2.dart
@@ -8,7 +8,8 @@
return a;
}
-/*element: foo:[subclass=Closure]*/
+/*strong.element: foo:[subclass=Closure]*/
+/*omit.element: foo:[subclass=Closure]*/
const foo = method;
/*element: returnNum:[null|subclass=Object]*/
diff --git a/tests/compiler/dart2js/inference/data/const_closure3.dart b/tests/compiler/dart2js/inference/data/const_closure3.dart
index 74b97a0..79a36f0 100644
--- a/tests/compiler/dart2js/inference/data/const_closure3.dart
+++ b/tests/compiler/dart2js/inference/data/const_closure3.dart
@@ -8,7 +8,8 @@
return a;
}
-/*element: foo:[subclass=Closure]*/
+/*strong.element: foo:[subclass=Closure]*/
+/*omit.element: foo:[subclass=Closure]*/
const foo = method;
/*element: returnInt:[null|subclass=Object]*/
diff --git a/tests/compiler/dart2js/inference/data/const_closure4.dart b/tests/compiler/dart2js/inference/data/const_closure4.dart
index 26b76ff..207a431 100644
--- a/tests/compiler/dart2js/inference/data/const_closure4.dart
+++ b/tests/compiler/dart2js/inference/data/const_closure4.dart
@@ -8,7 +8,8 @@
return a;
}
-/*element: foo:[subclass=Closure]*/
+/*strong.element: foo:[subclass=Closure]*/
+/*omit.element: foo:[subclass=Closure]*/
const foo = method;
/*element: returnNum:[null|subclass=Object]*/
diff --git a/tests/compiler/dart2js/inference/data/const_closure5.dart b/tests/compiler/dart2js/inference/data/const_closure5.dart
index 3055295..89a3abf 100644
--- a/tests/compiler/dart2js/inference/data/const_closure5.dart
+++ b/tests/compiler/dart2js/inference/data/const_closure5.dart
@@ -8,7 +8,8 @@
return a;
}
-/*element: foo:[subclass=Closure]*/
+/*strong.element: foo:[subclass=Closure]*/
+/*omit.element: foo:[subclass=Closure]*/
const foo = method;
/*element: returnInt:[null|subclass=Object]*/
diff --git a/tests/compiler/dart2js/inference/data/enum.dart b/tests/compiler/dart2js/inference/data/enum.dart
index 1fc823b..79b6d84 100644
--- a/tests/compiler/dart2js/inference/data/enum.dart
+++ b/tests/compiler/dart2js/inference/data/enum.dart
@@ -16,7 +16,8 @@
////////////////////////////////////////////////////////////////////////////////
enum Enum1 {
- /*element: Enum1.a:[exact=Enum1]*/
+ /*strong.element: Enum1.a:[exact=Enum1]*/
+ /*omit.element: Enum1.a:[exact=Enum1]*/
a,
}
@@ -28,7 +29,8 @@
////////////////////////////////////////////////////////////////////////////////
enum Enum2 {
- /*element: Enum2.a:[exact=Enum2]*/
+ /*strong.element: Enum2.a:[exact=Enum2]*/
+ /*omit.element: Enum2.a:[exact=Enum2]*/
a,
}
@@ -40,9 +42,11 @@
////////////////////////////////////////////////////////////////////////////////
enum Enum3 {
- /*element: Enum3.a:[exact=Enum3]*/
+ /*strong.element: Enum3.a:[exact=Enum3]*/
+ /*omit.element: Enum3.a:[exact=Enum3]*/
a,
- /*element: Enum3.b:[exact=Enum3]*/
+ /*strong.element: Enum3.b:[exact=Enum3]*/
+ /*omit.element: Enum3.b:[exact=Enum3]*/
b,
}
@@ -54,7 +58,8 @@
////////////////////////////////////////////////////////////////////////////////
enum Enum4 {
- /*element: Enum4.a:[exact=Enum4]*/
+ /*strong.element: Enum4.a:[exact=Enum4]*/
+ /*omit.element: Enum4.a:[exact=Enum4]*/
a,
}
@@ -68,9 +73,11 @@
////////////////////////////////////////////////////////////////////////////////
enum Enum5 {
- /*element: Enum5.a:[exact=Enum5]*/
+ /*strong.element: Enum5.a:[exact=Enum5]*/
+ /*omit.element: Enum5.a:[exact=Enum5]*/
a,
- /*element: Enum5.b:[exact=Enum5]*/
+ /*strong.element: Enum5.b:[exact=Enum5]*/
+ /*omit.element: Enum5.b:[exact=Enum5]*/
b,
}
diff --git a/tests/compiler/dart2js/inference/data/global_field_closure.dart b/tests/compiler/dart2js/inference/data/global_field_closure.dart
index d2fd3bc..d40bfaab 100644
--- a/tests/compiler/dart2js/inference/data/global_field_closure.dart
+++ b/tests/compiler/dart2js/inference/data/global_field_closure.dart
@@ -13,10 +13,16 @@
return a;
}
-/*element: foo1:[null|subclass=Closure]*/
+/*strong.element: foo1:[null|subclass=Closure]*/
+/*omit.element: foo1:[null|subclass=Closure]*/
+/*strongConst.element: foo1:[subclass=Closure]*/
+/*omitConst.element: foo1:[subclass=Closure]*/
var foo1 = method1;
-/*element: foo2:[null|subclass=Closure]*/
+/*strong.element: foo2:[null|subclass=Closure]*/
+/*omit.element: foo2:[null|subclass=Closure]*/
+/*strongConst.element: foo2:[subclass=Closure]*/
+/*omitConst.element: foo2:[subclass=Closure]*/
var foo2 = method2;
/*element: returnInt1:[null|subclass=Object]*/
diff --git a/tests/compiler/dart2js/inference/data/global_field_closure2.dart b/tests/compiler/dart2js/inference/data/global_field_closure2.dart
index 765913e..f4199e9 100644
--- a/tests/compiler/dart2js/inference/data/global_field_closure2.dart
+++ b/tests/compiler/dart2js/inference/data/global_field_closure2.dart
@@ -8,7 +8,10 @@
return a;
}
-/*element: foo:[null|subclass=Closure]*/
+/*strong.element: foo:[null|subclass=Closure]*/
+/*omit.element: foo:[null|subclass=Closure]*/
+/*strongConst.element: foo:[subclass=Closure]*/
+/*omitConst.element: foo:[subclass=Closure]*/
var foo = method;
/*element: returnInt:[null|subclass=Object]*/
diff --git a/tests/compiler/dart2js/inference/data/list.dart b/tests/compiler/dart2js/inference/data/list.dart
index 85919b2..967ed10 100644
--- a/tests/compiler/dart2js/inference/data/list.dart
+++ b/tests/compiler/dart2js/inference/data/list.dart
@@ -108,7 +108,8 @@
// Create a Uint16List using a const top-level field as length.
////////////////////////////////////////////////////////////////////////////////
-/*element: _field3:[exact=JSUInt31]*/
+/*strong.element: _field3:[exact=JSUInt31]*/
+/*omit.element: _field3:[exact=JSUInt31]*/
const _field3 = 12;
/*element: newUint16List:Container([exact=NativeUint16List], element: [exact=JSUInt31], length: 12)*/
@@ -134,7 +135,8 @@
////////////////////////////////////////////////////////////////////////////////
abstract class Class1 {
- /*element: Class1.field:[exact=JSUInt31]*/
+ /*strong.element: Class1.field:[exact=JSUInt31]*/
+ /*omit.element: Class1.field:[exact=JSUInt31]*/
static const field = 15;
}
diff --git a/tests/compiler/dart2js/inference/data/map_tracer_const.dart b/tests/compiler/dart2js/inference/data/map_tracer_const.dart
index ab50dff..05cd163 100644
--- a/tests/compiler/dart2js/inference/data/map_tracer_const.dart
+++ b/tests/compiler/dart2js/inference/data/map_tracer_const.dart
@@ -7,15 +7,21 @@
int
/*strong.Union([exact=JSDouble], [exact=JSUInt31])*/
/*omit.[exact=JSUInt31]*/
+ /*strongConst.Union([exact=JSDouble], [exact=JSUInt31])*/
+ /*omitConst.[exact=JSUInt31]*/
x) {
return x;
}
class A {
- /*element: A.DEFAULT:Dictionary([subclass=ConstantMap], key: Value([exact=JSString], value: "fun"), value: [null|subclass=Closure], map: {fun: [subclass=Closure]})*/
+ /*strong.element: A.DEFAULT:Dictionary([subclass=ConstantMap], key: Value([exact=JSString], value: "fun"), value: [null|subclass=Closure], map: {fun: [subclass=Closure]})*/
+ /*omit.element: A.DEFAULT:Dictionary([subclass=ConstantMap], key: Value([exact=JSString], value: "fun"), value: [null|subclass=Closure], map: {fun: [subclass=Closure]})*/
static const DEFAULT = const {'fun': closure};
- /*element: A.map:Dictionary([subclass=ConstantMap], key: Value([exact=JSString], value: "fun"), value: [null|subclass=Closure], map: {fun: [subclass=Closure]})*/
+ /*strong.element: A.map:Dictionary([subclass=ConstantMap], key: Value([exact=JSString], value: "fun"), value: [null|subclass=Closure], map: {fun: [subclass=Closure]})*/
+ /*omit.element: A.map:Dictionary([subclass=ConstantMap], key: Value([exact=JSString], value: "fun"), value: [null|subclass=Closure], map: {fun: [subclass=Closure]})*/
+ /*strongConst.element: A.map:Dictionary([exact=ConstantStringMap], key: Value([exact=JSString], value: "fun"), value: [null|subclass=Closure], map: {fun: [subclass=Closure]})*/
+ /*omitConst.element: A.map:Dictionary([exact=ConstantStringMap], key: Value([exact=JSString], value: "fun"), value: [null|subclass=Closure], map: {fun: [subclass=Closure]})*/
final map;
/*element: A.:[exact=A]*/
@@ -26,7 +32,10 @@
main() {
var a = new A();
a. /*[exact=A]*/ map
- /*Dictionary([subclass=ConstantMap], key: Value([exact=JSString], value: "fun"), value: [null|subclass=Closure], map: {fun: [subclass=Closure]})*/
+ /*strong.Dictionary([subclass=ConstantMap], key: Value([exact=JSString], value: "fun"), value: [null|subclass=Closure], map: {fun: [subclass=Closure]})*/
+ /*omit.Dictionary([subclass=ConstantMap], key: Value([exact=JSString], value: "fun"), value: [null|subclass=Closure], map: {fun: [subclass=Closure]})*/
+ /*strongConst.Dictionary([exact=ConstantStringMap], key: Value([exact=JSString], value: "fun"), value: [null|subclass=Closure], map: {fun: [subclass=Closure]})*/
+ /*omitConst.Dictionary([exact=ConstantStringMap], key: Value([exact=JSString], value: "fun"), value: [null|subclass=Closure], map: {fun: [subclass=Closure]})*/
['fun'](3.3);
print(closure(22));
}
diff --git a/tests/compiler/dart2js/inference/data/native.dart b/tests/compiler/dart2js/inference/data/native.dart
index e9ec7b9..a6cb859 100644
--- a/tests/compiler/dart2js/inference/data/native.dart
+++ b/tests/compiler/dart2js/inference/data/native.dart
@@ -7,7 +7,11 @@
nativeMethod();
}
-/*element: nativeMethod:[null|subclass=Object]*/
+/*strong.element: nativeMethod:[null|subclass=Object]*/
+/*omit.element: nativeMethod:[null|subclass=Object]*/
+// TODO(johnniwinther): Support native behavior from CFE constants:
+/*strongConst.element: nativeMethod:[null]*/
+/*omitConst.element: nativeMethod:[null]*/
nativeMethod()
// ignore: NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE
native;
diff --git a/tests/compiler/dart2js/inference/data/native2.dart b/tests/compiler/dart2js/inference/data/native2.dart
index bae53e9..86b88a5 100644
--- a/tests/compiler/dart2js/inference/data/native2.dart
+++ b/tests/compiler/dart2js/inference/data/native2.dart
@@ -12,7 +12,11 @@
createRectangle();
}
-/*element: createElement:[null|subclass=Element]*/
+/*strong.element: createElement:[null|subclass=Element]*/
+/*omit.element: createElement:[null|subclass=Element]*/
+// TODO(johnniwinther): Support native behavior from CFE constants:
+/*strongConst.element: createElement:[null]*/
+/*omitConst.element: createElement:[null]*/
Element createElement()
// ignore: NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE
native;
diff --git a/tests/compiler/dart2js/inference/data/native3.dart b/tests/compiler/dart2js/inference/data/native3.dart
index 73e458f..1c885db 100644
--- a/tests/compiler/dart2js/inference/data/native3.dart
+++ b/tests/compiler/dart2js/inference/data/native3.dart
@@ -9,7 +9,11 @@
createRectangle();
}
-/*element: createRectangle:[null|subclass=DomRectReadOnly]*/
+/*strong.element: createRectangle:[null|subclass=DomRectReadOnly]*/
+/*omit.element: createRectangle:[null|subclass=DomRectReadOnly]*/
+// TODO(johnniwinther): Support native behavior from CFE constants:
+/*strongConst.element: createRectangle:[null]*/
+/*omitConst.element: createRectangle:[null]*/
Rectangle createRectangle()
// ignore: NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE
native;
diff --git a/tests/compiler/dart2js/inference/data/no_such_method.dart b/tests/compiler/dart2js/inference/data/no_such_method.dart
index 16f5358..2803433 100644
--- a/tests/compiler/dart2js/inference/data/no_such_method.dart
+++ b/tests/compiler/dart2js/inference/data/no_such_method.dart
@@ -17,6 +17,8 @@
Invocation
/*strong.[null|subclass=Object]*/
/*omit.[null|exact=JSInvocationMirror]*/
+ /*strongConst.[null|subclass=Object]*/
+ /*omitConst.[null|exact=JSInvocationMirror]*/
_) =>
42;
@@ -41,6 +43,8 @@
Invocation
/*strong.[null|subclass=Object]*/
/*omit.[null|exact=JSInvocationMirror]*/
+ /*strongConst.[null|subclass=Object]*/
+ /*omitConst.[null|exact=JSInvocationMirror]*/
_) =>
42;
@@ -65,6 +69,8 @@
Invocation
/*strong.[null|subclass=Object]*/
/*omit.[null|exact=JSInvocationMirror]*/
+ /*strongConst.[null|subclass=Object]*/
+ /*omitConst.[null|exact=JSInvocationMirror]*/
invocation) {
return invocation
.
@@ -101,6 +107,8 @@
Invocation
/*strong.[null|subclass=Object]*/
/*omit.[null|exact=JSInvocationMirror]*/
+ /*strongConst.[null|subclass=Object]*/
+ /*omitConst.[null|exact=JSInvocationMirror]*/
invocation) {
this. /*update: [exact=Class4]*/ field = invocation
.
diff --git a/tests/compiler/dart2js/inference/data/no_such_method1.dart b/tests/compiler/dart2js/inference/data/no_such_method1.dart
index 2e9aadb..eeaed0e 100644
--- a/tests/compiler/dart2js/inference/data/no_such_method1.dart
+++ b/tests/compiler/dart2js/inference/data/no_such_method1.dart
@@ -8,6 +8,8 @@
noSuchMethod(
/*strong.[null|subclass=Object]*/
/*omit.[null|exact=JSInvocationMirror]*/
+ /*strongConst.[null|subclass=Object]*/
+ /*omitConst.[null|exact=JSInvocationMirror]*/
im) =>
42;
}
diff --git a/tests/compiler/dart2js/inference/data/no_such_method2.dart b/tests/compiler/dart2js/inference/data/no_such_method2.dart
index 2f0741b..3bce145 100644
--- a/tests/compiler/dart2js/inference/data/no_such_method2.dart
+++ b/tests/compiler/dart2js/inference/data/no_such_method2.dart
@@ -8,6 +8,8 @@
noSuchMethod(
/*strong.[null|subclass=Object]*/
/*omit.[null|exact=JSInvocationMirror]*/
+ /*strongConst.[null|subclass=Object]*/
+ /*omitConst.[null|exact=JSInvocationMirror]*/
im) =>
42;
}
@@ -33,6 +35,8 @@
noSuchMethod(
/*strong.[null|subclass=Object]*/
/*omit.[null|exact=JSInvocationMirror]*/
+ /*strongConst.[null|subclass=Object]*/
+ /*omitConst.[null|exact=JSInvocationMirror]*/
im) =>
42.5;
}
diff --git a/tests/compiler/dart2js/inference/data/no_such_method3.dart b/tests/compiler/dart2js/inference/data/no_such_method3.dart
index c89382c..07c56bd 100644
--- a/tests/compiler/dart2js/inference/data/no_such_method3.dart
+++ b/tests/compiler/dart2js/inference/data/no_such_method3.dart
@@ -10,6 +10,8 @@
noSuchMethod(
/*strong.[null|subclass=Object]*/
/*omit.[null|exact=JSInvocationMirror]*/
+ /*strongConst.[null|subclass=Object]*/
+ /*omitConst.[null|exact=JSInvocationMirror]*/
im) =>
throw 'foo';
}
diff --git a/tests/compiler/dart2js/inference/data/parameters_trust.dart b/tests/compiler/dart2js/inference/data/parameters_trust.dart
index fae5e390..27b45a3 100644
--- a/tests/compiler/dart2js/inference/data/parameters_trust.dart
+++ b/tests/compiler/dart2js/inference/data/parameters_trust.dart
@@ -18,6 +18,8 @@
int
/*strong.Union([exact=JSString], [exact=JSUInt31])*/
/*omit.[exact=JSUInt31]*/
+ /*strongConst.Union([exact=JSString], [exact=JSUInt31])*/
+ /*omitConst.[exact=JSUInt31]*/
i) {
return i;
}
diff --git a/tests/compiler/dart2js/inference/data/static.dart b/tests/compiler/dart2js/inference/data/static.dart
index 04fa7c3..4b65a4c 100644
--- a/tests/compiler/dart2js/inference/data/static.dart
+++ b/tests/compiler/dart2js/inference/data/static.dart
@@ -189,7 +189,10 @@
/*element: _method1:[exact=JSUInt31]*/
_method1() => 42;
-/*element: _field2:[null|subclass=Closure]*/
+/*strong.element: _field2:[null|subclass=Closure]*/
+/*omit.element: _field2:[null|subclass=Closure]*/
+/*strongConst.element: _field2:[subclass=Closure]*/
+/*omitConst.element: _field2:[subclass=Closure]*/
dynamic _field2 = _method1;
/*element: invokeStaticFieldTearOff:[null|subclass=Object]*/
@@ -202,7 +205,10 @@
/*element: _method5:Value([exact=JSString], value: "")*/
String _method5() => '';
-/*element: _field5:[null|subclass=Closure]*/
+/*strong.element: _field5:[null|subclass=Closure]*/
+/*omit.element: _field5:[null|subclass=Closure]*/
+/*strongConst.element: _field5:[subclass=Closure]*/
+/*omitConst.element: _field5:[subclass=Closure]*/
String Function() _field5 = _method5;
/*element: invokeStaticTypedFieldTearOff:[null|exact=JSString]*/
@@ -216,7 +222,10 @@
/*element: _method2:[exact=JSUInt31]*/
_method2(/*[exact=JSUInt31]*/ o) => 42;
-/*element: _field3:[null|subclass=Closure]*/
+/*strong.element: _field3:[null|subclass=Closure]*/
+/*omit.element: _field3:[null|subclass=Closure]*/
+/*strongConst.element: _field3:[subclass=Closure]*/
+/*omitConst.element: _field3:[subclass=Closure]*/
dynamic _field3 = _method2;
/*element: invokeStaticFieldTearOffParameters:[null|subclass=Object]*/
@@ -242,10 +251,16 @@
/*element: _method6:[exact=JSUInt31]*/
int _method6() => 0;
-/*element: _field7:[null|subclass=Closure]*/
+/*strong.element: _field7:[null|subclass=Closure]*/
+/*omit.element: _field7:[null|subclass=Closure]*/
+/*strongConst.element: _field7:[subclass=Closure]*/
+/*omitConst.element: _field7:[subclass=Closure]*/
int Function() _field7 = _method6;
-/*element: _getter3:[null|subclass=Closure]*/
+/*strong.element: _getter3:[null|subclass=Closure]*/
+/*omit.element: _getter3:[null|subclass=Closure]*/
+/*strongConst.element: _getter3:[subclass=Closure]*/
+/*omitConst.element: _getter3:[subclass=Closure]*/
int Function() get _getter3 => _field7;
/*element: invokeStaticTypedGetterTearOff:[null|subclass=JSInt]*/
@@ -284,7 +299,10 @@
/// arguments.
////////////////////////////////////////////////////////////////////////////////
-/*element: _field4:[null|subclass=Closure]*/
+/*strong.element: _field4:[null|subclass=Closure]*/
+/*omit.element: _field4:[null|subclass=Closure]*/
+/*strongConst.element: _field4:[subclass=Closure]*/
+/*omitConst.element: _field4:[subclass=Closure]*/
T Function<T>(T) _field4 = _method4;
/*element: invokeStaticGenericField1:[null|subclass=JSInt]*/
diff --git a/tests/compiler/dart2js/inference/inference_test_helper.dart b/tests/compiler/dart2js/inference/inference_test_helper.dart
index 5b5eb7f..9259adb 100644
--- a/tests/compiler/dart2js/inference/inference_test_helper.dart
+++ b/tests/compiler/dart2js/inference/inference_test_helper.dart
@@ -35,6 +35,7 @@
forUserLibrariesOnly: true,
args: args,
options: [stopAfterTypeInference],
+ testCFEConstants: true,
skipForStrong: skipForStrong,
shardIndex: shardIndex ?? 0,
shards: shardIndex != null ? 2 : 1);
diff --git a/tests/compiler/dart2js/serialization/data/const_literals.dart b/tests/compiler/dart2js/serialization/data/const_literals.dart
new file mode 100644
index 0000000..fb8128a
--- /dev/null
+++ b/tests/compiler/dart2js/serialization/data/const_literals.dart
@@ -0,0 +1,18 @@
+// 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.
+
+main() {
+ mapConstLiteral();
+ dictionaryConstLiteral();
+ listConstLiteral();
+ setConstLiteral();
+}
+
+mapConstLiteral() => const {0: 1};
+
+dictionaryConstLiteral() => const {'foo': 'bar'};
+
+listConstLiteral() => const ['foo', 'bar'];
+
+setConstLiteral() => const {'foo', 'bar'};