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

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

Issue 1195523002: Handle dynamic as bottom inside of function type reps (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 6 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 /* This library defines the representation of runtime types. 5 /* This library defines the representation of runtime types.
6 */ 6 */
7 7
8 dart_library.library('dart_runtime/_types', null, /* Imports */[ 8 dart_library.library('dart_runtime/_types', null, /* Imports */[
9 ], /* Lazy Imports */[ 9 ], /* Lazy Imports */[
10 'dart/core', 10 'dart/core',
11 'dart_runtime/_classes', 11 'dart_runtime/_classes',
12 'dart_runtime/_rtti' 12 'dart_runtime/_rtti'
13 ], function(exports, core, classes, rtti) { 13 ], function(exports, core, classes, rtti) {
14 'use strict'; 14 'use strict';
15 15
16 const getOwnPropertyNames = Object.getOwnPropertyNames; 16 const getOwnPropertyNames = Object.getOwnPropertyNames;
17 17
18 const assert = dart_utils.assert; 18 const assert = dart_utils.assert;
19 const copyProperties = dart_utils.copyProperties; 19 const copyProperties = dart_utils.copyProperties;
20 const safeGetOwnProperty = dart_utils.safeGetOwnProperty; 20 const safeGetOwnProperty = dart_utils.safeGetOwnProperty;
21 21
22 /**
23 * Types in dart are represented at runtime as follows.
24 * - Normal nominal types, produced from classes, are represented
25 * at runtime by the JS class of which they are an instance.
26 * If the type is the result of instantiating a generic class,
27 * then the "classes" module manages the association between the
28 * instantiated class and the original class declaration
29 * and the type arguments with which it was instantiated. This
30 * assocation can be queried via the "classes" module".
31 *
32 * - All other types are represented as instances of class TypeRep,
33 * defined in this module.
34 * - Dynamic, Void, and Bottom are singleton instances of sentinal
35 * classes.
36 * - Function types are instances of subclasses of AbstractFunctionType.
37 *
38 * Function types are represented in one of two ways:
39 * - As an instance of FunctionType. These are eagerly computed.
40 * - As an instance of TypeDef. The TypeDef representation lazily
41 * computes an instance of FunctionType, and delegates to that instance.
42 *
43 * All types satisfy the following interface:
44 * get String name;
45 * String toString();
46 *
47 */
22 class TypeRep extends rtti.LazyTagged(() => core.Type) { 48 class TypeRep extends rtti.LazyTagged(() => core.Type) {
23 get name() {return this.toString();} 49 get name() {return this.toString();}
24 } 50 }
25 51
26 class Dynamic extends TypeRep { 52 class Dynamic extends TypeRep {
27 toString() { return "dynamic"; } 53 toString() { return "dynamic"; }
28 } 54 }
29 let dynamicR = new Dynamic(); 55 let dynamicR = new Dynamic();
30 exports.dynamic = dynamicR; 56 exports.dynamic = dynamicR;
31 57
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 buffer += '}'; 109 buffer += '}';
84 } 110 }
85 111
86 buffer += ') -> ' + typeName(this.returnType); 112 buffer += ') -> ' + typeName(this.returnType);
87 this._stringValue = buffer; 113 this._stringValue = buffer;
88 return buffer; 114 return buffer;
89 } 115 }
90 } 116 }
91 117
92 class FunctionType extends AbstractFunctionType { 118 class FunctionType extends AbstractFunctionType {
93 constructor(returnType, args, optionals, named) { 119 /**
120 * Construct a function type. There are two arrow constructors,
121 * distinguished by the "definite" flag.
122 *
123 * The fuzzy arrow (definite is false) treats any arguments
124 * of type dynamic as having type bottom, and will always be
125 * called with a dynamic invoke.
126 *
127 * The definite arrow (definite is true) leaves arguments unchanged.
128 *
129 * We eagerly canonize the argument types to avoid having to deal with
130 * this logic in multple places.
131 *
132 * TODO(leafp): Figure out how to present this to the user. How
133 * should these be printed out?
134 */
135 constructor(definite, returnType, args, optionals, named) {
94 super(); 136 super();
137 this.definite = definite;
95 this.returnType = returnType; 138 this.returnType = returnType;
96 this.args = args; 139 this.args = args;
97 this.optionals = optionals; 140 this.optionals = optionals;
98 this.named = named; 141 this.named = named;
142 this._canonize();
143 }
144 _canonize() {
145 if (this.definite) return;
146
147 function replace(a) {
148 return (a == dynamicR) ? bottomR : a;
149 }
150
151 this.args = this.args.map(replace);
152
153 if (this.optionals.length > 0) {
154 this.optionals = this.optionals.map(replace);
155 }
156
157 if (Object.keys(this.named).length > 0) {
158 let r = {};
159 for (let name of getOwnPropertyNames(this.named)) {
160 r[name] = replace(this.named[name]);
161 }
162 this.named = r;
163 }
99 } 164 }
100 } 165 }
101 166
102 class Typedef extends AbstractFunctionType { 167 class Typedef extends AbstractFunctionType {
103 constructor(name, closure) { 168 constructor(name, closure) {
104 super(); 169 super();
105 this._name = name; 170 this._name = name;
106 this._closure = closure; 171 this._closure = closure;
107 this._functionType = null; 172 this._functionType = null;
108 } 173 }
109 174
175 get definite() {
176 return this._functionType.definite;
177 }
178
110 get name() { 179 get name() {
111 return this._name; 180 return this._name;
112 } 181 }
113 182
114 get functionType() { 183 get functionType() {
115 if (!this._functionType) { 184 if (!this._functionType) {
116 this._functionType = this._closure(); 185 this._functionType = this._closure();
117 } 186 }
118 return this._functionType; 187 return this._functionType;
119 } 188 }
120 189
121 get returnType() { 190 get returnType() {
122 return this.functionType.returnType; 191 return this.functionType.returnType;
123 } 192 }
124 193
125 get args() { 194 get args() {
126 return this.functionType.args; 195 return this.functionType.args;
127 } 196 }
128 197
129 get optionals() { 198 get optionals() {
130 return this.functionType.optionals; 199 return this.functionType.optionals;
131 } 200 }
132 201
133 get named() { 202 get named() {
134 return this.functionType.named; 203 return this.functionType.named;
135 } 204 }
136 } 205 }
137 206
138 function functionType(returnType, args, extra) { 207 function _functionType(definite, returnType, args, extra) {
139 // TODO(vsm): Cache / memomize? 208 // TODO(vsm): Cache / memomize?
140 let optionals; 209 let optionals;
141 let named; 210 let named;
142 if (extra === void 0) { 211 if (extra === void 0) {
143 optionals = []; 212 optionals = [];
144 named = {}; 213 named = {};
145 } else if (extra instanceof Array) { 214 } else if (extra instanceof Array) {
146 optionals = extra; 215 optionals = extra;
147 named = {}; 216 named = {};
148 } else { 217 } else {
149 optionals = []; 218 optionals = [];
150 named = extra; 219 named = extra;
151 } 220 }
152 return new FunctionType(returnType, args, optionals, named); 221 return new FunctionType(definite, returnType, args, optionals, named);
222 }
223
224 /**
225 * Create a "fuzzy" function type. If any argumets are dynamic
226 * they will be replaced with bottom.
227 */
228 function functionType(returnType, args, extra) {
229 return _functionType(false, returnType, args, extra);
153 } 230 }
154 exports.functionType = functionType; 231 exports.functionType = functionType;
155 232
233 /**
234 * Create a definite function type. No substitution of dynamic for
235 * bottom occurs.
236 */
237 function definiteFunctionType(returnType, args, extra) {
238 return _functionType(true, returnType, args, extra);
239 }
240 exports.definiteFunctionType = definiteFunctionType;
241
156 function typedef(name, closure) { 242 function typedef(name, closure) {
157 return new Typedef(name, closure); 243 return new Typedef(name, closure);
158 } 244 }
159 exports.typedef = typedef; 245 exports.typedef = typedef;
160 246
161 function isDartType(type) { 247 function isDartType(type) {
162 return rtti.read(type) === core.Type; 248 return rtti.read(type) === core.Type;
163 } 249 }
164 exports.isDartType = isDartType; 250 exports.isDartType = isDartType;
165 251
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 } 297 }
212 298
213 let args1 = ft1.args; 299 let args1 = ft1.args;
214 let args2 = ft2.args; 300 let args2 = ft2.args;
215 301
216 if (args1.length > args2.length) { 302 if (args1.length > args2.length) {
217 return false; 303 return false;
218 } 304 }
219 305
220 for (let i = 0; i < args1.length; ++i) { 306 for (let i = 0; i < args1.length; ++i) {
221 if (!isSubtype_(args2[i], args1[i], true)) { 307 if (!isSubtype_(args2[i], args1[i])) {
222 return false; 308 return false;
223 } 309 }
224 } 310 }
225 311
226 let optionals1 = ft1.optionals; 312 let optionals1 = ft1.optionals;
227 let optionals2 = ft2.optionals; 313 let optionals2 = ft2.optionals;
228 314
229 if (args1.length + optionals1.length < args2.length + optionals2.length) { 315 if (args1.length + optionals1.length < args2.length + optionals2.length) {
230 return false; 316 return false;
231 } 317 }
232 318
233 let j = 0; 319 let j = 0;
234 for (let i = args1.length; i < args2.length; ++i, ++j) { 320 for (let i = args1.length; i < args2.length; ++i, ++j) {
235 if (!isSubtype_(args2[i], optionals1[j], true)) { 321 if (!isSubtype_(args2[i], optionals1[j])) {
236 return false; 322 return false;
237 } 323 }
238 } 324 }
239 325
240 for (let i = 0; i < optionals2.length; ++i, ++j) { 326 for (let i = 0; i < optionals2.length; ++i, ++j) {
241 if (!isSubtype_(optionals2[i], optionals1[j], true)) { 327 if (!isSubtype_(optionals2[i], optionals1[j])) {
242 return false; 328 return false;
243 } 329 }
244 } 330 }
245 331
246 let named1 = ft1.named; 332 let named1 = ft1.named;
247 let named2 = ft2.named; 333 let named2 = ft2.named;
248 334
249 let names = getOwnPropertyNames(named2); 335 let names = getOwnPropertyNames(named2);
250 for (let i = 0; i < names.length; ++i) { 336 for (let i = 0; i < names.length; ++i) {
251 let name = names[i]; 337 let name = names[i];
252 let n1 = named1[name]; 338 let n1 = named1[name];
253 let n2 = named2[name]; 339 let n2 = named2[name];
254 if (n1 === void 0) { 340 if (n1 === void 0) {
255 return false; 341 return false;
256 } 342 }
257 if (!isSubtype_(n2, n1, true)) { 343 if (!isSubtype_(n2, n1)) {
258 return false; 344 return false;
259 } 345 }
260 } 346 }
261 347
262 return true; 348 return true;
263 } 349 }
264 350
265 /** 351 /**
266 * Computes the canonical type. 352 * Computes the canonical type.
267 * This maps JS types onto their corresponding Dart Type. 353 * This maps JS types onto their corresponding Dart Type.
(...skipping 23 matching lines...) Expand all
291 if (result !== void 0) return result; 377 if (result !== void 0) return result;
292 } else { 378 } else {
293 subtypeMap.set(t1, map = new Map()); 379 subtypeMap.set(t1, map = new Map());
294 } 380 }
295 result = isSubtype_(t1, t2) 381 result = isSubtype_(t1, t2)
296 map.set(t2, result); 382 map.set(t2, result);
297 return result; 383 return result;
298 } 384 }
299 exports.isSubtype = isSubtype; 385 exports.isSubtype = isSubtype;
300 386
301 function _isBottom(type, dynamicIsBottom) { 387 function _isBottom(type) {
302 return (type == dynamicR && dynamicIsBottom) || type == bottomR; 388 return type == bottomR;
303 } 389 }
304 390
305 function _isTop(type, dynamicIsBottom) { 391 function _isTop(type) {
306 return type == core.Object || (type == dynamicR && !dynamicIsBottom); 392 return type == core.Object || (type == dynamicR);
307 } 393 }
308 394
309 function isSubtype_(t1, t2, opt_dynamicIsBottom) { 395 function isSubtype_(t1, t2) {
310 let dynamicIsBottom =
311 opt_dynamicIsBottom === void 0 ? false : opt_dynamicIsBottom;
312
313 t1 = canonicalType(t1); 396 t1 = canonicalType(t1);
314 t2 = canonicalType(t2); 397 t2 = canonicalType(t2);
315 if (t1 == t2) return true; 398 if (t1 == t2) return true;
316 399
317 // In Dart, dynamic is effectively both top and bottom.
318 // Here, we treat dynamic as one or the other depending on context,
319 // but not both.
320
321 // Trivially true. 400 // Trivially true.
322 if (_isTop(t2, dynamicIsBottom) || _isBottom(t1, dynamicIsBottom)) { 401 if (_isTop(t2) || _isBottom(t1)) {
323 return true; 402 return true;
324 } 403 }
325 404
326 // Trivially false. 405 // Trivially false.
327 if (_isTop(t1, dynamicIsBottom) || _isBottom(t2, dynamicIsBottom)) { 406 if (_isTop(t1) || _isBottom(t2)) {
328 return false; 407 return false;
329 } 408 }
330 409
331 // "Traditional" name-based subtype check. 410 // "Traditional" name-based subtype check.
332 if (isClassSubType(t1, t2)) { 411 if (isClassSubType(t1, t2)) {
333 return true; 412 return true;
334 } 413 }
335 414
336 // Function subtyping. 415 // Function subtyping.
337 // TODO(vsm): Handle Objects with call methods. Those are functions 416 // TODO(vsm): Handle Objects with call methods. Those are functions
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 return false; 485 return false;
407 } 486 }
408 487
409 // TODO(jmesserly): this isn't currently used, but it could be if we want 488 // TODO(jmesserly): this isn't currently used, but it could be if we want
410 // `obj is NonGroundType<T,S>` to be rejected at runtime instead of compile 489 // `obj is NonGroundType<T,S>` to be rejected at runtime instead of compile
411 // time. 490 // time.
412 function isGroundType(type) { 491 function isGroundType(type) {
413 // TODO(vsm): Cache this if we start using it at runtime. 492 // TODO(vsm): Cache this if we start using it at runtime.
414 493
415 if (type instanceof AbstractFunctionType) { 494 if (type instanceof AbstractFunctionType) {
416 if (!_isTop(type.returnType, false)) return false; 495 if (!_isTop(type.returnType)) return false;
417 for (let i = 0; i < type.args.length; ++i) { 496 for (let i = 0; i < type.args.length; ++i) {
418 if (!_isBottom(type.args[i], true)) return false; 497 if (!_isBottom(type.args[i])) return false;
419 } 498 }
420 for (let i = 0; i < type.optionals.length; ++i) { 499 for (let i = 0; i < type.optionals.length; ++i) {
421 if (!_isBottom(type.optionals[i], true)) return false; 500 if (!_isBottom(type.optionals[i])) return false;
422 } 501 }
423 let names = getOwnPropertyNames(type.named); 502 let names = getOwnPropertyNames(type.named);
424 for (let i = 0; i < names.length; ++i) { 503 for (let i = 0; i < names.length; ++i) {
425 if (!_isBottom(type.named[names[i]], true)) return false; 504 if (!_isBottom(type.named[names[i]])) return false;
426 } 505 }
427 return true; 506 return true;
428 } 507 }
429 508
430 let typeArgs = classes.getGenericArgs(type); 509 let typeArgs = classes.getGenericArgs(type);
431 if (!typeArgs) return true; 510 if (!typeArgs) return true;
432 for (let t of typeArgs) { 511 for (let t of typeArgs) {
433 if (t != core.Object && t != dynamicR) return false; 512 if (t != core.Object && t != dynamicR) return false;
434 } 513 }
435 return true; 514 return true;
436 } 515 }
437 exports.isGroundType = isGroundType; 516 exports.isGroundType = isGroundType;
438 517
439 }); 518 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698