Chromium Code Reviews| Index: sdk/lib/_internal/js_runtime/lib/js_helper.dart |
| diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart |
| index 86e80d81b6ddbed5229a0da8d4540ac24cdd27c3..6e1548d396a3bb7cc40f13fa0de52e07bad54cc7 100644 |
| --- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart |
| +++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart |
| @@ -3361,6 +3361,59 @@ voidTypeCheck(value) { |
| throw new TypeErrorImplementation(value, 'void'); |
| } |
| +extractFunctionTypeObjectFrom(o) { |
| + var interceptor = getInterceptor(o); |
| + var signatureName = JS_GET_NAME(JsGetName.SIGNATURE_NAME); |
| + return JS('bool', '# in #', signatureName, interceptor) |
| + ? JS('', '#[#]()', interceptor, signatureName) |
| + : null; |
| +} |
| + |
| +functionTypeTest(value, functionTypeRti) { |
| + if (value == null) return false; |
| + var functionTypeObject = extractFunctionTypeObjectFrom(value); |
| + return functionTypeObject == null |
|
floitsch
2017/03/02 13:43:38
return functionTypeObject != null && isFunctionSub
|
| + ? false |
| + : isFunctionSubtype(functionTypeObject, functionTypeRti); |
| +} |
| + |
| +// Declared as 'var' to avoid assignment checks. |
| +var _inTypeAssertion = false; |
| + |
| +functionTypeCheck(value, functionTypeRti) { |
| + if (value == null) return value; |
| + |
| + // The function type test code contains type assertions for function |
| + // types. This leads to unbounded recursion, so disable the type checking of |
| + // function types while checking function types. |
| + |
| + if (true == _inTypeAssertion) return value; |
| + |
| + _inTypeAssertion = true; |
| + try { |
| + if (functionTypeTest(value, functionTypeRti)) return value; |
| + var self = runtimeTypeToString(functionTypeRti); |
| + throw new TypeErrorImplementation(value, self); |
| + } finally { |
| + _inTypeAssertion = false; |
| + } |
| +} |
| + |
| +functionTypeCast(value, functionTypeRti) { |
| + if (value == null) return value; |
| + if (functionTypeTest(value, functionTypeRti)) return value; |
| + |
| + var self = runtimeTypeToString(functionTypeRti); |
| + var functionTypeObject = extractFunctionTypeObjectFrom(value); |
| + var pretty; |
| + if (functionTypeObject != null) { |
| + pretty = runtimeTypeToString(functionTypeObject); |
| + } else { |
| + pretty = Primitives.objectTypeName(value); |
| + } |
| + throw new CastErrorImplementation(pretty, self); |
| +} |
| + |
| checkMalformedType(value, message) { |
| if (value == null) return value; |
| throw new TypeErrorImplementation.fromMessage(message); |
| @@ -3489,338 +3542,6 @@ class DeferredNotLoadedError extends Error implements NoSuchMethodError { |
| } |
| } |
| -abstract class RuntimeType { |
| - const RuntimeType(); |
| - |
| - toRti(); |
| -} |
| - |
| -class RuntimeFunctionType extends RuntimeType { |
| - final RuntimeType returnType; |
| - final List<RuntimeType> parameterTypes; |
| - final List<RuntimeType> optionalParameterTypes; |
| - final namedParameters; |
| - |
| - static var /* bool */ inAssert = false; |
| - |
| - RuntimeFunctionType(this.returnType, |
| - this.parameterTypes, |
| - this.optionalParameterTypes, |
| - this.namedParameters); |
| - |
| - 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]. |
| - @NoInline() @NoSideEffects() |
| - bool _isTest(expression) { |
| - var functionTypeObject = extractFunctionTypeObjectFrom(expression); |
| - return functionTypeObject == null |
| - ? false |
| - : isFunctionSubtype(functionTypeObject, toRti()); |
| - } |
| - |
| - @NoInline() @NoSideEffects() |
| - _asCheck(expression) { |
| - // Type inferrer doesn't think this is called with dynamic arguments. |
| - return _check(JS('', '#', expression), true); |
| - } |
| - |
| - @NoInline() @NoSideEffects() |
| - _assertCheck(expression) { |
| - if (inAssert) return null; |
| - inAssert = true; // Don't try to check this library itself. |
| - try { |
| - // Type inferrer don't think this is called with dynamic arguments. |
| - return _check(JS('', '#', expression), false); |
| - } finally { |
| - inAssert = false; |
| - } |
| - } |
| - |
| - _check(expression, bool isCast) { |
| - if (expression == null) return null; |
| - if (_isTest(expression)) return expression; |
| - |
| - var self = runtimeTypeToString(toRti()); |
| - if (isCast) { |
| - var functionTypeObject = extractFunctionTypeObjectFrom(expression); |
| - var pretty; |
| - if (functionTypeObject != null) { |
| - pretty = runtimeTypeToString(functionTypeObject); |
| - } 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 = createDartFunctionTypeRti(); |
| - if (isVoid) { |
| - JS('', '#[#] = true', result, |
| - JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG)); |
| - } else { |
| - if (returnType is! DynamicRuntimeType) { |
| - JS('', '#[#] = #', result, |
| - JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG), |
| - returnType.toRti()); |
| - } |
| - } |
| - if (parameterTypes != null && !parameterTypes.isEmpty) { |
| - JS('', '#[#] = #', result, |
| - JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG), |
| - listToRti(parameterTypes)); |
| - } |
| - |
| - if (optionalParameterTypes != null && !optionalParameterTypes.isEmpty) { |
| - JS('', '#[#] = #', result, |
| - JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG), |
| - listToRti(optionalParameterTypes)); |
| - } |
| - |
| - if (namedParameters != null) { |
| - var namedRti = JS('=Object', 'Object.create(null)'); |
| - var keys = extractKeys(namedParameters); |
| - for (var i = 0; i < keys.length; i++) { |
| - var name = keys[i]; |
| - var rti = JS('', '#[#]', namedParameters, name).toRti(); |
| - JS('', '#[#] = #', namedRti, name, rti); |
| - } |
| - JS('', '#[#] = #', result, |
| - JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG), |
| - namedRti); |
| - } |
| - |
| - return result; |
| - } |
| - |
| - static listToRti(list) { |
| - list = JS('JSFixedArray', '#', list); |
| - var result = JS('JSExtendableArray', '[]'); |
| - for (var i = 0; i < list.length; i++) { |
| - JS('', '#.push(#)', result, list[i].toRti()); |
| - } |
| - return result; |
| - } |
| - |
| - String toString() { |
| - String result = '('; |
| - bool needsComma = false; |
| - if (parameterTypes != null) { |
| - for (var i = 0; i < parameterTypes.length; i++) { |
| - RuntimeType type = parameterTypes[i]; |
| - if (needsComma) result += ', '; |
| - result += '$type'; |
| - needsComma = true; |
| - } |
| - } |
| - if (optionalParameterTypes != null && !optionalParameterTypes.isEmpty) { |
| - if (needsComma) result += ', '; |
| - needsComma = false; |
| - result += '['; |
| - for (var i = 0; i < optionalParameterTypes.length; i++) { |
| - RuntimeType type = optionalParameterTypes[i]; |
| - if (needsComma) result += ', '; |
| - result += '$type'; |
| - needsComma = true; |
| - } |
| - result += ']'; |
| - } else if (namedParameters != null) { |
| - if (needsComma) result += ', '; |
| - needsComma = false; |
| - result += '{'; |
| - var keys = extractKeys(namedParameters); |
| - for (var i = 0; i < keys.length; i++) { |
| - var name = keys[i]; |
| - if (needsComma) result += ', '; |
| - var rti = JS('', '#[#]', namedParameters, name).toRti(); |
| - result += '$rti ${JS("String", "#", name)}'; |
| - needsComma = true; |
| - } |
| - result += '}'; |
| - } |
| - |
| - result += ') -> $returnType'; |
| - return result; |
| - } |
| -} |
| - |
| -extractFunctionTypeObjectFrom(o) { |
| - var interceptor = getInterceptor(o); |
| - var signatureName = JS_GET_NAME(JsGetName.SIGNATURE_NAME); |
| - return JS('bool', '# in #', signatureName, interceptor) |
| - ? JS('', '#[#]()', interceptor, signatureName) |
| - : null; |
| -} |
| - |
| -RuntimeFunctionType buildFunctionType(returnType, |
| - parameterTypes, |
| - optionalParameterTypes) { |
| - return new RuntimeFunctionType( |
| - returnType, |
| - parameterTypes, |
| - optionalParameterTypes, |
| - null); |
| -} |
| - |
| -RuntimeFunctionType buildNamedFunctionType(returnType, |
| - parameterTypes, |
| - namedParameters) { |
| - return new RuntimeFunctionType( |
| - returnType, |
| - parameterTypes, |
| - null, |
| - namedParameters); |
| -} |
| - |
| -RuntimeType buildInterfaceType(rti, typeArguments) { |
| - String jsConstructorName = rawRtiToJsConstructorName(rti); |
| - if (typeArguments == null || typeArguments.isEmpty) { |
| - return new RuntimeTypePlain(jsConstructorName); |
| - } |
| - return new RuntimeTypeGeneric(jsConstructorName, 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(); |
| - |
| -/** |
| - * Meta helper for function type tests. |
| - * |
| - * A "meta helper" is a helper function that is never called but simulates how |
| - * generated code behaves as far as resolution and type inference is concerned. |
| - */ |
| -functionTypeTestMetaHelper() { |
| - var dyn = JS('', 'x'); |
| - var dyn2 = JS('', 'x'); |
| - List fixedListOrNull = JS('JSFixedArray|Null', 'x'); |
| - List fixedListOrNull2 = JS('JSFixedArray|Null', 'x'); |
| - List fixedList = JS('JSFixedArray', 'x'); |
| - // TODO(ahe): Can we use [UnknownJavaScriptObject] below? |
| - var /* UnknownJavaScriptObject */ jsObject = JS('=Object', 'x'); |
| - |
| - buildFunctionType(dyn, fixedListOrNull, fixedListOrNull2); |
| - buildNamedFunctionType(dyn, fixedList, jsObject); |
| - buildInterfaceType(dyn, fixedListOrNull); |
| - getDynamicRuntimeType(); |
| - getVoidRuntimeType(); |
| - convertRtiToRuntimeType(dyn); |
| - dyn._isTest(dyn2); |
| - dyn._asCheck(dyn2); |
| - dyn._assertCheck(dyn2); |
| -} |
| - |
| -RuntimeType convertRtiToRuntimeType(rti) { |
| - if (rti == null) { |
| - return getDynamicRuntimeType(); |
| - } else if (JS('bool', 'typeof # == "function"', rti)) { |
| - return new RuntimeTypePlain(JS('String', r'#.name', rti)); |
| - } 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 if (JS('bool', '"func" in #', rti)) { |
| - return new FunctionTypeInfoDecoderRing(rti).toRuntimeType(); |
| - } else { |
| - throw new RuntimeError( |
| - "Cannot convert " |
| - "'${JS('String', 'JSON.stringify(#)', rti)}' to RuntimeType."); |
| - } |
| -} |
| - |
| -class RuntimeTypePlain extends RuntimeType { |
| - /// The constructor name of this raw type. |
| - final String _jsConstructorName; |
| - |
| - RuntimeTypePlain(this._jsConstructorName); |
| - |
| - toRti() { |
| - var rti = jsConstructorNameToRti(_jsConstructorName); |
| - if (rti == null) throw "no type for '$_jsConstructorName'"; |
| - return rti; |
| - } |
| - |
| - String toString() => _jsConstructorName; |
| -} |
| - |
| -class RuntimeTypeGeneric extends RuntimeType { |
| - /// The constructor name of the raw type for this generic type. |
| - final String _jsConstructorName; |
| - final List<RuntimeType> arguments; |
| - var rti; |
| - |
| - RuntimeTypeGeneric(this._jsConstructorName, this.arguments, this.rti); |
| - |
| - toRti() { |
| - if (rti != null) return rti; |
| - var result = [jsConstructorNameToRti(_jsConstructorName)]; |
| - if (result[0] == null) { |
| - throw "no type for '$_jsConstructorName<...>'"; |
| - } |
| - for (RuntimeType argument in arguments) { |
| - result.add(argument.toRti()); |
| - } |
| - return rti = result; |
| - } |
| - |
| - String toString() => '$_jsConstructorName<${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', '!!#.v', _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); |
| - |
| - RuntimeType toRuntimeType() { |
| - // TODO(ahe): Implement this (and update return type). |
| - return const DynamicRuntimeType(); |
| - } |
| - |
| - String toString() { |
| - return _cachedToString ??= runtimeTypeToString(_typeData); |
| - } |
| -} |
| - |
| // TODO(ahe): Remove this class and call noSuchMethod instead. |
| class UnimplementedNoSuchMethodError extends Error |
| implements NoSuchMethodError { |