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 | 2 |
3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 import 'dart:collection' show HashMap, HashSet; | 6 import 'dart:collection' show HashMap, HashSet; |
7 import 'dart:math' show min, max; | 7 import 'dart:math' show min, max; |
8 | 8 |
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
(...skipping 26 matching lines...) Expand all Loading... | |
37 import '../js_ast/js_ast.dart' as JS; | 37 import '../js_ast/js_ast.dart' as JS; |
38 import '../js_ast/js_ast.dart' show js; | 38 import '../js_ast/js_ast.dart' show js; |
39 import 'ast_builder.dart' show AstBuilder; | 39 import 'ast_builder.dart' show AstBuilder; |
40 import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile; | 40 import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile; |
41 import 'element_helpers.dart'; | 41 import 'element_helpers.dart'; |
42 import 'extension_types.dart' show ExtensionTypeSet; | 42 import 'extension_types.dart' show ExtensionTypeSet; |
43 import 'js_interop.dart'; | 43 import 'js_interop.dart'; |
44 import 'js_metalet.dart' as JS; | 44 import 'js_metalet.dart' as JS; |
45 import 'js_names.dart' as JS; | 45 import 'js_names.dart' as JS; |
46 import 'js_typeref_codegen.dart' show JsTypeRefCodegen; | 46 import 'js_typeref_codegen.dart' show JsTypeRefCodegen; |
47 import 'js_typerep.dart' show JSTypeRep; | 47 import 'js_typerep.dart' show JSTypeRep, JSType; |
48 import 'module_builder.dart' show pathToJSIdentifier; | 48 import 'module_builder.dart' show pathToJSIdentifier; |
49 import 'nullable_type_inference.dart' show NullableTypeInference; | 49 import 'nullable_type_inference.dart' show NullableTypeInference; |
50 import 'property_model.dart'; | 50 import 'property_model.dart'; |
51 import 'reify_coercions.dart' show CoercionReifier; | 51 import 'reify_coercions.dart' show CoercionReifier; |
52 import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless; | 52 import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless; |
53 import 'type_utilities.dart'; | 53 import 'type_utilities.dart'; |
54 | 54 |
55 /// The code generator for Dart Dev Compiler. | 55 /// The code generator for Dart Dev Compiler. |
56 /// | 56 /// |
57 /// Takes as input resolved Dart ASTs for every compilation unit in every | 57 /// Takes as input resolved Dart ASTs for every compilation unit in every |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
128 | 128 |
129 final LibraryElement dartCoreLibrary; | 129 final LibraryElement dartCoreLibrary; |
130 final LibraryElement dartJSLibrary; | 130 final LibraryElement dartJSLibrary; |
131 | 131 |
132 /// The dart:async `StreamIterator<>` type. | 132 /// The dart:async `StreamIterator<>` type. |
133 final InterfaceType _asyncStreamIterator; | 133 final InterfaceType _asyncStreamIterator; |
134 | 134 |
135 /// The dart:core `identical` element. | 135 /// The dart:core `identical` element. |
136 final FunctionElement _coreIdentical; | 136 final FunctionElement _coreIdentical; |
137 | 137 |
138 /// The dart:_interceptors JSArray element. | 138 /// The dart:_interceptors implementation elements. |
139 final ClassElement _jsArray; | 139 final ClassElement _jsArray; |
140 final ClassElement _jsBool; | |
141 final ClassElement _jsNumber; | |
142 final ClassElement _jsString; | |
140 | 143 |
141 final ClassElement boolClass; | 144 final ClassElement boolClass; |
142 final ClassElement intClass; | 145 final ClassElement intClass; |
143 final ClassElement interceptorClass; | 146 final ClassElement interceptorClass; |
144 final ClassElement nullClass; | 147 final ClassElement nullClass; |
145 final ClassElement numClass; | 148 final ClassElement numClass; |
146 final ClassElement objectClass; | 149 final ClassElement objectClass; |
147 final ClassElement stringClass; | 150 final ClassElement stringClass; |
148 final ClassElement functionClass; | 151 final ClassElement functionClass; |
149 final ClassElement privateSymbolClass; | 152 final ClassElement privateSymbolClass; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
198 CodeGenerator( | 201 CodeGenerator( |
199 AnalysisContext c, this.summaryData, this.options, this._extensionTypes) | 202 AnalysisContext c, this.summaryData, this.options, this._extensionTypes) |
200 : context = c, | 203 : context = c, |
201 rules = new StrongTypeSystemImpl(c.typeProvider), | 204 rules = new StrongTypeSystemImpl(c.typeProvider), |
202 types = c.typeProvider, | 205 types = c.typeProvider, |
203 _asyncStreamIterator = | 206 _asyncStreamIterator = |
204 _getLibrary(c, 'dart:async').getType('StreamIterator').type, | 207 _getLibrary(c, 'dart:async').getType('StreamIterator').type, |
205 _coreIdentical = | 208 _coreIdentical = |
206 _getLibrary(c, 'dart:core').publicNamespace.get('identical'), | 209 _getLibrary(c, 'dart:core').publicNamespace.get('identical'), |
207 _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'), | 210 _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'), |
211 _jsBool = _getLibrary(c, 'dart:_interceptors').getType('JSBool'), | |
212 _jsString = _getLibrary(c, 'dart:_interceptors').getType('JSString'), | |
213 _jsNumber = _getLibrary(c, 'dart:_interceptors').getType('JSNumber'), | |
208 interceptorClass = | 214 interceptorClass = |
209 _getLibrary(c, 'dart:_interceptors').getType('Interceptor'), | 215 _getLibrary(c, 'dart:_interceptors').getType('Interceptor'), |
210 dartCoreLibrary = _getLibrary(c, 'dart:core'), | 216 dartCoreLibrary = _getLibrary(c, 'dart:core'), |
211 boolClass = _getLibrary(c, 'dart:core').getType('bool'), | 217 boolClass = _getLibrary(c, 'dart:core').getType('bool'), |
212 intClass = _getLibrary(c, 'dart:core').getType('int'), | 218 intClass = _getLibrary(c, 'dart:core').getType('int'), |
213 numClass = _getLibrary(c, 'dart:core').getType('num'), | 219 numClass = _getLibrary(c, 'dart:core').getType('num'), |
214 nullClass = _getLibrary(c, 'dart:core').getType('Null'), | 220 nullClass = _getLibrary(c, 'dart:core').getType('Null'), |
215 objectClass = _getLibrary(c, 'dart:core').getType('Object'), | 221 objectClass = _getLibrary(c, 'dart:core').getType('Object'), |
216 stringClass = _getLibrary(c, 'dart:core').getType('String'), | 222 stringClass = _getLibrary(c, 'dart:core').getType('String'), |
217 functionClass = _getLibrary(c, 'dart:core').getType('Function'), | 223 functionClass = _getLibrary(c, 'dart:core').getType('Function'), |
(...skipping 2207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2425 body.add(js.statement('if (# === void 0) # = #;', | 2431 body.add(js.statement('if (# === void 0) # = #;', |
2426 [jsParam, jsParam, _defaultParamValue(param)])); | 2432 [jsParam, jsParam, _defaultParamValue(param)])); |
2427 } | 2433 } |
2428 } | 2434 } |
2429 | 2435 |
2430 var paramElement = resolutionMap.elementDeclaredByFormalParameter(param); | 2436 var paramElement = resolutionMap.elementDeclaredByFormalParameter(param); |
2431 if (_isCovariant(paramElement)) { | 2437 if (_isCovariant(paramElement)) { |
2432 var castType = _emitType(paramElement.type); | 2438 var castType = _emitType(paramElement.type); |
2433 body.add(js.statement('#._check(#);', [castType, jsParam])); | 2439 body.add(js.statement('#._check(#);', [castType, jsParam])); |
2434 } | 2440 } |
2441 if (_annotatedNullCheck(paramElement)) { | |
2442 body.add(nullParameterCheck(jsParam)); | |
2443 } | |
2435 } | 2444 } |
2436 return body.isEmpty ? null : _statement(body); | 2445 return body.isEmpty ? null : _statement(body); |
2437 } | 2446 } |
2438 | 2447 |
2439 bool _isCovariant(ParameterElement p) { | 2448 bool _isCovariant(ParameterElement p) { |
2440 if (p.isCovariant) return true; | 2449 if (p.isCovariant) return true; |
2441 var covariantParams = _classProperties?.covariantParameters; | 2450 var covariantParams = _classProperties?.covariantParameters; |
2442 return covariantParams != null && covariantParams.contains(p); | 2451 return covariantParams != null && covariantParams.contains(p); |
2443 } | 2452 } |
2444 | 2453 |
(...skipping 815 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3260 var t = _bindValue(vars, 't', x, context: x); | 3269 var t = _bindValue(vars, 't', x, context: x); |
3261 return new JS.MetaLet(vars, [ | 3270 return new JS.MetaLet(vars, [ |
3262 js.call('# == null ? # : #', [_visit(t), _emitSet(x, right), _visit(t)]) | 3271 js.call('# == null ? # : #', [_visit(t), _emitSet(x, right), _visit(t)]) |
3263 ]); | 3272 ]); |
3264 } | 3273 } |
3265 | 3274 |
3266 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions | 3275 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions |
3267 // (for example, x is IndexExpression) we evaluate those once. | 3276 // (for example, x is IndexExpression) we evaluate those once. |
3268 var vars = <JS.MetaLetVariable, JS.Expression>{}; | 3277 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
3269 var lhs = _bindLeftHandSide(vars, left, context: context); | 3278 var lhs = _bindLeftHandSide(vars, left, context: context); |
3279 // TODO(leafp): The element for lhs here will be the setter element | |
3280 // instead of the getter element if lhs is a property access. This | |
3281 // interferes with nullability analysis. | |
Jennifer Messerly
2017/08/22 21:54:41
FYI ... I think it would be safe to fix _bindLeftH
Leaf
2017/08/23 17:26:14
Not super high priority, but good to fix at some p
| |
3270 Expression inc = AstBuilder.binaryExpression(lhs, op, right) | 3282 Expression inc = AstBuilder.binaryExpression(lhs, op, right) |
3271 ..staticElement = element | 3283 ..staticElement = element |
3272 ..staticType = getStaticType(lhs); | 3284 ..staticType = getStaticType(lhs); |
3273 | 3285 |
3274 var castTo = getImplicitOperationCast(left); | 3286 var castTo = getImplicitOperationCast(left); |
3275 if (castTo != null) inc = CoercionReifier.castExpression(inc, castTo); | 3287 if (castTo != null) inc = CoercionReifier.castExpression(inc, castTo); |
3276 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); | 3288 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); |
3277 } | 3289 } |
3278 | 3290 |
3279 JS.Expression _emitSet(Expression left, Expression right) { | 3291 JS.Expression _emitSet(Expression left, Expression right) { |
(...skipping 763 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4043 JS.Statement visitVariableDeclarationStatement( | 4055 JS.Statement visitVariableDeclarationStatement( |
4044 VariableDeclarationStatement node) { | 4056 VariableDeclarationStatement node) { |
4045 // Special case a single variable with an initializer. | 4057 // Special case a single variable with an initializer. |
4046 // This helps emit cleaner code for things like: | 4058 // This helps emit cleaner code for things like: |
4047 // var result = []..add(1)..add(2); | 4059 // var result = []..add(1)..add(2); |
4048 var variables = node.variables.variables; | 4060 var variables = node.variables.variables; |
4049 if (variables.length == 1) { | 4061 if (variables.length == 1) { |
4050 var v = variables[0]; | 4062 var v = variables[0]; |
4051 if (v.initializer != null) { | 4063 if (v.initializer != null) { |
4052 var name = new JS.Identifier(v.name.name); | 4064 var name = new JS.Identifier(v.name.name); |
4053 return _visit<JS.Expression>(v.initializer).toVariableDeclaration(name); | 4065 var value = _annotatedNullCheck(v.element) |
4066 ? notNull(v.initializer) | |
4067 : _visit<JS.Expression>(v.initializer); | |
4068 return value.toVariableDeclaration(name); | |
4054 } | 4069 } |
4055 } | 4070 } |
4056 return _visit<JS.Expression>(node.variables).toStatement(); | 4071 return _visit<JS.Expression>(node.variables).toStatement(); |
4057 } | 4072 } |
4058 | 4073 |
4059 @override | 4074 @override |
4060 visitVariableDeclarationList(VariableDeclarationList node) { | 4075 visitVariableDeclarationList(VariableDeclarationList node) { |
4061 return new JS.VariableDeclarationList('let', _visitList(node.variables)); | 4076 return new JS.VariableDeclarationList('let', _visitList(node.variables)); |
4062 } | 4077 } |
4063 | 4078 |
(...skipping 22 matching lines...) Expand all Loading... | |
4086 for (var field in fields) { | 4101 for (var field in fields) { |
4087 _moduleItems.add(annotate( | 4102 _moduleItems.add(annotate( |
4088 js.statement('# = #;', | 4103 js.statement('# = #;', |
4089 [_emitTopLevelName(field.element), _visitInitializer(field)]), | 4104 [_emitTopLevelName(field.element), _visitInitializer(field)]), |
4090 field, | 4105 field, |
4091 field.element)); | 4106 field.element)); |
4092 } | 4107 } |
4093 } | 4108 } |
4094 | 4109 |
4095 JS.Expression _visitInitializer(VariableDeclaration node) { | 4110 JS.Expression _visitInitializer(VariableDeclaration node) { |
4096 var value = _visit(node.initializer); | 4111 var value = _annotatedNullCheck(node.element) |
4112 ? notNull(node.initializer) | |
4113 : _visit(node.initializer); | |
4097 // explicitly initialize to null, to avoid getting `undefined`. | 4114 // explicitly initialize to null, to avoid getting `undefined`. |
4098 // TODO(jmesserly): do this only for vars that aren't definitely assigned. | 4115 // TODO(jmesserly): do this only for vars that aren't definitely assigned. |
4099 return value ?? new JS.LiteralNull(); | 4116 return value ?? new JS.LiteralNull(); |
4100 } | 4117 } |
4101 | 4118 |
4102 JS.Statement _emitLazyFields( | 4119 JS.Statement _emitLazyFields( |
4103 Element target, List<VariableDeclaration> fields) { | 4120 Element target, List<VariableDeclaration> fields) { |
4104 var methods = []; | 4121 var methods = []; |
4105 for (var node in fields) { | 4122 for (var node in fields) { |
4106 var name = node.name.name; | 4123 var name = node.name.name; |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4247 : new JS.LiteralNull(); | 4264 : new JS.LiteralNull(); |
4248 } | 4265 } |
4249 throw new StateError('failed to evaluate $node'); | 4266 throw new StateError('failed to evaluate $node'); |
4250 } | 4267 } |
4251 return _emitInstanceCreationExpression( | 4268 return _emitInstanceCreationExpression( |
4252 element, type, name, node.argumentList, node.isConst); | 4269 element, type, name, node.argumentList, node.isConst); |
4253 } | 4270 } |
4254 | 4271 |
4255 bool isPrimitiveType(DartType t) => typeRep.isPrimitive(t); | 4272 bool isPrimitiveType(DartType t) => typeRep.isPrimitive(t); |
4256 | 4273 |
4274 InterfaceType getImplementationType(DartType t) { | |
Jennifer Messerly
2017/08/22 21:54:41
add a doc comment?
/// Given a Dart type for `boo
Leaf
2017/08/23 17:26:14
Done.
| |
4275 JSType rep = typeRep.typeFor(t); | |
4276 // Number, String, and Bool are final | |
4277 if (rep == JSType.jsNumber) return _jsNumber.type; | |
4278 if (rep == JSType.jsBoolean) return _jsBool.type; | |
4279 if (rep == JSType.jsString) return _jsString.type; | |
4280 return null; | |
4281 } | |
4282 | |
4283 JS.Statement nullParameterCheck(JS.Expression param) { | |
4284 var call = _callHelper('throwArgumentErrorValue((#))', [param]); | |
Jennifer Messerly
2017/08/22 21:54:41
if these are really common, consider a shorter nam
Leaf
2017/08/23 17:26:13
Done.
| |
4285 return js.statement('if (# == null) #;', [param, call]); | |
4286 } | |
4287 | |
4257 JS.Expression notNull(Expression expr) { | 4288 JS.Expression notNull(Expression expr) { |
4258 if (expr == null) return null; | 4289 if (expr == null) return null; |
4259 var jsExpr = _visit(expr); | 4290 var jsExpr = _visit(expr); |
4260 if (!isNullable(expr)) return jsExpr; | 4291 if (!isNullable(expr)) return jsExpr; |
4261 return _callHelper('notNull(#)', jsExpr); | 4292 return _callHelper('notNull(#)', jsExpr); |
4262 } | 4293 } |
4263 | 4294 |
4264 JS.Expression _emitEqualityOperator(BinaryExpression node, Token op) { | 4295 JS.Expression _emitEqualityOperator(BinaryExpression node, Token op) { |
4265 var left = node.leftOperand; | 4296 var left = node.leftOperand; |
4266 var right = node.rightOperand; | 4297 var right = node.rightOperand; |
(...skipping 842 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5109 return new JS.Do(_visitScope(node.body), _visitTest(node.condition)); | 5140 return new JS.Do(_visitScope(node.body), _visitTest(node.condition)); |
5110 } | 5141 } |
5111 | 5142 |
5112 @override | 5143 @override |
5113 JS.Statement visitForEachStatement(ForEachStatement node) { | 5144 JS.Statement visitForEachStatement(ForEachStatement node) { |
5114 if (node.awaitKeyword != null) { | 5145 if (node.awaitKeyword != null) { |
5115 return _emitAwaitFor(node); | 5146 return _emitAwaitFor(node); |
5116 } | 5147 } |
5117 | 5148 |
5118 var init = _visit(node.identifier); | 5149 var init = _visit(node.identifier); |
5150 var iterable = _visit(node.iterable); | |
5151 var body = _visitScope(node.body); | |
5119 if (init == null) { | 5152 if (init == null) { |
5120 init = js.call('let #', node.loopVariable.identifier.name); | 5153 var name = node.loopVariable.identifier.name; |
5154 init = js.call('let #', name); | |
5155 if (_annotatedNullCheck(node.loopVariable.element)) { | |
5156 body = | |
5157 new JS.Block([nullParameterCheck(new JS.Identifier(name)), body]); | |
5158 } | |
5121 } | 5159 } |
5122 return new JS.ForOf(init, _visit(node.iterable), _visitScope(node.body)); | 5160 return new JS.ForOf(init, iterable, body); |
5123 } | 5161 } |
5124 | 5162 |
5125 JS.Statement _emitAwaitFor(ForEachStatement node) { | 5163 JS.Statement _emitAwaitFor(ForEachStatement node) { |
5126 // Emits `await for (var value in stream) ...`, which desugars as: | 5164 // Emits `await for (var value in stream) ...`, which desugars as: |
5127 // | 5165 // |
5128 // var iter = new StreamIterator(stream); | 5166 // var iter = new StreamIterator(stream); |
5129 // try { | 5167 // try { |
5130 // while (await iter.moveNext()) { | 5168 // while (await iter.moveNext()) { |
5131 // var value = iter.current; | 5169 // var value = iter.current; |
5132 // ... | 5170 // ... |
(...skipping 859 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5992 if (targetIdentifier.staticElement is! PrefixElement) return false; | 6030 if (targetIdentifier.staticElement is! PrefixElement) return false; |
5993 var prefix = targetIdentifier.staticElement as PrefixElement; | 6031 var prefix = targetIdentifier.staticElement as PrefixElement; |
5994 | 6032 |
5995 // The library the prefix is referring to must come from a deferred import. | 6033 // The library the prefix is referring to must come from a deferred import. |
5996 var containingLibrary = resolutionMap | 6034 var containingLibrary = resolutionMap |
5997 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 6035 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
5998 .library; | 6036 .library; |
5999 var imports = containingLibrary.getImportsWithPrefix(prefix); | 6037 var imports = containingLibrary.getImportsWithPrefix(prefix); |
6000 return imports.length == 1 && imports[0].isDeferred; | 6038 return imports.length == 1 && imports[0].isDeferred; |
6001 } | 6039 } |
6040 | |
6041 bool _annotatedNullCheck(Element e) => | |
6042 (e != null) && (findAnnotation(e, isNullCheckAnnotation) != null); | |
Jennifer Messerly
2017/08/22 21:54:41
fyi, parens not necessary
Leaf
2017/08/23 17:26:14
Done.
| |
OLD | NEW |