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 import 'dart:collection' show HashMap, HashSet; | 5 import 'dart:collection' show HashMap, HashSet; |
6 import 'dart:math' show min, max; | 6 import 'dart:math' show min, max; |
7 | 7 |
8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
59 /// We sometimes special case codegen for a single library, as it simplifies | 59 /// We sometimes special case codegen for a single library, as it simplifies |
60 /// name scoping requirements. | 60 /// name scoping requirements. |
61 final _libraries = new Map<LibraryElement, JS.Identifier>(); | 61 final _libraries = new Map<LibraryElement, JS.Identifier>(); |
62 | 62 |
63 /// Imported libraries, and the temporaries used to refer to them. | 63 /// Imported libraries, and the temporaries used to refer to them. |
64 final _imports = new Map<LibraryElement, JS.TemporaryId>(); | 64 final _imports = new Map<LibraryElement, JS.TemporaryId>(); |
65 | 65 |
66 /// The list of output module items, in the order they need to be emitted in. | 66 /// The list of output module items, in the order they need to be emitted in. |
67 final _moduleItems = <JS.ModuleItem>[]; | 67 final _moduleItems = <JS.ModuleItem>[]; |
68 | 68 |
69 /// Table of named and possibly hoisted types. | |
70 final _typeTable = new _TypeTable(); | |
71 | |
69 /// The global extension type table. | 72 /// The global extension type table. |
70 final ExtensionTypeSet _extensionTypes; | 73 final ExtensionTypeSet _extensionTypes; |
71 | 74 |
72 /// The variable for the target of the current `..` cascade expression. | 75 /// The variable for the target of the current `..` cascade expression. |
73 /// | 76 /// |
74 /// Usually a [SimpleIdentifier], but it can also be other expressions | 77 /// Usually a [SimpleIdentifier], but it can also be other expressions |
75 /// that are safe to evaluate multiple times, such as `this`. | 78 /// that are safe to evaluate multiple times, such as `this`. |
76 Expression _cascadeTarget; | 79 Expression _cascadeTarget; |
77 | 80 |
78 /// The variable for the current catch clause | 81 /// The variable for the current catch clause |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
245 // Visit each compilation unit and emit its code. | 248 // Visit each compilation unit and emit its code. |
246 // | 249 // |
247 // NOTE: declarations are not necessarily emitted in this order. | 250 // NOTE: declarations are not necessarily emitted in this order. |
248 // Order will be changed as needed so the resulting code can execute. | 251 // Order will be changed as needed so the resulting code can execute. |
249 // This is done by forward declaring items. | 252 // This is done by forward declaring items. |
250 compilationUnits.forEach(visitCompilationUnit); | 253 compilationUnits.forEach(visitCompilationUnit); |
251 | 254 |
252 // Declare imports | 255 // Declare imports |
253 _finishImports(items); | 256 _finishImports(items); |
254 | 257 |
258 // Discharge the type table cache variables and | |
259 // hoisted definitions. | |
260 items.addAll(_typeTable.discharge()); | |
261 | |
255 // Add the module's code (produced by visiting compilation units, above) | 262 // Add the module's code (produced by visiting compilation units, above) |
256 _copyAndFlattenBlocks(items, _moduleItems); | 263 _copyAndFlattenBlocks(items, _moduleItems); |
257 | 264 |
258 // Build the module. | 265 // Build the module. |
259 var module = new JS.Program(items, name: _buildUnit.name); | 266 var module = new JS.Program(items, name: _buildUnit.name); |
260 | 267 |
261 // Optional: lower module format. Otherwise just return it. | 268 // Optional: lower module format. Otherwise just return it. |
262 switch (options.moduleFormat) { | 269 switch (options.moduleFormat) { |
263 case ModuleFormat.legacy: | 270 case ModuleFormat.legacy: |
264 return new LegacyModuleBuilder().build(module); | 271 return new LegacyModuleBuilder().build(module); |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
561 return null; | 568 return null; |
562 } | 569 } |
563 | 570 |
564 @override | 571 @override |
565 visitFunctionTypeAlias(FunctionTypeAlias node) { | 572 visitFunctionTypeAlias(FunctionTypeAlias node) { |
566 FunctionTypeAliasElement element = node.element; | 573 FunctionTypeAliasElement element = node.element; |
567 | 574 |
568 JS.Expression body = annotate( | 575 JS.Expression body = annotate( |
569 js.call('dart.typedef(#, () => #)', [ | 576 js.call('dart.typedef(#, () => #)', [ |
570 js.string(element.name, "'"), | 577 js.string(element.name, "'"), |
571 _emitType(element.type, lowerTypedef: true) | 578 _emitType(element.type, nameType: false, lowerTypedef: true) |
572 ]), | 579 ]), |
573 node, | 580 node, |
574 element); | 581 element); |
575 | 582 |
576 var typeFormals = element.typeParameters; | 583 var typeFormals = element.typeParameters; |
577 if (typeFormals.isNotEmpty) { | 584 if (typeFormals.isNotEmpty) { |
578 return _defineClassTypeArguments(element, typeFormals, | 585 return _defineClassTypeArguments(element, typeFormals, |
579 js.statement('const # = #;', [element.name, body])); | 586 js.statement('const # = #;', [element.name, body])); |
580 } else { | 587 } else { |
581 return js.statement('# = #;', [_emitTopLevelName(element), body]); | 588 return js.statement('# = #;', [_emitTopLevelName(element), body]); |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
833 result.add(js.statement( | 840 result.add(js.statement( |
834 '#.values = dart.constList(#, #);', [id, values, _emitType(type)])); | 841 '#.values = dart.constList(#, #);', [id, values, _emitType(type)])); |
835 | 842 |
836 return _statement(result); | 843 return _statement(result); |
837 } | 844 } |
838 | 845 |
839 /// Wraps a possibly generic class in its type arguments. | 846 /// Wraps a possibly generic class in its type arguments. |
840 JS.Statement _defineClassTypeArguments(TypeDefiningElement element, | 847 JS.Statement _defineClassTypeArguments(TypeDefiningElement element, |
841 List<TypeParameterElement> formals, JS.Statement body) { | 848 List<TypeParameterElement> formals, JS.Statement body) { |
842 assert(formals.isNotEmpty); | 849 assert(formals.isNotEmpty); |
843 var genericCall = js.call('dart.generic((#) => { #; return #; })', | 850 var genericCall = js.call('dart.generic((#) => { #; #; return #; })', [ |
844 [_emitTypeFormals(formals), body, element.name]); | 851 _emitTypeFormals(formals), |
852 _typeTable.discharge(formals), | |
853 body, | |
854 element.name | |
855 ]); | |
845 if (element.library.isDartAsync && | 856 if (element.library.isDartAsync && |
846 (element.name == "Future" || element.name == "_Future")) { | 857 (element.name == "Future" || element.name == "_Future")) { |
847 genericCall = js.call('dart.flattenFutures(#)', [genericCall]); | 858 genericCall = js.call('dart.flattenFutures(#)', [genericCall]); |
848 } | 859 } |
849 var genericDef = js.statement( | 860 var genericDef = js.statement( |
850 '# = #;', [_emitTopLevelName(element, suffix: r'$'), genericCall]); | 861 '# = #;', [_emitTopLevelName(element, suffix: r'$'), genericCall]); |
851 var dynType = fillDynamicTypeArgs(element.type); | 862 var dynType = fillDynamicTypeArgs(element.type); |
852 var genericInst = _emitType(dynType, lowerGeneric: true); | 863 var genericInst = _emitType(dynType, lowerGeneric: true); |
853 return js.statement( | 864 return js.statement( |
854 '{ #; # = #; }', [genericDef, _emitTopLevelName(element), genericInst]); | 865 '{ #; # = #; }', [genericDef, _emitTopLevelName(element), genericInst]); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
887 _loader.startTopLevel(element); | 898 _loader.startTopLevel(element); |
888 | 899 |
889 // Find the super type | 900 // Find the super type |
890 JS.Expression heritage; | 901 JS.Expression heritage; |
891 var supertype = type.superclass; | 902 var supertype = type.superclass; |
892 if (_deferIfNeeded(supertype, element)) { | 903 if (_deferIfNeeded(supertype, element)) { |
893 // Fall back to raw type. | 904 // Fall back to raw type. |
894 supertype = fillDynamicTypeArgs(supertype.element.type); | 905 supertype = fillDynamicTypeArgs(supertype.element.type); |
895 _hasDeferredSupertype.add(element); | 906 _hasDeferredSupertype.add(element); |
896 } | 907 } |
897 heritage = _emitType(supertype); | 908 // We could choose to name the superclasses, but it's |
909 // not clear that there's much benefit | |
910 heritage = _emitType(supertype, nameType: false); | |
898 | 911 |
899 if (type.mixins.isNotEmpty) { | 912 if (type.mixins.isNotEmpty) { |
900 var mixins = type.mixins.map(_emitType).toList(); | 913 var mixins = |
914 type.mixins.map((t) => _emitType(t, nameType: false)).toList(); | |
901 mixins.insert(0, heritage); | 915 mixins.insert(0, heritage); |
902 heritage = js.call('dart.mixin(#)', [mixins]); | 916 heritage = js.call('dart.mixin(#)', [mixins]); |
903 } | 917 } |
904 | 918 |
905 _loader.finishTopLevel(element); | 919 _loader.finishTopLevel(element); |
906 | 920 |
907 return heritage; | 921 return heritage; |
908 } | 922 } |
909 | 923 |
910 /// Provide Dart getters and setters that forward to the underlying native | 924 /// Provide Dart getters and setters that forward to the underlying native |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1152 | 1166 |
1153 void _setBaseClass(ClassElement classElem, JS.Expression className, | 1167 void _setBaseClass(ClassElement classElem, JS.Expression className, |
1154 String jsPeerName, List<JS.Statement> body) { | 1168 String jsPeerName, List<JS.Statement> body) { |
1155 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) { | 1169 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) { |
1156 // TODO(jmesserly): we should really just extend Array in the first place. | 1170 // TODO(jmesserly): we should really just extend Array in the first place. |
1157 var newBaseClass = js.call('dart.global.#', [jsPeerName]); | 1171 var newBaseClass = js.call('dart.global.#', [jsPeerName]); |
1158 body.add(js.statement( | 1172 body.add(js.statement( |
1159 'dart.setExtensionBaseClass(#, #);', [className, newBaseClass])); | 1173 'dart.setExtensionBaseClass(#, #);', [className, newBaseClass])); |
1160 } else if (_hasDeferredSupertype.contains(classElem)) { | 1174 } else if (_hasDeferredSupertype.contains(classElem)) { |
1161 var newBaseClass = _emitType(classElem.type.superclass, | 1175 var newBaseClass = _emitType(classElem.type.superclass, |
1162 subClass: classElem, className: className); | 1176 nameType: false, subClass: classElem, className: className); |
1163 body.add( | 1177 body.add( |
1164 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass])); | 1178 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass])); |
1165 } | 1179 } |
1166 } | 1180 } |
1167 | 1181 |
1168 void _defineNamedConstructors(List<ConstructorDeclaration> ctors, | 1182 void _defineNamedConstructors(List<ConstructorDeclaration> ctors, |
1169 List<JS.Statement> body, JS.Expression className) { | 1183 List<JS.Statement> body, JS.Expression className) { |
1170 for (ConstructorDeclaration member in ctors) { | 1184 for (ConstructorDeclaration member in ctors) { |
1171 if (member.name != null && member.factoryKeyword == null) { | 1185 if (member.name != null && member.factoryKeyword == null) { |
1172 body.add(js.statement('dart.defineNamedConstructor(#, #);', | 1186 body.add(js.statement('dart.defineNamedConstructor(#, #);', |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1252 if (!(node.isSetter || node.isGetter || node.isAbstract)) { | 1266 if (!(node.isSetter || node.isGetter || node.isAbstract)) { |
1253 var name = node.name.name; | 1267 var name = node.name.name; |
1254 var element = node.element; | 1268 var element = node.element; |
1255 var inheritedElement = | 1269 var inheritedElement = |
1256 classElem.lookUpInheritedConcreteMethod(name, currentLibrary); | 1270 classElem.lookUpInheritedConcreteMethod(name, currentLibrary); |
1257 if (inheritedElement != null && inheritedElement.type == element.type) { | 1271 if (inheritedElement != null && inheritedElement.type == element.type) { |
1258 continue; | 1272 continue; |
1259 } | 1273 } |
1260 var memberName = _elementMemberName(element, | 1274 var memberName = _elementMemberName(element, |
1261 useExtension: _extensionTypes.isNativeClass(classElem)); | 1275 useExtension: _extensionTypes.isNativeClass(classElem)); |
1262 var parts = _emitFunctionTypeParts(element.type); | 1276 // TODO(leafp): Settle on a policy for this. Naming these makes the |
1263 var property = | 1277 // signature more compact, but it generates a lot of noise at the |
1264 new JS.Property(memberName, new JS.ArrayInitializer(parts)); | 1278 // top level, and it's not clear that there's much benefit. |
1279 var type = | |
1280 _emitFunctionType(element.type, nameType: false, definite: true); | |
1281 var property = new JS.Property(memberName, type); | |
1265 if (node.isStatic) { | 1282 if (node.isStatic) { |
1266 tStatics.add(property); | 1283 tStatics.add(property); |
1267 sNames.add(memberName); | 1284 sNames.add(memberName); |
1268 } else { | 1285 } else { |
1269 tMethods.add(property); | 1286 tMethods.add(property); |
1270 } | 1287 } |
1271 } | 1288 } |
1272 } | 1289 } |
1273 | 1290 |
1274 var tCtors = <JS.Property>[]; | 1291 var tCtors = <JS.Property>[]; |
1275 for (ConstructorDeclaration node in ctors) { | 1292 for (ConstructorDeclaration node in ctors) { |
1276 var memberName = _constructorName(node.element); | 1293 var memberName = _constructorName(node.element); |
1277 var element = node.element; | 1294 var element = node.element; |
1278 var parts = _emitFunctionTypeParts(element.type, | 1295 var type = _emitFunctionType(element.type, |
1279 parameters: node.parameters.parameters); | 1296 parameters: node.parameters.parameters, |
1280 var property = | 1297 nameType: false, |
1281 new JS.Property(memberName, new JS.ArrayInitializer(parts)); | 1298 definite: true); |
1299 var property = new JS.Property(memberName, type); | |
1282 tCtors.add(property); | 1300 tCtors.add(property); |
1283 } | 1301 } |
1284 | 1302 |
1285 JS.Property build(String name, List<JS.Property> elements) { | 1303 JS.Property build(String name, List<JS.Property> elements) { |
1286 var o = | 1304 var o = |
1287 new JS.ObjectInitializer(elements, multiline: elements.length > 1); | 1305 new JS.ObjectInitializer(elements, multiline: elements.length > 1); |
1288 var e = js.call('() => #', o); | 1306 var e = js.call('() => #', o); |
1289 return new JS.Property(_propertyName(name), e); | 1307 return new JS.Property(_propertyName(name), e); |
1290 } | 1308 } |
1291 var sigFields = <JS.Property>[]; | 1309 var sigFields = <JS.Property>[]; |
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1911 } | 1929 } |
1912 if (type.isDynamic || type.isVoid || type.isBottom) return true; | 1930 if (type.isDynamic || type.isVoid || type.isBottom) return true; |
1913 if (type is ParameterizedType && !type.typeArguments.every(_typeIsLoaded)) { | 1931 if (type is ParameterizedType && !type.typeArguments.every(_typeIsLoaded)) { |
1914 return false; | 1932 return false; |
1915 } | 1933 } |
1916 return _loader.isLoaded(type.element); | 1934 return _loader.isLoaded(type.element); |
1917 } | 1935 } |
1918 | 1936 |
1919 JS.Expression _emitFunctionTagged(JS.Expression fn, DartType type, | 1937 JS.Expression _emitFunctionTagged(JS.Expression fn, DartType type, |
1920 {topLevel: false}) { | 1938 {topLevel: false}) { |
1921 var name = type.name; | |
1922 var lazy = topLevel && !_typeIsLoaded(type); | 1939 var lazy = topLevel && !_typeIsLoaded(type); |
1923 | 1940 var typeRep = _emitFunctionType(type, definite: true); |
1924 if (type is FunctionType && (name == '' || name == null)) { | 1941 if (lazy) { |
1925 if (type.typeFormals.isEmpty && | 1942 return js.call('dart.lazyFn(#, () => #)', [fn, typeRep]); |
1926 type.returnType.isDynamic && | 1943 } else { |
1927 type.optionalParameterTypes.isEmpty && | 1944 return js.call('dart.fn(#, #)', [fn, typeRep]); |
1928 type.namedParameterTypes.isEmpty && | |
1929 type.normalParameterTypes.every((t) => t.isDynamic)) { | |
1930 return js.call('dart.fn(#)', [fn]); | |
1931 } | |
1932 | |
1933 var parts = _emitFunctionTypeParts(type); | |
1934 if (lazy) { | |
1935 return js.call( | |
1936 'dart.lazyFn(#, () => #)', [fn, new JS.ArrayInitializer(parts)]); | |
1937 } else { | |
1938 return js.call('dart.fn(#, #)', [fn, parts]); | |
1939 } | |
1940 } | 1945 } |
1941 throw 'Function has non function type: $type'; | 1946 throw 'Function has non function type: $type'; |
1942 } | 1947 } |
1943 | 1948 |
1944 /// Emits an arrow FunctionExpression node. | 1949 /// Emits an arrow FunctionExpression node. |
1945 /// | 1950 /// |
1946 /// This should be used for all places in Dart's AST where FunctionExpression | 1951 /// This should be used for all places in Dart's AST where FunctionExpression |
1947 /// appears and the function is actually in an Expression context. These | 1952 /// appears and the function is actually in an Expression context. These |
1948 /// correspond to arrow functions in Dart. | 1953 /// correspond to arrow functions in Dart. |
1949 /// | 1954 /// |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2005 /// Contrast with [visitFunctionExpression]. | 2010 /// Contrast with [visitFunctionExpression]. |
2006 JS.Fun _emitFunction(FunctionExpression node) { | 2011 JS.Fun _emitFunction(FunctionExpression node) { |
2007 var fn = _emitFunctionBody(node.element, node.parameters, node.body); | 2012 var fn = _emitFunctionBody(node.element, node.parameters, node.body); |
2008 return annotate(_makeGenericFunction(fn), node); | 2013 return annotate(_makeGenericFunction(fn), node); |
2009 } | 2014 } |
2010 | 2015 |
2011 JS.Fun _emitFunctionBody(ExecutableElement element, | 2016 JS.Fun _emitFunctionBody(ExecutableElement element, |
2012 FormalParameterList parameters, FunctionBody body) { | 2017 FormalParameterList parameters, FunctionBody body) { |
2013 FunctionType type = element.type; | 2018 FunctionType type = element.type; |
2014 | 2019 |
2015 // sync*, async, async* | 2020 // normal function (sync), vs (sync*, async, async*) |
2016 if (element.isAsynchronous || element.isGenerator) { | 2021 var stdFn = !(element.isAsynchronous || element.isGenerator); |
2017 return new JS.Fun( | 2022 var formals = visitFormalParameterList(parameters, destructure: stdFn); |
2018 visitFormalParameterList(parameters, destructure: false), | 2023 var code = (stdFn) |
2019 new JS.Block([ | 2024 ? _visit(body) |
2020 _emitGeneratorFunctionBody(element, parameters, body).toReturn() | 2025 : new JS.Block( |
2021 ]), | 2026 [_emitGeneratorFunctionBody(element, parameters, body).toReturn()]); |
2022 typeParams: _emitTypeFormals(type.typeFormals), | 2027 var typeFormals = _emitTypeFormals(type.typeFormals); |
2023 returnType: emitTypeRef(type.returnType)); | 2028 var returnType = emitTypeRef(type.returnType); |
2029 if (type.typeFormals.isNotEmpty) { | |
2030 code = new JS.Block( | |
2031 [new JS.Block(_typeTable.discharge(type.typeFormals)), code]); | |
2024 } | 2032 } |
2025 | 2033 return new JS.Fun(formals, code, |
2026 // normal function (sync) | 2034 typeParams: typeFormals, returnType: returnType); |
2027 return new JS.Fun(visitFormalParameterList(parameters), _visit(body), | |
2028 typeParams: _emitTypeFormals(type.typeFormals), | |
2029 returnType: emitTypeRef(type.returnType)); | |
2030 } | 2035 } |
2031 | 2036 |
2032 JS.Expression _emitGeneratorFunctionBody(ExecutableElement element, | 2037 JS.Expression _emitGeneratorFunctionBody(ExecutableElement element, |
2033 FormalParameterList parameters, FunctionBody body) { | 2038 FormalParameterList parameters, FunctionBody body) { |
2034 var kind = element.isSynchronous ? 'sync' : 'async'; | 2039 var kind = element.isSynchronous ? 'sync' : 'async'; |
2035 if (element.isGenerator) kind += 'Star'; | 2040 if (element.isGenerator) kind += 'Star'; |
2036 | 2041 |
2037 // Transforms `sync*` `async` and `async*` function bodies | 2042 // Transforms `sync*` `async` and `async*` function bodies |
2038 // using ES6 generators. | 2043 // using ES6 generators. |
2039 // | 2044 // |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2242 | 2247 |
2243 var type = declaration ? emitTypeRef(element.type) : null; | 2248 var type = declaration ? emitTypeRef(element.type) : null; |
2244 return new JS.Identifier(element.name, type: type); | 2249 return new JS.Identifier(element.name, type: type); |
2245 } | 2250 } |
2246 | 2251 |
2247 List<Annotation> _parameterMetadata(FormalParameter p) => | 2252 List<Annotation> _parameterMetadata(FormalParameter p) => |
2248 (p is NormalFormalParameter) | 2253 (p is NormalFormalParameter) |
2249 ? p.metadata | 2254 ? p.metadata |
2250 : (p as DefaultFormalParameter).parameter.metadata; | 2255 : (p as DefaultFormalParameter).parameter.metadata; |
2251 | 2256 |
2252 JS.ArrayInitializer _emitTypeNames(List<DartType> types, | 2257 JS.ArrayInitializer _emitTypeNames( |
2253 [List<FormalParameter> parameters]) { | 2258 List<DartType> types, List<FormalParameter> parameters, |
2259 {bool nameType: true, bool hoistType: true}) { | |
2254 var result = <JS.Expression>[]; | 2260 var result = <JS.Expression>[]; |
2255 for (int i = 0; i < types.length; ++i) { | 2261 for (int i = 0; i < types.length; ++i) { |
2256 var metadata = | 2262 var metadata = |
2257 parameters != null ? _parameterMetadata(parameters[i]) : []; | 2263 parameters != null ? _parameterMetadata(parameters[i]) : []; |
2258 var typeName = _emitType(types[i]); | 2264 var typeName = |
2265 _emitType(types[i], nameType: nameType, hoistType: hoistType); | |
2259 var value = typeName; | 2266 var value = typeName; |
2260 if (options.emitMetadata && metadata.isNotEmpty) { | 2267 if (options.emitMetadata && metadata.isNotEmpty) { |
2261 metadata = metadata.map(_instantiateAnnotation).toList(); | 2268 metadata = metadata.map(_instantiateAnnotation).toList(); |
2262 value = new JS.ArrayInitializer([typeName]..addAll(metadata)); | 2269 value = new JS.ArrayInitializer([typeName]..addAll(metadata)); |
2263 } | 2270 } |
2264 result.add(value); | 2271 result.add(value); |
2265 } | 2272 } |
2266 return new JS.ArrayInitializer(result); | 2273 return new JS.ArrayInitializer(result); |
2267 } | 2274 } |
2268 | 2275 |
2269 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { | 2276 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { |
2270 var properties = <JS.Property>[]; | 2277 var properties = <JS.Property>[]; |
2271 types.forEach((name, type) { | 2278 types.forEach((name, type) { |
2272 var key = _propertyName(name); | 2279 var key = _propertyName(name); |
2273 var value = _emitType(type); | 2280 var value = _emitType(type); |
2274 properties.add(new JS.Property(key, value)); | 2281 properties.add(new JS.Property(key, value)); |
2275 }); | 2282 }); |
2276 return new JS.ObjectInitializer(properties); | 2283 return new JS.ObjectInitializer(properties); |
2277 } | 2284 } |
2278 | 2285 |
2279 /// Emit the pieces of a function type, as an array of return type, | 2286 /// Emit the pieces of a function type, as an array of return type, |
2280 /// regular args, and optional/named args. | 2287 /// regular args, and optional/named args. |
2288 JS.Expression _emitFunctionType(FunctionType type, | |
2289 {List<FormalParameter> parameters, | |
2290 bool lowerTypedef: false, | |
2291 bool nameType: true, | |
2292 bool hoistType: true, | |
Jennifer Messerly
2016/05/24 21:56:39
do we ever set this to false? I wasn't able to fin
Leaf
2016/05/25 00:56:13
It was here so that we can play with different str
| |
2293 definite: false}) { | |
2294 var parts = _emitFunctionTypeParts(type, | |
2295 parameters: parameters, | |
2296 lowerTypedef: lowerTypedef, | |
2297 nameType: nameType, | |
2298 hoistType: hoistType); | |
2299 var helper = (definite) ? 'definiteFunctionType' : 'functionType'; | |
2300 var fullType = js.call('dart.${helper}(#)', [parts]); | |
2301 if (!nameType) return fullType; | |
2302 return _typeTable.nameType(type, fullType, hoistType, definite: definite); | |
2303 } | |
2304 | |
2305 /// Emit the pieces of a function type, as an array of return type, | |
2306 /// regular args, and optional/named args. | |
2281 List<JS.Expression> _emitFunctionTypeParts(FunctionType type, | 2307 List<JS.Expression> _emitFunctionTypeParts(FunctionType type, |
2282 {List<FormalParameter> parameters, bool lowerTypedef: false}) { | 2308 {List<FormalParameter> parameters, |
2309 bool lowerTypedef: false, | |
2310 bool nameType: true, | |
2311 bool hoistType: true}) { | |
2283 var parameterTypes = type.normalParameterTypes; | 2312 var parameterTypes = type.normalParameterTypes; |
2284 var optionalTypes = type.optionalParameterTypes; | 2313 var optionalTypes = type.optionalParameterTypes; |
2285 var namedTypes = type.namedParameterTypes; | 2314 var namedTypes = type.namedParameterTypes; |
2286 var rt = _emitType(type.returnType); | 2315 var rt = |
2287 var ra = _emitTypeNames(parameterTypes, parameters); | 2316 _emitType(type.returnType, nameType: nameType, hoistType: hoistType); |
2317 var ra = _emitTypeNames(parameterTypes, parameters, | |
2318 nameType: nameType, hoistType: hoistType); | |
2288 | 2319 |
2289 List<JS.Expression> typeParts; | 2320 List<JS.Expression> typeParts; |
2290 if (namedTypes.isNotEmpty) { | 2321 if (namedTypes.isNotEmpty) { |
2291 assert(optionalTypes.isEmpty); | 2322 assert(optionalTypes.isEmpty); |
2292 // TODO(vsm): Pass in annotations here as well. | 2323 // TODO(vsm): Pass in annotations here as well. |
2293 var na = _emitTypeProperties(namedTypes); | 2324 var na = _emitTypeProperties(namedTypes); |
2294 typeParts = [rt, ra, na]; | 2325 typeParts = [rt, ra, na]; |
2295 } else if (optionalTypes.isNotEmpty) { | 2326 } else if (optionalTypes.isNotEmpty) { |
2296 assert(namedTypes.isEmpty); | 2327 assert(namedTypes.isEmpty); |
2297 var oa = _emitTypeNames( | 2328 var oa = _emitTypeNames( |
2298 optionalTypes, parameters?.sublist(parameterTypes.length)); | 2329 optionalTypes, parameters?.sublist(parameterTypes.length), |
2330 nameType: nameType, hoistType: hoistType); | |
2299 typeParts = [rt, ra, oa]; | 2331 typeParts = [rt, ra, oa]; |
2300 } else { | 2332 } else { |
2301 typeParts = [rt, ra]; | 2333 typeParts = [rt, ra]; |
2302 } | 2334 } |
2303 | 2335 |
2304 var typeFormals = type.typeFormals; | 2336 var typeFormals = type.typeFormals; |
2305 if (typeFormals.isNotEmpty && !lowerTypedef) { | 2337 if (typeFormals.isNotEmpty && !lowerTypedef) { |
2306 // TODO(jmesserly): this is a suboptimal representation for universal | 2338 // TODO(jmesserly): this is a suboptimal representation for universal |
2307 // function types (as callable functions). See discussion at: | 2339 // function types (as callable functions). See discussion at: |
2308 // https://github.com/dart-lang/dev_compiler/issues/526 | 2340 // https://github.com/dart-lang/dev_compiler/issues/526 |
2309 var tf = _emitTypeFormals(typeFormals); | 2341 var tf = _emitTypeFormals(typeFormals); |
2310 typeParts = [new JS.ArrowFun(tf, new JS.ArrayInitializer(typeParts))]; | 2342 var names = _typeTable.discharge(typeFormals); |
2343 var parts = new JS.ArrayInitializer(typeParts); | |
2344 if (names.isEmpty) { | |
2345 typeParts = [ | |
2346 js.call('(#) => #', [tf, parts]) | |
2347 ]; | |
2348 } else { | |
2349 typeParts = [ | |
2350 js.call('(#) => {#; return #;}', [tf, names, parts]) | |
2351 ]; | |
2352 } | |
2311 } | 2353 } |
2312 return typeParts; | 2354 return typeParts; |
2313 } | 2355 } |
2314 | 2356 |
2315 /// Emits a Dart [type] into code. | 2357 /// Emits a Dart [type] into code. |
2316 /// | 2358 /// |
2317 /// If [lowerTypedef] is set, a typedef will be expanded as if it were a | 2359 /// If [lowerTypedef] is set, a typedef will be expanded as if it were a |
2318 /// function type. Similarly if [lowerGeneric] is set, the `List$()` form | 2360 /// function type. Similarly if [lowerGeneric] is set, the `List$()` form |
2319 /// will be used instead of `List`. These flags are used when generating | 2361 /// will be used instead of `List`. These flags are used when generating |
2320 /// the definitions for typedefs and generic types, respectively. | 2362 /// the definitions for typedefs and generic types, respectively. |
2321 /// | 2363 /// |
2322 /// If [subClass] is set, then we are setting the base class for the given | 2364 /// If [subClass] is set, then we are setting the base class for the given |
2323 /// class and should emit the given [className], which will already be | 2365 /// class and should emit the given [className], which will already be |
2324 /// defined. | 2366 /// defined. |
2325 JS.Expression _emitType(DartType type, | 2367 JS.Expression _emitType(DartType type, |
2326 {bool lowerTypedef: false, | 2368 {bool lowerTypedef: false, |
2327 bool lowerGeneric: false, | 2369 bool lowerGeneric: false, |
2370 bool nameType: true, | |
2371 bool hoistType: true, | |
2328 ClassElement subClass, | 2372 ClassElement subClass, |
2329 JS.Expression className}) { | 2373 JS.Expression className}) { |
2330 // The void and dynamic types are not defined in core. | 2374 // The void and dynamic types are not defined in core. |
2331 if (type.isVoid) { | 2375 if (type.isVoid) { |
2332 return js.call('dart.void'); | 2376 return js.call('dart.void'); |
2333 } else if (type.isDynamic) { | 2377 } else if (type.isDynamic) { |
2334 return js.call('dart.dynamic'); | 2378 return js.call('dart.dynamic'); |
2335 } else if (type.isBottom) { | 2379 } else if (type.isBottom) { |
2336 return js.call('dart.bottom'); | 2380 return js.call('dart.bottom'); |
2337 } | 2381 } |
2338 | 2382 |
2339 _declareBeforeUse(type.element); | 2383 _declareBeforeUse(type.element); |
2340 | 2384 |
2341 // TODO(jmesserly): like constants, should we hoist function types out of | 2385 // TODO(jmesserly): like constants, should we hoist function types out of |
2342 // methods? Similar issue with generic types. For all of these, we may want | 2386 // methods? Similar issue with generic types. For all of these, we may want |
2343 // to canonicalize them too, at least when inside the same library. | 2387 // to canonicalize them too, at least when inside the same library. |
2344 var name = type.name; | 2388 var name = type.name; |
2345 var element = type.element; | 2389 var element = type.element; |
2346 if (name == '' || name == null || lowerTypedef) { | 2390 if (name == '' || name == null || lowerTypedef) { |
2347 // TODO(jmesserly): should we change how typedefs work? They currently | 2391 // TODO(jmesserly): should we change how typedefs work? They currently |
2348 // go through use similar logic as generic classes. This makes them | 2392 // go through use similar logic as generic classes. This makes them |
2349 // different from universal function types. | 2393 // different from universal function types. |
2350 var ft = type as FunctionType; | 2394 return _emitFunctionType(type as FunctionType, |
2351 var parts = _emitFunctionTypeParts(ft, lowerTypedef: lowerTypedef); | 2395 lowerTypedef: lowerTypedef, nameType: nameType, hoistType: hoistType); |
2352 return js.call('dart.functionType(#)', [parts]); | |
2353 } | 2396 } |
2354 | 2397 |
2355 if (type is TypeParameterType) { | 2398 if (type is TypeParameterType) { |
2356 _typeParamInConst?.add(type); | 2399 _typeParamInConst?.add(type); |
2357 return new JS.Identifier(name); | 2400 return new JS.Identifier(name); |
2358 } | 2401 } |
2359 | 2402 |
2360 if (type == subClass?.type) { | 2403 if (type == subClass?.type) { |
2361 return className; | 2404 return className; |
2362 } | 2405 } |
2363 | 2406 |
2364 if (type is ParameterizedType) { | 2407 if (type is ParameterizedType) { |
2365 var args = type.typeArguments; | 2408 var args = type.typeArguments; |
2366 Iterable jsArgs = null; | 2409 Iterable jsArgs = null; |
2367 if (args.any((a) => !a.isDynamic)) { | 2410 if (args.any((a) => !a.isDynamic)) { |
2368 jsArgs = args | 2411 jsArgs = args.map((x) => _emitType(x, |
2369 .map((x) => _emitType(x, subClass: subClass, className: className)); | 2412 nameType: nameType, |
2413 hoistType: hoistType, | |
2414 subClass: subClass, | |
2415 className: className)); | |
2370 } else if (lowerGeneric) { | 2416 } else if (lowerGeneric) { |
2371 jsArgs = []; | 2417 jsArgs = []; |
2372 } | 2418 } |
2373 if (jsArgs != null) { | 2419 if (jsArgs != null) { |
2374 var genericName = _emitTopLevelName(element, suffix: '\$'); | 2420 var genericName = _emitTopLevelName(element, suffix: '\$'); |
2375 return js.call('#(#)', [genericName, jsArgs]); | 2421 var typeRep = js.call('#(#)', [genericName, jsArgs]); |
2422 return nameType | |
2423 ? _typeTable.nameType(type, typeRep, hoistType) | |
2424 : typeRep; | |
2376 } | 2425 } |
2377 } | 2426 } |
2378 | 2427 |
2379 return _emitTopLevelName(element); | 2428 return _emitTopLevelName(element); |
2380 } | 2429 } |
2381 | 2430 |
2382 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { | 2431 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { |
2383 var interop = _emitJSInterop(e); | 2432 var interop = _emitJSInterop(e); |
2384 if (interop != null) return interop; | 2433 if (interop != null) return interop; |
2385 String name = getJSExportName(e) + suffix; | 2434 String name = getJSExportName(e) + suffix; |
(...skipping 2172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4558 } | 4607 } |
4559 | 4608 |
4560 bool isLibraryPrefix(Expression node) => | 4609 bool isLibraryPrefix(Expression node) => |
4561 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4610 node is SimpleIdentifier && node.staticElement is PrefixElement; |
4562 | 4611 |
4563 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4612 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
4564 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4613 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
4565 | 4614 |
4566 bool _isDartRuntime(LibraryElement l) => | 4615 bool _isDartRuntime(LibraryElement l) => |
4567 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4616 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
4617 | |
4618 Set<TypeParameterElement> _freeTypeParameters(DartType t) { | |
4619 var result = new HashSet<TypeParameterElement>(); | |
4620 void find(DartType t) { | |
4621 if (t is TypeParameterType) { | |
4622 result.add(t.element); | |
4623 } else if (t is FunctionType) { | |
4624 find(t.returnType); | |
4625 t.parameters.forEach((p) => find(p.type)); | |
4626 t.typeFormals.forEach((p) => find(p.bound)); | |
4627 t.typeFormals.forEach(result.remove); | |
4628 } else if (t is InterfaceType) { | |
4629 t.typeArguments.forEach(find); | |
4630 } | |
4631 } | |
4632 find(t); | |
4633 return result; | |
4634 } | |
4635 | |
4636 /// _CacheTable tracks cache variables for variables that | |
4637 /// are emitted in place with a hoisted variable for a cache. | |
Jennifer Messerly
2016/05/24 21:56:39
Consider: including an example here of what it loo
Leaf
2016/05/25 00:56:13
Done below.
| |
4638 class _CacheTable { | |
Jennifer Messerly
2016/05/24 21:56:39
consider: putting these new classes into their own
Leaf
2016/05/25 00:56:13
Done.
| |
4639 /// Mapping from types to their canonical names. | |
4640 final _names = new Map<DartType, JS.TemporaryId>(); | |
4641 Iterable<DartType> get keys => _names.keys.toList(); | |
4642 | |
4643 JS.Statement _dischargeType(DartType type) { | |
4644 var name = _names.remove(type); | |
4645 if (name != null) { | |
4646 return (js.statement('let #;', [name])); | |
Jennifer Messerly
2016/05/24 21:56:39
nit: parens not needed around return value
Leaf
2016/05/25 00:56:13
Done.
Leaf
2016/05/25 00:56:13
Done.
| |
4647 } | |
4648 return null; | |
4649 } | |
4650 | |
4651 /// Emit a list of statements declaring the cache variables for | |
Jennifer Messerly
2016/05/24 21:56:39
doc comment style nit -- first sentence should be
Leaf
2016/05/25 00:56:13
Acknowledged.
| |
4652 /// types tracked by this table. If [typeFilter] is given, | |
4653 /// only emit the types listed in the filter. | |
4654 List<JS.Statement> discharge([Iterable<DartType> typeFilter]) { | |
4655 var decls = <JS.Statement>[]; | |
4656 var types = typeFilter ?? keys; | |
4657 for (var t in types) { | |
4658 var stmt = _dischargeType(t); | |
4659 if (stmt != null) decls.add(stmt); | |
4660 } | |
4661 return decls; | |
4662 } | |
4663 | |
4664 bool isNamed(DartType type) => _names.containsKey(type); | |
4665 | |
4666 /// If [type] is not already in the table, choose a new canonical | |
4667 /// variable to contain it. Emit an expression which uses [typeRep] to | |
4668 /// lazily initialize the cache in place. | |
4669 JS.Expression nameType(DartType type, JS.Expression typeRep) { | |
4670 var temp = _names[type]; | |
Jennifer Messerly
2016/05/24 21:56:39
you could also do
var temp = _names.putIfAbse
Leaf
2016/05/25 00:56:13
Acknowledged.
| |
4671 if (temp == null) { | |
4672 ; | |
Jennifer Messerly
2016/05/24 21:56:39
unintended empty statement?
Leaf
2016/05/25 00:56:13
Done.
| |
4673 _names[type] = temp = chooseTypeName(type); | |
4674 } | |
4675 return js.call('# || (# = #)', [temp, temp, typeRep]); | |
4676 } | |
4677 | |
4678 String _typeString(DartType type, {bool flat: false}) { | |
4679 if (type is ParameterizedType && type.name != null) { | |
4680 var clazz = type.name; | |
4681 var params = type.typeArguments; | |
4682 if (params == null) return clazz; | |
4683 if (params.every((p) => p.isDynamic)) return clazz; | |
4684 var paramStrings = params.map(_typeString); | |
4685 var paramString = paramStrings.join("\$"); | |
4686 return "${clazz}Of${paramString}"; | |
4687 } | |
4688 if (type is FunctionType) { | |
4689 if (flat) return "Fn"; | |
4690 var rType = _typeString(type.returnType, flat: true); | |
4691 var paramStrings = type.normalParameterTypes | |
4692 .take(3) | |
4693 .map((p) => _typeString(p, flat: true)); | |
4694 var paramString = paramStrings.join("And"); | |
4695 var count = type.normalParameterTypes.length; | |
4696 if (count > 3 || | |
4697 type.namedParameterTypes.isNotEmpty || | |
4698 type.optionalParameterTypes.isNotEmpty) { | |
4699 paramString = "${paramString}__"; | |
4700 } else if (count == 0) { | |
4701 paramString = "Void"; | |
4702 } | |
4703 return "${paramString}To${rType}"; | |
4704 } | |
4705 if (type is TypeParameterType) return type.name; | |
4706 if (type.name != null) return type.name; | |
4707 return "type"; | |
4708 } | |
4709 | |
4710 /// Heuristically choose a good name for the cache and generator | |
4711 /// variables. | |
4712 JS.Identifier chooseTypeName(DartType type) { | |
4713 return new JS.TemporaryId(_typeString(type)); | |
4714 } | |
4715 } | |
4716 | |
4717 /// _GeneratorTable tracks types which have been | |
4718 /// named and hoisted. | |
4719 class _GeneratorTable extends _CacheTable { | |
4720 final _defs = new Map<DartType, JS.Expression>(); | |
4721 | |
4722 _GeneratorTable(); | |
Jennifer Messerly
2016/05/24 21:56:39
note: this is not needed
Leaf
2016/05/25 00:56:13
Done.
| |
4723 | |
4724 JS.Statement _dischargeType(DartType t) { | |
4725 var name = _names.remove(t); | |
4726 if (name != null) { | |
4727 JS.Expression init = _defs.remove(t); | |
4728 assert(init != null); | |
4729 return js.statement( | |
4730 'let # = () => ((# = dart.constFn(#))());', [name, name, init]); | |
4731 } | |
4732 return null; | |
4733 } | |
4734 | |
4735 /// If [type] does not already have a generator name chosen for it, | |
4736 /// assign it one, using [typeRep] as the initializer for it. | |
4737 /// Emit an expression which calls the generator name. | |
4738 JS.Expression nameType(DartType type, JS.Expression typeRep) { | |
Jennifer Messerly
2016/05/24 21:56:39
this looks mostly identical to the super method, m
Leaf
2016/05/25 00:56:13
It's 3 of 5 lines that are duplicated. I don't se
| |
4739 var temp = _names[type]; | |
4740 if (temp == null) { | |
4741 _names[type] = temp = chooseTypeName(type); | |
4742 _defs[type] = typeRep; | |
4743 } | |
4744 return js.call('#()', [temp]); | |
4745 } | |
4746 } | |
4747 | |
4748 class _TypeTable { | |
4749 /// Cache variable names for types emitted in place. | |
4750 final _cacheNames = new _CacheTable(); | |
4751 | |
4752 /// Cache variable names for definite function types emitted in place. | |
4753 final _definiteCacheNames = new _CacheTable(); | |
4754 | |
4755 /// Generator variable names for hoisted types. | |
4756 final _generators = new _GeneratorTable(); | |
4757 | |
4758 /// Generator variable names for hoisted definite function types. | |
4759 final _definiteGenerators = new _GeneratorTable(); | |
4760 | |
4761 /// Mapping from type parameters to the types which must have their | |
4762 /// cache/generator variables discharged at the binding site for the | |
4763 /// type variable since the type definition depends on the type | |
4764 /// parameter. | |
4765 final _scopeDependencies = new Map<TypeParameterElement, List<DartType>>(); | |
4766 | |
4767 /// Emit a list of statements declaring the cache variables and generator | |
4768 /// definitions tracked by the table. If [formals] is present, only | |
4769 /// emit the definitions which depend on the formals. | |
4770 List<JS.Statement> discharge([List<TypeParameterElement> formals]) { | |
4771 var filter = formals?.expand((p) => _scopeDependencies[p] ?? []); | |
4772 var stmts = [ | |
4773 _cacheNames, | |
4774 _definiteCacheNames, | |
4775 _generators, | |
4776 _definiteGenerators | |
4777 ].expand((c) => c.discharge(filter)).toList(); | |
4778 formals?.forEach(_scopeDependencies.remove); | |
4779 return stmts; | |
4780 } | |
4781 | |
4782 /// Record the dependencies of the type on its free variables | |
4783 bool recordScopeDependencies(DartType type) { | |
4784 var fvs = _freeTypeParameters(type); | |
4785 // TODO(leafp): This is a hack to avoid trying to hoist out of | |
4786 // generic functions and generic function types. This often degrades | |
4787 // readability to little or no benefit. It would be good to do this | |
4788 // when we know that we can hoist it to an outer scope, but for | |
4789 // now we just disable it. | |
4790 if (fvs.any((i) => i.enclosingElement is FunctionTypedElement)) { | |
4791 return true; | |
4792 } | |
4793 void addScope(TypeParameterElement i) { | |
4794 List<DartType> types = _scopeDependencies[i]; | |
4795 if (types == null) _scopeDependencies[i] = types = []; | |
4796 types.add(type); | |
4797 } | |
4798 fvs.forEach(addScope); | |
4799 return false; | |
4800 } | |
4801 | |
4802 /// Given a type [type], and a JS expression [typeRep] which implements it, | |
4803 /// Add the type and its representation to the table, returning an | |
Jennifer Messerly
2016/05/24 21:56:39
nit: lowercase "add"
Leaf
2016/05/25 00:56:13
Done.
| |
4804 /// expression which implements the type (but which caches the value). | |
4805 /// If [hoist] is true, then the JS representation will be hoisted up | |
Jennifer Messerly
2016/05/24 21:56:39
consider: splitting this into a few paragraphs?
Leaf
2016/05/25 00:56:13
Done.
| |
4806 /// as far as possible and shared between instances of the type. | |
4807 /// If [hoist] is false, the cache variable will be hoisted up as | |
4808 /// far as possible and shared between instances of the type, but the | |
4809 /// initializer expression will be emitted in place. | |
4810 /// The boolean parameter [definite] distinguishes between definite function | |
4811 /// types and other types (since the same DartType may have different | |
4812 /// representations as definite and indefinite function types). | |
Jennifer Messerly
2016/05/24 21:56:39
I seem to recall at one point we had considered pu
Leaf
2016/05/25 00:56:13
Acknowledged.
| |
4813 JS.Expression nameType(DartType type, JS.Expression typeRep, bool hoist, | |
Jennifer Messerly
2016/05/24 21:56:39
any reason to make "hoist" required and "definite"
Leaf
2016/05/25 00:56:13
Made them both named, asserted hoist is set. Defi
| |
4814 {bool definite: false}) { | |
4815 var table = hoist | |
4816 ? (definite ? _definiteGenerators : _generators) | |
4817 : (definite ? _definiteCacheNames : _cacheNames); | |
4818 if (!table.isNamed(type)) { | |
4819 if (recordScopeDependencies(type)) return typeRep; | |
4820 } | |
4821 return table.nameType(type, typeRep); | |
4822 } | |
4823 } | |
OLD | NEW |