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:
Johnni Winther
2018-06-12 08:00:09 +00:00
committed by commit-bot@chromium.org
parent 1fb845c2f4
commit 52d7a3043a
48 changed files with 748 additions and 468 deletions
+24 -13
View File
@@ -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;
+44 -12
View File
@@ -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
+29 -2
View File
@@ -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);
}
+24 -21
View File
@@ -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();
}
}
+15 -3
View File
@@ -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;
+3 -1
View File
@@ -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);
}
+32 -4
View File
@@ -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, ''));
}