Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1228)

Unified Diff: pkg/analyzer/lib/src/task/driver.dart

Issue 1147853002: Properly handle circular references among constants in the task model. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/lib/src/task/driver.dart
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
index 0cff292ffcb488b8bf717696cca8e3526f4ffaa9..77e7cff07055a0a8ce1e619be12e9d2cbcaf0e7f 100644
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ b/pkg/analyzer/lib/src/task/driver.dart
@@ -149,7 +149,7 @@ class AnalysisDriver {
}
try {
TaskDescriptor taskDescriptor = taskManager.findTask(target, result);
- WorkItem workItem = new WorkItem(context, target, taskDescriptor);
+ WorkItem workItem = new WorkItem(context, target, taskDescriptor, result);
return new WorkOrder(taskManager, workItem);
} catch (exception, stackTrace) {
throw new AnalysisException(
@@ -352,6 +352,8 @@ abstract class CycleAwareDependencyWalker<Node> {
while (_currentIndices.isNotEmpty) {
Node nextUnevaluatedInput = getNextInput(_path[_currentIndices.last],
_provisionalDependencies[_currentIndices.last]);
+ assert(!_provisionalDependencies[_currentIndices.last]
+ .contains(nextUnevaluatedInput));
if (nextUnevaluatedInput != null) {
// TODO(paulberry): the call to _path.indexOf makes the algorithm
// O(n^2) in the depth of the dependency graph. If this becomes a
@@ -428,11 +430,19 @@ abstract class ExtendedAnalysisContext implements InternalAnalysisContext {
*/
class InfiniteTaskLoopException extends AnalysisException {
/**
- * Initialize a newly created exception to represent an attempt to perform
- * the task for the target represented by the given [item].
+ * If a dependency cycle was found while computing the inputs for the task,
+ * the set of [WorkItem]s contained in the cycle (if there are overlapping
+ * cycles, this is the set of all [WorkItem]s in the entire strongly
+ * connected component). Otherwise, `null`.
*/
- InfiniteTaskLoopException(WorkItem item) : super(
- 'Infinite loop while performing task ${item.descriptor.name} for ${item.target}');
+ final List<WorkItem> dependencyCycle;
+
+ /**
+ * Initialize a newly created exception to represent a failed attempt to
+ * perform the given [task] due to the given [dependencyCycle].
+ */
+ InfiniteTaskLoopException(AnalysisTask task, this.dependencyCycle) : super(
+ 'Infinite loop while performing task ${task.descriptor.name} for ${task.target}');
}
/**
@@ -456,6 +466,11 @@ class WorkItem {
final TaskDescriptor descriptor;
/**
+ * The [ResultDescriptor] which was led to this work item being spawned.
+ */
+ final ResultDescriptor spawningResult;
+
+ /**
* An iterator used to iterate over the descriptors of the inputs to the task,
* or `null` if all of the inputs have been collected and the task can be
* created.
@@ -482,10 +497,18 @@ class WorkItem {
CaughtException exception = null;
/**
+ * If a dependency cycle was found while computing the inputs for the task,
+ * the set of [WorkItem]s contained in the cycle (if there are overlapping
+ * cycles, this is the set of all [WorkItem]s in the entire strongly
+ * connected component). Otherwise, `null`.
+ */
+ List<WorkItem> dependencyCycle;
+
+ /**
* Initialize a newly created work item to compute the inputs for the task
* described by the given descriptor.
*/
- WorkItem(this.context, this.target, this.descriptor) {
+ WorkItem(this.context, this.target, this.descriptor, this.spawningResult) {
AnalysisTarget actualTarget = identical(
target, AnalysisContextTarget.request)
? new AnalysisContextTarget(context)
@@ -519,7 +542,9 @@ class WorkItem {
if (builder != null) {
throw new StateError("some inputs have not been computed");
}
- return descriptor.createTask(context, target, inputs);
+ AnalysisTask task = descriptor.createTask(context, target, inputs);
+ task.dependencyCycle = dependencyCycle;
+ return task;
}
/**
@@ -538,14 +563,19 @@ class WorkItem {
* if the field is non-`null` then the task cannot be performed and all of the
* tasks' results should be marked as being in ERROR.
*/
- WorkItem gatherInputs(TaskManager taskManager) {
+ WorkItem gatherInputs(TaskManager taskManager, List<WorkItem> skipInputs) {
while (builder != null) {
AnalysisTarget inputTarget = builder.currentTarget;
ResultDescriptor inputResult = builder.currentResult;
inputTargetedResults.add(new TargetedResult(inputTarget, inputResult));
CacheEntry inputEntry = context.getCacheEntry(inputTarget);
CacheState inputState = inputEntry.getState(inputResult);
- if (inputState == CacheState.ERROR) {
+ if (skipInputs.any((WorkItem item) =>
+ item.target == inputTarget && item.spawningResult == inputResult)) {
+ // This input is being skipped due to a circular dependency. Tell the
+ // builder that it's not available so we can move on to other inputs.
+ builder.currentValueNotAvailable();
+ } else if (inputState == CacheState.ERROR) {
exception = inputEntry.exception;
return null;
} else if (inputState == CacheState.IN_PROCESS) {
@@ -560,17 +590,19 @@ class WorkItem {
// IN_PROCESS is CONTENT, I don't know that it's worth the extra effort
// to implement the general solution at this point.
//
+ throw new UnimplementedError();
} else if (inputState != CacheState.VALID) {
try {
TaskDescriptor descriptor =
taskManager.findTask(inputTarget, inputResult);
- return new WorkItem(context, inputTarget, descriptor);
+ return new WorkItem(context, inputTarget, descriptor, inputResult);
} on AnalysisException catch (exception, stackTrace) {
this.exception = new CaughtException(exception, stackTrace);
return null;
}
+ } else {
+ builder.currentValue = inputEntry.getValue(inputResult);
}
- builder.currentValue = inputEntry.getValue(inputResult);
if (!builder.moveNext()) {
inputs = builder.inputValue;
builder = null;
@@ -584,31 +616,6 @@ class WorkItem {
}
/**
- * The priorities of work orders returned by [WorkManager]s.
- */
-enum WorkOrderPriority {
- /**
- * Responding to an user's action.
- */
- INTERACTIVE,
-
- /**
- * Computing information for priority sources.
- */
- PRIORITY,
-
- /**
- * A work should be done, but without any special urgency.
- */
- NORMAL,
-
- /**
- * Nothing to do.
- */
- NONE
-}
-
-/**
* [AnalysisDriver] uses [WorkManager]s to select results to compute.
*
* They know specific of the targets and results they care about,
@@ -695,11 +702,7 @@ class WorkOrder implements Iterator<WorkItem> {
if (currentItems.length > 1) {
// A cycle has been found.
for (WorkItem item in currentItems) {
- try {
- throw new InfiniteTaskLoopException(item);
- } on InfiniteTaskLoopException catch (exception, stackTrace) {
- item.exception = new CaughtException(exception, stackTrace);
- }
+ item.dependencyCycle = currentItems.toList();
}
} else {
assert(currentItems.length == 1);
@@ -710,6 +713,31 @@ class WorkOrder implements Iterator<WorkItem> {
}
/**
+ * The priorities of work orders returned by [WorkManager]s.
+ */
+enum WorkOrderPriority {
+ /**
+ * Responding to an user's action.
+ */
+ INTERACTIVE,
+
+ /**
+ * Computing information for priority sources.
+ */
+ PRIORITY,
+
+ /**
+ * A work should be done, but without any special urgency.
+ */
+ NORMAL,
+
+ /**
+ * Nothing to do.
+ */
+ NONE
+}
+
+/**
* Specilaization of [CycleAwareDependencyWalker] for use by [WorkOrder].
*/
class _WorkOrderDependencyWalker extends CycleAwareDependencyWalker<WorkItem> {
@@ -723,11 +751,6 @@ class _WorkOrderDependencyWalker extends CycleAwareDependencyWalker<WorkItem> {
@override
WorkItem getNextInput(WorkItem node, List<WorkItem> skipInputs) {
- if (skipInputs.isNotEmpty) {
- // TODO(paulberry): this is a hack. We assume that an analysis loop has
- // been found, so we don't try to compute anything else.
- return null;
- }
- return node.gatherInputs(taskManager);
+ return node.gatherInputs(taskManager, skipInputs);
}
}

Powered by Google App Engine
This is Rietveld 408576698