| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 dart2js.enqueue; | 5 library dart2js.enqueue; |
| 6 | 6 |
| 7 import 'dart:collection' show Queue; | 7 import 'dart:collection' show Queue; |
| 8 | 8 |
| 9 import 'common/resolution.dart' show Resolution; | 9 import 'common/resolution.dart' show Resolution; |
| 10 import 'common/tasks.dart' show CompilerTask; | 10 import 'common/tasks.dart' show CompilerTask; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 _codegen = compiler.backend.createCodegenEnqueuer(this, compiler); | 57 _codegen = compiler.backend.createCodegenEnqueuer(this, compiler); |
| 58 } | 58 } |
| 59 | 59 |
| 60 ResolutionEnqueuer get resolution => _resolution; | 60 ResolutionEnqueuer get resolution => _resolution; |
| 61 Enqueuer get codegen => _codegen; | 61 Enqueuer get codegen => _codegen; |
| 62 } | 62 } |
| 63 | 63 |
| 64 abstract class Enqueuer { | 64 abstract class Enqueuer { |
| 65 WorldBuilder get worldBuilder; | 65 WorldBuilder get worldBuilder; |
| 66 native.NativeEnqueuer get nativeEnqueuer; | 66 native.NativeEnqueuer get nativeEnqueuer; |
| 67 ImpactStrategy get impactStrategy; |
| 67 | 68 |
| 68 // TODO(johnniwinther): Initialize [_impactStrategy] to `null`. | 69 void open(ImpactStrategy impactStrategy, FunctionEntity mainMethod, |
| 69 ImpactStrategy _impactStrategy = const ImpactStrategy(); | 70 Iterable<LibraryEntity> libraries); |
| 70 | 71 void close(); |
| 71 ImpactStrategy get impactStrategy => _impactStrategy; | |
| 72 | |
| 73 void open(ImpactStrategy impactStrategy) { | |
| 74 _impactStrategy = impactStrategy; | |
| 75 } | |
| 76 | |
| 77 void close() { | |
| 78 // TODO(johnniwinther): Set [_impactStrategy] to `null` and [queueIsClosed] | |
| 79 // to `true` here. | |
| 80 _impactStrategy = const ImpactStrategy(); | |
| 81 } | |
| 82 | 72 |
| 83 /// Returns [:true:] if this enqueuer is the resolution enqueuer. | 73 /// Returns [:true:] if this enqueuer is the resolution enqueuer. |
| 84 bool get isResolutionQueue; | 74 bool get isResolutionQueue; |
| 85 | 75 |
| 86 bool queueIsClosed; | 76 bool queueIsClosed; |
| 87 | 77 |
| 88 bool get queueIsEmpty; | 78 bool get queueIsEmpty; |
| 89 | 79 |
| 90 ImpactUseCase get impactUse; | 80 ImpactUseCase get impactUse; |
| 91 | 81 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 WorldImpact registerClosureWithFreeTypeVariables(MemberEntity member); | 119 WorldImpact registerClosureWithFreeTypeVariables(MemberEntity member); |
| 130 | 120 |
| 131 /// Called to register that a member has been closurized. Any backend specific | 121 /// Called to register that a member has been closurized. Any backend specific |
| 132 /// [WorldImpact] of this is returned. | 122 /// [WorldImpact] of this is returned. |
| 133 WorldImpact registerBoundClosure(); | 123 WorldImpact registerBoundClosure(); |
| 134 | 124 |
| 135 /// Called to register that [element] is statically known to be used. Any | 125 /// Called to register that [element] is statically known to be used. Any |
| 136 /// backend specific [WorldImpact] of this is returned. | 126 /// backend specific [WorldImpact] of this is returned. |
| 137 WorldImpact registerUsedElement(MemberEntity member); | 127 WorldImpact registerUsedElement(MemberEntity member); |
| 138 | 128 |
| 129 void onQueueOpen(Enqueuer enqueuer, FunctionEntity mainMethod, |
| 130 Iterable<LibraryEntity> libraries); |
| 131 |
| 139 /// Called when [enqueuer]'s queue is empty, but before it is closed. | 132 /// Called when [enqueuer]'s queue is empty, but before it is closed. |
| 140 /// | 133 /// |
| 141 /// This is used, for example, by the JS backend to enqueue additional | 134 /// This is used, for example, by the JS backend to enqueue additional |
| 142 /// elements needed for reflection. [recentClasses] is a collection of | 135 /// elements needed for reflection. [recentClasses] is a collection of |
| 143 /// all classes seen for the first time by the [enqueuer] since the last call | 136 /// all classes seen for the first time by the [enqueuer] since the last call |
| 144 /// to [onQueueEmpty]. | 137 /// to [onQueueEmpty]. |
| 145 /// | 138 /// |
| 146 /// A return value of `true` indicates that [recentClasses] has been | 139 /// A return value of `true` indicates that [recentClasses] has been |
| 147 /// processed and its elements do not need to be seen in the next round. When | 140 /// processed and its elements do not need to be seen in the next round. When |
| 148 /// `false` is returned, [onQueueEmpty] will be called again once the | 141 /// `false` is returned, [onQueueEmpty] will be called again once the |
| 149 /// resolution queue has drained and [recentClasses] will be a superset of the | 142 /// resolution queue has drained and [recentClasses] will be a superset of the |
| 150 /// current value. | 143 /// current value. |
| 151 /// | 144 /// |
| 152 /// There is no guarantee that a class is only present once in | 145 /// There is no guarantee that a class is only present once in |
| 153 /// [recentClasses], but every class seen by the [enqueuer] will be present in | 146 /// [recentClasses], but every class seen by the [enqueuer] will be present in |
| 154 /// [recentClasses] at least once. | 147 /// [recentClasses] at least once. |
| 155 bool onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses); | 148 bool onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses); |
| 156 } | 149 } |
| 157 | 150 |
| 158 abstract class EnqueuerImpl extends Enqueuer { | 151 abstract class EnqueuerImpl extends Enqueuer { |
| 159 CompilerTask get task; | 152 CompilerTask get task; |
| 160 EnqueuerStrategy get strategy; | 153 EnqueuerStrategy get strategy; |
| 161 void checkClass(ClassEntity cls); | 154 void checkClass(ClassEntity cls); |
| 162 void processStaticUse(StaticUse staticUse); | 155 void processStaticUse(StaticUse staticUse); |
| 163 void processTypeUse(TypeUse typeUse); | 156 void processTypeUse(TypeUse typeUse); |
| 164 void processDynamicUse(DynamicUse dynamicUse); | 157 void processDynamicUse(DynamicUse dynamicUse); |
| 158 EnqueuerListener get listener; |
| 159 |
| 160 // TODO(johnniwinther): Initialize [_impactStrategy] to `null`. |
| 161 ImpactStrategy _impactStrategy = const ImpactStrategy(); |
| 162 |
| 163 ImpactStrategy get impactStrategy => _impactStrategy; |
| 164 |
| 165 void open(ImpactStrategy impactStrategy, FunctionEntity mainMethod, |
| 166 Iterable<LibraryEntity> libraries) { |
| 167 _impactStrategy = impactStrategy; |
| 168 listener.onQueueOpen(this, mainMethod, libraries); |
| 169 } |
| 170 |
| 171 void close() { |
| 172 // TODO(johnniwinther): Set [_impactStrategy] to `null` and [queueIsClosed] |
| 173 // to `true` here. |
| 174 _impactStrategy = const ImpactStrategy(); |
| 175 } |
| 165 } | 176 } |
| 166 | 177 |
| 167 /// [Enqueuer] which is specific to resolution. | 178 /// [Enqueuer] which is specific to resolution. |
| 168 class ResolutionEnqueuer extends EnqueuerImpl { | 179 class ResolutionEnqueuer extends EnqueuerImpl { |
| 169 static const ImpactUseCase IMPACT_USE = | 180 static const ImpactUseCase IMPACT_USE = |
| 170 const ImpactUseCase('ResolutionEnqueuer'); | 181 const ImpactUseCase('ResolutionEnqueuer'); |
| 171 | 182 |
| 172 final CompilerTask task; | 183 final CompilerTask task; |
| 173 final String name; | 184 final String name; |
| 174 final CompilerOptions _options; | 185 final CompilerOptions _options; |
| 175 final EnqueuerListener _listener; | 186 final EnqueuerListener listener; |
| 176 final native.NativeEnqueuer nativeEnqueuer; | 187 final native.NativeEnqueuer nativeEnqueuer; |
| 177 | 188 |
| 178 final EnqueuerStrategy strategy; | 189 final EnqueuerStrategy strategy; |
| 179 final Set<ClassEntity> _recentClasses = new Setlet<ClassEntity>(); | 190 final Set<ClassEntity> _recentClasses = new Setlet<ClassEntity>(); |
| 180 final ResolutionWorldBuilderImpl _universe; | 191 final ResolutionWorldBuilderImpl _universe; |
| 181 final WorkItemBuilder _workItemBuilder; | 192 final WorkItemBuilder _workItemBuilder; |
| 182 final DiagnosticReporter _reporter; | 193 final DiagnosticReporter _reporter; |
| 183 | 194 |
| 184 bool queueIsClosed = false; | 195 bool queueIsClosed = false; |
| 185 | 196 |
| 186 WorldImpactVisitor _impactVisitor; | 197 WorldImpactVisitor _impactVisitor; |
| 187 | 198 |
| 188 /// All declaration elements that have been processed by the resolver. | 199 /// All declaration elements that have been processed by the resolver. |
| 189 final Set<Entity> _processedEntities = new Set<Entity>(); | 200 final Set<Entity> _processedEntities = new Set<Entity>(); |
| 190 | 201 |
| 191 final Queue<WorkItem> _queue = new Queue<WorkItem>(); | 202 final Queue<WorkItem> _queue = new Queue<WorkItem>(); |
| 192 | 203 |
| 193 /// Queue of deferred resolution actions to execute when the resolution queue | 204 /// Queue of deferred resolution actions to execute when the resolution queue |
| 194 /// has been emptied. | 205 /// has been emptied. |
| 195 final Queue<_DeferredAction> _deferredQueue = new Queue<_DeferredAction>(); | 206 final Queue<_DeferredAction> _deferredQueue = new Queue<_DeferredAction>(); |
| 196 | 207 |
| 197 ResolutionEnqueuer( | 208 ResolutionEnqueuer(this.task, this._options, this._reporter, this.strategy, |
| 198 this.task, | 209 this.listener, this.nativeEnqueuer, this._universe, this._workItemBuilder, |
| 199 this._options, | |
| 200 this._reporter, | |
| 201 this.strategy, | |
| 202 this._listener, | |
| 203 this.nativeEnqueuer, | |
| 204 this._universe, | |
| 205 this._workItemBuilder, | |
| 206 [this.name = 'resolution enqueuer']) { | 210 [this.name = 'resolution enqueuer']) { |
| 207 _impactVisitor = new EnqueuerImplImpactVisitor(this); | 211 _impactVisitor = new EnqueuerImplImpactVisitor(this); |
| 208 } | 212 } |
| 209 | 213 |
| 210 ResolutionWorldBuilder get worldBuilder => _universe; | 214 ResolutionWorldBuilder get worldBuilder => _universe; |
| 211 | 215 |
| 212 bool get queueIsEmpty => _queue.isEmpty; | 216 bool get queueIsEmpty => _queue.isEmpty; |
| 213 | 217 |
| 214 @override | 218 @override |
| 215 void checkQueueIsEmpty() { | 219 void checkQueueIsEmpty() { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 234 bool globalDependency: false, | 238 bool globalDependency: false, |
| 235 bool isRedirection: false}) { | 239 bool isRedirection: false}) { |
| 236 task.measure(() { | 240 task.measure(() { |
| 237 _universe.registerTypeInstantiation(type, _applyClassUse, | 241 _universe.registerTypeInstantiation(type, _applyClassUse, |
| 238 constructor: constructor, | 242 constructor: constructor, |
| 239 byMirrors: mirrorUsage, | 243 byMirrors: mirrorUsage, |
| 240 isRedirection: isRedirection); | 244 isRedirection: isRedirection); |
| 241 if (nativeUsage) { | 245 if (nativeUsage) { |
| 242 nativeEnqueuer.onInstantiatedType(type); | 246 nativeEnqueuer.onInstantiatedType(type); |
| 243 } | 247 } |
| 244 _listener.registerInstantiatedType(type, | 248 listener.registerInstantiatedType(type, |
| 245 isGlobal: globalDependency && !mirrorUsage); | 249 isGlobal: globalDependency && !mirrorUsage); |
| 246 }); | 250 }); |
| 247 } | 251 } |
| 248 | 252 |
| 249 bool checkNoEnqueuedInvokedInstanceMethods() { | 253 bool checkNoEnqueuedInvokedInstanceMethods() { |
| 250 return strategy.checkEnqueuerConsistency(this); | 254 return strategy.checkEnqueuerConsistency(this); |
| 251 } | 255 } |
| 252 | 256 |
| 253 void checkClass(ClassEntity cls) { | 257 void checkClass(ClassEntity cls) { |
| 254 _universe.processClassMembers(cls, | 258 _universe.processClassMembers(cls, |
| 255 (MemberEntity member, EnumSet<MemberUse> useSet) { | 259 (MemberEntity member, EnumSet<MemberUse> useSet) { |
| 256 if (useSet.isNotEmpty) { | 260 if (useSet.isNotEmpty) { |
| 257 _reporter.internalError(member, | 261 _reporter.internalError(member, |
| 258 'Unenqueued use of $member: ${useSet.iterable(MemberUse.values)}'); | 262 'Unenqueued use of $member: ${useSet.iterable(MemberUse.values)}'); |
| 259 } | 263 } |
| 260 }); | 264 }); |
| 261 } | 265 } |
| 262 | 266 |
| 263 /// Callback for applying the use of a [member]. | 267 /// Callback for applying the use of a [member]. |
| 264 void _applyMemberUse(Entity member, EnumSet<MemberUse> useSet) { | 268 void _applyMemberUse(Entity member, EnumSet<MemberUse> useSet) { |
| 265 if (useSet.contains(MemberUse.NORMAL)) { | 269 if (useSet.contains(MemberUse.NORMAL)) { |
| 266 _addToWorkList(member); | 270 _addToWorkList(member); |
| 267 } | 271 } |
| 268 if (useSet.contains(MemberUse.CLOSURIZE_INSTANCE)) { | 272 if (useSet.contains(MemberUse.CLOSURIZE_INSTANCE)) { |
| 269 _registerClosurizedMember(member); | 273 _registerClosurizedMember(member); |
| 270 } | 274 } |
| 271 if (useSet.contains(MemberUse.CLOSURIZE_STATIC)) { | 275 if (useSet.contains(MemberUse.CLOSURIZE_STATIC)) { |
| 272 applyImpact(_listener.registerGetOfStaticFunction()); | 276 applyImpact(listener.registerGetOfStaticFunction()); |
| 273 } | 277 } |
| 274 } | 278 } |
| 275 | 279 |
| 276 /// Callback for applying the use of a [cls]. | 280 /// Callback for applying the use of a [cls]. |
| 277 void _applyClassUse(ClassEntity cls, EnumSet<ClassUse> useSet) { | 281 void _applyClassUse(ClassEntity cls, EnumSet<ClassUse> useSet) { |
| 278 if (useSet.contains(ClassUse.INSTANTIATED)) { | 282 if (useSet.contains(ClassUse.INSTANTIATED)) { |
| 279 _recentClasses.add(cls); | 283 _recentClasses.add(cls); |
| 280 _universe.processClassMembers(cls, _applyMemberUse); | 284 _universe.processClassMembers(cls, _applyMemberUse); |
| 281 // We only tell the backend once that [cls] was instantiated, so | 285 // We only tell the backend once that [cls] was instantiated, so |
| 282 // any additional dependencies must be treated as global | 286 // any additional dependencies must be treated as global |
| 283 // dependencies. | 287 // dependencies. |
| 284 applyImpact(_listener.registerInstantiatedClass(cls)); | 288 applyImpact(listener.registerInstantiatedClass(cls)); |
| 285 } | 289 } |
| 286 if (useSet.contains(ClassUse.IMPLEMENTED)) { | 290 if (useSet.contains(ClassUse.IMPLEMENTED)) { |
| 287 applyImpact(_listener.registerImplementedClass(cls)); | 291 applyImpact(listener.registerImplementedClass(cls)); |
| 288 } | 292 } |
| 289 } | 293 } |
| 290 | 294 |
| 291 void processDynamicUse(DynamicUse dynamicUse) { | 295 void processDynamicUse(DynamicUse dynamicUse) { |
| 292 task.measure(() { | 296 task.measure(() { |
| 293 _universe.registerDynamicUse(dynamicUse, _applyMemberUse); | 297 _universe.registerDynamicUse(dynamicUse, _applyMemberUse); |
| 294 }); | 298 }); |
| 295 } | 299 } |
| 296 | 300 |
| 297 void processStaticUse(StaticUse staticUse) { | 301 void processStaticUse(StaticUse staticUse) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 351 type = _universe.registerIsCheck(type); | 355 type = _universe.registerIsCheck(type); |
| 352 // Even in checked mode, type annotations for return type and argument | 356 // Even in checked mode, type annotations for return type and argument |
| 353 // types do not imply type checks, so there should never be a check | 357 // types do not imply type checks, so there should never be a check |
| 354 // against the type variable of a typedef. | 358 // against the type variable of a typedef. |
| 355 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); | 359 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); |
| 356 } | 360 } |
| 357 | 361 |
| 358 void _registerClosurizedMember(MemberElement element) { | 362 void _registerClosurizedMember(MemberElement element) { |
| 359 assert(element.isInstanceMember); | 363 assert(element.isInstanceMember); |
| 360 if (element.type.containsTypeVariables) { | 364 if (element.type.containsTypeVariables) { |
| 361 applyImpact(_listener.registerClosureWithFreeTypeVariables(element)); | 365 applyImpact(listener.registerClosureWithFreeTypeVariables(element)); |
| 362 _universe.closuresWithFreeTypeVariables.add(element); | 366 _universe.closuresWithFreeTypeVariables.add(element); |
| 363 } | 367 } |
| 364 applyImpact(_listener.registerBoundClosure()); | 368 applyImpact(listener.registerBoundClosure()); |
| 365 _universe.closurizedMembers.add(element); | 369 _universe.closurizedMembers.add(element); |
| 366 } | 370 } |
| 367 | 371 |
| 368 void forEach(void f(WorkItem work)) { | 372 void forEach(void f(WorkItem work)) { |
| 369 do { | 373 do { |
| 370 while (_queue.isNotEmpty) { | 374 while (_queue.isNotEmpty) { |
| 371 // TODO(johnniwinther): Find an optimal process order. | 375 // TODO(johnniwinther): Find an optimal process order. |
| 372 WorkItem work = _queue.removeLast(); | 376 WorkItem work = _queue.removeLast(); |
| 373 if (!_processedEntities.contains(work.element)) { | 377 if (!_processedEntities.contains(work.element)) { |
| 374 strategy.processWorkItem(f, work); | 378 strategy.processWorkItem(f, work); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 void _addToWorkList(MemberEntity entity) { | 419 void _addToWorkList(MemberEntity entity) { |
| 416 if (hasBeenProcessed(entity)) return; | 420 if (hasBeenProcessed(entity)) return; |
| 417 WorkItem workItem = _workItemBuilder.createWorkItem(entity); | 421 WorkItem workItem = _workItemBuilder.createWorkItem(entity); |
| 418 if (workItem == null) return; | 422 if (workItem == null) return; |
| 419 | 423 |
| 420 if (queueIsClosed) { | 424 if (queueIsClosed) { |
| 421 throw new SpannableAssertionFailure( | 425 throw new SpannableAssertionFailure( |
| 422 entity, "Resolution work list is closed. Trying to add $entity."); | 426 entity, "Resolution work list is closed. Trying to add $entity."); |
| 423 } | 427 } |
| 424 | 428 |
| 425 applyImpact(_listener.registerUsedElement(entity)); | 429 applyImpact(listener.registerUsedElement(entity)); |
| 426 _universe.registerUsedElement(entity); | 430 _universe.registerUsedElement(entity); |
| 427 _queue.add(workItem); | 431 _queue.add(workItem); |
| 428 } | 432 } |
| 429 | 433 |
| 430 /// Adds an action to the deferred task queue. | 434 /// Adds an action to the deferred task queue. |
| 431 /// The action is performed the next time the resolution queue has been | 435 /// The action is performed the next time the resolution queue has been |
| 432 /// emptied. | 436 /// emptied. |
| 433 /// | 437 /// |
| 434 /// The queue is processed in FIFO order. | 438 /// The queue is processed in FIFO order. |
| 435 void addDeferredAction(Entity entity, void action()) { | 439 void addDeferredAction(Entity entity, void action()) { |
| 436 if (queueIsClosed) { | 440 if (queueIsClosed) { |
| 437 throw new SpannableAssertionFailure( | 441 throw new SpannableAssertionFailure( |
| 438 entity, | 442 entity, |
| 439 "Resolution work list is closed. " | 443 "Resolution work list is closed. " |
| 440 "Trying to add deferred action for $entity"); | 444 "Trying to add deferred action for $entity"); |
| 441 } | 445 } |
| 442 _deferredQueue.add(new _DeferredAction(entity, action)); | 446 _deferredQueue.add(new _DeferredAction(entity, action)); |
| 443 } | 447 } |
| 444 | 448 |
| 445 /// [_onQueueEmpty] is called whenever the queue is drained. [recentClasses] | 449 /// [_onQueueEmpty] is called whenever the queue is drained. [recentClasses] |
| 446 /// contains the set of all classes seen for the first time since | 450 /// contains the set of all classes seen for the first time since |
| 447 /// [_onQueueEmpty] was called last. A return value of [true] indicates that | 451 /// [_onQueueEmpty] was called last. A return value of [true] indicates that |
| 448 /// the [recentClasses] have been processed and may be cleared. If [false] is | 452 /// the [recentClasses] have been processed and may be cleared. If [false] is |
| 449 /// returned, [_onQueueEmpty] will be called once the queue is empty again (or | 453 /// returned, [_onQueueEmpty] will be called once the queue is empty again (or |
| 450 /// still empty) and [recentClasses] will be a superset of the current value. | 454 /// still empty) and [recentClasses] will be a superset of the current value. |
| 451 bool _onQueueEmpty(Iterable<ClassEntity> recentClasses) { | 455 bool _onQueueEmpty(Iterable<ClassEntity> recentClasses) { |
| 452 _emptyDeferredQueue(); | 456 _emptyDeferredQueue(); |
| 453 | 457 |
| 454 return _listener.onQueueEmpty(this, recentClasses); | 458 return listener.onQueueEmpty(this, recentClasses); |
| 455 } | 459 } |
| 456 | 460 |
| 457 void emptyDeferredQueueForTesting() => _emptyDeferredQueue(); | 461 void emptyDeferredQueueForTesting() => _emptyDeferredQueue(); |
| 458 | 462 |
| 459 void _emptyDeferredQueue() { | 463 void _emptyDeferredQueue() { |
| 460 while (!_deferredQueue.isEmpty) { | 464 while (!_deferredQueue.isEmpty) { |
| 461 _DeferredAction task = _deferredQueue.removeFirst(); | 465 _DeferredAction task = _deferredQueue.removeFirst(); |
| 462 _reporter.withCurrentElement(task.element, task.action); | 466 _reporter.withCurrentElement(task.element, task.action); |
| 463 } | 467 } |
| 464 } | 468 } |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 577 @override | 581 @override |
| 578 WorkItem createWorkItem(MemberElement element) { | 582 WorkItem createWorkItem(MemberElement element) { |
| 579 assert(invariant(element, element.isDeclaration)); | 583 assert(invariant(element, element.isDeclaration)); |
| 580 if (element.isMalformed) return null; | 584 if (element.isMalformed) return null; |
| 581 | 585 |
| 582 assert(invariant(element, element is AnalyzableElement, | 586 assert(invariant(element, element is AnalyzableElement, |
| 583 message: 'Element $element is not analyzable.')); | 587 message: 'Element $element is not analyzable.')); |
| 584 return _resolution.createWorkItem(element); | 588 return _resolution.createWorkItem(element); |
| 585 } | 589 } |
| 586 } | 590 } |
| OLD | NEW |