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

Side by Side Diff: tool/input_sdk/private/types.dart

Issue 1530563003: Generate all runtime files from dart. (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Reverted to new .dart files in input_sdk: please compare them against previous patchset Created 5 years 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 /// This library defines the representation of runtime types.
6
7 library dart._types;
8
9 import 'dart:_foreign_helper' show JS, JsName;
10
11 import 'dart:_classes' show getGenericClass, getGenericArgs, getMixins, getImple ments;
12 import 'dart:_rtti' show LazyTagged, read;
13 import 'dart:_utils' as utils;
14
15 @JsName('assert')
16 final assert_ = JS('', '${utils.assert_}');
17 final getOwnPropertyNames = JS('', 'Object.getOwnPropertyNames');
18
19 ///
20 /// Types in dart are represented at runtime as follows.
21 /// - Normal nominal types, produced from classes, are represented
22 /// at runtime by the JS class of which they are an instance.
23 /// If the type is the result of instantiating a generic class,
24 /// then the "classes" module manages the association between the
25 /// instantiated class and the original class declaration
26 /// and the type arguments with which it was instantiated. This
27 /// assocation can be queried via the "classes" module".
28 ///
29 /// - All other types are represented as instances of class TypeRep,
30 /// defined in this module.
31 /// - Dynamic, Void, and Bottom are singleton instances of sentinal
32 /// classes.
33 /// - Function types are instances of subclasses of AbstractFunctionType.
34 ///
35 /// Function types are represented in one of two ways:
36 /// - As an instance of FunctionType. These are eagerly computed.
37 /// - As an instance of TypeDef. The TypeDef representation lazily
38 /// computes an instance of FunctionType, and delegates to that instance.
39 ///
40 /// All types satisfy the following interface:
41 /// get String name;
42 /// String toString();
43 ///
44 ///
45 final TypeRep = JS('', '''
46 class TypeRep extends $LazyTagged(() => $Type) {
47 get name() {return this.toString();}
48 }
49 ''');
50
51 final Dynamic = JS('', '''
52 class Dynamic extends $TypeRep {
53 toString() { return "dynamic"; }
54 }
55 ''');
56 @JsName('dynamic')
57 final dynamicR = JS('', 'new $Dynamic()');
58
59 final Void = JS('', '''
60 class Void extends $TypeRep {
61 toString() { return "void"; }
62 }
63 ''');
64
65 @JsName('void')
66 final voidR = JS('', 'new $Void()');
67
68 final Bottom = JS('', '''
69 class Bottom extends $TypeRep {
70 toString() { return "bottom"; }
71 }
72 ''');
73 final bottom = JS('', 'new $Bottom()');
74
75 final JSObject = JS('', '''
76 class JSObject extends $TypeRep {
77 toString() { return "NativeJavaScriptObject"; }
78 }
79 ''');
80 final jsobject = JS('', 'new $JSObject()');
81
82 final AbstractFunctionType = JS('', '''
83 class AbstractFunctionType extends $TypeRep {
84 constructor() {
85 super();
86 this._stringValue = null;
87 }
88
89 toString() { return this.name; }
90
91 get name() {
92 if (this._stringValue) return this._stringValue;
93
94 let buffer = '(';
95 for (let i = 0; i < this.args.length; ++i) {
96 if (i > 0) {
97 buffer += ', ';
98 }
99 buffer += $typeName(this.args[i]);
100 }
101 if (this.optionals.length > 0) {
102 if (this.args.length > 0) buffer += ', ';
103 buffer += '[';
104 for (let i = 0; i < this.optionals.length; ++i) {
105 if (i > 0) {
106 buffer += ', ';
107 }
108 buffer += $typeName(this.optionals[i]);
109 }
110 buffer += ']';
111 } else if (Object.keys(this.named).length > 0) {
112 if (this.args.length > 0) buffer += ', ';
113 buffer += '{';
114 let names = $getOwnPropertyNames(this.named).sort();
115 for (let i = 0; i < names.length; ++i) {
116 if (i > 0) {
117 buffer += ', ';
118 }
119 buffer += names[i] + ': ' + $typeName(this.named[names[i]]);
120 }
121 buffer += '}';
122 }
123
124 buffer += ') -> ' + $typeName(this.returnType);
125 this._stringValue = buffer;
126 return buffer;
127 }
128 }
129 ''');
130
131 final FunctionType = JS('', '''
132 class FunctionType extends $AbstractFunctionType {
133 /**
134 * Construct a function type. There are two arrow constructors,
135 * distinguished by the "definite" flag.
136 *
137 * The fuzzy arrow (definite is false) treats any arguments
138 * of type dynamic as having type bottom, and will always be
139 * called with a dynamic invoke.
140 *
141 * The definite arrow (definite is true) leaves arguments unchanged.
142 *
143 * We eagerly canonize the argument types to avoid having to deal with
144 * this logic in multiple places.
145 *
146 * TODO(leafp): Figure out how to present this to the user. How
147 * should these be printed out?
148 */
149 constructor(definite, returnType, args, optionals, named) {
150 super();
151 this.definite = definite;
152 this.returnType = returnType;
153 this.args = args;
154 this.optionals = optionals;
155 this.named = named;
156
157 // TODO(vsm): This is just parameter metadata for now.
158 this.metadata = [];
159 function process(array, metadata) {
160 var result = [];
161 for (var i = 0; i < array.length; ++i) {
162 var arg = array[i];
163 if (arg instanceof Array) {
164 metadata.push(arg.slice(1));
165 result.push(arg[0]);
166 } else {
167 metadata.push([]);
168 result.push(arg);
169 }
170 }
171 return result;
172 }
173 this.args = process(this.args, this.metadata);
174 this.optionals = process(this.optionals, this.metadata);
175 // TODO(vsm): Add named arguments.
176 this._canonize();
177 }
178 _canonize() {
179 if (this.definite) return;
180
181 function replace(a) {
182 return (a == $dynamicR) ? $bottom : a;
183 }
184
185 this.args = this.args.map(replace);
186
187 if (this.optionals.length > 0) {
188 this.optionals = this.optionals.map(replace);
189 }
190
191 if (Object.keys(this.named).length > 0) {
192 let r = {};
193 for (let name of $getOwnPropertyNames(this.named)) {
194 r[name] = replace(this.named[name]);
195 }
196 this.named = r;
197 }
198 }
199 }
200 ''');
201
202 final Typedef = JS('', '''
203 class Typedef extends $AbstractFunctionType {
204 constructor(name, closure) {
205 super();
206 this._name = name;
207 this._closure = closure;
208 this._functionType = null;
209 }
210
211 get definite() {
212 return this._functionType.definite;
213 }
214
215 get name() {
216 return this._name;
217 }
218
219 get functionType() {
220 if (!this._functionType) {
221 this._functionType = this._closure();
222 }
223 return this._functionType;
224 }
225
226 get returnType() {
227 return this.functionType.returnType;
228 }
229
230 get args() {
231 return this.functionType.args;
232 }
233
234 get optionals() {
235 return this.functionType.optionals;
236 }
237
238 get named() {
239 return this.functionType.named;
240 }
241
242 get metadata() {
243 return this.functionType.metadata;
244 }
245 }
246 ''');
247
248 _functionType(definite, returnType, args, extra) => JS('', '''(() => {
249 // TODO(vsm): Cache / memomize?
250 let optionals;
251 let named;
252 if ($extra === void 0) {
253 optionals = [];
254 named = {};
255 } else if ($extra instanceof Array) {
256 optionals = $extra;
257 named = {};
258 } else {
259 optionals = [];
260 named = $extra;
261 }
262 return new $FunctionType($definite, $returnType, $args, optionals, named);
263 })()''');
264
265 ///
266 /// Create a "fuzzy" function type. If any arguments are dynamic
267 /// they will be replaced with bottom.
268 ///
269 functionType(returnType, args, extra) => JS('', '''(() => {
270 return _functionType(false, $returnType, $args, $extra);
271 })()''');
272
273 ///
274 /// Create a definite function type. No substitution of dynamic for
275 /// bottom occurs.
276 ///
277 definiteFunctionType(returnType, args, extra) => JS('', '''(() => {
278 return _functionType(true, $returnType, $args, $extra);
279 })()''');
280
281 typedef(name, closure) => JS('', '''(() => {
282 return new $Typedef($name, $closure);
283 })()''');
284
285 isDartType(type) => JS('', '''(() => {
286 return $read($type) === $Type;
287 })()''');
288
289 typeName(type) => JS('', '''(() => {
290 // Non-instance types
291 if ($type instanceof $TypeRep) return $type.toString();
292 // Instance types
293 let tag = $read($type);
294 if (tag === $Type) {
295 let name = $type.name;
296 let args = $getGenericArgs($type);
297 if (args) {
298 name += '<';
299 for (let i = 0; i < args.length; ++i) {
300 if (i > 0) name += ', ';
301 name += $typeName(args[i]);
302 }
303 name += '>';
304 }
305 return name;
306 }
307 if (tag) return "Not a type: " + tag.name;
308 return "JSObject<" + $type.name + ">";
309 })()''');
310
311 isFunctionType(type) => JS('', '''(() => {
312 return $type instanceof $AbstractFunctionType || $type == $Function;
313 })()''');
314
315 isFunctionSubType(ft1, ft2) => JS('', '''(() => {
316 if ($ft2 == $Function) {
317 return true;
318 }
319
320 let ret1 = $ft1.returnType;
321 let ret2 = $ft2.returnType;
322
323 if (!$isSubtype_(ret1, ret2)) {
324 // Covariant return types
325 // Note, void (which can only appear as a return type) is effectively
326 // treated as dynamic. If the base return type is void, we allow any
327 // subtype return type.
328 // E.g., we allow:
329 // () -> int <: () -> void
330 if (ret2 != $voidR) {
331 return false;
332 }
333 }
334
335 let args1 = $ft1.args;
336 let args2 = $ft2.args;
337
338 if (args1.length > args2.length) {
339 return false;
340 }
341
342 for (let i = 0; i < args1.length; ++i) {
343 if (!$isSubtype_(args2[i], args1[i])) {
344 return false;
345 }
346 }
347
348 let optionals1 = $ft1.optionals;
349 let optionals2 = $ft2.optionals;
350
351 if (args1.length + optionals1.length < args2.length + optionals2.length) {
352 return false;
353 }
354
355 let j = 0;
356 for (let i = args1.length; i < args2.length; ++i, ++j) {
357 if (!$isSubtype_(args2[i], optionals1[j])) {
358 return false;
359 }
360 }
361
362 for (let i = 0; i < optionals2.length; ++i, ++j) {
363 if (!$isSubtype_(optionals2[i], optionals1[j])) {
364 return false;
365 }
366 }
367
368 let named1 = $ft1.named;
369 let named2 = $ft2.named;
370
371 let names = $getOwnPropertyNames(named2);
372 for (let i = 0; i < names.length; ++i) {
373 let name = names[i];
374 let n1 = named1[name];
375 let n2 = named2[name];
376 if (n1 === void 0) {
377 return false;
378 }
379 if (!$isSubtype_(n2, n1)) {
380 return false;
381 }
382 }
383
384 return true;
385 })()''');
386
387 ///
388 /// Computes the canonical type.
389 /// This maps JS types onto their corresponding Dart Type.
390 ///
391 // TODO(jmesserly): lots more needs to be done here.
392 canonicalType(t) => JS('', '''(() => {
393 if ($t === Object) return $Object;
394 if ($t === Function) return $Function;
395 if ($t === Array) return $List;
396
397 // We shouldn't normally get here with these types, unless something strange
398 // happens like subclassing Number in JS and passing it to Dart.
399 if ($t === String) return $String;
400 if ($t === Number) return $double;
401 if ($t === Boolean) return $bool;
402 return $t;
403 })()''');
404
405 final subtypeMap = JS('', 'new Map()');
406 isSubtype(t1, t2) => JS('', '''(() => {
407 // See if we already know the answer
408 // TODO(jmesserly): general purpose memoize function?
409 let map = $subtypeMap.get($t1);
410 let result;
411 if (map) {
412 result = map.get($t2);
413 if (result !== void 0) return result;
414 } else {
415 $subtypeMap.set($t1, map = new Map());
416 }
417 result = $isSubtype_($t1, $t2);
418 map.set($t2, result);
419 return result;
420 })()''');
421
422 _isBottom(type) => JS('', '''(() => {
423 return $type == $bottom;
424 })()''');
425
426 _isTop(type) => JS('', '''(() => {
427 return $type == $Object || ($type == $dynamicR);
428 })()''');
429
430 isSubtype_(t1, t2) => JS('', '''(() => {
431 $t1 = $canonicalType($t1);
432 $t2 = $canonicalType($t2);
433 if ($t1 == $t2) return true;
434
435 // Trivially true.
436 if ($_isTop($t2) || $_isBottom($t1)) {
437 return true;
438 }
439
440 // Trivially false.
441 if ($_isTop($t1) || $_isBottom($t2)) {
442 return false;
443 }
444
445 // "Traditional" name-based subtype check.
446 if ($isClassSubType($t1, $t2)) {
447 return true;
448 }
449
450 // Function subtyping.
451 // TODO(vsm): Handle Objects with call methods. Those are functions
452 // even if they do not *nominally* subtype core.Function.
453 if ($isFunctionType($t1) &&
454 $isFunctionType($t2)) {
455 return $isFunctionSubType($t1, $t2);
456 }
457 return false;
458 })()''');
459
460 isClassSubType(t1, t2) => JS('', '''(() => {
461 // We support Dart's covariant generics with the caveat that we do not
462 // substitute bottom for dynamic in subtyping rules.
463 // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow:
464 // - S !<: S<T1, ..., Tn>
465 // - S<dynamic, ..., dynamic> !<: S<T1, ..., Tn>
466 $t1 = $canonicalType($t1);
467 $assert_($t2 == $canonicalType($t2));
468 if ($t1 == $t2) return true;
469
470 if ($t1 == $Object) return false;
471
472 // If t1 is a JS Object, we may not hit core.Object.
473 if ($t1 == null) return $t2 == $Object || $t2 == $dynamicR;
474
475 // Check if t1 and t2 have the same raw type. If so, check covariance on
476 // type parameters.
477 let raw1 = $getGenericClass($t1);
478 let raw2 = $getGenericClass($t2);
479 if (raw1 != null && raw1 == raw2) {
480 let typeArguments1 = $getGenericArgs($t1);
481 let typeArguments2 = $getGenericArgs($t2);
482 let length = typeArguments1.length;
483 if (typeArguments2.length == 0) {
484 // t2 is the raw form of t1
485 return true;
486 } else if (length == 0) {
487 // t1 is raw, but t2 is not
488 return false;
489 }
490 $assert_(length == typeArguments2.length);
491 for (let i = 0; i < length; ++i) {
492 if (!$isSubtype(typeArguments1[i], typeArguments2[i])) {
493 return false;
494 }
495 }
496 return true;
497 }
498
499 // Check superclass.
500 if ($isClassSubType($t1.__proto__, $t2)) return true;
501
502 // Check mixins.
503 let mixins = $getMixins($t1);
504 if (mixins) {
505 for (let m1 of mixins) {
506 // TODO(jmesserly): remove the != null check once we can load core libs.
507 if (m1 != null && $isClassSubType(m1, $t2)) return true;
508 }
509 }
510
511 // Check interfaces.
512 let getInterfaces = $getImplements($t1);
513 if (getInterfaces) {
514 for (let i1 of getInterfaces()) {
515 // TODO(jmesserly): remove the != null check once we can load core libs.
516 if (i1 != null && $isClassSubType(i1, $t2)) return true;
517 }
518 }
519
520 return false;
521 })()''');
522
523 // TODO(jmesserly): this isn't currently used, but it could be if we want
524 // `obj is NonGroundType<T,S>` to be rejected at runtime instead of compile
525 // time.
526 isGroundType(type) => JS('', '''(() => {
527 // TODO(vsm): Cache this if we start using it at runtime.
528
529 if ($type instanceof $AbstractFunctionType) {
530 if (!$_isTop($type.returnType)) return false;
531 for (let i = 0; i < $type.args.length; ++i) {
532 if (!$_isBottom($type.args[i])) return false;
533 }
534 for (let i = 0; i < $type.optionals.length; ++i) {
535 if (!$_isBottom($type.optionals[i])) return false;
536 }
537 let names = $getOwnPropertyNames($type.named);
538 for (let i = 0; i < names.length; ++i) {
539 if (!$_isBottom($type.named[names[i]])) return false;
540 }
541 return true;
542 }
543
544 let typeArgs = $getGenericArgs($type);
545 if (!typeArgs) return true;
546 for (let t of typeArgs) {
547 if (t != $Object && t != $dynamicR) return false;
548 }
549 return true;
550 })()''');
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698