| 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 HashSet, HashMap, SplayTreeSet; | 5 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; |
| 6 | 6 |
| 7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 8 import 'package:analyzer/dart/ast/token.dart'; | 8 import 'package:analyzer/dart/ast/token.dart'; |
| 9 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
| 10 import 'package:analyzer/src/generated/constant.dart'; | 10 import 'package:analyzer/src/generated/constant.dart'; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 import 'code_generator.dart'; | 33 import 'code_generator.dart'; |
| 34 import 'js_field_storage.dart'; | 34 import 'js_field_storage.dart'; |
| 35 import 'js_interop.dart'; | 35 import 'js_interop.dart'; |
| 36 import 'js_names.dart' as JS; | 36 import 'js_names.dart' as JS; |
| 37 import 'js_metalet.dart' as JS; | 37 import 'js_metalet.dart' as JS; |
| 38 import 'js_module_item_order.dart'; | 38 import 'js_module_item_order.dart'; |
| 39 import 'js_names.dart'; | 39 import 'js_names.dart'; |
| 40 import 'js_printer.dart' show writeJsLibrary; | 40 import 'js_printer.dart' show writeJsLibrary; |
| 41 import 'js_typeref_codegen.dart'; | 41 import 'js_typeref_codegen.dart'; |
| 42 import 'module_builder.dart'; | 42 import 'module_builder.dart'; |
| 43 import 'nullability_inferrer.dart'; | 43 import 'nullable_type_inference.dart'; |
| 44 import 'side_effect_analysis.dart'; | 44 import 'side_effect_analysis.dart'; |
| 45 | 45 |
| 46 // Various dynamic helpers we call. | 46 // Various dynamic helpers we call. |
| 47 // If renaming these, make sure to check other places like the | 47 // If renaming these, make sure to check other places like the |
| 48 // _runtime.js file and comments. | 48 // _runtime.js file and comments. |
| 49 // TODO(jmesserly): ideally we'd have a "dynamic call" dart library we can | 49 // TODO(jmesserly): ideally we'd have a "dynamic call" dart library we can |
| 50 // import and generate calls to, rather than dart_runtime.js | 50 // import and generate calls to, rather than dart_runtime.js |
| 51 const DPUT = 'dput'; | 51 const DPUT = 'dput'; |
| 52 const DLOAD = 'dload'; | 52 const DLOAD = 'dload'; |
| 53 const DINDEX = 'dindex'; | 53 const DINDEX = 'dindex'; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 ModuleItemLoadOrder _loader; | 104 ModuleItemLoadOrder _loader; |
| 105 | 105 |
| 106 /// _interceptors.JSArray<E>, used for List literals. | 106 /// _interceptors.JSArray<E>, used for List literals. |
| 107 ClassElement _jsArray; | 107 ClassElement _jsArray; |
| 108 | 108 |
| 109 /// The default value of the module object. See [visitLibraryDirective]. | 109 /// The default value of the module object. See [visitLibraryDirective]. |
| 110 String _jsModuleValue; | 110 String _jsModuleValue; |
| 111 | 111 |
| 112 bool _isDartRuntime; | 112 bool _isDartRuntime; |
| 113 | 113 |
| 114 NullableTypeInference _nullInference; |
| 115 |
| 114 JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary, | 116 JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary, |
| 115 this._extensionTypes, this._fieldsNeedingStorage) | 117 this._extensionTypes, this._fieldsNeedingStorage) |
| 116 : compiler = compiler, | 118 : compiler = compiler, |
| 117 options = compiler.options.codegenOptions, | 119 options = compiler.options.codegenOptions, |
| 118 _types = compiler.context.typeProvider { | 120 _types = compiler.context.typeProvider { |
| 119 _loader = new ModuleItemLoadOrder(_emitModuleItem); | 121 _loader = new ModuleItemLoadOrder(_emitModuleItem); |
| 120 | 122 |
| 121 var context = compiler.context; | 123 var context = compiler.context; |
| 122 var src = context.sourceFactory.forUri('dart:_interceptors'); | 124 var src = context.sourceFactory.forUri('dart:_interceptors'); |
| 123 var interceptors = context.computeLibraryElement(src); | 125 var interceptors = context.computeLibraryElement(src); |
| 124 _jsArray = interceptors.getType('JSArray'); | 126 _jsArray = interceptors.getType('JSArray'); |
| 125 _isDartRuntime = currentLibrary.source.uri.toString() == 'dart:_runtime'; | 127 _isDartRuntime = currentLibrary.source.uri.toString() == 'dart:_runtime'; |
| 126 } | 128 } |
| 127 | 129 |
| 128 TypeProvider get types => _types; | 130 TypeProvider get types => _types; |
| 129 | 131 |
| 130 NullableExpressionPredicate _isNullable; | |
| 131 | |
| 132 JS.Program emitLibrary(LibraryUnit library) { | 132 JS.Program emitLibrary(LibraryUnit library) { |
| 133 // Modify the AST to make coercions explicit. | 133 // Modify the AST to make coercions explicit. |
| 134 new CoercionReifier(library, rules).reify(); | 134 new CoercionReifier(library, rules).reify(); |
| 135 | 135 |
| 136 // Build the public namespace for this library. This allows us to do | 136 // Build the public namespace for this library. This allows us to do |
| 137 // constant time lookups (contrast with `Element.getChild(name)`). | 137 // constant time lookups (contrast with `Element.getChild(name)`). |
| 138 if (currentLibrary.publicNamespace == null) { | 138 if (currentLibrary.publicNamespace == null) { |
| 139 (currentLibrary as LibraryElementImpl).publicNamespace = | 139 (currentLibrary as LibraryElementImpl).publicNamespace = |
| 140 new PublicNamespaceBuilder().build(currentLibrary); | 140 new PublicNamespaceBuilder().build(currentLibrary); |
| 141 } | 141 } |
| 142 | 142 |
| 143 library.library.directives.forEach(_visit); | 143 library.library.directives.forEach(_visit); |
| 144 | 144 |
| 145 var units = library.partsThenLibrary; |
| 146 |
| 145 // Rather than directly visit declarations, we instead use [_loader] to | 147 // Rather than directly visit declarations, we instead use [_loader] to |
| 146 // visit them. It has the ability to sort elements on demand, so | 148 // visit them. It has the ability to sort elements on demand, so |
| 147 // dependencies between top level items are handled with a minimal | 149 // dependencies between top level items are handled with a minimal |
| 148 // reordering of the user's input code. The loader will call back into | 150 // reordering of the user's input code. The loader will call back into |
| 149 // this visitor via [_emitModuleItem] when it's ready to visit the item | 151 // this visitor via [_emitModuleItem] when it's ready to visit the item |
| 150 // for real. | 152 // for real. |
| 151 _loader.collectElements(currentLibrary, library.partsThenLibrary); | 153 _loader.collectElements(currentLibrary, units); |
| 152 | 154 |
| 153 var units = library.partsThenLibrary; | 155 // TODO(jmesserly): ideally we could do this at a smaller granularity. |
| 154 // TODO(ochafik): Move this down to smaller scopes (method, top-levels) to | 156 // We'll need to be consistent about when we're generating functions, and |
| 155 // save memory. | 157 // only run this on the outermost function. |
| 156 _isNullable = new NullabilityInferrer(units, | 158 _nullInference = |
| 157 getStaticType: getStaticType, isJSBuiltinType: _isJSBuiltinType) | 159 new NullableTypeInference.forLibrary(_isPrimitiveType, units); |
| 158 .buildNullabilityPredicate(); | 160 |
| 161 _constField = new ConstFieldVisitor(types, library.library.element.source); |
| 159 | 162 |
| 160 for (var unit in units) { | 163 for (var unit in units) { |
| 161 _constField = new ConstFieldVisitor(types, unit); | |
| 162 | |
| 163 for (var decl in unit.declarations) { | 164 for (var decl in unit.declarations) { |
| 164 if (decl is TopLevelVariableDeclaration) { | 165 if (decl is TopLevelVariableDeclaration) { |
| 165 visitTopLevelVariableDeclaration(decl); | 166 visitTopLevelVariableDeclaration(decl); |
| 166 } else { | 167 } else { |
| 167 _loader.loadDeclaration(decl, decl.element); | 168 _loader.loadDeclaration(decl, decl.element); |
| 168 } | 169 } |
| 169 } | 170 } |
| 170 } | 171 } |
| 171 | 172 |
| 172 // Flush any unwritten fields/properties. | 173 // Flush any unwritten fields/properties. |
| (...skipping 1065 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1238 | 1239 |
| 1239 /// Initialize fields. They follow the sequence: | 1240 /// Initialize fields. They follow the sequence: |
| 1240 /// | 1241 /// |
| 1241 /// 1. field declaration initializer if non-const, | 1242 /// 1. field declaration initializer if non-const, |
| 1242 /// 2. field initializing parameters, | 1243 /// 2. field initializing parameters, |
| 1243 /// 3. constructor field initializers, | 1244 /// 3. constructor field initializers, |
| 1244 /// 4. initialize fields not covered in 1-3 | 1245 /// 4. initialize fields not covered in 1-3 |
| 1245 JS.Statement _initializeFields( | 1246 JS.Statement _initializeFields( |
| 1246 ClassDeclaration cls, List<FieldDeclaration> fieldDecls, | 1247 ClassDeclaration cls, List<FieldDeclaration> fieldDecls, |
| 1247 [ConstructorDeclaration ctor]) { | 1248 [ConstructorDeclaration ctor]) { |
| 1248 var unit = cls.getAncestor((a) => a is CompilationUnit) as CompilationUnit; | |
| 1249 var constField = new ConstFieldVisitor(types, unit); | |
| 1250 bool isConst = ctor != null && ctor.constKeyword != null; | 1249 bool isConst = ctor != null && ctor.constKeyword != null; |
| 1251 if (isConst) _loader.startTopLevel(cls.element); | 1250 if (isConst) _loader.startTopLevel(cls.element); |
| 1252 | 1251 |
| 1253 // Run field initializers if they can have side-effects. | 1252 // Run field initializers if they can have side-effects. |
| 1254 var fields = new Map<FieldElement, JS.Expression>(); | 1253 var fields = new Map<FieldElement, JS.Expression>(); |
| 1255 var unsetFields = new Map<FieldElement, VariableDeclaration>(); | 1254 var unsetFields = new Map<FieldElement, VariableDeclaration>(); |
| 1256 for (var declaration in fieldDecls) { | 1255 for (var declaration in fieldDecls) { |
| 1257 for (var fieldNode in declaration.fields.variables) { | 1256 for (var fieldNode in declaration.fields.variables) { |
| 1258 var element = fieldNode.element; | 1257 var element = fieldNode.element; |
| 1259 if (constField.isFieldInitConstant(fieldNode)) { | 1258 if (_constField.isFieldInitConstant(fieldNode)) { |
| 1260 unsetFields[element as FieldElement] = fieldNode; | 1259 unsetFields[element as FieldElement] = fieldNode; |
| 1261 } else { | 1260 } else { |
| 1262 fields[element as FieldElement] = _visitInitializer(fieldNode); | 1261 fields[element as FieldElement] = _visitInitializer(fieldNode); |
| 1263 } | 1262 } |
| 1264 } | 1263 } |
| 1265 } | 1264 } |
| 1266 | 1265 |
| 1267 // Initialize fields from `this.fieldName` parameters. | 1266 // Initialize fields from `this.fieldName` parameters. |
| 1268 if (ctor != null) { | 1267 if (ctor != null) { |
| 1269 for (var p in ctor.parameters.parameters) { | 1268 for (var p in ctor.parameters.parameters) { |
| (...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1610 // arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them | 1609 // arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them |
| 1611 // with regular functions (e.g. `function({a} = {}) { return 1 }`). | 1610 // with regular functions (e.g. `function({a} = {}) { return 1 }`). |
| 1612 // Note that Firefox accepts both syntaxes just fine. | 1611 // Note that Firefox accepts both syntaxes just fine. |
| 1613 // TODO(ochafik): Simplify this code when Chrome Canary catches up. | 1612 // TODO(ochafik): Simplify this code when Chrome Canary catches up. |
| 1614 bool destructureNamed = params.any((p) => | 1613 bool destructureNamed = params.any((p) => |
| 1615 p is JS.DestructuredVariable && | 1614 p is JS.DestructuredVariable && |
| 1616 p.structure is JS.ObjectBindingPattern); | 1615 p.structure is JS.ObjectBindingPattern); |
| 1617 | 1616 |
| 1618 if (body is ExpressionFunctionBody && !destructureNamed) { | 1617 if (body is ExpressionFunctionBody && !destructureNamed) { |
| 1619 // An arrow function can use the expression directly. | 1618 // An arrow function can use the expression directly. |
| 1620 // Note: this only works if we don't need to emit argument initializers. | |
| 1621 jsBody = _visit(body.expression); | 1619 jsBody = _visit(body.expression); |
| 1622 } else { | 1620 } else { |
| 1623 jsBody = _visit(body); | 1621 jsBody = _visit(body); |
| 1624 } | 1622 } |
| 1625 } | 1623 } |
| 1626 | 1624 |
| 1627 var fn = new JS.ArrowFun(params, jsBody, | 1625 var fn = new JS.ArrowFun(params, jsBody, |
| 1628 typeParams: _emitTypeFormals(type.typeFormals), | 1626 typeParams: _emitTypeFormals(type.typeFormals), |
| 1629 returnType: emitTypeRef(type.returnType)); | 1627 returnType: emitTypeRef(type.returnType)); |
| 1630 return annotate(fn, node); | 1628 return annotate(fn, node); |
| (...skipping 1007 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2638 var name = constructor.name; | 2636 var name = constructor.name; |
| 2639 var type = constructor.type.type; | 2637 var type = constructor.type.type; |
| 2640 return _emitInstanceCreationExpression( | 2638 return _emitInstanceCreationExpression( |
| 2641 element, type, name, node.argumentList, node.isConst); | 2639 element, type, name, node.argumentList, node.isConst); |
| 2642 } | 2640 } |
| 2643 | 2641 |
| 2644 /// True if this type is built-in to JS, and we use the values unwrapped. | 2642 /// True if this type is built-in to JS, and we use the values unwrapped. |
| 2645 /// For these types we generate a calling convention via static | 2643 /// For these types we generate a calling convention via static |
| 2646 /// "extension methods". This allows types to be extended without adding | 2644 /// "extension methods". This allows types to be extended without adding |
| 2647 /// extensions directly on the prototype. | 2645 /// extensions directly on the prototype. |
| 2648 bool _isJSBuiltinType(DartType t) => | 2646 bool _isPrimitiveType(DartType t) => |
| 2649 typeIsPrimitiveInJS(t) || t == _types.stringType; | 2647 typeIsPrimitiveInJS(t) || t == _types.stringType; |
| 2650 | 2648 |
| 2651 bool typeIsPrimitiveInJS(DartType t) => | 2649 bool typeIsPrimitiveInJS(DartType t) => |
| 2652 _isNumberInJS(t) || t == _types.boolType; | 2650 _isNumberInJS(t) || t == _types.boolType; |
| 2653 | 2651 |
| 2654 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => | 2652 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => |
| 2655 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); | 2653 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); |
| 2656 | 2654 |
| 2657 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); | 2655 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); |
| 2658 | 2656 |
| 2659 JS.Expression notNull(Expression expr) { | 2657 JS.Expression notNull(Expression expr) { |
| 2660 if (expr == null) return null; | 2658 if (expr == null) return null; |
| 2661 var jsExpr = _visit(expr); | 2659 var jsExpr = _visit(expr); |
| 2662 if (!_isNullable(expr)) return jsExpr; | 2660 if (!_isNullable(expr)) return jsExpr; |
| 2663 return js.call('dart.notNull(#)', jsExpr); | 2661 return js.call('dart.notNull(#)', jsExpr); |
| 2664 } | 2662 } |
| 2665 | 2663 |
| 2664 /// Returns true if [expr] can be null, optionally using [localIsNullable] |
| 2665 /// for locals. |
| 2666 /// |
| 2667 /// This analysis is conservative and incomplete, but it can optimize many |
| 2668 /// common patterns. |
| 2669 bool _isNullable(Expression expr) => _nullInference.isNullable(expr); |
| 2670 |
| 2666 @override | 2671 @override |
| 2667 JS.Expression visitBinaryExpression(BinaryExpression node) { | 2672 JS.Expression visitBinaryExpression(BinaryExpression node) { |
| 2668 var op = node.operator; | 2673 var op = node.operator; |
| 2669 var left = node.leftOperand; | 2674 var left = node.leftOperand; |
| 2670 var right = node.rightOperand; | 2675 var right = node.rightOperand; |
| 2671 | 2676 |
| 2672 var leftType = getStaticType(left); | 2677 var leftType = getStaticType(left); |
| 2673 var rightType = getStaticType(right); | 2678 var rightType = getStaticType(right); |
| 2674 | 2679 |
| 2675 var code; | 2680 var code; |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2728 var numType = types.numType; | 2733 var numType = types.numType; |
| 2729 if (rules.isSubtypeOf(t, numType)) return numType; | 2734 if (rules.isSubtypeOf(t, numType)) return numType; |
| 2730 return t; | 2735 return t; |
| 2731 } | 2736 } |
| 2732 | 2737 |
| 2733 bool _canUsePrimitiveEquality(Expression left, Expression right) { | 2738 bool _canUsePrimitiveEquality(Expression left, Expression right) { |
| 2734 if (_isNull(left) || _isNull(right)) return true; | 2739 if (_isNull(left) || _isNull(right)) return true; |
| 2735 | 2740 |
| 2736 var leftType = _canonicalizeNumTypes(getStaticType(left)); | 2741 var leftType = _canonicalizeNumTypes(getStaticType(left)); |
| 2737 var rightType = _canonicalizeNumTypes(getStaticType(right)); | 2742 var rightType = _canonicalizeNumTypes(getStaticType(right)); |
| 2738 return _isJSBuiltinType(leftType) && leftType == rightType; | 2743 return _isPrimitiveType(leftType) && leftType == rightType; |
| 2739 } | 2744 } |
| 2740 | 2745 |
| 2741 bool _isNull(Expression expr) => expr is NullLiteral; | 2746 bool _isNull(Expression expr) => expr is NullLiteral; |
| 2742 | 2747 |
| 2743 SimpleIdentifier _createTemporary(String name, DartType type) { | 2748 SimpleIdentifier _createTemporary(String name, DartType type, |
| 2749 {bool nullable: true}) { |
| 2744 // We use an invalid source location to signal that this is a temporary. | 2750 // We use an invalid source location to signal that this is a temporary. |
| 2745 // See [_isTemporary]. | 2751 // See [_isTemporary]. |
| 2746 // TODO(jmesserly): alternatives are | 2752 // TODO(jmesserly): alternatives are |
| 2747 // * (ab)use Element.isSynthetic, which isn't currently used for | 2753 // * (ab)use Element.isSynthetic, which isn't currently used for |
| 2748 // LocalVariableElementImpl, so we could repurpose to mean "temp". | 2754 // LocalVariableElementImpl, so we could repurpose to mean "temp". |
| 2749 // * add a new property to LocalVariableElementImpl. | 2755 // * add a new property to LocalVariableElementImpl. |
| 2750 // * create a new subtype of LocalVariableElementImpl to mark a temp. | 2756 // * create a new subtype of LocalVariableElementImpl to mark a temp. |
| 2751 var id = | 2757 var id = |
| 2752 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, -1)); | 2758 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, -1)); |
| 2753 id.staticElement = new TemporaryVariableElement.forNode(id); | 2759 id.staticElement = new TemporaryVariableElement.forNode(id); |
| 2754 id.staticType = type; | 2760 id.staticType = type; |
| 2755 DynamicInvoke.set(id, type.isDynamic); | 2761 DynamicInvoke.set(id, type.isDynamic); |
| 2762 _nullInference.addVariable(id.staticElement, nullable: nullable); |
| 2756 return id; | 2763 return id; |
| 2757 } | 2764 } |
| 2758 | 2765 |
| 2759 JS.Expression _emitConst(JS.Expression expr()) { | 2766 JS.Expression _emitConst(JS.Expression expr()) { |
| 2760 // TODO(jmesserly): emit the constants at top level if possible. | 2767 // TODO(jmesserly): emit the constants at top level if possible. |
| 2761 // This wasn't quite working, so disabled for now. | 2768 // This wasn't quite working, so disabled for now. |
| 2762 return js.call('dart.const(#)', expr()); | 2769 return js.call('dart.const(#)', expr()); |
| 2763 } | 2770 } |
| 2764 | 2771 |
| 2765 /// Returns a new expression, which can be be used safely *once* on the | 2772 /// Returns a new expression, which can be be used safely *once* on the |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2988 var tail = <JS.Expression>[]; | 2995 var tail = <JS.Expression>[]; |
| 2989 for (;;) { | 2996 for (;;) { |
| 2990 var op = _getOperator(node); | 2997 var op = _getOperator(node); |
| 2991 if (op != null && op.lexeme == '?.') { | 2998 if (op != null && op.lexeme == '?.') { |
| 2992 var nodeTarget = _getTarget(node); | 2999 var nodeTarget = _getTarget(node); |
| 2993 if (!_isNullable(nodeTarget)) { | 3000 if (!_isNullable(nodeTarget)) { |
| 2994 node = _stripNullAwareOp(node, nodeTarget); | 3001 node = _stripNullAwareOp(node, nodeTarget); |
| 2995 break; | 3002 break; |
| 2996 } | 3003 } |
| 2997 | 3004 |
| 2998 var param = _createTemporary('_', nodeTarget.staticType); | 3005 var param = |
| 3006 _createTemporary('_', nodeTarget.staticType, nullable: false); |
| 2999 var baseNode = _stripNullAwareOp(node, param); | 3007 var baseNode = _stripNullAwareOp(node, param); |
| 3000 tail.add(new JS.ArrowFun([_visit(param)], _visit(baseNode))); | 3008 tail.add(new JS.ArrowFun([_visit(param)], _visit(baseNode))); |
| 3001 node = nodeTarget; | 3009 node = nodeTarget; |
| 3002 } else { | 3010 } else { |
| 3003 break; | 3011 break; |
| 3004 } | 3012 } |
| 3005 } | 3013 } |
| 3006 if (tail.isEmpty) return _visit(node); | 3014 if (tail.isEmpty) return _visit(node); |
| 3007 return js.call('dart.nullSafe(#, #)', [_visit(node), tail.reversed]); | 3015 return js.call('dart.nullSafe(#, #)', [_visit(node), tail.reversed]); |
| 3008 } | 3016 } |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3223 var T = node.loopVariable.element.type; | 3231 var T = node.loopVariable.element.type; |
| 3224 var StreamIterator_T = | 3232 var StreamIterator_T = |
| 3225 dart_async.getType('StreamIterator').type.substitute4([T]); | 3233 dart_async.getType('StreamIterator').type.substitute4([T]); |
| 3226 | 3234 |
| 3227 var createStreamIter = _emitInstanceCreationExpression( | 3235 var createStreamIter = _emitInstanceCreationExpression( |
| 3228 StreamIterator_T.element.unnamedConstructor, | 3236 StreamIterator_T.element.unnamedConstructor, |
| 3229 StreamIterator_T, | 3237 StreamIterator_T, |
| 3230 null, | 3238 null, |
| 3231 AstBuilder.argumentList([node.iterable]), | 3239 AstBuilder.argumentList([node.iterable]), |
| 3232 false); | 3240 false); |
| 3233 var iter = _visit(_createTemporary('it', StreamIterator_T)); | 3241 var iter = |
| 3242 _visit(_createTemporary('it', StreamIterator_T, nullable: false)); |
| 3234 | 3243 |
| 3235 var init = _visit(node.identifier); | 3244 var init = _visit(node.identifier); |
| 3236 if (init == null) { | 3245 if (init == null) { |
| 3237 init = js | 3246 init = js |
| 3238 .call('let # = #.current', [node.loopVariable.identifier.name, iter]); | 3247 .call('let # = #.current', [node.loopVariable.identifier.name, iter]); |
| 3239 } else { | 3248 } else { |
| 3240 init = js.call('# = #.current', [init, iter]); | 3249 init = js.call('# = #.current', [init, iter]); |
| 3241 } | 3250 } |
| 3242 return js.statement( | 3251 return js.statement( |
| 3243 '{' | 3252 '{' |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3639 /// Choose a canonical name from the library element. | 3648 /// Choose a canonical name from the library element. |
| 3640 /// This never uses the library's name (the identifier in the `library` | 3649 /// This never uses the library's name (the identifier in the `library` |
| 3641 /// declaration) as it doesn't have any meaningful rules enforced. | 3650 /// declaration) as it doesn't have any meaningful rules enforced. |
| 3642 JS.Identifier emitLibraryName(LibraryElement library) { | 3651 JS.Identifier emitLibraryName(LibraryElement library) { |
| 3643 if (library == currentLibrary) return _exportsVar; | 3652 if (library == currentLibrary) return _exportsVar; |
| 3644 if (library.name == 'dart._runtime') return _runtimeLibVar; | 3653 if (library.name == 'dart._runtime') return _runtimeLibVar; |
| 3645 return _imports.putIfAbsent( | 3654 return _imports.putIfAbsent( |
| 3646 library, () => new JS.TemporaryId(jsLibraryName(library))); | 3655 library, () => new JS.TemporaryId(jsLibraryName(library))); |
| 3647 } | 3656 } |
| 3648 | 3657 |
| 3649 DartType getStaticType(Expression e) => | |
| 3650 e.staticType ?? DynamicTypeImpl.instance; | |
| 3651 | |
| 3652 JS.Node annotate(JS.Node node, AstNode original, [Element element]) { | 3658 JS.Node annotate(JS.Node node, AstNode original, [Element element]) { |
| 3653 if (options.closure && element != null) { | 3659 if (options.closure && element != null) { |
| 3654 node = node.withClosureAnnotation(closureAnnotationFor( | 3660 node = node.withClosureAnnotation(closureAnnotationFor( |
| 3655 node, original, element, namedArgumentTemp.name)); | 3661 node, original, element, namedArgumentTemp.name)); |
| 3656 } | 3662 } |
| 3657 return node..sourceInformation = original; | 3663 return node..sourceInformation = original; |
| 3658 } | 3664 } |
| 3659 | 3665 |
| 3660 /// Returns true if this is any kind of object represented by `Number` in JS. | 3666 /// Returns true if this is any kind of object represented by `Number` in JS. |
| 3661 /// | 3667 /// |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3814 | 3820 |
| 3815 /// A special kind of element created by the compiler, signifying a temporary | 3821 /// A special kind of element created by the compiler, signifying a temporary |
| 3816 /// variable. These objects use instance equality, and should be shared | 3822 /// variable. These objects use instance equality, and should be shared |
| 3817 /// everywhere in the tree where they are treated as the same variable. | 3823 /// everywhere in the tree where they are treated as the same variable. |
| 3818 class TemporaryVariableElement extends LocalVariableElementImpl { | 3824 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 3819 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3825 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 3820 | 3826 |
| 3821 int get hashCode => identityHashCode(this); | 3827 int get hashCode => identityHashCode(this); |
| 3822 bool operator ==(Object other) => identical(this, other); | 3828 bool operator ==(Object other) => identical(this, other); |
| 3823 } | 3829 } |
| OLD | NEW |