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

Unified Diff: sdk/lib/_internal/compiler/implementation/lib/js_rti.dart

Issue 12334070: Support runtime check of function types. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: New check encoding Created 7 years, 9 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: sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart b/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
index 559ccfbfd6e1136ee6ee497296aa649013502a95..59bbd67be4e87a5c7b402073494e261d7dbacd0d 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
@@ -15,8 +15,23 @@ getRuntimeTypeInfo(target) {
return JS('var', r'#.$builtinTypeInfo', target);
}
+forwardRuntimeTypeInfo(target, substitution, source) {
karlklose 2013/03/22 13:17:46 Is this still used?
Johnni Winther 2013/06/21 12:19:14 Removed.
+ setRuntimeTypeInfo(target,
+ substitute(substitution, getRuntimeTypeInfo(source)));
+ return target;
+}
+
+/**
+ * Returns the type arguments of [target] as an instance of [substitutionName].
+ */
+getRuntimeTypeArguments(target, substitutionName) {
+ var substitution =
+ getField(target, '${JS_OPERATOR_AS_PREFIX()}$substitutionName');
+ return substitute(substitution, getRuntimeTypeInfo(target));
+}
+
getRuntimeTypeArgument(target, substitution, index) {
- var arguments = substitute(substitution, getRuntimeTypeInfo(target));
+ var arguments = getRuntimeTypeArguments(target, substitution);
return (arguments == null) ? null : getField(arguments, index);
}
@@ -79,17 +94,28 @@ 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);
}
+Object invokeOn(function, receiver, arguments) {
+ return JS('var', r'#.apply(#, #)', function, receiver, arguments);
+}
+
Object call(target, name) => JS('var', r'#[#]()', target, name);
substitute(var substitution, var arguments) {
if (isJsArray(substitution)) {
arguments = substitution;
} else if (isJsFunction(substitution)) {
- arguments = invoke(substitution, arguments);
+ substitution = invoke(substitution, arguments);
+ if (isJsArray(substitution)) {
+ arguments = substitution;
+ } else if (isJsFunction(substitution)) {
karlklose 2013/03/22 13:17:46 Is this path used?
Johnni Winther 2013/06/21 12:19:14 Not sure. Added a TODO.
+ arguments = invoke(substitution, arguments);
+ }
}
return arguments;
}
@@ -134,6 +160,49 @@ bool checkArguments(var substitution, var arguments, var checks) {
return areSubtypes(substitute(substitution, arguments), checks);
}
+/**
+ * Checks that the type of [target] is a subtype of the function type denoted by
+ * [signatureName]. The
karlklose 2013/03/22 13:17:46 Please finish the
Johnni Winther 2013/06/21 12:19:14 Now it
+ */
+bool checkFunctionSubtype(var target, String signatureName,
+ var context, String contextName) {
+ if (isNull(target)) return false;
+ if (hasField(target, '${JS_OPERATOR_IS_PREFIX()}_$signatureName')) {
+ return true;
+ }
+ var signatureLocation = JS_CURRENT_ISOLATE();
+ if (isNotNull(context)) {
+ signatureLocation = getField(signatureLocation, contextName);
+ }
+ var typeSignature =
+ getField(signatureLocation, '${JS_SIGNATURE_NAME()}_$signatureName');
+ if (isNull(typeSignature)) {
+ // All checks can be determined statically so the type signature has not
+ // been computed.
+ return false;
+ }
+ var targetSignatureFunction = getField(target, '${JS_SIGNATURE_NAME()}');
+ var targetSignature = invokeOn(targetSignatureFunction, target, null);
karlklose 2013/03/22 13:17:46 remove space.
Johnni Winther 2013/06/21 12:19:14 Done.
+ if (isJsFunction(typeSignature)) {
+ if (context != null) {
+ typeSignature =
+ invoke(typeSignature, getRuntimeTypeArguments(context, contextName));
+ } else {
+ typeSignature = invoke(typeSignature, null);
+ }
+ }
+ return isFunctionSubtype(targetSignature, typeSignature);
+}
+
+/**
+ * Applies the type arguments of [context] as an instance of [contextName] to
+ * the signature function [signature].
+ */
+applySignature(var signature, var context, var contextName) {
+ var typeArguments = getRuntimeTypeArguments(context, contextName);
+ return invokeOn(signature, context, typeArguments);
+}
+
bool areSubtypes(List s, List t) {
// [:null:] means a raw type.
if (s == null || t == null) return true;
@@ -157,6 +226,12 @@ getArguments(var type) {
getField(var object, var name) => JS('var', r'#[#]', object, name);
+hasField(var object, var name) => JS('bool', r'#[#]', object, name);
+
+isNull(var object) => JS('bool', '# == null', object);
+
+isNotNull(var object) => JS('bool', '# != null', object);
+
/**
* Tests whether the Dart object [o] is a subtype of the runtime type
* representation [t], which is a type representation as described in the
@@ -207,6 +282,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 (hasField(t, '${JS_FUNCTION_TYPE_TAG()}')) {
+ 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;
@@ -232,4 +310,85 @@ 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;
karlklose 2013/03/22 13:17:46 What does null mean here?
Johnni Winther 2013/06/21 12:19:14 Empty lists, i.e. not arguments of that kind.
+ 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.
+ 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 (!hasField(s, '${JS_FUNCTION_TYPE_TAG()}')) return false;
+ if (hasField(s, '${JS_FUNCTION_TYPE_VOID_RETURN_TAG()}')) {
+ if (!hasField(t, '${JS_FUNCTION_TYPE_VOID_RETURN_TAG()}')) return false;
+ } else if (!hasField(t, '${JS_FUNCTION_TYPE_VOID_RETURN_TAG()}')) {
+ var sReturnType = getField(s, '${JS_FUNCTION_TYPE_RETURN_TYPE_TAG()}');
+ var tReturnType = getField(t, '${JS_FUNCTION_TYPE_RETURN_TYPE_TAG()}');
+ if (!isAssignable(sReturnType, tReturnType)) return false;
+ }
+ var sParameterTypes =
+ getField(s, '${JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG()}');
+ var tParameterTypes =
+ getField(t, '${JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG()}');
+ if (!areAssignable(sParameterTypes, tParameterTypes, false)) return false;
+ var sOptionalParameterTypes =
+ getField(s, '${JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG()}');
+ var tOptionalParameterTypes =
+ getField(t, '${JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG()}');
+ if (!areAssignable(sOptionalParameterTypes, tOptionalParameterTypes, true)) {
+ return false;
+ }
+ var sNamedParameters =
+ getField(s, '${JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG()}');
+ var tNamedParameters =
+ getField(t, '${JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG()}');
+ if (!areAssignableMaps(sNamedParameters, tNamedParameters)) return false;
+ return true;
+}
+
createRuntimeType(String name) => new TypeImpl(name);

Powered by Google App Engine
This is Rietveld 408576698