Track RTI dependency through instantiations
Closes #33093 Change-Id: Ia7d9cd1235cd4fe60858f37533689f5eeb600540 Reviewed-on: https://dart-review.googlesource.com/59400 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Stephen Adams <sra@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
1fb845c2f4
commit
52d7a3043a
@@ -7,6 +7,7 @@ library dart2js.common.codegen;
|
||||
import '../common_elements.dart';
|
||||
import '../elements/entities.dart';
|
||||
import '../elements/types.dart' show DartType, InterfaceType;
|
||||
import '../universe/feature.dart';
|
||||
import '../universe/use.dart' show ConstantUse, DynamicUse, StaticUse, TypeUse;
|
||||
import '../universe/world_impact.dart'
|
||||
show WorldImpact, WorldImpactBuilderImpl, WorldImpactVisitor;
|
||||
@@ -29,7 +30,10 @@ class CodegenImpact extends WorldImpact {
|
||||
|
||||
bool get usesInterceptor => false;
|
||||
|
||||
Iterable<AsyncMarker> get asyncMarkers => <AsyncMarker>[];
|
||||
Iterable<AsyncMarker> get asyncMarkers => const <AsyncMarker>[];
|
||||
|
||||
Iterable<GenericInstantiation> get genericInstantiations =>
|
||||
const <GenericInstantiation>[];
|
||||
}
|
||||
|
||||
class _CodegenImpact extends WorldImpactBuilderImpl implements CodegenImpact {
|
||||
@@ -38,6 +42,7 @@ class _CodegenImpact extends WorldImpactBuilderImpl implements CodegenImpact {
|
||||
List<Set<ClassEntity>> _specializedGetInterceptors;
|
||||
bool _usesInterceptor = false;
|
||||
EnumSet<AsyncMarker> _asyncMarkers;
|
||||
Set<GenericInstantiation> _genericInstantiations;
|
||||
|
||||
_CodegenImpact();
|
||||
|
||||
@@ -49,9 +54,7 @@ class _CodegenImpact extends WorldImpactBuilderImpl implements CodegenImpact {
|
||||
|
||||
void registerTypeVariableBoundsSubtypeCheck(
|
||||
DartType subtype, DartType supertype) {
|
||||
if (_typeVariableBoundsSubtypeChecks == null) {
|
||||
_typeVariableBoundsSubtypeChecks = new Setlet<Pair<DartType, DartType>>();
|
||||
}
|
||||
_typeVariableBoundsSubtypeChecks ??= new Setlet<Pair<DartType, DartType>>();
|
||||
_typeVariableBoundsSubtypeChecks
|
||||
.add(new Pair<DartType, DartType>(subtype, supertype));
|
||||
}
|
||||
@@ -63,9 +66,7 @@ class _CodegenImpact extends WorldImpactBuilderImpl implements CodegenImpact {
|
||||
}
|
||||
|
||||
void registerConstSymbol(String name) {
|
||||
if (_constSymbols == null) {
|
||||
_constSymbols = new Setlet<String>();
|
||||
}
|
||||
_constSymbols ??= new Setlet<String>();
|
||||
_constSymbols.add(name);
|
||||
}
|
||||
|
||||
@@ -74,9 +75,7 @@ class _CodegenImpact extends WorldImpactBuilderImpl implements CodegenImpact {
|
||||
}
|
||||
|
||||
void registerSpecializedGetInterceptor(Set<ClassEntity> classes) {
|
||||
if (_specializedGetInterceptors == null) {
|
||||
_specializedGetInterceptors = <Set<ClassEntity>>[];
|
||||
}
|
||||
_specializedGetInterceptors ??= <Set<ClassEntity>>[];
|
||||
_specializedGetInterceptors.add(classes);
|
||||
}
|
||||
|
||||
@@ -93,9 +92,7 @@ class _CodegenImpact extends WorldImpactBuilderImpl implements CodegenImpact {
|
||||
bool get usesInterceptor => _usesInterceptor;
|
||||
|
||||
void registerAsyncMarker(AsyncMarker asyncMarker) {
|
||||
if (_asyncMarkers == null) {
|
||||
_asyncMarkers = new EnumSet<AsyncMarker>();
|
||||
}
|
||||
_asyncMarkers ??= new EnumSet<AsyncMarker>();
|
||||
_asyncMarkers.add(asyncMarker);
|
||||
}
|
||||
|
||||
@@ -104,6 +101,16 @@ class _CodegenImpact extends WorldImpactBuilderImpl implements CodegenImpact {
|
||||
? _asyncMarkers.iterable(AsyncMarker.values)
|
||||
: const <AsyncMarker>[];
|
||||
}
|
||||
|
||||
void registerGenericInstantiation(GenericInstantiation instantiation) {
|
||||
_genericInstantiations ??= new Set<GenericInstantiation>();
|
||||
_genericInstantiations.add(instantiation);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<GenericInstantiation> get genericInstantiations {
|
||||
return _genericInstantiations ?? const <GenericInstantiation>[];
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(johnniwinther): Split this class into interface and implementation.
|
||||
@@ -169,6 +176,10 @@ class CodegenRegistry {
|
||||
void registerAsyncMarker(AsyncMarker asyncMarker) {
|
||||
worldImpact.registerAsyncMarker(asyncMarker);
|
||||
}
|
||||
|
||||
void registerGenericInstantiation(GenericInstantiation instantiation) {
|
||||
worldImpact.registerGenericInstantiation(instantiation);
|
||||
}
|
||||
}
|
||||
|
||||
/// [WorkItem] used exclusively by the [CodegenEnqueuer].
|
||||
|
||||
@@ -21,4 +21,7 @@ class ResolutionImpact extends WorldImpact {
|
||||
Iterable<ClassEntity> get seenClasses => const <ClassEntity>[];
|
||||
|
||||
Iterable<dynamic> get nativeData => const <dynamic>[];
|
||||
|
||||
Iterable<GenericInstantiation> get genericInstantiations =>
|
||||
const <GenericInstantiation>[];
|
||||
}
|
||||
|
||||
@@ -43,9 +43,6 @@ abstract class BackendUsage {
|
||||
|
||||
/// `true` if `noSuchMethod` is used.
|
||||
bool get isNoSuchMethodUsed;
|
||||
|
||||
/// `true` if generic instantiation is used.
|
||||
bool get isGenericInstantiationUsed;
|
||||
}
|
||||
|
||||
abstract class BackendUsageBuilder {
|
||||
@@ -83,9 +80,6 @@ abstract class BackendUsageBuilder {
|
||||
/// `true` if `noSuchMethod` is used.
|
||||
bool isNoSuchMethodUsed;
|
||||
|
||||
/// `true` if generic instantiation is used.
|
||||
bool isGenericInstantiationUsed;
|
||||
|
||||
BackendUsage close();
|
||||
}
|
||||
|
||||
@@ -122,9 +116,6 @@ class BackendUsageBuilderImpl implements BackendUsageBuilder {
|
||||
/// `true` if `noSuchMethod` is used.
|
||||
bool isNoSuchMethodUsed = false;
|
||||
|
||||
/// `true` if generic instantiation is used.
|
||||
bool isGenericInstantiationUsed = false;
|
||||
|
||||
BackendUsageBuilderImpl(this._commonElements);
|
||||
|
||||
@override
|
||||
@@ -280,8 +271,7 @@ class BackendUsageBuilderImpl implements BackendUsageBuilder {
|
||||
isRuntimeTypeUsed: isRuntimeTypeUsed,
|
||||
isFunctionApplyUsed: isFunctionApplyUsed,
|
||||
isMirrorsUsed: isMirrorsUsed,
|
||||
isNoSuchMethodUsed: isNoSuchMethodUsed,
|
||||
isGenericInstantiationUsed: isGenericInstantiationUsed);
|
||||
isNoSuchMethodUsed: isNoSuchMethodUsed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,9 +307,6 @@ class BackendUsageImpl implements BackendUsage {
|
||||
/// `true` if `noSuchMethod` is used.
|
||||
final bool isNoSuchMethodUsed;
|
||||
|
||||
/// `true` if generic instantiation is used.
|
||||
final bool isGenericInstantiationUsed;
|
||||
|
||||
BackendUsageImpl(
|
||||
{Set<FunctionEntity> globalFunctionDependencies,
|
||||
Set<ClassEntity> globalClassDependencies,
|
||||
@@ -332,8 +319,7 @@ class BackendUsageImpl implements BackendUsage {
|
||||
this.isRuntimeTypeUsed,
|
||||
this.isFunctionApplyUsed,
|
||||
this.isMirrorsUsed,
|
||||
this.isNoSuchMethodUsed,
|
||||
this.isGenericInstantiationUsed})
|
||||
this.isNoSuchMethodUsed})
|
||||
: this._globalFunctionDependencies = globalFunctionDependencies,
|
||||
this._globalClassDependencies = globalClassDependencies,
|
||||
this._helperFunctionsUsed = helperFunctionsUsed,
|
||||
|
||||
@@ -104,10 +104,6 @@ class JavaScriptImpactTransformer extends ImpactTransformer {
|
||||
new TypeUse.instantiation(_commonElements.nullType));
|
||||
registerImpact(_impacts.nullLiteral);
|
||||
break;
|
||||
case Feature.GENERIC_INSTANTIATION:
|
||||
registerImpact(_impacts.genericInstantiation);
|
||||
_backendUsageBuilder.isGenericInstantiationUsed = true;
|
||||
break;
|
||||
case Feature.LAZY_FIELD:
|
||||
registerImpact(_impacts.lazyField);
|
||||
break;
|
||||
@@ -292,6 +288,14 @@ class JavaScriptImpactTransformer extends ImpactTransformer {
|
||||
_classHierarchyBuilder.registerClass(classEntity);
|
||||
}
|
||||
|
||||
if (worldImpact.genericInstantiations.isNotEmpty) {
|
||||
registerImpact(_impacts.genericInstantiation);
|
||||
for (GenericInstantiation instantiation
|
||||
in worldImpact.genericInstantiations) {
|
||||
_rtiNeedBuilder.registerGenericInstantiation(instantiation);
|
||||
}
|
||||
}
|
||||
|
||||
return transformed;
|
||||
}
|
||||
|
||||
@@ -460,6 +464,10 @@ class CodegenImpactTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
for (GenericInstantiation instantiation in impact.genericInstantiations) {
|
||||
_rtiChecksBuilder.registerGenericInstantiation(instantiation);
|
||||
}
|
||||
|
||||
// TODO(johnniwinther): Remove eager registration.
|
||||
return transformed;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import '../js/js.dart' as jsAst;
|
||||
import '../js/js.dart' show js;
|
||||
import '../js_emitter/js_emitter.dart' show Emitter;
|
||||
import '../options.dart';
|
||||
import '../universe/feature.dart';
|
||||
import '../universe/selector.dart';
|
||||
import '../universe/world_builder.dart';
|
||||
import '../world.dart' show JClosedWorld, KClosedWorld;
|
||||
@@ -95,6 +96,13 @@ abstract class RuntimeTypesNeed {
|
||||
/// Returns `true` if a dynamic call of [selector] needs to pass type
|
||||
/// arguments.
|
||||
bool selectorNeedsTypeArguments(Selector selector);
|
||||
|
||||
/// Returns `true` if a generic instantiation on an expression of type
|
||||
/// [functionType] with the given [typeArgumentCount] needs to pass type
|
||||
/// arguments.
|
||||
// TODO(johnniwinther): Use [functionType].
|
||||
bool instantiationNeedsTypeArguments(
|
||||
DartType functionType, int typeArgumentCount);
|
||||
}
|
||||
|
||||
class TrivialRuntimeTypesNeed implements RuntimeTypesNeed {
|
||||
@@ -117,6 +125,12 @@ class TrivialRuntimeTypesNeed implements RuntimeTypesNeed {
|
||||
|
||||
@override
|
||||
bool selectorNeedsTypeArguments(Selector selector) => true;
|
||||
|
||||
@override
|
||||
bool instantiationNeedsTypeArguments(
|
||||
DartType functionType, int typeArgumentCount) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface for computing classes and methods that need runtime types.
|
||||
@@ -131,6 +145,9 @@ abstract class RuntimeTypesNeedBuilder {
|
||||
/// literal.
|
||||
void registerLocalFunctionUsingTypeVariableLiteral(Local localFunction);
|
||||
|
||||
/// Registers that a generic [instantiation] is used.
|
||||
void registerGenericInstantiation(GenericInstantiation instantiation);
|
||||
|
||||
/// Computes the [RuntimeTypesNeed] for the data registered with this builder.
|
||||
RuntimeTypesNeed computeRuntimeTypesNeed(
|
||||
ResolutionWorldBuilder resolutionWorldBuilder,
|
||||
@@ -150,6 +167,9 @@ class TrivialRuntimeTypesNeedBuilder implements RuntimeTypesNeedBuilder {
|
||||
@override
|
||||
void registerLocalFunctionUsingTypeVariableLiteral(Local localFunction) {}
|
||||
|
||||
@override
|
||||
void registerGenericInstantiation(GenericInstantiation instantiation) {}
|
||||
|
||||
@override
|
||||
RuntimeTypesNeed computeRuntimeTypesNeed(
|
||||
ResolutionWorldBuilder resolutionWorldBuilder,
|
||||
@@ -194,6 +214,9 @@ abstract class RuntimeTypesChecksBuilder {
|
||||
void registerTypeVariableBoundsSubtypeCheck(
|
||||
DartType typeArgument, DartType bound);
|
||||
|
||||
/// Registers that a generic [instantiation] is used.
|
||||
void registerGenericInstantiation(GenericInstantiation instantiation);
|
||||
|
||||
/// Computes the [RuntimeTypesChecks] for the data in this builder.
|
||||
RuntimeTypesChecks computeRequiredChecks(
|
||||
CodegenWorldBuilder codegenWorldBuilder, CompilerOptions options);
|
||||
@@ -214,6 +237,9 @@ class TrivialRuntimeTypesChecksBuilder implements RuntimeTypesChecksBuilder {
|
||||
void registerTypeVariableBoundsSubtypeCheck(
|
||||
DartType typeArgument, DartType bound) {}
|
||||
|
||||
@override
|
||||
void registerGenericInstantiation(GenericInstantiation instantiation) {}
|
||||
|
||||
@override
|
||||
RuntimeTypesChecks computeRequiredChecks(
|
||||
CodegenWorldBuilder codegenWorldBuilder, CompilerOptions options) {
|
||||
@@ -700,6 +726,7 @@ class RuntimeTypesNeedImpl implements RuntimeTypesNeed {
|
||||
final Set<Local> localFunctionsNeedingSignature;
|
||||
final Set<Local> localFunctionsNeedingTypeArguments;
|
||||
final Set<Selector> selectorsNeedingTypeArguments;
|
||||
final Set<int> instantiationsNeedingTypeArguments;
|
||||
|
||||
RuntimeTypesNeedImpl(
|
||||
this._elementEnvironment,
|
||||
@@ -709,7 +736,8 @@ class RuntimeTypesNeedImpl implements RuntimeTypesNeed {
|
||||
this.methodsNeedingTypeArguments,
|
||||
this.localFunctionsNeedingSignature,
|
||||
this.localFunctionsNeedingTypeArguments,
|
||||
this.selectorsNeedingTypeArguments);
|
||||
this.selectorsNeedingTypeArguments,
|
||||
this.instantiationsNeedingTypeArguments);
|
||||
|
||||
bool checkClass(covariant ClassEntity cls) => true;
|
||||
|
||||
@@ -749,6 +777,12 @@ class RuntimeTypesNeedImpl implements RuntimeTypesNeed {
|
||||
if (_backendUsage.isRuntimeTypeUsed) return true;
|
||||
return selectorsNeedingTypeArguments.contains(selector);
|
||||
}
|
||||
|
||||
@override
|
||||
bool instantiationNeedsTypeArguments(
|
||||
DartType functionType, int typeArgumentCount) {
|
||||
return instantiationsNeedingTypeArguments.contains(typeArgumentCount);
|
||||
}
|
||||
}
|
||||
|
||||
class TypeVariableTests {
|
||||
@@ -756,6 +790,7 @@ class TypeVariableTests {
|
||||
Map<ClassEntity, ClassNode> _classes = <ClassEntity, ClassNode>{};
|
||||
Map<Entity, MethodNode> _methods = <Entity, MethodNode>{};
|
||||
Map<Selector, Set<Entity>> _appliedSelectorMap;
|
||||
Map<GenericInstantiation, Set<Entity>> _instantiationMap;
|
||||
|
||||
/// All explicit is-tests.
|
||||
final Set<DartType> explicitIsChecks;
|
||||
@@ -763,11 +798,17 @@ class TypeVariableTests {
|
||||
/// All implicit is-tests.
|
||||
final Set<DartType> implicitIsChecks = new Set<DartType>();
|
||||
|
||||
TypeVariableTests(ElementEnvironment elementEnvironment,
|
||||
CommonElements commonElements, DartTypes types, WorldBuilder worldBuilder,
|
||||
TypeVariableTests(
|
||||
ElementEnvironment elementEnvironment,
|
||||
CommonElements commonElements,
|
||||
DartTypes types,
|
||||
WorldBuilder worldBuilder,
|
||||
Set<GenericInstantiation> genericInstantiations,
|
||||
{bool forRtiNeeds: true})
|
||||
: explicitIsChecks = new Set<DartType>.from(worldBuilder.isChecks) {
|
||||
_setupDependencies(elementEnvironment, commonElements, worldBuilder);
|
||||
_setupDependencies(
|
||||
elementEnvironment, commonElements, worldBuilder, genericInstantiations,
|
||||
forRtiNeeds: forRtiNeeds);
|
||||
_propagateTests(commonElements, elementEnvironment, worldBuilder);
|
||||
if (forRtiNeeds) {
|
||||
_propagateLiterals(elementEnvironment, worldBuilder);
|
||||
@@ -867,6 +908,13 @@ class TypeVariableTests {
|
||||
_appliedSelectorMap.forEach(f);
|
||||
}
|
||||
|
||||
/// Calls [f] for each generic instantiation that applies to generic
|
||||
/// closurized [targets].
|
||||
void forEachGenericInstantiation(
|
||||
void f(GenericInstantiation instantiation, Set<Entity> targets)) {
|
||||
_instantiationMap?.forEach(f);
|
||||
}
|
||||
|
||||
ClassNode _getClassNode(ClassEntity cls) {
|
||||
return _classes.putIfAbsent(cls, () {
|
||||
ClassNode node = new ClassNode(cls);
|
||||
@@ -905,8 +953,12 @@ class TypeVariableTests {
|
||||
});
|
||||
}
|
||||
|
||||
void _setupDependencies(ElementEnvironment elementEnvironment,
|
||||
CommonElements commonElements, WorldBuilder worldBuilder) {
|
||||
void _setupDependencies(
|
||||
ElementEnvironment elementEnvironment,
|
||||
CommonElements commonElements,
|
||||
WorldBuilder worldBuilder,
|
||||
Set<GenericInstantiation> genericInstantiations,
|
||||
{bool forRtiNeeds: true}) {
|
||||
/// Register that if `node.entity` needs type arguments then so do entities
|
||||
/// whose type variables occur in [type].
|
||||
///
|
||||
@@ -1018,6 +1070,31 @@ class TypeVariableTests {
|
||||
worldBuilder.closurizedStatics.forEach(processEntity);
|
||||
worldBuilder.userNoSuchMethods.forEach(processEntity);
|
||||
});
|
||||
|
||||
for (GenericInstantiation instantiation in genericInstantiations) {
|
||||
void processEntity(Entity entity) {
|
||||
MethodNode node =
|
||||
_getMethodNode(elementEnvironment, worldBuilder, entity);
|
||||
if (node.parameterStructure.typeParameters ==
|
||||
instantiation.typeArguments.length) {
|
||||
if (forRtiNeeds) {
|
||||
_instantiationMap ??= <GenericInstantiation, Set<Entity>>{};
|
||||
_instantiationMap
|
||||
.putIfAbsent(instantiation, () => new Set<Entity>())
|
||||
.add(entity);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
worldBuilder.closurizedMembers.forEach(processEntity);
|
||||
worldBuilder.closurizedStatics.forEach(processEntity);
|
||||
worldBuilder.genericLocalFunctions.forEach(processEntity);
|
||||
}
|
||||
}
|
||||
|
||||
void _propagateTests(CommonElements commonElements,
|
||||
@@ -1339,6 +1416,12 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase
|
||||
|
||||
Map<Selector, Set<Entity>> selectorsNeedingTypeArgumentsForTesting;
|
||||
|
||||
Map<GenericInstantiation, Set<Entity>>
|
||||
instantiationsNeedingTypeArgumentsForTesting;
|
||||
|
||||
final Set<GenericInstantiation> _genericInstantiations =
|
||||
new Set<GenericInstantiation>();
|
||||
|
||||
TypeVariableTests typeVariableTestsForTesting;
|
||||
|
||||
RuntimeTypesNeedBuilderImpl(this._elementEnvironment, DartTypes types)
|
||||
@@ -1359,6 +1442,11 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase
|
||||
localFunctionsUsingTypeVariableLiterals.add(localFunction);
|
||||
}
|
||||
|
||||
@override
|
||||
void registerGenericInstantiation(GenericInstantiation instantiation) {
|
||||
_genericInstantiations.add(instantiation);
|
||||
}
|
||||
|
||||
@override
|
||||
RuntimeTypesNeed computeRuntimeTypesNeed(
|
||||
ResolutionWorldBuilder resolutionWorldBuilder,
|
||||
@@ -1368,7 +1456,8 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase
|
||||
closedWorld.elementEnvironment,
|
||||
closedWorld.commonElements,
|
||||
closedWorld.dartTypes,
|
||||
resolutionWorldBuilder);
|
||||
resolutionWorldBuilder,
|
||||
_genericInstantiations);
|
||||
Set<ClassEntity> classesNeedingTypeArguments = new Set<ClassEntity>();
|
||||
Set<FunctionEntity> methodsNeedingSignature = new Set<FunctionEntity>();
|
||||
Set<FunctionEntity> methodsNeedingTypeArguments = new Set<FunctionEntity>();
|
||||
@@ -1440,8 +1529,9 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase
|
||||
if (potentialSubtypeOf == null ||
|
||||
closedWorld.dartTypes.isPotentialSubtype(
|
||||
functionType, potentialSubtypeOf,
|
||||
assumeInstantiations:
|
||||
closedWorld.backendUsage.isGenericInstantiationUsed)) {
|
||||
// TODO(johnniwinther): Use register generic instantiations
|
||||
// instead.
|
||||
assumeInstantiations: _genericInstantiations.isNotEmpty)) {
|
||||
functionType.forEachTypeVariable((TypeVariableType typeVariable) {
|
||||
Entity typeDeclaration = typeVariable.element.typeDeclaration;
|
||||
if (!processedEntities.contains(typeDeclaration)) {
|
||||
@@ -1571,6 +1661,28 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase
|
||||
}
|
||||
}
|
||||
});
|
||||
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 (cacheRtiDataForTesting) {
|
||||
instantiationsNeedingTypeArgumentsForTesting ??=
|
||||
<GenericInstantiation, Set<Entity>>{};
|
||||
instantiationsNeedingTypeArgumentsForTesting
|
||||
.putIfAbsent(instantiation, () => new Set<Entity>())
|
||||
.add(target);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (cacheRtiDataForTesting) {
|
||||
typeVariableTestsForTesting = typeVariableTests;
|
||||
@@ -1594,9 +1706,11 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase
|
||||
localFunctionsNeedingTypeArguments.forEach((e) => print(' $e'));
|
||||
print('------------------------------------------------------------------');
|
||||
print('selectorsNeedingTypeArguments:');
|
||||
selectorsNeedingTypeArguments.forEach((e) => print(' $e'));*/
|
||||
selectorsNeedingTypeArguments.forEach((e) => print(' $e'));
|
||||
print('instantiationsNeedingTypeArguments: '
|
||||
'$instantiationsNeedingTypeArguments');*/
|
||||
|
||||
return _createRuntimeTypesNeed(
|
||||
return new RuntimeTypesNeedImpl(
|
||||
_elementEnvironment,
|
||||
closedWorld.backendUsage,
|
||||
classesNeedingTypeArguments,
|
||||
@@ -1604,27 +1718,8 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase
|
||||
methodsNeedingTypeArguments,
|
||||
localFunctionsNeedingSignature,
|
||||
localFunctionsNeedingTypeArguments,
|
||||
selectorsNeedingTypeArguments);
|
||||
}
|
||||
|
||||
RuntimeTypesNeed _createRuntimeTypesNeed(
|
||||
ElementEnvironment elementEnvironment,
|
||||
BackendUsage backendUsage,
|
||||
Set<ClassEntity> classesNeedingTypeArguments,
|
||||
Set<FunctionEntity> methodsNeedingSignature,
|
||||
Set<FunctionEntity> methodsNeedingTypeArguments,
|
||||
Set<Local> localFunctionsNeedingSignature,
|
||||
Set<Local> localFunctionsNeedingTypeArguments,
|
||||
Set<Selector> selectorsNeedingTypeArguments) {
|
||||
return new RuntimeTypesNeedImpl(
|
||||
_elementEnvironment,
|
||||
backendUsage,
|
||||
classesNeedingTypeArguments,
|
||||
methodsNeedingSignature,
|
||||
methodsNeedingTypeArguments,
|
||||
localFunctionsNeedingSignature,
|
||||
localFunctionsNeedingTypeArguments,
|
||||
selectorsNeedingTypeArguments);
|
||||
selectorsNeedingTypeArguments,
|
||||
instantiationsNeedingTypeArguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1672,6 +1767,9 @@ class RuntimeTypesImpl extends _RuntimeTypesBase
|
||||
|
||||
Map<ClassEntity, ClassUse> classUseMapForTesting;
|
||||
|
||||
final Set<GenericInstantiation> _genericInstantiations =
|
||||
new Set<GenericInstantiation>();
|
||||
|
||||
@override
|
||||
void registerTypeVariableBoundsSubtypeCheck(
|
||||
DartType typeArgument, DartType bound) {
|
||||
@@ -1679,10 +1777,19 @@ class RuntimeTypesImpl extends _RuntimeTypesBase
|
||||
checkedBounds.add(bound);
|
||||
}
|
||||
|
||||
@override
|
||||
void registerGenericInstantiation(GenericInstantiation instantiation) {
|
||||
_genericInstantiations.add(instantiation);
|
||||
}
|
||||
|
||||
RuntimeTypesChecks computeRequiredChecks(
|
||||
CodegenWorldBuilder codegenWorldBuilder, CompilerOptions options) {
|
||||
TypeVariableTests typeVariableTests = new TypeVariableTests(
|
||||
_elementEnvironment, _commonElements, _types, codegenWorldBuilder,
|
||||
_elementEnvironment,
|
||||
_commonElements,
|
||||
_types,
|
||||
codegenWorldBuilder,
|
||||
_genericInstantiations,
|
||||
forRtiNeeds: false);
|
||||
Set<DartType> explicitIsChecks = typeVariableTests.explicitIsChecks;
|
||||
Set<DartType> implicitIsChecks = typeVariableTests.implicitIsChecks;
|
||||
|
||||
@@ -199,6 +199,13 @@ class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case VariableUseKind.instantiationTypeArgument:
|
||||
// TODO(johnniwinther): Use the static type of the expression.
|
||||
if (rtiNeed.instantiationNeedsTypeArguments(
|
||||
null, usage.instantiation.typeArguments.length)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -428,6 +435,9 @@ enum VariableUseKind {
|
||||
|
||||
/// A type variable in a field type.
|
||||
fieldType,
|
||||
|
||||
/// A type argument of an generic instantiation.
|
||||
instantiationTypeArgument,
|
||||
}
|
||||
|
||||
class VariableUse {
|
||||
@@ -436,21 +446,25 @@ class VariableUse {
|
||||
final ir.TreeNode /*ir.FunctionDeclaration|ir.FunctionExpression*/
|
||||
localFunction;
|
||||
final ir.MethodInvocation invocation;
|
||||
final ir.Instantiation instantiation;
|
||||
|
||||
const VariableUse._simple(this.kind)
|
||||
: this.member = null,
|
||||
this.localFunction = null,
|
||||
this.invocation = null;
|
||||
this.invocation = null,
|
||||
this.instantiation = null;
|
||||
|
||||
VariableUse.memberParameter(this.member)
|
||||
: this.kind = VariableUseKind.memberParameter,
|
||||
this.localFunction = null,
|
||||
this.invocation = null;
|
||||
this.invocation = null,
|
||||
this.instantiation = null;
|
||||
|
||||
VariableUse.localParameter(this.localFunction)
|
||||
: this.kind = VariableUseKind.localParameter,
|
||||
this.member = null,
|
||||
this.invocation = null {
|
||||
this.invocation = null,
|
||||
this.instantiation = null {
|
||||
assert(localFunction is ir.FunctionDeclaration ||
|
||||
localFunction is ir.FunctionExpression);
|
||||
}
|
||||
@@ -458,12 +472,14 @@ class VariableUse {
|
||||
VariableUse.memberReturnType(this.member)
|
||||
: this.kind = VariableUseKind.memberReturnType,
|
||||
this.localFunction = null,
|
||||
this.invocation = null;
|
||||
this.invocation = null,
|
||||
this.instantiation = null;
|
||||
|
||||
VariableUse.localReturnType(this.localFunction)
|
||||
: this.kind = VariableUseKind.localReturnType,
|
||||
this.member = null,
|
||||
this.invocation = null {
|
||||
this.invocation = null,
|
||||
this.instantiation = null {
|
||||
assert(localFunction is ir.FunctionDeclaration ||
|
||||
localFunction is ir.FunctionExpression);
|
||||
}
|
||||
@@ -471,25 +487,35 @@ class VariableUse {
|
||||
VariableUse.constructorTypeArgument(this.member)
|
||||
: this.kind = VariableUseKind.constructorTypeArgument,
|
||||
this.localFunction = null,
|
||||
this.invocation = null;
|
||||
this.invocation = null,
|
||||
this.instantiation = null;
|
||||
|
||||
VariableUse.staticTypeArgument(this.member)
|
||||
: this.kind = VariableUseKind.staticTypeArgument,
|
||||
this.localFunction = null,
|
||||
this.invocation = null;
|
||||
this.invocation = null,
|
||||
this.instantiation = null;
|
||||
|
||||
VariableUse.instanceTypeArgument(this.invocation)
|
||||
: this.kind = VariableUseKind.instanceTypeArgument,
|
||||
this.member = null,
|
||||
this.localFunction = null;
|
||||
this.localFunction = null,
|
||||
this.instantiation = null;
|
||||
|
||||
VariableUse.localTypeArgument(this.localFunction, this.invocation)
|
||||
: this.kind = VariableUseKind.localTypeArgument,
|
||||
this.member = null {
|
||||
this.member = null,
|
||||
this.instantiation = null {
|
||||
assert(localFunction is ir.FunctionDeclaration ||
|
||||
localFunction is ir.FunctionExpression);
|
||||
}
|
||||
|
||||
VariableUse.instantiationTypeArgument(this.instantiation)
|
||||
: this.kind = VariableUseKind.instantiationTypeArgument,
|
||||
this.member = null,
|
||||
this.localFunction = null,
|
||||
this.invocation = null;
|
||||
|
||||
static const VariableUse explicit =
|
||||
const VariableUse._simple(VariableUseKind.explicit);
|
||||
|
||||
@@ -512,7 +538,8 @@ class VariableUse {
|
||||
kind.hashCode * 11 +
|
||||
member.hashCode * 13 +
|
||||
localFunction.hashCode * 17 +
|
||||
invocation.hashCode * 19;
|
||||
invocation.hashCode * 19 +
|
||||
instantiation.hashCode * 23;
|
||||
|
||||
bool operator ==(other) {
|
||||
if (identical(this, other)) return true;
|
||||
@@ -520,11 +547,13 @@ class VariableUse {
|
||||
return kind == other.kind &&
|
||||
member == other.member &&
|
||||
localFunction == other.localFunction &&
|
||||
invocation == other.invocation;
|
||||
invocation == other.invocation &&
|
||||
instantiation == other.instantiation;
|
||||
}
|
||||
|
||||
String toString() => 'VariableUse(kind=$kind,member=$member,'
|
||||
'localFunction=$localFunction,invocation=$invocation)';
|
||||
'localFunction=$localFunction,invocation=$invocation,'
|
||||
'instantiation=$instantiation)';
|
||||
}
|
||||
|
||||
class KernelScopeInfo {
|
||||
@@ -1150,4 +1179,7 @@ abstract class ClosureRtiNeed {
|
||||
bool localFunctionNeedsSignature(ir.Node node);
|
||||
|
||||
bool selectorNeedsTypeArguments(Selector selector);
|
||||
|
||||
bool instantiationNeedsTypeArguments(
|
||||
DartType functionType, int typeArgumentCount);
|
||||
}
|
||||
|
||||
@@ -631,7 +631,8 @@ class CapturedScopeBuilder extends ir.Visitor {
|
||||
|
||||
@override
|
||||
visitInstantiation(ir.Instantiation node) {
|
||||
visitChildrenInContext(node, VariableUse.explicit);
|
||||
visitChildrenInContext(
|
||||
node, new VariableUse.instantiationTypeArgument(node));
|
||||
}
|
||||
|
||||
/// Returns true if the node is a field, or a constructor (factory or
|
||||
|
||||
@@ -416,7 +416,6 @@ class JsClosedWorldBuilder {
|
||||
map.toBackendFunctionSet(backendUsage.helperFunctionsUsed);
|
||||
Set<ClassEntity> helperClassesUsed =
|
||||
map.toBackendClassSet(backendUsage.helperClassesUsed);
|
||||
|
||||
return new BackendUsageImpl(
|
||||
globalFunctionDependencies: globalFunctionDependencies,
|
||||
globalClassDependencies: globalClassDependencies,
|
||||
@@ -572,7 +571,8 @@ class JsClosedWorldBuilder {
|
||||
methodsNeedingTypeArguments,
|
||||
null,
|
||||
null,
|
||||
selectorsNeedingTypeArguments);
|
||||
selectorsNeedingTypeArguments,
|
||||
rtiNeed.instantiationsNeedingTypeArguments);
|
||||
}
|
||||
|
||||
/// Construct a closure class and set up the necessary class inference
|
||||
@@ -829,12 +829,28 @@ class TypeConverter extends DartTypeVisitor<DartType, Null> {
|
||||
class TrivialClosureRtiNeed implements ClosureRtiNeed {
|
||||
const TrivialClosureRtiNeed();
|
||||
|
||||
@override
|
||||
bool localFunctionNeedsSignature(ir.Node node) => true;
|
||||
|
||||
@override
|
||||
bool classNeedsTypeArguments(ClassEntity cls) => true;
|
||||
|
||||
@override
|
||||
bool methodNeedsTypeArguments(FunctionEntity method) => true;
|
||||
|
||||
@override
|
||||
bool localFunctionNeedsTypeArguments(ir.Node node) => true;
|
||||
|
||||
@override
|
||||
bool selectorNeedsTypeArguments(Selector selector) => true;
|
||||
|
||||
@override
|
||||
bool methodNeedsSignature(MemberEntity method) => true;
|
||||
|
||||
@override
|
||||
bool instantiationNeedsTypeArguments(
|
||||
DartType functionType, int typeArgumentCount) =>
|
||||
true;
|
||||
}
|
||||
|
||||
class JsClosureRtiNeed implements ClosureRtiNeed {
|
||||
@@ -849,6 +865,7 @@ class JsClosureRtiNeed implements ClosureRtiNeed {
|
||||
this.localFunctionsNodesNeedingTypeArguments,
|
||||
this.localFunctionsNodesNeedingSignature);
|
||||
|
||||
@override
|
||||
bool localFunctionNeedsSignature(ir.Node node) {
|
||||
assert(node is ir.FunctionDeclaration || node is ir.FunctionExpression);
|
||||
return backendUsage.isRuntimeTypeUsed
|
||||
@@ -856,12 +873,15 @@ class JsClosureRtiNeed implements ClosureRtiNeed {
|
||||
: localFunctionsNodesNeedingSignature.contains(node);
|
||||
}
|
||||
|
||||
@override
|
||||
bool classNeedsTypeArguments(ClassEntity cls) =>
|
||||
rtiNeed.classNeedsTypeArguments(cls);
|
||||
|
||||
@override
|
||||
bool methodNeedsTypeArguments(FunctionEntity method) =>
|
||||
rtiNeed.methodNeedsTypeArguments(method);
|
||||
|
||||
@override
|
||||
bool localFunctionNeedsTypeArguments(ir.Node node) {
|
||||
assert(node is ir.FunctionDeclaration || node is ir.FunctionExpression);
|
||||
return backendUsage.isRuntimeTypeUsed
|
||||
@@ -869,9 +889,16 @@ class JsClosureRtiNeed implements ClosureRtiNeed {
|
||||
: localFunctionsNodesNeedingTypeArguments.contains(node);
|
||||
}
|
||||
|
||||
@override
|
||||
bool selectorNeedsTypeArguments(Selector selector) =>
|
||||
rtiNeed.selectorNeedsTypeArguments(selector);
|
||||
|
||||
@override
|
||||
bool methodNeedsSignature(MemberEntity method) =>
|
||||
rtiNeed.methodNeedsSignature(method);
|
||||
|
||||
@override
|
||||
bool instantiationNeedsTypeArguments(
|
||||
DartType functionType, int typeArgumentCount) =>
|
||||
rtiNeed.instantiationNeedsTypeArguments(functionType, typeArgumentCount);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ class ResolutionWorldImpactBuilder extends WorldImpactBuilderImpl
|
||||
Setlet<ConstantExpression> _constantLiterals;
|
||||
Setlet<dynamic> _nativeData;
|
||||
Setlet<ClassEntity> _seenClasses;
|
||||
Set<GenericInstantiation> _genericInstantiations;
|
||||
|
||||
ResolutionWorldImpactBuilder(this.name);
|
||||
|
||||
@@ -30,9 +31,7 @@ class ResolutionWorldImpactBuilder extends WorldImpactBuilderImpl
|
||||
|
||||
void registerMapLiteral(MapLiteralUse mapLiteralUse) {
|
||||
assert(mapLiteralUse != null);
|
||||
if (_mapLiterals == null) {
|
||||
_mapLiterals = new Setlet<MapLiteralUse>();
|
||||
}
|
||||
_mapLiterals ??= new Setlet<MapLiteralUse>();
|
||||
_mapLiterals.add(mapLiteralUse);
|
||||
}
|
||||
|
||||
@@ -43,9 +42,7 @@ class ResolutionWorldImpactBuilder extends WorldImpactBuilderImpl
|
||||
|
||||
void registerListLiteral(ListLiteralUse listLiteralUse) {
|
||||
assert(listLiteralUse != null);
|
||||
if (_listLiterals == null) {
|
||||
_listLiterals = new Setlet<ListLiteralUse>();
|
||||
}
|
||||
_listLiterals ??= new Setlet<ListLiteralUse>();
|
||||
_listLiterals.add(listLiteralUse);
|
||||
}
|
||||
|
||||
@@ -55,9 +52,7 @@ class ResolutionWorldImpactBuilder extends WorldImpactBuilderImpl
|
||||
}
|
||||
|
||||
void registerConstSymbolName(String name) {
|
||||
if (_constSymbolNames == null) {
|
||||
_constSymbolNames = new Setlet<String>();
|
||||
}
|
||||
_constSymbolNames ??= new Setlet<String>();
|
||||
_constSymbolNames.add(name);
|
||||
}
|
||||
|
||||
@@ -67,9 +62,7 @@ class ResolutionWorldImpactBuilder extends WorldImpactBuilderImpl
|
||||
}
|
||||
|
||||
void registerFeature(Feature feature) {
|
||||
if (_features == null) {
|
||||
_features = new EnumSet<Feature>();
|
||||
}
|
||||
_features ??= new EnumSet<Feature>();
|
||||
_features.add(feature);
|
||||
}
|
||||
|
||||
@@ -81,9 +74,7 @@ class ResolutionWorldImpactBuilder extends WorldImpactBuilderImpl
|
||||
}
|
||||
|
||||
void registerConstantLiteral(ConstantExpression constant) {
|
||||
if (_constantLiterals == null) {
|
||||
_constantLiterals = new Setlet<ConstantExpression>();
|
||||
}
|
||||
_constantLiterals ??= new Setlet<ConstantExpression>();
|
||||
_constantLiterals.add(constant);
|
||||
}
|
||||
|
||||
@@ -95,9 +86,7 @@ class ResolutionWorldImpactBuilder extends WorldImpactBuilderImpl
|
||||
|
||||
void registerNativeData(dynamic nativeData) {
|
||||
assert(nativeData != null);
|
||||
if (_nativeData == null) {
|
||||
_nativeData = new Setlet<dynamic>();
|
||||
}
|
||||
_nativeData ??= new Setlet<dynamic>();
|
||||
_nativeData.add(nativeData);
|
||||
}
|
||||
|
||||
@@ -107,9 +96,7 @@ class ResolutionWorldImpactBuilder extends WorldImpactBuilderImpl
|
||||
}
|
||||
|
||||
void registerSeenClass(ClassEntity seenClass) {
|
||||
if (_seenClasses == null) {
|
||||
_seenClasses = new Setlet<ClassEntity>();
|
||||
}
|
||||
_seenClasses ??= new Setlet<ClassEntity>();
|
||||
_seenClasses.add(seenClass);
|
||||
}
|
||||
|
||||
@@ -118,6 +105,16 @@ class ResolutionWorldImpactBuilder extends WorldImpactBuilderImpl
|
||||
return _seenClasses ?? const <ClassEntity>[];
|
||||
}
|
||||
|
||||
void registerInstantiation(GenericInstantiation instantiation) {
|
||||
_genericInstantiations ??= new Set<GenericInstantiation>();
|
||||
_genericInstantiations.add(instantiation);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<GenericInstantiation> get genericInstantiations {
|
||||
return _genericInstantiations ?? const <GenericInstantiation>[];
|
||||
}
|
||||
|
||||
String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.write('_ResolutionWorldImpact($name)');
|
||||
@@ -155,6 +152,12 @@ class ResolutionWorldImpactBuilder extends WorldImpactBuilderImpl
|
||||
sb.write('\n $data');
|
||||
}
|
||||
}
|
||||
if (_genericInstantiations != null) {
|
||||
sb.write('\n instantiations:');
|
||||
for (var data in _genericInstantiations) {
|
||||
sb.write('\n $data');
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import '../native/native.dart' as native;
|
||||
import '../types/abstract_value_domain.dart';
|
||||
import '../types/types.dart';
|
||||
import '../universe/call_structure.dart';
|
||||
import '../universe/feature.dart';
|
||||
import '../universe/selector.dart';
|
||||
import '../universe/side_effects.dart' show SideEffects;
|
||||
import '../universe/target_checks.dart' show TargetChecks;
|
||||
@@ -4234,9 +4235,20 @@ class KernelSsaGraphBuilder extends ir.Visitor
|
||||
var arguments = <HInstruction>[];
|
||||
node.expression.accept(this);
|
||||
arguments.add(pop());
|
||||
for (ir.DartType type in node.typeArguments) {
|
||||
HInstruction instruction = typeBuilder.analyzeTypeArgument(
|
||||
_elementMap.getDartType(type), sourceElement);
|
||||
// TODO(johnniwinther): Use the static type of the expression.
|
||||
bool typeArgumentsNeeded = rtiNeed.instantiationNeedsTypeArguments(
|
||||
null, node.typeArguments.length);
|
||||
List<DartType> typeArguments = node.typeArguments
|
||||
.map((type) => typeArgumentsNeeded
|
||||
? _elementMap.getDartType(type)
|
||||
: _commonElements.dynamicType)
|
||||
.toList();
|
||||
registry.registerGenericInstantiation(
|
||||
new GenericInstantiation(null, typeArguments));
|
||||
// TODO(johnniwinther): Can we avoid creating the instantiation object?
|
||||
for (DartType type in typeArguments) {
|
||||
HInstruction instruction =
|
||||
typeBuilder.analyzeTypeArgument(type, sourceElement);
|
||||
arguments.add(instruction);
|
||||
}
|
||||
int typeArgumentCount = node.typeArguments.length;
|
||||
|
||||
@@ -680,7 +680,9 @@ class KernelImpactBuilder extends ir.Visitor {
|
||||
@override
|
||||
void visitInstantiation(ir.Instantiation node) {
|
||||
// TODO(johnniwinther): Track which arities are used in instantiation.
|
||||
impactBuilder.registerFeature(Feature.GENERIC_INSTANTIATION);
|
||||
impactBuilder.registerInstantiation(new GenericInstantiation(
|
||||
elementMap.getStaticType(node.expression),
|
||||
node.typeArguments.map(elementMap.getDartType).toList()));
|
||||
node.visitChildren(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
/// compilation pipeline, for example during resolution.
|
||||
library compiler.universe.feature;
|
||||
|
||||
import '../elements/types.dart' show InterfaceType;
|
||||
import '../elements/types.dart' show DartType, InterfaceType;
|
||||
import '../util/util.dart';
|
||||
|
||||
/// A language feature that may be seen in the program.
|
||||
// TODO(johnniwinther): Should mirror usage be part of this?
|
||||
@@ -43,9 +44,6 @@ enum Feature {
|
||||
/// A field without an initializer.
|
||||
FIELD_WITHOUT_INITIALIZER,
|
||||
|
||||
/// A generic instantiation (application of type parameters).
|
||||
GENERIC_INSTANTIATION,
|
||||
|
||||
/// A field whose initialization is not a constant.
|
||||
LAZY_FIELD,
|
||||
|
||||
@@ -149,3 +147,33 @@ class ListLiteralUse {
|
||||
return 'ListLiteralUse($type,isConstant:$isConstant,isEmpty:$isEmpty)';
|
||||
}
|
||||
}
|
||||
|
||||
/// A generic instantiation of an expression of type [functionType] with the
|
||||
/// given [typeArguments].
|
||||
class GenericInstantiation {
|
||||
/// The static type of the instantiated expression.
|
||||
final DartType functionType;
|
||||
|
||||
/// The type arguments of the instantiation.
|
||||
final List<DartType> typeArguments;
|
||||
|
||||
GenericInstantiation(this.functionType, this.typeArguments);
|
||||
|
||||
/// Short textual representation use for testing.
|
||||
String get shortText => '<${typeArguments.join(',')}>';
|
||||
|
||||
int get hashCode =>
|
||||
Hashing.listHash(typeArguments, Hashing.objectHash(functionType));
|
||||
|
||||
bool operator ==(other) {
|
||||
if (identical(this, other)) return true;
|
||||
if (other is! GenericInstantiation) return false;
|
||||
return functionType == other.functionType &&
|
||||
equalElements(typeArguments, other.typeArguments);
|
||||
}
|
||||
|
||||
String toString() {
|
||||
return 'GenericInstantiation(functionType:$functionType,'
|
||||
'typeArguments:$typeArguments)';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,9 +99,7 @@ class WorldImpactBuilderImpl extends WorldImpact implements WorldImpactBuilder {
|
||||
|
||||
void registerDynamicUse(DynamicUse dynamicUse) {
|
||||
assert(dynamicUse != null);
|
||||
if (_dynamicUses == null) {
|
||||
_dynamicUses = new Setlet<DynamicUse>();
|
||||
}
|
||||
_dynamicUses ??= new Setlet<DynamicUse>();
|
||||
_dynamicUses.add(dynamicUse);
|
||||
}
|
||||
|
||||
@@ -111,9 +109,7 @@ class WorldImpactBuilderImpl extends WorldImpact implements WorldImpactBuilder {
|
||||
|
||||
void registerTypeUse(TypeUse typeUse) {
|
||||
assert(typeUse != null);
|
||||
if (_typeUses == null) {
|
||||
_typeUses = new Setlet<TypeUse>();
|
||||
}
|
||||
_typeUses ??= new Setlet<TypeUse>();
|
||||
_typeUses.add(typeUse);
|
||||
}
|
||||
|
||||
@@ -123,9 +119,7 @@ class WorldImpactBuilderImpl extends WorldImpact implements WorldImpactBuilder {
|
||||
|
||||
void registerStaticUse(StaticUse staticUse) {
|
||||
assert(staticUse != null);
|
||||
if (_staticUses == null) {
|
||||
_staticUses = new Setlet<StaticUse>();
|
||||
}
|
||||
_staticUses ??= new Setlet<StaticUse>();
|
||||
_staticUses.add(staticUse);
|
||||
}
|
||||
|
||||
@@ -135,9 +129,7 @@ class WorldImpactBuilderImpl extends WorldImpact implements WorldImpactBuilder {
|
||||
|
||||
void registerConstantUse(ConstantUse constantUse) {
|
||||
assert(constantUse != null);
|
||||
if (_constantUses == null) {
|
||||
_constantUses = new Setlet<ConstantUse>();
|
||||
}
|
||||
_constantUses ??= new Setlet<ConstantUse>();
|
||||
_constantUses.add(constantUse);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ main(List<String> args) {
|
||||
asyncTest(() async {
|
||||
Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
|
||||
await checkTests(dataDir, computeKernelClosureData,
|
||||
skipForKernel: skipForKernel, args: args);
|
||||
skipForKernel: skipForKernel, args: args, testOmit: true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -55,8 +55,14 @@ class Class1<T> {
|
||||
return /*fields=[S,U],free=[S,U],hasThis*/ () => '$S$U';
|
||||
}
|
||||
|
||||
var local2 = /*fields=[S,this],free=[S,this],hasThis*/ (o) {
|
||||
return /*fields=[S,this],free=[S,this],hasThis*/ () => new Map<T, S>();
|
||||
var local2 =
|
||||
/*strong.fields=[S,this],free=[S,this],hasThis*/
|
||||
/*omit.hasThis*/
|
||||
(o) {
|
||||
return
|
||||
/*strong.fields=[S,this],free=[S,this],hasThis*/
|
||||
/*omit.hasThis*/
|
||||
() => new Map<T, S>();
|
||||
};
|
||||
return local2(local<double>());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
int f<T>(T a) => null;
|
||||
|
||||
typedef int F<R>(R a);
|
||||
|
||||
/*element: B.:hasThis*/
|
||||
class B<S> {
|
||||
/*element: B.method:hasThis*/
|
||||
method() {
|
||||
return
|
||||
/*kernel.hasThis*/
|
||||
/*strong.fields=[this],free=[this],hasThis*/
|
||||
/*omit.hasThis*/
|
||||
() {
|
||||
F<S> c = f;
|
||||
return c;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
new B().method();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
bool f<T>(T a) => a is T;
|
||||
|
||||
typedef bool F<R>(R a);
|
||||
|
||||
/*element: B.:hasThis*/
|
||||
class B<S> {
|
||||
/*element: B.method:hasThis*/
|
||||
method() {
|
||||
return
|
||||
/*kernel.hasThis*/
|
||||
/*!kernel.fields=[this],free=[this],hasThis*/
|
||||
() {
|
||||
F<S> c = f;
|
||||
return c;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
new B().method();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
int f<T>(T a) => null;
|
||||
|
||||
typedef int F<R>(R a);
|
||||
|
||||
method<S>() {
|
||||
return
|
||||
/*strong.fields=[S],free=[S]*/
|
||||
/*omit.*/
|
||||
() {
|
||||
F<S> c = f;
|
||||
return c;
|
||||
};
|
||||
}
|
||||
|
||||
main() {
|
||||
method();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
bool f<T>(T a) => a is T;
|
||||
|
||||
typedef bool F<R>(R a);
|
||||
|
||||
method<S>() {
|
||||
return
|
||||
/*strong.fields=[S],free=[S]*/
|
||||
/*omit.fields=[S],free=[S]*/
|
||||
() {
|
||||
F<S> c = f;
|
||||
return c;
|
||||
};
|
||||
}
|
||||
|
||||
main() {
|
||||
method();
|
||||
}
|
||||
@@ -5,7 +5,8 @@
|
||||
T id<T>(T t) => t;
|
||||
|
||||
method<S>(S s) {
|
||||
/*fields=[S],free=[S]*/
|
||||
/*strong.fields=[S],free=[S]*/
|
||||
/*omit.*/
|
||||
S Function(S) getId() => id;
|
||||
return getId();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ import 'package:expect/expect.dart';
|
||||
|
||||
@NoInline()
|
||||
method<T>() {
|
||||
/**/ dynamic local() => <T>[];
|
||||
/*!strong.*/
|
||||
/*strong.fields=[T],free=[T]*/
|
||||
dynamic local() => <T>[];
|
||||
return local;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@ class A<T> {
|
||||
/*element: A.method:hasThis*/
|
||||
@NoInline()
|
||||
method() {
|
||||
/*hasThis*/ dynamic local() => <T>[];
|
||||
/*!strong.hasThis*/
|
||||
/*strong.fields=[this],free=[this],hasThis*/
|
||||
dynamic local() => <T>[];
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ import 'package:expect/expect.dart';
|
||||
|
||||
@NoInline()
|
||||
method<T>() {
|
||||
/**/ dynamic local() => <T, int>{};
|
||||
/*!strong.*/
|
||||
/*strong.fields=[T],free=[T]*/
|
||||
dynamic local() => <T, int>{};
|
||||
return local;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@ class A<T> {
|
||||
/*element: A.method:hasThis*/
|
||||
@NoInline()
|
||||
method() {
|
||||
/*hasThis*/ dynamic local() => <T, int>{};
|
||||
/*!strong.hasThis*/
|
||||
/*strong.fields=[this],free=[this],hasThis*/
|
||||
dynamic local() => <T, int>{};
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class Class2<T> {
|
||||
class Class3<T> {
|
||||
/*element: Class3.method3:hasThis*/
|
||||
method3(dynamic o) {
|
||||
/*kernel.fields=[o],free=[o],hasThis*/
|
||||
/*!strong.fields=[o],free=[o],hasThis*/
|
||||
/*strong.fields=[o,this],free=[o,this],hasThis*/
|
||||
T local() => o;
|
||||
return local;
|
||||
|
||||
@@ -30,7 +30,8 @@ method2<T>(dynamic o) {
|
||||
|
||||
/*element: method3:*/
|
||||
method3<T>(dynamic o) {
|
||||
/*fields=[T,o],free=[T,o]*/
|
||||
/*strong.fields=[T,o],free=[T,o]*/
|
||||
/*omit.fields=[o],free=[o]*/
|
||||
T local() => o;
|
||||
return local;
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Explicit is-test is required even with --omit-implicit-checks.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*element: method1:*/
|
||||
method1<T>(dynamic o) {
|
||||
/*fields=[T,o],free=[T,o]*/
|
||||
dynamic local() => o is T;
|
||||
return local;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Explicit as-cast is required even with --omit-implicit-checks.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*element: method2:*/
|
||||
method2<T>(dynamic o) {
|
||||
/*fields=[T,o],free=[T,o]*/
|
||||
dynamic local() => o as T;
|
||||
return local;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Implicit as-cast is not required with --omit-implicit-checks.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*element: method3:*/
|
||||
method3<T>(dynamic o) {
|
||||
/*fields=[o],free=[o]*/
|
||||
T local() => o;
|
||||
return local;
|
||||
}
|
||||
|
||||
main() {
|
||||
method1<int>(0).call();
|
||||
method2<int>(0).call();
|
||||
method3<int>(0).call();
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Explicit is-test is required even with --omit-implicit-checks.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*element: Class1.:hasThis*/
|
||||
class Class1<T> {
|
||||
/*element: Class1.method1:hasThis*/
|
||||
method1(dynamic o) {
|
||||
/*fields=[o,this],free=[o,this],hasThis*/
|
||||
dynamic local() => o is T;
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Explicit as-cast is required even with --omit-implicit-checks.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*element: Class2.:hasThis*/
|
||||
class Class2<T> {
|
||||
/*element: Class2.method2:hasThis*/
|
||||
method2(dynamic o) {
|
||||
/*fields=[o,this],free=[o,this],hasThis*/
|
||||
dynamic local() => o as T;
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Implicit as-cast is not required with --omit-implicit-checks.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*element: Class3.:hasThis*/
|
||||
class Class3<T> {
|
||||
/*element: Class3.method3:hasThis*/
|
||||
method3(dynamic o) {
|
||||
/*fields=[o],free=[o],hasThis*/
|
||||
T local() => o;
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
new Class1<int>().method1(0).call();
|
||||
new Class2<int>().method2(0).call();
|
||||
new Class3<int>().method3(0).call();
|
||||
}
|
||||
@@ -48,7 +48,7 @@ class Class1b<T> {
|
||||
class Class2<T> {
|
||||
/*element: Class2.method2:hasThis*/
|
||||
method2() {
|
||||
/*kernel.hasThis*/
|
||||
/*!strong.hasThis*/
|
||||
/*strong.fields=[this],free=[this],hasThis*/
|
||||
dynamic local(T t) => t;
|
||||
return local;
|
||||
@@ -63,7 +63,7 @@ class Class2<T> {
|
||||
class Class3<T> {
|
||||
/*element: Class3.method3:hasThis*/
|
||||
method3(dynamic o) {
|
||||
/*kernel.fields=[o],free=[o],hasThis*/
|
||||
/*!strong.fields=[o],free=[o],hasThis*/
|
||||
/*strong.fields=[o,this],free=[o,this],hasThis*/
|
||||
T local() => o;
|
||||
return local;
|
||||
@@ -106,7 +106,7 @@ class Class5<T> {
|
||||
class Class6<T> {
|
||||
/*element: Class6.method6:hasThis*/
|
||||
method6() {
|
||||
/*kernel.hasThis*/
|
||||
/*!strong.hasThis*/
|
||||
/*strong.fields=[this],free=[this],hasThis*/
|
||||
dynamic local(T t) {
|
||||
/*fields=[t],free=[t],hasThis*/
|
||||
@@ -126,7 +126,7 @@ class Class6<T> {
|
||||
class Class7<T> {
|
||||
/*element: Class7.method7:hasThis*/
|
||||
method7(dynamic o) {
|
||||
/*kernel.fields=[o],free=[o],hasThis*/
|
||||
/*!strong.fields=[o],free=[o],hasThis*/
|
||||
/*strong.fields=[o,this],free=[o,this],hasThis*/
|
||||
T local() {
|
||||
/*fields=[o],free=[o],hasThis*/
|
||||
|
||||
@@ -21,7 +21,8 @@ method1<T>(T o) {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
method2<T>() {
|
||||
/*fields=[T],free=[T]*/
|
||||
/*strong.fields=[T],free=[T]*/
|
||||
/*omit.*/
|
||||
dynamic local(T t) => t;
|
||||
return local;
|
||||
}
|
||||
@@ -31,7 +32,8 @@ method2<T>() {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
method3<T>(dynamic o) {
|
||||
/*fields=[T,o],free=[T,o]*/
|
||||
/*strong.fields=[T,o],free=[T,o]*/
|
||||
/*omit.fields=[o],free=[o]*/
|
||||
T local() => o;
|
||||
return local;
|
||||
}
|
||||
@@ -61,7 +63,8 @@ T method5<T>(dynamic o) {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
method6<T>() {
|
||||
/*fields=[T],free=[T]*/
|
||||
/*strong.fields=[T],free=[T]*/
|
||||
/*omit.*/
|
||||
dynamic local(T t) {
|
||||
/*fields=[t],free=[t]*/
|
||||
dynamic inner() => t;
|
||||
@@ -76,7 +79,8 @@ method6<T>() {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
method7<T>(dynamic o) {
|
||||
/*fields=[T,o],free=[T,o]*/
|
||||
/*strong.fields=[T,o],free=[T,o]*/
|
||||
/*omit.fields=[o],free=[o]*/
|
||||
T local() {
|
||||
/*fields=[o],free=[o]*/
|
||||
dynamic inner() => o;
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A sound assignment to a local variable doesn't capture the type variable.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
method1<T>(T o) {
|
||||
/*fields=[o],free=[o]*/
|
||||
dynamic local() {
|
||||
T t = o;
|
||||
return t;
|
||||
}
|
||||
|
||||
return local;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A local function parameter type is with --omit-type-checks.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
method2<T>() {
|
||||
/**/
|
||||
dynamic local(T t) => t;
|
||||
return local;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A local function return type is not captured with --omit-type-checks.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
method3<T>(dynamic o) {
|
||||
/*fields=[o],free=[o]*/
|
||||
T local() => o;
|
||||
return local;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A member parameter type is not captured.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
method4<T>(T o) {
|
||||
/*fields=[o],free=[o]*/
|
||||
dynamic local() => o;
|
||||
return local;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A member return type is not captured.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
T method5<T>(dynamic o) {
|
||||
/*fields=[o],free=[o]*/
|
||||
dynamic local() => o;
|
||||
return local();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A local function parameter type is not captured by an inner local function.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
method6<T>() {
|
||||
/**/
|
||||
dynamic local(T t) {
|
||||
/*fields=[t],free=[t]*/
|
||||
dynamic inner() => t;
|
||||
return inner;
|
||||
}
|
||||
|
||||
return local;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A local function return type is not captured by an inner local function.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
method7<T>(dynamic o) {
|
||||
/*fields=[o],free=[o]*/
|
||||
T local() {
|
||||
/*fields=[o],free=[o]*/
|
||||
dynamic inner() => o;
|
||||
return inner();
|
||||
}
|
||||
|
||||
return local;
|
||||
}
|
||||
|
||||
main() {
|
||||
method1<int>(0).call();
|
||||
method2<int>().call(0);
|
||||
method3<int>(0).call();
|
||||
method4<int>(0).call();
|
||||
method5<int>(0);
|
||||
method6<int>().call(0).call();
|
||||
method7<int>(0).call().call();
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A sound assignment to a local variable doesn't capture the type variable.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*element: Class1.:hasThis*/
|
||||
class Class1<T> {
|
||||
/*element: Class1.method1:hasThis*/
|
||||
method1(T o) {
|
||||
/*fields=[o],free=[o],hasThis*/
|
||||
dynamic local() {
|
||||
T t = o;
|
||||
return t;
|
||||
}
|
||||
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A local function parameter type is with --omit-type-checks.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*element: Class2.:hasThis*/
|
||||
class Class2<T> {
|
||||
/*element: Class2.method2:hasThis*/
|
||||
method2() {
|
||||
/*hasThis*/
|
||||
dynamic local(T t) => t;
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A local function return type is not captured with --omit-type-checks.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*element: Class3.:hasThis*/
|
||||
class Class3<T> {
|
||||
/*element: Class3.method3:hasThis*/
|
||||
method3(dynamic o) {
|
||||
/*fields=[o],free=[o],hasThis*/
|
||||
T local() => o;
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A member parameter type is not captured.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*element: Class4.:hasThis*/
|
||||
class Class4<T> {
|
||||
/*element: Class4.method4:hasThis*/
|
||||
method4(T o) {
|
||||
/*fields=[o],free=[o],hasThis*/
|
||||
dynamic local() => o;
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A member return type is not captured.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*element: Class5.:hasThis*/
|
||||
class Class5<T> {
|
||||
/*element: Class5.method5:hasThis*/
|
||||
T method5(dynamic o) {
|
||||
/*fields=[o],free=[o],hasThis*/
|
||||
dynamic local() => o;
|
||||
return local();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A local function parameter type is not captured by an inner local function.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*element: Class6.:hasThis*/
|
||||
class Class6<T> {
|
||||
/*element: Class6.method6:hasThis*/
|
||||
method6() {
|
||||
/*hasThis*/
|
||||
dynamic local(T t) {
|
||||
/*fields=[t],free=[t],hasThis*/
|
||||
dynamic inner() => t;
|
||||
return inner;
|
||||
}
|
||||
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// A local function return type is not captured by an inner local function.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*element: Class7.:hasThis*/
|
||||
class Class7<T> {
|
||||
/*element: Class7.method7:hasThis*/
|
||||
method7(dynamic o) {
|
||||
/*fields=[o],free=[o],hasThis*/
|
||||
T local() {
|
||||
/*fields=[o],free=[o],hasThis*/
|
||||
dynamic inner() => o;
|
||||
return inner();
|
||||
}
|
||||
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
new Class1<int>().method1(0).call();
|
||||
new Class2<int>().method2().call(0);
|
||||
new Class3<int>().method3(0).call();
|
||||
new Class4<int>().method4(0).call();
|
||||
new Class5<int>().method5(0);
|
||||
new Class6<int>().method6().call(0).call();
|
||||
new Class7<int>().method7(0).call().call();
|
||||
}
|
||||
@@ -202,7 +202,8 @@ class A9 {
|
||||
|
||||
/*element: A9.:[exact=A9]*/
|
||||
A9(/*[exact=JSBool]*/ x) {
|
||||
if (x) {} else {
|
||||
if (x) {
|
||||
} else {
|
||||
/*update: [exact=A9]*/ f9 = "1";
|
||||
}
|
||||
}
|
||||
@@ -727,7 +728,8 @@ class A29 {
|
||||
/*element: A29.:[exact=A29]*/
|
||||
A29(/*[exact=JSUInt31]*/ x) {
|
||||
this. /*update: [exact=A29]*/ f29a = x;
|
||||
if (x /*invoke: [exact=JSUInt31]*/ == 0) {} else {
|
||||
if (x /*invoke: [exact=JSUInt31]*/ == 0) {
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
this. /*update: [exact=A29]*/ f29b = x;
|
||||
|
||||
@@ -306,7 +306,8 @@ testIsCheck25(/*[null|subclass=Object]*/ a) {
|
||||
|
||||
/*element: testIsCheck26:[subclass=JSInt]*/
|
||||
testIsCheck26(/*[null|subclass=Object]*/ a) {
|
||||
if (a is int) {} else {
|
||||
if (a is int) {
|
||||
} else {
|
||||
throw 42;
|
||||
}
|
||||
return a;
|
||||
@@ -314,7 +315,8 @@ testIsCheck26(/*[null|subclass=Object]*/ a) {
|
||||
|
||||
/*element: testIsCheck27:[subclass=JSInt]*/
|
||||
testIsCheck27(/*[null|subclass=Object]*/ a) {
|
||||
if (a is int) {} else {
|
||||
if (a is int) {
|
||||
} else {
|
||||
return 42;
|
||||
}
|
||||
return a;
|
||||
@@ -322,7 +324,8 @@ testIsCheck27(/*[null|subclass=Object]*/ a) {
|
||||
|
||||
/*element: testIsCheck28:[null|subclass=Object]*/
|
||||
testIsCheck28(/*[null|subclass=Object]*/ a) {
|
||||
if (a is int) {} else {}
|
||||
if (a is int) {
|
||||
} else {}
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -344,7 +347,8 @@ testIf1(/*[null|subclass=Object]*/ a) {
|
||||
/*element: testIf2:[null|exact=JSUInt31]*/
|
||||
testIf2(/*[null|subclass=Object]*/ a) {
|
||||
var c = null;
|
||||
if (a) {} else {
|
||||
if (a) {
|
||||
} else {
|
||||
c = 10;
|
||||
}
|
||||
return c;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
/*strong.element: f:deps=[B],direct,explicit=[f.T],needsArgs,needsInst=[<B.S>]*/
|
||||
/*omit.element: f:deps=[B]*/
|
||||
int f<T>(T a) => null;
|
||||
|
||||
typedef int F<R>(R a);
|
||||
|
||||
/*strong.class: B:explicit=[int Function(B.S)],indirect,needsArgs*/
|
||||
class B<S> {
|
||||
F<S> c;
|
||||
|
||||
B() : c = f;
|
||||
}
|
||||
|
||||
main() {
|
||||
new B();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
/*kernel.element: f:direct,explicit=[f.T]*/
|
||||
/*!kernel.element: f:deps=[B],direct,explicit=[f.T],needsArgs,needsInst=[<B.S>]*/
|
||||
bool f<T>(T a) => a is T;
|
||||
|
||||
typedef bool F<R>(R a);
|
||||
|
||||
/*strong.class: B:explicit=[bool Function(B.S)],indirect,needsArgs*/
|
||||
/*omit.class: B:indirect,needsArgs*/
|
||||
class B<S> {
|
||||
F<S> c;
|
||||
|
||||
B() : c = f;
|
||||
}
|
||||
|
||||
main() {
|
||||
new B();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
/*strong.element: f:deps=[B],direct,explicit=[f.T],needsArgs,needsInst=[<B.S>]*/
|
||||
/*omit.element: f:deps=[B]*/
|
||||
int f<T>(T a) => null;
|
||||
|
||||
typedef int F<R>(R a);
|
||||
|
||||
/*strong.class: B:direct,explicit=[int Function(B.S)],needsArgs*/
|
||||
class B<S> {
|
||||
F<S> c;
|
||||
|
||||
method() {
|
||||
return () {
|
||||
c = f;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
new B().method();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
/*kernel.element: f:direct,explicit=[f.T]*/
|
||||
/*!kernel.element: f:deps=[B],direct,explicit=[f.T],needsArgs,needsInst=[<B.S>]*/
|
||||
bool f<T>(T a) => a is T;
|
||||
|
||||
typedef bool F<R>(R a);
|
||||
|
||||
/*strong.class: B:direct,explicit=[bool Function(B.S)],needsArgs*/
|
||||
/*omit.class: B:indirect,needsArgs*/
|
||||
class B<S> {
|
||||
F<S> c;
|
||||
|
||||
method() {
|
||||
return () {
|
||||
c = f;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
main() {
|
||||
new B().method();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
/*strong.element: f:deps=[method],direct,explicit=[f.T],needsArgs,needsInst=[<method.S>]*/
|
||||
/*omit.element: f:deps=[method]*/
|
||||
int f<T>(T a) => null;
|
||||
|
||||
typedef int F<R>(R a);
|
||||
|
||||
/*strong.element: method:indirect,needsArgs*/
|
||||
method<S>() {
|
||||
F<S> c;
|
||||
|
||||
return () {
|
||||
c = f;
|
||||
return c;
|
||||
};
|
||||
}
|
||||
|
||||
main() {
|
||||
method();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
/*kernel.element: f:direct,explicit=[f.T]*/
|
||||
/*!kernel.element: f:deps=[method],direct,explicit=[f.T],needsArgs,needsInst=[<method.S>]*/
|
||||
bool f<T>(T a) => a is T;
|
||||
|
||||
typedef bool F<R>(R a);
|
||||
|
||||
/*!kernel.element: method:indirect,needsArgs*/
|
||||
method<S>() {
|
||||
F<S> c;
|
||||
|
||||
return () {
|
||||
c = f;
|
||||
return c;
|
||||
};
|
||||
}
|
||||
|
||||
main() {
|
||||
method();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
/*strong.element: f1:deps=[method],direct,explicit=[f1.T],needsArgs,needsInst=[<method.X>]*/
|
||||
/*omit.element: f1:deps=[method]*/
|
||||
int f1<T>(T a, T b, T c) => null;
|
||||
|
||||
/*strong.element: f2:deps=[method],direct,explicit=[f2.S,f2.T],needsArgs,needsInst=[<method.X,method.Y>]*/
|
||||
/*omit.element: f2:deps=[method]*/
|
||||
int f2<T, S>(T a, S b, S c) => null;
|
||||
|
||||
/*strong.element: f3:deps=[method],direct,explicit=[f3.S,f3.T,f3.U],needsArgs,needsInst=[<method.X,method.Y,method.Z>]*/
|
||||
/*omit.element: f3:deps=[method]*/
|
||||
int f3<T, S, U>(T a, S b, U c) => null;
|
||||
|
||||
typedef int F1<R>(R a, R b, R c);
|
||||
typedef int F2<R, P>(R a, P b, P c);
|
||||
typedef int F3<R, P, Q>(R a, P b, Q c);
|
||||
|
||||
/*strong.element: method:indirect,needsArgs*/
|
||||
method<X, Y, Z>() {
|
||||
F1<X> c1;
|
||||
F2<X, Y> c2;
|
||||
F3<X, Y, Z> c3;
|
||||
|
||||
return () {
|
||||
c1 = f1;
|
||||
c2 = f2;
|
||||
c3 = f3;
|
||||
return c1 ?? c2 ?? c3;
|
||||
};
|
||||
}
|
||||
|
||||
main() {
|
||||
method();
|
||||
}
|
||||
@@ -77,7 +77,7 @@ method9<T>() {
|
||||
}
|
||||
|
||||
method10() {
|
||||
/*strong.direct,explicit=[local.T],needsArgs,needsSignature*/
|
||||
/*strong.direct,explicit=[local.T],needsArgs,needsInst=[<dynamic>,<num>,<num>],needsSignature*/
|
||||
/*omit.needsSignature*/
|
||||
num local<T>(T n) => null;
|
||||
return local;
|
||||
@@ -90,7 +90,7 @@ method11() {
|
||||
}
|
||||
|
||||
method12() {
|
||||
/*strong.direct,explicit=[local.T],needsArgs*/
|
||||
/*strong.direct,explicit=[local.T],needsArgs,needsInst=[<dynamic>,<num>,<num>]*/
|
||||
/*omit.*/
|
||||
num local<T>(num n, T t) => null;
|
||||
return local;
|
||||
@@ -103,7 +103,7 @@ num Function(num) method13() {
|
||||
}
|
||||
|
||||
num Function(num) method14() {
|
||||
/*strong.direct,explicit=[local.T],needsArgs,needsSignature*/
|
||||
/*strong.direct,explicit=[local.T],needsArgs,needsInst=[<dynamic>,<num>,<num>],needsSignature*/
|
||||
/*omit.needsSignature*/
|
||||
num local<T>(T n) => null;
|
||||
return local;
|
||||
|
||||
@@ -16,7 +16,7 @@ class Class1 {
|
||||
}
|
||||
|
||||
class Class2 {
|
||||
/*strong.element: Class2.method4:direct,explicit=[method4.T],needsArgs*/
|
||||
/*strong.element: Class2.method4:direct,explicit=[method4.T],needsArgs,needsInst=[<num>,<num>]*/
|
||||
/*omit.element: Class2.method4:*/
|
||||
num method4<T>(T n) => null;
|
||||
}
|
||||
@@ -27,19 +27,19 @@ class Class3 {
|
||||
}
|
||||
|
||||
class Class4 {
|
||||
/*strong.element: Class4.method6:direct,explicit=[method6.T],needsArgs*/
|
||||
/*strong.element: Class4.method6:direct,explicit=[method6.T],needsArgs,needsInst=[<num>,<num>]*/
|
||||
/*omit.element: Class4.method6:*/
|
||||
num method6<T>(num n, T t) => null;
|
||||
}
|
||||
|
||||
/*strong.element: method7:direct,explicit=[method7.T],needsArgs*/
|
||||
/*strong.element: method7:direct,explicit=[method7.T],needsArgs,needsInst=[<num>,<num>]*/
|
||||
/*omit.element: method7:*/
|
||||
num method7<T>(T n) => null;
|
||||
|
||||
/*element: method8:*/
|
||||
T method8<T>(num n) => null;
|
||||
|
||||
/*strong.element: method9:direct,explicit=[method9.T],needsArgs*/
|
||||
/*strong.element: method9:direct,explicit=[method9.T],needsArgs,needsInst=[<num>,<num>]*/
|
||||
/*omit.element: method9:*/
|
||||
num method9<T>(num n, T t) => null;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import 'package:compiler/src/js_backend/runtime_types.dart';
|
||||
import 'package:compiler/src/kernel/element_map.dart';
|
||||
import 'package:compiler/src/kernel/kernel_backend_strategy.dart';
|
||||
import 'package:compiler/src/kernel/kernel_strategy.dart';
|
||||
import 'package:compiler/src/universe/feature.dart';
|
||||
import 'package:compiler/src/universe/selector.dart';
|
||||
import 'package:compiler/src/universe/world_builder.dart';
|
||||
import 'package:kernel/ast.dart' as ir;
|
||||
@@ -56,6 +57,7 @@ class Tags {
|
||||
static const String indirectTypeArgumentTest = 'indirect';
|
||||
static const String typeLiteral = 'exp';
|
||||
static const String selectors = 'selectors';
|
||||
static const String instantiationsNeedTypeArguments = 'needsInst';
|
||||
}
|
||||
|
||||
abstract class ComputeValueMixin<T> {
|
||||
@@ -162,6 +164,13 @@ abstract class ComputeValueMixin<T> {
|
||||
features.addElement(Tags.selectors, selector);
|
||||
}
|
||||
});
|
||||
rtiNeedBuilder.instantiationsNeedingTypeArgumentsForTesting?.forEach(
|
||||
(GenericInstantiation instantiation, Set<Entity> targets) {
|
||||
if (targets.contains(entity)) {
|
||||
features.addElement(
|
||||
Tags.instantiationsNeedTypeArguments, instantiation.shortText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (frontendClosure != null) {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
// dart2jsOptions=--strong
|
||||
|
||||
int f<T>(T a) => null;
|
||||
|
||||
typedef int F<R>(R a);
|
||||
|
||||
class B<S> {
|
||||
F<S> c;
|
||||
|
||||
B() : c = f;
|
||||
}
|
||||
|
||||
main() {
|
||||
new B<int>().c(0);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
// dart2jsOptions=--strong --omit-implicit-checks
|
||||
|
||||
int f<T>(T a) => null;
|
||||
|
||||
typedef int F<R>(R a);
|
||||
|
||||
class B<S> {
|
||||
F<S> c;
|
||||
|
||||
B() : c = f;
|
||||
}
|
||||
|
||||
main() {
|
||||
new B<int>().c(0);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
// dart2jsOptions=--strong
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
bool f<T, S>(T a, S b) => a is S;
|
||||
|
||||
typedef bool F<P, Q>(P a, Q b);
|
||||
|
||||
class B<X, Y> {
|
||||
F<X, Y> c;
|
||||
|
||||
B() : c = f;
|
||||
}
|
||||
|
||||
main() {
|
||||
Expect.isTrue(new B<int, int>().c(0, 0));
|
||||
Expect.isFalse(new B<int, String>().c(0, ''));
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
// dart2jsOptions=--strong --omit-implicit-checks
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
bool f<T, S>(T a, S b) => a is S;
|
||||
|
||||
typedef bool F<P, Q>(P a, Q b);
|
||||
|
||||
class B<X, Y> {
|
||||
F<X, Y> c;
|
||||
|
||||
B() : c = f;
|
||||
}
|
||||
|
||||
main() {
|
||||
Expect.isTrue(new B<int, int>().c(0, 0));
|
||||
Expect.isFalse(new B<int, String>().c(0, ''));
|
||||
}
|
||||
Reference in New Issue
Block a user