[dart2js] Narrow type of map entries in global inference based on static type.
This helps avoid some regressions from doing less static inference and depending more on the CFE static types.
Change-Id: Id95596fab87ecc9ea0c2baf3a8c21f9c90b90f94
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/348221
Reviewed-by: Mayank Patke <fishythefish@google.com>
diff --git a/pkg/compiler/lib/src/inferrer/builder.dart b/pkg/compiler/lib/src/inferrer/builder.dart
index 3a28668..e196cfd 100644
--- a/pkg/compiler/lib/src/inferrer/builder.dart
+++ b/pkg/compiler/lib/src/inferrer/builder.dart
@@ -713,12 +713,16 @@
TypeInformation visitMapLiteral(ir.MapLiteral node) {
return createMapTypeInformation(
node, node.entries.map((e) => Pair(visit(e.key)!, visit(e.value)!)),
- isConst: node.isConst);
+ isConst: node.isConst,
+ keyStaticType: _elementMap.getDartType(node.keyType),
+ valueStaticType: _elementMap.getDartType(node.valueType));
}
TypeInformation createMapTypeInformation(ir.TreeNode node,
Iterable<Pair<TypeInformation, TypeInformation>> entryTypes,
- {required bool isConst}) {
+ {required bool isConst,
+ required DartType keyStaticType,
+ required DartType valueStaticType}) {
return _inferrer.concreteTypes.putIfAbsent(node, () {
List<TypeInformation> keyTypes = [];
List<TypeInformation> valueTypes = [];
@@ -729,8 +733,8 @@
}
final type = isConst ? _types.constMapType : _types.mapType;
- return _types.allocateMap(
- type, node, _analyzedMember, keyTypes, valueTypes);
+ return _types.allocateMap(type, node, _analyzedMember, keyTypes,
+ valueTypes, keyStaticType, valueStaticType);
});
}
@@ -2334,7 +2338,9 @@
ConstantReference(expression, node),
node.entries
.map((e) => Pair(visitConstant(e.key), visitConstant(e.value))),
- isConst: true);
+ isConst: true,
+ keyStaticType: builder._elementMap.getDartType(node.keyType),
+ valueStaticType: builder._elementMap.getDartType(node.valueType));
}
@override
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index dbbbb81..304d717 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -1908,7 +1908,7 @@
String keyString = key.asString();
typeInfoMap.putIfAbsent(keyString, () {
newInfo = ValueInMapTypeInformation(
- abstractValueDomain, context, null, nonNull);
+ abstractValueDomain, context, null, valueType.staticType, nonNull);
return newInfo!;
});
typeInfoMap[keyString]!.addInput(value);
@@ -1930,7 +1930,7 @@
other.typeInfoMap.forEach((keyString, value) {
typeInfoMap.putIfAbsent(keyString, () {
final newInfo = ValueInMapTypeInformation(
- abstractValueDomain, context, null, false);
+ abstractValueDomain, context, null, valueType.staticType, false);
newInfos.add(newInfo);
return newInfo;
});
@@ -2046,8 +2046,10 @@
/// A [KeyInMapTypeInformation] holds the common type
/// for the keys in a [MapTypeInformation]
class KeyInMapTypeInformation extends InferredTypeInformation {
+ final AbstractValue staticType;
+
KeyInMapTypeInformation(
- super.abstractValueDomain, super.context, TypeInformation super.keyType);
+ super.abstractValueDomain, super.context, super.keyType, this.staticType);
@override
accept(TypeInformationVisitor visitor) {
@@ -2055,6 +2057,12 @@
}
@override
+ AbstractValue computeType(InferrerEngine inferrer) {
+ return inferrer.abstractValueDomain
+ .intersection(super.computeType(inferrer), staticType);
+ }
+
+ @override
String toString() => 'Key in Map $type';
}
@@ -2065,9 +2073,10 @@
// Note that only values assigned to a specific key value in dictionary
// mode can ever be marked as [nonNull].
bool get nonNull => _flags.hasFlag(_Flag.valueInMapNonNull);
+ final AbstractValue staticType;
- ValueInMapTypeInformation(
- super.abstractValueDomain, super.context, super.valueType,
+ ValueInMapTypeInformation(super.abstractValueDomain, super.context,
+ super.valueType, this.staticType,
[bool nonNull = false]) {
_flags = _flags.updateFlag(_Flag.valueInMapNonNull, nonNull);
}
@@ -2079,9 +2088,11 @@
@override
AbstractValue computeType(InferrerEngine inferrer) {
+ final valueType = inferrer.abstractValueDomain
+ .intersection(super.computeType(inferrer), staticType);
return nonNull
- ? super.computeType(inferrer)
- : inferrer.abstractValueDomain.includeNull(super.computeType(inferrer));
+ ? valueType
+ : inferrer.abstractValueDomain.includeNull(valueType);
}
@override
diff --git a/pkg/compiler/lib/src/inferrer/type_system.dart b/pkg/compiler/lib/src/inferrer/type_system.dart
index 5cea296..96c8efa 100644
--- a/pkg/compiler/lib/src/inferrer/type_system.dart
+++ b/pkg/compiler/lib/src/inferrer/type_system.dart
@@ -469,7 +469,9 @@
ir.TreeNode node,
MemberEntity element,
List<TypeInformation> keyTypes,
- List<TypeInformation> valueTypes) {
+ List<TypeInformation> valueTypes,
+ DartType keyStaticType,
+ DartType valueStaticType) {
assert(strategy.checkMapNode(node));
assert(keyTypes.length == valueTypes.length);
bool isFixed = (type.type == _abstractValueDomain.constMapType);
@@ -503,9 +505,19 @@
type.type, node, element, keyTypeMask, valueTypeMask);
final keyTypeInfo = KeyInMapTypeInformation(
- _abstractValueDomain, currentMember, simplifiedKeyType);
+ _abstractValueDomain,
+ currentMember,
+ simplifiedKeyType,
+ _abstractValueDomain
+ .createFromStaticType(keyStaticType, nullable: false)
+ .abstractValue);
final valueTypeInfo = ValueInMapTypeInformation(
- _abstractValueDomain, currentMember, simplifiedValueType);
+ _abstractValueDomain,
+ currentMember,
+ simplifiedValueType,
+ _abstractValueDomain
+ .createFromStaticType(valueStaticType, nullable: false)
+ .abstractValue);
allocatedTypes.add(keyTypeInfo);
allocatedTypes.add(valueTypeInfo);
diff --git a/pkg/compiler/test/inference/data/dictionary_types.dart b/pkg/compiler/test/inference/data/dictionary_types.dart
index c948951..3f807b5 100644
--- a/pkg/compiler/test/inference/data/dictionary_types.dart
+++ b/pkg/compiler/test/inference/data/dictionary_types.dart
@@ -178,7 +178,7 @@
2);
}
-/*member: dict5:Map([null|exact=JsLinkedHashMap], key: [null|subclass=Object], value: [null|subclass=Object])*/
+/*member: dict5:Map([null|exact=JsLinkedHashMap], key: [exact=JSString], value: [null|subclass=Object])*/
dynamic dict5 = makeMap5([1, 2]);
/*member: notInt5:[null|subclass=Object]*/
@@ -187,7 +187,7 @@
/*member: alsoNotInt5:[null|subclass=Object]*/
dynamic alsoNotInt5 = 0;
-/*member: makeMap5:Map([exact=JsLinkedHashMap], key: [null|subclass=Object], value: [null|subclass=Object])*/
+/*member: makeMap5:Map([exact=JsLinkedHashMap], key: [exact=JSString], value: [null|subclass=Object])*/
makeMap5(
/*Container([exact=JSExtendableArray], element: [exact=JSUInt31], length: 2)*/ values) {
return {
@@ -203,14 +203,14 @@
/*member: test5:[null]*/
test5() {
dict5
- /*update: Map([null|exact=JsLinkedHashMap], key: [null|subclass=Object], value: [null|subclass=Object])*/
+ /*update: Map([null|exact=JsLinkedHashMap], key: [exact=JSString], value: [null|subclass=Object])*/
['goo'] = 42;
var closure =
- /*Map([null|exact=JsLinkedHashMap], key: [null|subclass=Object], value: [null|subclass=Object])*/
+ /*Map([null|exact=JsLinkedHashMap], key: [exact=JSString], value: [null|subclass=Object])*/
() => dict5;
notInt5 = closure()['boo'];
alsoNotInt5 = dict5
- /*Map([null|exact=JsLinkedHashMap], key: [null|subclass=Object], value: [null|subclass=Object])*/
+ /*Map([null|exact=JsLinkedHashMap], key: [exact=JSString], value: [null|subclass=Object])*/
['goo'];
print("$notInt5 and $alsoNotInt5.");
}
diff --git a/pkg/compiler/test/inference/data/index_set.dart b/pkg/compiler/test/inference/data/index_set.dart
index 4ee4028..3b51686 100644
--- a/pkg/compiler/test/inference/data/index_set.dart
+++ b/pkg/compiler/test/inference/data/index_set.dart
@@ -106,7 +106,7 @@
mapUpdateMixedKeys() {
dynamic map = {'': 2};
return map
- /*update: Map([exact=JsLinkedHashMap], key: Union([exact=JSString], [exact=JSUInt31]), value: [null|exact=JSUInt31])*/
+ /*update: Map([exact=JsLinkedHashMap], key: [exact=JSString], value: [null|exact=JSUInt31])*/
[0] = 42;
}
@@ -118,7 +118,7 @@
mapUpdateMixedValues() {
dynamic map = {2: ''};
return map
- /*update: Map([exact=JsLinkedHashMap], key: [exact=JSUInt31], value: Union(null, [exact=JSString], [exact=JSUInt31]))*/
+ /*update: Map([exact=JsLinkedHashMap], key: [exact=JSUInt31], value: [null|exact=JSString])*/
[2] = 42;
}