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 { |