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 |