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

Unified Diff: dart/sdk/lib/_internal/lib/js_helper.dart

Issue 50313007: Implement dynamic function checks. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 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: dart/sdk/lib/_internal/lib/js_helper.dart
diff --git a/dart/sdk/lib/_internal/lib/js_helper.dart b/dart/sdk/lib/_internal/lib/js_helper.dart
index ff0cf493b32e7ca4331741af2107beaf45320721..10171cc8986363d4ccacc8f483efc0937e04f9ce 100644
--- a/dart/sdk/lib/_internal/lib/js_helper.dart
+++ b/dart/sdk/lib/_internal/lib/js_helper.dart
@@ -31,6 +31,7 @@ import 'dart:_interceptors';
import 'dart:_collection-dev' as _symbol_dev;
import 'dart:_js_names' show
+ extractKeys,
mangledNames,
unmangleGlobalNameIfPreservedAnyways;
@@ -2006,3 +2007,318 @@ class RuntimeError extends Error {
RuntimeError(this.message);
String toString() => "RuntimeError: $message";
}
+
+abstract class RuntimeType {
+ const RuntimeType();
+
+ bool isTest(expression);
Johnni Winther 2013/10/30 12:02:19 Several subtypes have no implementation for this.
ahe 2013/11/29 13:10:17 Done.
+
+ toRti();
+}
+
+// TODO(ahe): Remove this class.
+class DummyRuntimeType extends RuntimeType {
+ final String impl;
+
+ DummyRuntimeType(this.impl);
+
+ bool isTest(expression) {
+ throw "<<is-test with '$impl' not implemented>>";
+ }
+
+ String toString() => 'DummyRuntimeType($impl)';
+}
+
+// TODO(ahe): Delete this method.
+DummyRuntimeType buildDummyType(String impl) => new DummyRuntimeType(impl);
+
+class RuntimeFunctionType extends RuntimeType {
+ final RuntimeType returnType;
+ final List<RuntimeType> parameterTypes;
+ final List<RuntimeType> optionalParameterTypes;
+ final namedParameters;
+
+ RuntimeFunctionType(this.returnType,
+ this.parameterTypes,
+ this.optionalParameterTypes,
+ this.namedParameters);
+
+ // TODO(ahe): Implement this.
+ bool get isVoid => returnType is VoidRuntimeType;
+
+ /// Called from generated code. [expression] is a Dart object and this method
+ /// returns true if [this] is a supertype of [expression].
+ bool _isTest(expression) {
+ // Type inferrer don't think this is called with dynamic arguments.
+ expression = JS('', '#', expression);
+
+ var interceptor = getInterceptor(expression);
+ if (!JS('bool', '# in #', JS_SIGNATURE_NAME(), interceptor)) return false;
+ var functionTypeObject = JS('', '#[#]()', interceptor, JS_SIGNATURE_NAME());
+ bool result = isFunctionSubtype(functionTypeObject, toRti());
+
+ // DEBUG REMOVE
+ var pretty = new FunctionTypeInfoDecoderRing(functionTypeObject).toString();
+ var self = new FunctionTypeInfoDecoderRing(toRti()).toString();
+ print("<<$pretty is $this (${self}) [$result]>>");
+
+ return result;
+ }
+
+ void _asCheck(expression) {
+ // Type inferrer don't think this is called with dynamic arguments.
+ _check(JS('', '#', expression), true);
+ }
+
+ void _assertCheck(expression) {
+ // Type inferrer don't think this is called with dynamic arguments.
+ _check(JS('', '#', expression), false);
+ }
+
+ void _check(expression, bool isCast) {
+ if (expression == null) return null;
+ if (_isTest(expression)) return expression;
+
+ var self = new FunctionTypeInfoDecoderRing(toRti()).toString();
+ if (isCast) {
+ var interceptor = getInterceptor(expression);
+ var pretty;
+ if (JS('bool', '# in #', JS_SIGNATURE_NAME(), interceptor)) {
+ var functionTypeObject =
+ JS('', '#[#]()', interceptor, JS_SIGNATURE_NAME());
+ pretty = new FunctionTypeInfoDecoderRing(functionTypeObject).toString();
+ } else {
+ pretty = Primitives.objectTypeName(expression);
+ }
+ throw new CastErrorImplementation(pretty, self);
+ } else {
+ // TODO(ahe): Pass "pretty" function-type to TypeErrorImplementation?
+ throw new TypeErrorImplementation(expression, self);
+ }
+ }
+
+ toRti() {
+ var result = JS('=Object', '{ #: "dynafunc" }', JS_FUNCTION_TYPE_TAG());
+ if (isVoid) {
+ JS('', '#[#] = true', result, JS_FUNCTION_TYPE_VOID_RETURN_TAG());
+ } else {
+ if (returnType is! DynamicRuntimeType) {
+ JS('', '#[#] = #', result, JS_FUNCTION_TYPE_RETURN_TYPE_TAG(),
+ returnType.toRti());
+ }
+ }
+ if (parameterTypes.length > 0) {
+ JS('', '#[#] = #', result, JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG(),
+ new List.from(parameterTypes.map((p) => p.toRti())));
+ }
+
+ if (optionalParameterTypes != null && !optionalParameterTypes.isEmpty) {
+ JS('', '#[#] = #', result, JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG(),
+ new List.from(optionalParameterTypes.map((p) => p.toRti())));
+ }
+
+ if (namedParameters != null) {
+ var namedRti = JS('=Object', '{}');
+ for (var name in extractKeys(namedParameters)) {
+ var rti = JS('', '#[#]', namedParameters, name).toRti();
+ JS('', '#[#] = #', namedRti, name, rti);
+ }
+ JS('', '#[#] = #', result, JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG(),
+ namedRti);
+ }
+
+ return result;
+ }
+
+ String toString() {
+ String result = '(';
+ bool needsComma = false;
+ for (RuntimeType type in parameterTypes) {
+ if (needsComma) result += ', ';
+ result += '$type';
+ needsComma = true;
+ }
+ if (optionalParameterTypes != null && !optionalParameterTypes.isEmpty) {
+ if (needsComma) result += ', ';
+ needsComma = false;
+ result += '[';
+ for (RuntimeType type in optionalParameterTypes) {
+ if (needsComma) result += ', ';
+ result += '$type';
+ needsComma = true;
+ }
+ result += ']';
+ }
Johnni Winther 2013/10/30 12:02:19 Named parameters not handled.
ahe 2013/11/29 13:10:17 Done.
+ result += ') -> $returnType';
+ return result;
+ }
+}
+
+RuntimeFunctionType buildFunctionType(RuntimeType returnType,
+ List parameterTypes,
+ List optionalParameterTypes) {
+ return new RuntimeFunctionType(
+ returnType, parameterTypes, optionalParameterTypes, null);
+}
+
+RuntimeFunctionType buildNamedFunctionType(RuntimeType returnType,
+ List parameterTypes,
+ namedParameters) {
+ return new RuntimeFunctionType(
+ returnType, parameterTypes, null, namedParameters);
+}
+
+RuntimeType buildInterfaceType(rti, List typeArguments) {
+ String name = JS('String|Null', r'#.name', rti);
+ typeArguments = JS('JSFixedArray', '#', typeArguments);
+ if (typeArguments.isEmpty) return new RuntimeTypePlain(name);
+ return new RuntimeTypeGeneric(name, typeArguments, null);
+}
+
+class DynamicRuntimeType extends RuntimeType {
+ const DynamicRuntimeType();
+
+ String toString() => 'dynamic';
+
+ toRti() => null;
+}
+
+RuntimeType getDynamicRuntimeType() => const DynamicRuntimeType();
+
+class VoidRuntimeType extends RuntimeType {
+ const VoidRuntimeType();
+
+ String toString() => 'void';
+
+ toRti() => throw 'internal error';
+}
+
+RuntimeType getVoidRuntimeType() => const VoidRuntimeType();
+
+RuntimeType convertRtiToRuntimeType(rti) {
+ if (rti == null) {
+ return getDynamicRuntimeType();
+ } else if (JS('bool', 'typeof # == "function"', rti)) {
+ return new RuntimeTypePlain(JS('String', r'rti.name'));
+ } else if (JS('bool', '#.constructor == Array', rti)) {
+ List list = JS('JSFixedArray', '#', rti);
+ String name = JS('String', r'#.name', list[0]);
+ List arguments = [];
+ for (int i = 1; i < list.length; i++) {
+ arguments.add(convertRtiToRuntimeType(list[i]));
+ }
+ return new RuntimeTypeGeneric(name, arguments, rti);
+ } else {
+ return new DummyRuntimeType("${JS('String', 'JSON.stringify(#)', rti)}");
+ }
+}
+
+class RuntimeTypePlain extends RuntimeType {
+ final String name;
+
+ RuntimeTypePlain(this.name);
+
+ toRti() {
+ var rti = JS('', 'init.allClasses[#]', name);
+ if (rti == null) throw "no type for '$name'";
+ return rti;
+ }
+
+ String toString() => name;
+}
+
+class RuntimeTypeGeneric extends RuntimeType {
+ final String name;
+ final List<RuntimeType> arguments;
+ var rti;
+
+ RuntimeTypeGeneric(this.name, this.arguments, this.rti);
+
+ toRti() {
+ if (rti != null) return rti;
+ var result = JS('JSExtendableArray', '[init.allClasses[#]]', name);
+ if (result[0] == null) {
+ throw "no type for '$name<...>'";
+ }
+ for (RuntimeType argument in arguments) {
+ JS('', '#.push(#)', result, argument.toRti());
+ }
+ return rti = result;
+ }
+
+ String toString() => '$name<${arguments.join(", ")}>';
+}
+
+class FunctionTypeInfoDecoderRing {
+ final _typeData;
+ String _cachedToString;
+
+ FunctionTypeInfoDecoderRing(this._typeData);
+
+ bool get _hasReturnType => JS('bool', '"ret" in #', _typeData);
+ get _returnType => JS('', '#.ret', _typeData);
+
+ bool get _isVoid => JS('bool', '!!#.void', _typeData);
+
+ bool get _hasArguments => JS('bool', '"args" in #', _typeData);
+ List get _arguments => JS('JSExtendableArray', '#.args', _typeData);
+
+ bool get _hasOptionalArguments => JS('bool', '"opt" in #', _typeData);
+ List get _optionalArguments => JS('JSExtendableArray', '#.opt', _typeData);
+
+ bool get _hasNamedArguments => JS('bool', '"named" in #', _typeData);
+ get _namedArguments => JS('=Object', '#.named', _typeData);
+
+ String _convert(type) {
+ String result = runtimeTypeToString(type);
+ if (result != null) return result;
+ if (JS('bool', '"func" in #', type)) {
+ return new FunctionTypeInfoDecoderRing(type).toString();
+ } else {
+ throw 'bad type';
+ }
+ }
+
+ String toString() {
+ if (_cachedToString != null) return _cachedToString;
+ var s = "(";
+ var sep = '';
+ if (_hasArguments) {
+ for (var argument in _arguments) {
+ s += sep;
+ s += _convert(argument);
+ sep = ', ';
+ }
+ }
+ if (_hasOptionalArguments) {
+ s += '$sep[';
+ sep = '';
+ for (var argument in _optionalArguments) {
+ s += sep;
+ s += _convert(argument);
+ sep = ', ';
+ }
+ s += ']';
+ }
+ if (_hasNamedArguments) {
+ s += '$sep{';
+ sep = '';
+ for (var name in extractKeys(_namedArguments)) {
+ s += sep;
+ s += '$name: ';
+ s += _convert(JS('', '#[#]', _namedArguments, name));
+ sep = ', ';
+ }
+ s += '}';
+ }
+ s += ') -> ';
+ if (_isVoid) {
+ s += 'void';
+ } else if (_hasReturnType) {
+ s += _convert(_returnType);
+ } else {
+ s += 'dynamic';
+ }
+ return _cachedToString = "$s";
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698