Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/lib/js_helper.dart |
| diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart |
| index e4536f3622aca4ed21dc7eeb3a2b8fc849153a19..3657858d89dd7fc1a0cf1e7a9df4d46fc91ab035 100644 |
| --- a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart |
| +++ b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart |
| @@ -1049,6 +1049,12 @@ getRuntimeTypeInfo(target) { |
| return JS('var', r'#.$builtinTypeInfo', target); |
| } |
| +forwardRuntimeTypeInfo(target, substitution, source) { |
| + setRuntimeTypeInfo(target, |
| + substitute(substitution, getRuntimeTypeInfo(source))); |
| + return target; |
| +} |
| + |
| getRuntimeTypeArgument(target, substitution, index) { |
| var arguments = substitute(substitution, getRuntimeTypeInfo(target)); |
| return (arguments == null) ? null : getField(arguments, index); |
| @@ -1472,6 +1478,8 @@ String getRuntimeTypeString(var object) { |
| bool isJsFunction(var o) => JS('bool', r'typeof # == "function"', o); |
| +bool isJsObject(var o) => JS('bool', r"typeof # == 'object'", o); |
| + |
| Object invoke(function, arguments) { |
| return JS('var', r'#.apply(null, #)', function, arguments); |
| } |
| @@ -1497,6 +1505,26 @@ bool checkArguments(var substitution, var arguments, var checks) { |
| return areSubtypes(substitute(substitution, arguments), checks); |
| } |
| +bool getSignature(var signature, var target) { |
| + return invoke(signature, getRuntimeTypeInfo(target)); |
| +} |
| + |
| +bool checkFunctionSubtype(var target, var typeSignature, var context) { |
| + var targetSignature = getField(target, r'$signature'); |
|
ngeoffray
2013/03/13 09:30:46
Using $signature directly is brittle, you should p
Johnni Winther
2013/03/22 07:30:24
Done.
|
| + if (targetSignature == null) { |
| + // The target is statically known to be a subtype so further check is |
|
ngeoffray
2013/03/13 09:30:46
further or no further? Could you add an example?
Johnni Winther
2013/03/22 07:30:24
Not needed in the new encoding.
|
| + // needed. |
| + return true; |
| + } |
| + if (isJsFunction(targetSignature)) { |
| + targetSignature = invoke(targetSignature, getRuntimeTypeInfo(target)); |
| + } |
| + if (isJsFunction(typeSignature)) { |
| + typeSignature = invoke(typeSignature, getRuntimeTypeInfo(context)); |
| + } |
| + return isFunctionSubtype(targetSignature, typeSignature); |
| +} |
| + |
| bool areSubtypes(List s, List t) { |
| // [:null:] means a raw type. |
| if (s == null || t == null) return true; |
| @@ -1571,6 +1599,9 @@ bool isSubtype(var s, var t) { |
| if (JS('bool', '# == null', s) || JS('bool', '# == null', t)) return true; |
| // Subtyping is reflexive. |
| if (JS('bool', '# === #', s, t)) return true; |
| + if (getField(t, 'func') == true) { |
|
ngeoffray
2013/03/13 09:30:46
What is this? Probably needs an abstraction.
Johnni Winther
2013/03/22 07:30:24
A tag used to identify function type representatio
|
| + return isFunctionSubtype(s, t); |
| + } |
| // Get the object describing the class and check for the subtyping flag |
| // constructed from the type of [t]. |
| var typeOfS = isJsArray(s) ? s[0] : s; |
| @@ -1596,4 +1627,79 @@ bool isSubtype(var s, var t) { |
| return checkArguments(substitution, getArguments(s), getArguments(t)); |
| } |
| +bool isAssignable(var s, var t) { |
| + return isSubtype(s, t) || isSubtype(t, s); |
| +} |
| + |
| +bool areAssignable(List s, List t, bool allowSubset) { |
| + if (t == null) return true; |
| + if (s == null) return false; |
| + |
| + assert(isJsArray(s)); |
| + assert(isJsArray(t)); |
| + |
| + if (allowSubset) { |
| + if (s.length < t.length) return false; |
| + } else { |
| + if (s.length != t.length) return false; |
| + } |
| + |
| + int len = t.length; |
| + for (int i = 0; i < len; i++) { |
| + if (!isAssignable(s[i], t[i])) { |
| + return false; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| +bool areAssignableMaps(var s, var t) { |
| + if (t == null) return true; |
| + if (s == null) return false; |
| + |
| + assert(isJsObject(s)); |
| + assert(isJsObject(t)); |
| + |
| + // Hack: We need to iterate over the properties in [t], and the names of these |
| + // properties are not statically known so they must be retrieved dynamically. |
| + // Therefore we (mis)use the [JS] function to generate a for-each loop on [t] |
| + // using the JavaScript variable [:$name:] to hold the property names. |
|
ngeoffray
2013/03/13 09:30:46
To not make it a hack, please create a JavaScript
Johnni Winther
2013/03/22 07:30:24
How?
|
| + JS('', r'for (var $name in #) {', t); { |
| + // We need to distinguish the existing property with value [:undefined:] or |
| + // [:null:] from the non-existing property. The former is interpreted as a |
| + // named parameter of type [:dynamic:] and the later is interpreted as |
| + // [:$name:] not being a named parameter of [s]. |
| + if (JS('bool', r'!#.hasOwnProperty($name)', s)) return false; |
| + var tType = JS('', r'#[$name]', t); |
| + var sType = JS('', r'#[$name]', s); |
| + if (!isAssignable(sType, tType)) { |
| + return false; |
| + } |
| + } JS('', '}'); |
| + return true; |
| +} |
| + |
| +bool isFunctionSubtype(var s, var t) { |
| + if (!getField(s, 'func')) return false; |
| + if (getField(s, 'retvoid')) { |
| + if (!getField(t, 'retvoid')) return false; |
| + } else if (!getField(t, 'retvoid')) { |
| + var sReturnType = getField(s, 'ret'); |
| + var tReturnType = getField(t, 'ret'); |
| + if (!isAssignable(sReturnType, tReturnType)) return false; |
| + } |
| + var sParameterTypes = getField(s, 'args'); |
| + var tParameterTypes = getField(t, 'args'); |
| + if (!areAssignable(sParameterTypes, tParameterTypes, false)) return false; |
| + var sOptionalParameterTypes = getField(s, 'opt'); |
| + var tOptionalParameterTypes = getField(t, 'opt'); |
| + if (!areAssignable(sOptionalParameterTypes, tOptionalParameterTypes, true)) { |
| + return false; |
| + } |
| + var sNamedParameters = getField(s, 'named'); |
| + var tNamedParameters = getField(t, 'named'); |
| + if (!areAssignableMaps(sNamedParameters, tNamedParameters)) return false; |
| + return true; |
| +} |
| + |
| createRuntimeType(String name) => new TypeImpl(name); |