blob: 5df28695e55c7e6802aa84bf20976bb8fc0bbfcf [file] [log] [blame]
// Copyright (c) 2013, 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 type_graph_inferrer;
import 'dart:collection' show Queue;
import '../compiler.dart' show Compiler;
import '../elements/entities.dart';
import '../tree/tree.dart' as ast show Node;
import '../types/masks.dart'
show CommonMasks, ContainerTypeMask, MapTypeMask, TypeMask;
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show ClosedWorld, ClosedWorldRefiner;
import 'ast_inferrer_engine.dart';
import 'inferrer_engine.dart';
import 'type_graph_nodes.dart';
/**
* A work queue for the inferrer. It filters out nodes that are tagged as
* [TypeInformation.doNotEnqueue], as well as ensures through
* [TypeInformation.inQueue] that a node is in the queue only once at
* a time.
*/
class WorkQueue {
final Queue<TypeInformation> queue = new Queue<TypeInformation>();
void add(TypeInformation element) {
if (element.doNotEnqueue) return;
if (element.inQueue) return;
queue.addLast(element);
element.inQueue = true;
}
void addAll(Iterable<TypeInformation> all) {
all.forEach(add);
}
TypeInformation remove() {
TypeInformation element = queue.removeFirst();
element.inQueue = false;
return element;
}
bool get isEmpty => queue.isEmpty;
int get length => queue.length;
}
abstract class TypeGraphInferrer<T> implements TypesInferrer<T> {
InferrerEngine<T> inferrer;
final bool _disableTypeInference;
final ClosedWorld closedWorld;
final ClosedWorldRefiner closedWorldRefiner;
TypeGraphInferrer(this.closedWorld, this.closedWorldRefiner,
{bool disableTypeInference: false})
: this._disableTypeInference = disableTypeInference;
String get name => 'Graph inferrer';
CommonMasks get commonMasks => closedWorld.commonMasks;
TypeMask get _dynamicType => commonMasks.dynamicType;
void analyzeMain(FunctionEntity main) {
inferrer = createInferrerEngineFor(main);
if (_disableTypeInference) return;
inferrer.runOverAllElements();
}
InferrerEngine<T> createInferrerEngineFor(FunctionEntity main);
TypeMask getReturnTypeOfMember(MemberEntity element) {
if (_disableTypeInference) return _dynamicType;
// Currently, closure calls return dynamic.
if (element is! FunctionEntity) return _dynamicType;
return inferrer.types.getInferredTypeOfMember(element).type;
}
TypeMask getReturnTypeOfParameter(Local element) {
if (_disableTypeInference) return _dynamicType;
return _dynamicType;
}
TypeMask getTypeOfMember(MemberEntity element) {
if (_disableTypeInference) return _dynamicType;
// The inferrer stores the return type for a function, so we have to
// be careful to not return it here.
if (element is FunctionEntity) return commonMasks.functionType;
return inferrer.types.getInferredTypeOfMember(element).type;
}
TypeMask getTypeOfParameter(Local element) {
if (_disableTypeInference) return _dynamicType;
// The inferrer stores the return type for a function, so we have to
// be careful to not return it here.
return inferrer.types.getInferredTypeOfParameter(element).type;
}
TypeMask getTypeForNewList(T node) {
if (_disableTypeInference) return _dynamicType;
return inferrer.types.allocatedLists[node].type;
}
bool isFixedArrayCheckedForGrowable(T node) {
if (_disableTypeInference) return true;
ListTypeInformation info = inferrer.types.allocatedLists[node];
return info.checksGrowable;
}
TypeMask getTypeOfSelector(Selector selector, TypeMask mask) {
if (_disableTypeInference) return _dynamicType;
// Bailout for closure calls. We're not tracking types of
// closures.
if (selector.isClosureCall) return _dynamicType;
if (selector.isSetter || selector.isIndexSet) {
return _dynamicType;
}
if (inferrer.returnsListElementType(selector, mask)) {
ContainerTypeMask containerTypeMask = mask;
TypeMask elementType = containerTypeMask.elementType;
return elementType == null ? _dynamicType : elementType;
}
if (inferrer.returnsMapValueType(selector, mask)) {
MapTypeMask mapTypeMask = mask;
TypeMask valueType = mapTypeMask.valueType;
return valueType == null ? _dynamicType : valueType;
}
TypeMask result = const TypeMask.nonNullEmpty();
Iterable<MemberEntity> elements =
inferrer.closedWorld.locateMembers(selector, mask);
for (MemberEntity element in elements) {
TypeMask type = inferrer.typeOfMemberWithSelector(element, selector).type;
result = result.union(type, inferrer.closedWorld);
}
return result;
}
Iterable<MemberEntity> getCallersOf(MemberEntity element) {
if (_disableTypeInference) {
throw new UnsupportedError(
"Cannot query the type inferrer when type inference is disabled.");
}
return inferrer.getCallersOf(element);
}
bool isMemberCalledOnce(MemberEntity element) {
if (_disableTypeInference) return false;
MemberTypeInformation info =
inferrer.types.getInferredTypeOfMember(element);
return info.isCalledOnce();
}
void clear() {
inferrer.clear();
}
}
class AstTypeGraphInferrer extends TypeGraphInferrer<ast.Node> {
final Compiler _compiler;
AstTypeGraphInferrer(
this._compiler, ClosedWorld closedWorld, closedWorldRefiner,
{bool disableTypeInference: false})
: super(closedWorld, closedWorldRefiner,
disableTypeInference: disableTypeInference);
@override
InferrerEngine<ast.Node> createInferrerEngineFor(FunctionEntity main) {
return new AstInferrerEngine(
_compiler, closedWorld, closedWorldRefiner, main);
}
@override
GlobalTypeInferenceResults createResults() {
return new AstGlobalTypeInferenceResults(this, closedWorld);
}
}