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

Side by Side Diff: sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart

Issue 14685002: Backjump on a source or description mismatch. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 /// A back-tracking depth-first solver. Attempts to find the best solution for 5 /// A back-tracking depth-first solver. Attempts to find the best solution for
6 /// a root package's transitive dependency graph, where a "solution" is a set 6 /// a root package's transitive dependency graph, where a "solution" is a set
7 /// of concrete package versions. A valid solution will select concrete 7 /// of concrete package versions. A valid solution will select concrete
8 /// versions for every package reached from the root package's dependency graph, 8 /// versions for every package reached from the root package's dependency graph,
9 /// and each of those packages will fit the version constraints placed on it. 9 /// and each of those packages will fit the version constraints placed on it.
10 /// 10 ///
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 /// solution to try. If possible, it will backjump based on the cause of the 186 /// solution to try. If possible, it will backjump based on the cause of the
187 /// [failure] to minize backtracking. Otherwise, it will simply backtrack to 187 /// [failure] to minize backtracking. Otherwise, it will simply backtrack to
188 /// the next possible solution. 188 /// the next possible solution.
189 /// 189 ///
190 /// Returns `true` if there is a new solution to try. 190 /// Returns `true` if there is a new solution to try.
191 bool _backtrack(SolveFailure failure) { 191 bool _backtrack(SolveFailure failure) {
192 var dependers = failure.dependencies.map((dep) => dep.depender).toSet(); 192 var dependers = failure.dependencies.map((dep) => dep.depender).toSet();
193 193
194 while (!_selected.isEmpty) { 194 while (!_selected.isEmpty) {
195 // Look for a relevant selection to jump back to. 195 // Look for a relevant selection to jump back to.
196 for (var i = _selected.length - 1; i >= 0; i--) { 196 if (failure.mayHaveTransitiveCause) {
nweiz 2013/04/30 22:00:29 I don't understand this distinction. Why can't sou
Bob Nystrom 2013/05/01 01:06:15 After putting on my thinking cap, I've got a clean
197 // Can't jump to a package that has no more alternatives. 197 _backjumpToDependency(failure.package);
198 if (_selected[i].length == 1) continue; 198 } else {
199 199 _backjumpToPackage(failure.dependencies);
200 var selected = _selected[i].first;
201
202 // If we find the package itself that failed, jump to it.
203 if (selected.name == failure.package) {
204 logSolve('jump to selected package ${failure.package}');
205 _selected.removeRange(i + 1, _selected.length);
206 break;
207 }
208
209 // See if this package directly or indirectly depends on [package].
210 var path = _getDependencyPath(selected, failure.package);
211 if (path != null) {
212 logSolve('backjump to ${selected.name} because it depends on '
213 '${failure.package} by $path');
214 _selected.removeRange(i + 1, _selected.length);
215 break;
216 }
217 } 200 }
218 201
219 // Advance past the current version of the leaf-most package. 202 // Advance past the current version of the leaf-most package.
220 var previous = _selected.last.removeFirst(); 203 var previous = _selected.last.removeFirst();
221 if (!_selected.last.isEmpty) { 204 if (!_selected.last.isEmpty) {
222 logSolve(); 205 logSolve();
223 return true; 206 return true;
224 } 207 }
225 208
226 logSolve('$previous is last version, backtracking'); 209 logSolve('$previous is last version, backtracking');
227 210
228 // That package has no more versions, so pop it and try the next one. 211 // That package has no more versions, so pop it and try the next one.
229 _selected.removeLast(); 212 _selected.removeLast();
230 } 213 }
231 214
232 return false; 215 return false;
233 } 216 }
234 217
218 /// Backjumps to the most recently selected package in [dependencies]. Does
219 /// not consider dependent or related packages. This is used for failures
220 /// like [SourceMismatchException] where one of the packages explicitly in
221 /// that list is known to be a direct cause of the failure.
222 void _backjumpToPackage(Iterable<Dependency> dependencies) {
223 for (var i = _selected.length - 1; i >= 0; i--) {
224 var selected = _selected[i].first;
225
226 for (var dep in dependencies) {
227 if (selected.name == dep.dep.name) {
228 logSolve('backjump to ${selected.name} because it caused conflict');
229 _selected.removeRange(i + 1, _selected.length);
230 return;
231 }
232 }
233 }
234 }
235
236 /// Backjumps to the most recently selected package that directly or
237 /// indirectly depends on [package]. This is used for failures like
238 /// [NoVersionException] where we failed to find a version for [package] and
239 /// any package along the dependency graph leading to it could have caused
240 /// that failure.
241 void _backjumpToDependency(String package) {
242 for (var i = _selected.length - 1; i >= 0; i--) {
243 // Can't jump to a package that has no more alternatives.
244 if (_selected[i].length == 1) continue;
245
246 var selected = _selected[i].first;
247
248 // See if this package directly or indirectly depends on [package].
249 var path = _getDependencyPath(selected, package);
250 if (path != null) {
251 logSolve('backjump to ${selected.name} because it depends on '
252 '${package} by $path');
nweiz 2013/04/30 22:00:29 indentation
Bob Nystrom 2013/05/01 01:06:15 Done.
253 _selected.removeRange(i + 1, _selected.length);
254 return;
255 }
256 }
257 }
258
235 /// Determines if [depender] has a direct or indirect dependency on 259 /// Determines if [depender] has a direct or indirect dependency on
236 /// [dependent] based on the currently selected versions of all packages. 260 /// [dependent] based on the currently selected versions of all packages.
237 /// Returns a string describing the dependency chain if it does, or `null` if 261 /// Returns a string describing the dependency chain if it does, or `null` if
238 /// there is no dependency. 262 /// there is no dependency.
239 String _getDependencyPath(PackageId depender, String dependent) { 263 String _getDependencyPath(PackageId depender, String dependent) {
240 // TODO(rnystrom): This is O(n^2) where n is the number of selected 264 // TODO(rnystrom): This is O(n^2) where n is the number of selected
241 // packages. Could store the reverse dependency graph to address that. If 265 // packages. Could store the reverse dependency graph to address that. If
242 // we do that, we need to make sure it gets correctly rolled back when 266 // we do that, we need to make sure it gets correctly rolled back when
243 // backtracking occurs. 267 // backtracking occurs.
244 var visited = new Set<String>(); 268 var visited = new Set<String>();
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after
592 // know what they're doing. 616 // know what they're doing.
593 if (sdk.isBleedingEdge) return; 617 if (sdk.isBleedingEdge) return;
594 618
595 if (pubspec.environment.sdkVersion.allows(sdk.version)) return; 619 if (pubspec.environment.sdkVersion.allows(sdk.version)) return;
596 620
597 throw new CouldNotSolveException( 621 throw new CouldNotSolveException(
598 'Package ${pubspec.name} requires SDK version ' 622 'Package ${pubspec.name} requires SDK version '
599 '${pubspec.environment.sdkVersion} but the current SDK is ' 623 '${pubspec.environment.sdkVersion} but the current SDK is '
600 '${sdk.version}.'); 624 '${sdk.version}.');
601 } 625 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698