Chromium Code Reviews| 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 |