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

Side by Side Diff: lib/runtime/dart_runtime.js

Issue 1076883003: Initial support for runtime function types and type checking (Closed) Base URL: https://github.com/dart-lang/dev_compiler.git@master
Patch Set: uncomment code Created 5 years, 8 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 var dart, _js_helper; 5 var dart, _js_helper;
6 (function (dart) { 6 (function (dart) {
7 'use strict'; 7 'use strict';
8 8
9 let defineProperty = Object.defineProperty; 9 let defineProperty = Object.defineProperty;
10 let getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; 10 let getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 case "boolean": 119 case "boolean":
120 return core.bool; 120 return core.bool;
121 case "string": 121 case "string":
122 return core.String; 122 return core.String;
123 case "symbol": 123 case "symbol":
124 return Symbol; 124 return Symbol;
125 } 125 }
126 // Undefined is handled above. For historical reasons, 126 // Undefined is handled above. For historical reasons,
127 // typeof null == "object" in JS. 127 // typeof null == "object" in JS.
128 if (obj === null) return core.Null; 128 if (obj === null) return core.Null;
129 return obj.constructor; 129 // TODO(vsm): Should we explicitly check if this is a core.Object?
Jennifer Messerly 2015/04/09 18:44:28 I wondered this too, but since we didn't need it y
vsm 2015/04/09 19:52:25 Changed the comment a bit. I think my real questi
130 var result = obj[dart.runtimeType];
Jennifer Messerly 2015/04/09 18:44:28 what does this do? are you trying to call the Obje
vsm 2015/04/09 19:52:24 It's only used by tests are the moment. I was usi
131 if (result) return result;
132 result = obj.constructor;
133 if (result == Function) {
134 return getFunctionType(obj);
135 }
136 return result;
130 } 137 }
131 dart.getRuntimeType = getRuntimeType; 138 dart.getRuntimeType = getRuntimeType;
132 139
133 function instanceOf(obj, type) { 140 function instanceOf(obj, type) {
134 return isSubtype(getRuntimeType(obj), type); 141 return isSubtype(getRuntimeType(obj), type);
135 } 142 }
136 dart.is = instanceOf; 143 dart.is = instanceOf;
137 144
138 /** 145 /**
139 * Computes the canonical type. 146 * Computes the canonical type.
(...skipping 23 matching lines...) Expand all
163 result = map.get(t2); 170 result = map.get(t2);
164 if (result !== void 0) return result; 171 if (result !== void 0) return result;
165 } else { 172 } else {
166 subtypeMap.set(t1, map = new Map()); 173 subtypeMap.set(t1, map = new Map());
167 } 174 }
168 map.set(t2, result = isSubtype_(t1, t2)); 175 map.set(t2, result = isSubtype_(t1, t2));
169 return result; 176 return result;
170 } 177 }
171 dart.isSubtype = isSubtype; 178 dart.isSubtype = isSubtype;
172 179
173 function isSubtype_(t1, t2) { 180 function _isBottom(type, dynamicIsBottom) {
181 return (type == dart.dynamic && dynamicIsBottom) || type == dart.bottom;
182 }
183
184 function _isTop(type, dynamicIsBottom) {
185 return type == core.Object || (type == dart.dynamic && !dynamicIsBottom);
186 }
187
188 function isSubtype_(t1, t2, opt_dynamicIsBottom) {
189 let dynamicIsBottom =
190 opt_dynamicIsBottom === void 0 ? false : opt_dynamicIsBottom;
191
174 t1 = canonicalType(t1); 192 t1 = canonicalType(t1);
175 t2 = canonicalType(t2); 193 t2 = canonicalType(t2);
176 if (t1 == t2) return true; 194 if (t1 == t2) return true;
177 195
178 // In Dart, dynamic is effectively both top and bottom. 196 // In Dart, dynamic is effectively both top and bottom.
179 // Here, we treat dynamic as top - the base type of everything. 197 // Here, we treat dynamic as one or the other depending on context,
180 if (t1 == dart.dynamic) return false; 198 // but not both.
181 if (t2 == dart.dynamic) return true;
182 199
183 if (t2 == core.Object) return true; 200 // Trivially true.
184 if (t1 == core.Object) return false; 201 if (_isTop(t2, dynamicIsBottom) || _isBottom(t1, dynamicIsBottom)) return tr ue;
Jennifer Messerly 2015/04/09 18:44:28 some long lines here
vsm 2015/04/09 19:52:24 Done. The dart formatter has made me lazy on this
202
203 // Trivially false.
204 if (_isTop(t1, dynamicIsBottom) || _isBottom(t2, dynamicIsBottom)) return fa lse;
185 205
186 // "Traditional" name-based subtype check. 206 // "Traditional" name-based subtype check.
187 if (isClassSubType(t1, t2)) { 207 if (isClassSubType(t1, t2)) {
188 return true; 208 return true;
189 } 209 }
190 210
191 // Function subtyping. 211 // Function subtyping.
192 // TODO(jmesserly): implement this properly. 212 // TODO(vsm): Handle Objects with call methods. Those are functions
Jennifer Messerly 2015/04/09 18:44:28 does dart_runtime.dart handle this case? it would
vsm 2015/04/09 19:52:25 Yes.
193 if (isClassSubType(t1, core.Function) && 213 // even if they do not *nominally* subtype core.Function.
194 isClassSubType(t2, core.Function)) { 214 if (isFunctionType(t1) &&
195 return true; 215 isFunctionType(t2)) {
216 return isFunctionSubType(t1, t2);
196 } 217 }
197 return false; 218 return false;
198 } 219 }
199 220
200 function safeGetOwnProperty(obj, name) { 221 function safeGetOwnProperty(obj, name) {
201 var desc = getOwnPropertyDescriptor(obj, name); 222 var desc = getOwnPropertyDescriptor(obj, name);
202 if (desc) return desc.value; 223 if (desc) return desc.value;
203 } 224 }
204 225
205 function isClassSubType(t1, t2) { 226 function isClassSubType(t1, t2) {
206 // We support Dart's covariant generics with the caveat that we do not 227 // We support Dart's covariant generics with the caveat that we do not
207 // substitute bottom for dynamic in subtyping rules. 228 // substitute bottom for dynamic in subtyping rules.
208 // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow: 229 // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow:
209 // - S !<: S<T1, ..., Tn> 230 // - S !<: S<T1, ..., Tn>
210 // - S<dynamic, ..., dynamic> !<: S<T1, ..., Tn> 231 // - S<dynamic, ..., dynamic> !<: S<T1, ..., Tn>
211 if (t1 == t2) return true; 232 if (t1 == t2) return true;
212 233
213 if (t1 == core.Object) return false; 234 if (t1 == core.Object) return false;
214 235
236 // If t1 is a JS Object, we may not hit core.Object.
237 if (t1 == null) return t2 == core.Object || t2 == dart.dynamic;
Jennifer Messerly 2015/04/09 18:44:29 Hmmm, canonicalType was supposed to be handling th
vsm 2015/04/09 19:52:25 Yeah, I was hitting this at runtime.
238
215 // Check if t1 and t2 have the same raw type. If so, check covariance on 239 // Check if t1 and t2 have the same raw type. If so, check covariance on
216 // type parameters. 240 // type parameters.
217 let raw1 = safeGetOwnProperty(t1, dart.originalDeclaration); 241 let raw1 = safeGetOwnProperty(t1, dart.originalDeclaration);
218 let raw2 = safeGetOwnProperty(t2, dart.originalDeclaration); 242 let raw2 = safeGetOwnProperty(t2, dart.originalDeclaration);
219 if (raw1 != null && raw1 == raw2) { 243 if (raw1 != null && raw1 == raw2) {
220 let typeArguments1 = safeGetOwnProperty(t1, dart.typeArguments); 244 let typeArguments1 = safeGetOwnProperty(t1, dart.typeArguments);
221 let typeArguments2 = safeGetOwnProperty(t2, dart.typeArguments); 245 let typeArguments2 = safeGetOwnProperty(t2, dart.typeArguments);
222 let length = typeArguments1.length; 246 let length = typeArguments1.length;
223 if (typeArguments2.length == 0) { 247 if (typeArguments2.length == 0) {
224 // t2 is the raw form of t1 248 // t2 is the raw form of t1
(...skipping 28 matching lines...) Expand all
253 if (getInterfaces) { 277 if (getInterfaces) {
254 for (let i1 of getInterfaces()) { 278 for (let i1 of getInterfaces()) {
255 // TODO(jmesserly): remove the != null check once we can load core libs. 279 // TODO(jmesserly): remove the != null check once we can load core libs.
256 if (i1 != null && isClassSubType(i1, t2)) return true; 280 if (i1 != null && isClassSubType(i1, t2)) return true;
257 } 281 }
258 } 282 }
259 283
260 return false; 284 return false;
261 } 285 }
262 286
263 function closureWrap(obj, type) {
264 // TODO(vsm): Remove this once we handle in the checker.
265 return obj;
266 }
267 dart.closureWrap = closureWrap;
268
269
270 // TODO(jmesserly): this isn't currently used, but it could be if we want 287 // TODO(jmesserly): this isn't currently used, but it could be if we want
271 // `obj is NonGroundType<T,S>` to be rejected at runtime instead of compile 288 // `obj is NonGroundType<T,S>` to be rejected at runtime instead of compile
272 // time. Also TODO: update this to handle functions. 289 // time.
273 function isGroundType(type) { 290 function isGroundType(type) {
291 // TODO(vsm): Cache this if we start using it at runtime.
292
293 if (type instanceof AbstractFunctionType) {
294 if (!_isTop(type.returnType, false)) return false;
295 for (var i = 0; i < type.args.length; ++i) {
296 if (!_isBottom(type.args[i], true)) return false;
297 }
298 for (var i = 0; i < type.optionals.length; ++i) {
299 if (!_isBottom(type.optionals[i], true)) return false;
300 }
301 var names = Object.getOwnPropertyNames(type.named);
302 for (var i = 0; i < names.length; ++i) {
303 if (!_isBottom(type.named[names[i]], true)) return false;
304 }
305 return true;
306 }
307
274 let typeArgs = safeGetOwnProperty(type, dart.typeArguments); 308 let typeArgs = safeGetOwnProperty(type, dart.typeArguments);
275 if (!typeArgs) return true; 309 if (!typeArgs) return true;
276 for (let t of typeArgs) { 310 for (let t of typeArgs) {
277 if (t != core.Object && t != dart.dynamic) return false; 311 if (t != core.Object && t != dart.dynamic) return false;
278 } 312 }
279 return true; 313 return true;
280 } 314 }
281 dart.isGroundType = isGroundType; 315 dart.isGroundType = isGroundType;
282 316
283 function arity(f) { 317 function arity(f) {
(...skipping 10 matching lines...) Expand all
294 } 328 }
295 dart.equals = equals; 329 dart.equals = equals;
296 330
297 /** Checks that `x` is not null or undefined. */ 331 /** Checks that `x` is not null or undefined. */
298 function notNull(x) { 332 function notNull(x) {
299 if (x == null) throw 'expected not-null value'; 333 if (x == null) throw 'expected not-null value';
300 return x; 334 return x;
301 } 335 }
302 dart.notNull = notNull; 336 dart.notNull = notNull;
303 337
338 function _typeName(type) {
339 // TODO(vsm): Common type object?
Jennifer Messerly 2015/04/09 18:44:28 we could, it's kind of nice to reuse the JS type o
Jennifer Messerly 2015/04/09 18:47:24 having said that, we can certainly have a differen
vsm 2015/04/09 19:52:25 That's a good point.
340 if (type instanceof AbstractFunctionType) return type.toString();
Jennifer Messerly 2015/04/09 18:44:29 could you just set a `name` property on this?
vsm 2015/04/09 19:52:25 Done.
341 var name = type.name;
342 if (name) return name;
343 return type.toString();
Jennifer Messerly 2015/04/09 18:44:28 does this happen?
vsm 2015/04/09 19:52:25 Doesn't seem to. Changed the code to throw.
344 }
345
346 class AbstractFunctionType {
347 constructor() {
348 this._stringValue = null;
349 }
350
351 toString() {
352 if (this._stringValue) return this._stringValue;
353
354 var buffer = '(';
355 for (var i = 0; i < this.args.length; ++i) {
356 if (i > 0) {
357 buffer += ', ';
358 }
359 buffer += _typeName(this.args[i]);
360 }
361 if (this.optionals.length > 0) {
362 if (this.args.length > 0) buffer += ', ';
363 buffer += '[';
364 for (var i = 0; i < this.optionals.length; ++i) {
365 if (i > 0) {
366 buffer += ', ';
367 }
368 buffer += _typeName(this.optionals[i]);
369 }
370 buffer += ']';
371 } else if (this.named.length > 0) {
372 if (this.args.length > 0) buffer += ', ';
373 buffer += '{';
374 let names = Object.getOwnPropertyNames(this.named).sort();
375 for (var i = 0; i < names.length; ++i) {
376 if (i > 0) {
377 buffer += ', ';
378 }
379 buffer += names[i] + ': ' + _typeName(this.named[names[i]]);
380 }
381 buffer += '}';
382 }
383
384 buffer += ') -> ' + _typeName(this.returnType);
385 this._stringValue = buffer;
386 return buffer;
387 }
388 }
389
390 class FunctionType extends AbstractFunctionType {
391 constructor(returnType, args, optionals, named) {
392 super();
393 this.returnType = returnType;
394 this.args = args;
395 this.optionals = optionals;
396 this.named = named;
397 }
398 }
399
400 function functionType(returnType, args, extra) {
401 // TODO(vsm): Cache / memomize?
402 var optionals;
403 var named;
404 if (extra === void 0) {
405 optionals = [];
406 named = {};
407 } else if (extra instanceof Array) {
408 optionals = extra;
409 named = {};
410 } else {
411 optionals = [];
412 named = extra;
413 }
414 return new FunctionType(returnType, args, optionals, named);
415 }
416 dart.functionType = functionType;
417
418 class Typedef extends AbstractFunctionType {
419 constructor(name, closure) {
420 super();
421 this._name = name;
422 this._closure = closure;
423 this._functionType = null;
424 }
425
426 toString() {
427 return this._name;
428 }
429
430 get functionType() {
431 if (!this._functionType) {
432 this._functionType = this._closure();
433 }
434 return this._functionType;
435 }
436
437 get returnType() {
438 return this.functionType.returnType;
439 }
440
441 get args() {
442 return this.functionType.args;
443 }
444
445 get optionals() {
446 return this.functionType.optionals;
447 }
448
449 get named() {
450 return this.functionType.named;
451 }
452 }
453
454 function typedef(name, closure) {
455 return new Typedef(name, closure);
456 }
457 dart.typedef = typedef;
458
459 function isFunctionType(type) {
460 return isClassSubType(type, core.Function) || type instanceof AbstractFuncti onType;
461 }
462
463 function getFunctionType(obj) {
464 // TODO(vsm): Encode this properly on the function for Dart-generated code.
465 var args = Array.apply(null, new Array(obj.length)).map(function(){return co re.Object});
466 return functionType(dart.bottom, args);
467 }
468
469 function isFunctionSubType(ft1, ft2) {
470 if (ft2 == core.Function) {
471 return true;
472 }
473
474 let ret1 = ft1.returnType;
475 let ret2 = ft2.returnType;
476
477 if (!isSubtype_(ret1, ret2)) {
478 // Covariant return types
479 // Note, void (which can only appear as a return type) is effectively
480 // treated as dynamic. If the base return type is void, we allow any
481 // subtype return type.
482 // E.g., we allow:
483 // () -> int <: () -> void
484 if (ret2 != dart.void) {
485 return false;
486 }
487 }
488
489 let args1 = ft1.args;
490 let args2 = ft2.args;
491
492 if (args1.length > args2.length) {
493 return false;
494 }
495
496 for (var i = 0; i < args1.length; ++i) {
497 if (!isSubtype_(args2[i], args1[i], true)) {
498 return false;
499 }
500 }
501
502 let optionals1 = ft1.optionals;
503 let optionals2 = ft2.optionals;
504
505 if (args1.length + optionals1.length < args2.length + optionals2.length) {
506 return false;
507 }
508
509 var j = 0;
510 for (var i = args1.length; i < args2.length; ++i, ++j) {
511 if (!isSubtype_(args2[i], optionals1[j], true)) {
512 return false;
513 }
514 }
515
516 for (var i = 0; i < optionals2.length; ++i, ++j) {
517 if (!isSubtype_(optionals2[i], optionals1[j], true)) {
518 return false;
519 }
520 }
521
522 let named1 = ft1.named;
523 let named2 = ft2.named;
524
525 let names = Object.getOwnPropertyNames(named2);
526 for (var i = 0; i < names.length; ++i) {
527 let name = names[i];
528 let n1 = named1[name]
529 let n2 = named2[name];
530 if (n1 === void 0) {
531 return false;
532 }
533 if (!isSubtype_(n2, n1, true)) {
534 return false;
535 }
536 }
537
538 return true;
539 }
540
304 /** 541 /**
305 * Defines a lazy property. 542 * Defines a lazy property.
306 * After initial get or set, it will replace itself with a value property. 543 * After initial get or set, it will replace itself with a value property.
307 */ 544 */
308 // TODO(jmesserly): is this the best implementation for JS engines? 545 // TODO(jmesserly): is this the best implementation for JS engines?
309 // TODO(jmesserly): reusing descriptor objects has been shown to improve 546 // TODO(jmesserly): reusing descriptor objects has been shown to improve
310 // performance in other projects (e.g. webcomponents.js ShadowDOM polyfill). 547 // performance in other projects (e.g. webcomponents.js ShadowDOM polyfill).
311 function defineLazyProperty(to, name, desc) { 548 function defineLazyProperty(to, name, desc) {
312 let init = desc.get; 549 let init = desc.get;
313 let writable = !!desc.set; 550 let writable = !!desc.set;
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
501 } 738 }
502 return value; 739 return value;
503 } 740 }
504 return makeGenericType; 741 return makeGenericType;
505 } 742 }
506 dart.generic = generic; 743 dart.generic = generic;
507 744
508 // TODO(jmesserly): right now this is a sentinel. It should be a type object 745 // TODO(jmesserly): right now this is a sentinel. It should be a type object
509 // of some sort, assuming we keep around `dynamic` at runtime. 746 // of some sort, assuming we keep around `dynamic` at runtime.
510 dart.dynamic = { toString() { return 'dynamic'; } }; 747 dart.dynamic = { toString() { return 'dynamic'; } };
748 dart.void = { toString() { return 'void'; } };
749 dart.bottom = { toString() { return 'bottom'; } };
750
751 // TODO(vsm): How should we encode the runtime type?
752 dart.runtimeType = Symbol('runtimeType');
511 753
512 dart.JsSymbol = Symbol; 754 dart.JsSymbol = Symbol;
513 755
514 // TODO(jmesserly): hack to bootstrap the SDK 756 // TODO(jmesserly): hack to bootstrap the SDK
515 _js_helper = _js_helper || {}; 757 _js_helper = _js_helper || {};
516 _js_helper.checkNum = notNull; 758 _js_helper.checkNum = notNull;
517 759
518 })(dart || (dart = {})); 760 })(dart || (dart = {}));
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698