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; |
11 import 'package:analyzer/dart/element/element.dart'; | 11 import 'package:analyzer/dart/element/element.dart'; |
12 import 'package:analyzer/dart/element/type.dart'; | 12 import 'package:analyzer/dart/element/type.dart'; |
13 import 'package:analyzer/src/dart/ast/token.dart' show StringToken; | 13 import 'package:analyzer/src/dart/ast/token.dart' show StringToken; |
14 import 'package:analyzer/src/dart/element/element.dart' | 14 import 'package:analyzer/src/dart/element/element.dart' |
15 show LocalVariableElementImpl; | 15 show LocalVariableElementImpl; |
16 import 'package:analyzer/src/dart/element/type.dart' show DynamicTypeImpl; | 16 import 'package:analyzer/src/dart/element/type.dart' show DynamicTypeImpl; |
17 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | 17 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
18 import 'package:analyzer/src/generated/resolver.dart' | 18 import 'package:analyzer/src/generated/resolver.dart' |
19 show TypeProvider, NamespaceBuilder; | 19 show TypeProvider, NamespaceBuilder; |
20 import 'package:analyzer/src/generated/type_system.dart' | 20 import 'package:analyzer/src/generated/type_system.dart' |
21 show StrongTypeSystemImpl; | 21 show StrongTypeSystemImpl; |
22 import 'package:analyzer/src/summary/summarize_elements.dart' | 22 import 'package:analyzer/src/summary/summarize_elements.dart' |
23 show PackageBundleAssembler; | 23 show PackageBundleAssembler; |
24 import 'package:analyzer/src/task/strong/ast_properties.dart' | 24 import 'package:analyzer/src/task/strong/ast_properties.dart' |
25 show isDynamicInvoke, setIsDynamicInvoke; | 25 show isDynamicInvoke, setIsDynamicInvoke; |
26 import 'package:source_maps/source_maps.dart'; | |
27 import 'package:path/path.dart' show separator; | 26 import 'package:path/path.dart' show separator; |
28 | 27 |
29 import '../closure/closure_annotator.dart' show ClosureAnnotator; | 28 import '../closure/closure_annotator.dart' show ClosureAnnotator; |
30 import '../js_ast/js_ast.dart' as JS; | 29 import '../js_ast/js_ast.dart' as JS; |
31 import '../js_ast/js_ast.dart' show js; | 30 import '../js_ast/js_ast.dart' show js; |
32 import 'ast_builder.dart' show AstBuilder; | 31 import 'ast_builder.dart' show AstBuilder; |
33 import 'compiler.dart' | 32 import 'compiler.dart' |
34 show BuildUnit, CompilerOptions, JSModuleFile, ModuleFormat; | 33 show BuildUnit, CompilerOptions, JSModuleFile; |
35 import 'element_helpers.dart'; | 34 import 'element_helpers.dart'; |
36 import 'element_loader.dart' show ElementLoader; | 35 import 'element_loader.dart' show ElementLoader; |
37 import 'extension_types.dart' show ExtensionTypeSet; | 36 import 'extension_types.dart' show ExtensionTypeSet; |
38 import 'js_field_storage.dart' show checkForPropertyOverride, getSuperclasses; | 37 import 'js_field_storage.dart' show checkForPropertyOverride, getSuperclasses; |
39 import 'js_interop.dart'; | 38 import 'js_interop.dart'; |
40 import 'js_metalet.dart' as JS; | 39 import 'js_metalet.dart' as JS; |
41 import 'js_names.dart' as JS; | 40 import 'js_names.dart' as JS; |
42 import 'js_typeref_codegen.dart' show JsTypeRefCodegen; | 41 import 'js_typeref_codegen.dart' show JsTypeRefCodegen; |
43 import 'module_builder.dart' | 42 import 'module_builder.dart' show pathToJSIdentifier; |
44 show LegacyModuleBuilder, NodeModuleBuilder, pathToJSIdentifier; | |
45 import 'nullable_type_inference.dart' show NullableTypeInference; | 43 import 'nullable_type_inference.dart' show NullableTypeInference; |
46 import 'reify_coercions.dart' show CoercionReifier; | 44 import 'reify_coercions.dart' show CoercionReifier; |
47 import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless; | 45 import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless; |
48 import 'source_map_printer.dart' show SourceMapPrintingContext; | |
49 import 'type_utilities.dart'; | 46 import 'type_utilities.dart'; |
50 | 47 |
51 class CodeGenerator extends GeneralizingAstVisitor | 48 class CodeGenerator extends GeneralizingAstVisitor |
52 with ClosureAnnotator, JsTypeRefCodegen, NullableTypeInference { | 49 with ClosureAnnotator, JsTypeRefCodegen, NullableTypeInference { |
53 final AnalysisContext context; | 50 final AnalysisContext context; |
54 final CompilerOptions options; | 51 final CompilerOptions options; |
55 final rules = new StrongTypeSystemImpl(); | 52 final rules = new StrongTypeSystemImpl(); |
56 | 53 |
57 /// The set of libraries we are currently compiling, and the temporaries used | 54 /// The set of libraries we are currently compiling, and the temporaries used |
58 /// to refer to them. | 55 /// to refer to them. |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
166 /// Takes the metadata for the build unit, as well as resolved trees and | 163 /// Takes the metadata for the build unit, as well as resolved trees and |
167 /// errors, and computes the output module code and optionally the source map. | 164 /// errors, and computes the output module code and optionally the source map. |
168 JSModuleFile compile(BuildUnit unit, List<CompilationUnit> compilationUnits, | 165 JSModuleFile compile(BuildUnit unit, List<CompilationUnit> compilationUnits, |
169 List<String> errors) { | 166 List<String> errors) { |
170 _buildUnit = unit; | 167 _buildUnit = unit; |
171 _libraryRoot = _buildUnit.libraryRoot; | 168 _libraryRoot = _buildUnit.libraryRoot; |
172 if (!_libraryRoot.endsWith(separator)) { | 169 if (!_libraryRoot.endsWith(separator)) { |
173 _libraryRoot = '$_libraryRoot${separator}'; | 170 _libraryRoot = '$_libraryRoot${separator}'; |
174 } | 171 } |
175 | 172 |
176 var jsTree = _emitModule(compilationUnits); | 173 var module = _emitModule(compilationUnits); |
177 var codeAndSourceMap = _writeJSText(unit, jsTree); | 174 var dartApiSummary = _summarizeModule(compilationUnits); |
178 | 175 |
179 List<int> summary; | 176 return new JSModuleFile(unit.name, errors, options, module, dartApiSummary); |
180 if (options.summarizeApi) { | |
181 var assembler = new PackageBundleAssembler(); | |
182 compilationUnits | |
183 .map((u) => u.element.library) | |
184 .toSet() | |
185 .forEach(assembler.serializeLibraryElement); | |
186 summary = assembler.assemble().toBuffer(); | |
187 } | |
188 | |
189 return new JSModuleFile( | |
190 unit.name, errors, codeAndSourceMap.e0, codeAndSourceMap.e1, summary); | |
191 } | 177 } |
192 | 178 |
193 Tuple2<String, Map> _writeJSText(BuildUnit unit, JS.Program jsTree) { | 179 List<int> _summarizeModule(List<CompilationUnit> compilationUnits) { |
194 var opts = new JS.JavaScriptPrintingOptions( | 180 if (!options.summarizeApi) return null; |
195 emitTypes: options.closure, | |
196 allowKeywordsInProperties: true, | |
197 allowSingleLineIfStatements: true); | |
198 JS.SimpleJavaScriptPrintingContext printer; | |
199 SourceMapBuilder sourceMap; | |
200 if (options.sourceMap) { | |
201 var sourceMapContext = new SourceMapPrintingContext(); | |
202 sourceMap = sourceMapContext.sourceMap; | |
203 printer = sourceMapContext; | |
204 } else { | |
205 printer = new JS.SimpleJavaScriptPrintingContext(); | |
206 } | |
207 | 181 |
208 jsTree.accept(new JS.Printer(opts, printer, | 182 var assembler = new PackageBundleAssembler(); |
209 localNamer: new JS.TemporaryNamer(jsTree))); | 183 compilationUnits |
210 | 184 .map((u) => u.element.library) |
211 if (options.sourceMap && options.sourceMapComment) { | 185 .toSet() |
212 printer.emit('\n//# sourceMappingURL=${unit.name}.js.map\n'); | 186 .forEach(assembler.serializeLibraryElement); |
213 } | 187 return assembler.assemble().toBuffer(); |
214 | |
215 return new Tuple2(printer.getText(), sourceMap?.build(unit.name + '.js')); | |
216 } | 188 } |
217 | 189 |
218 JS.Program _emitModule(List<CompilationUnit> compilationUnits) { | 190 JS.Program _emitModule(List<CompilationUnit> compilationUnits) { |
219 if (_moduleItems.isNotEmpty) { | 191 if (_moduleItems.isNotEmpty) { |
220 throw new StateError('Can only call emitModule once.'); | 192 throw new StateError('Can only call emitModule once.'); |
221 } | 193 } |
222 | 194 |
223 // Transform the AST to make coercions explicit. | 195 // Transform the AST to make coercions explicit. |
224 compilationUnits = CoercionReifier.reify(compilationUnits); | 196 compilationUnits = CoercionReifier.reify(compilationUnits); |
225 | 197 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
277 _finishImports(items); | 249 _finishImports(items); |
278 | 250 |
279 // Discharge the type table cache variables and | 251 // Discharge the type table cache variables and |
280 // hoisted definitions. | 252 // hoisted definitions. |
281 items.addAll(_typeTable.discharge()); | 253 items.addAll(_typeTable.discharge()); |
282 | 254 |
283 // Add the module's code (produced by visiting compilation units, above) | 255 // Add the module's code (produced by visiting compilation units, above) |
284 _copyAndFlattenBlocks(items, _moduleItems); | 256 _copyAndFlattenBlocks(items, _moduleItems); |
285 | 257 |
286 // Build the module. | 258 // Build the module. |
287 var module = new JS.Program(items, name: _buildUnit.name); | 259 return new JS.Program(items, name: _buildUnit.name); |
288 | |
289 // Optional: lower module format. Otherwise just return it. | |
290 switch (options.moduleFormat) { | |
291 case ModuleFormat.legacy: | |
292 return new LegacyModuleBuilder().build(module); | |
293 case ModuleFormat.node: | |
294 return new NodeModuleBuilder().build(module); | |
295 case ModuleFormat.es6: | |
296 return module; | |
297 } | |
298 return null; // unreachable. It is here to suppress a bogus Analyzer message | |
299 } | 260 } |
300 | 261 |
301 List<String> _getJSName(Element e) { | 262 List<String> _getJSName(Element e) { |
302 if (findAnnotation(e.library, isPublicJSAnnotation) == null) { | 263 if (findAnnotation(e.library, isPublicJSAnnotation) == null) { |
303 return null; | 264 return null; |
304 } | 265 } |
305 | 266 |
306 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); | 267 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); |
307 var libraryPrefix = <String>[]; | 268 var libraryPrefix = <String>[]; |
308 if (libraryJSName != null && libraryJSName.isNotEmpty) { | 269 if (libraryJSName != null && libraryJSName.isNotEmpty) { |
(...skipping 1434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1743 var property = new JS.Property(memberName, type); | 1704 var property = new JS.Property(memberName, type); |
1744 tCtors.add(property); | 1705 tCtors.add(property); |
1745 } | 1706 } |
1746 | 1707 |
1747 JS.Property build(String name, List<JS.Property> elements) { | 1708 JS.Property build(String name, List<JS.Property> elements) { |
1748 var o = | 1709 var o = |
1749 new JS.ObjectInitializer(elements, multiline: elements.length > 1); | 1710 new JS.ObjectInitializer(elements, multiline: elements.length > 1); |
1750 var e = js.call('() => #', o); | 1711 var e = js.call('() => #', o); |
1751 return new JS.Property(_propertyName(name), e); | 1712 return new JS.Property(_propertyName(name), e); |
1752 } | 1713 } |
1714 | |
1753 var sigFields = <JS.Property>[]; | 1715 var sigFields = <JS.Property>[]; |
1754 if (!tCtors.isEmpty) sigFields.add(build('constructors', tCtors)); | 1716 if (!tCtors.isEmpty) sigFields.add(build('constructors', tCtors)); |
1755 if (!tMethods.isEmpty) sigFields.add(build('methods', tMethods)); | 1717 if (!tMethods.isEmpty) sigFields.add(build('methods', tMethods)); |
1756 if (!tStatics.isEmpty) { | 1718 if (!tStatics.isEmpty) { |
1757 assert(!sNames.isEmpty); | 1719 assert(!sNames.isEmpty); |
1758 var aNames = new JS.Property( | 1720 var aNames = new JS.Property( |
1759 _propertyName('names'), new JS.ArrayInitializer(sNames)); | 1721 _propertyName('names'), new JS.ArrayInitializer(sNames)); |
1760 sigFields.add(build('statics', tStatics)); | 1722 sigFields.add(build('statics', tStatics)); |
1761 sigFields.add(aNames); | 1723 sigFields.add(aNames); |
1762 } | 1724 } |
(...skipping 1492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3255 var element = node.methodName.staticElement; | 3217 var element = node.methodName.staticElement; |
3256 bool isStatic = element is ExecutableElement && element.isStatic; | 3218 bool isStatic = element is ExecutableElement && element.isStatic; |
3257 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); | 3219 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); |
3258 | 3220 |
3259 JS.Expression jsTarget = _visit(target); | 3221 JS.Expression jsTarget = _visit(target); |
3260 if (isDynamicInvoke(target) || isDynamicInvoke(node.methodName)) { | 3222 if (isDynamicInvoke(target) || isDynamicInvoke(node.methodName)) { |
3261 if (_inWhitelistCode(target)) { | 3223 if (_inWhitelistCode(target)) { |
3262 var vars = <JS.MetaLetVariable, JS.Expression>{}; | 3224 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
3263 var l = _visit(_bindValue(vars, 'l', target)); | 3225 var l = _visit(_bindValue(vars, 'l', target)); |
3264 jsTarget = new JS.MetaLet(vars, [ | 3226 jsTarget = new JS.MetaLet(vars, [ |
3265 js.call('(#[(#[dart._extensionType]) ? dartx[#] : #])', | 3227 js.call('(#[(#[dart._extensionType]) ? dartx[#] : #])', [ |
3266 [l, l, memberName, memberName,]) | 3228 l, |
3229 l, | |
3230 memberName, | |
3231 memberName, | |
3232 ]) | |
3267 ]); | 3233 ]); |
3268 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); | 3234 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); |
3269 return new JS.Call(jsTarget, args); | 3235 return new JS.Call(jsTarget, args); |
3270 } | 3236 } |
3271 if (typeArgs != null) { | 3237 if (typeArgs != null) { |
3272 return js.call('dart.dgsend(#, #, #, #)', | 3238 return js.call('dart.dgsend(#, #, #, #)', |
3273 [jsTarget, new JS.ArrayInitializer(typeArgs), memberName, args]); | 3239 [jsTarget, new JS.ArrayInitializer(typeArgs), memberName, args]); |
3274 } else { | 3240 } else { |
3275 return js.call('dart.dsend(#, #, #)', [jsTarget, memberName, args]); | 3241 return js.call('dart.dsend(#, #, #)', [jsTarget, memberName, args]); |
3276 } | 3242 } |
(...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3799 if (name != null) { | 3765 if (name != null) { |
3800 ctor = new JS.PropertyAccess(ctor, _propertyName(name.name)); | 3766 ctor = new JS.PropertyAccess(ctor, _propertyName(name.name)); |
3801 } | 3767 } |
3802 } else { | 3768 } else { |
3803 ctor = _emitConstructorName(element, type, name); | 3769 ctor = _emitConstructorName(element, type, name); |
3804 isFactory = element.isFactory; | 3770 isFactory = element.isFactory; |
3805 } | 3771 } |
3806 var args = _visit(argumentList) as List<JS.Expression>; | 3772 var args = _visit(argumentList) as List<JS.Expression>; |
3807 return isFactory ? new JS.Call(ctor, args) : new JS.New(ctor, args); | 3773 return isFactory ? new JS.Call(ctor, args) : new JS.New(ctor, args); |
3808 } | 3774 } |
3775 | |
3809 if (element != null && _isObjectLiteral(element.enclosingElement)) { | 3776 if (element != null && _isObjectLiteral(element.enclosingElement)) { |
3810 return _emitObjectLiteral(argumentList); | 3777 return _emitObjectLiteral(argumentList); |
3811 } | 3778 } |
3812 if (isConst) return _emitConst(emitNew); | 3779 if (isConst) return _emitConst(emitNew); |
3813 return emitNew(); | 3780 return emitNew(); |
3814 } | 3781 } |
3815 | 3782 |
3816 bool _isObjectLiteral(ClassElement classElem) { | 3783 bool _isObjectLiteral(ClassElement classElem) { |
3817 return findAnnotation(classElem, isPublicJSAnnotation) != null && | 3784 return findAnnotation(classElem, isPublicJSAnnotation) != null && |
3818 findAnnotation(classElem, isJSAnonymousAnnotation) != null; | 3785 findAnnotation(classElem, isJSAnonymousAnnotation) != null; |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4040 } | 4007 } |
4041 int finishIdentifier(SimpleIdentifier identifier) { | 4008 int finishIdentifier(SimpleIdentifier identifier) { |
4042 Element staticElement = identifier.staticElement; | 4009 Element staticElement = identifier.staticElement; |
4043 if (staticElement is PropertyAccessorElement && staticElement.isGetter) { | 4010 if (staticElement is PropertyAccessorElement && staticElement.isGetter) { |
4044 PropertyInducingElement variable = staticElement.variable; | 4011 PropertyInducingElement variable = staticElement.variable; |
4045 int value = variable?.constantValue?.toIntValue(); | 4012 int value = variable?.constantValue?.toIntValue(); |
4046 if (value != null && value >= low && value <= high) return value; | 4013 if (value != null && value >= low && value <= high) return value; |
4047 } | 4014 } |
4048 return null; | 4015 return null; |
4049 } | 4016 } |
4017 | |
4050 if (expr is SimpleIdentifier) { | 4018 if (expr is SimpleIdentifier) { |
4051 return finishIdentifier(expr); | 4019 return finishIdentifier(expr); |
4052 } else if (expr is PrefixedIdentifier && !expr.isDeferred) { | 4020 } else if (expr is PrefixedIdentifier && !expr.isDeferred) { |
4053 return finishIdentifier(expr.identifier); | 4021 return finishIdentifier(expr.identifier); |
4054 } | 4022 } |
4055 return null; | 4023 return null; |
4056 } | 4024 } |
4057 | 4025 |
4058 bool _isDefinitelyNonNegative(Expression expr) { | 4026 bool _isDefinitelyNonNegative(Expression expr) { |
4059 expr = expr.unParenthesized; | 4027 expr = expr.unParenthesized; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4127 } | 4095 } |
4128 return MAX; | 4096 return MAX; |
4129 default: | 4097 default: |
4130 return MAX; | 4098 return MAX; |
4131 } | 4099 } |
4132 } | 4100 } |
4133 int value = _asIntInRange(expr, 0, 0x7fffffff); | 4101 int value = _asIntInRange(expr, 0, 0x7fffffff); |
4134 if (value != null) return value.bitLength; | 4102 if (value != null) return value.bitLength; |
4135 return MAX; | 4103 return MAX; |
4136 } | 4104 } |
4105 | |
4137 return bitWidth(expr, 0) < 32; | 4106 return bitWidth(expr, 0) < 32; |
4138 } | 4107 } |
4139 | 4108 |
4140 /// If the type [t] is [int] or [double], or a type parameter | 4109 /// If the type [t] is [int] or [double], or a type parameter |
4141 /// bounded by [int], [double] or [num] returns [num]. | 4110 /// bounded by [int], [double] or [num] returns [num]. |
4142 /// Otherwise returns [t]. | 4111 /// Otherwise returns [t]. |
4143 DartType _canonicalizeNumTypes(DartType t) { | 4112 DartType _canonicalizeNumTypes(DartType t) { |
4144 var numType = types.numType; | 4113 var numType = types.numType; |
4145 if (rules.isSubtypeOf(t, numType)) return numType; | 4114 if (rules.isSubtypeOf(t, numType)) return numType; |
4146 return t; | 4115 return t; |
(...skipping 770 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4917 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); | 4886 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); |
4918 | 4887 |
4919 @override | 4888 @override |
4920 visitSymbolLiteral(SymbolLiteral node) { | 4889 visitSymbolLiteral(SymbolLiteral node) { |
4921 JS.Expression emitSymbol() { | 4890 JS.Expression emitSymbol() { |
4922 // TODO(vsm): When we canonicalize, we need to treat private symbols | 4891 // TODO(vsm): When we canonicalize, we need to treat private symbols |
4923 // correctly. | 4892 // correctly. |
4924 var name = js.string(node.components.join('.'), "'"); | 4893 var name = js.string(node.components.join('.'), "'"); |
4925 return js.call('#.new(#)', [_emitType(types.symbolType), name]); | 4894 return js.call('#.new(#)', [_emitType(types.symbolType), name]); |
4926 } | 4895 } |
4896 | |
4927 return _emitConst(emitSymbol); | 4897 return _emitConst(emitSymbol); |
4928 } | 4898 } |
4929 | 4899 |
4930 @override | 4900 @override |
4931 visitListLiteral(ListLiteral node) { | 4901 visitListLiteral(ListLiteral node) { |
4932 var isConst = node.constKeyword != null; | 4902 var isConst = node.constKeyword != null; |
4933 JS.Expression emitList() { | 4903 JS.Expression emitList() { |
4934 JS.Expression list = new JS.ArrayInitializer( | 4904 JS.Expression list = new JS.ArrayInitializer( |
4935 _visitList(node.elements) as List<JS.Expression>); | 4905 _visitList(node.elements) as List<JS.Expression>); |
4936 ParameterizedType type = node.staticType; | 4906 ParameterizedType type = node.staticType; |
4937 var elementType = type.typeArguments.single; | 4907 var elementType = type.typeArguments.single; |
4938 // TODO(jmesserly): analyzer will usually infer `List<Object>` because | 4908 // TODO(jmesserly): analyzer will usually infer `List<Object>` because |
4939 // that is the least upper bound of the element types. So we rarely | 4909 // that is the least upper bound of the element types. So we rarely |
4940 // generate a plain `List<dynamic>` anymore. | 4910 // generate a plain `List<dynamic>` anymore. |
4941 if (!elementType.isDynamic || isConst) { | 4911 if (!elementType.isDynamic || isConst) { |
4942 // dart.list helper internally depends on _interceptors.JSArray. | 4912 // dart.list helper internally depends on _interceptors.JSArray. |
4943 _declareBeforeUse(_jsArray); | 4913 _declareBeforeUse(_jsArray); |
4944 if (isConst) { | 4914 if (isConst) { |
4945 var typeRep = _emitType(elementType); | 4915 var typeRep = _emitType(elementType); |
4946 list = js.call('dart.constList(#, #)', [list, typeRep]); | 4916 list = js.call('dart.constList(#, #)', [list, typeRep]); |
4947 } else { | 4917 } else { |
4948 // Call `new JSArray<E>.of(list)` | 4918 // Call `new JSArray<E>.of(list)` |
4949 var jsArrayType = _jsArray.type.instantiate(type.typeArguments); | 4919 var jsArrayType = _jsArray.type.instantiate(type.typeArguments); |
4950 list = js.call('#.of(#)', [_emitType(jsArrayType), list]); | 4920 list = js.call('#.of(#)', [_emitType(jsArrayType), list]); |
4951 } | 4921 } |
4952 } | 4922 } |
4953 return list; | 4923 return list; |
4954 } | 4924 } |
4925 | |
4955 if (isConst) return _cacheConst(emitList); | 4926 if (isConst) return _cacheConst(emitList); |
4956 return emitList(); | 4927 return emitList(); |
4957 } | 4928 } |
4958 | 4929 |
4959 @override | 4930 @override |
4960 visitMapLiteral(MapLiteral node) { | 4931 visitMapLiteral(MapLiteral node) { |
4961 // TODO(jmesserly): we can likely make these faster. | 4932 // TODO(jmesserly): we can likely make these faster. |
4962 JS.Expression emitMap() { | 4933 JS.Expression emitMap() { |
4963 var entries = node.entries; | 4934 var entries = node.entries; |
4964 var mapArguments = null; | 4935 var mapArguments = null; |
(...skipping 18 matching lines...) Expand all Loading... | |
4983 values.add(_visit(e.value)); | 4954 values.add(_visit(e.value)); |
4984 } | 4955 } |
4985 mapArguments = new JS.ArrayInitializer(values); | 4956 mapArguments = new JS.ArrayInitializer(values); |
4986 } | 4957 } |
4987 var types = <JS.Expression>[]; | 4958 var types = <JS.Expression>[]; |
4988 if (reifyTypeArgs) { | 4959 if (reifyTypeArgs) { |
4989 types.addAll(typeArgs.map((e) => _emitType(e))); | 4960 types.addAll(typeArgs.map((e) => _emitType(e))); |
4990 } | 4961 } |
4991 return js.call('dart.map(#, #)', [mapArguments, types]); | 4962 return js.call('dart.map(#, #)', [mapArguments, types]); |
4992 } | 4963 } |
4964 | |
4993 if (node.constKeyword != null) return _emitConst(emitMap); | 4965 if (node.constKeyword != null) return _emitConst(emitMap); |
4994 return emitMap(); | 4966 return emitMap(); |
4995 } | 4967 } |
4996 | 4968 |
4997 @override | 4969 @override |
4998 JS.LiteralString visitSimpleStringLiteral(SimpleStringLiteral node) => | 4970 JS.LiteralString visitSimpleStringLiteral(SimpleStringLiteral node) => |
4999 js.escapedString(node.value, node.isSingleQuoted ? "'" : '"'); | 4971 js.escapedString(node.value, node.isSingleQuoted ? "'" : '"'); |
5000 | 4972 |
5001 @override | 4973 @override |
5002 JS.Expression visitAdjacentStrings(AdjacentStrings node) => | 4974 JS.Expression visitAdjacentStrings(AdjacentStrings node) => |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5059 | 5031 |
5060 /// Generates an expression for a boolean conversion context (if, while, &&, | 5032 /// Generates an expression for a boolean conversion context (if, while, &&, |
5061 /// etc.), where conversions and null checks are implemented via `dart.test` | 5033 /// etc.), where conversions and null checks are implemented via `dart.test` |
5062 /// to give a more helpful message. | 5034 /// to give a more helpful message. |
5063 // TODO(sra): When nullablility is available earlier, it would be cleaner to | 5035 // TODO(sra): When nullablility is available earlier, it would be cleaner to |
5064 // build an input AST where the boolean conversion is a single AST node. | 5036 // build an input AST where the boolean conversion is a single AST node. |
5065 JS.Expression _visitTest(Expression node) { | 5037 JS.Expression _visitTest(Expression node) { |
5066 JS.Expression finish(JS.Expression result) { | 5038 JS.Expression finish(JS.Expression result) { |
5067 return annotate(result, node); | 5039 return annotate(result, node); |
5068 } | 5040 } |
5041 | |
5069 if (node is PrefixExpression && node.operator.lexeme == '!') { | 5042 if (node is PrefixExpression && node.operator.lexeme == '!') { |
5070 return finish(js.call('!#', _visitTest(node.operand))); | 5043 return finish(js.call('!#', _visitTest(node.operand))); |
5071 } | 5044 } |
5072 if (node is ParenthesizedExpression) { | 5045 if (node is ParenthesizedExpression) { |
5073 return finish(_visitTest(node.expression)); | 5046 return finish(_visitTest(node.expression)); |
5074 } | 5047 } |
5075 if (node is BinaryExpression) { | 5048 if (node is BinaryExpression) { |
5076 JS.Expression shortCircuit(String code) { | 5049 JS.Expression shortCircuit(String code) { |
5077 return finish(js.call(code, | 5050 return finish(js.call(code, |
5078 [_visitTest(node.leftOperand), _visitTest(node.rightOperand)])); | 5051 [_visitTest(node.leftOperand), _visitTest(node.rightOperand)])); |
5079 } | 5052 } |
5053 | |
5080 var op = node.operator.type.lexeme; | 5054 var op = node.operator.type.lexeme; |
5081 if (op == '&&') return shortCircuit('# && #'); | 5055 if (op == '&&') return shortCircuit('# && #'); |
5082 if (op == '||') return shortCircuit('# || #'); | 5056 if (op == '||') return shortCircuit('# || #'); |
5083 } | 5057 } |
5084 if (isReifiedCoercion(node)) { | 5058 if (isReifiedCoercion(node)) { |
5085 AsExpression asNode = node; | 5059 AsExpression asNode = node; |
5086 assert(asNode.staticType == types.boolType); | 5060 assert(asNode.staticType == types.boolType); |
5087 return js.call('dart.test(#)', _visit(asNode.expression)); | 5061 return js.call('dart.test(#)', _visit(asNode.expression)); |
5088 } | 5062 } |
5089 JS.Expression result = _visit(node); | 5063 JS.Expression result = _visit(node); |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5287 // TODO(leafp): The above only handles the case where the return type | 5261 // TODO(leafp): The above only handles the case where the return type |
5288 // is exactly Future/Stream/Iterable. Handle the subtype case. | 5262 // is exactly Future/Stream/Iterable. Handle the subtype case. |
5289 return DynamicTypeImpl.instance; | 5263 return DynamicTypeImpl.instance; |
5290 } | 5264 } |
5291 } | 5265 } |
5292 | 5266 |
5293 /// Maps whitelisted files to a list of whitelisted methods | 5267 /// Maps whitelisted files to a list of whitelisted methods |
5294 /// within the file. | 5268 /// within the file. |
5295 /// | 5269 /// |
5296 /// If the value is null, the entire file is whitelisted. | 5270 /// If the value is null, the entire file is whitelisted. |
5271 /// | |
5272 // TODO(jmesserly): why is this here, and what can we do to remove it? | |
5273 // | |
5274 // Hard coded lists are completely unnecessary -- if a feature is needed, | |
5275 // metadata, type system features, or command line options is the right way to | |
5276 // express it. | |
5277 // | |
5278 // As it is this is completely unsound and unmaintainable. | |
5279 // | |
nweiz
2016/08/24 23:33:26
Nit: unnecessary newline.
Jennifer Messerly
2016/08/25 16:21:39
there are not enough newlines to contain my rage a
| |
5297 static Map<String, List<String>> _uncheckedWhitelist = { | 5280 static Map<String, List<String>> _uncheckedWhitelist = { |
5298 'dom_renderer.dart': ['moveNodesAfterSibling',], | 5281 'dom_renderer.dart': ['moveNodesAfterSibling'], |
5299 'template_ref.dart': ['createEmbeddedView'], | 5282 'template_ref.dart': ['createEmbeddedView'], |
5300 'ng_class.dart': ['_applyIterableChanges'], | 5283 'ng_class.dart': ['_applyIterableChanges'], |
5301 'ng_for.dart': ['_bulkRemove', '_bulkInsert'], | 5284 'ng_for.dart': ['_bulkRemove', '_bulkInsert'], |
5302 'view_container_ref.dart': ['createEmbeddedView'], | 5285 'view_container_ref.dart': ['createEmbeddedView'], |
5303 'default_iterable_differ.dart': null, | 5286 'default_iterable_differ.dart': null, |
5304 }; | 5287 }; |
5305 | 5288 |
5306 static Set<String> _uncheckedWhitelistCalls = new Set() | 5289 static Set<String> _uncheckedWhitelistCalls = new Set() |
5307 ..add('ng_zone_impl.dart') | 5290 ..add('ng_zone_impl.dart') |
5308 ..add('stack_zone_specification.dart') | 5291 ..add('stack_zone_specification.dart') |
(...skipping 19 matching lines...) Expand all Loading... | |
5328 } | 5311 } |
5329 | 5312 |
5330 // Dynamic calls are less risky so there is no need to whitelist at the | 5313 // Dynamic calls are less risky so there is no need to whitelist at the |
5331 // method level. | 5314 // method level. |
5332 if (isCall && _uncheckedWhitelistCalls.contains(filename)) return true; | 5315 if (isCall && _uncheckedWhitelistCalls.contains(filename)) return true; |
5333 | 5316 |
5334 return path.endsWith(".template.dart"); | 5317 return path.endsWith(".template.dart"); |
5335 } | 5318 } |
5336 } | 5319 } |
5337 | 5320 |
5338 /// Choose a canonical name from the library element. | 5321 /// Choose a canonical name from the [library] element. |
5322 /// | |
5339 /// This never uses the library's name (the identifier in the `library` | 5323 /// This never uses the library's name (the identifier in the `library` |
5340 /// declaration) as it doesn't have any meaningful rules enforced. | 5324 /// declaration) as it doesn't have any meaningful rules enforced. |
5341 String jsLibraryName(String libraryRoot, LibraryElement library) { | 5325 String jsLibraryName(String libraryRoot, LibraryElement library) { |
5342 var uri = library.source.uri; | 5326 var uri = library.source.uri; |
5343 if (uri.scheme == 'dart') { | 5327 if (uri.scheme == 'dart') { |
5344 return uri.path; | 5328 return uri.path; |
5345 } | 5329 } |
5346 // TODO(vsm): This is not necessarily unique if '__' appears in a file name. | 5330 // TODO(vsm): This is not necessarily unique if '__' appears in a file name. |
5347 var separator = '__'; | 5331 var separator = '__'; |
5348 String qualifiedPath; | 5332 String qualifiedPath; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5385 } | 5369 } |
5386 | 5370 |
5387 bool isLibraryPrefix(Expression node) => | 5371 bool isLibraryPrefix(Expression node) => |
5388 node is SimpleIdentifier && node.staticElement is PrefixElement; | 5372 node is SimpleIdentifier && node.staticElement is PrefixElement; |
5389 | 5373 |
5390 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 5374 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
5391 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 5375 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
5392 | 5376 |
5393 bool _isDartRuntime(LibraryElement l) => | 5377 bool _isDartRuntime(LibraryElement l) => |
5394 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 5378 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
OLD | NEW |