Index: compiler/lib/implementation/rtt.js |
diff --git a/compiler/lib/implementation/rtt.js b/compiler/lib/implementation/rtt.js |
index 83179d3dfa46193a18563e04bcd62f1eaa1ee3dc..e3a072b181c9388662f9c6011a632b6b50ff7590 100644 |
--- a/compiler/lib/implementation/rtt.js |
+++ b/compiler/lib/implementation/rtt.js |
@@ -10,16 +10,20 @@ |
* @param {string} classkey |
* @param {string=} typekey |
* @param {Array.<RTT>=} typeargs |
+ * @param {RTT} returnType |
+ * @param {bool} functionType |
*/ |
-function RTT(classkey, typekey, typeargs) { |
+function RTT(classkey, typekey, typeargs, returnType, functionType) { |
this.classKey = classkey; |
this.typeKey = typekey ? typekey : classkey; |
this.typeArgs = typeargs; |
+ this.returnType = returnType; // key for the return type |
this.implementedTypes = {}; |
+ this.functionType = functionType; |
// Add self |
this.implementedTypes[classkey] = this; |
// Add Object |
- if (classkey != $cls('Object')) { |
+ if (!functionType && classkey != $cls('Object')) { |
this.implementedTypes[$cls('Object')] = RTT.objectType; |
} |
} |
@@ -39,6 +43,7 @@ RTT.prototype.toString = function() { return this.typeKey; } |
*/ |
RTT.prototype.implementedBy = function(value){ |
return (value == null) ? RTT.nullInstanceOf(this) : |
+ this.functionType ? this.implementedByTypeFunc(value) : |
this.implementedByType(RTT.getTypeInfo(value)); |
}; |
@@ -53,6 +58,11 @@ function $mapLookup(map, key) { |
return map.hasOwnProperty(key) ? map[key] : null; |
} |
+RTT.prototype.implementedByTypeSwitch = function(value){ |
+ return this.functionType ? this.implementedByTypeFunc(value) : |
+ this.implementedByType(value); |
+}; |
+ |
/** |
* @param {!RTT} other |
* @return {boolean} Whether this type is implement by other |
@@ -67,7 +77,32 @@ RTT.prototype.implementedByType = function(otherType) { |
} |
if (targetTypeInfo.typeArgs && this.typeArgs) { |
for(var i = this.typeArgs.length - 1; i >= 0; i--) { |
- if (!this.typeArgs[i].implementedByType(targetTypeInfo.typeArgs[i])) { |
+ if (!this.typeArgs[i].implementedByTypeSwitch(targetTypeInfo.typeArgs[i])) { |
+ return false; |
+ } |
+ } |
+ } |
+ return true; |
+}; |
+ |
+/** |
+ * @param {!RTT} other |
+ * @return {boolean} Whether this type is assignable by other |
+ */ |
+RTT.prototype.assignableByType = function(otherType) { |
+ if (otherType === this || otherType === RTT.dynamicType || this === RTT.dynamicType) { |
+ return true; |
+ } |
+ var targetTypeInfo = $mapLookup(otherType.implementedTypes, this.classKey); |
+ if (targetTypeInfo == null) { |
+ targetTypeInfo = $mapLookup(this.implementedTypes, otherType.classKey); |
+ if (targetTypeInfo == null) { |
+ return false; |
+ } |
+ } |
+ if (targetTypeInfo.typeArgs && this.typeArgs) { |
+ for(var i = this.typeArgs.length - 1; i >= 0; i--) { |
+ if (!this.typeArgs[i].assignableByType(targetTypeInfo.typeArgs[i])) { |
return false; |
} |
} |
@@ -75,6 +110,44 @@ RTT.prototype.implementedByType = function(otherType) { |
return true; |
}; |
+ |
+/** |
+ * @param {!RTT} other |
+ * @return {boolean} Whether this type is implemented by other |
+ */ |
+RTT.prototype.implementedByTypeFunc = function(otherType) { |
+ if (otherType.$lookupRTT) { |
+ otherType = otherType.$lookupRTT(); |
+ } else if (!(otherType instanceof RTT)) { |
+ return false; |
+ } |
+ if (otherType === this || otherType === RTT.dynamicType) { |
+ return true; |
+ } |
+ var props = Object.getOwnPropertyNames(otherType.implementedTypes); |
+ NEXT_PROPERTY: for (var i = 0 ; i < props.length; i++) { |
+ var mapped = otherType.implementedTypes[props[i]]; |
+ if (mapped.returnType && this.returnType && |
+ !this.returnType.assignableByType(mapped.returnType)) { |
+ continue; |
+ } |
+ if (mapped.typeArgs && this.typeArgs) { |
+ if (this.typeArgs.length != mapped.typeArgs.length) { |
+ continue; |
+ } |
+ for (var x = this.typeArgs.length - 1; x >= 0; x--) { |
+ if (!this.typeArgs[x].assignableByType(mapped.typeArgs[x])) { |
+ continue NEXT_PROPERTY; |
+ } |
+ } |
+ } else if (mapped.typeArgs || this.typeArgs) { |
+ return false; |
+ } |
+ return true; |
+ } |
+ return false; |
+}; |
+ |
/** |
* @return {string} the class name associated with this type |
*/ |
@@ -134,15 +207,37 @@ RTT.create = function(name, implementsSupplier, typeArgs) { |
}; |
/** |
+ * @param {Array.<RTT>=} typeArgs |
+ * @param {<RTT>=} returnType (if defined) |
+ * @return {RTT} The RTT information object |
+ */ |
+RTT.createFunction = function(typeArgs, returnType) { |
+ var name = $cls("Function"); |
+ var typekey = RTT.getTypeKey(name, typeArgs, returnType); |
+ var rtt = $mapLookup(RTT.types, typekey); |
+ if (rtt) { |
+ return rtt; |
+ } |
+ var classkey = RTT.getTypeKey(name); |
+ rtt = new RTT(classkey, typekey, typeArgs, returnType, true); |
+ RTT.types[typekey] = rtt; |
+ return rtt; |
+}; |
+ |
+/** |
* @param {string} classkey |
* @param {Array.<(RTT|string)>=} typeargs |
+ * @param {string} returntype |
* @return {string} |
*/ |
-RTT.getTypeKey = function(classkey, typeargs) { |
+RTT.getTypeKey = function(classkey, typeargs, returntype) { |
var key = classkey; |
if (typeargs) { |
key += "<" + typeargs.join(",") + ">"; |
} |
+ if (returntype) { |
+ key += "-><" + returntype + ">"; |
+ } |
return key; |
}; |
@@ -217,6 +312,10 @@ RTT.dynamicType = new RTT($cls('Dynamic')); |
RTT.dynamicType.implementedBy = function(o) {return true}; |
RTT.dynamicType.implementedByType = function(o) {return true}; |
+function getDynamic() { |
+ return RTT.dynamicType; |
+} |
+ |
/** @type {!RTT} */ |
RTT.placeholderType = new RTT($cls('::')); |
RTT.placeholderType.implementedBy = function(o) {return true}; |