Index: sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart |
diff --git a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart |
index c5580a901ed1204142842aef2aa577a07c13b84b..37533c11bd4f83d4cf7966184da989fe16e6a598 100644 |
--- a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart |
+++ b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart |
@@ -192,29 +192,7 @@ class BacktrackingSolver { |
var dependers = failure.dependencies.map((dep) => dep.depender).toSet(); |
while (!_selected.isEmpty) { |
- // Look for a relevant selection to jump back to. |
- for (var i = _selected.length - 1; i >= 0; i--) { |
- // Can't jump to a package that has no more alternatives. |
- if (_selected[i].length == 1) continue; |
- |
- var selected = _selected[i].first; |
- |
- // If we find the package itself that failed, jump to it. |
- if (selected.name == failure.package) { |
- logSolve('jump to selected package ${failure.package}'); |
- _selected.removeRange(i + 1, _selected.length); |
- break; |
- } |
- |
- // See if this package directly or indirectly depends on [package]. |
- var path = _getDependencyPath(selected, failure.package); |
- if (path != null) { |
- logSolve('backjump to ${selected.name} because it depends on ' |
- '${failure.package} by $path'); |
- _selected.removeRange(i + 1, _selected.length); |
- break; |
- } |
- } |
+ _backjump(failure); |
// Advance past the current version of the leaf-most package. |
var previous = _selected.last.removeFirst(); |
@@ -232,6 +210,44 @@ class BacktrackingSolver { |
return false; |
} |
+ /// Walks the selected packages from most to least recent to determine which |
+ /// ones can be ignored and jumped over by the backtracker. The only packages |
+ /// we need to backtrack to are ones that have other versions to try and that |
+ /// led (possibly indirectly) to the failure. Everything else can be skipped. |
+ void _backjump(SolveFailure failure) { |
+ for (var i = _selected.length - 1; i >= 0; i--) { |
+ // Each queue will never be empty since it gets discarded by _backtrack() |
+ // when that happens. |
+ var selected = _selected[i].first; |
+ |
+ // If the package has no more versions, we can jump over it. |
+ if (_selected[i].length == 1) continue; |
+ |
+ // If we get to the package that failed, backtrack to here. |
+ if (selected.name == failure.package) { |
+ logSolve('backjump to failed package ${selected.name}'); |
+ _selected.removeRange(i + 1, _selected.length); |
+ return; |
+ } |
+ |
+ // If we get to a package that depends on the failing package, backtrack |
+ // to here. |
+ var path = _getDependencyPath(selected, failure.package); |
+ if (path != null) { |
+ logSolve('backjump to ${selected.name} because it depends on ' |
+ '${failure.package} along $path'); |
+ _selected.removeRange(i + 1, _selected.length); |
+ return; |
+ } |
+ } |
+ |
+ // If we got here, we walked the entire list without finding a package that |
+ // could lead to another solution, so discard everything. This will happen |
+ // if every package that led to the failure has no other versions that it |
+ // can try to select. |
+ _selected.removeRange(1, _selected.length); |
+ } |
+ |
/// Determines if [depender] has a direct or indirect dependency on |
/// [dependent] based on the currently selected versions of all packages. |
/// Returns a string describing the dependency chain if it does, or `null` if |
@@ -594,7 +610,7 @@ void _validateSdkConstraint(Pubspec pubspec) { |
if (pubspec.environment.sdkVersion.allows(sdk.version)) return; |
- throw new CouldNotSolveException( |
+ throw new BadSdkVersionException(pubspec.name, |
'Package ${pubspec.name} requires SDK version ' |
'${pubspec.environment.sdkVersion} but the current SDK is ' |
'${sdk.version}.'); |