| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 deferred_load; | 5 library deferred_load; |
| 6 | 6 |
| 7 import 'common.dart'; | 7 import 'common.dart'; |
| 8 import 'common/backend_api.dart' show | 8 import 'common/backend_api.dart' show Backend; |
| 9 Backend; | 9 import 'common/tasks.dart' show CompilerTask; |
| 10 import 'common/tasks.dart' show | 10 import 'compiler.dart' show Compiler; |
| 11 CompilerTask; | 11 import 'constants/values.dart' |
| 12 import 'compiler.dart' show | 12 show |
| 13 Compiler; | 13 ConstantValue, |
| 14 import 'constants/values.dart' show | 14 ConstructedConstantValue, |
| 15 ConstantValue, | 15 DeferredConstantValue, |
| 16 ConstructedConstantValue, | 16 StringConstantValue; |
| 17 DeferredConstantValue, | |
| 18 StringConstantValue; | |
| 19 import 'dart_types.dart'; | 17 import 'dart_types.dart'; |
| 20 import 'elements/elements.dart' show | 18 import 'elements/elements.dart' |
| 21 AccessorElement, | 19 show |
| 22 AstElement, | 20 AccessorElement, |
| 23 ClassElement, | 21 AstElement, |
| 24 Element, | 22 ClassElement, |
| 25 ElementKind, | 23 Element, |
| 26 Elements, | 24 ElementKind, |
| 27 ExportElement, | 25 Elements, |
| 28 FunctionElement, | 26 ExportElement, |
| 29 ImportElement, | 27 FunctionElement, |
| 30 LibraryElement, | 28 ImportElement, |
| 31 LocalFunctionElement, | 29 LibraryElement, |
| 32 MetadataAnnotation, | 30 LocalFunctionElement, |
| 33 PrefixElement, | 31 MetadataAnnotation, |
| 34 ScopeContainerElement, | 32 PrefixElement, |
| 35 TypedefElement; | 33 ScopeContainerElement, |
| 36 import 'js_backend/js_backend.dart' show | 34 TypedefElement; |
| 37 JavaScriptBackend; | 35 import 'js_backend/js_backend.dart' show JavaScriptBackend; |
| 38 import 'resolution/resolution.dart' show | 36 import 'resolution/resolution.dart' show AnalyzableElementX; |
| 39 AnalyzableElementX; | 37 import 'resolution/tree_elements.dart' show TreeElements; |
| 40 import 'resolution/tree_elements.dart' show | |
| 41 TreeElements; | |
| 42 import 'tree/tree.dart' as ast; | 38 import 'tree/tree.dart' as ast; |
| 43 import 'tree/tree.dart' show | 39 import 'tree/tree.dart' |
| 44 Import, | 40 show |
| 45 LibraryTag, | 41 Import, |
| 46 LibraryDependency, | 42 LibraryTag, |
| 47 LiteralDartString, | 43 LibraryDependency, |
| 48 LiteralString, | 44 LiteralDartString, |
| 49 NewExpression, | 45 LiteralString, |
| 50 Node; | 46 NewExpression, |
| 51 import 'universe/use.dart' show | 47 Node; |
| 52 DynamicUse, | 48 import 'universe/use.dart' show DynamicUse, StaticUse, TypeUse, TypeUseKind; |
| 53 StaticUse, | 49 import 'universe/world_impact.dart' |
| 54 TypeUse, | 50 show ImpactUseCase, WorldImpact, WorldImpactVisitorImpl; |
| 55 TypeUseKind; | 51 import 'util/setlet.dart' show Setlet; |
| 56 import 'universe/world_impact.dart' show | |
| 57 ImpactUseCase, | |
| 58 WorldImpact, | |
| 59 WorldImpactVisitorImpl; | |
| 60 import 'util/setlet.dart' show | |
| 61 Setlet; | |
| 62 import 'util/uri_extras.dart' as uri_extras; | 52 import 'util/uri_extras.dart' as uri_extras; |
| 63 import 'util/util.dart' show | 53 import 'util/util.dart' show Link, makeUnique; |
| 64 Link, makeUnique; | |
| 65 | 54 |
| 66 /// A "hunk" of the program that will be loaded whenever one of its [imports] | 55 /// A "hunk" of the program that will be loaded whenever one of its [imports] |
| 67 /// are loaded. | 56 /// are loaded. |
| 68 /// | 57 /// |
| 69 /// Elements that are only used in one deferred import, is in an OutputUnit with | 58 /// Elements that are only used in one deferred import, is in an OutputUnit with |
| 70 /// the deferred import as single element in the [imports] set. | 59 /// the deferred import as single element in the [imports] set. |
| 71 /// | 60 /// |
| 72 /// Whenever a deferred Element is shared between several deferred imports it is | 61 /// Whenever a deferred Element is shared between several deferred imports it is |
| 73 /// in an output unit with those imports in the [imports] Set. | 62 /// in an output unit with those imports in the [imports] Set. |
| 74 /// | 63 /// |
| 75 /// OutputUnits are equal if their [imports] are equal. | 64 /// OutputUnits are equal if their [imports] are equal. |
| 76 class OutputUnit { | 65 class OutputUnit { |
| 77 /// The deferred imports that will load this output unit when one of them is | 66 /// The deferred imports that will load this output unit when one of them is |
| 78 /// loaded. | 67 /// loaded. |
| 79 final Setlet<_DeferredImport> imports = new Setlet<_DeferredImport>(); | 68 final Setlet<_DeferredImport> imports = new Setlet<_DeferredImport>(); |
| 80 | 69 |
| 81 /// `true` if this output unit is for the main output file. | 70 /// `true` if this output unit is for the main output file. |
| 82 final bool isMainOutput; | 71 final bool isMainOutput; |
| 83 | 72 |
| 84 /// A unique name representing this [OutputUnit]. | 73 /// A unique name representing this [OutputUnit]. |
| 85 String name; | 74 String name; |
| 86 | 75 |
| 87 OutputUnit({this.isMainOutput: false}); | 76 OutputUnit({this.isMainOutput: false}); |
| 88 | 77 |
| 89 String toString() => "OutputUnit($name)"; | 78 String toString() => "OutputUnit($name)"; |
| 90 | 79 |
| 91 bool operator==(OutputUnit other) { | 80 bool operator ==(OutputUnit other) { |
| 92 return imports.length == other.imports.length && | 81 return imports.length == other.imports.length && |
| 93 imports.containsAll(other.imports); | 82 imports.containsAll(other.imports); |
| 94 } | 83 } |
| 95 | 84 |
| 96 int get hashCode { | 85 int get hashCode { |
| 97 int sum = 0; | 86 int sum = 0; |
| 98 for (_DeferredImport import in imports) { | 87 for (_DeferredImport import in imports) { |
| 99 sum = (sum + import.hashCode) & 0x3FFFFFFF; // Stay in 30 bit range. | 88 sum = (sum + import.hashCode) & 0x3FFFFFFF; // Stay in 30 bit range. |
| 100 } | 89 } |
| 101 return sum; | 90 return sum; |
| 102 } | 91 } |
| 103 } | 92 } |
| 104 | 93 |
| 105 /// For each deferred import, find elements and constants to be loaded when that | 94 /// For each deferred import, find elements and constants to be loaded when that |
| 106 /// import is loaded. Elements that are used by several deferred imports are in | 95 /// import is loaded. Elements that are used by several deferred imports are in |
| 107 /// shared OutputUnits. | 96 /// shared OutputUnits. |
| 108 class DeferredLoadTask extends CompilerTask { | 97 class DeferredLoadTask extends CompilerTask { |
| 109 /// The name of this task. | 98 /// The name of this task. |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 /// | 211 /// |
| 223 /// For example, if we have two deferred libraries `A` and `B` that both | 212 /// For example, if we have two deferred libraries `A` and `B` that both |
| 224 /// import a library `C`, then even though elements from `A` and `C` end up in | 213 /// import a library `C`, then even though elements from `A` and `C` end up in |
| 225 /// different output units, there is a non-deferred path between `A` and `C`. | 214 /// different output units, there is a non-deferred path between `A` and `C`. |
| 226 bool hasOnlyNonDeferredImportPaths(Element from, Element to) { | 215 bool hasOnlyNonDeferredImportPaths(Element from, Element to) { |
| 227 OutputUnit outputUnitFrom = outputUnitForElement(from); | 216 OutputUnit outputUnitFrom = outputUnitForElement(from); |
| 228 OutputUnit outputUnitTo = outputUnitForElement(to); | 217 OutputUnit outputUnitTo = outputUnitForElement(to); |
| 229 return outputUnitTo.imports.containsAll(outputUnitFrom.imports); | 218 return outputUnitTo.imports.containsAll(outputUnitFrom.imports); |
| 230 } | 219 } |
| 231 | 220 |
| 232 void registerConstantDeferredUse(DeferredConstantValue constant, | 221 void registerConstantDeferredUse( |
| 233 PrefixElement prefix) { | 222 DeferredConstantValue constant, PrefixElement prefix) { |
| 234 OutputUnit outputUnit = new OutputUnit(); | 223 OutputUnit outputUnit = new OutputUnit(); |
| 235 outputUnit.imports.add(new _DeclaredDeferredImport(prefix.deferredImport)); | 224 outputUnit.imports.add(new _DeclaredDeferredImport(prefix.deferredImport)); |
| 236 _constantToOutputUnit[constant] = outputUnit; | 225 _constantToOutputUnit[constant] = outputUnit; |
| 237 } | 226 } |
| 238 | 227 |
| 239 /// Answers whether [element] is explicitly deferred when referred to from | 228 /// Answers whether [element] is explicitly deferred when referred to from |
| 240 /// [library]. | 229 /// [library]. |
| 241 bool _isExplicitlyDeferred(Element element, LibraryElement library) { | 230 bool _isExplicitlyDeferred(Element element, LibraryElement library) { |
| 242 Iterable<ImportElement> imports = _getImports(element, library); | 231 Iterable<ImportElement> imports = _getImports(element, library); |
| 243 // If the element is not imported explicitly, it is implicitly imported | 232 // If the element is not imported explicitly, it is implicitly imported |
| (...skipping 14 matching lines...) Expand all Loading... |
| 258 if (element.isAccessor) { | 247 if (element.isAccessor) { |
| 259 element = (element as AccessorElement).abstractField; | 248 element = (element as AccessorElement).abstractField; |
| 260 } | 249 } |
| 261 return library.getImportsFor(element); | 250 return library.getImportsFor(element); |
| 262 } | 251 } |
| 263 | 252 |
| 264 /// Finds all elements and constants that [element] depends directly on. | 253 /// Finds all elements and constants that [element] depends directly on. |
| 265 /// (not the transitive closure.) | 254 /// (not the transitive closure.) |
| 266 /// | 255 /// |
| 267 /// Adds the results to [elements] and [constants]. | 256 /// Adds the results to [elements] and [constants]. |
| 268 void _collectAllElementsAndConstantsResolvedFrom( | 257 void _collectAllElementsAndConstantsResolvedFrom(Element element, |
| 269 Element element, | 258 Set<Element> elements, Set<ConstantValue> constants, isMirrorUsage) { |
| 270 Set<Element> elements, | |
| 271 Set<ConstantValue> constants, | |
| 272 isMirrorUsage) { | |
| 273 | |
| 274 if (element.isMalformed) { | 259 if (element.isMalformed) { |
| 275 // Malformed elements are ignored. | 260 // Malformed elements are ignored. |
| 276 return; | 261 return; |
| 277 } | 262 } |
| 278 | 263 |
| 279 /// Recursively collects all the dependencies of [type]. | 264 /// Recursively collects all the dependencies of [type]. |
| 280 void collectTypeDependencies(DartType type) { | 265 void collectTypeDependencies(DartType type) { |
| 281 // TODO(het): we would like to separate out types that are only needed for | 266 // TODO(het): we would like to separate out types that are only needed for |
| 282 // rti from types that are needed for their members. | 267 // rti from types that are needed for their members. |
| 283 if (type is GenericType) { | 268 if (type is GenericType) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 AstElement analyzableElement = element.analyzableElement.declaration; | 305 AstElement analyzableElement = element.analyzableElement.declaration; |
| 321 if (!compiler.enqueuer.resolution.hasBeenProcessed(analyzableElement)) { | 306 if (!compiler.enqueuer.resolution.hasBeenProcessed(analyzableElement)) { |
| 322 return; | 307 return; |
| 323 } | 308 } |
| 324 | 309 |
| 325 WorldImpact worldImpact = | 310 WorldImpact worldImpact = |
| 326 compiler.resolution.getWorldImpact(analyzableElement); | 311 compiler.resolution.getWorldImpact(analyzableElement); |
| 327 compiler.impactStrategy.visitImpact( | 312 compiler.impactStrategy.visitImpact( |
| 328 analyzableElement, | 313 analyzableElement, |
| 329 worldImpact, | 314 worldImpact, |
| 330 new WorldImpactVisitorImpl( | 315 new WorldImpactVisitorImpl(visitStaticUse: (StaticUse staticUse) { |
| 331 visitStaticUse: (StaticUse staticUse) { | 316 elements.add(staticUse.element); |
| 332 elements.add(staticUse.element); | 317 }, visitTypeUse: (TypeUse typeUse) { |
| 333 }, | 318 DartType type = typeUse.type; |
| 334 visitTypeUse: (TypeUse typeUse) { | 319 switch (typeUse.kind) { |
| 335 DartType type = typeUse.type; | 320 case TypeUseKind.TYPE_LITERAL: |
| 336 switch (typeUse.kind) { | 321 if (type.isTypedef || type.isInterfaceType) { |
| 337 case TypeUseKind.TYPE_LITERAL: | 322 elements.add(type.element); |
| 338 if (type.isTypedef || type.isInterfaceType) { | |
| 339 elements.add(type.element); | |
| 340 } | |
| 341 break; | |
| 342 case TypeUseKind.INSTANTIATION: | |
| 343 case TypeUseKind.IS_CHECK: | |
| 344 case TypeUseKind.AS_CAST: | |
| 345 case TypeUseKind.CATCH_TYPE: | |
| 346 collectTypeDependencies(type); | |
| 347 break; | |
| 348 case TypeUseKind.CHECKED_MODE_CHECK: | |
| 349 if (compiler.options.enableTypeAssertions) { | |
| 350 collectTypeDependencies(type); | |
| 351 } | |
| 352 break; | |
| 353 } | 323 } |
| 354 }), | 324 break; |
| 355 IMPACT_USE); | 325 case TypeUseKind.INSTANTIATION: |
| 326 case TypeUseKind.IS_CHECK: |
| 327 case TypeUseKind.AS_CAST: |
| 328 case TypeUseKind.CATCH_TYPE: |
| 329 collectTypeDependencies(type); |
| 330 break; |
| 331 case TypeUseKind.CHECKED_MODE_CHECK: |
| 332 if (compiler.options.enableTypeAssertions) { |
| 333 collectTypeDependencies(type); |
| 334 } |
| 335 break; |
| 336 } |
| 337 }), |
| 338 IMPACT_USE); |
| 356 | 339 |
| 357 TreeElements treeElements = analyzableElement.resolvedAst.elements; | 340 TreeElements treeElements = analyzableElement.resolvedAst.elements; |
| 358 assert(treeElements != null); | 341 assert(treeElements != null); |
| 359 | 342 |
| 360 treeElements.forEachConstantNode((Node node, _) { | 343 treeElements.forEachConstantNode((Node node, _) { |
| 361 // Explicitly depend on the backend constants. | 344 // Explicitly depend on the backend constants. |
| 362 ConstantValue value = | 345 ConstantValue value = |
| 363 backend.constants.getConstantValueForNode(node, treeElements); | 346 backend.constants.getConstantValueForNode(node, treeElements); |
| 364 if (value != null) { | 347 if (value != null) { |
| 365 // TODO(johnniwinther): Assert that all constants have values when | 348 // TODO(johnniwinther): Assert that all constants have values when |
| (...skipping 30 matching lines...) Expand all Loading... |
| 396 ClassElement cls = element.declaration; | 379 ClassElement cls = element.declaration; |
| 397 cls.forEachLocalMember(addLiveInstanceMember); | 380 cls.forEachLocalMember(addLiveInstanceMember); |
| 398 if (cls.implementation != cls) { | 381 if (cls.implementation != cls) { |
| 399 // TODO(ahe): Why doesn't ClassElement.forEachLocalMember do this? | 382 // TODO(ahe): Why doesn't ClassElement.forEachLocalMember do this? |
| 400 cls.implementation.forEachLocalMember(addLiveInstanceMember); | 383 cls.implementation.forEachLocalMember(addLiveInstanceMember); |
| 401 } | 384 } |
| 402 for (var type in cls.implementation.allSupertypes) { | 385 for (var type in cls.implementation.allSupertypes) { |
| 403 elements.add(type.element.implementation); | 386 elements.add(type.element.implementation); |
| 404 } | 387 } |
| 405 elements.add(cls.implementation); | 388 elements.add(cls.implementation); |
| 406 } else if (Elements.isStaticOrTopLevel(element) || | 389 } else if (Elements.isStaticOrTopLevel(element) || element.isConstructor) { |
| 407 element.isConstructor) { | |
| 408 elements.add(element); | 390 elements.add(element); |
| 409 collectDependencies(element); | 391 collectDependencies(element); |
| 410 } | 392 } |
| 411 if (element.isGenerativeConstructor) { | 393 if (element.isGenerativeConstructor) { |
| 412 // When instantiating a class, we record a reference to the | 394 // When instantiating a class, we record a reference to the |
| 413 // constructor, not the class itself. We must add all the | 395 // constructor, not the class itself. We must add all the |
| 414 // instance members of the constructor's class. | 396 // instance members of the constructor's class. |
| 415 ClassElement implementation = | 397 ClassElement implementation = element.enclosingClass.implementation; |
| 416 element.enclosingClass.implementation; | |
| 417 _collectAllElementsAndConstantsResolvedFrom( | 398 _collectAllElementsAndConstantsResolvedFrom( |
| 418 implementation, elements, constants, isMirrorUsage); | 399 implementation, elements, constants, isMirrorUsage); |
| 419 } | 400 } |
| 420 | 401 |
| 421 // Other elements, in particular instance members, are ignored as | 402 // Other elements, in particular instance members, are ignored as |
| 422 // they are processed as part of the class. | 403 // they are processed as part of the class. |
| 423 } | 404 } |
| 424 | 405 |
| 425 /// Returns the transitive closure of all libraries that are imported | 406 /// Returns the transitive closure of all libraries that are imported |
| 426 /// from root without DeferredLibrary annotations. | 407 /// from root without DeferredLibrary annotations. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 450 if (library.isPatched) { | 431 if (library.isPatched) { |
| 451 iterateTags(library.implementation); | 432 iterateTags(library.implementation); |
| 452 } | 433 } |
| 453 } | 434 } |
| 454 traverseLibrary(root); | 435 traverseLibrary(root); |
| 455 result.add(compiler.coreLibrary); | 436 result.add(compiler.coreLibrary); |
| 456 return result; | 437 return result; |
| 457 } | 438 } |
| 458 | 439 |
| 459 /// Add all dependencies of [constant] to the mapping of [import]. | 440 /// Add all dependencies of [constant] to the mapping of [import]. |
| 460 void _mapConstantDependencies(ConstantValue constant, | 441 void _mapConstantDependencies( |
| 461 _DeferredImport import) { | 442 ConstantValue constant, _DeferredImport import) { |
| 462 Set<ConstantValue> constants = _constantsDeferredBy.putIfAbsent(import, | 443 Set<ConstantValue> constants = _constantsDeferredBy.putIfAbsent( |
| 463 () => new Set<ConstantValue>()); | 444 import, () => new Set<ConstantValue>()); |
| 464 if (constants.contains(constant)) return; | 445 if (constants.contains(constant)) return; |
| 465 constants.add(constant); | 446 constants.add(constant); |
| 466 if (constant is ConstructedConstantValue) { | 447 if (constant is ConstructedConstantValue) { |
| 467 _mapDependencies(element: constant.type.element, import: import); | 448 _mapDependencies(element: constant.type.element, import: import); |
| 468 } | 449 } |
| 469 constant.getDependencies().forEach((ConstantValue dependency) { | 450 constant.getDependencies().forEach((ConstantValue dependency) { |
| 470 _mapConstantDependencies(dependency, import); | 451 _mapConstantDependencies(dependency, import); |
| 471 }); | 452 }); |
| 472 } | 453 } |
| 473 | 454 |
| 474 /// Recursively traverses the graph of dependencies from one of [element] | 455 /// Recursively traverses the graph of dependencies from one of [element] |
| 475 /// or [constant], mapping deferred imports to each dependency it needs in the | 456 /// or [constant], mapping deferred imports to each dependency it needs in the |
| 476 /// sets [_importedDeferredBy] and [_constantsDeferredBy]. | 457 /// sets [_importedDeferredBy] and [_constantsDeferredBy]. |
| 477 /// Only one of [element] and [constant] should be given. | 458 /// Only one of [element] and [constant] should be given. |
| 478 void _mapDependencies({Element element, | 459 void _mapDependencies( |
| 479 _DeferredImport import, | 460 {Element element, _DeferredImport import, isMirrorUsage: false}) { |
| 480 isMirrorUsage: false}) { | 461 Set<Element> elements = |
| 481 | 462 _importedDeferredBy.putIfAbsent(import, () => new Set<Element>()); |
| 482 Set<Element> elements = _importedDeferredBy.putIfAbsent(import, | |
| 483 () => new Set<Element>()); | |
| 484 | |
| 485 | 463 |
| 486 Set<Element> dependentElements = new Set<Element>(); | 464 Set<Element> dependentElements = new Set<Element>(); |
| 487 Set<ConstantValue> dependentConstants = new Set<ConstantValue>(); | 465 Set<ConstantValue> dependentConstants = new Set<ConstantValue>(); |
| 488 | 466 |
| 489 LibraryElement library; | 467 LibraryElement library; |
| 490 | 468 |
| 491 if (element != null) { | 469 if (element != null) { |
| 492 // Only process elements once, unless we are doing dependencies due to | 470 // Only process elements once, unless we are doing dependencies due to |
| 493 // mirrors, which are added in additional traversals. | 471 // mirrors, which are added in additional traversals. |
| 494 if (!isMirrorUsage && elements.contains(element)) return; | 472 if (!isMirrorUsage && elements.contains(element)) return; |
| 495 // Anything used directly by main will be loaded from the start | 473 // Anything used directly by main will be loaded from the start |
| 496 // We do not need to traverse it again. | 474 // We do not need to traverse it again. |
| 497 if (import != _fakeMainImport && _mainElements.contains(element)) return; | 475 if (import != _fakeMainImport && _mainElements.contains(element)) return; |
| 498 elements.add(element); | 476 elements.add(element); |
| 499 | 477 |
| 500 | |
| 501 // This call can modify [dependentElements] and [dependentConstants]. | 478 // This call can modify [dependentElements] and [dependentConstants]. |
| 502 _collectAllElementsAndConstantsResolvedFrom( | 479 _collectAllElementsAndConstantsResolvedFrom( |
| 503 element, dependentElements, dependentConstants, isMirrorUsage); | 480 element, dependentElements, dependentConstants, isMirrorUsage); |
| 504 | 481 |
| 505 library = element.library; | 482 library = element.library; |
| 506 } | 483 } |
| 507 | 484 |
| 508 for (Element dependency in dependentElements) { | 485 for (Element dependency in dependentElements) { |
| 509 if (_isExplicitlyDeferred(dependency, library)) { | 486 if (_isExplicitlyDeferred(dependency, library)) { |
| 510 for (ImportElement deferredImport in _getImports(dependency, library)) { | 487 for (ImportElement deferredImport in _getImports(dependency, library)) { |
| 511 _mapDependencies(element: dependency, | 488 _mapDependencies( |
| 489 element: dependency, |
| 512 import: new _DeclaredDeferredImport(deferredImport)); | 490 import: new _DeclaredDeferredImport(deferredImport)); |
| 513 } | 491 } |
| 514 } else { | 492 } else { |
| 515 _mapDependencies(element: dependency, import: import); | 493 _mapDependencies(element: dependency, import: import); |
| 516 } | 494 } |
| 517 } | 495 } |
| 518 | 496 |
| 519 for (ConstantValue dependency in dependentConstants) { | 497 for (ConstantValue dependency in dependentConstants) { |
| 520 if (dependency is DeferredConstantValue) { | 498 if (dependency is DeferredConstantValue) { |
| 521 _mapConstantDependencies(dependency, | 499 _mapConstantDependencies(dependency, |
| 522 new _DeclaredDeferredImport(dependency.prefix.deferredImport)); | 500 new _DeclaredDeferredImport(dependency.prefix.deferredImport)); |
| 523 } else { | 501 } else { |
| 524 _mapConstantDependencies(dependency, import); | 502 _mapConstantDependencies(dependency, import); |
| 525 } | 503 } |
| 526 } | 504 } |
| 527 } | 505 } |
| 528 | 506 |
| 529 /// Adds extra dependencies coming from mirror usage. | 507 /// Adds extra dependencies coming from mirror usage. |
| 530 /// | 508 /// |
| 531 /// The elements are added with [_mapDependencies]. | 509 /// The elements are added with [_mapDependencies]. |
| 532 void _addMirrorElements() { | 510 void _addMirrorElements() { |
| 533 void mapDependenciesIfResolved(Element element, | 511 void mapDependenciesIfResolved( |
| 534 _DeferredImport deferredImport) { | 512 Element element, _DeferredImport deferredImport) { |
| 535 // If an element is the target of a MirrorsUsed annotation but never used | 513 // If an element is the target of a MirrorsUsed annotation but never used |
| 536 // It will not be resolved, and we should not call isNeededForReflection. | 514 // It will not be resolved, and we should not call isNeededForReflection. |
| 537 // TODO(sigurdm): Unresolved elements should just answer false when | 515 // TODO(sigurdm): Unresolved elements should just answer false when |
| 538 // asked isNeededForReflection. Instead an internal error is triggered. | 516 // asked isNeededForReflection. Instead an internal error is triggered. |
| 539 // So we have to filter them out here. | 517 // So we have to filter them out here. |
| 540 if (element is AnalyzableElementX && !element.hasTreeElements) return; | 518 if (element is AnalyzableElementX && !element.hasTreeElements) return; |
| 541 if (compiler.backend.isAccessibleByReflection(element)) { | 519 if (compiler.backend.isAccessibleByReflection(element)) { |
| 542 _mapDependencies( | 520 _mapDependencies( |
| 543 element: element, import: deferredImport, isMirrorUsage: true); | 521 element: element, import: deferredImport, isMirrorUsage: true); |
| 544 } | 522 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 561 } | 539 } |
| 562 } | 540 } |
| 563 | 541 |
| 564 processMetadata(library); | 542 processMetadata(library); |
| 565 library.imports.forEach(processMetadata); | 543 library.imports.forEach(processMetadata); |
| 566 library.exports.forEach(processMetadata); | 544 library.exports.forEach(processMetadata); |
| 567 } | 545 } |
| 568 | 546 |
| 569 for (_DeferredImport deferredImport in _allDeferredImports.keys) { | 547 for (_DeferredImport deferredImport in _allDeferredImports.keys) { |
| 570 LibraryElement deferredLibrary = _allDeferredImports[deferredImport]; | 548 LibraryElement deferredLibrary = _allDeferredImports[deferredImport]; |
| 571 for (LibraryElement library in | 549 for (LibraryElement library |
| 572 _nonDeferredReachableLibraries(deferredLibrary)) { | 550 in _nonDeferredReachableLibraries(deferredLibrary)) { |
| 573 handleLibrary(library, deferredImport); | 551 handleLibrary(library, deferredImport); |
| 574 } | 552 } |
| 575 } | 553 } |
| 576 } | 554 } |
| 577 | 555 |
| 578 /// Computes a unique string for the name field for each outputUnit. | 556 /// Computes a unique string for the name field for each outputUnit. |
| 579 /// | 557 /// |
| 580 /// Also sets up the [hunksToLoad] mapping. | 558 /// Also sets up the [hunksToLoad] mapping. |
| 581 void _assignNamesToOutputUnits(Set<OutputUnit> allOutputUnits) { | 559 void _assignNamesToOutputUnits(Set<OutputUnit> allOutputUnits) { |
| 582 Set<String> usedImportNames = new Set<String>(); | 560 Set<String> usedImportNames = new Set<String>(); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 635 allOutputUnits.add(mainOutputUnit); | 613 allOutputUnits.add(mainOutputUnit); |
| 636 return; | 614 return; |
| 637 } | 615 } |
| 638 if (main == null) return; | 616 if (main == null) return; |
| 639 LibraryElement mainLibrary = main.library; | 617 LibraryElement mainLibrary = main.library; |
| 640 _importedDeferredBy = new Map<_DeferredImport, Set<Element>>(); | 618 _importedDeferredBy = new Map<_DeferredImport, Set<Element>>(); |
| 641 _constantsDeferredBy = new Map<_DeferredImport, Set<ConstantValue>>(); | 619 _constantsDeferredBy = new Map<_DeferredImport, Set<ConstantValue>>(); |
| 642 _importedDeferredBy[_fakeMainImport] = _mainElements; | 620 _importedDeferredBy[_fakeMainImport] = _mainElements; |
| 643 | 621 |
| 644 measureElement(mainLibrary, () { | 622 measureElement(mainLibrary, () { |
| 645 | |
| 646 // Starting from main, traverse the program and find all dependencies. | 623 // Starting from main, traverse the program and find all dependencies. |
| 647 _mapDependencies(element: compiler.mainFunction, import: _fakeMainImport); | 624 _mapDependencies(element: compiler.mainFunction, import: _fakeMainImport); |
| 648 | 625 |
| 649 // Also add "global" dependencies to the main OutputUnit. These are | 626 // Also add "global" dependencies to the main OutputUnit. These are |
| 650 // things that the backend needs but cannot associate with a particular | 627 // things that the backend needs but cannot associate with a particular |
| 651 // element, for example, startRootIsolate. This set also contains | 628 // element, for example, startRootIsolate. This set also contains |
| 652 // elements for which we lack precise information. | 629 // elements for which we lack precise information. |
| 653 for (Element element in compiler.globalDependencies.otherDependencies) { | 630 for (Element element in compiler.globalDependencies.otherDependencies) { |
| 654 _mapDependencies(element: element, import: _fakeMainImport); | 631 _mapDependencies(element: element, import: _fakeMainImport); |
| 655 } | 632 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 669 // all deferred imports mapped to this element. Same for constants. | 646 // all deferred imports mapped to this element. Same for constants. |
| 670 for (_DeferredImport import in _importedDeferredBy.keys) { | 647 for (_DeferredImport import in _importedDeferredBy.keys) { |
| 671 for (Element element in _importedDeferredBy[import]) { | 648 for (Element element in _importedDeferredBy[import]) { |
| 672 // Only one file should be loaded when the program starts, so make | 649 // Only one file should be loaded when the program starts, so make |
| 673 // sure that only one OutputUnit is created for [fakeMainImport]. | 650 // sure that only one OutputUnit is created for [fakeMainImport]. |
| 674 if (import == _fakeMainImport) { | 651 if (import == _fakeMainImport) { |
| 675 elementToOutputUnitBuilder[element] = mainOutputUnit; | 652 elementToOutputUnitBuilder[element] = mainOutputUnit; |
| 676 } else { | 653 } else { |
| 677 elementToOutputUnitBuilder | 654 elementToOutputUnitBuilder |
| 678 .putIfAbsent(element, () => new OutputUnit()) | 655 .putIfAbsent(element, () => new OutputUnit()) |
| 679 .imports.add(import); | 656 .imports |
| 657 .add(import); |
| 680 } | 658 } |
| 681 } | 659 } |
| 682 } | 660 } |
| 683 for (_DeferredImport import in _constantsDeferredBy.keys) { | 661 for (_DeferredImport import in _constantsDeferredBy.keys) { |
| 684 for (ConstantValue constant in _constantsDeferredBy[import]) { | 662 for (ConstantValue constant in _constantsDeferredBy[import]) { |
| 685 // Only one file should be loaded when the program starts, so make | 663 // Only one file should be loaded when the program starts, so make |
| 686 // sure that only one OutputUnit is created for [fakeMainImport]. | 664 // sure that only one OutputUnit is created for [fakeMainImport]. |
| 687 if (import == _fakeMainImport) { | 665 if (import == _fakeMainImport) { |
| 688 constantToOutputUnitBuilder[constant] = mainOutputUnit; | 666 constantToOutputUnitBuilder[constant] = mainOutputUnit; |
| 689 } else { | 667 } else { |
| 690 constantToOutputUnitBuilder | 668 constantToOutputUnitBuilder |
| 691 .putIfAbsent(constant, () => new OutputUnit()) | 669 .putIfAbsent(constant, () => new OutputUnit()) |
| 692 .imports.add(import); | 670 .imports |
| 671 .add(import); |
| 693 } | 672 } |
| 694 } | 673 } |
| 695 } | 674 } |
| 696 | 675 |
| 697 // Release maps; | 676 // Release maps; |
| 698 _importedDeferredBy = null; | 677 _importedDeferredBy = null; |
| 699 _constantsDeferredBy = null; | 678 _constantsDeferredBy = null; |
| 700 | 679 |
| 701 // Find all the output units elements/constants have been mapped to, and | 680 // Find all the output units elements/constants have been mapped to, and |
| 702 // canonicalize them. | 681 // canonicalize them. |
| 703 elementToOutputUnitBuilder.forEach( | 682 elementToOutputUnitBuilder |
| 704 (Element element, OutputUnit outputUnit) { | 683 .forEach((Element element, OutputUnit outputUnit) { |
| 705 OutputUnit representative = allOutputUnits.lookup(outputUnit); | 684 OutputUnit representative = allOutputUnits.lookup(outputUnit); |
| 706 if (representative == null) { | 685 if (representative == null) { |
| 707 representative = outputUnit; | 686 representative = outputUnit; |
| 708 allOutputUnits.add(representative); | 687 allOutputUnits.add(representative); |
| 709 } | 688 } |
| 710 _elementToOutputUnit[element] = representative; | 689 _elementToOutputUnit[element] = representative; |
| 711 }); | 690 }); |
| 712 constantToOutputUnitBuilder.forEach( | 691 constantToOutputUnitBuilder |
| 713 (ConstantValue constant, OutputUnit outputUnit) { | 692 .forEach((ConstantValue constant, OutputUnit outputUnit) { |
| 714 OutputUnit representative = allOutputUnits.lookup(outputUnit); | 693 OutputUnit representative = allOutputUnits.lookup(outputUnit); |
| 715 if (representative == null) { | 694 if (representative == null) { |
| 716 representative = outputUnit; | 695 representative = outputUnit; |
| 717 allOutputUnits.add(representative); | 696 allOutputUnits.add(representative); |
| 718 } | 697 } |
| 719 _constantToOutputUnit[constant] = representative; | 698 _constantToOutputUnit[constant] = representative; |
| 720 }); | 699 }); |
| 721 | 700 |
| 722 // Generate a unique name for each OutputUnit. | 701 // Generate a unique name for each OutputUnit. |
| 723 _assignNamesToOutputUnits(allOutputUnits); | 702 _assignNamesToOutputUnits(allOutputUnits); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 761 for (ImportElement import in library.imports) { | 740 for (ImportElement import in library.imports) { |
| 762 /// Give an error if the old annotation-based syntax has been used. | 741 /// Give an error if the old annotation-based syntax has been used. |
| 763 List<MetadataAnnotation> metadataList = import.metadata; | 742 List<MetadataAnnotation> metadataList = import.metadata; |
| 764 if (metadataList != null) { | 743 if (metadataList != null) { |
| 765 for (MetadataAnnotation metadata in metadataList) { | 744 for (MetadataAnnotation metadata in metadataList) { |
| 766 metadata.ensureResolved(compiler.resolution); | 745 metadata.ensureResolved(compiler.resolution); |
| 767 ConstantValue value = | 746 ConstantValue value = |
| 768 compiler.constants.getConstantValue(metadata.constant); | 747 compiler.constants.getConstantValue(metadata.constant); |
| 769 Element element = value.getType(compiler.coreTypes).element; | 748 Element element = value.getType(compiler.coreTypes).element; |
| 770 if (element == deferredLibraryClass) { | 749 if (element == deferredLibraryClass) { |
| 771 reporter.reportErrorMessage( | 750 reporter.reportErrorMessage( |
| 772 import, MessageKind.DEFERRED_OLD_SYNTAX); | 751 import, MessageKind.DEFERRED_OLD_SYNTAX); |
| 773 } | 752 } |
| 774 } | 753 } |
| 775 } | 754 } |
| 776 | 755 |
| 777 String prefix = (import.prefix != null) | 756 String prefix = (import.prefix != null) ? import.prefix.name : null; |
| 778 ? import.prefix.name | |
| 779 : null; | |
| 780 // The last import we saw with the same prefix. | 757 // The last import we saw with the same prefix. |
| 781 ImportElement previousDeferredImport = prefixDeferredImport[prefix]; | 758 ImportElement previousDeferredImport = prefixDeferredImport[prefix]; |
| 782 if (import.isDeferred) { | 759 if (import.isDeferred) { |
| 783 _DeferredImport key = new _DeclaredDeferredImport(import); | 760 _DeferredImport key = new _DeclaredDeferredImport(import); |
| 784 LibraryElement importedLibrary = import.importedLibrary; | 761 LibraryElement importedLibrary = import.importedLibrary; |
| 785 _allDeferredImports[key] = importedLibrary; | 762 _allDeferredImports[key] = importedLibrary; |
| 786 | 763 |
| 787 if (prefix == null) { | 764 if (prefix == null) { |
| 788 reporter.reportErrorMessage( | 765 reporter.reportErrorMessage( |
| 789 import, | 766 import, MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX); |
| 790 MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX); | |
| 791 } else { | 767 } else { |
| 792 prefixDeferredImport[prefix] = import; | 768 prefixDeferredImport[prefix] = import; |
| 793 _deferredImportDescriptions[key] = | 769 _deferredImportDescriptions[key] = |
| 794 new ImportDescription(import, library, compiler); | 770 new ImportDescription(import, library, compiler); |
| 795 } | 771 } |
| 796 isProgramSplit = true; | 772 isProgramSplit = true; |
| 797 lastDeferred = import; | 773 lastDeferred = import; |
| 798 } | 774 } |
| 799 if (prefix != null) { | 775 if (prefix != null) { |
| 800 if (previousDeferredImport != null || | 776 if (previousDeferredImport != null || |
| 801 (import.isDeferred && usedPrefixes.contains(prefix))) { | 777 (import.isDeferred && usedPrefixes.contains(prefix))) { |
| 802 ImportElement failingImport = (previousDeferredImport != null) | 778 ImportElement failingImport = (previousDeferredImport != null) |
| 803 ? previousDeferredImport | 779 ? previousDeferredImport |
| 804 : import; | 780 : import; |
| 805 reporter.reportErrorMessage( | 781 reporter.reportErrorMessage(failingImport.prefix, |
| 806 failingImport.prefix, | |
| 807 MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX); | 782 MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX); |
| 808 } | 783 } |
| 809 usedPrefixes.add(prefix); | 784 usedPrefixes.add(prefix); |
| 810 } | 785 } |
| 811 } | 786 } |
| 812 }); | 787 }); |
| 813 } | 788 } |
| 814 if (isProgramSplit) { | 789 if (isProgramSplit) { |
| 815 isProgramSplit = compiler.backend.enableDeferredLoadingIfSupported( | 790 isProgramSplit = compiler.backend.enableDeferredLoadingIfSupported( |
| 816 lastDeferred, compiler.globalDependencies); | 791 lastDeferred, compiler.globalDependencies); |
| 817 } | 792 } |
| 818 } | 793 } |
| 819 | 794 |
| 820 /// If [send] is a static send with a deferred element, returns the | 795 /// If [send] is a static send with a deferred element, returns the |
| 821 /// [PrefixElement] that the first prefix of the send resolves to. | 796 /// [PrefixElement] that the first prefix of the send resolves to. |
| 822 /// Otherwise returns null. | 797 /// Otherwise returns null. |
| 823 /// | 798 /// |
| 824 /// Precondition: send must be static. | 799 /// Precondition: send must be static. |
| 825 /// | 800 /// |
| 826 /// Example: | 801 /// Example: |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 886 /// - <prefix> is the `as` prefix used for a given deferred import. | 861 /// - <prefix> is the `as` prefix used for a given deferred import. |
| 887 /// - <list of files> is a list of the filenames the must be loaded when that | 862 /// - <list of files> is a list of the filenames the must be loaded when that |
| 888 /// import is loaded. | 863 /// import is loaded. |
| 889 Map<String, Map<String, dynamic>> computeDeferredMap() { | 864 Map<String, Map<String, dynamic>> computeDeferredMap() { |
| 890 JavaScriptBackend backend = compiler.backend; | 865 JavaScriptBackend backend = compiler.backend; |
| 891 Map<String, Map<String, dynamic>> mapping = | 866 Map<String, Map<String, dynamic>> mapping = |
| 892 new Map<String, Map<String, dynamic>>(); | 867 new Map<String, Map<String, dynamic>>(); |
| 893 _deferredImportDescriptions.keys.forEach((_DeferredImport import) { | 868 _deferredImportDescriptions.keys.forEach((_DeferredImport import) { |
| 894 List<OutputUnit> outputUnits = hunksToLoad[importDeferName[import]]; | 869 List<OutputUnit> outputUnits = hunksToLoad[importDeferName[import]]; |
| 895 ImportDescription description = _deferredImportDescriptions[import]; | 870 ImportDescription description = _deferredImportDescriptions[import]; |
| 896 Map<String, dynamic> libraryMap = | 871 Map<String, dynamic> libraryMap = mapping.putIfAbsent( |
| 897 mapping.putIfAbsent(description.importingUri, | 872 description.importingUri, |
| 898 () => <String, dynamic>{"name": description.importingLibraryName, | 873 () => <String, dynamic>{ |
| 899 "imports": <String, List<String>>{}}); | 874 "name": description.importingLibraryName, |
| 875 "imports": <String, List<String>>{} |
| 876 }); |
| 900 | 877 |
| 901 libraryMap["imports"][importDeferName[import]] = outputUnits.map( | 878 libraryMap["imports"][importDeferName[import]] = |
| 902 (OutputUnit outputUnit) { | 879 outputUnits.map((OutputUnit outputUnit) { |
| 903 return backend.deferredPartFileName(outputUnit.name); | 880 return backend.deferredPartFileName(outputUnit.name); |
| 904 }).toList(); | 881 }).toList(); |
| 905 }); | 882 }); |
| 906 return mapping; | 883 return mapping; |
| 907 } | 884 } |
| 908 | 885 |
| 909 /// Creates a textual representation of the output unit content. | 886 /// Creates a textual representation of the output unit content. |
| 910 String dump() { | 887 String dump() { |
| 911 Map<OutputUnit, List<String>> elementMap = <OutputUnit, List<String>>{}; | 888 Map<OutputUnit, List<String>> elementMap = <OutputUnit, List<String>>{}; |
| 912 Map<OutputUnit, List<String>> constantMap = | 889 Map<OutputUnit, List<String>> constantMap = <OutputUnit, List<String>>{}; |
| 913 <OutputUnit, List<String>>{}; | |
| 914 _elementToOutputUnit.forEach((Element element, OutputUnit output) { | 890 _elementToOutputUnit.forEach((Element element, OutputUnit output) { |
| 915 elementMap.putIfAbsent(output, () => <String>[]).add('$element'); | 891 elementMap.putIfAbsent(output, () => <String>[]).add('$element'); |
| 916 }); | 892 }); |
| 917 _constantToOutputUnit.forEach((ConstantValue value, OutputUnit output) { | 893 _constantToOutputUnit.forEach((ConstantValue value, OutputUnit output) { |
| 918 constantMap.putIfAbsent(output, () => <String>[]) | 894 constantMap |
| 895 .putIfAbsent(output, () => <String>[]) |
| 919 .add(value.toStructuredString()); | 896 .add(value.toStructuredString()); |
| 920 }); | 897 }); |
| 921 | 898 |
| 922 StringBuffer sb = new StringBuffer(); | 899 StringBuffer sb = new StringBuffer(); |
| 923 for (OutputUnit outputUnit in allOutputUnits) { | 900 for (OutputUnit outputUnit in allOutputUnits) { |
| 924 sb.write(outputUnit.name); | 901 sb.write(outputUnit.name); |
| 925 List<String> elements = elementMap[outputUnit]; | 902 List<String> elements = elementMap[outputUnit]; |
| 926 if (elements != null) { | 903 if (elements != null) { |
| 927 sb.write('\n elements:'); | 904 sb.write('\n elements:'); |
| 928 for (String element in elements..sort()) { | 905 for (String element in elements..sort()) { |
| 929 sb.write('\n $element'); | 906 sb.write('\n $element'); |
| 930 } | 907 } |
| 931 } | 908 } |
| 932 List<String> constants = constantMap[outputUnit]; | 909 List<String> constants = constantMap[outputUnit]; |
| 933 if (constants != null) { | 910 if (constants != null) { |
| 934 sb.write('\n constants:'); | 911 sb.write('\n constants:'); |
| 935 for (String value in constants..sort()) { | 912 for (String value in constants..sort()) { |
| 936 sb.write('\n $value'); | 913 sb.write('\n $value'); |
| 937 } | 914 } |
| 938 } | 915 } |
| 939 } | 916 } |
| 940 return sb.toString(); | 917 return sb.toString(); |
| 941 } | 918 } |
| 942 | |
| 943 } | 919 } |
| 944 | 920 |
| 945 class ImportDescription { | 921 class ImportDescription { |
| 946 /// Relative uri to the importing library. | 922 /// Relative uri to the importing library. |
| 947 final String importingUri; | 923 final String importingUri; |
| 924 |
| 948 /// The prefix this import is imported as. | 925 /// The prefix this import is imported as. |
| 949 final String prefix; | 926 final String prefix; |
| 950 final LibraryElement _importingLibrary; | 927 final LibraryElement _importingLibrary; |
| 951 | 928 |
| 952 ImportDescription(ImportElement import, | 929 ImportDescription( |
| 953 LibraryElement importingLibrary, | 930 ImportElement import, LibraryElement importingLibrary, Compiler compiler) |
| 954 Compiler compiler) | 931 : importingUri = uri_extras.relativize(compiler.mainApp.canonicalUri, |
| 955 : importingUri = uri_extras.relativize( | 932 importingLibrary.canonicalUri, false), |
| 956 compiler.mainApp.canonicalUri, | |
| 957 importingLibrary.canonicalUri, false), | |
| 958 prefix = import.prefix.name, | 933 prefix = import.prefix.name, |
| 959 _importingLibrary = importingLibrary; | 934 _importingLibrary = importingLibrary; |
| 960 | 935 |
| 961 String get importingLibraryName { | 936 String get importingLibraryName { |
| 962 return _importingLibrary.hasLibraryName | 937 return _importingLibrary.hasLibraryName |
| 963 ? _importingLibrary.libraryName : "<unnamed>"; | 938 ? _importingLibrary.libraryName |
| 939 : "<unnamed>"; |
| 964 } | 940 } |
| 965 } | 941 } |
| 966 | 942 |
| 967 /// A node in the deferred import graph. | 943 /// A node in the deferred import graph. |
| 968 /// | 944 /// |
| 969 /// This class serves as the root node; the 'import' of the main library. | 945 /// This class serves as the root node; the 'import' of the main library. |
| 970 class _DeferredImport { | 946 class _DeferredImport { |
| 971 const _DeferredImport(); | 947 const _DeferredImport(); |
| 972 | 948 |
| 973 /// Computes a suggestive name for this import. | 949 /// Computes a suggestive name for this import. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1012 return result; | 988 return result; |
| 1013 } | 989 } |
| 1014 | 990 |
| 1015 bool operator ==(other) { | 991 bool operator ==(other) { |
| 1016 if (other is! _DeclaredDeferredImport) return false; | 992 if (other is! _DeclaredDeferredImport) return false; |
| 1017 return declaration == other.declaration; | 993 return declaration == other.declaration; |
| 1018 } | 994 } |
| 1019 | 995 |
| 1020 int get hashCode => declaration.hashCode * 17; | 996 int get hashCode => declaration.hashCode * 17; |
| 1021 } | 997 } |
| OLD | NEW |