blob: e6e6a61dadd49ae4e60cbea0ce739aae4787984a [file] [log] [blame]
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of world_builder;
/// [ResolutionEnqueuerWorldBuilder] based on the [Element] model.
class ElementResolutionWorldBuilder extends ResolutionWorldBuilderBase {
/// Used for testing the new more precise computation of instantiated types
/// and classes.
static bool useInstantiationMap = false;
final JavaScriptBackend _backend;
final Resolution _resolution;
ElementResolutionWorldBuilder(
this._backend,
this._resolution,
NativeBasicData nativeBasicData,
NativeDataBuilder nativeDataBuilder,
InterceptorDataBuilder interceptorDataBuilder,
BackendUsageBuilder backendUsageBuilder,
SelectorConstraintsStrategy selectorConstraintsStrategy)
: super(
_backend.compiler.elementEnvironment,
_resolution.commonElements,
nativeBasicData,
nativeDataBuilder,
interceptorDataBuilder,
backendUsageBuilder,
selectorConstraintsStrategy);
bool isImplemented(ClassElement cls) {
return super.isImplemented(cls.declaration);
}
void registerTypeInstantiation(
InterfaceType type, ClassUsedCallback classUsed,
{ConstructorEntity constructor,
bool byMirrors: false,
bool isRedirection: false}) {
ClassElement cls = type.element;
cls.ensureResolved(_resolution);
super.registerTypeInstantiation(type, classUsed,
constructor: constructor,
byMirrors: byMirrors,
isRedirection: isRedirection);
}
/// Returns the instantiation map used for computing the closed world.
///
/// If [useInstantiationMap] is `true`, redirections are removed and
/// redirecting factories are converted to their effective target and type.
Map<ClassEntity, InstantiationInfo> getInstantiationMap() {
if (!useInstantiationMap) return _instantiationInfo;
Map<ClassEntity, InstantiationInfo> instantiationMap =
<ClassEntity, InstantiationInfo>{};
InstantiationInfo infoFor(ClassEntity cls) {
return instantiationMap.putIfAbsent(cls, () => new InstantiationInfo());
}
_instantiationInfo.forEach((cls, info) {
if (info.instantiationMap != null) {
info.instantiationMap
.forEach((ConstructorElement constructor, Set<Instance> set) {
for (Instance instance in set) {
if (instance.isRedirection) {
continue;
}
if (constructor == null || !constructor.isRedirectingFactory) {
infoFor(cls)
.addInstantiation(constructor, instance.type, instance.kind);
} else {
ConstructorElement target = constructor.effectiveTarget;
ResolutionInterfaceType targetType =
constructor.computeEffectiveTargetType(instance.type);
ClassElement cls = target.enclosingClass;
bool isNative = _nativeBasicData.isNativeClass(cls);
Instantiation kind;
if (isNative) {
kind = Instantiation.ABSTRACTLY_INSTANTIATED;
} else if (cls.isAbstract) {
kind = Instantiation.UNINSTANTIATED;
} else {
kind = Instantiation.DIRECTLY_INSTANTIATED;
}
infoFor(targetType.element)
.addInstantiation(target, targetType, kind);
}
}
});
}
});
return instantiationMap;
}
void registerIsCheck(ResolutionDartType type) {
type.computeUnaliased(_resolution);
type = type.unaliased;
// Even in checked mode, type annotations for return type and argument
// types do not imply type checks, so there should never be a check
// against the type variable of a typedef.
assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef);
super.registerIsCheck(type);
}
void registerStaticUse(StaticUse staticUse, MemberUsedCallback memberUsed) {
Element element = staticUse.element;
assert(invariant(element, element.isDeclaration,
message: "Element ${element} is not the declaration."));
super.registerStaticUse(staticUse, memberUsed);
}
_ClassUsage _createClassUsage(ClassElement cls) {
cls.ensureResolved(_resolution);
_resolution.ensureClassMembers(cls);
return super._createClassUsage(cls);
}
/// Called to add [cls] to the set of known classes.
///
/// This ensures that class hierarchy queries can be performed on [cls] and
/// classes that extend or implement it.
void registerClass(ClassElement cls) => _registerClass(cls.declaration);
void _registerClass(ClassEntity cls, {bool isDirectlyInstantiated: false}) {
_ensureClassSet(cls);
if (isDirectlyInstantiated) {
_updateClassHierarchyNodeForClass(cls, directlyInstantiated: true);
}
}
void _processInstantiatedClassMember(
ClassEntity cls, MemberElement member, MemberUsedCallback memberUsed) {
assert(invariant(member, member.isDeclaration));
member.computeType(_resolution);
super._processInstantiatedClassMember(cls, member, memberUsed);
}
@override
ClassEntity getAppliedMixin(ClassElement cls) {
if (cls.isMixinApplication) {
MixinApplicationElement mixinApplication = cls;
// Note: If [mixinApplication] is malformed [mixin] is `null`.
return mixinApplication.mixin;
}
return null;
}
@override
int getHierarchyDepth(ClassElement cls) => cls.hierarchyDepth;
@override
bool checkClass(ClassElement cls) => cls.isDeclaration;
@override
bool validateClass(ClassElement cls) => cls.isResolved;
@override
bool implementsFunction(ClassElement cls) =>
cls.implementsFunction(_commonElements);
@override
ClassEntity getSuperClass(ClassElement cls) => cls.superclass;
@override
Iterable<InterfaceType> getSupertypes(ClassElement cls) => cls.allSupertypes;
ClosedWorld closeWorld() {
Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses =
populateHierarchyNodes();
_closed = true;
return _closedWorldCache = new ClosedWorldImpl(
commonElements: _commonElements,
constantSystem: _backend.constantSystem,
nativeData: _nativeDataBuilder.close(),
interceptorData: _interceptorDataBuilder.close(),
backendUsage: _backendUsageBuilder.close(),
resolutionWorldBuilder: this,
functionSet: _allFunctions.close(),
allTypedefs: _allTypedefs,
mixinUses: _mixinUses,
typesImplementedBySubclasses: typesImplementedBySubclasses,
classHierarchyNodes: _classHierarchyNodes,
classSets: _classSets);
}
@override
void registerMixinUse(
MixinApplicationElement mixinApplication, ClassElement mixin) {
assert(mixin.isDeclaration);
super.registerMixinUse(mixinApplication, mixin);
}
}