Index: pkg/compiler/lib/src/js_backend/runtime_types.dart |
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart |
index 4c1eed13f228b8588488b11961ed28045a76d7e3..dcacfccdc60514c169b025cc782a04fff7a95823 100644 |
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart |
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart |
@@ -138,11 +138,15 @@ abstract class RuntimeTypesEncoder { |
/// Common functionality for [_RuntimeTypesNeedBuilder] and [_RuntimeTypes]. |
abstract class _RuntimeTypesBase { |
+ final DartTypes _types; |
+ |
// TODO(21969): remove this and analyze instantiated types and factory calls |
// instead to find out which types are instantiated, if finitely many, or if |
// we have to use the more imprecise generic algorithm. |
bool get cannotDetermineInstantiatedTypesPrecisely => true; |
+ _RuntimeTypesBase(this._types); |
+ |
/** |
* Compute type arguments of classes that use one of their type variables in |
* is-checks and add the is-checks that they imply. |
@@ -153,18 +157,21 @@ abstract class _RuntimeTypesBase { |
* immutable datastructure. |
*/ |
void registerImplicitChecks( |
- WorldBuilder worldBuilder, Iterable<ClassElement> classesUsingChecks) { |
+ WorldBuilder worldBuilder, Iterable<ClassEntity> classesUsingChecks) { |
// If there are no classes that use their variables in checks, there is |
// nothing to do. |
if (classesUsingChecks.isEmpty) return; |
Set<InterfaceType> instantiatedTypes = worldBuilder.instantiatedTypes; |
if (cannotDetermineInstantiatedTypesPrecisely) { |
- for (ResolutionInterfaceType type in instantiatedTypes) { |
+ for (InterfaceType type in instantiatedTypes) { |
do { |
- for (ResolutionDartType argument in type.typeArguments) { |
+ for (DartType argument in type.typeArguments) { |
worldBuilder.registerIsCheck(argument); |
} |
- type = type.element.supertype; |
+ // TODO(johnniwinther): This seems wrong; the type arguments of [type] |
Siggi Cherem (dart-lang)
2017/05/02 19:56:50
just checking, the old code did this too too, corr
Johnni Winther
2017/05/03 07:36:33
Yes, adding the TODO to remember the fishy code.
|
+ // are not substituted - `List<int>` yields `Iterable<E>` and not |
+ // `Iterable<int>`. |
+ type = _types.getSupertype(type.element); |
} while (type != null && !instantiatedTypes.contains(type)); |
} |
} else { |
@@ -173,18 +180,21 @@ abstract class _RuntimeTypesBase { |
// set of is-checks. |
// TODO(karlklose): replace this with code that uses a subtype lookup |
// datastructure in the world. |
- for (ResolutionInterfaceType type in instantiatedTypes) { |
- for (ClassElement cls in classesUsingChecks) { |
+ for (InterfaceType type in instantiatedTypes) { |
+ for (ClassEntity cls in classesUsingChecks) { |
do { |
// We need the type as instance of its superclass anyway, so we just |
// try to compute the substitution; if the result is [:null:], the |
// classes are not related. |
- ResolutionInterfaceType instance = type.asInstanceOf(cls); |
+ InterfaceType instance = _types.asInstanceOf(type, cls); |
if (instance == null) break; |
- for (ResolutionDartType argument in instance.typeArguments) { |
+ for (DartType argument in instance.typeArguments) { |
worldBuilder.registerIsCheck(argument); |
} |
- type = type.element.supertype; |
+ // TODO(johnniwinther): This seems wrong; the type arguments of |
+ // [type] are not substituted - `List<int>` yields `Iterable<E>` and |
+ // not `Iterable<int>`. |
+ type = _types.getSupertype(type.element); |
} while (type != null && !instantiatedTypes.contains(type)); |
} |
} |
@@ -193,31 +203,37 @@ abstract class _RuntimeTypesBase { |
} |
class _RuntimeTypesNeed implements RuntimeTypesNeed { |
+ final ElementEnvironment _elementEnvironment; |
final BackendUsage _backendUsage; |
- final Set<ClassElement> classesNeedingRti; |
- final Set<Element> methodsNeedingRti; |
- final Set<Element> localFunctionsNeedingRti; |
+ final Set<ClassEntity> classesNeedingRti; |
+ final Set<FunctionEntity> methodsNeedingRti; |
+ final Set<Local> localFunctionsNeedingRti; |
/// The set of classes that use one of their type variables as expressions |
/// to get the runtime type. |
- final Set<ClassElement> classesUsingTypeVariableExpression; |
+ final Set<ClassEntity> classesUsingTypeVariableExpression; |
_RuntimeTypesNeed( |
+ this._elementEnvironment, |
this._backendUsage, |
this.classesNeedingRti, |
this.methodsNeedingRti, |
this.localFunctionsNeedingRti, |
this.classesUsingTypeVariableExpression); |
- bool classNeedsRti(ClassElement cls) { |
+ bool checkClass(ClassEntity cls) => true; |
+ |
+ bool classNeedsRti(ClassEntity cls) { |
+ assert(checkClass(cls)); |
if (_backendUsage.isRuntimeTypeUsed) return true; |
- return classesNeedingRti.contains(cls.declaration); |
+ return classesNeedingRti.contains(cls); |
} |
- bool classNeedsRtiField(ClassElement cls) { |
- if (cls.rawType.typeArguments.isEmpty) return false; |
+ bool classNeedsRtiField(ClassEntity cls) { |
+ assert(checkClass(cls)); |
+ if (!_elementEnvironment.isGenericClass(cls)) return false; |
if (_backendUsage.isRuntimeTypeUsed) return true; |
- return classesNeedingRti.contains(cls.declaration); |
+ return classesNeedingRti.contains(cls); |
} |
bool methodNeedsRti(MethodElement function) { |
@@ -231,30 +247,56 @@ class _RuntimeTypesNeed implements RuntimeTypesNeed { |
} |
@override |
- bool classUsesTypeVariableExpression(ClassElement cls) { |
+ bool classUsesTypeVariableExpression(ClassEntity cls) { |
return classesUsingTypeVariableExpression.contains(cls); |
} |
} |
+class _ResolutionRuntimeTypesNeed extends _RuntimeTypesNeed { |
+ _ResolutionRuntimeTypesNeed( |
+ ElementEnvironment elementEnvironment, |
+ BackendUsage backendUsage, |
+ Set<ClassEntity> classesNeedingRti, |
+ Set<FunctionEntity> methodsNeedingRti, |
+ Set<Local> localFunctionsNeedingRti, |
+ Set<ClassEntity> classesUsingTypeVariableExpression) |
+ : super( |
+ elementEnvironment, |
+ backendUsage, |
+ classesNeedingRti, |
+ methodsNeedingRti, |
+ localFunctionsNeedingRti, |
+ classesUsingTypeVariableExpression); |
+ |
+ bool checkClass(ClassElement cls) => cls.isDeclaration; |
+} |
+ |
class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase |
implements RuntimeTypesNeedBuilder { |
- final Map<ClassElement, Set<ClassElement>> rtiDependencies = |
- <ClassElement, Set<ClassElement>>{}; |
+ final ElementEnvironment _elementEnvironment; |
- final Set<ClassElement> classesUsingTypeVariableExpression = |
- new Set<ClassElement>(); |
+ final Map<ClassEntity, Set<ClassEntity>> rtiDependencies = |
+ <ClassEntity, Set<ClassEntity>>{}; |
+ |
+ final Set<ClassEntity> classesUsingTypeVariableExpression = |
+ new Set<ClassEntity>(); |
+ |
+ RuntimeTypesNeedBuilderImpl(this._elementEnvironment, DartTypes types) |
+ : super(types); |
+ |
+ bool checkClass(ClassEntity cls) => true; |
@override |
- void registerClassUsingTypeVariableExpression(ClassElement cls) { |
+ void registerClassUsingTypeVariableExpression(ClassEntity cls) { |
classesUsingTypeVariableExpression.add(cls); |
} |
@override |
- void registerRtiDependency(ClassElement element, ClassElement dependency) { |
+ void registerRtiDependency(ClassEntity element, ClassEntity dependency) { |
// We're not dealing with typedef for now. |
assert(element != null); |
- Set<ClassElement> classes = |
- rtiDependencies.putIfAbsent(element, () => new Set<ClassElement>()); |
+ Set<ClassEntity> classes = |
+ rtiDependencies.putIfAbsent(element, () => new Set<ClassEntity>()); |
classes.add(dependency); |
} |
@@ -266,43 +308,43 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase |
CommonElements commonElements, |
BackendUsage backendUsage, |
{bool enableTypeAssertions}) { |
- Set<ClassElement> classesNeedingRti = new Set<ClassElement>(); |
- Set<MethodElement> methodsNeedingRti = new Set<MethodElement>(); |
- Set<LocalFunctionElement> localFunctionsNeedingRti = |
- new Set<LocalFunctionElement>(); |
+ Set<ClassEntity> classesNeedingRti = new Set<ClassEntity>(); |
+ Set<FunctionEntity> methodsNeedingRti = new Set<FunctionEntity>(); |
+ Set<Local> localFunctionsNeedingRti = new Set<Local>(); |
// Find the classes that need runtime type information. Such |
// classes are: |
// (1) used in a is check with type variables, |
// (2) dependencies of classes in (1), |
// (3) subclasses of (2) and (3). |
- void potentiallyAddForRti(ClassElement cls) { |
- assert(invariant(cls, cls.isDeclaration)); |
- if (cls.typeVariables.isEmpty) return; |
+ void potentiallyAddForRti(ClassEntity cls) { |
+ assert(checkClass(cls)); |
+ if (!_elementEnvironment.isGenericClass(cls)) return; |
if (classesNeedingRti.contains(cls)) return; |
classesNeedingRti.add(cls); |
// TODO(ngeoffray): This should use subclasses, not subtypes. |
- closedWorld.forEachStrictSubtypeOf(cls, (ClassElement sub) { |
+ closedWorld.forEachStrictSubtypeOf(cls, (ClassEntity sub) { |
potentiallyAddForRti(sub); |
}); |
- Set<ClassElement> dependencies = rtiDependencies[cls]; |
+ Set<ClassEntity> dependencies = rtiDependencies[cls]; |
if (dependencies != null) { |
- dependencies.forEach((ClassElement other) { |
+ dependencies.forEach((ClassEntity other) { |
potentiallyAddForRti(other); |
}); |
} |
} |
- Set<ClassElement> classesUsingTypeVariableTests = new Set<ClassElement>(); |
- resolutionWorldBuilder.isChecks.forEach((ResolutionDartType type) { |
+ Set<ClassEntity> classesUsingTypeVariableTests = new Set<ClassEntity>(); |
+ resolutionWorldBuilder.isChecks.forEach((DartType type) { |
if (type.isTypeVariable) { |
- TypeVariableElement variable = type.element; |
+ TypeVariableType typeVariableType = type; |
+ TypeVariableEntity variable = typeVariableType.element; |
// GENERIC_METHODS: When generic method support is complete enough to |
// include a runtime value for method type variables, this may need to |
// be updated: It simply ignores method type arguments. |
- if (variable.typeDeclaration is ClassElement) { |
+ if (variable.typeDeclaration is ClassEntity) { |
classesUsingTypeVariableTests.add(variable.typeDeclaration); |
} |
} |
@@ -317,21 +359,33 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase |
// JSArray needs type arguments. |
// TODO(karlklose): make this dependency visible from code. |
if (commonElements.jsArrayClass != null) { |
- ClassElement listClass = commonElements.listClass; |
+ ClassEntity listClass = commonElements.listClass; |
registerRtiDependency(commonElements.jsArrayClass, listClass); |
} |
// Check local functions and closurized members. |
- void checkClosures(bool analyzeFunction(FunctionElement function)) { |
- for (LocalFunctionElement function |
+ void checkClosures({DartType potentialSubtypeOf}) { |
+ bool checkFunctionType(FunctionType functionType) { |
+ ClassEntity contextClass = Types.getClassContext(functionType); |
+ if (contextClass != null && |
+ (potentialSubtypeOf == null || |
+ types.isPotentialSubtype(functionType, potentialSubtypeOf))) { |
+ potentiallyAddForRti(contextClass); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ for (Local function |
in resolutionWorldBuilder.localFunctionsWithFreeTypeVariables) { |
- if (analyzeFunction(function)) { |
+ if (checkFunctionType( |
+ _elementEnvironment.getLocalFunctionType(function))) { |
localFunctionsNeedingRti.add(function); |
} |
} |
- for (MethodElement function |
+ for (FunctionEntity function |
in resolutionWorldBuilder.closurizedMembersWithFreeTypeVariables) { |
- if (analyzeFunction(function)) { |
+ if (checkFunctionType(_elementEnvironment.getFunctionType(function))) { |
methodsNeedingRti.add(function); |
} |
} |
@@ -339,14 +393,14 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase |
// Compute the set of all classes and methods that need runtime type |
// information. |
- resolutionWorldBuilder.isChecks.forEach((ResolutionDartType type) { |
+ resolutionWorldBuilder.isChecks.forEach((DartType type) { |
if (type.isInterfaceType) { |
ResolutionInterfaceType itf = type; |
if (!itf.treatAsRaw) { |
potentiallyAddForRti(itf.element); |
} |
} else { |
- ClassElement contextClass = Types.getClassContext(type); |
+ ClassEntity contextClass = Types.getClassContext(type); |
if (contextClass != null) { |
// [type] contains type variables (declared in [contextClass]) if |
// [contextClass] is non-null. This handles checks against type |
@@ -354,40 +408,61 @@ class RuntimeTypesNeedBuilderImpl extends _RuntimeTypesBase |
potentiallyAddForRti(contextClass); |
} |
if (type.isFunctionType) { |
- bool analyzeMethod(FunctionElement method) { |
- ResolutionDartType memberType = method.type; |
- ClassElement contextClass = Types.getClassContext(memberType); |
- if (contextClass != null && |
- types.isPotentialSubtype(memberType, type)) { |
- potentiallyAddForRti(contextClass); |
- return true; |
- } |
- return false; |
- } |
- |
- checkClosures(analyzeMethod); |
+ checkClosures(potentialSubtypeOf: type); |
} |
} |
}); |
if (enableTypeAssertions) { |
- bool analyzeMethod(FunctionElement method) { |
- ResolutionDartType memberType = method.type; |
- ClassElement contextClass = Types.getClassContext(memberType); |
- if (contextClass != null) { |
- potentiallyAddForRti(contextClass); |
- return true; |
- } |
- return false; |
- } |
- |
- checkClosures(analyzeMethod); |
+ checkClosures(); |
} |
// Add the classes that need RTI because they use a type variable as |
// expression. |
classesUsingTypeVariableExpression.forEach(potentiallyAddForRti); |
+ return _createRuntimeTypesNeed( |
+ _elementEnvironment, |
+ backendUsage, |
+ classesNeedingRti, |
+ methodsNeedingRti, |
+ localFunctionsNeedingRti, |
+ classesUsingTypeVariableExpression); |
+ } |
+ |
+ RuntimeTypesNeed _createRuntimeTypesNeed( |
+ ElementEnvironment elementEnvironment, |
+ BackendUsage backendUsage, |
+ Set<ClassEntity> classesNeedingRti, |
+ Set<FunctionEntity> methodsNeedingRti, |
+ Set<Local> localFunctionsNeedingRti, |
+ Set<ClassEntity> classesUsingTypeVariableExpression) { |
return new _RuntimeTypesNeed( |
+ _elementEnvironment, |
+ backendUsage, |
+ classesNeedingRti, |
+ methodsNeedingRti, |
+ localFunctionsNeedingRti, |
+ classesUsingTypeVariableExpression); |
+ } |
+} |
+ |
+class ResolutionRuntimeTypesNeedBuilderImpl |
+ extends RuntimeTypesNeedBuilderImpl { |
+ ResolutionRuntimeTypesNeedBuilderImpl( |
+ ElementEnvironment elementEnvironment, DartTypes types) |
+ : super(elementEnvironment, types); |
+ |
+ bool checkClass(ClassElement cls) => cls.isDeclaration; |
+ |
+ RuntimeTypesNeed _createRuntimeTypesNeed( |
+ ElementEnvironment elementEnvironment, |
+ BackendUsage backendUsage, |
+ Set<ClassEntity> classesNeedingRti, |
+ Set<FunctionEntity> methodsNeedingRti, |
+ Set<Local> localFunctionsNeedingRti, |
+ Set<ClassEntity> classesUsingTypeVariableExpression) { |
+ return new _ResolutionRuntimeTypesNeed( |
+ _elementEnvironment, |
backendUsage, |
classesNeedingRti, |
methodsNeedingRti, |
@@ -440,7 +515,8 @@ class _RuntimeTypes extends _RuntimeTypesBase |
_RuntimeTypes(Compiler compiler) |
: this.compiler = compiler, |
checkedTypeArguments = new Set<ResolutionDartType>(), |
- checkedBounds = new Set<ResolutionDartType>(); |
+ checkedBounds = new Set<ResolutionDartType>(), |
+ super(compiler.types); |
Set<ClassElement> directlyInstantiatedArguments; |
Set<ClassElement> allInstantiatedArguments; |