blob: 474b10e743803d7a257c514d8f6a8e50eb0249f3 [file] [log] [blame]
// Copyright (c) 2012, 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.
library dart2js.common.resolution;
import '../compiler.dart' show
Compiler;
import '../core_types.dart' show
CoreTypes;
import '../dart_types.dart' show
DartType,
InterfaceType;
import '../diagnostics/diagnostic_listener.dart' show
DiagnosticReporter;
import '../elements/elements.dart' show
AstElement,
ClassElement,
Element,
ErroneousElement,
FunctionElement,
FunctionSignature,
LocalFunctionElement,
MetadataAnnotation,
MethodElement,
TypedefElement,
TypeVariableElement;
import '../enqueue.dart' show
ResolutionEnqueuer,
WorldImpact;
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
ItemCompilationContext,
WorkItem;
/// [WorkItem] used exclusively by the [ResolutionEnqueuer].
class ResolutionWorkItem extends WorkItem {
bool _isAnalyzed = false;
ResolutionWorkItem(AstElement element,
ItemCompilationContext compilationContext)
: super(element, compilationContext);
WorldImpact run(Compiler compiler, ResolutionEnqueuer world) {
WorldImpact impact = compiler.analyze(this, world);
impact = compiler.backend.resolutionCallbacks.transformImpact(impact);
_isAnalyzed = true;
return impact;
}
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) {}
/// Register that an 'await for' has been seen.
void onAsyncForIn(AsyncForIn node, Registry registry) {}
/// Called during resolution to notify to the backend that the
/// program uses string interpolation.
void onStringInterpolation(Registry registry) {}
/// Called during resolution to notify to the backend that the
/// program has a catch statement.
void onCatchStatement(Registry registry) {}
/// Called during resolution to notify to the backend that the
/// program explicitly throws an exception.
void onThrowExpression(Registry registry) {}
/// Called during resolution to notify to the backend that the
/// program has a global variable with a lazy initializer.
void onLazyField(Registry registry) {}
/// Called during resolution to notify to the backend that the
/// program uses a type variable as an expression.
void onTypeVariableExpression(Registry registry,
TypeVariableElement variable) {}
/// Called during resolution to notify to the backend that the
/// program uses a type literal.
void onTypeLiteral(DartType type, Registry registry) {}
/// Called during resolution to notify to the backend that the
/// program has a catch statement with a stack trace.
void onStackTraceInCatch(Registry registry) {}
/// Register an is check to the backend.
void onIsCheck(DartType type, Registry registry) {}
/// Called during resolution to notify to the backend that the
/// program has a for-in loop.
void onSyncForIn(Registry registry) {}
/// Register an as check to the backend.
void onAsCheck(DartType type, Registry registry) {}
/// Registers that a type variable bounds check might occur at runtime.
void onTypeVariableBoundCheck(Registry registry) {}
/// Register that the application may throw a [NoSuchMethodError].
void onThrowNoSuchMethod(Registry registry) {}
/// Register that the application may throw a [RuntimeError].
void onThrowRuntimeError(Registry registry) {}
/// Register that the application has a compile time error.
void onCompileTimeError(Registry registry, ErroneousElement error) {}
/// Register that the application may throw an
/// [AbstractClassInstantiationError].
void onAbstractClassInstantiation(Registry registry) {}
/// Register that the application may throw a [FallThroughError].
void onFallThroughError(Registry registry) {}
/// Register that a super call will end up calling
/// [: super.noSuchMethod :].
void onSuperNoSuchMethod(Registry registry) {}
/// Register that the application creates a constant map.
void onMapLiteral(Registry registry, DartType type, bool isConstant) {}
/// Called when resolving the `Symbol` constructor.
void onSymbolConstructor(Registry registry) {}
/// Called when resolving a prefix or postfix expression.
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) {
// TODO(johnniwinther): Remove this when dependency tracking is done on
// the world impact itself.
registerDependency(element);
if (_staticUses == null) {
_staticUses = new Setlet<Element>();
}
_staticUses.add(element);
}
@override
Iterable<LocalFunctionElement> get closures => worldImpact.closures;
}
// TODO(johnniwinther): Rename to `Resolver` or `ResolverContext`.
abstract class Resolution {
Parsing get parsing;
DiagnosticReporter get reporter;
CoreTypes get coreTypes;
void resolveTypedef(TypedefElement typdef);
void resolveClass(ClassElement cls);
void registerClass(ClassElement cls);
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`.
abstract class Parsing {
DiagnosticReporter get reporter;
void parsePatchClass(ClassElement cls);
measure(f());
}