Avoid eager enqueueing from resolution

BUG=
R=sigurdm@google.com

Review URL: https://codereview.chromium.org/1376863004.
This commit is contained in:
Johnni Winther 2015-10-06 13:53:15 +02:00
parent 76b7203c19
commit dda38dfe47
24 changed files with 919 additions and 215 deletions

View file

@ -227,7 +227,7 @@ abstract class Backend {
/// Call this method to enable support for isolates.
void enableIsolateSupport(Enqueuer enqueuer) {}
void registerRequiredType(DartType type, Element enclosingElement) {}
void registerRequiredType(DartType type) {}
void registerConstSymbol(String name, Registry registry) {}
void registerNewSymbol(Registry registry) {}
@ -401,4 +401,4 @@ abstract class ForeignResolver {
/// Resolves [typeName] to a type in the context of [node].
DartType resolveTypeFromString(Node node, String typeName);
}
}

View file

@ -191,7 +191,7 @@ class CodegenWorkItem extends WorkItem {
// generation could spuriously be adding dependencies on things we know we
// don't need.
assert(invariant(element,
compiler.enqueuer.resolution.hasBeenResolved(element),
compiler.enqueuer.resolution.hasBeenProcessed(element),
message: "$element has not been resolved."));
assert(invariant(element, element.resolvedAst.elements != null,
message: 'Resolution tree is null for $element in codegen work item'));

View file

@ -10,7 +10,8 @@ import '../compiler.dart' show
import '../core_types.dart' show
CoreTypes;
import '../dart_types.dart' show
DartType;
DartType,
InterfaceType;
import '../diagnostics/diagnostic_listener.dart' show
DiagnosticReporter;
import '../elements/elements.dart' show
@ -20,7 +21,9 @@ import '../elements/elements.dart' show
ErroneousElement,
FunctionElement,
FunctionSignature,
LocalFunctionElement,
MetadataAnnotation,
MethodElement,
TypedefElement,
TypeVariableElement;
import '../enqueue.dart' show
@ -30,6 +33,10 @@ import '../tree/tree.dart' show
AsyncForIn,
Send,
TypeAnnotation;
import '../universe/universe.dart' show
UniverseSelector;
import '../util/util.dart' show
Setlet;
import 'registry.dart' show
Registry;
import 'work.dart' show
@ -46,6 +53,7 @@ class ResolutionWorkItem extends WorkItem {
WorldImpact run(Compiler compiler, ResolutionEnqueuer world) {
WorldImpact impact = compiler.analyze(this, world);
impact = compiler.backend.resolutionCallbacks.transformImpact(impact);
_isAnalyzed = true;
return impact;
}
@ -53,8 +61,13 @@ class ResolutionWorkItem extends WorkItem {
bool get isAnalyzed => _isAnalyzed;
}
// TODO(johnniwinther): Rename this to something like `BackendResolutionApi`
// and clean up the interface.
/// Backend callbacks function specific to the resolution phase.
class ResolutionCallbacks {
///
WorldImpact transformImpact(ResolutionWorldImpact worldImpact) => worldImpact;
/// Register that an assert has been seen.
void onAssert(bool hasMessage, Registry registry) {}
@ -133,6 +146,256 @@ class ResolutionCallbacks {
void onIncDecOperation(Registry registry) {}
}
class ResolutionWorldImpact extends WorldImpact {
const ResolutionWorldImpact();
// TODO(johnniwinther): Remove this.
void registerDependency(Element element) {}
Iterable<Feature> get features => const <Feature>[];
Iterable<DartType> get requiredTypes => const <DartType>[];
Iterable<MapLiteralUse> get mapLiterals => const <MapLiteralUse>[];
Iterable<ListLiteralUse> get listLiterals => const <ListLiteralUse>[];
Iterable<DartType> get typeLiterals => const <DartType>[];
Iterable<String> get constSymbolNames => const <String>[];
}
/// A language feature seen during resolution.
// TODO(johnniwinther): Should mirror usage be part of this?
enum Feature {
/// Invocation of a generative construction on an abstract class.
ABSTRACT_CLASS_INSTANTIATION,
/// An assert statement with no message.
ASSERT,
/// An assert statement with a message.
ASSERT_WITH_MESSAGE,
/// A method with an `async` body modifier.
ASYNC,
/// An asynchronous for in statement like `await for (var e in i) {}`.
ASYNC_FOR_IN,
/// A method with an `async*` body modifier.
ASYNC_STAR,
/// A catch statement.
CATCH_STATEMENT,
/// A compile time error.
COMPILE_TIME_ERROR,
/// A fall through in a switch case.
FALL_THROUGH_ERROR,
/// A ++/-- operation.
INC_DEC_OPERATION,
/// A field whose initialization is not a constant.
LAZY_FIELD,
/// A call to `new Symbol`.
NEW_SYMBOL,
/// A catch clause with a variable for the stack trace.
STACK_TRACE_IN_CATCH,
/// String interpolation.
STRING_INTERPOLATION,
/// An implicit call to `super.noSuchMethod`, like calling an unresolved
/// super method.
SUPER_NO_SUCH_METHOD,
/// A redirection to the `Symbol` constructor.
SYMBOL_CONSTRUCTOR,
/// An synchronous for in statement, like `for (var e in i) {}`.
SYNC_FOR_IN,
/// A method with a `sync*` body modifier.
SYNC_STAR,
/// A throw expression.
THROW_EXPRESSION,
/// An implicit throw of a `NoSuchMethodError`, like calling an unresolved
/// static method.
THROW_NO_SUCH_METHOD,
/// An implicit throw of a runtime error, like
THROW_RUNTIME_ERROR,
/// The need for a type variable bound check, like instantiation of a generic
/// type whose type variable have non-trivial bounds.
TYPE_VARIABLE_BOUNDS_CHECK,
}
/// A use of a map literal seen during resolution.
class MapLiteralUse {
final InterfaceType type;
final bool isConstant;
final bool isEmpty;
MapLiteralUse(this.type, {this.isConstant: false, this.isEmpty: false});
int get hashCode {
return
type.hashCode * 13 +
isConstant.hashCode * 17 +
isEmpty.hashCode * 19;
}
bool operator ==(other) {
if (identical(this, other)) return true;
if (other is! MapLiteralUse) return false;
return
type == other.type &&
isConstant == other.isConstant &&
isEmpty == other.isEmpty;
}
}
/// A use of a list literal seen during resolution.
class ListLiteralUse {
final InterfaceType type;
final bool isConstant;
final bool isEmpty;
ListLiteralUse(this.type, {this.isConstant: false, this.isEmpty: false});
int get hashCode {
return
type.hashCode * 13 +
isConstant.hashCode * 17 +
isEmpty.hashCode * 19;
}
bool operator ==(other) {
if (identical(this, other)) return true;
if (other is! ListLiteralUse) return false;
return
type == other.type &&
isConstant == other.isConstant &&
isEmpty == other.isEmpty;
}
}
/// Mutable implementation of [WorldImpact] used to transform
/// [ResolutionWorldImpact] to [WorldImpact].
// TODO(johnniwinther): Remove [Registry] when dependency is tracked directly
// on [WorldImpact].
class TransformedWorldImpact implements WorldImpact, Registry {
final ResolutionWorldImpact worldImpact;
Setlet<Element> _staticUses;
Setlet<InterfaceType> _instantiatedTypes;
Setlet<UniverseSelector> _dynamicGetters;
Setlet<UniverseSelector> _dynamicInvocations;
Setlet<UniverseSelector> _dynamicSetters;
TransformedWorldImpact(this.worldImpact);
@override
Iterable<DartType> get asCasts => worldImpact.asCasts;
@override
Iterable<DartType> get checkedModeChecks => worldImpact.checkedModeChecks;
@override
Iterable<MethodElement> get closurizedFunctions {
return worldImpact.closurizedFunctions;
}
@override
Iterable<UniverseSelector> get dynamicGetters {
return _dynamicGetters != null
? _dynamicGetters : worldImpact.dynamicGetters;
}
@override
Iterable<UniverseSelector> get dynamicInvocations {
return _dynamicInvocations != null
? _dynamicInvocations : worldImpact.dynamicInvocations;
}
@override
Iterable<UniverseSelector> get dynamicSetters {
return _dynamicSetters != null
? _dynamicSetters : worldImpact.dynamicSetters;
}
@override
Iterable<DartType> get isChecks => worldImpact.isChecks;
@override
Iterable<Element> get staticUses {
if (_staticUses == null) {
return worldImpact.staticUses;
}
return _staticUses;
}
@override
bool get isForResolution => true;
_unsupported(String message) => throw new UnsupportedError(message);
@override
Iterable<Element> get otherDependencies => _unsupported('otherDependencies');
// TODO(johnniwinther): Remove this.
@override
void registerAssert(bool hasMessage) => _unsupported('registerAssert');
@override
void registerDependency(Element element) {
worldImpact.registerDependency(element);
}
@override
void registerDynamicGetter(UniverseSelector selector) {
if (_dynamicGetters == null) {
_dynamicGetters = new Setlet<UniverseSelector>();
_dynamicGetters.addAll(worldImpact.dynamicGetters);
}
_dynamicGetters.add(selector);
}
@override
void registerDynamicInvocation(UniverseSelector selector) {
if (_dynamicInvocations == null) {
_dynamicInvocations = new Setlet<UniverseSelector>();
_dynamicInvocations.addAll(worldImpact.dynamicInvocations);
}
_dynamicInvocations.add(selector);
}
@override
void registerDynamicSetter(UniverseSelector selector) {
if (_dynamicSetters == null) {
_dynamicSetters = new Setlet<UniverseSelector>();
_dynamicSetters.addAll(worldImpact.dynamicSetters);
}
_dynamicSetters.add(selector);
}
@override
void registerGetOfStaticFunction(FunctionElement element) {
_unsupported('registerGetOfStaticFunction($element)');
}
@override
void registerInstantiation(InterfaceType type) {
// TODO(johnniwinther): Remove this when dependency tracking is done on
// the world impact itself.
registerDependency(type.element);
if (_instantiatedTypes == null) {
_instantiatedTypes = new Setlet<InterfaceType>();
}
_instantiatedTypes.add(type);
}
@override
Iterable<InterfaceType> get instantiatedTypes {
return _instantiatedTypes != null
? _instantiatedTypes : const <InterfaceType>[];
}
@override
void registerStaticInvocation(Element element) {
if (_staticUses == null) {
_staticUses = new Setlet<Element>();
_staticUses.addAll(worldImpact.staticUses);
}
_staticUses.add(element);
}
@override
Iterable<LocalFunctionElement> get closures => worldImpact.closures;
}
// TODO(johnniwinther): Rename to `Resolver` or `ResolverContext`.
abstract class Resolution {
Parsing get parsing;
@ -145,6 +408,9 @@ abstract class Resolution {
void resolveMetadataAnnotation(MetadataAnnotation metadataAnnotation);
FunctionSignature resolveSignature(FunctionElement function);
DartType resolveTypeAnnotation(Element element, TypeAnnotation node);
bool hasBeenResolved(Element element);
ResolutionWorldImpact analyzeElement(Element element);
}
// TODO(johnniwinther): Rename to `Parser` or `ParsingContext`.

View file

@ -1265,10 +1265,9 @@ class ErroneousAstConstant extends AstConstant {
new ErroneousConstantExpression(), new NullConstantValue());
}
// TODO(johnniwinther): Avoid the need for this hack.
// TODO(johnniwinther): Clean this up.
TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) {
WorldImpact worldImpact = compiler.analyzeElement(element.declaration);
compiler.enqueuer.resolution.applyImpact(element.declaration, worldImpact);
compiler.resolution.analyzeElement(element.declaration);
return element.resolvedAst.elements;
}

View file

@ -26,7 +26,8 @@ import 'common/registry.dart' show
import 'common/resolution.dart' show
Parsing,
Resolution,
ResolutionWorkItem;
ResolutionWorkItem,
ResolutionWorldImpact;
import 'common/tasks.dart' show
CompilerTask,
GenericTask;
@ -769,7 +770,7 @@ abstract class Compiler {
bool isProxyConstant(ConstantValue value) {
FieldElement field = coreLibrary.find('proxy');
if (field == null) return false;
if (!enqueuer.resolution.hasBeenResolved(field)) return false;
if (!resolution.hasBeenResolved(field)) return false;
if (proxyConstant == null) {
proxyConstant =
constants.getConstantValue(
@ -1160,7 +1161,7 @@ abstract class Compiler {
});
}
if (!REPORT_EXCESS_RESOLUTION) return;
var resolved = new Set.from(enqueuer.resolution.resolvedElements);
var resolved = new Set.from(enqueuer.resolution.processedElements);
for (Element e in enqueuer.codegen.generatedCode.keys) {
resolved.remove(e);
}
@ -1187,7 +1188,7 @@ abstract class Compiler {
}
}
WorldImpact analyzeElement(Element element) {
ResolutionWorldImpact analyzeElement(Element element) {
assert(invariant(element,
element.impliesType ||
element.isField ||
@ -1199,23 +1200,11 @@ abstract class Compiler {
assert(invariant(element, element is AnalyzableElement,
message: 'Element $element is not analyzable.'));
assert(invariant(element, element.isDeclaration));
ResolutionEnqueuer world = enqueuer.resolution;
if (world.hasBeenResolved(element)) {
return const WorldImpact();
}
assert(parser != null);
Node tree = parser.parse(element);
assert(invariant(element, !element.isSynthesized || tree == null));
WorldImpact worldImpact = resolver.resolve(element);
if (tree != null && !analyzeSignaturesOnly && !suppressWarnings) {
// Only analyze nodes with a corresponding [TreeElements].
checker.check(element);
}
world.registerResolvedElement(element);
return worldImpact;
return resolution.analyzeElement(element);
}
WorldImpact analyze(ResolutionWorkItem work, ResolutionEnqueuer world) {
ResolutionWorldImpact analyze(ResolutionWorkItem work,
ResolutionEnqueuer world) {
assert(invariant(work.element, identical(world, enqueuer.resolution)));
assert(invariant(work.element, !work.isAnalyzed,
message: 'Element ${work.element} has already been analyzed'));
@ -1223,18 +1212,19 @@ abstract class Compiler {
// TODO(ahe): Add structured diagnostics to the compiler API and
// use it to separate this from the --verbose option.
if (phase == PHASE_RESOLVING) {
reporter.log(
'Resolved ${enqueuer.resolution.resolvedElements.length} '
reporter.log(
'Resolved ${enqueuer.resolution.processedElements.length} '
'elements.');
progress.reset();
}
}
AstElement element = work.element;
if (world.hasBeenResolved(element)) {
return const WorldImpact();
if (world.hasBeenProcessed(element)) {
return const ResolutionWorldImpact();
}
WorldImpact worldImpact = analyzeElement(element);
ResolutionWorldImpact worldImpact = analyzeElement(element);
backend.onElementResolved(element, element.resolvedAst.elements);
world.registerProcessedElement(element);
return worldImpact;
}
@ -1330,7 +1320,7 @@ abstract class Compiler {
void checkLive(member) {
if (member.isErroneous) return;
if (member.isFunction) {
if (!enqueuer.resolution.hasBeenResolved(member)) {
if (!enqueuer.resolution.hasBeenProcessed(member)) {
reporter.reportHintMessage(
member, MessageKind.UNUSED_METHOD, {'name': member.name});
}
@ -1490,28 +1480,47 @@ class _CompilerCoreTypes implements CoreTypes {
_CompilerCoreTypes(this.resolution);
@override
InterfaceType get objectType => objectClass.computeType(resolution);
InterfaceType get objectType {
objectClass.ensureResolved(resolution);
return objectClass.rawType;
}
@override
InterfaceType get boolType => boolClass.computeType(resolution);
InterfaceType get boolType {
boolClass.ensureResolved(resolution);
return boolClass.rawType;
}
@override
InterfaceType get doubleType => doubleClass.computeType(resolution);
InterfaceType get doubleType {
doubleClass.ensureResolved(resolution);
return doubleClass.rawType;
}
@override
InterfaceType get functionType => functionClass.computeType(resolution);
InterfaceType get functionType {
functionClass.ensureResolved(resolution);
return functionClass.rawType;
}
@override
InterfaceType get intType => intClass.computeType(resolution);
InterfaceType get intType {
intClass.ensureResolved(resolution);
return intClass.rawType;
}
@override
InterfaceType get resourceType => resourceClass.computeType(resolution);
InterfaceType get resourceType {
resourceClass.ensureResolved(resolution);
return resourceClass.rawType;
}
@override
InterfaceType listType([DartType elementType]) {
InterfaceType type = listClass.computeType(resolution);
listClass.ensureResolved(resolution);
InterfaceType type = listClass.rawType;
if (elementType == null) {
return listClass.rawType;
return type;
}
return type.createInstantiation([elementType]);
}
@ -1519,9 +1528,10 @@ class _CompilerCoreTypes implements CoreTypes {
@override
InterfaceType mapType([DartType keyType,
DartType valueType]) {
InterfaceType type = mapClass.computeType(resolution);
mapClass.ensureResolved(resolution);
InterfaceType type = mapClass.rawType;
if (keyType == null && valueType == null) {
return mapClass.rawType;
return type;
} else if (keyType == null) {
keyType = const DynamicType();
} else if (valueType == null) {
@ -1531,43 +1541,61 @@ class _CompilerCoreTypes implements CoreTypes {
}
@override
InterfaceType get nullType => nullClass.computeType(resolution);
InterfaceType get nullType {
nullClass.ensureResolved(resolution);
return nullClass.rawType;
}
@override
InterfaceType get numType => numClass.computeType(resolution);
InterfaceType get numType {
numClass.ensureResolved(resolution);
return numClass.rawType;
}
@override
InterfaceType get stringType => stringClass.computeType(resolution);
InterfaceType get stringType {
stringClass.ensureResolved(resolution);
return stringClass.rawType;
}
@override
InterfaceType get symbolType => symbolClass.computeType(resolution);
InterfaceType get symbolType {
symbolClass.ensureResolved(resolution);
return symbolClass.rawType;
}
@override
InterfaceType get typeType => typeClass.computeType(resolution);
InterfaceType get typeType {
typeClass.ensureResolved(resolution);
return typeClass.rawType;
}
@override
InterfaceType iterableType([DartType elementType]) {
InterfaceType type = iterableClass.computeType(resolution);
iterableClass.ensureResolved(resolution);
InterfaceType type = iterableClass.rawType;
if (elementType == null) {
return iterableClass.rawType;
return type;
}
return type.createInstantiation([elementType]);
}
@override
InterfaceType futureType([DartType elementType]) {
InterfaceType type = futureClass.computeType(resolution);
futureClass.ensureResolved(resolution);
InterfaceType type = futureClass.rawType;
if (elementType == null) {
return futureClass.rawType;
return type;
}
return type.createInstantiation([elementType]);
}
@override
InterfaceType streamType([DartType elementType]) {
InterfaceType type = streamClass.computeType(resolution);
streamClass.ensureResolved(resolution);
InterfaceType type = streamClass.rawType;
if (elementType == null) {
return streamClass.rawType;
return type;
}
return type.createInstantiation([elementType]);
}
@ -1920,6 +1948,8 @@ class _CompilerDiagnosticReporter extends DiagnosticReporter {
// TODO(johnniwinther): Move [ResolverTask] here.
class _CompilerResolution implements Resolution {
final Compiler compiler;
final Map<Element, ResolutionWorldImpact> _worldImpactCache =
<Element, ResolutionWorldImpact>{};
_CompilerResolution(this.compiler);
@ -1961,6 +1991,27 @@ class _CompilerResolution implements Resolution {
DartType resolveTypeAnnotation(Element element, TypeAnnotation node) {
return compiler.resolver.resolveTypeAnnotation(element, node);
}
ResolutionWorldImpact analyzeElement(Element element) {
return _worldImpactCache.putIfAbsent(element, () {
assert(compiler.parser != null);
Node tree = compiler.parser.parse(element);
assert(invariant(element, !element.isSynthesized || tree == null));
ResolutionWorldImpact worldImpact = compiler.resolver.resolve(element);
if (tree != null &&
!compiler.analyzeSignaturesOnly &&
!compiler.suppressWarnings) {
// Only analyze nodes with a corresponding [TreeElements].
compiler.checker.check(element);
}
return worldImpact;
});
}
@override
bool hasBeenResolved(Element element) {
return _worldImpactCache.containsKey(element);
}
}
// TODO(johnniwinther): Move [ParserTask], [PatchParserTask], [DietParserTask]

View file

@ -183,7 +183,7 @@ class DartBackend extends Backend {
int totalSize = outputter.assembleProgram(
libraries: compiler.libraryLoader.libraries,
instantiatedClasses: compiler.resolverWorld.directlyInstantiatedClasses,
resolvedElements: compiler.enqueuer.resolution.resolvedElements,
resolvedElements: compiler.enqueuer.resolution.processedElements,
usedTypeLiterals: usedTypeLiterals,
postProcessElementAst: postProcessElementAst,
computeElementAst: computeElementAst,
@ -346,6 +346,24 @@ class DartResolutionCallbacks extends ResolutionCallbacks {
DartResolutionCallbacks(this.backend);
@override
WorldImpact transformImpact(ResolutionWorldImpact worldImpact) {
TransformedWorldImpact transformed =
new TransformedWorldImpact(worldImpact);
for (DartType typeLiteral in worldImpact.typeLiterals) {
onTypeLiteral(typeLiteral, transformed);
}
for (InterfaceType instantiatedType in worldImpact.instantiatedTypes) {
// TODO(johnniwinther): Remove this when dependency tracking is done on
// the world impact itself.
transformed.registerInstantiation(instantiatedType);
backend.registerInstantiatedType(
instantiatedType, backend.compiler.enqueuer.resolution, transformed);
}
return transformed;
}
@override
void onTypeLiteral(DartType type, Registry registry) {
if (type.isInterfaceType) {
backend.usedTypeLiterals.add(type.element);

View file

@ -20,7 +20,9 @@ import '../common/registry.dart' show
Registry;
import '../common/resolution.dart' show
Resolution,
ResolutionCallbacks;
ResolutionCallbacks,
ResolutionWorldImpact,
TransformedWorldImpact;
import '../common/tasks.dart' show
CompilerTask;
import '../compiler.dart' show

View file

@ -304,7 +304,7 @@ class DeferredLoadTask extends CompilerTask {
// TODO(sigurdm): We want to be more specific about this - need a better
// way to query "liveness".
if (astElement is! TypedefElement &&
!compiler.enqueuer.resolution.hasBeenResolved(astElement)) {
!compiler.enqueuer.resolution.hasBeenProcessed(astElement)) {
return;
}
@ -356,7 +356,7 @@ class DeferredLoadTask extends CompilerTask {
// to. Static members are not relevant, unless we are processing
// extra dependencies due to mirrors.
void addLiveInstanceMember(Element element) {
if (!compiler.enqueuer.resolution.hasBeenResolved(element)) return;
if (!compiler.enqueuer.resolution.hasBeenProcessed(element)) return;
if (!isMirrorUsage && !element.isInstanceMember) return;
collectDependencies(element.implementation);
}

View file

@ -2595,7 +2595,8 @@ abstract class BaseClassElementX extends ElementX
* The returned element may not be resolved yet.
*/
ClassElement get superclass {
assert(supertypeLoadState == STATE_DONE);
assert(invariant(this, supertypeLoadState == STATE_DONE,
message: "Superclass has not been computed for $this."));
return supertype == null ? null : supertype.element;
}

View file

@ -112,9 +112,15 @@ class WorldImpact {
// TODO(johnniwinther): Collect checked types for checked mode separately to
// support serialization.
Iterable<DartType> get checkedTypes => const <DartType>[];
Iterable<DartType> get isChecks => const <DartType>[];
Iterable<DartType> get checkedModeChecks => const <DartType>[];
Iterable<DartType> get asCasts => const <DartType>[];
Iterable<MethodElement> get closurizedFunctions => const <MethodElement>[];
Iterable<LocalFunctionElement> get closures => const <LocalFunctionElement>[];
}
abstract class Enqueuer {
@ -161,6 +167,10 @@ abstract class Enqueuer {
/// Returns [:true:] if [member] has been processed by this enqueuer.
bool isProcessed(Element member);
bool isClassProcessed(ClassElement cls) => _processedClasses.contains(cls);
Iterable<ClassElement> get processedClasses => _processedClasses;
/**
* Documentation wanted -- johnniwinther
*
@ -190,10 +200,14 @@ abstract class Enqueuer {
worldImpact.dynamicGetters.forEach(registerDynamicGetter);
worldImpact.dynamicSetters.forEach(registerDynamicSetter);
worldImpact.staticUses.forEach(registerStaticUse);
// TODO(johnniwinther): Register [worldImpact.instantiatedTypes] when it
// doesn't require a [Registry].
worldImpact.checkedTypes.forEach(registerIsCheck);
worldImpact.instantiatedTypes.forEach(registerInstantiatedType);
worldImpact.isChecks.forEach(registerIsCheck);
worldImpact.asCasts.forEach(registerIsCheck);
if (compiler.enableTypeAssertions) {
worldImpact.checkedModeChecks.forEach(registerIsCheck);
}
worldImpact.closurizedFunctions.forEach(registerGetOfStaticFunction);
worldImpact.closures.forEach(registerClosure);
}
// TODO(johnniwinther): Remove the need for passing the [registry].
@ -334,6 +348,15 @@ abstract class Enqueuer {
void processClass(ClassElement superclass) {
if (_processedClasses.contains(superclass)) return;
// TODO(johnniwinther): Re-insert this invariant when unittests don't
// fail. There is already a similar invariant on the members.
/*if (!isResolutionQueue) {
assert(invariant(superclass,
superclass.isClosure ||
compiler.enqueuer.resolution.isClassProcessed(superclass),
message: "Class $superclass has not been "
"processed in resolution."));
}*/
_processedClasses.add(superclass);
recentClasses.add(superclass);
@ -767,7 +790,7 @@ class ResolutionEnqueuer extends Enqueuer {
*
* Invariant: Key elements are declaration elements.
*/
final Set<AstElement> resolvedElements;
final Set<AstElement> processedElements;
final Queue<ResolutionWorkItem> queue;
@ -784,22 +807,22 @@ class ResolutionEnqueuer extends Enqueuer {
compiler,
itemCompilationContextCreator,
strategy),
resolvedElements = new Set<AstElement>(),
processedElements = new Set<AstElement>(),
queue = new Queue<ResolutionWorkItem>(),
deferredTaskQueue = new Queue<DeferredTask>();
bool get isResolutionQueue => true;
bool isProcessed(Element member) => resolvedElements.contains(member);
bool isProcessed(Element member) => processedElements.contains(member);
/// Returns `true` if [element] has been processed by the resolution enqueuer.
bool hasBeenResolved(Element element) {
return resolvedElements.contains(element.analyzableElement.declaration);
bool hasBeenProcessed(Element element) {
return processedElements.contains(element.analyzableElement.declaration);
}
/// Registers [element] as resolved for the resolution enqueuer.
void registerResolvedElement(AstElement element) {
resolvedElements.add(element);
/// Registers [element] as processed by the resolution enqueuer.
void registerProcessedElement(AstElement element) {
processedElements.add(element);
}
/**
@ -820,7 +843,7 @@ class ResolutionEnqueuer extends Enqueuer {
assert(invariant(element, element is AnalyzableElement,
message: 'Element $element is not analyzable.'));
if (hasBeenResolved(element)) return false;
if (hasBeenProcessed(element)) return false;
if (queueIsClosed) {
throw new SpannableAssertionFailure(element,
"Resolution work list is closed. Trying to add $element.");
@ -912,12 +935,12 @@ class ResolutionEnqueuer extends Enqueuer {
}
void _logSpecificSummary(log(message)) {
log('Resolved ${resolvedElements.length} elements.');
log('Resolved ${processedElements.length} elements.');
}
void forgetElement(Element element) {
super.forgetElement(element);
resolvedElements.remove(element);
processedElements.remove(element);
}
}

View file

@ -671,6 +671,7 @@ class TypeGraphInferrerEngine
compiler.progress.reset();
}
sortResolvedElements().forEach((Element element) {
assert(compiler.enqueuer.resolution.hasBeenProcessed(element));
if (compiler.shouldPrintProgress) {
reporter.log('Added $addedInGraph elements in inferencing graph.');
compiler.progress.reset();
@ -1220,10 +1221,10 @@ class TypeGraphInferrerEngine
Iterable<Element> sortResolvedElements() {
int max = 0;
Map<int, Setlet<Element>> methodSizes = new Map<int, Setlet<Element>>();
compiler.enqueuer.resolution.resolvedElements.forEach((AstElement element) {
compiler.enqueuer.resolution.processedElements.forEach((AstElement element) {
// TODO(ngeoffray): Not sure why the resolver would put a null
// mapping.
if (!compiler.enqueuer.resolution.hasBeenResolved(element)) return;
if (!compiler.enqueuer.resolution.hasBeenProcessed(element)) return;
TreeElementMapping mapping = element.resolvedAst.elements;
element = element.implementation;
if (element.impliesType) return;

View file

@ -1420,7 +1420,7 @@ class JavaScriptBackend extends Backend {
}
}
void registerRequiredType(DartType type, Element enclosingElement) {
void registerRequiredType(DartType type) {
// If [argument] has type variables or is a type variable, this method
// registers a RTI dependency between the class where the type variable is
// defined (that is the enclosing class of the current element being
@ -1428,7 +1428,6 @@ class JavaScriptBackend extends Backend {
// then the class of the type variable does too.
ClassElement contextClass = Types.getClassContext(type);
if (contextClass != null) {
assert(contextClass == enclosingElement.enclosingClass.declaration);
rti.registerRtiDependency(type.element, contextClass);
}
}
@ -2427,13 +2426,13 @@ class JavaScriptBackend extends Backend {
reflectableMembers.add(cls);
// 2) its constructors (if resolved)
cls.constructors.forEach((Element constructor) {
if (resolution.hasBeenResolved(constructor)) {
if (resolution.hasBeenProcessed(constructor)) {
reflectableMembers.add(constructor);
}
});
// 3) all members, including fields via getter/setters (if resolved)
cls.forEachClassMember((Member member) {
if (resolution.hasBeenResolved(member.element)) {
if (resolution.hasBeenProcessed(member.element)) {
memberNames.add(member.name);
reflectableMembers.add(member.element);
}
@ -2445,8 +2444,8 @@ class JavaScriptBackend extends Backend {
if (memberNames.contains(member.name)) {
// TODO(20993): find out why this assertion fails.
// assert(invariant(member.element,
// resolution.hasBeenResolved(member.element)));
if (resolution.hasBeenResolved(member.element)) {
// resolution.hasBeenProcessed(member.element)));
if (resolution.hasBeenProcessed(member.element)) {
reflectableMembers.add(member.element);
}
}
@ -2462,13 +2461,13 @@ class JavaScriptBackend extends Backend {
} else {
// check members themselves
cls.constructors.forEach((ConstructorElement element) {
if (!resolution.hasBeenResolved(element)) return;
if (!resolution.hasBeenProcessed(element)) return;
if (referencedFromMirrorSystem(element, false)) {
reflectableMembers.add(element);
}
});
cls.forEachClassMember((Member member) {
if (!resolution.hasBeenResolved(member.element)) return;
if (!resolution.hasBeenProcessed(member.element)) return;
if (referencedFromMirrorSystem(member.element, false)) {
reflectableMembers.add(member.element);
}
@ -2493,7 +2492,7 @@ class JavaScriptBackend extends Backend {
if (lib.isInternalLibrary) continue;
lib.forEachLocalMember((Element member) {
if (!member.isClass &&
resolution.hasBeenResolved(member) &&
resolution.hasBeenProcessed(member) &&
referencedFromMirrorSystem(member)) {
reflectableMembers.add(member);
}
@ -2652,7 +2651,15 @@ class JavaScriptBackend extends Backend {
reporter.log('Retaining metadata.');
compiler.libraryLoader.libraries.forEach(retainMetadataOf);
if (!enqueuer.isResolutionQueue) {
if (enqueuer.isResolutionQueue) {
for (Dependency dependency in metadataConstants) {
registerCompileTimeConstant(
dependency.constant,
new EagerRegistry(compiler,
dependency.annotatedElement.analyzableElement.treeElements),
addForEmission: false);
}
} else {
for (Dependency dependency in metadataConstants) {
registerCompileTimeConstant(
dependency.constant,
@ -2799,33 +2806,48 @@ class JavaScriptBackend extends Backend {
Enqueuer enqueuer,
Registry registry) {
if (element.asyncMarker == AsyncMarker.ASYNC) {
enqueue(enqueuer, getAsyncHelper(), registry);
enqueue(enqueuer, getSyncCompleterConstructor(), registry);
enqueue(enqueuer, getStreamIteratorConstructor(), registry);
enqueue(enqueuer, getWrapBody(), registry);
_registerAsync(enqueuer, registry);
} else if (element.asyncMarker == AsyncMarker.SYNC_STAR) {
ClassElement clsSyncStarIterable = getSyncStarIterable();
clsSyncStarIterable.ensureResolved(resolution);
registerInstantiatedType(clsSyncStarIterable.rawType, enqueuer, registry);
enqueue(enqueuer, getSyncStarIterableConstructor(), registry);
enqueue(enqueuer, getEndOfIteration(), registry);
enqueue(enqueuer, getYieldStar(), registry);
enqueue(enqueuer, getSyncStarUncaughtError(), registry);
_registerSyncStar(enqueuer, registry);
} else if (element.asyncMarker == AsyncMarker.ASYNC_STAR) {
ClassElement clsASyncStarController = getASyncStarController();
clsASyncStarController.ensureResolved(resolution);
registerInstantiatedType(
clsASyncStarController.rawType, enqueuer, registry);
enqueue(enqueuer, getAsyncStarHelper(), registry);
enqueue(enqueuer, getStreamOfController(), registry);
enqueue(enqueuer, getYieldSingle(), registry);
enqueue(enqueuer, getYieldStar(), registry);
enqueue(enqueuer, getASyncStarControllerConstructor(), registry);
enqueue(enqueuer, getStreamIteratorConstructor(), registry);
enqueue(enqueuer, getWrapBody(), registry);
_registerAsyncStar(enqueuer, registry);
}
}
void _registerAsync(Enqueuer enqueuer,
Registry registry) {
enqueue(enqueuer, getAsyncHelper(), registry);
enqueue(enqueuer, getSyncCompleterConstructor(), registry);
enqueue(enqueuer, getStreamIteratorConstructor(), registry);
enqueue(enqueuer, getWrapBody(), registry);
}
void _registerSyncStar(Enqueuer enqueuer,
Registry registry) {
ClassElement clsSyncStarIterable = getSyncStarIterable();
clsSyncStarIterable.ensureResolved(compiler.resolution);
registerInstantiatedType(clsSyncStarIterable.rawType, enqueuer, registry);
enqueue(enqueuer, getSyncStarIterableConstructor(), registry);
enqueue(enqueuer, getEndOfIteration(), registry);
enqueue(enqueuer, getYieldStar(), registry);
enqueue(enqueuer, getSyncStarUncaughtError(), registry);
}
void _registerAsyncStar(Enqueuer enqueuer,
Registry registry) {
ClassElement clsASyncStarController = getASyncStarController();
clsASyncStarController.ensureResolved(compiler.resolution);
registerInstantiatedType(
clsASyncStarController.rawType, enqueuer, registry);
enqueue(enqueuer, getAsyncStarHelper(), registry);
enqueue(enqueuer, getStreamOfController(), registry);
enqueue(enqueuer, getYieldSingle(), registry);
enqueue(enqueuer, getYieldStar(), registry);
enqueue(enqueuer, getASyncStarControllerConstructor(), registry);
enqueue(enqueuer, getStreamIteratorConstructor(), registry);
enqueue(enqueuer, getWrapBody(), registry);
}
@override
bool enableDeferredLoadingIfSupported(Spannable node, Registry registry) {
registerCheckDeferredIsLoaded(registry);
@ -2984,6 +3006,132 @@ class JavaScriptResolutionCallbacks extends ResolutionCallbacks {
JavaScriptResolutionCallbacks(this.backend);
WorldImpact transformImpact(ResolutionWorldImpact worldImpact) {
TransformedWorldImpact transformed =
new TransformedWorldImpact(worldImpact);
for (Feature feature in worldImpact.features) {
switch (feature) {
case Feature.ABSTRACT_CLASS_INSTANTIATION:
onAbstractClassInstantiation(transformed);
break;
case Feature.ASSERT:
onAssert(false, transformed);
break;
case Feature.ASSERT_WITH_MESSAGE:
onAssert(true, transformed);
break;
case Feature.ASYNC:
backend._registerAsync(
backend.compiler.enqueuer.resolution, transformed);
break;
case Feature.ASYNC_FOR_IN:
onAsyncForIn(null, transformed);
break;
case Feature.ASYNC_STAR:
backend._registerAsyncStar(
backend.compiler.enqueuer.resolution, transformed);
break;
case Feature.CATCH_STATEMENT:
onCatchStatement(transformed);
break;
case Feature.COMPILE_TIME_ERROR:
onCompileTimeError(transformed, null);
break;
case Feature.FALL_THROUGH_ERROR:
onFallThroughError(transformed);
break;
case Feature.INC_DEC_OPERATION:
onIncDecOperation(transformed);
break;
case Feature.LAZY_FIELD:
onLazyField(transformed);
break;
case Feature.NEW_SYMBOL:
backend.registerNewSymbol(transformed);
break;
case Feature.STACK_TRACE_IN_CATCH:
onStackTraceInCatch(transformed);
break;
case Feature.STRING_INTERPOLATION:
onStringInterpolation(transformed);
break;
case Feature.SUPER_NO_SUCH_METHOD:
onSuperNoSuchMethod(transformed);
break;
case Feature.SYMBOL_CONSTRUCTOR:
onSymbolConstructor(transformed);
break;
case Feature.SYNC_FOR_IN:
onSyncForIn(transformed);
break;
case Feature.SYNC_STAR:
backend._registerSyncStar(
backend.compiler.enqueuer.resolution, transformed);
break;
case Feature.THROW_EXPRESSION:
onThrowExpression(transformed);
break;
case Feature.THROW_NO_SUCH_METHOD:
onThrowNoSuchMethod(transformed);
break;
case Feature.THROW_RUNTIME_ERROR:
onThrowRuntimeError(transformed);
break;
case Feature.TYPE_VARIABLE_BOUNDS_CHECK:
onTypeVariableBoundCheck(transformed);
break;
}
}
for (DartType type in worldImpact.isChecks) {
onIsCheck(type, transformed);
}
for (DartType type in worldImpact.asCasts) {
onIsCheck(type, transformed);
onAsCheck(type, transformed);
}
if (backend.compiler.enableTypeAssertions) {
for (DartType type in worldImpact.checkedModeChecks) {
onIsCheck(type, transformed);
}
}
for (DartType requiredType in worldImpact.requiredTypes) {
backend.registerRequiredType(requiredType);
}
for (MapLiteralUse mapLiteralUse in worldImpact.mapLiterals) {
// TODO(johnniwinther): Use the [isEmpty] property when factory
// constructors are registered directly.
onMapLiteral(transformed, mapLiteralUse.type, mapLiteralUse.isConstant);
}
for (ListLiteralUse listLiteralUse in worldImpact.listLiterals) {
// TODO(johnniwinther): Use the [isConstant] and [isEmpty] property when
// factory constructors are registered directly.
transformed.registerInstantiation(listLiteralUse.type);
}
for (DartType typeLiteral in worldImpact.typeLiterals) {
onTypeLiteral(typeLiteral, transformed);
transformed.registerInstantiation(backend.compiler.coreTypes.typeType);
if (typeLiteral.isTypeVariable) {
onTypeVariableExpression(transformed, typeLiteral.element);
}
}
for (String constSymbolName in worldImpact.constSymbolNames) {
backend.registerConstSymbol(constSymbolName, transformed);
}
for (LocalFunctionElement closure in worldImpact.closures) {
if (closure.computeType(backend.resolution).containsTypeVariables) {
backend.registerClosureWithFreeTypeVariables(
closure, backend.compiler.enqueuer.resolution, transformed);
}
}
// TODO(johnniwinther): Remove this when dependency tracking is done on
// the world impact itself.
for (InterfaceType instantiatedType in worldImpact.instantiatedTypes) {
transformed.registerInstantiation(instantiatedType);
}
return transformed;
}
void registerBackendStaticInvocation(Element element, Registry registry) {
registry.registerStaticInvocation(backend.registerBackendUse(element));
}
@ -3189,7 +3337,7 @@ class JavaScriptResolutionCallbacks extends ResolutionCallbacks {
'Needed to encode the name of super.noSuchMethod.');
}
void onMapLiteral(ResolutionRegistry registry,
void onMapLiteral(Registry registry,
DartType type,
bool isConstant) {
assert(registry.isForResolution);
@ -3204,7 +3352,7 @@ class JavaScriptResolutionCallbacks extends ResolutionCallbacks {
enqueue(JavaScriptMapConstant.DART_STRING_CLASS);
enqueue(JavaScriptMapConstant.DART_GENERAL_CLASS);
} else {
registry.registerInstantiatedType(type);
registry.registerInstantiation(type);
}
}

View file

@ -26,8 +26,13 @@ import '../common/registry.dart' show
import '../common/tasks.dart' show
CompilerTask;
import '../common/resolution.dart' show
Feature,
ListLiteralUse,
MapLiteralUse,
Resolution,
ResolutionCallbacks;
ResolutionCallbacks,
ResolutionWorldImpact,
TransformedWorldImpact;
import '../common/work.dart' show
ItemCompilationContext;
import '../compiler.dart' show
@ -77,7 +82,7 @@ import '../js_emitter/js_emitter.dart' show
import '../library_loader.dart' show LibraryLoader, LoadedLibraries;
import '../native/native.dart' as native;
import '../resolution/registry.dart' show
ResolutionRegistry;
EagerRegistry;
import '../resolution/tree_elements.dart' show
TreeElements;
import '../ssa/ssa.dart';

View file

@ -853,6 +853,7 @@ abstract class ClassMemberMixin implements ClassElement {
/// this class.
MembersCreator _prepareCreator(Compiler compiler) {
if (classMembers == null) {
ensureResolved(compiler.resolution);
classMembers = new Map<Name, Member>();
if (interfaceMembersAreClassMembers) {

View file

@ -414,7 +414,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
TypeResult visitTypeAnnotation(TypeAnnotation node) {
DartType type = resolveTypeAnnotation(node);
if (inCheckContext) {
registry.registerIsCheck(type);
registry.registerCheckedModeCheck(type);
}
return new TypeResult(type);
}
@ -500,7 +500,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
});
if (inCheckContext) {
functionParameters.forEachParameter((ParameterElement element) {
registry.registerIsCheck(element.type);
registry.registerCheckedModeCheck(element.type);
});
}
}
@ -1190,7 +1190,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
Node typeNode = node.arguments.head;
DartType type = resolveTypeAnnotation(typeNode);
registry.registerAsCheck(type);
registry.registerAsCast(type);
registry.registerSendStructure(node, new AsStructure(type));
return const NoneResult();
}
@ -1952,7 +1952,6 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
} else {
semantics = new StaticAccess.typeParameterTypeLiteral(element);
}
registry.registerTypeVariableExpression(element);
registry.useElement(node, element);
registry.registerTypeLiteral(node, element.type);
@ -2005,14 +2004,10 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
MessageKind.ASSIGNING_TYPE, const {});
}
if (node.isComplex) {
// We read the type variable before trying write to it.
registry.registerTypeVariableExpression(element);
}
// TODO(23998): Remove this when all information goes through
// the [SendStructure].
registry.useElement(node, error);
// TODO(johnniwinther): Register only on read?
registry.registerTypeLiteral(node, element.type);
registry.registerThrowNoSuchMethod();
semantics = new StaticAccess.typeParameterTypeLiteral(element);
@ -4008,7 +4003,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
this, node, malformedIsError: malformedIsError,
deferredIsMalformed: deferredIsMalformed);
if (inCheckContext) {
registry.registerIsCheck(type);
registry.registerCheckedModeCheck(type);
registry.registerRequiredType(type, enclosingElement);
}
return type;
@ -4048,8 +4043,11 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
} else {
listType = coreTypes.listType();
}
registry.setType(node, listType);
registry.registerInstantiatedType(listType);
registry.registerLiteralList(
node,
listType,
isConstant: node.isConst,
isEmpty: node.elements.isEmpty);
registry.registerRequiredType(listType, enclosingElement);
if (node.isConst) {
List<ConstantExpression> constantExpressions = <ConstantExpression>[];
@ -4369,7 +4367,11 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
MessageKind.TYPE_VARIABLE_IN_CONSTANT);
isValidAsConstant = false;
}
registry.registerMapLiteral(node, mapType, node.isConst);
registry.registerMapLiteral(
node,
mapType,
isConstant: node.isConst,
isEmpty: node.entries.isEmpty);
registry.registerRequiredType(mapType, enclosingElement);
if (node.isConst) {

View file

@ -7,6 +7,11 @@ library dart2js.resolution.registry;
import '../common/backend_api.dart' show
Backend,
ForeignResolver;
import '../common/resolution.dart' show
Feature,
ListLiteralUse,
MapLiteralUse,
ResolutionWorldImpact;
import '../common/registry.dart' show
Registry;
import '../compiler.dart' show
@ -16,9 +21,9 @@ import '../dart_types.dart';
import '../diagnostics/invariant.dart' show
invariant;
import '../enqueue.dart' show
ResolutionEnqueuer,
WorldImpact;
ResolutionEnqueuer;
import '../elements/elements.dart';
import '../helpers/helpers.dart';
import '../tree/tree.dart';
import '../util/util.dart' show
Setlet;
@ -37,11 +42,7 @@ import 'members.dart' show
import 'tree_elements.dart' show
TreeElementMapping;
/// [ResolutionRegistry] collects all resolution information. It stores node
/// related information in a [TreeElements] mapping and registers calls with
/// [Backend], [World] and [Enqueuer].
// TODO(johnniwinther): Split this into an interface and implementation class.
// TODO(johnniwinther): Remove this.
class EagerRegistry implements Registry {
final Compiler compiler;
final TreeElementMapping mapping;
@ -100,19 +101,35 @@ class EagerRegistry implements Registry {
String toString() => 'EagerRegistry for ${mapping.analyzedElement}';
}
class ResolutionWorldImpact implements WorldImpact {
class _ResolutionWorldImpact implements ResolutionWorldImpact {
final Registry registry;
// TODO(johnniwinther): Do we benefit from lazy initialization of the
// [Setlet]s?
Setlet<UniverseSelector> _dynamicInvocations;
Setlet<UniverseSelector> _dynamicGetters;
Setlet<UniverseSelector> _dynamicSetters;
Setlet<InterfaceType> _instantiatedTypes;
Setlet<Element> _staticUses;
Setlet<DartType> _checkedTypes;
Setlet<DartType> _isChecks;
Setlet<DartType> _asCasts;
Setlet<DartType> _checkedModeChecks;
Setlet<MethodElement> _closurizedFunctions;
Setlet<LocalFunctionElement> _closures;
Setlet<Feature> _features;
// TODO(johnniwinther): This seems to be a union of other sets.
Setlet<DartType> _requiredTypes;
Setlet<MapLiteralUse> _mapLiterals;
Setlet<ListLiteralUse> _listLiterals;
Setlet<DartType> _typeLiterals;
Setlet<String> _constSymbolNames;
ResolutionWorldImpact(Compiler compiler, TreeElementMapping mapping)
_ResolutionWorldImpact(Compiler compiler, TreeElementMapping mapping)
: this.registry = new EagerRegistry(compiler, mapping);
void registerDependency(Element element) {
registry.registerDependency(element);
}
void registerDynamicGetter(UniverseSelector selector) {
if (_dynamicGetters == null) {
_dynamicGetters = new Setlet<UniverseSelector>();
@ -153,10 +170,6 @@ class ResolutionWorldImpact implements WorldImpact {
}
void registerInstantiatedType(InterfaceType type) {
// TODO(johnniwinther): Enable this when registration doesn't require a
// [Registry].
throw new UnsupportedError(
'Lazy registration of instantiated not supported.');
if (_instantiatedTypes == null) {
_instantiatedTypes = new Setlet<InterfaceType>();
}
@ -169,6 +182,58 @@ class ResolutionWorldImpact implements WorldImpact {
? _instantiatedTypes : const <InterfaceType>[];
}
void registerTypeLiteral(DartType type) {
if (_typeLiterals == null) {
_typeLiterals = new Setlet<DartType>();
}
_typeLiterals.add(type);
}
@override
Iterable<DartType> get typeLiterals {
return _typeLiterals != null
? _typeLiterals : const <DartType>[];
}
void registerRequiredType(DartType type) {
if (_requiredTypes == null) {
_requiredTypes = new Setlet<DartType>();
}
_requiredTypes.add(type);
}
@override
Iterable<DartType> get requiredTypes {
return _requiredTypes != null
? _requiredTypes : const <DartType>[];
}
void registerMapLiteral(MapLiteralUse mapLiteralUse) {
if (_mapLiterals == null) {
_mapLiterals = new Setlet<MapLiteralUse>();
}
_mapLiterals.add(mapLiteralUse);
}
@override
Iterable<MapLiteralUse> get mapLiterals {
return _mapLiterals != null
? _mapLiterals : const <MapLiteralUse>[];
}
void registerListLiteral(ListLiteralUse listLiteralUse) {
if (_listLiterals == null) {
_listLiterals = new Setlet<ListLiteralUse>();
}
_listLiterals.add(listLiteralUse);
}
@override
Iterable<ListLiteralUse> get listLiterals {
return _listLiterals != null
? _listLiterals : const <ListLiteralUse>[];
}
void registerStaticUse(Element element) {
if (_staticUses == null) {
_staticUses = new Setlet<Element>();
@ -181,17 +246,43 @@ class ResolutionWorldImpact implements WorldImpact {
return _staticUses != null ? _staticUses : const <Element>[];
}
void registerCheckedType(DartType type) {
if (_checkedTypes == null) {
_checkedTypes = new Setlet<DartType>();
void registerIsCheck(DartType type) {
if (_isChecks == null) {
_isChecks = new Setlet<DartType>();
}
_checkedTypes.add(type);
_isChecks.add(type);
}
@override
Iterable<DartType> get checkedTypes {
return _checkedTypes != null
? _checkedTypes : const <DartType>[];
Iterable<DartType> get isChecks {
return _isChecks != null
? _isChecks : const <DartType>[];
}
void registerAsCast(DartType type) {
if (_asCasts == null) {
_asCasts = new Setlet<DartType>();
}
_asCasts.add(type);
}
@override
Iterable<DartType> get asCasts {
return _asCasts != null
? _asCasts : const <DartType>[];
}
void registerCheckedModeCheckedType(DartType type) {
if (_checkedModeChecks == null) {
_checkedModeChecks = new Setlet<DartType>();
}
_checkedModeChecks.add(type);
}
@override
Iterable<DartType> get checkedModeChecks {
return _checkedModeChecks != null
? _checkedModeChecks : const <DartType>[];
}
void registerClosurizedFunction(MethodElement element) {
@ -206,17 +297,61 @@ class ResolutionWorldImpact implements WorldImpact {
return _closurizedFunctions != null
? _closurizedFunctions : const <MethodElement>[];
}
void registerClosure(LocalFunctionElement element) {
if (_closures == null) {
_closures = new Setlet<LocalFunctionElement>();
}
_closures.add(element);
}
@override
Iterable<LocalFunctionElement> get closures {
return _closures != null
? _closures : const <LocalFunctionElement>[];
}
void registerConstSymbolName(String name) {
if (_constSymbolNames == null) {
_constSymbolNames = new Setlet<String>();
}
_constSymbolNames.add(name);
}
@override
Iterable<String> get constSymbolNames {
return _constSymbolNames != null
? _constSymbolNames : const <String>[];
}
void registerFeature(Feature feature) {
if (_features == null) {
_features = new Setlet<Feature>();
}
_features.add(feature);
}
@override
Iterable<Feature> get features {
return _features != null ? _features : const <Feature>[];
}
String toString() => '$registry';
}
/// [ResolutionRegistry] collects all resolution information. It stores node
/// related information in a [TreeElements] mapping and registers calls with
/// [Backend], [World] and [Enqueuer].
// TODO(johnniwinther): Split this into an interface and implementation class.
class ResolutionRegistry implements Registry {
final Compiler compiler;
final TreeElementMapping mapping;
final ResolutionWorldImpact worldImpact;
final _ResolutionWorldImpact worldImpact;
ResolutionRegistry(Compiler compiler, TreeElementMapping mapping)
: this.compiler = compiler,
this.mapping = mapping,
this.worldImpact = new ResolutionWorldImpact(compiler, mapping);
this.worldImpact = new _ResolutionWorldImpact(compiler, mapping);
bool get isForResolution => true;
@ -401,7 +536,7 @@ class ResolutionRegistry implements Registry {
}
void registerImplicitSuperCall(FunctionElement superConstructor) {
universe.registerImplicitSuperCall(this, superConstructor);
registerDependency(superConstructor);
}
// TODO(johnniwinther): Remove this.
@ -413,47 +548,49 @@ class ResolutionRegistry implements Registry {
}
void registerLazyField() {
backend.resolutionCallbacks.onLazyField(this);
worldImpact.registerFeature(Feature.LAZY_FIELD);
}
void registerMetadataConstant(MetadataAnnotation metadata,
Element annotatedElement) {
backend.registerMetadataConstant(metadata, annotatedElement, this);
void registerMetadataConstant(MetadataAnnotation metadata) {
backend.registerMetadataConstant(metadata, metadata.annotatedElement, this);
}
void registerThrowRuntimeError() {
backend.resolutionCallbacks.onThrowRuntimeError(this);
worldImpact.registerFeature(Feature.THROW_RUNTIME_ERROR);
}
void registerCompileTimeError(ErroneousElement error) {
backend.resolutionCallbacks.onCompileTimeError(this, error);
worldImpact.registerFeature(Feature.COMPILE_TIME_ERROR);
}
void registerTypeVariableBoundCheck() {
backend.resolutionCallbacks.onTypeVariableBoundCheck(this);
worldImpact.registerFeature(Feature.TYPE_VARIABLE_BOUNDS_CHECK);
}
void registerThrowNoSuchMethod() {
backend.resolutionCallbacks.onThrowNoSuchMethod(this);
worldImpact.registerFeature(Feature.THROW_NO_SUCH_METHOD);
}
void registerIsCheck(DartType type) {
worldImpact.registerCheckedType(type);
backend.resolutionCallbacks.onIsCheck(type, this);
/// Register a checked mode check against [type].
void registerCheckedModeCheck(DartType type) {
worldImpact.registerCheckedModeCheckedType(type);
mapping.addRequiredType(type);
}
void registerAsCheck(DartType type) {
registerIsCheck(type);
backend.resolutionCallbacks.onAsCheck(type, this);
/// Register an is-test or is-not-test of [type].
void registerIsCheck(DartType type) {
worldImpact.registerIsCheck(type);
mapping.addRequiredType(type);
}
/// Register an as-cast of [type].
void registerAsCast(DartType type) {
worldImpact.registerAsCast(type);
mapping.addRequiredType(type);
}
void registerClosure(LocalFunctionElement element) {
if (element.computeType(compiler.resolution).containsTypeVariables) {
backend.registerClosureWithFreeTypeVariables(element, world, this);
}
world.registerClosure(element);
worldImpact.registerClosure(element);
}
void registerSuperUse(Node node) {
@ -465,22 +602,30 @@ class ResolutionRegistry implements Registry {
}
void registerSuperNoSuchMethod() {
backend.resolutionCallbacks.onSuperNoSuchMethod(this);
}
void registerTypeVariableExpression(TypeVariableElement element) {
backend.resolutionCallbacks.onTypeVariableExpression(this, element);
worldImpact.registerFeature(Feature.SUPER_NO_SUCH_METHOD);
}
void registerTypeLiteral(Send node, DartType type) {
mapping.setType(node, type);
backend.resolutionCallbacks.onTypeLiteral(type, this);
backend.registerInstantiatedType(compiler.coreTypes.typeType, world, this);
worldImpact.registerTypeLiteral(type);
}
void registerMapLiteral(Node node, DartType type, bool isConstant) {
void registerLiteralList(Node node,
InterfaceType type,
{bool isConstant,
bool isEmpty}) {
setType(node, type);
backend.resolutionCallbacks.onMapLiteral(this, type, isConstant);
worldImpact.registerListLiteral(
new ListLiteralUse(type, isConstant: isConstant, isEmpty: isEmpty));
}
void registerMapLiteral(Node node,
InterfaceType type,
{bool isConstant,
bool isEmpty}) {
setType(node, type);
worldImpact.registerMapLiteral(
new MapLiteralUse(type, isConstant: isConstant, isEmpty: isEmpty));
}
void registerForeignCall(Node node,
@ -507,49 +652,49 @@ class ResolutionRegistry implements Registry {
}
void registerConstSymbol(String name) {
backend.registerConstSymbol(name, this);
worldImpact.registerConstSymbolName(name);
}
void registerSymbolConstructor() {
backend.resolutionCallbacks.onSymbolConstructor(this);
worldImpact.registerFeature(Feature.SYMBOL_CONSTRUCTOR);
}
void registerInstantiatedType(InterfaceType type) {
backend.registerInstantiatedType(type, world, this);
worldImpact.registerInstantiatedType(type);
mapping.addRequiredType(type);
}
void registerAbstractClassInstantiation() {
backend.resolutionCallbacks.onAbstractClassInstantiation(this);
worldImpact.registerFeature(Feature.ABSTRACT_CLASS_INSTANTIATION);
}
void registerNewSymbol() {
backend.registerNewSymbol(this);
worldImpact.registerFeature(Feature.NEW_SYMBOL);
}
void registerRequiredType(DartType type, Element enclosingElement) {
backend.registerRequiredType(type, enclosingElement);
worldImpact.registerRequiredType(type);
mapping.addRequiredType(type);
}
void registerStringInterpolation() {
backend.resolutionCallbacks.onStringInterpolation(this);
worldImpact.registerFeature(Feature.STRING_INTERPOLATION);
}
void registerFallThroughError() {
backend.resolutionCallbacks.onFallThroughError(this);
worldImpact.registerFeature(Feature.FALL_THROUGH_ERROR);
}
void registerCatchStatement() {
backend.resolutionCallbacks.onCatchStatement(this);
worldImpact.registerFeature(Feature.CATCH_STATEMENT);
}
void registerStackTraceInCatch() {
backend.resolutionCallbacks.onStackTraceInCatch(this);
worldImpact.registerFeature(Feature.STACK_TRACE_IN_CATCH);
}
void registerSyncForIn(Node node) {
backend.resolutionCallbacks.onSyncForIn(this);
worldImpact.registerFeature(Feature.SYNC_FOR_IN);
}
ClassElement defaultSuperclass(ClassElement element) {
@ -562,7 +707,7 @@ class ResolutionRegistry implements Registry {
}
void registerThrowExpression() {
backend.resolutionCallbacks.onThrowExpression(this);
worldImpact.registerFeature(Feature.THROW_EXPRESSION);
}
void registerDependency(Element element) {
@ -580,11 +725,12 @@ class ResolutionRegistry implements Registry {
}
void registerInstantiation(InterfaceType type) {
backend.registerInstantiatedType(type, world, this);
registerInstantiatedType(type);
}
void registerAssert(bool hasMessage) {
backend.resolutionCallbacks.onAssert(hasMessage, this);
worldImpact.registerFeature(
hasMessage ? Feature.ASSERT_WITH_MESSAGE : Feature.ASSERT);
}
void registerSendStructure(Send node, SendStructure sendStructure) {
@ -598,15 +744,27 @@ class ResolutionRegistry implements Registry {
}
void registerAsyncMarker(FunctionElement element) {
backend.registerAsyncMarker(element, world, this);
switch (element.asyncMarker) {
case AsyncMarker.SYNC:
break;
case AsyncMarker.SYNC_STAR:
worldImpact.registerFeature(Feature.SYNC_STAR);
break;
case AsyncMarker.ASYNC:
worldImpact.registerFeature(Feature.ASYNC);
break;
case AsyncMarker.ASYNC_STAR:
worldImpact.registerFeature(Feature.ASYNC_STAR);
break;
}
}
void registerAsyncForIn(AsyncForIn node) {
backend.resolutionCallbacks.onAsyncForIn(node, this);
worldImpact.registerFeature(Feature.ASYNC_FOR_IN);
}
void registerIncDecOperation() {
backend.resolutionCallbacks.onIncDecOperation(this);
worldImpact.registerFeature(Feature.INC_DEC_OPERATION);
}
void registerTryStatement() {

View file

@ -10,7 +10,8 @@ import '../common/names.dart' show
Identifiers;
import '../common/resolution.dart' show
Parsing,
Resolution;
Resolution,
ResolutionWorldImpact;
import '../common/tasks.dart' show
CompilerTask,
DeferredAction;
@ -77,14 +78,14 @@ class ResolverTask extends CompilerTask {
Parsing get parsing => compiler.parsing;
WorldImpact resolve(Element element) {
ResolutionWorldImpact resolve(Element element) {
return measure(() {
if (Elements.isErroneous(element)) {
// TODO(johnniwinther): Add a predicate for this.
assert(invariant(element, element is! ErroneousElement,
message: "Element $element expected to have parse errors."));
_ensureTreeElements(element);
return const WorldImpact();
return const ResolutionWorldImpact();
}
WorldImpact processMetadata([WorldImpact result]) {
@ -108,7 +109,7 @@ class ResolverTask extends CompilerTask {
if (element.isClass) {
ClassElement cls = element;
cls.ensureResolved(resolution);
return processMetadata(const WorldImpact());
return processMetadata(const ResolutionWorldImpact());
} else if (element.isTypedef) {
TypedefElement typdef = element;
return processMetadata(resolveTypedef(typdef));
@ -286,13 +287,13 @@ class ResolverTask extends CompilerTask {
WorldImpact resolveMethodElement(FunctionElementX element) {
assert(invariant(element, element.isDeclaration));
return reporter.withCurrentElement(element, () {
if (compiler.enqueuer.resolution.hasBeenResolved(element)) {
if (compiler.enqueuer.resolution.hasBeenProcessed(element)) {
// TODO(karlklose): Remove the check for [isConstructor]. [elememts]
// should never be non-null, not even for constructors.
assert(invariant(element, element.isConstructor,
message: 'Non-constructor element $element '
'has already been analyzed.'));
return const WorldImpact();
return const ResolutionWorldImpact();
}
if (element.isSynthesized) {
if (element.isGenerativeConstructor) {
@ -312,7 +313,7 @@ class ResolverTask extends CompilerTask {
} else {
assert(element.isDeferredLoaderGetter || element.isErroneous);
_ensureTreeElements(element);
return const WorldImpact();
return const ResolutionWorldImpact();
}
} else {
element.parseNode(resolution.parsing);
@ -717,7 +718,7 @@ class ResolverTask extends CompilerTask {
// mixin application has been performed.
// TODO(johnniwinther): Obtain the [TreeElements] for [member]
// differently.
if (compiler.enqueuer.resolution.hasBeenResolved(member)) {
if (compiler.enqueuer.resolution.hasBeenProcessed(member)) {
checkMixinSuperUses(
member.resolvedAst.elements,
mixinApplication,
@ -994,7 +995,7 @@ class ResolverTask extends CompilerTask {
}
WorldImpact resolveTypedef(TypedefElementX element) {
if (element.isResolved) return const WorldImpact();
if (element.isResolved) return const ResolutionWorldImpact();
compiler.world.allTypedefs.add(element);
return _resolveTypeDeclaration(element, () {
ResolutionRegistry registry = new ResolutionRegistry(
@ -1042,7 +1043,7 @@ class ResolverTask extends CompilerTask {
// and the annotated element instead. This will allow the backend to
// retrieve the backend constant and only register metadata on the
// elements for which it is needed. (Issue 17732).
registry.registerMetadataConstant(annotation, annotatedElement);
registry.registerMetadataConstant(annotation);
annotation.resolutionState = STATE_DONE;
}));
}

View file

@ -65,7 +65,7 @@ class DeserializedResolutionWorkItem implements ResolutionWorkItem {
@override
WorldImpact run(Compiler compiler, ResolutionEnqueuer world) {
_isAnalyzed = true;
world.registerResolvedElement(element);
world.registerProcessedElement(element);
return worldImpact;
}
}

View file

@ -679,11 +679,6 @@ class World implements ClassWorld {
return elementsThatCannotThrow.contains(element);
}
void registerImplicitSuperCall(Registry registry,
FunctionElement superConstructor) {
registry.registerDependency(superConstructor);
}
void registerMightBePassedToApply(Element element) {
functionsThatMightBePassedToApply.add(element);
}

View file

@ -85,7 +85,7 @@ bool checkResults(Compiler compiler, CollectingDiagnosticHandler handler) {
'pkg/compiler/lib/src/helpers/helpers.dart');
void checkLive(member) {
if (member.isFunction) {
if (compiler.enqueuer.resolution.hasBeenResolved(member)) {
if (compiler.enqueuer.resolution.hasBeenProcessed(member)) {
compiler.reporter.reportHintMessage(
member, MessageKind.GENERIC,
{'text': "Helper function in production code '$member'."});

View file

@ -245,10 +245,10 @@ Compiler compilerFor(
compiler.deferredLibraryClass = cachedCompiler.deferredLibraryClass;
Iterable cachedTreeElements =
cachedCompiler.enqueuer.resolution.resolvedElements;
cachedCompiler.enqueuer.resolution.processedElements;
cachedTreeElements.forEach((element) {
if (element.library.isPlatformLibrary) {
compiler.enqueuer.resolution.registerResolvedElement(element);
compiler.enqueuer.resolution.registerProcessedElement(element);
}
});

View file

@ -6,6 +6,9 @@
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/enqueue.dart';
import 'package:compiler/src/js_backend/js_backend.dart';
import 'package:expect/expect.dart';
import 'memory_compiler.dart';
@ -13,15 +16,45 @@ main() {
asyncTest(() async {
await analyze('main() {}');
await analyze('main() => proxy;', proxyConstant: true);
await analyze('@deprecated main() {}');
await analyze('@deprecated main() => deprecated;', deprecatedClass: true);
await analyze('main() => deprecated;', deprecatedClass: true);
});
}
void checkInstantiated(Compiler compiler, ClassElement cls, bool expected) {
ResolutionEnqueuer enqueuer = compiler.enqueuer.resolution;
bool isInstantiated =
enqueuer.universe.directlyInstantiatedClasses.contains(cls);
bool isProcessed = enqueuer.isClassProcessed(cls);
Expect.equals(expected, isInstantiated,
'Unexpected instantiation state of class $cls.');
Expect.equals(expected, isProcessed,
'Unexpected processing state of class $cls.');
}
analyze(String code,
{bool proxyConstant: false}) async {
{bool proxyConstant: false,
bool deprecatedClass: false}) async {
CompilationResult result = await runCompiler(
memorySourceFiles: {'main.dart': code},
options: ['--analyze-only']);
Expect.isTrue(result.isSuccess);
Compiler compiler = result.compiler;
Expect.equals(proxyConstant, compiler.proxyConstant != null);
Expect.equals(proxyConstant, compiler.proxyConstant != null,
"Unexpected computation of proxy constant.");
checkInstantiated(
compiler, compiler.coreLibrary.find('_Proxy'), proxyConstant);
checkInstantiated(
compiler, compiler.coreLibrary.find('Deprecated'), deprecatedClass);
LibraryElement jsHelperLibrary =
compiler.libraryLoader.lookupLibrary(JavaScriptBackend.DART_JS_HELPER);
jsHelperLibrary.forEachLocalMember((Element element) {
Uri uri = element.compilationUnit.script.resourceUri;
if (element.isClass && uri.path.endsWith('annotations.dart')) {
checkInstantiated(compiler, element, false);
}
});
}

View file

@ -56,7 +56,7 @@ void checkLibraryElement(Compiler compiler, LibraryElement library) {
/// Check [member] for unrelated types.
void checkMemberElement(Compiler compiler, MemberElement member) {
if (!compiler.enqueuer.resolution.hasBeenResolved(member)) return;
if (!compiler.resolution.hasBeenResolved(member)) return;
ResolvedAst resolvedAst = member.resolvedAst;
RelatedTypesChecker relatedTypesChecker =

View file

@ -1083,7 +1083,7 @@ checkMemberResolved(compiler, className, memberName) {
Element memberElement = cls.lookupLocalMember(memberName);
Expect.isNotNull(memberElement);
Expect.isTrue(
compiler.enqueuer.resolution.hasBeenResolved(memberElement));
compiler.enqueuer.resolution.hasBeenProcessed(memberElement));
}
testToString() {