Compute static types for for-in loops
Change-Id: I47e98eaf6df7d04286cb737bfdff135e6c0d34d2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/100843
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/ir/cached_static_type.dart b/pkg/compiler/lib/src/ir/cached_static_type.dart
index 6067b5e..ea00634 100644
--- a/pkg/compiler/lib/src/ir/cached_static_type.dart
+++ b/pkg/compiler/lib/src/ir/cached_static_type.dart
@@ -8,12 +8,14 @@
import 'package:kernel/type_algebra.dart' as ir;
import 'package:kernel/type_environment.dart' as ir;
import 'static_type_base.dart';
+import 'static_type_cache.dart';
import 'static_type_provider.dart';
/// Class that provides the static type of expression using the visitor pattern
/// and a precomputed cache for complex expression type.
class CachedStaticType extends StaticTypeBase implements StaticTypeProvider {
- final Map<ir.Expression, ir.DartType> _cache;
+ final StaticTypeCache _cache;
+
@override
final ThisInterfaceType thisType;
@@ -28,6 +30,13 @@
return type;
}
+ @override
+ ir.DartType getForInIteratorType(ir.ForInStatement node) {
+ ir.DartType type = _cache.getForInIteratorType(node);
+ assert(type != null, "No for-in iterator type found for ${node}.");
+ return type;
+ }
+
ir.DartType _getStaticType(ir.Expression node) {
ir.DartType type = _cache[node];
assert(type != null, "No static type cached for ${node.runtimeType}.");
diff --git a/pkg/compiler/lib/src/ir/impact.dart b/pkg/compiler/lib/src/ir/impact.dart
index d635b78..8799d9b 100644
--- a/pkg/compiler/lib/src/ir/impact.dart
+++ b/pkg/compiler/lib/src/ir/impact.dart
@@ -15,7 +15,7 @@
import 'runtime_type_analysis.dart';
import 'scope.dart';
import 'static_type.dart';
-import 'static_type_base.dart';
+import 'static_type_cache.dart';
import 'util.dart';
/// Interface for collecting world impact data.
@@ -77,9 +77,11 @@
void registerThrow();
- void registerSyncForIn(ir.DartType iterableType);
+ void registerSyncForIn(ir.DartType iterableType, ir.DartType iteratorType,
+ ClassRelation iteratorClassRelation);
- void registerAsyncForIn(ir.DartType iterableType);
+ void registerAsyncForIn(ir.DartType iterableType, ir.DartType iteratorType,
+ ClassRelation iteratorClassRelation);
void registerCatch();
@@ -200,16 +202,6 @@
ir.ClassHierarchy classHierarchy, this.variableScopeModel)
: super(typeEnvironment, classHierarchy);
- ClassRelation _computeClassRelationFromType(ir.DartType type) {
- if (type is ThisInterfaceType) {
- return ClassRelation.thisExpression;
- } else if (type is ExactInterfaceType) {
- return ClassRelation.exact;
- } else {
- return ClassRelation.subtype;
- }
- }
-
@override
void handleIntLiteral(ir.IntLiteral node) {
registerIntLiteral(node.value);
@@ -378,11 +370,14 @@
}
@override
- void handleForInStatement(ir.ForInStatement node, ir.DartType iterableType) {
+ void handleForInStatement(ir.ForInStatement node, ir.DartType iterableType,
+ ir.DartType iteratorType) {
if (node.isAsync) {
- registerAsyncForIn(iterableType);
+ registerAsyncForIn(iterableType, iteratorType,
+ computeClassRelationFromType(iteratorType));
} else {
- registerSyncForIn(iterableType);
+ registerSyncForIn(iterableType, iteratorType,
+ computeClassRelationFromType(iteratorType));
}
}
@@ -536,7 +531,7 @@
registerLocalFunctionInvocation(receiver.variable.parent,
positionArguments, namedArguments, typeArguments);
} else {
- ClassRelation relation = _computeClassRelationFromType(receiverType);
+ ClassRelation relation = computeClassRelationFromType(receiverType);
ir.Member interfaceTarget = node.interfaceTarget;
if (interfaceTarget == null) {
@@ -584,7 +579,7 @@
@override
void handlePropertyGet(
ir.PropertyGet node, ir.DartType receiverType, ir.DartType resultType) {
- ClassRelation relation = _computeClassRelationFromType(receiverType);
+ ClassRelation relation = computeClassRelationFromType(receiverType);
if (node.interfaceTarget != null) {
registerInstanceGet(receiverType, relation, node.interfaceTarget);
} else {
@@ -601,7 +596,7 @@
@override
void handlePropertySet(
ir.PropertySet node, ir.DartType receiverType, ir.DartType valueType) {
- ClassRelation relation = _computeClassRelationFromType(receiverType);
+ ClassRelation relation = computeClassRelationFromType(receiverType);
if (node.interfaceTarget != null) {
registerInstanceSet(receiverType, relation, node.interfaceTarget);
} else {
@@ -682,7 +677,7 @@
}
node.accept(this);
return new ImpactBuilderData(
- impactData, typeMapsForTesting, cachedStaticTypes);
+ impactData, typeMapsForTesting, getStaticTypeCache());
}
}
@@ -693,7 +688,7 @@
class ImpactBuilderData {
final ImpactData impactData;
final Map<ir.Expression, TypeMap> typeMapsForTesting;
- final Map<ir.Expression, ir.DartType> cachedStaticTypes;
+ final StaticTypeCache cachedStaticTypes;
ImpactBuilderData(
this.impactData, this.typeMapsForTesting, this.cachedStaticTypes);
diff --git a/pkg/compiler/lib/src/ir/impact_data.dart b/pkg/compiler/lib/src/ir/impact_data.dart
index 543d3ed..79a7960 100644
--- a/pkg/compiler/lib/src/ir/impact_data.dart
+++ b/pkg/compiler/lib/src/ir/impact_data.dart
@@ -259,13 +259,21 @@
}
@override
- void registerAsyncForIn(ir.DartType iterableType) {
- _registerTypeUse(iterableType, _TypeUseKind.asyncForIn);
+ void registerAsyncForIn(ir.DartType iterableType, ir.DartType iteratorType,
+ ClassRelation iteratorClassRelation) {
+ _data._forInData ??= [];
+ _data._forInData.add(new _ForInData(
+ iterableType, iteratorType, iteratorClassRelation,
+ isAsync: true));
}
@override
- void registerSyncForIn(ir.DartType iterableType) {
- _registerTypeUse(iterableType, _TypeUseKind.syncForIn);
+ void registerSyncForIn(ir.DartType iterableType, ir.DartType iteratorType,
+ ClassRelation iteratorClassRelation) {
+ _data._forInData ??= [];
+ _data._forInData.add(new _ForInData(
+ iterableType, iteratorType, iteratorClassRelation,
+ isAsync: false));
}
@override
@@ -506,6 +514,7 @@
List<double> _doubleLiterals;
List<int> _intLiterals;
List<_RuntimeTypeUse> _runtimeTypeUses;
+ List<_ForInData> _forInData;
// TODO(johnniwinther): Remove these when CFE provides constants.
List<ir.Constructor> _constructorNodes;
@@ -868,12 +877,6 @@
case _TypeUseKind.catchType:
registry.registerCatchType(data.type);
break;
- case _TypeUseKind.asyncForIn:
- registry.registerAsyncForIn(data.type);
- break;
- case _TypeUseKind.syncForIn:
- registry.registerSyncForIn(data.type);
- break;
case _TypeUseKind.asCast:
registry.registerAsCast(data.type);
break;
@@ -997,6 +1000,17 @@
data.node, data.kind, data.receiverType, data.argumentType);
}
}
+ if (_forInData != null) {
+ for (_ForInData data in _forInData) {
+ if (data.isAsync) {
+ registry.registerAsyncForIn(
+ data.iterableType, data.iteratorType, data.iteratorClassRelation);
+ } else {
+ registry.registerSyncForIn(
+ data.iterableType, data.iteratorType, data.iteratorClassRelation);
+ }
+ }
+ }
// TODO(johnniwinther): Remove these when CFE provides constants.
if (_constructorNodes != null) {
@@ -1415,8 +1429,6 @@
enum _TypeUseKind {
parameterCheck,
catchType,
- asyncForIn,
- syncForIn,
asCast,
implicitCast,
isCheck,
@@ -1606,3 +1618,34 @@
sink.end(tag);
}
}
+
+class _ForInData {
+ static const String tag = '_ForInData';
+
+ final ir.DartType iterableType;
+ final ir.DartType iteratorType;
+ final ClassRelation iteratorClassRelation;
+ final bool isAsync;
+
+ _ForInData(this.iterableType, this.iteratorType, this.iteratorClassRelation,
+ {this.isAsync});
+
+ factory _ForInData.fromDataSource(DataSource source) {
+ source.begin(tag);
+ ir.DartType iterableType = source.readDartTypeNode();
+ ir.DartType iteratorType = source.readDartTypeNode(allowNull: true);
+ ClassRelation iteratorClassRelation = source.readEnum(ClassRelation.values);
+ bool isAsync = source.readBool();
+ return new _ForInData(iterableType, iteratorType, iteratorClassRelation,
+ isAsync: isAsync);
+ }
+
+ void toDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeDartTypeNode(iterableType);
+ sink.writeDartTypeNode(iteratorType);
+ sink.writeEnum(iteratorClassRelation);
+ sink.writeBool(isAsync);
+ sink.end(tag);
+ }
+}
diff --git a/pkg/compiler/lib/src/ir/static_type.dart b/pkg/compiler/lib/src/ir/static_type.dart
index 7aee79e..a1bc702 100644
--- a/pkg/compiler/lib/src/ir/static_type.dart
+++ b/pkg/compiler/lib/src/ir/static_type.dart
@@ -12,6 +12,7 @@
import 'runtime_type_analysis.dart';
import 'scope.dart';
import 'static_type_base.dart';
+import 'static_type_cache.dart';
/// Enum values for how the target of a static type should be interpreted.
enum ClassRelation {
@@ -27,6 +28,16 @@
exact,
}
+ClassRelation computeClassRelationFromType(ir.DartType type) {
+ if (type is ThisInterfaceType) {
+ return ClassRelation.thisExpression;
+ } else if (type is ExactInterfaceType) {
+ return ClassRelation.exact;
+ } else {
+ return ClassRelation.subtype;
+ }
+}
+
/// Visitor that computes and caches the static type of expression while
/// visiting the full tree at expression level.
///
@@ -35,7 +46,8 @@
/// adds 'handleX' hooks for subclasses to handle individual expressions using
/// the readily compute static types of subexpressions.
abstract class StaticTypeVisitor extends StaticTypeBase {
- Map<ir.Expression, ir.DartType> _cache = {};
+ final Map<ir.Expression, ir.DartType> _expressionTypeCache = {};
+ Map<ir.ForInStatement, ir.DartType> _forInIteratorTypeCache;
Map<ir.Expression, TypeMap> typeMapsForTesting;
Map<ir.PropertyGet, RuntimeTypeUseData> _pendingRuntimeTypeUseData = {};
@@ -46,7 +58,9 @@
StaticTypeVisitor(ir.TypeEnvironment typeEnvironment, this.hierarchy)
: super(typeEnvironment);
- Map<ir.Expression, ir.DartType> get cachedStaticTypes => _cache;
+ StaticTypeCache getStaticTypeCache() {
+ return new StaticTypeCache(_expressionTypeCache, _forInIteratorTypeCache);
+ }
/// If `true`, the effect of executing assert statements is taken into account
/// when computing the static type.
@@ -141,6 +155,13 @@
visitNodes(node.fields);
}
+ ir.InterfaceType getInterfaceTypeOf(ir.DartType type) {
+ while (type is ir.TypeParameterType) {
+ type = (type as ir.TypeParameterType).parameter.bound;
+ }
+ return type is ir.InterfaceType ? type : null;
+ }
+
/// Returns the static type of the expression as an instantiation of
/// [superclass].
///
@@ -215,8 +236,8 @@
@override
ir.DartType visitPropertyGet(ir.PropertyGet node) {
ir.DartType receiverType = visitNode(node.receiver);
- ir.DartType resultType =
- _cache[node] = _computePropertyGetType(node, receiverType);
+ ir.DartType resultType = _expressionTypeCache[node] =
+ _computePropertyGetType(node, receiverType);
receiverType = _narrowInstanceReceiver(node.interfaceTarget, receiverType);
handlePropertyGet(node, receiverType, resultType);
if (node.name.name == Identifiers.runtimeType_) {
@@ -297,7 +318,7 @@
receiverType = getTypeAsInstanceOf(receiverType, superclass);
ir.DartType resultType = ir.Substitution.fromInterfaceType(receiverType)
.substituteType(node.target.getterType);
- _cache[node] = resultType;
+ _expressionTypeCache[node] = resultType;
handleDirectPropertyGet(node, receiverType, resultType);
return resultType;
}
@@ -326,7 +347,7 @@
node.target.function.typeParameters, node.arguments.types)
.substituteType(returnType);
}
- _cache[node] = returnType;
+ _expressionTypeCache[node] = returnType;
handleDirectMethodInvocation(node, receiverType, argumentTypes, returnType);
return returnType;
}
@@ -500,7 +521,7 @@
ir.VariableGet get = new ir.VariableGet(variable)..parent = parent;
// Visit the newly created variable get.
handleVariableGet(get, argumentType);
- cachedStaticTypes[get] = argumentType;
+ _expressionTypeCache[get] = argumentType;
if (checkedParameterType == null) {
return get;
@@ -682,7 +703,7 @@
.promote(right.variable, right.variable.type, isTrue: true);
}
}
- _cache[node] = returnType;
+ _expressionTypeCache[node] = returnType;
handleMethodInvocation(node, receiverType, argumentTypes, returnType);
return returnType;
}
@@ -701,7 +722,7 @@
typeEnvironment.isSubtypeOf(promotedType, node.promotedType),
"Unexpected promotion of ${node.variable} in ${node.parent}. "
"Expected ${node.promotedType}, found $promotedType");
- _cache[node] = promotedType;
+ _expressionTypeCache[node] = promotedType;
handleVariableGet(node, promotedType);
return promotedType;
}
@@ -748,7 +769,7 @@
ir.DartType returnType = ir.Substitution.fromPairs(
node.target.function.typeParameters, node.arguments.types)
.substituteType(node.target.function.returnType);
- _cache[node] = returnType;
+ _expressionTypeCache[node] = returnType;
handleStaticInvocation(node, argumentTypes, returnType);
return returnType;
}
@@ -763,7 +784,7 @@
? new ExactInterfaceType.from(node.target.enclosingClass.rawType)
: new ExactInterfaceType(
node.target.enclosingClass, node.arguments.types);
- _cache[node] = resultType;
+ _expressionTypeCache[node] = resultType;
handleConstructorInvocation(node, argumentTypes, resultType);
return resultType;
}
@@ -788,7 +809,7 @@
.substituteType(node.interfaceTarget.getterType);
}
}
- _cache[node] = resultType;
+ _expressionTypeCache[node] = resultType;
handleSuperPropertyGet(node, resultType);
return resultType;
}
@@ -824,7 +845,7 @@
node.arguments.types)
.substituteType(returnType);
}
- _cache[node] = returnType;
+ _expressionTypeCache[node] = returnType;
handleSuperMethodInvocation(node, argumentTypes, returnType);
return returnType;
}
@@ -943,7 +964,7 @@
ir.DartType visitInstantiation(ir.Instantiation node) {
ir.FunctionType expressionType = visitNode(node.expression);
ir.DartType resultType = _computeInstantiationType(node, expressionType);
- _cache[node] = resultType;
+ _expressionTypeCache[node] = resultType;
handleInstantiation(node, expressionType, resultType);
return resultType;
}
@@ -1172,16 +1193,42 @@
typeMap = beforeLoop;
}
- void handleForInStatement(ir.ForInStatement node, ir.DartType iterableType) {}
+ void handleForInStatement(ir.ForInStatement node, ir.DartType iterableType,
+ ir.DartType iteratorType) {}
@override
Null visitForInStatement(ir.ForInStatement node) {
+ // For sync for-in [iterableType] is a subtype of `Iterable`, for async
+ // for-in [iterableType] is a subtype of `Stream`.
ir.DartType iterableType = visitNode(node.iterable);
+ ir.DartType iteratorType = const ir.DynamicType();
+ if (node.isAsync) {
+ ir.InterfaceType streamInterfaceType = getInterfaceTypeOf(iterableType);
+ ir.InterfaceType streamType = typeEnvironment.getTypeAsInstanceOf(
+ streamInterfaceType, typeEnvironment.coreTypes.streamClass);
+ if (streamType != null) {
+ iteratorType = new ir.InterfaceType(
+ typeEnvironment.coreTypes.streamIteratorClass,
+ streamType.typeArguments);
+ }
+ } else {
+ ir.InterfaceType iterableInterfaceType = getInterfaceTypeOf(iterableType);
+ ir.Member member = hierarchy.getInterfaceMember(
+ iterableInterfaceType.classNode, new ir.Name(Identifiers.iterator));
+ if (member != null) {
+ iteratorType = ir.Substitution.fromInterfaceType(
+ typeEnvironment.getTypeAsInstanceOf(
+ iterableInterfaceType, member.enclosingClass))
+ .substituteType(member.getterType);
+ }
+ }
+ _forInIteratorTypeCache ??= {};
+ _forInIteratorTypeCache[node] = iteratorType;
TypeMap beforeLoop = typeMap =
typeMap.remove(variableScopeModel.getScopeFor(node).assignedVariables);
visitNode(node.variable);
visitNode(node.body);
- handleForInStatement(node, iterableType);
+ handleForInStatement(node, iterableType, iteratorType);
typeMap = beforeLoop;
}
diff --git a/pkg/compiler/lib/src/ir/static_type_cache.dart b/pkg/compiler/lib/src/ir/static_type_cache.dart
new file mode 100644
index 0000000..64cf6b8
--- /dev/null
+++ b/pkg/compiler/lib/src/ir/static_type_cache.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2017, 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' as ir;
+import 'package:kernel/class_hierarchy.dart' as ir;
+import 'package:kernel/core_types.dart' as ir;
+import 'package:kernel/type_algebra.dart' as ir;
+import 'package:kernel/type_environment.dart' as ir;
+
+import '../serialization/serialization.dart';
+
+class StaticTypeCache {
+ static const String tag = 'static-type-cache';
+
+ final Map<ir.Expression, ir.DartType> _expressionTypes;
+ final Map<ir.ForInStatement, ir.DartType> _forInIteratorTypes;
+
+ const StaticTypeCache(
+ [this._expressionTypes = const {}, this._forInIteratorTypes]);
+
+ factory StaticTypeCache.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ Map<ir.Expression, ir.DartType> expressionTypes =
+ source.readTreeNodeMap(source.readDartTypeNode);
+ Map<ir.ForInStatement, ir.DartType> forInIteratorTypes =
+ source.readTreeNodeMap(source.readDartTypeNode, emptyAsNull: true);
+ source.end(tag);
+ return new StaticTypeCache(expressionTypes, forInIteratorTypes);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeTreeNodeMap(_expressionTypes, sink.writeDartTypeNode);
+ sink.writeTreeNodeMap(_forInIteratorTypes, sink.writeDartTypeNode,
+ allowNull: true);
+ sink.end(tag);
+ }
+
+ ir.DartType operator [](ir.Expression node) => _expressionTypes[node];
+
+ ir.DartType getForInIteratorType(ir.ForInStatement node) {
+ return _forInIteratorTypes != null ? _forInIteratorTypes[node] : null;
+ }
+}
diff --git a/pkg/compiler/lib/src/ir/static_type_provider.dart b/pkg/compiler/lib/src/ir/static_type_provider.dart
index 2901f34..ee0db10 100644
--- a/pkg/compiler/lib/src/ir/static_type_provider.dart
+++ b/pkg/compiler/lib/src/ir/static_type_provider.dart
@@ -11,4 +11,5 @@
/// Interface for accessing static types on expressions.
abstract class StaticTypeProvider {
ir.DartType getStaticType(ir.Expression node);
+ ir.DartType getForInIteratorType(ir.ForInStatement node);
}
diff --git a/pkg/compiler/lib/src/js_model/closure.dart b/pkg/compiler/lib/src/js_model/closure.dart
index 61847ff..bb595f5 100644
--- a/pkg/compiler/lib/src/js_model/closure.dart
+++ b/pkg/compiler/lib/src/js_model/closure.dart
@@ -12,6 +12,7 @@
import '../elements/types.dart';
import '../ir/closure.dart';
import '../ir/element_map.dart';
+import '../ir/static_type_cache.dart';
import '../js_model/element_map.dart';
import '../js_model/env.dart';
import '../ordered_typeset.dart';
@@ -1065,7 +1066,7 @@
ClosureMemberData(this.definition, this.memberThisType);
@override
- Map<ir.Expression, ir.DartType> get staticTypes {
+ StaticTypeCache get staticTypes {
// The cached types are stored in the data for enclosing member.
throw new UnsupportedError("ClosureMemberData.staticTypes");
}
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index 1b9694b..be39539 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -33,6 +33,7 @@
import '../ir/types.dart';
import '../ir/visitors.dart';
import '../ir/static_type_base.dart';
+import '../ir/static_type_cache.dart';
import '../ir/static_type_provider.dart';
import '../ir/util.dart';
import '../js/js.dart' as js;
@@ -1143,7 +1144,7 @@
@override
StaticTypeProvider getStaticTypeProvider(MemberEntity member) {
MemberDefinition memberDefinition = members.getData(member).definition;
- Map<ir.Expression, ir.DartType> cachedStaticTypes;
+ StaticTypeCache cachedStaticTypes;
ir.InterfaceType thisType;
switch (memberDefinition.kind) {
case MemberKind.regular:
@@ -1168,7 +1169,7 @@
case MemberKind.closureField:
case MemberKind.signature:
case MemberKind.generatorBody:
- cachedStaticTypes = const {};
+ cachedStaticTypes = const StaticTypeCache();
break;
}
diff --git a/pkg/compiler/lib/src/js_model/env.dart b/pkg/compiler/lib/src/js_model/env.dart
index 4bd4808..9017330 100644
--- a/pkg/compiler/lib/src/js_model/env.dart
+++ b/pkg/compiler/lib/src/js_model/env.dart
@@ -14,6 +14,7 @@
import '../elements/indexed.dart';
import '../elements/types.dart';
import '../ir/element_map.dart';
+import '../ir/static_type_cache.dart';
import '../ir/visitors.dart';
import '../js_model/element_map.dart';
import '../ordered_typeset.dart';
@@ -520,7 +521,7 @@
ClassTypeVariableAccess get classTypeVariableAccess;
- Map<ir.Expression, ir.DartType> get staticTypes;
+ StaticTypeCache get staticTypes;
JMemberData();
@@ -559,7 +560,7 @@
final MemberDefinition definition;
@override
- final Map<ir.Expression, ir.DartType> staticTypes;
+ final StaticTypeCache staticTypes;
JMemberDataImpl(this.node, this.definition, this.staticTypes);
@@ -659,7 +660,7 @@
FunctionType _type;
FunctionDataImpl(ir.Member node, this.functionNode,
- MemberDefinition definition, Map<ir.Expression, ir.DartType> staticTypes)
+ MemberDefinition definition, StaticTypeCache staticTypes)
: super(node, definition, staticTypes);
factory FunctionDataImpl.readFromDataSource(DataSource source) {
@@ -676,8 +677,8 @@
}
MemberDefinition definition =
new MemberDefinition.readFromDataSource(source);
- Map<ir.Expression, ir.DartType> staticTypes =
- source.readTreeNodeMap(() => source.readDartTypeNode());
+ StaticTypeCache staticTypes =
+ new StaticTypeCache.readFromDataSource(source);
source.end(tag);
return new FunctionDataImpl(node, functionNode, definition, staticTypes);
}
@@ -688,7 +689,7 @@
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
- sink.writeTreeNodeMap(staticTypes, sink.writeDartTypeNode);
+ staticTypes.writeToDataSink(sink);
sink.end(tag);
}
@@ -744,7 +745,7 @@
}
@override
- Map<ir.Expression, ir.DartType> get staticTypes => const {};
+ StaticTypeCache get staticTypes => const StaticTypeCache();
@override
FunctionType getFunctionType(covariant JsKernelToElementMap elementMap) {
@@ -840,7 +841,7 @@
}
@override
- Map<ir.Expression, ir.DartType> get staticTypes => const {};
+ StaticTypeCache get staticTypes => const StaticTypeCache();
}
abstract class JConstructorData extends FunctionData {
@@ -858,7 +859,7 @@
JConstructorBody constructorBody;
JConstructorDataImpl(ir.Member node, ir.FunctionNode functionNode,
- MemberDefinition definition, Map<ir.Expression, ir.DartType> staticTypes)
+ MemberDefinition definition, StaticTypeCache staticTypes)
: super(node, functionNode, definition, staticTypes);
factory JConstructorDataImpl.readFromDataSource(DataSource source) {
@@ -875,8 +876,8 @@
}
MemberDefinition definition =
new MemberDefinition.readFromDataSource(source);
- Map<ir.Expression, ir.DartType> staticTypes =
- source.readTreeNodeMap(() => source.readDartTypeNode());
+ StaticTypeCache staticTypes =
+ new StaticTypeCache.readFromDataSource(source);
source.end(tag);
return new JConstructorDataImpl(
node, functionNode, definition, staticTypes);
@@ -889,7 +890,7 @@
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
assert(constructorBody == null);
- sink.writeTreeNodeMap(staticTypes, sink.writeDartTypeNode);
+ staticTypes.writeToDataSink(sink);
sink.end(tag);
}
@@ -921,7 +922,7 @@
static const String tag = 'constructor-body-data';
ConstructorBodyDataImpl(ir.Member node, ir.FunctionNode functionNode,
- MemberDefinition definition, Map<ir.Expression, ir.DartType> staticTypes)
+ MemberDefinition definition, StaticTypeCache staticTypes)
: super(node, functionNode, definition, staticTypes);
factory ConstructorBodyDataImpl.readFromDataSource(DataSource source) {
@@ -938,8 +939,8 @@
}
MemberDefinition definition =
new MemberDefinition.readFromDataSource(source);
- Map<ir.Expression, ir.DartType> staticTypes =
- source.readTreeNodeMap(() => source.readDartTypeNode());
+ StaticTypeCache staticTypes =
+ new StaticTypeCache.readFromDataSource(source);
source.end(tag);
return new ConstructorBodyDataImpl(
node, functionNode, definition, staticTypes);
@@ -951,7 +952,7 @@
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
- sink.writeTreeNodeMap(staticTypes, sink.writeDartTypeNode);
+ staticTypes.writeToDataSink(sink);
sink.end(tag);
}
@@ -977,8 +978,8 @@
DartType _type;
ConstantExpression _constantExpression;
- JFieldDataImpl(ir.Field node, MemberDefinition definition,
- Map<ir.Expression, ir.DartType> staticTypes)
+ JFieldDataImpl(
+ ir.Field node, MemberDefinition definition, StaticTypeCache staticTypes)
: super(node, definition, staticTypes);
factory JFieldDataImpl.readFromDataSource(DataSource source) {
@@ -986,8 +987,8 @@
ir.Member node = source.readMemberNode();
MemberDefinition definition =
new MemberDefinition.readFromDataSource(source);
- Map<ir.Expression, ir.DartType> staticTypes =
- source.readTreeNodeMap(() => source.readDartTypeNode());
+ StaticTypeCache staticTypes =
+ new StaticTypeCache.readFromDataSource(source);
source.end(tag);
return new JFieldDataImpl(node, definition, staticTypes);
}
@@ -998,7 +999,7 @@
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
- sink.writeTreeNodeMap(staticTypes, sink.writeDartTypeNode);
+ staticTypes.writeToDataSink(sink);
sink.end(tag);
}
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 7a2b12a..bb8f069 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -34,6 +34,7 @@
import '../ir/impact.dart';
import '../ir/impact_data.dart';
import '../ir/static_type.dart';
+import '../ir/static_type_cache.dart';
import '../ir/scope.dart';
import '../ir/types.dart';
import '../ir/visitors.dart';
@@ -1389,14 +1390,13 @@
typeMapsForTesting[member] = builder.typeMapsForTesting = {};
}
node.accept(builder);
- memberData.staticTypes = builder.cachedStaticTypes;
+ memberData.staticTypes = builder.getStaticTypeCache();
return builder.impactBuilder;
}
}
- Map<ir.Expression, ir.DartType> getCachedStaticTypes(KMember member) {
- Map<ir.Expression, ir.DartType> staticTypes =
- members.getData(member).staticTypes;
+ StaticTypeCache getCachedStaticTypes(KMember member) {
+ StaticTypeCache staticTypes = members.getData(member).staticTypes;
assert(staticTypes != null, "No static types cached for $member.");
return staticTypes;
}
diff --git a/pkg/compiler/lib/src/kernel/env.dart b/pkg/compiler/lib/src/kernel/env.dart
index 0f004e3..c76aaaa 100644
--- a/pkg/compiler/lib/src/kernel/env.dart
+++ b/pkg/compiler/lib/src/kernel/env.dart
@@ -19,6 +19,7 @@
import '../elements/entities.dart';
import '../elements/types.dart';
import '../ir/element_map.dart';
+import '../ir/static_type_cache.dart';
import '../ir/visitors.dart';
import '../ir/util.dart';
import '../js_model/element_map.dart';
@@ -669,7 +670,7 @@
abstract class KMemberData {
ir.Member get node;
- Map<ir.Expression, ir.DartType> staticTypes;
+ StaticTypeCache staticTypes;
Iterable<ConstantValue> getMetadata(IrToElementMap elementMap);
@@ -688,7 +689,7 @@
Iterable<ConstantValue> _metadata;
@override
- Map<ir.Expression, ir.DartType> staticTypes;
+ StaticTypeCache staticTypes;
KMemberDataImpl(this.node);
diff --git a/pkg/compiler/lib/src/kernel/kernel_impact.dart b/pkg/compiler/lib/src/kernel/kernel_impact.dart
index e32ea87..6041116 100644
--- a/pkg/compiler/lib/src/kernel/kernel_impact.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_impact.dart
@@ -739,23 +739,31 @@
}
@override
- void registerSyncForIn(ir.DartType iterableType) {
- // TODO(johnniwinther): Use receiver constraints for the dynamic uses in
- // strong mode.
+ void registerSyncForIn(ir.DartType iterableType, ir.DartType iteratorType,
+ ClassRelation iteratorClassRelation) {
+ Object receiverConstraint =
+ _computeReceiverConstraint(iteratorType, iteratorClassRelation);
impactBuilder.registerFeature(Feature.SYNC_FOR_IN);
- impactBuilder.registerDynamicUse(new DynamicUse(Selectors.iterator));
- impactBuilder.registerDynamicUse(new DynamicUse(Selectors.current));
- impactBuilder.registerDynamicUse(new DynamicUse(Selectors.moveNext));
+ impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
+ Selectors.iterator, receiverConstraint, const []));
+ impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
+ Selectors.current, receiverConstraint, const []));
+ impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
+ Selectors.moveNext, receiverConstraint, const []));
}
@override
- void registerAsyncForIn(ir.DartType iterableType) {
- // TODO(johnniwinther): Use receiver constraints for the dynamic uses in
- // strong mode.
+ void registerAsyncForIn(ir.DartType iterableType, ir.DartType iteratorType,
+ ClassRelation iteratorClassRelation) {
+ Object receiverConstraint =
+ _computeReceiverConstraint(iteratorType, iteratorClassRelation);
impactBuilder.registerFeature(Feature.ASYNC_FOR_IN);
- impactBuilder.registerDynamicUse(new DynamicUse(Selectors.cancel));
- impactBuilder.registerDynamicUse(new DynamicUse(Selectors.current));
- impactBuilder.registerDynamicUse(new DynamicUse(Selectors.moveNext));
+ impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
+ Selectors.cancel, receiverConstraint, const []));
+ impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
+ Selectors.current, receiverConstraint, const []));
+ impactBuilder.registerDynamicUse(new ConstrainedDynamicUse(
+ Selectors.moveNext, receiverConstraint, const []));
}
@override
diff --git a/tests/compiler/dart2js/codegen/model_data/dynamic_get.dart b/tests/compiler/dart2js/codegen/model_data/dynamic_get.dart
index 81c7601..e7f67fb 100644
--- a/tests/compiler/dart2js/codegen/model_data/dynamic_get.dart
+++ b/tests/compiler/dart2js/codegen/model_data/dynamic_get.dart
@@ -63,6 +63,7 @@
class Class4b implements Class4a {
/*element: Class4b.field4:emitted,get=simple*/
@pragma('dart2js:noElision')
+ @override
int field4;
}
diff --git a/tests/compiler/dart2js/impact/data/async.dart b/tests/compiler/dart2js/impact/data/async.dart
index 69792ef..bde8eb7 100644
--- a/tests/compiler/dart2js/impact/data/async.dart
+++ b/tests/compiler/dart2js/impact/data/async.dart
@@ -219,9 +219,9 @@
/*element: testAsyncForIn:
dynamic=[
- cancel(0),
- current,
- moveNext(0)],
+ _StreamIterator.cancel(0),
+ _StreamIterator.current,
+ _StreamIterator.moveNext(0)],
static=[
StreamIterator.(1),
_asyncAwait(2),
@@ -243,9 +243,9 @@
/*element: testAsyncForInTyped:
dynamic=[
- cancel(0),
- current,
- moveNext(0)],
+ _StreamIterator.cancel(0),
+ _StreamIterator.current,
+ _StreamIterator.moveNext(0)],
static=[
StreamIterator.(1),
_asyncAwait(2),
diff --git a/tests/compiler/dart2js/impact/data/statements.dart b/tests/compiler/dart2js/impact/data/statements.dart
index 3b5e240..7a89d28 100644
--- a/tests/compiler/dart2js/impact/data/statements.dart
+++ b/tests/compiler/dart2js/impact/data/statements.dart
@@ -67,9 +67,9 @@
/*element: testForIn:
dynamic=[
- current,
- iterator,
- moveNext(0)],
+ Iterator.current,
+ Iterator.iterator,
+ Iterator.moveNext(0)],
static=[checkConcurrentModificationError(2)],
type=[
impl:Iterable<dynamic>,
@@ -84,9 +84,9 @@
/*element: testForInTyped:
dynamic=[
- current,
- iterator,
- moveNext(0)],
+ Iterator.current,
+ Iterator.iterator,
+ Iterator.moveNext(0)],
static=[checkConcurrentModificationError(2)],
type=[
impl:Iterable<dynamic>,
diff --git a/tests/compiler/dart2js/inference/data/field_type.dart b/tests/compiler/dart2js/inference/data/field_type.dart
index 4f499a9..d97d431 100644
--- a/tests/compiler/dart2js/inference/data/field_type.dart
+++ b/tests/compiler/dart2js/inference/data/field_type.dart
@@ -24,7 +24,9 @@
test18();
test19();
test20();
+ test20b();
test21();
+ test21b();
test22();
test23();
test24();
@@ -460,26 +462,22 @@
}
class A20 {
- /*element: A20.f20:[null|exact=JSUInt31]*/
+ /*element: A20.f20:[null]*/
var f20;
/*element: A20.:[exact=A20]*/
A20() {
dynamic a = this;
- // TODO(johnniwinther): Fix ast equivalence on instance fields in for.
/*iterator: [exact=A20]*/
- /*current: [exact=A20]*/
- /*moveNext: [exact=A20]*/
+ /*current: [empty]*/
+ /*moveNext: [empty]*/
for (/*update: [exact=A20]*/ f20 in a) {}
}
- /*element: A20.iterator:[exact=A20]*/
get iterator => this;
- /*element: A20.current:[exact=JSUInt31]*/
get current => 42;
- /*element: A20.moveNext:Value([exact=JSBool], value: false)*/
bool moveNext() => false;
}
@@ -488,6 +486,37 @@
new A20();
}
+class A20b extends Iterable implements Iterator {
+ /*element: A20b.f20b:[null|exact=JSUInt31]*/
+ var f20b;
+
+ /*element: A20b.:[exact=A20b]*/
+ A20b() {
+ dynamic a = this;
+ /*iterator: [exact=A20b]*/
+ /*current: [exact=A20b]*/
+ /*moveNext: [exact=A20b]*/
+ for (/*update: [exact=A20b]*/ f20b in a) {}
+ }
+
+ /*element: A20b.iterator:[exact=A20b]*/
+ @override
+ get iterator => this;
+
+ /*element: A20b.current:[exact=JSUInt31]*/
+ @override
+ get current => 42;
+
+ /*element: A20b.moveNext:Value([exact=JSBool], value: false)*/
+ @override
+ bool moveNext() => false;
+}
+
+/*element: test20b:[null]*/
+test20b() {
+ new A20b();
+}
+
class A21 {
/*element: A21.f21:[null|exact=JSUInt31]*/
var f21;
@@ -496,14 +525,14 @@
A21() {
dynamic a = this;
/*iterator: [exact=A21]*/
- /*current: [null]*/
- /*moveNext: [null]*/
+ /*current: [empty]*/
+ /*moveNext: [empty]*/
for (
// ignore: unused_local_variable
var i in a) {}
/*update: [exact=A21]*/ f21 = 42;
}
- /*element: A21.iterator:[null]*/
+
get iterator => null;
}
@@ -512,6 +541,32 @@
new A21();
}
+class A21b extends Iterable {
+ /*element: A21b.f21:[null|exact=JSUInt31]*/
+ var f21;
+
+ /*element: A21b.:[exact=A21b]*/
+ A21b() {
+ dynamic a = this;
+ /*iterator: [exact=A21b]*/
+ /*current: [null]*/
+ /*moveNext: [null]*/
+ for (
+ // ignore: unused_local_variable
+ var i in a) {}
+ /*update: [exact=A21b]*/ f21 = 42;
+ }
+
+ /*element: A21b.iterator:[null]*/
+ @override
+ get iterator => null;
+}
+
+/*element: test21b:[null]*/
+test21b() {
+ new A21b();
+}
+
class A22 {
/*element: A22.f22a:[exact=JSUInt31]*/
var f22a;
@@ -617,6 +672,7 @@
/*element: B24.:[exact=B24]*/
class B24 extends A24 {
/*element: B24.bar24:[exact=JSUInt31]*/
+ @override
bar24() => 42;
}
@@ -683,6 +739,7 @@
/*element: B27.:[exact=B27]*/
class B27 extends A27 {
+ @override
set f27b(/*[exact=JSUInt31]*/ value) {}
}
diff --git a/tests/compiler/dart2js/member_usage/data/general.dart b/tests/compiler/dart2js/member_usage/data/general.dart
index 465f141..9954b67 100644
--- a/tests/compiler/dart2js/member_usage/data/general.dart
+++ b/tests/compiler/dart2js/member_usage/data/general.dart
@@ -34,43 +34,75 @@
/*element: C.:invoke*/
class C extends A {
/*element: C.method1:invoke*/
+ @override
method1() {}
/*element: B.method2:invoke*/
+ @override
method2() {}
+
+ @override
method4() {}
/*element: C.getter:read*/
+ @override
get getter => 42;
+
+ @override
set setter(_) {}
}
/*element: D.:invoke*/
class D implements B {
+ @override
method1() {}
/*element: D.method2:invoke*/
+ @override
method2() {}
+
+ @override
method5() {}
+
+ @override
get getter => 42;
/*element: D.setter=:write*/
+ @override
set setter(_) {}
}
class E implements A {
+ @override
method1() {}
+
+ @override
method2() {}
+
+ @override
method4() {}
+
+ @override
get getter => 42;
+
+ @override
set setter(_) {}
}
class F extends B {
+ @override
method1() {}
+
+ @override
method2() {}
+
+ @override
method5() {}
+
+ @override
get getter => 42;
+
+ @override
set setter(_) {}
}
@@ -134,12 +166,15 @@
/*element: P.:invoke*/
class P implements O {
/*element: P.method1:invoke*/
+ @override
method1() {}
/*element: P.getter:read*/
+ @override
get getter => 42;
/*element: P.setter=:write*/
+ @override
set setter(_) {}
}
diff --git a/tests/compiler/dart2js/rti/data/generic_methods_dynamic_05.dart b/tests/compiler/dart2js/rti/data/generic_methods_dynamic_05.dart
index dcd1539..142ac30 100644
--- a/tests/compiler/dart2js/rti/data/generic_methods_dynamic_05.dart
+++ b/tests/compiler/dart2js/rti/data/generic_methods_dynamic_05.dart
@@ -5,7 +5,7 @@
// Test derived from language_2/generic_methods_dynamic_test/05
/*omit.class: global#JSArray:deps=[List],explicit=[JSArray],needsArgs*/
-/*strong.class: global#JSArray:deps=[ArrayIterator,List],direct,explicit=[JSArray,JSArray.E,JSArray<ArrayIterator.E>],implicit=[JSArray.E],needsArgs*/
+/*strong.class: global#JSArray:deps=[ArrayIterator,List],explicit=[JSArray,JSArray.E,JSArray<ArrayIterator.E>],implicit=[JSArray.E],indirect,needsArgs*/
/*omit.class: global#List:deps=[C.bar],explicit=[List,List<B>],needsArgs*/
/*strong.class: global#List:deps=[C.bar],explicit=[List,List<B>,List<String>],indirect,needsArgs*/
diff --git a/tests/compiler/dart2js/rti/data/local_function_list_literal.dart b/tests/compiler/dart2js/rti/data/local_function_list_literal.dart
index 7cbb508..aa06e82 100644
--- a/tests/compiler/dart2js/rti/data/local_function_list_literal.dart
+++ b/tests/compiler/dart2js/rti/data/local_function_list_literal.dart
@@ -4,7 +4,7 @@
import 'package:expect/expect.dart';
-/*strong.class: global#JSArray:deps=[ArrayIterator,List],direct,explicit=[JSArray,JSArray.E,JSArray<ArrayIterator.E>],implicit=[JSArray.E],needsArgs*/
+/*strong.class: global#JSArray:deps=[ArrayIterator,List],explicit=[JSArray,JSArray.E,JSArray<ArrayIterator.E>],implicit=[JSArray.E],indirect,needsArgs*/
/*omit.class: global#JSArray:deps=[List],explicit=[JSArray],needsArgs*/
/*strong.element: method:implicit=[method.T],indirect,needsArgs*/
diff --git a/tests/compiler/dart2js/static_type/data/for_in.dart b/tests/compiler/dart2js/static_type/data/for_in.dart
index 3168538..a97c74b 100644
--- a/tests/compiler/dart2js/static_type/data/for_in.dart
+++ b/tests/compiler/dart2js/static_type/data/for_in.dart
@@ -6,9 +6,17 @@
Iterable<Class> next;
}
+abstract class Class2<E> implements Iterable<E> {
+ @override
+ Iterator<E> iterator;
+}
+
main() {
forIn1(null);
forIn2(null);
+ forIn3(null);
+ forIn4(null);
+ forIn5(null);
}
forIn1(dynamic c) {
@@ -36,3 +44,30 @@
/*Class*/ c.next;
}
}
+
+forIn3(o) {
+ /*dynamic*/ o;
+ for (var e in /*dynamic*/ o) {
+ /*dynamic*/ e;
+ /*dynamic*/ o;
+ }
+ /*dynamic*/ o;
+}
+
+forIn4(o) {
+ /*dynamic*/ o;
+ for (int e in /*dynamic*/ o) {
+ /*int*/ e;
+ /*dynamic*/ o;
+ }
+ /*dynamic*/ o;
+}
+
+forIn5(Class2<int> o) {
+ /*Class2<int>*/ o;
+ for (var e in /*Class2<int>*/ o) {
+ /*int*/ e;
+ /*Class2<int>*/ o;
+ }
+ /*Class2<int>*/ o;
+}
diff --git a/tests/compiler/dart2js/static_type/static_type_test.dart b/tests/compiler/dart2js/static_type/static_type_test.dart
index 1f935d8..8999060 100644
--- a/tests/compiler/dart2js/static_type/static_type_test.dart
+++ b/tests/compiler/dart2js/static_type/static_type_test.dart
@@ -9,6 +9,7 @@
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/ir/cached_static_type.dart';
import 'package:compiler/src/ir/static_type_base.dart';
+import 'package:compiler/src/ir/static_type_cache.dart';
import 'package:compiler/src/kernel/element_map_impl.dart';
import 'package:compiler/src/kernel/kernel_strategy.dart';
import 'package:kernel/ast.dart' as ir;
@@ -49,8 +50,7 @@
{bool verbose: false}) {
KernelFrontEndStrategy frontendStrategy = compiler.frontendStrategy;
KernelToElementMapImpl elementMap = frontendStrategy.elementMap;
- Map<ir.TreeNode, ir.DartType> staticTypeCache =
- elementMap.getCachedStaticTypes(member);
+ StaticTypeCache staticTypeCache = elementMap.getCachedStaticTypes(member);
ir.Member node = elementMap.getMemberNode(member);
new StaticTypeIrComputer(
compiler.reporter,