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

Unified Diff: lib/runtime/dart_runtime.js

Issue 1050723002: partially implement instance of checks and some codegen fixes (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 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
« no previous file with comments | « lib/runtime/dart/math.js ('k') | lib/src/codegen/js_codegen.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/runtime/dart_runtime.js
diff --git a/lib/runtime/dart_runtime.js b/lib/runtime/dart_runtime.js
index c872085277f70e6397360292955531d10363caef..f91a9347cac41280ed7591adf0c7ef7c044e6d5e 100644
--- a/lib/runtime/dart_runtime.js
+++ b/lib/runtime/dart_runtime.js
@@ -6,25 +6,25 @@ var dart, _js_helper;
(function (dart) {
'use strict';
- var defineProperty = Object.defineProperty;
- var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
- var getOwnPropertyNames = Object.getOwnPropertyNames;
+ let defineProperty = Object.defineProperty;
+ let getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
+ let getOwnPropertyNames = Object.getOwnPropertyNames;
// Adapted from Angular.js
- var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
- var FN_ARG_SPLIT = /,/;
- var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
- var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
+ let FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
+ let FN_ARG_SPLIT = /,/;
+ let FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
+ let STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
function formalParameterList(fn) {
- var fnText,argDecl;
- var args=[];
+ let fnText,argDecl;
+ let args=[];
fnText = fn.toString().replace(STRIP_COMMENTS, '');
argDecl = fnText.match(FN_ARGS);
- var r = argDecl[1].split(FN_ARG_SPLIT);
- for(var a in r) {
- var arg = r[a];
+ let r = argDecl[1].split(FN_ARG_SPLIT);
+ for(let a in r) {
+ let arg = r[a];
arg.replace(FN_ARG, function(all, underscore, name){
args.push(name);
});
@@ -54,12 +54,12 @@ var dart, _js_helper;
throwNoSuchMethod(obj, method, args);
}
}
- var formals = formalParameterList(f);
+ let formals = formalParameterList(f);
// TODO(vsm): Type check args! We need to encode sufficient type info on f.
if (formals.length < args.length) {
throwNoSuchMethod(obj, name, args, f);
} else if (formals.length > args.length) {
- for (var i = args.length; i < formals.length; ++i) {
+ for (let i = args.length; i < formals.length; ++i) {
if (formals[i].indexOf("opt$") != 0) {
throwNoSuchMethod(obj, name, args, f);
}
@@ -69,13 +69,13 @@ var dart, _js_helper;
}
function dinvokef(f/*, ...args*/) {
- var args = Array.prototype.slice.call(arguments, 1);
+ let args = Array.prototype.slice.call(arguments, 1);
return checkAndCall(f, void 0, args, 'call');
}
dart.dinvokef = dinvokef;
function dinvoke(obj, method/*, ...args*/) {
- var args = Array.prototype.slice.call(arguments, 2);
+ let args = Array.prototype.slice.call(arguments, 2);
return checkAndCall(obj[method], obj, args, method);
}
dart.dinvoke = dinvoke;
@@ -95,19 +95,157 @@ var dart, _js_helper;
}
dart.dbinary = dbinary;
- function as_(obj, type) {
- // TODO(vsm): Implement.
- // if (obj == null || is(obj, type)) return obj;
- // throw new core.CastError();
- return obj;
+ function cast(obj, type) {
+ //TODO(vsm): handle non-nullable types
+ if (obj == null) return obj;
+ let actual = getRuntimeType(obj);
+ if (isSubtype(actual, type)) return obj;
+ throw new _js_helper.CastErrorImplementation(actual, type);
}
- dart.as = as_;
+ dart.as = cast;
- function is(obj, type) {
- // TODO(vsm): Implement.
- throw new core.UnimplementedError();
+ /**
+ * Returns the runtime type of obj. This is the same as `obj.runtimeType`
+ * but will not call an overridden getter.
+ *
+ * Currently this will return null for non-Dart objects.
+ */
+ function getRuntimeType(obj) {
+ switch (typeof obj) {
+ case "undefined":
+ return core.Null;
+ case "number":
+ return Math.floor(obj) == obj ? core.int : core.double;
+ case "boolean":
+ return core.bool;
+ case "string":
+ return core.String;
+ case "symbol":
+ return Symbol;
+ }
+ // Undefined is handled above. For historical reasons,
+ // typeof null == "object" in JS.
+ if (obj === null) return core.Null;
+ return obj.constructor;
+ }
+ dart.getRuntimeType = getRuntimeType;
+
+ function instanceOf(obj, type) {
+ return isSubtype(getRuntimeType(obj), type);
+ }
+ dart.is = instanceOf;
+
+ /**
+ * Computes the canonical type.
+ * This maps JS types onto their corresponding Dart Type.
+ */
+ // TODO(jmesserly): lots more needs to be done here.
+ function canonicalType(t) {
+ if (t === Object) return core.Object;
+ if (t === Function) return core.Function;
+ if (t === Array) return core.List;
+
+ // We shouldn't normally get here with these types, unless something strange
+ // happens like subclassing Number in JS and passing it to Dart.
+ if (t === String) return core.String;
+ if (t === Number) return core.double;
+ if (t === Boolean) return core.bool;
+ return t;
+ }
+
+ let subtypeMap = new Map();
+ function isSubtype(t1, t2) {
+ // See if we already know the answer
+ // TODO(jmesserly): general purpose memoize function?
+ let map = subtypeMap.get(t1);
+ let result;
+ if (map) {
+ result = map.get(t2);
+ if (result !== void 0) return result;
+ } else {
+ subtypeMap.set(t1, map = new Map());
+ }
+ map.set(t2, result = isSubtype_(t1, t2));
+ return result;
+ }
+ dart.isSubtype = isSubtype;
+
+ function isSubtype_(t1, t2) {
+ t1 = canonicalType(t1);
+ t2 = canonicalType(t2);
+ if (t1 == t2) return true;
+
+ // In Dart, dynamic is effectively both top and bottom.
+ // Here, we treat dynamic as top - the base type of everything.
+ if (t1 == dart.dynamic) return false;
+ if (t2 == dart.dynamic) return true;
+
+ if (t2 == core.Object) return true;
+ if (t1 == core.Object) return false;
+
+ // "Traditional" name-based subtype check.
+ if (isClassSubType(t1, t2)) {
+ return true;
+ }
+
+ // Function subtyping.
+ // TODO(jmesserly): implement.
+ return false;
+ }
+
+ function safeGetOwnProperty(obj, name) {
+ var desc = getOwnPropertyDescriptor(obj, name);
+ if (desc) return desc.value;
+ }
+
+ function isClassSubType(t1, t2) {
+ // We support Dart's covariant generics with the caveat that we do not
+ // substitute bottom for dynamic in subtyping rules.
+ // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow:
+ // - S !<: S<T1, ..., Tn>
+ // - S<dynamic, ..., dynamic> !<: S<T1, ..., Tn>
+ if (t1 == t2) return true;
+
+ if (t1 == core.Object) return false;
+
+ // Check if t1 and t2 have the same raw type. If so, check covariance on
+ // type parameters.
+ let raw1 = safeGetOwnProperty(t1, dart.originalDeclaration);
+ let raw2 = safeGetOwnProperty(t2, dart.originalDeclaration);
+ if (raw1 != null && raw1 == raw2) {
+ let typeArguments1 = safeGetOwnProperty(t1, dart.typeArguments);
+ let typeArguments2 = safeGetOwnProperty(t2, dart.typeArguments);
+ let length = typeArguments1.length;
+ if (typeArguments2.length == 0) {
+ // t2 is the raw form of t1
+ return true;
+ } else if (length == 0) {
+ // t1 is raw, but t2 is not
+ return false;
+ }
+ assert(length == typeArguments2.length);
+ for (let i = 0; i < length; ++i) {
+ if (!isSubtype(typeArguments1[i], typeArguments2[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Check superclass.
+ if (isClassSubType(t1.__proto__, t2)) return true;
+
+ // Check interfaces.
+ let getInterfaces = safeGetOwnProperty(t1, dart.implements);
+ if (getInterfaces) {
+ for (let i1 of getInterfaces()) {
+ // TODO(jmesserly): remove the != null check once we can load core libs.
+ if (i1 != null && isClassSubType(i1, t2)) return true;
+ }
+ }
+
+ return false;
}
- dart.is = is;
function closureWrap(obj, type) {
// TODO(vsm): Remove this once we handle in the checker.
@@ -115,21 +253,30 @@ var dart, _js_helper;
}
dart.closureWrap = closureWrap;
+
+ // TODO(jmesserly): this isn't currently used, but it could be if we want
+ // `obj is NonGroundType<T,S>` to be rejected at runtime instead of compile
+ // time. Also TODO: update this to handle functions.
function isGroundType(type) {
- // TODO(vsm): Implement.
- throw new core.UnimplementedError();
+ let typeArgs = safeGetOwnProperty(type, dart.typeArguments);
+ if (!typeArgs) return true;
+ for (let t of typeArgs) {
+ if (t != core.Object && t != dart.dynamic) return false;
+ }
+ return true;
}
dart.isGroundType = isGroundType;
function arity(f) {
- // TODO(vsm): Implement.
- throw new core.UnimplementedError();
+ // TODO(jmesserly): need to parse optional params.
+ // In ES6, length is the number of required arguments.
+ return { min: f.length, max: f.length };
}
dart.arity = arity;
function equals(x, y) {
if (x == null || y == null) return x == y;
- var eq = x['=='];
+ let eq = x['=='];
return eq ? eq.call(x, y) : x == y;
}
dart.equals = equals;
@@ -149,19 +296,19 @@ var dart, _js_helper;
// TODO(jmesserly): reusing descriptor objects has been shown to improve
// performance in other projects (e.g. webcomponents.js ShadowDOM polyfill).
function defineLazyProperty(to, name, desc) {
- var init = desc.get;
- var writable = !!desc.set;
+ let init = desc.get;
+ let writable = !!desc.set;
function lazySetter(value) {
defineProperty(to, name, { value: value, writable: writable });
}
function lazyGetter() {
// Clear the init function to detect circular initialization.
- var f = init;
+ let f = init;
if (f === null) throw 'circular initialization for field ' + name;
init = null;
// Compute and store the value.
- var value = f();
+ let value = f();
lazySetter(value);
return value;
}
@@ -172,9 +319,9 @@ var dart, _js_helper;
}
function defineLazy(to, from) {
- var names = getOwnPropertyNames(from);
- for (var i = 0; i < names.length; i++) {
- var name = names[i];
+ let names = getOwnPropertyNames(from);
+ for (let i = 0; i < names.length; i++) {
+ let name = names[i];
defineLazyProperty(to, name, getOwnPropertyDescriptor(from, name));
}
}
@@ -188,9 +335,9 @@ var dart, _js_helper;
* This operation is commonly called `mixin` in JS.
*/
function copyProperties(to, from) {
- var names = getOwnPropertyNames(from);
- for (var i = 0; i < names.length; i++) {
- var name = names[i];
+ let names = getOwnPropertyNames(from);
+ for (let i = 0; i < names.length; i++) {
+ let name = names[i];
defineProperty(to, name, getOwnPropertyDescriptor(from, name));
}
return to;
@@ -200,7 +347,7 @@ var dart, _js_helper;
/** The Symbol for storing type arguments on a specialized generic type. */
dart.mixins = Symbol('mixins');
- dart.implements = Symbol('implements')
+ dart.implements = Symbol('implements');
/**
* Returns a new type that mixes members from base and all mixins.
@@ -214,7 +361,7 @@ var dart, _js_helper;
function mixin(base/*, ...mixins*/) {
// Create an initializer for the mixin, so when derived constructor calls
// super, we can correctly initialize base and mixins.
- var mixins = Array.prototype.slice.call(arguments, 1);
+ let mixins = Array.prototype.slice.call(arguments, 1);
// Create a class that will hold all of the mixin methods.
class Mixin extends base {
@@ -222,8 +369,8 @@ var dart, _js_helper;
[base.name](/*...args*/) {
// Run mixin initializers. They cannot have arguments.
// Run them backwards so most-derived mixin is initialized first.
- for (var i = mixins.length - 1; i >= 0; i--) {
- var mixin = mixins[i];
+ for (let i = mixins.length - 1; i >= 0; i--) {
+ let mixin = mixins[i];
mixin.prototype[mixin.name].call(this);
}
// Run base initializer.
@@ -231,8 +378,8 @@ var dart, _js_helper;
}
}
// Copy each mixin's methods, with later ones overwriting earlier entries.
- for (var i = 0; i < mixins.length; i++) {
- copyProperties(Mixin.prototype, mixins[i].prototype);
+ for (let m of mixins) {
+ copyProperties(Mixin.prototype, m.prototype);
}
// Save mixins for reflection
Mixin[dart.mixins] = mixins;
@@ -255,19 +402,16 @@ var dart, _js_helper;
*/
// TODO(jmesserly): this could be faster
function map(values) {
- var map = new collection.LinkedHashMap();
+ let map = new collection.LinkedHashMap();
if (Array.isArray(values)) {
- for (var i = 0, end = values.length - 1; i < end; i += 2) {
- var key = values[i];
- var value = values[i + 1];
+ for (let i = 0, end = values.length - 1; i < end; i += 2) {
+ let key = values[i];
+ let value = values[i + 1];
map.set(key, value);
}
} else if (typeof values === 'object') {
- var keys = Object.getOwnPropertyNames(values);
- for (var i = 0; i < keys.length; i++) {
- var key = keys[i];
- var value = values[key];
- map.set(key, value);
+ for (let key of Object.getOwnPropertyNames(values)) {
+ map.set(key, values[key]);
}
}
return map;
@@ -288,9 +432,9 @@ var dart, _js_helper;
* function with the same name. For example `new SomeClass.name(args)`.
*/
function defineNamedConstructor(clazz, name) {
- var proto = clazz.prototype;
- var initMethod = proto[name];
- var ctor = function() { return initMethod.apply(this, arguments); }
+ let proto = clazz.prototype;
+ let initMethod = proto[name];
+ let ctor = function() { return initMethod.apply(this, arguments); }
ctor.prototype = proto;
clazz[name] = ctor;
}
@@ -302,33 +446,37 @@ var dart, _js_helper;
dart.stackTrace = stackTrace;
/** The Symbol for storing type arguments on a specialized generic type. */
- dart.typeSignature = Symbol('typeSignature');
+ dart.typeArguments = Symbol('typeArguments');
+ dart.originalDeclaration = Symbol('originalDeclaration');
/** Memoize a generic type constructor function. */
function generic(typeConstructor) {
- var length = typeConstructor.length;
- if (length < 1) throw 'must have at least one generic type argument';
+ let length = typeConstructor.length;
+ if (length < 1) throw Error('must have at least one generic type argument');
- var resultMap = new Map();
+ let resultMap = new Map();
function makeGenericType(/*...arguments*/) {
if (arguments.length != length && arguments.length != 0) {
- throw 'requires ' + length + ' or 0 type arguments';
+ throw Error('requires ' + length + ' or 0 type arguments');
}
-
- var value = resultMap;
- for (var i = 0; i < length; i++) {
- var arg = arguments[i];
- if (arg === void 0) arg = dart.dynamic;
-
- var map = value;
+ let args = Array.prototype.slice.call(arguments);
+ while (args.length < length) args.push(dart.dynamic);
+
+ let value = resultMap;
+ for (let i = 0; i < length; i++) {
+ let arg = args[i];
+ if (arg == null) {
+ throw Error('type arguments should not be null: ' + typeConstructor);
+ }
+ let map = value;
value = map.get(arg);
if (value === void 0) {
if (i + 1 == length) {
- value = typeConstructor.apply(null, arguments);
+ value = typeConstructor.apply(null, args);
// Save the type constructor and arguments for reflection.
if (value) {
- var args = Array.prototype.slice.call(arguments);
- value[dart.typeSignature] = [makeGenericType].concat(args);
+ value[dart.typeArguments] = args;
+ value[dart.originalDeclaration] = makeGenericType;
}
} else {
value = new Map();
@@ -344,7 +492,7 @@ var dart, _js_helper;
// TODO(jmesserly): right now this is a sentinel. It should be a type object
// of some sort, assuming we keep around `dynamic` at runtime.
- dart.dynamic = Object.create(null);
+ dart.dynamic = { toString() { return 'dynamic'; } };
dart.JsSymbol = Symbol;
« no previous file with comments | « lib/runtime/dart/math.js ('k') | lib/src/codegen/js_codegen.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698