Produce better output when a locked version is the only version

We used to produce weird output like "Because no versions of foo match
<1.0.0 or >1.0.0 and foo 1.0.0 depends on bar, all versions of foo
require bar". Now we're able to just say "all versions of foo depend
on bar" without having to derive that.
diff --git a/lib/src/solver/package_lister.dart b/lib/src/solver/package_lister.dart
index 0ee7a92..90c0158 100644
--- a/lib/src/solver/package_lister.dart
+++ b/lib/src/solver/package_lister.dart
@@ -233,7 +233,10 @@
     }
 
     var versions = await _versions;
-    var index = indexWhere(versions, (other) => identical(id, other));
+    var index = lowerBound(versions, id,
+        compare: (id1, id2) => id1.version.compareTo(id2.version));
+    assert(index < versions.length);
+    assert(versions[index].version == id.version);
 
     var dartSdkIncompatibility = await _checkSdkConstraint(index);
     if (dartSdkIncompatibility != null) return [dartSdkIncompatibility];
diff --git a/lib/src/solver/version_solver.dart b/lib/src/solver/version_solver.dart
index 42775ab..3327329 100644
--- a/lib/src/solver/version_solver.dart
+++ b/lib/src/solver/version_solver.dart
@@ -388,11 +388,20 @@
     }
 
     if (version == null) {
-      // If there are no versions that satisfy [package.constraint], add an
-      // incompatibility that indicates that.
-      _addIncompatibility(new Incompatibility(
-          [new Term(package, true)], IncompatibilityCause.noVersions));
-      return package.name;
+      // If the constraint excludes only a single version, it must have come
+      // from the inverse of a lockfile's dependency. In that case, we request
+      // any version instead so that the lister gives us more general
+      // incompatibilities. This makes error reporting much nicer.
+      if (_excludesSingleVersion(package.constraint)) {
+        version =
+            await _packageLister(package).bestVersion(VersionConstraint.any);
+      } else {
+        // If there are no versions that satisfy [package.constraint], add an
+        // incompatibility that indicates that.
+        _addIncompatibility(new Incompatibility(
+            [new Term(package, true)], IncompatibilityCause.noVersions));
+        return package.name;
+      }
     }
 
     var conflict = false;
@@ -428,6 +437,10 @@
     }
   }
 
+  /// Returns whether [constraint] allows all versions except one.
+  bool _excludesSingleVersion(VersionConstraint constraint) =>
+      VersionConstraint.any.difference(constraint) is Version;
+
   /// Creates a [SolveResult] from the decisions in [_solution].
   Future<SolveResult> _result() async {
     var decisions = _solution.decisions.toList();
diff --git a/test/version_solver_test.dart b/test/version_solver_test.dart
index 30be6da..1d1bb69 100644
--- a/test/version_solver_test.dart
+++ b/test/version_solver_test.dart
@@ -202,6 +202,27 @@
       'newdep': '2.0.0'
     }, tries: 2);
   });
+
+  // Issue 1853
+  test(
+      "produces a nice message for a locked dependency that's the only "
+      "version of its package", () async {
+    await servePackages((builder) {
+      builder.serve('foo', '1.0.0', deps: {'bar': '>=2.0.0'});
+      builder.serve('bar', '1.0.0');
+      builder.serve('bar', '2.0.0');
+    });
+
+    await d.appDir({'foo': 'any'}).create();
+    await expectResolves(result: {'foo': '1.0.0', 'bar': '2.0.0'});
+
+    await d.appDir({'foo': 'any', 'bar': '<2.0.0'}).create();
+    await expectResolves(error: equalsIgnoringWhitespace('''
+      Because every version of foo depends on bar >=2.0.0 and myapp depends on
+        bar <2.0.0, foo is forbidden.
+      So, because myapp depends on foo any, version solving failed.
+    '''));
+  });
 }
 
 void rootDependency() {