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 1014f047542f1e7c1666ef7752768e05f228991f..9aabb41a9ff2daa2d5db3ad06de0ae7e9c7e3b07 100644 |
| --- a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart |
| +++ b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart |
| @@ -1054,12 +1054,12 @@ setRuntimeTypeInfo(target, typeInfo) { |
| getRuntimeTypeInfo(target) { |
| if (target == null) return null; |
| - var res = JS('var', r'#.$builtinTypeInfo', target); |
| - // If the object does not have runtime type information, return an |
| - // empty literal, to avoid null checks. |
| - // TODO(ngeoffray): Make the object a top-level field to avoid |
| - // allocating a new object every single time. |
| - return (res == null) ? JS('var', '{}') : res; |
| + return JS('var', r'#.$builtinTypeInfo', target); |
| +} |
| + |
| +getRuntimeTypeArgument(target, index) { |
| + var rti = getRuntimeTypeInfo(target); |
| + return (rti != null) ? JS('var', r'#[#]', rti, index) : null; |
| } |
| /** |
| @@ -1421,7 +1421,7 @@ String getClassName(var object) { |
| return JS('String', r'#.constructor.builtin$cls', object); |
| } |
| -String getTypeArgumentAsString(List runtimeType) { |
| +String getRuntimeTypeAsString(List runtimeType) { |
| String className = getConstructorName(runtimeType[0]); |
| if (runtimeType.length == 1) return className; |
| return '$className<${joinArguments(runtimeType, 1)}>'; |
| @@ -1434,7 +1434,7 @@ String runtimeTypeToString(type) { |
| return 'dynamic'; |
| } else if (isJsArray(type)) { |
| // A list representing a type with arguments. |
| - return getTypeArgumentAsString(type); |
| + return getRuntimeTypeAsString(type); |
| } else { |
| // A reference to the constructor. |
| return getConstructorName(type); |
| @@ -1463,6 +1463,50 @@ String getRuntimeTypeString(var object) { |
| return "$className<${joinArguments(typeInfo, 0)}>"; |
| } |
| +bool isJsFunction(var o) => JS('bool', r"typeof # == 'function'", o); |
| + |
| +Object invoke(function, arguments) { |
| + return JS('var', r'#.apply(null, #)', function, arguments); |
| +} |
| + |
| +/** |
| + * Check that the types in the list [arguments] are subtypes of the types in |
| + * list [checks] (at the respective positions), possibly applying [substitution] |
| + * to the arguments before the check. |
| + * |
| + * See [:RuntimeTypes.getSubtypeSubstitution:] for a description of the possible |
| + * values for [substitution]. |
| + */ |
| +bool checkArguments(var substitution, var arguments, var checks) { |
| + if (isJsArray(substitution)) { |
| + arguments = substitution; |
| + } else if (isJsFunction(substitution)) { |
| + arguments = invoke(substitution, arguments); |
| + } |
| + return areSubtypes(arguments, checks); |
| +} |
| + |
| +bool areSubtypes(var s, var t) { |
| + // [:null:] means a raw type. |
| + if (s == null || t == null) return true; |
| + |
| + if (!isJsArray(s)) throw 's not an array'; |
|
kasperl
2013/01/29 15:02:34
Change to asserts?
karlklose
2013/01/30 12:01:19
Done.
|
| + if (!isJsArray(t)) throw 't not an array'; |
| + if (s.length != t.length) throw 'size mismatch'; |
| + |
| + int len = s.length; |
| + for (int i = 0; i < len; i++) { |
| + if (!isSubtype(s[i], t[i])) { |
| + return false; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| +var getArguments(var type) => JS('var', r'#.slice(1)', type); |
|
kasperl
2013/01/29 15:02:34
var isn't a legal return type.
karlklose
2013/01/30 12:01:19
Done.
|
| + |
| +var getField(var object, String name) => JS('var', r'#[#]', object, name); |
|
kasperl
2013/01/29 15:02:34
var isn't a legal return type.
karlklose
2013/01/30 12:01:19
Done.
|
| + |
| /** |
| * Check whether the type represented by [s] is a subtype of the type |
| * represented by [t]. |
| @@ -1486,20 +1530,20 @@ bool isSubtype(var s, var t) { |
| // constructed from the type of [t]. |
| var typeOfS = isJsArray(s) ? s[0] : s; |
| var typeOfT = isJsArray(t) ? t[0] : t; |
| + // Check for a subtyping flag. |
| var test = '${JS_OPERATOR_IS_PREFIX()}${runtimeTypeToString(typeOfT)}'; |
| - if (JS('var', r'#[#]', typeOfS, test) == null) return false; |
| + if (getField(typeOfS, test) == null) return false; |
| // The class of [s] is a subclass of the class of [t]. If either of the types |
| // is raw, [s] is a subtype of [t]. |
| if (!isJsArray(s) || !isJsArray(t)) return true; |
| - // Recursively check the type arguments. |
| - int len = s.length; |
| - if (len != t.length) return false; |
| - for (int i = 1; i < len; i++) { |
| - if (!isSubtype(s[i], t[i])) { |
| - return false; |
| - } |
| + // Get the necessary substitution of the type arguments, if there is one. |
| + var substitution; |
| + if (JS('bool', '# !== #', typeOfT, typeOfS)) { |
| + var field = '${JS_OPERATOR_AS_PREFIX()}${runtimeTypeToString(typeOfT)}'; |
| + substitution = getField(typeOfS, field); |
| } |
| - return true; |
| + // Recursively check the type arguments. |
| + return checkArguments(substitution, getArguments(s), getArguments(t)); |
| } |
| createRuntimeType(String name) => new TypeImpl(name); |