blob: ca3860a96f4ee4a50369c16fc36e451066f43fd5 [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 'package:kernel/ast.dart' as ir;
import '../elements/entities.dart';
import '../types/abstract_value_domain.dart';
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show JClosedWorld;
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 implements TypesInferrer {
InferrerEngine inferrer;
final bool _disableTypeInference;
final JClosedWorld closedWorld;
TypeGraphInferrer(this.closedWorld, {bool disableTypeInference: false})
: this._disableTypeInference = disableTypeInference;
String get name => 'Graph inferrer';
AbstractValueDomain get abstractValueDomain =>
closedWorld.abstractValueDomain;
AbstractValue get _dynamicType => abstractValueDomain.dynamicType;
void analyzeMain(FunctionEntity main) {
inferrer = createInferrerEngineFor(main);
if (_disableTypeInference) return;
inferrer.runOverAllElements();
}
InferrerEngine createInferrerEngineFor(FunctionEntity main);
AbstractValue getReturnTypeOfMember(MemberEntity element) {
if (_disableTypeInference) return _dynamicType;
// Currently, closure calls return dynamic.
if (element is! FunctionEntity) return _dynamicType;
return inferrer.types.getInferredTypeOfMember(element).type;
}
AbstractValue getReturnTypeOfParameter(Local element) {
if (_disableTypeInference) return _dynamicType;
return _dynamicType;
}
AbstractValue 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 abstractValueDomain.functionType;
return inferrer.types.getInferredTypeOfMember(element).type;
}
AbstractValue 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;
}
AbstractValue getTypeForNewList(ir.Node node) {
if (_disableTypeInference) return _dynamicType;
return inferrer.types.allocatedLists[node].type;
}
bool isFixedArrayCheckedForGrowable(ir.Node node) {
if (_disableTypeInference) return true;
ListTypeInformation info = inferrer.types.allocatedLists[node];
return info.checksGrowable;
}
AbstractValue getTypeOfSelector(Selector selector, AbstractValue receiver) {
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, receiver)) {
return abstractValueDomain.getContainerElementType(receiver);
}
if (inferrer.returnsMapValueType(selector, receiver)) {
return abstractValueDomain.getMapValueType(receiver);
}
if (inferrer.closedWorld.includesClosureCall(selector, receiver)) {
return abstractValueDomain.dynamicType;
} else {
Iterable<MemberEntity> elements =
inferrer.closedWorld.locateMembers(selector, receiver);
List<AbstractValue> types = <AbstractValue>[];
for (MemberEntity element in elements) {
AbstractValue type =
inferrer.typeOfMemberWithSelector(element, selector).type;
types.add(type);
}
return abstractValueDomain.unionOfMany(types);
}
}
Iterable<MemberEntity> getCallersOfForTesting(MemberEntity element) {
if (_disableTypeInference) {
throw new UnsupportedError(
"Cannot query the type inferrer when type inference is disabled.");
}
return inferrer.getCallersOfForTesting(element);
}
bool isMemberCalledOnce(MemberEntity element) {
if (_disableTypeInference) return false;
MemberTypeInformation info =
inferrer.types.getInferredTypeOfMember(element);
return info.isCalledOnce();
}
void clear() {
inferrer.clear();
}
}