| OLD | NEW |
| 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 Loading... |
| 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 treat Dart and JS objects differently here? |
| 130 // E.g., we can check if obj instanceof core.Object to differentiate. |
| 131 var result = obj[dart.runtimeType]; |
| 132 if (result) return result; |
| 133 result = obj.constructor; |
| 134 if (result == Function) { |
| 135 return getFunctionType(obj); |
| 136 } |
| 137 return result; |
| 130 } | 138 } |
| 131 dart.getRuntimeType = getRuntimeType; | 139 dart.getRuntimeType = getRuntimeType; |
| 132 | 140 |
| 133 function instanceOf(obj, type) { | 141 function instanceOf(obj, type) { |
| 134 return isSubtype(getRuntimeType(obj), type); | 142 return isSubtype(getRuntimeType(obj), type); |
| 135 } | 143 } |
| 136 dart.is = instanceOf; | 144 dart.is = instanceOf; |
| 137 | 145 |
| 138 /** | 146 /** |
| 139 * Computes the canonical type. | 147 * Computes the canonical type. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 163 result = map.get(t2); | 171 result = map.get(t2); |
| 164 if (result !== void 0) return result; | 172 if (result !== void 0) return result; |
| 165 } else { | 173 } else { |
| 166 subtypeMap.set(t1, map = new Map()); | 174 subtypeMap.set(t1, map = new Map()); |
| 167 } | 175 } |
| 168 map.set(t2, result = isSubtype_(t1, t2)); | 176 map.set(t2, result = isSubtype_(t1, t2)); |
| 169 return result; | 177 return result; |
| 170 } | 178 } |
| 171 dart.isSubtype = isSubtype; | 179 dart.isSubtype = isSubtype; |
| 172 | 180 |
| 173 function isSubtype_(t1, t2) { | 181 function _isBottom(type, dynamicIsBottom) { |
| 182 return (type == dart.dynamic && dynamicIsBottom) || type == dart.bottom; |
| 183 } |
| 184 |
| 185 function _isTop(type, dynamicIsBottom) { |
| 186 return type == core.Object || (type == dart.dynamic && !dynamicIsBottom); |
| 187 } |
| 188 |
| 189 function isSubtype_(t1, t2, opt_dynamicIsBottom) { |
| 190 let dynamicIsBottom = |
| 191 opt_dynamicIsBottom === void 0 ? false : opt_dynamicIsBottom; |
| 192 |
| 174 t1 = canonicalType(t1); | 193 t1 = canonicalType(t1); |
| 175 t2 = canonicalType(t2); | 194 t2 = canonicalType(t2); |
| 176 if (t1 == t2) return true; | 195 if (t1 == t2) return true; |
| 177 | 196 |
| 178 // In Dart, dynamic is effectively both top and bottom. | 197 // In Dart, dynamic is effectively both top and bottom. |
| 179 // Here, we treat dynamic as top - the base type of everything. | 198 // Here, we treat dynamic as one or the other depending on context, |
| 180 if (t1 == dart.dynamic) return false; | 199 // but not both. |
| 181 if (t2 == dart.dynamic) return true; | |
| 182 | 200 |
| 183 if (t2 == core.Object) return true; | 201 // Trivially true. |
| 184 if (t1 == core.Object) return false; | 202 if (_isTop(t2, dynamicIsBottom) || _isBottom(t1, dynamicIsBottom)) { |
| 203 return true; |
| 204 } |
| 205 |
| 206 // Trivially false. |
| 207 if (_isTop(t1, dynamicIsBottom) || _isBottom(t2, dynamicIsBottom)) { |
| 208 return false; |
| 209 } |
| 185 | 210 |
| 186 // "Traditional" name-based subtype check. | 211 // "Traditional" name-based subtype check. |
| 187 if (isClassSubType(t1, t2)) { | 212 if (isClassSubType(t1, t2)) { |
| 188 return true; | 213 return true; |
| 189 } | 214 } |
| 190 | 215 |
| 191 // Function subtyping. | 216 // Function subtyping. |
| 192 // TODO(jmesserly): implement this properly. | 217 // TODO(vsm): Handle Objects with call methods. Those are functions |
| 193 if (isClassSubType(t1, core.Function) && | 218 // even if they do not *nominally* subtype core.Function. |
| 194 isClassSubType(t2, core.Function)) { | 219 if (isFunctionType(t1) && |
| 195 return true; | 220 isFunctionType(t2)) { |
| 221 return isFunctionSubType(t1, t2); |
| 196 } | 222 } |
| 197 return false; | 223 return false; |
| 198 } | 224 } |
| 199 | 225 |
| 200 function safeGetOwnProperty(obj, name) { | 226 function safeGetOwnProperty(obj, name) { |
| 201 var desc = getOwnPropertyDescriptor(obj, name); | 227 var desc = getOwnPropertyDescriptor(obj, name); |
| 202 if (desc) return desc.value; | 228 if (desc) return desc.value; |
| 203 } | 229 } |
| 204 | 230 |
| 205 function isClassSubType(t1, t2) { | 231 function isClassSubType(t1, t2) { |
| 206 // We support Dart's covariant generics with the caveat that we do not | 232 // We support Dart's covariant generics with the caveat that we do not |
| 207 // substitute bottom for dynamic in subtyping rules. | 233 // substitute bottom for dynamic in subtyping rules. |
| 208 // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow: | 234 // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow: |
| 209 // - S !<: S<T1, ..., Tn> | 235 // - S !<: S<T1, ..., Tn> |
| 210 // - S<dynamic, ..., dynamic> !<: S<T1, ..., Tn> | 236 // - S<dynamic, ..., dynamic> !<: S<T1, ..., Tn> |
| 211 if (t1 == t2) return true; | 237 if (t1 == t2) return true; |
| 212 | 238 |
| 213 if (t1 == core.Object) return false; | 239 if (t1 == core.Object) return false; |
| 214 | 240 |
| 241 // If t1 is a JS Object, we may not hit core.Object. |
| 242 if (t1 == null) return t2 == core.Object || t2 == dart.dynamic; |
| 243 |
| 215 // Check if t1 and t2 have the same raw type. If so, check covariance on | 244 // Check if t1 and t2 have the same raw type. If so, check covariance on |
| 216 // type parameters. | 245 // type parameters. |
| 217 let raw1 = safeGetOwnProperty(t1, dart.originalDeclaration); | 246 let raw1 = safeGetOwnProperty(t1, dart.originalDeclaration); |
| 218 let raw2 = safeGetOwnProperty(t2, dart.originalDeclaration); | 247 let raw2 = safeGetOwnProperty(t2, dart.originalDeclaration); |
| 219 if (raw1 != null && raw1 == raw2) { | 248 if (raw1 != null && raw1 == raw2) { |
| 220 let typeArguments1 = safeGetOwnProperty(t1, dart.typeArguments); | 249 let typeArguments1 = safeGetOwnProperty(t1, dart.typeArguments); |
| 221 let typeArguments2 = safeGetOwnProperty(t2, dart.typeArguments); | 250 let typeArguments2 = safeGetOwnProperty(t2, dart.typeArguments); |
| 222 let length = typeArguments1.length; | 251 let length = typeArguments1.length; |
| 223 if (typeArguments2.length == 0) { | 252 if (typeArguments2.length == 0) { |
| 224 // t2 is the raw form of t1 | 253 // t2 is the raw form of t1 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 253 if (getInterfaces) { | 282 if (getInterfaces) { |
| 254 for (let i1 of getInterfaces()) { | 283 for (let i1 of getInterfaces()) { |
| 255 // TODO(jmesserly): remove the != null check once we can load core libs. | 284 // TODO(jmesserly): remove the != null check once we can load core libs. |
| 256 if (i1 != null && isClassSubType(i1, t2)) return true; | 285 if (i1 != null && isClassSubType(i1, t2)) return true; |
| 257 } | 286 } |
| 258 } | 287 } |
| 259 | 288 |
| 260 return false; | 289 return false; |
| 261 } | 290 } |
| 262 | 291 |
| 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 | 292 // 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 | 293 // `obj is NonGroundType<T,S>` to be rejected at runtime instead of compile |
| 272 // time. Also TODO: update this to handle functions. | 294 // time. |
| 273 function isGroundType(type) { | 295 function isGroundType(type) { |
| 296 // TODO(vsm): Cache this if we start using it at runtime. |
| 297 |
| 298 if (type instanceof AbstractFunctionType) { |
| 299 if (!_isTop(type.returnType, false)) return false; |
| 300 for (var i = 0; i < type.args.length; ++i) { |
| 301 if (!_isBottom(type.args[i], true)) return false; |
| 302 } |
| 303 for (var i = 0; i < type.optionals.length; ++i) { |
| 304 if (!_isBottom(type.optionals[i], true)) return false; |
| 305 } |
| 306 var names = Object.getOwnPropertyNames(type.named); |
| 307 for (var i = 0; i < names.length; ++i) { |
| 308 if (!_isBottom(type.named[names[i]], true)) return false; |
| 309 } |
| 310 return true; |
| 311 } |
| 312 |
| 274 let typeArgs = safeGetOwnProperty(type, dart.typeArguments); | 313 let typeArgs = safeGetOwnProperty(type, dart.typeArguments); |
| 275 if (!typeArgs) return true; | 314 if (!typeArgs) return true; |
| 276 for (let t of typeArgs) { | 315 for (let t of typeArgs) { |
| 277 if (t != core.Object && t != dart.dynamic) return false; | 316 if (t != core.Object && t != dart.dynamic) return false; |
| 278 } | 317 } |
| 279 return true; | 318 return true; |
| 280 } | 319 } |
| 281 dart.isGroundType = isGroundType; | 320 dart.isGroundType = isGroundType; |
| 282 | 321 |
| 283 function arity(f) { | 322 function arity(f) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 294 } | 333 } |
| 295 dart.equals = equals; | 334 dart.equals = equals; |
| 296 | 335 |
| 297 /** Checks that `x` is not null or undefined. */ | 336 /** Checks that `x` is not null or undefined. */ |
| 298 function notNull(x) { | 337 function notNull(x) { |
| 299 if (x == null) throw 'expected not-null value'; | 338 if (x == null) throw 'expected not-null value'; |
| 300 return x; | 339 return x; |
| 301 } | 340 } |
| 302 dart.notNull = notNull; | 341 dart.notNull = notNull; |
| 303 | 342 |
| 343 function _typeName(type) { |
| 344 var name = type.name; |
| 345 if (!name) throw 'Unexpected type: ' + type; |
| 346 return name; |
| 347 } |
| 348 |
| 349 class AbstractFunctionType { |
| 350 constructor() { |
| 351 this._stringValue = null; |
| 352 } |
| 353 |
| 354 get name() { |
| 355 if (this._stringValue) return this._stringValue; |
| 356 |
| 357 var buffer = '('; |
| 358 for (var i = 0; i < this.args.length; ++i) { |
| 359 if (i > 0) { |
| 360 buffer += ', '; |
| 361 } |
| 362 buffer += _typeName(this.args[i]); |
| 363 } |
| 364 if (this.optionals.length > 0) { |
| 365 if (this.args.length > 0) buffer += ', '; |
| 366 buffer += '['; |
| 367 for (var i = 0; i < this.optionals.length; ++i) { |
| 368 if (i > 0) { |
| 369 buffer += ', '; |
| 370 } |
| 371 buffer += _typeName(this.optionals[i]); |
| 372 } |
| 373 buffer += ']'; |
| 374 } else if (this.named.length > 0) { |
| 375 if (this.args.length > 0) buffer += ', '; |
| 376 buffer += '{'; |
| 377 let names = Object.getOwnPropertyNames(this.named).sort(); |
| 378 for (var i = 0; i < names.length; ++i) { |
| 379 if (i > 0) { |
| 380 buffer += ', '; |
| 381 } |
| 382 buffer += names[i] + ': ' + _typeName(this.named[names[i]]); |
| 383 } |
| 384 buffer += '}'; |
| 385 } |
| 386 |
| 387 buffer += ') -> ' + _typeName(this.returnType); |
| 388 this._stringValue = buffer; |
| 389 return buffer; |
| 390 } |
| 391 } |
| 392 |
| 393 class FunctionType extends AbstractFunctionType { |
| 394 constructor(returnType, args, optionals, named) { |
| 395 super(); |
| 396 this.returnType = returnType; |
| 397 this.args = args; |
| 398 this.optionals = optionals; |
| 399 this.named = named; |
| 400 } |
| 401 } |
| 402 |
| 403 function functionType(returnType, args, extra) { |
| 404 // TODO(vsm): Cache / memomize? |
| 405 var optionals; |
| 406 var named; |
| 407 if (extra === void 0) { |
| 408 optionals = []; |
| 409 named = {}; |
| 410 } else if (extra instanceof Array) { |
| 411 optionals = extra; |
| 412 named = {}; |
| 413 } else { |
| 414 optionals = []; |
| 415 named = extra; |
| 416 } |
| 417 return new FunctionType(returnType, args, optionals, named); |
| 418 } |
| 419 dart.functionType = functionType; |
| 420 |
| 421 class Typedef extends AbstractFunctionType { |
| 422 constructor(name, closure) { |
| 423 super(); |
| 424 this._name = name; |
| 425 this._closure = closure; |
| 426 this._functionType = null; |
| 427 } |
| 428 |
| 429 get name() { |
| 430 return this._name; |
| 431 } |
| 432 |
| 433 get functionType() { |
| 434 if (!this._functionType) { |
| 435 this._functionType = this._closure(); |
| 436 } |
| 437 return this._functionType; |
| 438 } |
| 439 |
| 440 get returnType() { |
| 441 return this.functionType.returnType; |
| 442 } |
| 443 |
| 444 get args() { |
| 445 return this.functionType.args; |
| 446 } |
| 447 |
| 448 get optionals() { |
| 449 return this.functionType.optionals; |
| 450 } |
| 451 |
| 452 get named() { |
| 453 return this.functionType.named; |
| 454 } |
| 455 } |
| 456 |
| 457 function typedef(name, closure) { |
| 458 return new Typedef(name, closure); |
| 459 } |
| 460 dart.typedef = typedef; |
| 461 |
| 462 function isFunctionType(type) { |
| 463 return isClassSubType(type, core.Function) || type instanceof AbstractFuncti
onType; |
| 464 } |
| 465 |
| 466 function getFunctionType(obj) { |
| 467 // TODO(vsm): Encode this properly on the function for Dart-generated code. |
| 468 var args = Array.apply(null, new Array(obj.length)).map(function(){return co
re.Object}); |
| 469 return functionType(dart.bottom, args); |
| 470 } |
| 471 |
| 472 function isFunctionSubType(ft1, ft2) { |
| 473 if (ft2 == core.Function) { |
| 474 return true; |
| 475 } |
| 476 |
| 477 let ret1 = ft1.returnType; |
| 478 let ret2 = ft2.returnType; |
| 479 |
| 480 if (!isSubtype_(ret1, ret2)) { |
| 481 // Covariant return types |
| 482 // Note, void (which can only appear as a return type) is effectively |
| 483 // treated as dynamic. If the base return type is void, we allow any |
| 484 // subtype return type. |
| 485 // E.g., we allow: |
| 486 // () -> int <: () -> void |
| 487 if (ret2 != dart.void) { |
| 488 return false; |
| 489 } |
| 490 } |
| 491 |
| 492 let args1 = ft1.args; |
| 493 let args2 = ft2.args; |
| 494 |
| 495 if (args1.length > args2.length) { |
| 496 return false; |
| 497 } |
| 498 |
| 499 for (var i = 0; i < args1.length; ++i) { |
| 500 if (!isSubtype_(args2[i], args1[i], true)) { |
| 501 return false; |
| 502 } |
| 503 } |
| 504 |
| 505 let optionals1 = ft1.optionals; |
| 506 let optionals2 = ft2.optionals; |
| 507 |
| 508 if (args1.length + optionals1.length < args2.length + optionals2.length) { |
| 509 return false; |
| 510 } |
| 511 |
| 512 var j = 0; |
| 513 for (var i = args1.length; i < args2.length; ++i, ++j) { |
| 514 if (!isSubtype_(args2[i], optionals1[j], true)) { |
| 515 return false; |
| 516 } |
| 517 } |
| 518 |
| 519 for (var i = 0; i < optionals2.length; ++i, ++j) { |
| 520 if (!isSubtype_(optionals2[i], optionals1[j], true)) { |
| 521 return false; |
| 522 } |
| 523 } |
| 524 |
| 525 let named1 = ft1.named; |
| 526 let named2 = ft2.named; |
| 527 |
| 528 let names = Object.getOwnPropertyNames(named2); |
| 529 for (var i = 0; i < names.length; ++i) { |
| 530 let name = names[i]; |
| 531 let n1 = named1[name] |
| 532 let n2 = named2[name]; |
| 533 if (n1 === void 0) { |
| 534 return false; |
| 535 } |
| 536 if (!isSubtype_(n2, n1, true)) { |
| 537 return false; |
| 538 } |
| 539 } |
| 540 |
| 541 return true; |
| 542 } |
| 543 |
| 304 /** | 544 /** |
| 305 * Defines a lazy property. | 545 * Defines a lazy property. |
| 306 * After initial get or set, it will replace itself with a value property. | 546 * After initial get or set, it will replace itself with a value property. |
| 307 */ | 547 */ |
| 308 // TODO(jmesserly): is this the best implementation for JS engines? | 548 // TODO(jmesserly): is this the best implementation for JS engines? |
| 309 // TODO(jmesserly): reusing descriptor objects has been shown to improve | 549 // TODO(jmesserly): reusing descriptor objects has been shown to improve |
| 310 // performance in other projects (e.g. webcomponents.js ShadowDOM polyfill). | 550 // performance in other projects (e.g. webcomponents.js ShadowDOM polyfill). |
| 311 function defineLazyProperty(to, name, desc) { | 551 function defineLazyProperty(to, name, desc) { |
| 312 let init = desc.get; | 552 let init = desc.get; |
| 313 let writable = !!desc.set; | 553 let writable = !!desc.set; |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 501 } | 741 } |
| 502 return value; | 742 return value; |
| 503 } | 743 } |
| 504 return makeGenericType; | 744 return makeGenericType; |
| 505 } | 745 } |
| 506 dart.generic = generic; | 746 dart.generic = generic; |
| 507 | 747 |
| 508 // TODO(jmesserly): right now this is a sentinel. It should be a type object | 748 // 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. | 749 // of some sort, assuming we keep around `dynamic` at runtime. |
| 510 dart.dynamic = { toString() { return 'dynamic'; } }; | 750 dart.dynamic = { toString() { return 'dynamic'; } }; |
| 751 dart.void = { toString() { return 'void'; } }; |
| 752 dart.bottom = { toString() { return 'bottom'; } }; |
| 753 |
| 754 // TODO(vsm): How should we encode the runtime type? |
| 755 dart.runtimeType = Symbol('runtimeType'); |
| 511 | 756 |
| 512 dart.JsSymbol = Symbol; | 757 dart.JsSymbol = Symbol; |
| 513 | 758 |
| 514 // TODO(jmesserly): hack to bootstrap the SDK | 759 // TODO(jmesserly): hack to bootstrap the SDK |
| 515 _js_helper = _js_helper || {}; | 760 _js_helper = _js_helper || {}; |
| 516 _js_helper.checkNum = notNull; | 761 _js_helper.checkNum = notNull; |
| 517 | 762 |
| 518 })(dart || (dart = {})); | 763 })(dart || (dart = {})); |
| OLD | NEW |