[dart2js] Ensure RTI need/checks account for instantiations.
If a type variable T is used in an `is` or `as` expression (e.g.
`42 is T` or `42 as T`) or is part of a subtype check, then any types
which may be substituted for T via instantiation must also be treated as
participating in a type check.
This CL ensures that the RTI need computation includes type arguments
for those substituted types and that those types are included in the
list of implicit checks.
Additionally, in order for this to work, this CL fixes a bug in which
the impact transformer was failing to register generic instantiations
occurring in (partial) constants.
Fixes: https://github.com/dart-lang/sdk/issues/45046
Change-Id: I98ae0eca0adcbbb26cdd664318da0da578b289b5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/190460
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Mayank Patke <fishythefish@google.com>
diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart
index 4c261da..41e58eb 100644
--- a/pkg/compiler/lib/src/elements/types.dart
+++ b/pkg/compiler/lib/src/elements/types.dart
@@ -1381,7 +1381,7 @@
@override
bool visitNeverType(NeverType type, List<FunctionTypeVariable> bindings) =>
- false;
+ handleNeverType(type);
@override
bool visitVoidType(VoidType type, List<FunctionTypeVariable> bindings) =>
diff --git a/pkg/compiler/lib/src/js_backend/impact_transformer.dart b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
index 474f127..fee1573 100644
--- a/pkg/compiler/lib/src/js_backend/impact_transformer.dart
+++ b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
@@ -415,11 +415,17 @@
case ConstantValueKind.SET:
case ConstantValueKind.MAP:
case ConstantValueKind.CONSTRUCTED:
- case ConstantValueKind.INSTANTIATION:
case ConstantValueKind.LIST:
transformed.registerStaticUse(StaticUse.staticInvoke(
_closedWorld.commonElements.findType, CallStructure.ONE_ARG));
break;
+ case ConstantValueKind.INSTANTIATION:
+ transformed.registerStaticUse(StaticUse.staticInvoke(
+ _closedWorld.commonElements.findType, CallStructure.ONE_ARG));
+ InstantiationConstantValue instantiation = constantUse.value;
+ _rtiChecksBuilder.registerGenericInstantiation(GenericInstantiation(
+ instantiation.function.type, instantiation.typeArguments));
+ break;
case ConstantValueKind.DEFERRED_GLOBAL:
_closedWorld.outputUnitData
.registerConstantDeferredUse(constantUse.value);
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index c24e828..e7113df 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -533,7 +533,6 @@
TypeVariableTests typeVariableTests = new TypeVariableTests(
_elementEnvironment,
_commonElements,
- _types,
codegenWorld,
_genericInstantiations,
forRtiNeeds: false);
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart b/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
index 7afc77e..9348b79 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
@@ -197,11 +197,17 @@
}
class TypeVariableTests {
- Map<ClassEntity, ClassNode> _classes = {};
- Map<Entity, MethodNode> _methods = {};
- Map<MemberEntity, CallablePropertyNode> _callableProperties = {};
+ final ElementEnvironment _elementEnvironment;
+ final CommonElements _commonElements;
+ final BuiltWorld _world;
+ final Set<GenericInstantiation> _genericInstantiations;
+ final bool forRtiNeeds;
+
+ final Map<ClassEntity, ClassNode> _classes = {};
+ final Map<Entity, MethodNode> _methods = {};
+ final Map<MemberEntity, CallablePropertyNode> _callableProperties = {};
Map<Selector, Set<Entity>> _appliedSelectorMap;
- Map<GenericInstantiation, Set<Entity>> _instantiationMap;
+ final Map<Entity, Set<GenericInstantiation>> _instantiationMap = {};
/// All explicit is-tests.
final Set<DartType> explicitIsChecks;
@@ -209,25 +215,20 @@
/// All implicit is-tests.
final Set<DartType> implicitIsChecks = new Set<DartType>();
- TypeVariableTests(
- ElementEnvironment elementEnvironment,
- CommonElements commonElements,
- DartTypes types,
- BuiltWorld world,
- Set<GenericInstantiation> genericInstantiations,
- {bool forRtiNeeds: true})
- : explicitIsChecks = new Set<DartType>.from(world.isChecks) {
- _setupDependencies(
- elementEnvironment, commonElements, world, genericInstantiations,
- forRtiNeeds: forRtiNeeds);
- _propagateTests(commonElements, elementEnvironment, world);
+ TypeVariableTests(this._elementEnvironment, this._commonElements, this._world,
+ this._genericInstantiations,
+ {this.forRtiNeeds: true})
+ : explicitIsChecks = _world.isChecks.toSet() {
+ _setupDependencies();
+ _propagateTests();
if (forRtiNeeds) {
- _propagateLiterals(elementEnvironment, world);
+ _propagateLiterals();
}
- _collectResults(commonElements, elementEnvironment, types, world,
- forRtiNeeds: forRtiNeeds);
+ _collectResults();
}
+ DartTypes get _dartTypes => _commonElements.dartTypes;
+
/// Classes whose type variables are explicitly or implicitly used in
/// is-tests.
///
@@ -323,9 +324,9 @@
/// Calls [f] for each generic instantiation that applies to generic
/// closurized [targets].
- void forEachGenericInstantiation(
- void f(GenericInstantiation instantiation, Set<Entity> targets)) {
- _instantiationMap?.forEach(f);
+ void forEachInstantiatedEntity(
+ void f(Entity target, Set<GenericInstantiation> instantiations)) {
+ _instantiationMap.forEach(f);
}
ClassNode _getClassNode(ClassEntity cls) {
@@ -366,12 +367,7 @@
_callableProperties.putIfAbsent(
property, () => CallablePropertyNode(property, type));
- void _setupDependencies(
- ElementEnvironment elementEnvironment,
- CommonElements commonElements,
- BuiltWorld world,
- Set<GenericInstantiation> genericInstantiations,
- {bool forRtiNeeds: true}) {
+ void _setupDependencies() {
/// Register that if `node.entity` needs type arguments then so do entities
/// whose type variables occur in [type].
///
@@ -387,11 +383,33 @@
node.addDependency(_getClassNode(typeDeclaration));
} else {
node.addDependency(
- _getMethodNode(elementEnvironment, world, typeDeclaration));
+ _getMethodNode(_elementEnvironment, _world, typeDeclaration));
}
});
}
+ void registerDependenciesForInstantiation(RtiNode node, DartType type) {
+ void onInterface(InterfaceType type) {
+ if (type.typeArguments.isNotEmpty) {
+ node.addDependency(_getClassNode(type.element));
+ }
+ }
+
+ void onTypeVariable(TypeVariableType type) {
+ Entity declaration = type.element.typeDeclaration;
+ if (declaration is ClassEntity) {
+ node.addDependency(_getClassNode(declaration));
+ } else {
+ node.addDependency(
+ _getMethodNode(_elementEnvironment, _world, declaration));
+ }
+ }
+
+ _DependencyVisitor(
+ onInterface: onInterface, onTypeVariable: onTypeVariable)
+ .run(type);
+ }
+
// Add the rti dependencies that are implicit in the way the backend
// generates code: when we create a new [List], we actually create a
// [JSArray] in the backend and we need to add type arguments to the calls
@@ -412,17 +430,17 @@
//
// TODO(johnniwinther): Make this dependency visible from code, possibly
// using generic methods.
- if (commonElements.jsArrayClass != null) {
- _getClassNode(commonElements.jsArrayClass)
- .addDependency(_getClassNode(commonElements.listClass));
+ if (_commonElements.jsArrayClass != null) {
+ _getClassNode(_commonElements.jsArrayClass)
+ .addDependency(_getClassNode(_commonElements.listClass));
}
- if (commonElements.setLiteralClass != null) {
- _getClassNode(commonElements.setLiteralClass)
- .addDependency(_getClassNode(commonElements.setClass));
+ if (_commonElements.setLiteralClass != null) {
+ _getClassNode(_commonElements.setLiteralClass)
+ .addDependency(_getClassNode(_commonElements.setClass));
}
- if (commonElements.mapLiteralClass != null) {
- _getClassNode(commonElements.mapLiteralClass)
- .addDependency(_getClassNode(commonElements.mapClass));
+ if (_commonElements.mapLiteralClass != null) {
+ _getClassNode(_commonElements.mapLiteralClass)
+ .addDependency(_getClassNode(_commonElements.mapClass));
}
void processCheckedType(DartType type) {
@@ -439,36 +457,36 @@
// For the implied `is Future<X>` test, register that if `Future` needs
// type arguments then so do the entities that declare type variables
// occurring in `type.typeArgument`.
- registerDependencies(_getClassNode(commonElements.futureClass),
+ registerDependencies(_getClassNode(_commonElements.futureClass),
typeWithoutNullability.typeArgument);
// Process `type.typeArgument` for the implied `is X` test.
processCheckedType(typeWithoutNullability.typeArgument);
}
}
- world.isChecks.forEach(processCheckedType);
+ _world.isChecks.forEach(processCheckedType);
- world.instantiatedTypes.forEach((InterfaceType type) {
+ _world.instantiatedTypes.forEach((InterfaceType type) {
// Register that if [cls] needs type arguments then so do the entities
// that declare type variables occurring in [type].
ClassEntity cls = type.element;
registerDependencies(_getClassNode(cls), type);
});
- world.forEachStaticTypeArgument(
+ _world.forEachStaticTypeArgument(
(Entity entity, Iterable<DartType> typeArguments) {
for (DartType type in typeArguments) {
// Register that if [entity] needs type arguments then so do the
// entities that declare type variables occurring in [type].
registerDependencies(
- _getMethodNode(elementEnvironment, world, entity), type);
+ _getMethodNode(_elementEnvironment, _world, entity), type);
}
});
- world.forEachDynamicTypeArgument(
+ _world.forEachDynamicTypeArgument(
(Selector selector, Iterable<DartType> typeArguments) {
void processCallableNode(CallableNode node) {
- if (node.selectorApplies(selector, world)) {
+ if (node.selectorApplies(selector, _world)) {
for (DartType type in typeArguments) {
// Register that if `node.entity` needs type arguments then so do
// the entities that declare type variables occurring in [type].
@@ -478,7 +496,7 @@
}
void processMethod(Entity entity) {
- MethodNode node = _getMethodNode(elementEnvironment, world, entity);
+ MethodNode node = _getMethodNode(_elementEnvironment, _world, entity);
processCallableNode(node);
}
@@ -487,47 +505,38 @@
processCallableNode(node);
}
- world.forEachGenericInstanceMethod(processMethod);
- world.genericLocalFunctions.forEach(processMethod);
- world.closurizedStatics.forEach(processMethod);
- world.userNoSuchMethods.forEach(processMethod);
- world.genericCallableProperties.forEach(processCallableProperty);
+ _world.forEachGenericInstanceMethod(processMethod);
+ _world.genericLocalFunctions.forEach(processMethod);
+ _world.closurizedStatics.forEach(processMethod);
+ _world.userNoSuchMethods.forEach(processMethod);
+ _world.genericCallableProperties.forEach(processCallableProperty);
});
- for (GenericInstantiation instantiation in genericInstantiations) {
+ for (GenericInstantiation instantiation in _genericInstantiations) {
void processEntity(Entity entity) {
- MethodNode node = _getMethodNode(elementEnvironment, world, entity);
- if (node.parameterStructure.typeParameters ==
- instantiation.typeArguments.length) {
- if (forRtiNeeds) {
- _instantiationMap ??= <GenericInstantiation, Set<Entity>>{};
- _instantiationMap
- .putIfAbsent(instantiation, () => new Set<Entity>())
- .add(entity);
- }
+ MethodNode node = _getMethodNode(_elementEnvironment, _world, entity);
+ if (node.parameterStructure ==
+ ParameterStructure.fromType(instantiation.functionType)) {
+ _instantiationMap.putIfAbsent(entity, () => {}).add(instantiation);
for (DartType type in instantiation.typeArguments) {
- // Register that if `node.entity` needs type arguments then so do
- // the entities that declare type variables occurring in [type].
- registerDependencies(node, type);
+ registerDependenciesForInstantiation(node, type);
}
}
}
- world.closurizedMembers.forEach(processEntity);
- world.closurizedStatics.forEach(processEntity);
- world.genericLocalFunctions.forEach(processEntity);
+ _world.closurizedMembers.forEach(processEntity);
+ _world.closurizedStatics.forEach(processEntity);
+ _world.genericLocalFunctions.forEach(processEntity);
}
}
- void _propagateTests(CommonElements commonElements,
- ElementEnvironment elementEnvironment, BuiltWorld worldBuilder) {
+ void _propagateTests() {
void processTypeVariableType(TypeVariableType type, {bool direct: true}) {
TypeVariableEntity variable = type.element;
if (variable.typeDeclaration is ClassEntity) {
_getClassNode(variable.typeDeclaration).markTest(direct: direct);
} else {
- _getMethodNode(
- elementEnvironment, worldBuilder, variable.typeDeclaration)
+ _getMethodNode(_elementEnvironment, _world, variable.typeDeclaration)
.markTest(direct: direct);
}
}
@@ -535,7 +544,7 @@
void processType(DartType type, {bool direct: true}) {
var typeWithoutNullability = type.withoutNullability;
if (typeWithoutNullability is FutureOrType) {
- _getClassNode(commonElements.futureClass).markIndirectTest();
+ _getClassNode(_commonElements.futureClass).markIndirectTest();
processType(typeWithoutNullability.typeArgument, direct: false);
} else {
typeWithoutNullability.forEachTypeVariable((TypeVariableType type) {
@@ -544,17 +553,17 @@
}
}
- worldBuilder.isChecks.forEach(processType);
+ _world.isChecks.forEach(processType);
}
- void _propagateLiterals(
- ElementEnvironment elementEnvironment, BuiltWorld world) {
- world.typeVariableTypeLiterals.forEach((TypeVariableType typeVariableType) {
+ void _propagateLiterals() {
+ _world.typeVariableTypeLiterals
+ .forEach((TypeVariableType typeVariableType) {
TypeVariableEntity variable = typeVariableType.element;
if (variable.typeDeclaration is ClassEntity) {
_getClassNode(variable.typeDeclaration).markDirectLiteral();
} else {
- _getMethodNode(elementEnvironment, world, variable.typeDeclaration)
+ _getMethodNode(_elementEnvironment, _world, variable.typeDeclaration)
.markDirectLiteral();
}
});
@@ -608,34 +617,45 @@
return sb.toString();
}
- void _collectResults(CommonElements commonElements,
- ElementEnvironment elementEnvironment, DartTypes types, BuiltWorld world,
- {bool forRtiNeeds: true}) {
- /// Register the implicit is-test of [type].
- ///
- /// If [type] is of the form `FutureOr<X>`, also register the implicit
- /// is-tests of `Future<X>` and `X`.
- void addImplicitCheck(DartType type) {
- var typeWithoutNullability = type.withoutNullability;
- if (implicitIsChecks.add(typeWithoutNullability)) {
- if (typeWithoutNullability is FutureOrType) {
- addImplicitCheck(
- commonElements.futureType(typeWithoutNullability.typeArgument));
- addImplicitCheck(typeWithoutNullability.typeArgument);
- }
+ /// Register the implicit is-test of [type].
+ ///
+ /// If [type] is of the form `FutureOr<X>`, also register the implicit
+ /// is-tests of `Future<X>` and `X`.
+ void _addImplicitCheck(DartType type) {
+ var typeWithoutNullability = type.withoutNullability;
+ if (implicitIsChecks.add(typeWithoutNullability)) {
+ if (typeWithoutNullability is FutureOrType) {
+ _addImplicitCheck(
+ _commonElements.futureType(typeWithoutNullability.typeArgument));
+ _addImplicitCheck(typeWithoutNullability.typeArgument);
+ } else if (typeWithoutNullability is TypeVariableType) {
+ _addImplicitChecksViaInstantiation(typeWithoutNullability);
}
}
+ }
- void addImplicitChecks(Iterable<DartType> types) {
- types.forEach(addImplicitCheck);
- }
+ void _addImplicitChecks(Iterable<DartType> types) {
+ types.forEach(_addImplicitCheck);
+ }
- world.isChecks.forEach((DartType type) {
+ void _addImplicitChecksViaInstantiation(TypeVariableType variable) {
+ TypeVariableEntity entity = variable.element;
+ Entity declaration = entity.typeDeclaration;
+ _instantiationMap[declaration]
+ ?.forEach((GenericInstantiation instantiation) {
+ _addImplicitCheck(instantiation.typeArguments[entity.index]);
+ });
+ }
+
+ void _collectResults() {
+ _world.isChecks.forEach((DartType type) {
var typeWithoutNullability = type.withoutNullability;
if (typeWithoutNullability is FutureOrType) {
- addImplicitCheck(
- commonElements.futureType(typeWithoutNullability.typeArgument));
- addImplicitCheck(typeWithoutNullability.typeArgument);
+ _addImplicitCheck(
+ _commonElements.futureType(typeWithoutNullability.typeArgument));
+ _addImplicitCheck(typeWithoutNullability.typeArgument);
+ } else if (typeWithoutNullability is TypeVariableType) {
+ _addImplicitChecksViaInstantiation(typeWithoutNullability);
}
});
@@ -646,45 +666,45 @@
// Find all instantiated types that are a subtype of a class that uses
// one of its type arguments in an is-check and add the arguments to the
// set of is-checks.
- for (InterfaceType type in world.instantiatedTypes) {
+ for (InterfaceType type in _world.instantiatedTypes) {
// We need the type as instance of its superclass anyway, so we just
// try to compute the substitution; if the result is [:null:], the
// classes are not related.
- InterfaceType instance = types.asInstanceOf(type, cls);
+ InterfaceType instance = _dartTypes.asInstanceOf(type, cls);
if (instance != null) {
for (DartType argument in instance.typeArguments) {
- addImplicitCheck(argument);
+ _addImplicitCheck(argument);
}
}
}
});
- world.forEachStaticTypeArgument(
+ _world.forEachStaticTypeArgument(
(Entity function, Iterable<DartType> typeArguments) {
- if (!_getMethodNode(elementEnvironment, world, function).hasTest) {
+ if (!_getMethodNode(_elementEnvironment, _world, function).hasTest) {
return;
}
- addImplicitChecks(typeArguments);
+ _addImplicitChecks(typeArguments);
});
if (forRtiNeeds) {
_appliedSelectorMap = <Selector, Set<Entity>>{};
}
- world.forEachDynamicTypeArgument(
+ _world.forEachDynamicTypeArgument(
(Selector selector, Iterable<DartType> typeArguments) {
for (CallableNode node in [
..._methods.values,
..._callableProperties.values
]) {
- if (node.selectorApplies(selector, world)) {
+ if (node.selectorApplies(selector, _world)) {
if (forRtiNeeds) {
_appliedSelectorMap
.putIfAbsent(selector, () => {})
.add(node.entity);
}
if (node.hasTest) {
- addImplicitChecks(typeArguments);
+ _addImplicitChecks(typeArguments);
}
}
}
@@ -692,6 +712,25 @@
}
}
+class _DependencyVisitor extends DartTypeStructuralPredicateVisitor {
+ void Function(InterfaceType) onInterface;
+ void Function(TypeVariableType) onTypeVariable;
+
+ _DependencyVisitor({this.onInterface, this.onTypeVariable});
+
+ @override
+ bool handleInterfaceType(InterfaceType type) {
+ onInterface(type);
+ return false;
+ }
+
+ @override
+ bool handleTypeVariableType(TypeVariableType type) {
+ onTypeVariable(type);
+ return false;
+ }
+}
+
/// Interface for the classes and methods that need runtime types.
abstract class RuntimeTypesNeed {
/// Deserializes a [RuntimeTypesNeed] object from [source].
@@ -770,7 +809,7 @@
/// arguments.
// TODO(johnniwinther): Use [functionType].
bool instantiationNeedsTypeArguments(
- DartType functionType, int typeArgumentCount);
+ FunctionType functionType, int typeArgumentCount);
}
class TrivialRuntimeTypesNeed implements RuntimeTypesNeed {
@@ -804,7 +843,7 @@
@override
bool instantiationNeedsTypeArguments(
- DartType functionType, int typeArgumentCount) {
+ FunctionType functionType, int typeArgumentCount) {
return true;
}
}
@@ -903,7 +942,7 @@
@override
bool instantiationNeedsTypeArguments(
- DartType functionType, int typeArgumentCount) {
+ FunctionType functionType, int typeArgumentCount) {
return instantiationsNeedingTypeArguments.contains(typeArgumentCount);
}
}
@@ -963,8 +1002,11 @@
Map<Selector, Set<Entity>> selectorsNeedingTypeArgumentsForTesting;
- Map<GenericInstantiation, Set<Entity>>
- instantiationsNeedingTypeArgumentsForTesting;
+ Map<Entity, Set<GenericInstantiation>>
+ _instantiatedEntitiesNeedingTypeArgumentsForTesting;
+ Map<Entity, Set<GenericInstantiation>>
+ get instantiatedEntitiesNeedingTypeArgumentsForTesting =>
+ _instantiatedEntitiesNeedingTypeArgumentsForTesting ?? const {};
final Set<GenericInstantiation> _genericInstantiations =
new Set<GenericInstantiation>();
@@ -999,7 +1041,6 @@
TypeVariableTests typeVariableTests = new TypeVariableTests(
closedWorld.elementEnvironment,
closedWorld.commonElements,
- closedWorld.dartTypes,
closedWorld,
_genericInstantiations);
Set<ClassEntity> classesNeedingTypeArguments = new Set<ClassEntity>();
@@ -1348,24 +1389,19 @@
}
});
Set<int> instantiationsNeedingTypeArguments = new Set<int>();
- typeVariableTests.forEachGenericInstantiation(
- (GenericInstantiation instantiation, Set<Entity> targets) {
- for (Entity target in targets) {
- if (methodsNeedingTypeArguments.contains(target) ||
- localFunctionsNeedingTypeArguments.contains(target)) {
- // TODO(johnniwinther): Use the static type of the instantiated
- // expression.
- instantiationsNeedingTypeArguments
- .add(instantiation.typeArguments.length);
- if (retainDataForTesting) {
- instantiationsNeedingTypeArgumentsForTesting ??=
- <GenericInstantiation, Set<Entity>>{};
- instantiationsNeedingTypeArgumentsForTesting
- .putIfAbsent(instantiation, () => new Set<Entity>())
- .add(target);
- } else {
- return;
- }
+ typeVariableTests.forEachInstantiatedEntity(
+ (Entity target, Set<GenericInstantiation> instantiations) {
+ if (methodsNeedingTypeArguments.contains(target) ||
+ localFunctionsNeedingTypeArguments.contains(target)) {
+ // TODO(johnniwinther): Use the static type of the instantiated
+ // expression.
+ instantiationsNeedingTypeArguments
+ .add(instantiations.first.typeArguments.length);
+ if (retainDataForTesting) {
+ _instantiatedEntitiesNeedingTypeArgumentsForTesting ??= {};
+ _instantiatedEntitiesNeedingTypeArgumentsForTesting
+ .putIfAbsent(target, () => {})
+ .addAll(instantiations);
}
}
});
diff --git a/pkg/compiler/lib/src/js_model/closure.dart b/pkg/compiler/lib/src/js_model/closure.dart
index 41f9170..216f25e 100644
--- a/pkg/compiler/lib/src/js_model/closure.dart
+++ b/pkg/compiler/lib/src/js_model/closure.dart
@@ -1411,5 +1411,5 @@
bool selectorNeedsTypeArguments(Selector selector);
bool instantiationNeedsTypeArguments(
- DartType functionType, int typeArgumentCount);
+ FunctionType functionType, int typeArgumentCount);
}
diff --git a/pkg/compiler/lib/src/js_model/js_world_builder.dart b/pkg/compiler/lib/src/js_model/js_world_builder.dart
index f2fdbe6..c07ccea 100644
--- a/pkg/compiler/lib/src/js_model/js_world_builder.dart
+++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart
@@ -528,7 +528,7 @@
@override
bool instantiationNeedsTypeArguments(
- DartType functionType, int typeArgumentCount) =>
+ FunctionType functionType, int typeArgumentCount) =>
true;
}
@@ -568,7 +568,7 @@
@override
bool instantiationNeedsTypeArguments(
- DartType functionType, int typeArgumentCount) =>
+ FunctionType functionType, int typeArgumentCount) =>
rtiNeed.instantiationNeedsTypeArguments(functionType, typeArgumentCount);
}
diff --git a/pkg/compiler/lib/src/kernel/kernel_impact.dart b/pkg/compiler/lib/src/kernel/kernel_impact.dart
index f3df3a2..9a40f68 100644
--- a/pkg/compiler/lib/src/kernel/kernel_impact.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_impact.dart
@@ -700,7 +700,7 @@
ir.FunctionType expressionType, List<ir.DartType> typeArguments) {
// TODO(johnniwinther): Track which arities are used in instantiation.
impactBuilder.registerInstantiation(new GenericInstantiation(
- elementMap.getDartType(expressionType),
+ elementMap.getDartType(expressionType).withoutNullability,
typeArguments.map(elementMap.getDartType).toList()));
}
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 083df95..2831f5c 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -5193,15 +5193,16 @@
node.expression.accept(this);
arguments.add(pop());
StaticType expressionType = _getStaticType(node.expression);
+ FunctionType functionType = expressionType.type.withoutNullability;
bool typeArgumentsNeeded = _rtiNeed.instantiationNeedsTypeArguments(
- expressionType.type, node.typeArguments.length);
+ functionType, node.typeArguments.length);
List<DartType> typeArguments = node.typeArguments
.map((type) => typeArgumentsNeeded
? _elementMap.getDartType(type)
: _commonElements.dynamicType)
.toList();
registry.registerGenericInstantiation(
- new GenericInstantiation(expressionType.type, typeArguments));
+ new GenericInstantiation(functionType, typeArguments));
// TODO(johnniwinther): Can we avoid creating the instantiation object?
for (DartType type in typeArguments) {
HInstruction instruction =
diff --git a/pkg/compiler/lib/src/universe/feature.dart b/pkg/compiler/lib/src/universe/feature.dart
index 7ea60b7..f907c36 100644
--- a/pkg/compiler/lib/src/universe/feature.dart
+++ b/pkg/compiler/lib/src/universe/feature.dart
@@ -237,7 +237,7 @@
static const String tag = 'generic-instantiation';
/// The static type of the instantiated expression.
- final DartType functionType;
+ final FunctionType functionType;
/// The type arguments of the instantiation.
final List<DartType> typeArguments;
diff --git a/pkg/compiler/test/rti/data/instantiation1.dart b/pkg/compiler/test/rti/data/instantiation1.dart
index 8fbd5f3..c838bbe 100644
--- a/pkg/compiler/test/rti/data/instantiation1.dart
+++ b/pkg/compiler/test/rti/data/instantiation1.dart
@@ -10,7 +10,7 @@
typedef int F<R>(R a);
-/*spec.class: B:explicit=[int* Function(B.S*)*],indirect,needsArgs*/
+/*spec.class: B:explicit=[int* Function(B.S*)*],implicit=[B.S],indirect,needsArgs*/
class B<S> {
F<S> c;
diff --git a/pkg/compiler/test/rti/data/instantiation2.dart b/pkg/compiler/test/rti/data/instantiation2.dart
index dbb5db8..934152a 100644
--- a/pkg/compiler/test/rti/data/instantiation2.dart
+++ b/pkg/compiler/test/rti/data/instantiation2.dart
@@ -9,8 +9,8 @@
typedef bool F<R>(R a);
-/*spec.class: B:explicit=[bool* Function(B.S*)*],indirect,needsArgs*/
-/*prod.class: B:indirect,needsArgs*/
+/*spec.class: B:explicit=[bool* Function(B.S*)*],implicit=[B.S],indirect,needsArgs*/
+/*prod.class: B:implicit=[B.S],indirect,needsArgs*/
class B<S> {
F<S> c;
diff --git a/pkg/compiler/test/rti/data/instantiation3.dart b/pkg/compiler/test/rti/data/instantiation3.dart
index 96e7c7a..f852f9f 100644
--- a/pkg/compiler/test/rti/data/instantiation3.dart
+++ b/pkg/compiler/test/rti/data/instantiation3.dart
@@ -10,7 +10,7 @@
typedef int F<R>(R a);
-/*spec.class: B:direct,explicit=[int* Function(B.S*)*],needsArgs*/
+/*spec.class: B:direct,explicit=[int* Function(B.S*)*],implicit=[B.S],needsArgs*/
class B<S> {
F<S> c;
diff --git a/pkg/compiler/test/rti/data/instantiation4.dart b/pkg/compiler/test/rti/data/instantiation4.dart
index 7ec0433..be3b975 100644
--- a/pkg/compiler/test/rti/data/instantiation4.dart
+++ b/pkg/compiler/test/rti/data/instantiation4.dart
@@ -9,8 +9,8 @@
typedef bool F<R>(R a);
-/*spec.class: B:direct,explicit=[bool* Function(B.S*)*],needsArgs*/
-/*prod.class: B:indirect,needsArgs*/
+/*spec.class: B:direct,explicit=[bool* Function(B.S*)*],implicit=[B.S],needsArgs*/
+/*prod.class: B:implicit=[B.S],indirect,needsArgs*/
class B<S> {
F<S> c;
diff --git a/pkg/compiler/test/rti/data/instantiation5.dart b/pkg/compiler/test/rti/data/instantiation5.dart
index 80063c5..525be33 100644
--- a/pkg/compiler/test/rti/data/instantiation5.dart
+++ b/pkg/compiler/test/rti/data/instantiation5.dart
@@ -10,7 +10,7 @@
typedef int F<R>(R a);
-/*spec.member: method:indirect,needsArgs*/
+/*spec.member: method:implicit=[method.S],indirect,needsArgs*/
method<S>() {
F<S> c;
diff --git a/pkg/compiler/test/rti/data/instantiation6.dart b/pkg/compiler/test/rti/data/instantiation6.dart
index fdfa1d2..e596af2 100644
--- a/pkg/compiler/test/rti/data/instantiation6.dart
+++ b/pkg/compiler/test/rti/data/instantiation6.dart
@@ -9,7 +9,7 @@
typedef bool F<R>(R a);
-/*member: method:indirect,needsArgs*/
+/*member: method:implicit=[method.S],indirect,needsArgs*/
method<S>() {
F<S> c;
diff --git a/pkg/compiler/test/rti/data/instantiation7.dart b/pkg/compiler/test/rti/data/instantiation7.dart
index fda2e4a..a47924b 100644
--- a/pkg/compiler/test/rti/data/instantiation7.dart
+++ b/pkg/compiler/test/rti/data/instantiation7.dart
@@ -20,7 +20,7 @@
typedef int F2<R, P>(R a, P b, P c);
typedef int F3<R, P, Q>(R a, P b, Q c);
-/*spec.member: method:indirect,needsArgs*/
+/*spec.member: method:implicit=[method.X,method.Y,method.Z],indirect,needsArgs*/
method<X, Y, Z>() {
F1<X> c1;
F2<X, Y> c2;
diff --git a/pkg/compiler/test/rti/data/local_function_signatures_generic.dart b/pkg/compiler/test/rti/data/local_function_signatures_generic.dart
index dc86b33..7956fe4 100644
--- a/pkg/compiler/test/rti/data/local_function_signatures_generic.dart
+++ b/pkg/compiler/test/rti/data/local_function_signatures_generic.dart
@@ -89,8 +89,8 @@
}
method12() {
- /*spec.direct,explicit=[local.T*],needsArgs,needsInst=[<dynamic>,<num*>,<num*>],needsSignature*/
- /*prod.needsArgs,needsInst=[<dynamic>,<num*>,<num*>],needsSignature*/num local<T>(num n, T t) => null;
+ /*spec.direct,explicit=[local.T*],needsArgs,needsSignature*/
+ /*prod.needsArgs,needsSignature*/num local<T>(num n, T t) => null;
return local;
}
diff --git a/pkg/compiler/test/rti/data/method_signatures_generic.dart b/pkg/compiler/test/rti/data/method_signatures_generic.dart
index b3866f8..0d2c352 100644
--- a/pkg/compiler/test/rti/data/method_signatures_generic.dart
+++ b/pkg/compiler/test/rti/data/method_signatures_generic.dart
@@ -28,7 +28,7 @@
}
class Class4 {
- /*spec.member: Class4.method6:direct,explicit=[method6.T*],needsArgs,needsInst=[<num*>,<num*>,<num*>,<num*>]*/
+ /*spec.member: Class4.method6:direct,explicit=[method6.T*],needsArgs*/
num method6<T>(num n, T t) => null;
}
@@ -38,7 +38,7 @@
/*member: method8:*/
T method8<T>(num n) => null;
-/*spec.member: method9:direct,explicit=[method9.T*],needsArgs,needsInst=[<num*>,<num*>,<num*>,<num*>]*/
+/*spec.member: method9:direct,explicit=[method9.T*],needsArgs*/
num method9<T>(num n, T t) => null;
@pragma('dart2js:noInline')
diff --git a/pkg/compiler/test/rti/rti_need_test_helper.dart b/pkg/compiler/test/rti/rti_need_test_helper.dart
index 4170976..4206006 100644
--- a/pkg/compiler/test/rti/rti_need_test_helper.dart
+++ b/pkg/compiler/test/rti/rti_need_test_helper.dart
@@ -160,12 +160,11 @@
features.addElement(Tags.selectors, selector);
}
});
- rtiNeedBuilder.instantiationsNeedingTypeArgumentsForTesting?.forEach(
- (GenericInstantiation instantiation, Set<Entity> targets) {
- if (targets.contains(entity)) {
- features.addElement(
- Tags.instantiationsNeedTypeArguments, instantiation.shortText);
- }
+ rtiNeedBuilder
+ .instantiatedEntitiesNeedingTypeArgumentsForTesting[entity]
+ ?.forEach((GenericInstantiation instantiation) {
+ features.addElement(
+ Tags.instantiationsNeedTypeArguments, instantiation.shortText);
});
}