| 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 library dev_compiler.src.closure.closure_type; | 5 library dev_compiler.src.closure.closure_type; |
| 6 | 6 |
| 7 /// Poor-man's representation of a Closure type. | 7 /// Poor-man's representation of a Closure type. |
| 8 /// See https://developers.google.com/closure/compiler/docs/js-for-compiler | 8 /// See https://developers.google.com/closure/compiler/docs/js-for-compiler |
| 9 /// | 9 /// |
| 10 /// The goal here is not to completely support Closure's type system, but to | 10 /// The goal here is not to completely support Closure's type system, but to |
| 11 /// be able to generate just the types needed for DDC's JS output. | 11 /// be able to generate just the types needed for DDC's JS output. |
| 12 /// | 12 /// |
| 13 /// TODO(ochafik): Consider convergence with TypeScript, which has no nullabilit
y-awareness | 13 /// TODO(ochafik): Consider convergence with TypeScript, which has no nullabilit
y-awareness |
| 14 /// (see http://www.typescriptlang.org/Handbook). | 14 /// (see http://www.typescriptlang.org/Handbook). |
| 15 class ClosureType { | 15 class ClosureType { |
| 16 static const ClosureType _ALL = const ClosureType._("*"); | 16 static const ClosureType _ALL = const ClosureType._("*"); |
| 17 static const ClosureType _UNKNOWN = const ClosureType._("?"); | 17 static const ClosureType _UNKNOWN = const ClosureType._("?"); |
| 18 | 18 |
| 19 final String _representation; | 19 final String _representation; |
| 20 final bool isNullable; | 20 final bool isNullable; |
| 21 | 21 |
| 22 const ClosureType._(this._representation, {this.isNullable: true}); | 22 const ClosureType._(this._representation, {this.isNullable: true}); |
| 23 | 23 |
| 24 bool get isAll => _representation == "*"; | 24 bool get isAll => _representation == "*"; |
| 25 bool get isUnknown => _representation == "?"; | 25 bool get isUnknown => _representation == "?"; |
| 26 | 26 |
| 27 @override toString() => _representation; | 27 @override toString() => _representation; |
| 28 | 28 |
| 29 factory ClosureType.all() => _ALL; | 29 factory ClosureType.all() => _ALL; |
| 30 factory ClosureType.unknown() => _UNKNOWN; | 30 factory ClosureType.unknown() => _UNKNOWN; |
| 31 | 31 |
| 32 factory ClosureType.record(Map<String, ClosureType> fieldTypes) { | 32 factory ClosureType.record(Map<String, ClosureType> fieldTypes) { |
| 33 var entries = <String>[]; | 33 var entries = <String>[]; |
| 34 fieldTypes.forEach((n, t) => entries.add('$n: $t')); | 34 fieldTypes.forEach((n, t) => entries.add('$n: $t')); |
| 35 return new ClosureType._('{${entries.join(', ')}}'); | 35 return new ClosureType._('{${entries.join(', ')}}'); |
| 36 } | 36 } |
| 37 factory ClosureType.function([List<ClosureType> paramTypes, ClosureType return
Type]) { | 37 factory ClosureType.function( |
| 38 [List<ClosureType> paramTypes, ClosureType returnType]) { |
| 38 if (paramTypes == null && returnType == null) { | 39 if (paramTypes == null && returnType == null) { |
| 39 return new ClosureType.type("Function"); | 40 return new ClosureType.type("Function"); |
| 40 } | 41 } |
| 41 var suffix = returnType == null ? '' : ':$returnType'; | 42 var suffix = returnType == null ? '' : ':$returnType'; |
| 42 return new ClosureType._( | 43 return new ClosureType._( |
| 43 'function(${paramTypes == null ? '...*' : paramTypes.join(', ')})$suffix
'); | 44 'function(${paramTypes == null ? '...*' : paramTypes.join(', ')})$suffix
'); |
| 44 } | 45 } |
| 45 | 46 |
| 46 factory ClosureType.map([ClosureType keyType, ClosureType valueType]) => | 47 factory ClosureType.map([ClosureType keyType, ClosureType valueType]) => |
| 47 new ClosureType._("Object<${keyType ?? _ALL}, ${valueType ?? _ALL}>"); | 48 new ClosureType._("Object<${keyType ?? _ALL}, ${valueType ?? _ALL}>"); |
| 48 | 49 |
| 49 factory ClosureType.type([String className = "Object"]) => | 50 factory ClosureType.type([String className = "Object"]) => |
| 50 new ClosureType._(className); | 51 new ClosureType._(className); |
| 51 | 52 |
| 52 factory ClosureType.array([ClosureType componentType]) => | 53 factory ClosureType.array([ClosureType componentType]) => |
| 53 new ClosureType._("Array<${componentType ?? _ALL}>"); | 54 new ClosureType._("Array<${componentType ?? _ALL}>"); |
| 54 | 55 |
| 55 factory ClosureType.undefined() => new ClosureType._("undefined", isNullable:
false); | 56 factory ClosureType.undefined() => |
| 56 factory ClosureType.number() => new ClosureType._("number", isNullable: false)
; | 57 new ClosureType._("undefined", isNullable: false); |
| 57 factory ClosureType.boolean() => new ClosureType._("boolean", isNullable: fals
e); | 58 factory ClosureType.number() => |
| 59 new ClosureType._("number", isNullable: false); |
| 60 factory ClosureType.boolean() => |
| 61 new ClosureType._("boolean", isNullable: false); |
| 58 factory ClosureType.string() => new ClosureType._("string"); | 62 factory ClosureType.string() => new ClosureType._("string"); |
| 59 | 63 |
| 60 ClosureType toOptional() => | 64 ClosureType toOptional() => new ClosureType._("$this="); |
| 61 new ClosureType._("$this="); | 65 |
| 62 | 66 ClosureType toNullable() => isNullable |
| 63 ClosureType toNullable() => | 67 ? this |
| 64 isNullable ? this : new ClosureType._( | 68 : new ClosureType._( |
| 65 _representation.startsWith('!') ? _representation.substring(1) : "?$th
is", | 69 _representation.startsWith('!') |
| 70 ? _representation.substring(1) |
| 71 : "?$this", |
| 66 isNullable: true); | 72 isNullable: true); |
| 67 | 73 |
| 68 ClosureType toNonNullable() => | 74 ClosureType toNonNullable() => !isNullable |
| 69 !isNullable ? this : new ClosureType._( | 75 ? this |
| 70 _representation.startsWith('?') ? _representation.substring(1) : "!$th
is", | 76 : new ClosureType._( |
| 77 _representation.startsWith('?') |
| 78 ? _representation.substring(1) |
| 79 : "!$this", |
| 71 isNullable: false); | 80 isNullable: false); |
| 72 | 81 |
| 73 /// TODO(ochafik): See which optimizations make sense here (it could be that `
(*|undefined)` | 82 /// TODO(ochafik): See which optimizations make sense here (it could be that `
(*|undefined)` |
| 74 /// cannot be optimized to `*` when used to model optional record fields). | 83 /// cannot be optimized to `*` when used to model optional record fields). |
| 75 ClosureType or(ClosureType other) => | 84 ClosureType or(ClosureType other) => new ClosureType._("($this|$other)", |
| 76 new ClosureType._("($this|$other)", isNullable: isNullable || other.isNull
able); | 85 isNullable: isNullable || other.isNullable); |
| 77 | 86 |
| 78 ClosureType orUndefined() => | 87 ClosureType orUndefined() => or(new ClosureType.undefined()); |
| 79 or(new ClosureType.undefined()); | |
| 80 } | 88 } |
| OLD | NEW |