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 // 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 library dev_compiler.src.codegen.js_codegen; | 5 library dev_compiler.src.codegen.js_codegen; |
| 6 | 6 |
| 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; | 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
| 11 import 'package:analyzer/src/generated/constant.dart'; | 11 import 'package:analyzer/src/generated/constant.dart'; |
| 12 import 'package:analyzer/src/generated/element.dart'; | 12 import 'package:analyzer/src/generated/element.dart'; |
| 13 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 13 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
| 14 import 'package:analyzer/src/generated/scanner.dart' | 14 import 'package:analyzer/src/generated/scanner.dart' |
| 15 show StringToken, Token, TokenType; | 15 show StringToken, Token, TokenType; |
| 16 import 'package:analyzer/src/generated/type_system.dart' | 16 import 'package:analyzer/src/generated/type_system.dart' |
| 17 show StrongTypeSystemImpl; | 17 show StrongTypeSystemImpl; |
| 18 import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder; | 18 import 'package:analyzer/src/task/dart.dart' show PublicNamespaceBuilder; |
| 19 | 19 |
| 20 import 'ast_builder.dart' show AstBuilder; | 20 import 'ast_builder.dart' show AstBuilder; |
| 21 import 'reify_coercions.dart' show CoercionReifier, Tuple2; | 21 import 'reify_coercions.dart' show CoercionReifier, Tuple2; |
| 22 | 22 |
| 23 // TODO(jmesserly): import from its own package | 23 // TODO(jmesserly): import from its own package |
| 24 import '../js/js_ast.dart' as JS; | 24 import '../js/js_ast.dart' as JS; |
| 25 import '../js/js_ast.dart' show js; | 25 import '../js/js_ast.dart' show js; |
| 26 | 26 |
| 27 import '../closure/closure_annotator.dart' show ClosureAnnotator; | 27 import '../closure/closure_annotator.dart' show ClosureAnnotator; |
| 28 import '../compiler.dart' show AbstractCompiler; | 28 import '../compiler.dart' |
| 29 show AbstractCompiler, corelibOrder, getCorelibModuleName; | |
| 29 import '../info.dart'; | 30 import '../info.dart'; |
| 30 import '../options.dart' show CodegenOptions; | 31 import '../options.dart' show CodegenOptions; |
| 31 import '../utils.dart'; | 32 import '../utils.dart'; |
| 32 | 33 |
| 33 import 'code_generator.dart'; | 34 import 'code_generator.dart'; |
| 34 import 'js_field_storage.dart'; | 35 import 'js_field_storage.dart'; |
| 35 import 'js_interop.dart'; | 36 import 'js_interop.dart'; |
| 36 import 'js_names.dart' as JS; | 37 import 'js_names.dart' as JS; |
| 37 import 'js_metalet.dart' as JS; | 38 import 'js_metalet.dart' as JS; |
| 38 import 'js_module_item_order.dart'; | 39 import 'js_module_item_order.dart'; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 74 Expression _cascadeTarget; | 75 Expression _cascadeTarget; |
| 75 | 76 |
| 76 /// The variable for the current catch clause | 77 /// The variable for the current catch clause |
| 77 SimpleIdentifier _catchParameter; | 78 SimpleIdentifier _catchParameter; |
| 78 | 79 |
| 79 /// In an async* function, this represents the stream controller parameter. | 80 /// In an async* function, this represents the stream controller parameter. |
| 80 JS.TemporaryId _asyncStarController; | 81 JS.TemporaryId _asyncStarController; |
| 81 | 82 |
| 82 /// Imported libraries, and the temporaries used to refer to them. | 83 /// Imported libraries, and the temporaries used to refer to them. |
| 83 final _imports = new Map<LibraryElement, JS.TemporaryId>(); | 84 final _imports = new Map<LibraryElement, JS.TemporaryId>(); |
| 84 final _exports = new Set<String>(); | 85 final _exports = <String, String>{}; |
| 85 final _properties = <FunctionDeclaration>[]; | 86 final _properties = <FunctionDeclaration>[]; |
| 86 final _privateNames = new HashMap<String, JS.TemporaryId>(); | 87 final _privateNames = new HashMap<String, JS.TemporaryId>(); |
| 87 final _moduleItems = <JS.Statement>[]; | 88 final _moduleItems = <JS.Statement>[]; |
| 88 final _temps = new HashMap<Element, JS.TemporaryId>(); | 89 final _temps = new HashMap<Element, JS.TemporaryId>(); |
| 89 final _qualifiedIds = new List<Tuple2<Element, JS.MaybeQualifiedId>>(); | 90 final _qualifiedIds = new List<Tuple2<Element, JS.MaybeQualifiedId>>(); |
| 90 | 91 |
| 91 /// The name for the library's exports inside itself. | 92 /// The name for the library's exports inside itself. |
| 92 /// `exports` was chosen as the most similar to ES module patterns. | 93 /// `exports` was chosen as the most similar to ES module patterns. |
| 93 final _dartxVar = new JS.Identifier('dartx'); | 94 final _dartxVar = new JS.Identifier('dartx'); |
| 94 final _exportsVar = new JS.TemporaryId('exports'); | 95 final _exportsVar = new JS.TemporaryId('exports'); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 177 var id = elementIdPairs.e1; | 178 var id = elementIdPairs.e1; |
| 178 id.setQualified(!_loader.isLoaded(element)); | 179 id.setQualified(!_loader.isLoaded(element)); |
| 179 } | 180 } |
| 180 | 181 |
| 181 var moduleBuilder = new ModuleBuilder(options.moduleFormat); | 182 var moduleBuilder = new ModuleBuilder(options.moduleFormat); |
| 182 | 183 |
| 183 _exports.forEach(moduleBuilder.addExport); | 184 _exports.forEach(moduleBuilder.addExport); |
| 184 | 185 |
| 185 var items = <JS.ModuleItem>[]; | 186 var items = <JS.ModuleItem>[]; |
| 186 if (!_isDartRuntime) { | 187 if (!_isDartRuntime) { |
| 188 if (currentLibrary.source.isInSystemLibrary) { | |
| 189 // Force the import order of runtime libs. | |
| 190 // TODO(ochafik): Reduce this to a minimum. | |
| 191 for (var lib in corelibOrder.reversed) { | |
| 192 moduleBuilder.addImport(getCorelibModuleName(lib), null); | |
|
Jennifer Messerly
2016/01/29 00:32:31
it would be better to use the URI here... rather t
ochafik
2016/01/29 09:38:17
Good idea, left myself a todo :-)
| |
| 193 } | |
| 194 } | |
| 187 moduleBuilder.addImport('dart/_runtime', _runtimeLibVar); | 195 moduleBuilder.addImport('dart/_runtime', _runtimeLibVar); |
| 188 | 196 |
| 189 var dartxImport = | 197 var dartxImport = |
| 190 js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]); | 198 js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]); |
| 191 items.add(dartxImport); | 199 items.add(dartxImport); |
| 192 } | 200 } |
| 193 items.addAll(_moduleItems); | 201 items.addAll(_moduleItems); |
| 194 | 202 |
| 195 _imports.forEach((LibraryElement lib, JS.TemporaryId temp) { | 203 _imports.forEach((LibraryElement lib, JS.TemporaryId temp) { |
| 196 moduleBuilder.addImport(compiler.getModuleName(lib.source.uri), temp, | 204 moduleBuilder.addImport(compiler.getModuleName(lib.source.uri), temp, |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 257 .where((s) => !currentLibNames.containsKey(s)) | 265 .where((s) => !currentLibNames.containsKey(s)) |
| 258 .map((s) => js.string(s, "'"))); | 266 .map((s) => js.string(s, "'"))); |
| 259 } | 267 } |
| 260 if (hide != null) { | 268 if (hide != null) { |
| 261 hiddenNames.addAll(hide.hiddenNames.map((i) => js.string(i.name, "'"))); | 269 hiddenNames.addAll(hide.hiddenNames.map((i) => js.string(i.name, "'"))); |
| 262 } | 270 } |
| 263 args.add(new JS.ArrayInitializer(shownNames)); | 271 args.add(new JS.ArrayInitializer(shownNames)); |
| 264 args.add(new JS.ArrayInitializer(hiddenNames)); | 272 args.add(new JS.ArrayInitializer(hiddenNames)); |
| 265 } | 273 } |
| 266 | 274 |
| 267 // When we compile _runtime.js, we need to source export_ from _utils.js: | |
| 268 _moduleItems.add(js.statement('dart.export(#);', [args])); | 275 _moduleItems.add(js.statement('dart.export(#);', [args])); |
| 269 } | 276 } |
| 270 | 277 |
| 271 JS.Identifier _initSymbol(JS.Identifier id) { | 278 JS.Identifier _initSymbol(JS.Identifier id) { |
| 272 var s = | 279 var s = |
| 273 js.statement('const # = $_SYMBOL(#);', [id, js.string(id.name, "'")]); | 280 js.statement('const # = $_SYMBOL(#);', [id, js.string(id.name, "'")]); |
| 274 _moduleItems.add(s); | 281 _moduleItems.add(s); |
| 275 return id; | 282 return id; |
| 276 } | 283 } |
| 277 | 284 |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 531 var genericInst = _emitTypeName(dynType, lowerGeneric: true); | 538 var genericInst = _emitTypeName(dynType, lowerGeneric: true); |
| 532 return js.statement('{ #; let # = #; }', [genericDef, name, genericInst]); | 539 return js.statement('{ #; let # = #; }', [genericDef, name, genericInst]); |
| 533 } | 540 } |
| 534 return body; | 541 return body; |
| 535 } | 542 } |
| 536 | 543 |
| 537 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) { | 544 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) { |
| 538 var name = type.name; | 545 var name = type.name; |
| 539 var genericName = '$name\$'; | 546 var genericName = '$name\$'; |
| 540 var typeParams = _boundTypeParametersOf(type).map((p) => p.name); | 547 var typeParams = _boundTypeParametersOf(type).map((p) => p.name); |
| 541 if (isPublic(name)) _exports.add(genericName); | 548 if (isPublic(name)) _addExport(genericName); |
| 542 return js.statement('const # = dart.generic(function(#) { #; return #; });', | 549 return js.statement('const # = dart.generic(function(#) { #; return #; });', |
| 543 [genericName, typeParams, body, name]); | 550 [genericName, typeParams, body, name]); |
| 544 } | 551 } |
| 545 | 552 |
| 546 final _hasDeferredSupertype = new HashSet<ClassElement>(); | 553 final _hasDeferredSupertype = new HashSet<ClassElement>(); |
| 547 | 554 |
| 548 bool _deferIfNeeded(DartType type, ClassElement current) { | 555 bool _deferIfNeeded(DartType type, ClassElement current) { |
| 549 if (type is ParameterizedType) { | 556 if (type is ParameterizedType) { |
| 550 var typeArguments = type.typeArguments; | 557 var typeArguments = type.typeArguments; |
| 551 for (var typeArg in typeArguments) { | 558 for (var typeArg in typeArguments) { |
| (...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1295 | 1302 |
| 1296 if (node.isGetter || node.isSetter) { | 1303 if (node.isGetter || node.isSetter) { |
| 1297 // Add these later so we can use getter/setter syntax. | 1304 // Add these later so we can use getter/setter syntax. |
| 1298 _properties.add(node); | 1305 _properties.add(node); |
| 1299 return null; | 1306 return null; |
| 1300 } | 1307 } |
| 1301 | 1308 |
| 1302 var body = <JS.Statement>[]; | 1309 var body = <JS.Statement>[]; |
| 1303 _flushLibraryProperties(body); | 1310 _flushLibraryProperties(body); |
| 1304 | 1311 |
| 1305 var name = _getJSExportName(node.element) ?? node.name.name; | 1312 var name = node.name.name; |
| 1306 | 1313 |
| 1307 var fn = _visit(node.functionExpression); | 1314 var fn = _visit(node.functionExpression); |
| 1308 | 1315 |
| 1309 if (currentLibrary.source.isInSystemLibrary && | 1316 if (currentLibrary.source.isInSystemLibrary && |
| 1310 _isInlineJSFunction(node.functionExpression)) { | 1317 _isInlineJSFunction(node.functionExpression)) { |
| 1311 fn = _simplifyPassThroughArrowFunCallBody(fn); | 1318 fn = _simplifyPassThroughArrowFunCallBody(fn); |
| 1312 } | 1319 } |
| 1313 | 1320 |
| 1314 var id = new JS.Identifier(name); | 1321 var id = new JS.Identifier(name); |
| 1315 body.add(annotate(new JS.FunctionDeclaration(id, fn), node.element)); | 1322 body.add(annotate(new JS.FunctionDeclaration(id, fn), node.element)); |
| 1316 if (!_isDartRuntime) { | 1323 if (!_isDartRuntime) { |
| 1317 body.add(_emitFunctionTagged(id, node.element.type, topLevel: true) | 1324 body.add(_emitFunctionTagged(id, node.element.type, topLevel: true) |
| 1318 .toStatement()); | 1325 .toStatement()); |
| 1319 } | 1326 } |
| 1320 | 1327 |
| 1321 if (isPublic(name)) _addExport(name); | 1328 if (isPublic(name)) { |
| 1329 _addExport(name, _getJSExportName(node.element) ?? name); | |
| 1330 } | |
| 1322 return _statement(body); | 1331 return _statement(body); |
| 1323 } | 1332 } |
| 1324 | 1333 |
| 1325 bool _isInlineJSFunction(FunctionExpression functionExpression) { | 1334 bool _isInlineJSFunction(FunctionExpression functionExpression) { |
| 1326 var body = functionExpression.body; | 1335 var body = functionExpression.body; |
| 1327 if (body is ExpressionFunctionBody) { | 1336 if (body is ExpressionFunctionBody) { |
| 1328 return _isJSInvocation(body.expression); | 1337 return _isJSInvocation(body.expression); |
| 1329 } else if (body is BlockFunctionBody) { | 1338 } else if (body is BlockFunctionBody) { |
| 1330 if (body.block.statements.length == 1) { | 1339 if (body.block.statements.length == 1) { |
| 1331 var stat = body.block.statements.single; | 1340 var stat = body.block.statements.single; |
| (...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1745 var genericName = _emitTopLevelName(element, suffix: '\$'); | 1754 var genericName = _emitTopLevelName(element, suffix: '\$'); |
| 1746 return js.call('#(#)', [genericName, jsArgs]); | 1755 return js.call('#(#)', [genericName, jsArgs]); |
| 1747 } | 1756 } |
| 1748 } | 1757 } |
| 1749 | 1758 |
| 1750 return _emitTopLevelName(element); | 1759 return _emitTopLevelName(element); |
| 1751 } | 1760 } |
| 1752 | 1761 |
| 1753 JS.Expression _emitTopLevelName(Element e, {String suffix: ''}) { | 1762 JS.Expression _emitTopLevelName(Element e, {String suffix: ''}) { |
| 1754 var libName = _libraryName(e.library); | 1763 var libName = _libraryName(e.library); |
| 1755 var nameExpr = _propertyName((_getJSExportName(e) ?? e.name) + suffix); | |
| 1756 | 1764 |
| 1757 // Always qualify: | 1765 // Always qualify: |
| 1758 // * mutable top-level fields | 1766 // * mutable top-level fields |
| 1759 // * elements from other libraries | 1767 // * elements from other libraries |
| 1760 bool mutableTopLevel = e is TopLevelVariableElement && | 1768 bool mutableTopLevel = e is TopLevelVariableElement && |
| 1761 !e.isConst && | 1769 !e.isConst && |
| 1762 !_isFinalJSDecl(e.computeNode()); | 1770 !_isFinalJSDecl(e.computeNode()); |
| 1763 bool fromAnotherLibrary = e.library != currentLibrary; | 1771 bool fromAnotherLibrary = e.library != currentLibrary; |
| 1772 var nameExpr; | |
| 1773 if (fromAnotherLibrary) { | |
| 1774 nameExpr = _propertyName((_getJSExportName(e) ?? e.name) + suffix); | |
| 1775 } else { | |
| 1776 nameExpr = _propertyName(e.name + suffix); | |
| 1777 } | |
| 1764 if (mutableTopLevel || fromAnotherLibrary) { | 1778 if (mutableTopLevel || fromAnotherLibrary) { |
| 1765 return new JS.PropertyAccess(libName, nameExpr); | 1779 return new JS.PropertyAccess(libName, nameExpr); |
| 1766 } | 1780 } |
| 1767 | 1781 |
| 1768 var id = new JS.MaybeQualifiedId(libName, nameExpr); | 1782 var id = new JS.MaybeQualifiedId(libName, nameExpr); |
| 1769 _qualifiedIds.add(new Tuple2(e, id)); | 1783 _qualifiedIds.add(new Tuple2(e, id)); |
| 1770 return id; | 1784 return id; |
| 1771 } | 1785 } |
| 1772 | 1786 |
| 1773 @override | 1787 @override |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2131 return new JS.Yield(_visit(node.expression)); | 2145 return new JS.Yield(_visit(node.expression)); |
| 2132 } | 2146 } |
| 2133 | 2147 |
| 2134 @override | 2148 @override |
| 2135 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | 2149 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
| 2136 for (var v in node.variables.variables) { | 2150 for (var v in node.variables.variables) { |
| 2137 _loader.loadDeclaration(v, v.element); | 2151 _loader.loadDeclaration(v, v.element); |
| 2138 } | 2152 } |
| 2139 } | 2153 } |
| 2140 | 2154 |
| 2141 _addExport(String name) { | 2155 /// Emits static fields. |
| 2142 if (!_exports.add(name)) throw 'Duplicate top level name found: $name'; | 2156 /// |
| 2157 /// Instance fields are emitted in [_initializeFields]. | |
| 2158 /// | |
| 2159 /// These are generally treated the same as top-level fields, see | |
| 2160 /// [visitTopLevelVariableDeclaration]. | |
| 2161 @override | |
| 2162 visitFieldDeclaration(FieldDeclaration node) { | |
| 2163 if (!node.isStatic) return; | |
| 2164 | |
| 2165 for (var f in node.fields.variables) { | |
| 2166 _loader.loadDeclaration(f, f.element); | |
| 2167 } | |
| 2168 } | |
| 2169 | |
| 2170 _addExport(String name, [String exportName]) { | |
| 2171 if (_exports.containsKey(name)) { | |
| 2172 throw 'Duplicate top level name found: $name'; | |
| 2173 } | |
| 2174 _exports[name] = exportName ?? name; | |
| 2143 } | 2175 } |
| 2144 | 2176 |
| 2145 @override | 2177 @override |
| 2146 JS.Statement visitVariableDeclarationStatement( | 2178 JS.Statement visitVariableDeclarationStatement( |
| 2147 VariableDeclarationStatement node) { | 2179 VariableDeclarationStatement node) { |
| 2148 // Special case a single variable with an initializer. | 2180 // Special case a single variable with an initializer. |
| 2149 // This helps emit cleaner code for things like: | 2181 // This helps emit cleaner code for things like: |
| 2150 // var result = []..add(1)..add(2); | 2182 // var result = []..add(1)..add(2); |
| 2151 if (node.variables.variables.length == 1) { | 2183 if (node.variables.variables.length == 1) { |
| 2152 var v = node.variables.variables.single; | 2184 var v = node.variables.variables.single; |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2241 // later on when we emit lazy fields. That seems busted. | 2273 // later on when we emit lazy fields. That seems busted. |
| 2242 jsInit = _visitInitializer(field); | 2274 jsInit = _visitInitializer(field); |
| 2243 eagerInit = false; | 2275 eagerInit = false; |
| 2244 } | 2276 } |
| 2245 | 2277 |
| 2246 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile | 2278 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile |
| 2247 // runtime helpers. | 2279 // runtime helpers. |
| 2248 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field); | 2280 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field); |
| 2249 if (isJSTopLevel) eagerInit = true; | 2281 if (isJSTopLevel) eagerInit = true; |
| 2250 | 2282 |
| 2251 var fieldName = _getJSExportName(element) ?? field.name.name; | 2283 var fieldName = field.name.name; |
| 2252 if (field.isConst && eagerInit || isJSTopLevel) { | 2284 var exportName = fieldName; |
| 2285 if (element is TopLevelVariableElement) { | |
| 2286 exportName = _getJSExportName(element) ?? fieldName; | |
| 2287 } | |
| 2288 if ((field.isConst && eagerInit && element is TopLevelVariableElement) || | |
| 2289 isJSTopLevel) { | |
| 2253 // constant fields don't change, so we can generate them as `let` | 2290 // constant fields don't change, so we can generate them as `let` |
| 2254 // but add them to the module's exports. However, make sure we generate | 2291 // but add them to the module's exports. However, make sure we generate |
| 2255 // anything they depend on first. | 2292 // anything they depend on first. |
| 2256 if (isPublic(fieldName)) _addExport(fieldName); | 2293 |
| 2294 if (isPublic(fieldName)) _addExport(fieldName, exportName); | |
| 2257 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; | 2295 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let'; |
| 2258 return annotateVariable( | 2296 return annotateVariable( |
| 2259 js.statement( | 2297 js.statement( |
| 2260 '$declKeyword # = #;', [new JS.Identifier(fieldName), jsInit]), | 2298 '$declKeyword # = #;', [new JS.Identifier(fieldName), jsInit]), |
| 2261 field.element); | 2299 field.element); |
| 2262 } | 2300 } |
| 2263 | 2301 |
| 2264 if (eagerInit && !JS.invalidStaticFieldName(fieldName)) { | 2302 if (eagerInit && !JS.invalidStaticFieldName(fieldName)) { |
| 2265 return annotateVariable( | 2303 return annotateVariable( |
| 2266 js.statement('# = #;', [_visit(field.name), jsInit]), field.element); | 2304 js.statement('# = #;', [_visit(field.name), jsInit]), field.element); |
| (...skipping 1285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3552 | 3590 |
| 3553 /// A special kind of element created by the compiler, signifying a temporary | 3591 /// A special kind of element created by the compiler, signifying a temporary |
| 3554 /// variable. These objects use instance equality, and should be shared | 3592 /// variable. These objects use instance equality, and should be shared |
| 3555 /// everywhere in the tree where they are treated as the same variable. | 3593 /// everywhere in the tree where they are treated as the same variable. |
| 3556 class TemporaryVariableElement extends LocalVariableElementImpl { | 3594 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 3557 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3595 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 3558 | 3596 |
| 3559 int get hashCode => identityHashCode(this); | 3597 int get hashCode => identityHashCode(this); |
| 3560 bool operator ==(Object other) => identical(this, other); | 3598 bool operator ==(Object other) => identical(this, other); |
| 3561 } | 3599 } |
| OLD | NEW |