Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(398)

Unified Diff: lib/compiler/implementation/types/concrete_types_inferrer.dart

Issue 11093078: - Add support for binary operators (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: sync to head Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: lib/compiler/implementation/types/concrete_types_inferrer.dart
diff --git a/lib/compiler/implementation/types/concrete_types_inferrer.dart b/lib/compiler/implementation/types/concrete_types_inferrer.dart
index 0a835de894b4cdf04df536755be659eb6928b3e4..f324961819e45ccaec06d4a8dbd4be6a384597c7 100644
--- a/lib/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/lib/compiler/implementation/types/concrete_types_inferrer.dart
@@ -144,6 +144,10 @@ class UnionType implements ConcreteType {
return result;
}
+ // TODO(polux): Collapse {num, int, ...}, {num, double, ...} and
+ // {int, double,...} into {num, ...} as an optimization. It will require
+ // UnionType to know about these class elements, which is cumbersome because
+ // there are no nested classes. We need factory methods instead.
ConcreteType union(ConcreteType other) {
if (other.isUnkown()) {
return const UnknownConcreteType();
@@ -249,6 +253,7 @@ class ConcreteTypeCartesianProductIterator implements Iterator {
class BaseTypes {
final BaseType intBaseType;
final BaseType doubleBaseType;
+ final BaseType numBaseType;
final BaseType boolBaseType;
final BaseType stringBaseType;
final BaseType listBaseType;
@@ -258,6 +263,7 @@ class BaseTypes {
BaseTypes(Compiler compiler) :
intBaseType = new ClassBaseType(compiler.intClass),
doubleBaseType = new ClassBaseType(compiler.doubleClass),
+ numBaseType = new ClassBaseType(compiler.numClass),
boolBaseType = new ClassBaseType(compiler.boolClass),
stringBaseType = new ClassBaseType(compiler.stringClass),
listBaseType = new ClassBaseType(compiler.listClass),
@@ -403,6 +409,73 @@ class ConcreteTypesInferrer {
callers = new Map<FunctionElement, Set<FunctionElement>>(),
readers = new Map<Element, Set<FunctionElement>>();
+ /**
+ * Populates [cache] with ad hoc rules like:
+ *
+ * {int} + {int} -> {int}
+ * {int} + {double} -> {num}
+ * {int} + {num} -> {double}
+ * ...
+ */
+ populateCacheWithBuiltinRules() {
+ // Builds the environment that would be looked up if we were to analyze
+ // o.method(arg) where o has concrete type {receiverType} and arg has
+ // concrete type {argumentType}.
+ ConcreteTypesEnvironment makeEnvironment(BaseType receiverType,
+ FunctionElement method,
+ BaseType argumentType) {
+ ArgumentsTypes argumentsTypes = new ArgumentsTypes(
+ [new ConcreteType.singleton(argumentType)],
+ new Map());
+ Map<Element, ConcreteType> argumentMap =
+ associateArguments(method, argumentsTypes);
+ ConcreteTypeCartesianProduct product =
+ new ConcreteTypeCartesianProduct(receiverType, argumentMap);
+ return product.iterator().next();
karlklose 2012/10/23 10:58:15 Can we construct this object more directly instead
polux 2012/10/25 12:02:01 Absolutely! Done. On 2012/10/23 10:58:15, karlklo
+ }
+
+ // Adds the rule {receiverType}.method({argumentType}) -> {returnType}
+ // to cache.
+ void rule(ClassBaseType receiverType, String method,
+ BaseType argumentType, BaseType returnType) {
+ // The following line shouldn't be needed but the mock compiler doesn't
+ // resolve num for some reason.
+ if (receiverType.element.resolutionState == STATE_NOT_STARTED) {
karlklose 2012/10/23 10:58:15 use ensureResolved?
polux 2012/10/25 12:02:01 Done.
+ compiler.resolver.resolveClass(receiverType.element);
+ }
+ FunctionElement methodElement =
+ receiverType.element.lookupMember(new SourceString(method));
+ ConcreteTypesEnvironment environment =
+ makeEnvironment(receiverType, methodElement, argumentType);
+ Map<ConcreteTypesEnvironment, ConcreteType> map =
+ cache.containsKey(methodElement)
+ ? cache[methodElement]
+ : new Map<ConcreteTypesEnvironment, ConcreteType>();
+ map[environment] = new ConcreteType.singleton(returnType);
+ cache[methodElement] = map;
+ }
+
+ // The hardcoded typing rules.
+ final ClassBaseType int = baseTypes.intBaseType;
+ final ClassBaseType double = baseTypes.doubleBaseType;
+ final ClassBaseType num = baseTypes.numBaseType;
+ for (String operator in ['add', 'mul', 'sub']) {
+ final String method = r"operator$".concat(operator);
+
+ rule(int, method, int, int);
+ rule(int, method, double, num);
+ rule(int, method, num, num);
+
+ rule(double, method, double, double);
+ rule(double, method, int, num);
+ rule(double, method, num, num);
+
+ rule(num, method, int, num);
+ rule(num, method, double, num);
+ rule(num, method, num, num);
+ }
+ }
+
// --- utility methods ---
/**
@@ -554,7 +627,7 @@ class ConcreteTypesInferrer {
Map<Element, ConcreteType> associateArguments(FunctionElement function,
ArgumentsTypes argumentsTypes) {
final Map<Element, ConcreteType> result = new Map<Element, ConcreteType>();
- final FunctionSignature signature = function.functionSignature;
+ final FunctionSignature signature = function.computeSignature(compiler);
// too many arguments
if (argumentsTypes.length > signature.parameterCount) {
return null;
@@ -644,6 +717,11 @@ class ConcreteTypesInferrer {
ConcreteType analyzeMethod(FunctionElement element,
ConcreteTypesEnvironment environment) {
FunctionExpression tree = element.parseNode(compiler);
+ // This should never happen since we only deal with concrete types, except
+ // for external methods whose typing rules have not been hardcoded yet.
+ if (!tree.hasBody()) {
+ return new ConcreteType.unknown();
+ }
TreeElements elements =
compiler.enqueuer.resolution.resolvedElements[element];
Visitor visitor =
@@ -702,6 +780,7 @@ class ConcreteTypesInferrer {
void analyzeMain(Element element) {
baseTypes = new BaseTypes(compiler);
cache[element] = new Map<ConcreteTypesEnvironment, ConcreteType>();
+ populateCacheWithBuiltinRules();
try {
workQueue.addLast(
new InferenceWorkItem(element, new ConcreteTypesEnvironment()));
@@ -1099,6 +1178,7 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> {
}
ConcreteType visitLiteralMapEntry(LiteralMapEntry node) {
+ // We don't need to visit the key, it's always a string.
return analyze(node.value);
}
@@ -1139,7 +1219,7 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> {
}
ConcreteType visitOperatorSend(Send node) {
- inferrer.fail(node, 'not implemented');
+ return visitDynamicSend(node);
}
ConcreteType visitGetterSend(Send node) {
@@ -1206,14 +1286,54 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> {
inferrer.fail(node, 'not implemented');
}
+ // TODO(polux): handle unary operators
+ final Set<SourceString> operators = new Set<SourceString>()
karlklose 2012/10/23 10:58:15 When all operators are supported, we should be abl
polux 2012/10/25 12:02:01 Done.
+ ..add(const SourceString('=='))
+ ..add(const SourceString('!='))
+ ..add(const SourceString('~'))
+ ..add(const SourceString('[]'))
+ ..add(const SourceString('[]='))
+ ..add(const SourceString('*'))
+ ..add(const SourceString('*='))
+ ..add(const SourceString('/'))
+ ..add(const SourceString('/='))
+ ..add(const SourceString('%'))
+ ..add(const SourceString('%='))
+ ..add(const SourceString('~/'))
+ ..add(const SourceString('~/='))
+ ..add(const SourceString('+'))
+ ..add(const SourceString('+='))
+ ..add(const SourceString('-'))
+ ..add(const SourceString('-='))
+ ..add(const SourceString('<<'))
+ ..add(const SourceString('<<='))
+ ..add(const SourceString('>>'))
+ ..add(const SourceString('>>='))
+ ..add(const SourceString('>='))
+ ..add(const SourceString('>'))
+ ..add(const SourceString('<='))
+ ..add(const SourceString('<'))
+ ..add(const SourceString('&'))
+ ..add(const SourceString('&='))
+ ..add(const SourceString('^'))
+ ..add(const SourceString('^='))
+ ..add(const SourceString('|'))
+ ..add(const SourceString('|='));
+
+ SourceString canonicalize(SourceString s) {
karlklose 2012/10/23 10:58:15 Perhaps 'canonicalMethodName'?
polux 2012/10/25 12:02:01 Done.
+ return operators.contains(s)
+ ? Elements.constructOperatorName(s, false)
+ : s;
+ }
+
ConcreteType visitDynamicSend(Send node) {
ConcreteType receiverType = analyze(node.receiver);
ConcreteType result = new ConcreteType.empty();
final argumentsTypes = analyzeArguments(node.arguments);
if (receiverType.isUnkown()) {
- List<FunctionElement> methods =
- inferrer.getMembersByName(node.selector.asIdentifier().source);
+ List<FunctionElement> methods = inferrer.getMembersByName(
+ canonicalize(node.selector.asIdentifier().source));
for (final method in methods) {
inferrer.addCaller(method, currentMethod);
Element classElem = method.enclosingElement;
@@ -1225,9 +1345,10 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> {
} else {
for (BaseType baseReceiverType in receiverType.baseTypes) {
if (!baseReceiverType.isNull()) {
- FunctionElement method = (baseReceiverType as ClassBaseType).element
- .lookupMember(node.selector.asIdentifier().source);
- if (method != null) {
+ ClassBaseType classBaseReceiverType = baseReceiverType;
+ FunctionElement method = classBaseReceiverType.element
+ .lookupMember(canonicalize(node.selector.asIdentifier().source));
+ if (method !== null) {
karlklose 2012/10/23 10:58:15 Use != instead of !==.
polux 2012/10/25 12:02:01 Done.
inferrer.addCaller(method, currentMethod);
result = result.union(inferrer.getSendReturnType(method,
baseReceiverType, argumentsTypes));
« no previous file with comments | « no previous file | tests/compiler/dart2js/cpa_inference_test.dart » ('j') | tests/compiler/dart2js/cpa_inference_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698