Index: lucene/memory/src/test/org/apache/lucene/index/memory/MemoryIndexTest.java
===================================================================
--- lucene/memory/src/test/org/apache/lucene/index/memory/MemoryIndexTest.java	(revision 1467310)
+++ lucene/memory/src/test/org/apache/lucene/index/memory/MemoryIndexTest.java	(working copy)
@@ -323,7 +323,7 @@
     AtomicReader reader = (AtomicReader) memory.createSearcher().getIndexReader();
     DocsEnum disi = _TestUtil.docs(random(), reader, "foo", new BytesRef("bar"), null, null, DocsEnum.FLAG_NONE);
     int docid = disi.docID();
-    assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+    assertEquals(-1, docid);
     assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
     
     // now reuse and check again
@@ -331,7 +331,7 @@
     assertTrue(te.seekExact(new BytesRef("bar"), true));
     disi = te.docs(null, disi, DocsEnum.FLAG_NONE);
     docid = disi.docID();
-    assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+    assertEquals(-1, docid);
     assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
     reader.close();
   }
@@ -354,7 +354,7 @@
       assertEquals(1, reader.terms("foo").getSumTotalTermFreq());
       DocsAndPositionsEnum disi = reader.termPositionsEnum(new Term("foo", "bar"));
       int docid = disi.docID();
-      assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+      assertEquals(-1, docid);
       assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
       assertEquals(0, disi.nextPosition());
       assertEquals(0, disi.startOffset());
@@ -365,7 +365,7 @@
       assertTrue(te.seekExact(new BytesRef("bar"), true));
       disi = te.docsAndPositions(null, disi);
       docid = disi.docID();
-      assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+      assertEquals(-1, docid);
       assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
       reader.close();
       memory.reset();
Index: lucene/CHANGES.txt
===================================================================
--- lucene/CHANGES.txt	(revision 1467310)
+++ lucene/CHANGES.txt	(working copy)
@@ -19,6 +19,9 @@
   (Nikola Tanković, Uwe Schindler, Chris Male, Mike McCandless,
   Robert Muir)
 
+* LUCENE-4924: Sub-classes of DocIdSetIterator must now return -1 when the
+  iterator is not positioned. (Adrien Grand)
+
 New Features
 
 * LUCENE-4747: Move to Java 7 as minimum Java version.
Index: lucene/test-framework/src/java/org/apache/lucene/index/BasePostingsFormatTestCase.java
===================================================================
--- lucene/test-framework/src/java/org/apache/lucene/index/BasePostingsFormatTestCase.java	(revision 1467310)
+++ lucene/test-framework/src/java/org/apache/lucene/index/BasePostingsFormatTestCase.java	(working copy)
@@ -699,7 +699,7 @@
 
     assertNotNull("null DocsEnum", docsEnum);
     int initialDocID = docsEnum.docID();
-    assertTrue("inital docID should be -1 or NO_MORE_DOCS: " + docsEnum, initialDocID == -1 || initialDocID == DocsEnum.NO_MORE_DOCS);
+    assertEquals("inital docID should be -1" + docsEnum, -1, initialDocID);
 
     if (VERBOSE) {
       if (prevDocsEnum == null) {
Index: lucene/test-framework/src/java/org/apache/lucene/index/AssertingAtomicReader.java
===================================================================
--- lucene/test-framework/src/java/org/apache/lucene/index/AssertingAtomicReader.java	(revision 1467310)
+++ lucene/test-framework/src/java/org/apache/lucene/index/AssertingAtomicReader.java	(working copy)
@@ -237,7 +237,7 @@
       super(in);
       try {
         int docid = in.docID();
-        assert docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS : in.getClass() + ": invalid initial doc id: " + docid;
+        assert docid == -1 : in.getClass() + ": invalid initial doc id: " + docid;
       } catch (UnsupportedOperationException e) {
         if (failOnUnsupportedDocID) {
           throw e;
@@ -256,7 +256,7 @@
       } else {
         state = DocsEnumState.ITERATING;
       }
-      assert docID() == nextDoc;
+      assert super.docID() == nextDoc;
       return doc = nextDoc;
     }
 
@@ -271,13 +271,15 @@
       } else {
         state = DocsEnumState.ITERATING;
       }
-      assert docID() == advanced;
+      assert super.docID() == advanced;
       return doc = advanced;
     }
 
-    // NOTE: We don't assert anything for docId(). Specifically DocsEnum javadocs
-    // are ambiguous with DocIdSetIterator here, DocIdSetIterator says its ok
-    // to call this method before nextDoc(), just that it must be -1 or NO_MORE_DOCS!
+    @Override
+    public int docID() {
+      assert doc == super.docID() : " invalid docID() in " + in.getClass() + " " + super.docID() + " instead of " + doc;
+      return doc;
+    }
 
     @Override
     public int freq() throws IOException {
@@ -298,7 +300,7 @@
     public AssertingDocsAndPositionsEnum(DocsAndPositionsEnum in) {
       super(in);
       int docid = in.docID();
-      assert docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS : "invalid initial doc id: " + docid;
+      assert docid == -1 : "invalid initial doc id: " + docid;
       doc = -1;
     }
 
@@ -315,7 +317,7 @@
         state = DocsEnumState.ITERATING;
         positionMax = super.freq();
       }
-      assert docID() == nextDoc;
+      assert super.docID() == nextDoc;
       return doc = nextDoc;
     }
 
@@ -333,11 +335,17 @@
         state = DocsEnumState.ITERATING;
         positionMax = super.freq();
       }
-      assert docID() == advanced;
+      assert super.docID() == advanced;
       return doc = advanced;
     }
 
     @Override
+    public int docID() {
+      assert doc == super.docID() : " invalid docID() in " + in.getClass() + " " + super.docID() + " instead of " + doc;
+      return doc;
+    }
+
+    @Override
     public int freq() throws IOException {
       assert state != DocsEnumState.START : "freq() called before nextDoc()/advance()";
       assert state != DocsEnumState.FINISHED : "freq() called after NO_MORE_DOCS";
Index: lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
===================================================================
--- lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java	(revision 1467310)
+++ lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java	(working copy)
@@ -1534,8 +1534,8 @@
       assertNull(rightDocs);
       return;
     }
-    assertTrue(info, leftDocs.docID() == -1 || leftDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
-    assertTrue(info, rightDocs.docID() == -1 || rightDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
+    assertEquals(info, -1, leftDocs.docID());
+    assertEquals(info, -1, rightDocs.docID());
     int docid;
     while ((docid = leftDocs.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
       assertEquals(info, docid, rightDocs.nextDoc());
@@ -1559,8 +1559,8 @@
       assertNull(rightDocs);
       return;
     }
-    assertTrue(info, leftDocs.docID() == -1 || leftDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
-    assertTrue(info, rightDocs.docID() == -1 || rightDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
+    assertEquals(info, -1, leftDocs.docID());
+    assertEquals(info, -1, rightDocs.docID());
     int docid;
     while ((docid = leftDocs.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
       assertEquals(info, docid, rightDocs.nextDoc());
Index: lucene/core/src/test/org/apache/lucene/codecs/lucene41/TestBlockPostingsFormat3.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/codecs/lucene41/TestBlockPostingsFormat3.java	(revision 1467310)
+++ lucene/core/src/test/org/apache/lucene/codecs/lucene41/TestBlockPostingsFormat3.java	(working copy)
@@ -394,8 +394,8 @@
       assertNull(rightDocs);
       return;
     }
-    assertTrue(leftDocs.docID() == -1 || leftDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
-    assertTrue(rightDocs.docID() == -1 || rightDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
+    assertEquals(-1, leftDocs.docID());
+    assertEquals(-1, rightDocs.docID());
     int docid;
     while ((docid = leftDocs.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
       assertEquals(docid, rightDocs.nextDoc());
@@ -417,8 +417,8 @@
       assertNull(rightDocs);
       return;
     }
-    assertTrue(leftDocs.docID() == -1 || leftDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
-    assertTrue(rightDocs.docID() == -1 || rightDocs.docID() == DocIdSetIterator.NO_MORE_DOCS);
+    assertEquals(-1, leftDocs.docID());
+    assertEquals(-1, rightDocs.docID());
     int docid;
     while ((docid = leftDocs.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
       assertEquals(docid, rightDocs.nextDoc());
Index: lucene/core/src/test/org/apache/lucene/index/TestTermVectorsReader.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/index/TestTermVectorsReader.java	(revision 1467310)
+++ lucene/core/src/test/org/apache/lucene/index/TestTermVectorsReader.java	(working copy)
@@ -229,7 +229,7 @@
         docsEnum = _TestUtil.docs(random(), termsEnum, null, docsEnum, DocsEnum.FLAG_NONE);
         assertNotNull(docsEnum);
         int doc = docsEnum.docID();
-        assertTrue(doc == -1 || doc == DocIdSetIterator.NO_MORE_DOCS);
+        assertEquals(-1, doc);
         assertTrue(docsEnum.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
         assertEquals(DocIdSetIterator.NO_MORE_DOCS, docsEnum.nextDoc());
       }
@@ -256,7 +256,7 @@
       dpEnum = termsEnum.docsAndPositions(null, dpEnum);
       assertNotNull(dpEnum);
       int doc = dpEnum.docID();
-      assertTrue(doc == -1 || doc == DocIdSetIterator.NO_MORE_DOCS);
+      assertEquals(-1, doc);
       assertTrue(dpEnum.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
       assertEquals(dpEnum.freq(), positions[i].length);
       for (int j = 0; j < positions[i].length; j++) {
@@ -266,7 +266,7 @@
 
       dpEnum = termsEnum.docsAndPositions(null, dpEnum);
       doc = dpEnum.docID();
-      assertTrue(doc == -1 || doc == DocIdSetIterator.NO_MORE_DOCS);
+      assertEquals(-1, doc);
       assertTrue(dpEnum.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
       assertNotNull(dpEnum);
       assertEquals(dpEnum.freq(), positions[i].length);
Index: lucene/core/src/test/org/apache/lucene/index/TestDocsAndPositions.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/index/TestDocsAndPositions.java	(revision 1467310)
+++ lucene/core/src/test/org/apache/lucene/index/TestDocsAndPositions.java	(working copy)
@@ -336,7 +336,7 @@
     AtomicReader r = getOnlySegmentReader(reader);
     DocsEnum disi = _TestUtil.docs(random(), r, "foo", new BytesRef("bar"), null, null, DocsEnum.FLAG_NONE);
     int docid = disi.docID();
-    assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+    assertEquals(-1, docid);
     assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
     
     // now reuse and check again
@@ -344,7 +344,7 @@
     assertTrue(te.seekExact(new BytesRef("bar"), true));
     disi = _TestUtil.docs(random(), te, null, disi, DocsEnum.FLAG_NONE);
     docid = disi.docID();
-    assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+    assertEquals(-1, docid);
     assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
     writer.close();
     r.close();
@@ -361,7 +361,7 @@
     AtomicReader r = getOnlySegmentReader(reader);
     DocsAndPositionsEnum disi = r.termPositionsEnum(new Term("foo", "bar"));
     int docid = disi.docID();
-    assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+    assertEquals(-1, docid);
     assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
     
     // now reuse and check again
@@ -369,7 +369,7 @@
     assertTrue(te.seekExact(new BytesRef("bar"), true));
     disi = te.docsAndPositions(null, disi);
     docid = disi.docID();
-    assertTrue(docid == -1 || docid == DocIdSetIterator.NO_MORE_DOCS);
+    assertEquals(-1, docid);
     assertTrue(disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS);
     writer.close();
     r.close();
Index: lucene/core/src/java/org/apache/lucene/search/Scorer.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/search/Scorer.java	(revision 1467310)
+++ lucene/core/src/java/org/apache/lucene/search/Scorer.java	(working copy)
@@ -58,7 +58,7 @@
    * @param collector The collector to which all matching documents are passed.
    */
   public void score(Collector collector) throws IOException {
-    assert docID() == -1 || docID() == NO_MORE_DOCS; // not started
+    assert docID() == -1; // not started
     collector.setScorer(this);
     int doc;
     while ((doc = nextDoc()) != NO_MORE_DOCS) {
Index: lucene/core/src/java/org/apache/lucene/search/DocIdSet.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/search/DocIdSet.java	(revision 1467310)
+++ lucene/core/src/java/org/apache/lucene/search/DocIdSet.java	(working copy)
@@ -29,20 +29,36 @@
   /** An empty {@code DocIdSet} instance for easy use, e.g. in Filters that hit no documents. */
   public static final DocIdSet EMPTY_DOCIDSET = new DocIdSet() {
     
-    private final DocIdSetIterator iterator = new DocIdSetIterator() {
-      @Override
-      public int advance(int target) { return NO_MORE_DOCS; }
-      @Override
-      public int docID() { return NO_MORE_DOCS; }
-      @Override
-      public int nextDoc() { return NO_MORE_DOCS; }
-      @Override
-      public long cost() { return 0; }
-    };
-    
     @Override
     public DocIdSetIterator iterator() {
-      return iterator;
+      return new DocIdSetIterator() {
+        boolean exhausted = false;
+
+        @Override
+        public int advance(int target) {
+          assert !exhausted;
+          assert target >= 0;
+          exhausted = true;
+          return NO_MORE_DOCS;
+        }
+
+        @Override
+        public int docID() {
+          return exhausted ? NO_MORE_DOCS : -1;
+        }
+
+        @Override
+        public int nextDoc() {
+          assert !exhausted;
+          exhausted = true;
+          return NO_MORE_DOCS;
+        }
+
+        @Override
+        public long cost() {
+          return 0;
+        }
+      };
     }
     
     @Override
@@ -56,7 +72,7 @@
       return null;
     }
   };
-    
+
   /** Provides a {@link DocIdSetIterator} to access the set.
    * This implementation can return <code>null</code> or
    * <code>{@linkplain #EMPTY_DOCIDSET}.iterator()</code> if there
Index: lucene/core/src/java/org/apache/lucene/search/spans/SpanScorer.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/search/spans/SpanScorer.java	(revision 1467310)
+++ lucene/core/src/java/org/apache/lucene/search/spans/SpanScorer.java	(working copy)
@@ -42,12 +42,8 @@
     this.docScorer = docScorer;
     this.spans = spans;
 
-    if (this.spans.next()) {
-      doc = -1;
-    } else {
-      doc = NO_MORE_DOCS;
-      more = false;
-    }
+    doc = -1;
+    more = spans.next();
   }
 
   @Override
Index: lucene/core/src/java/org/apache/lucene/search/DocIdSetIterator.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/search/DocIdSetIterator.java	(revision 1467310)
+++ lucene/core/src/java/org/apache/lucene/search/DocIdSetIterator.java	(working copy)
@@ -37,7 +37,7 @@
   /**
    * Returns the following:
    * <ul>
-   * <li>-1 or {@link #NO_MORE_DOCS} if {@link #nextDoc()} or
+   * <li><code>-1</code> if {@link #nextDoc()} or
    * {@link #advance(int)} were not called yet.
    * <li>{@link #NO_MORE_DOCS} if the iterator has exhausted.
    * <li>Otherwise it should return the doc ID it is currently on.
@@ -96,8 +96,7 @@
   /** Slow (linear) implementation of {@link #advance} relying on
    *  {@link #nextDoc()} to advance beyond the target position. */
   protected final int slowAdvance(int target) throws IOException {
-    assert docID() == NO_MORE_DOCS // can happen when the enum is not positioned yet
-        || docID() < target;
+    assert docID() < target;
     int doc;
     do {
       doc = nextDoc();
Index: lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java
===================================================================
--- lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java	(revision 1467310)
+++ lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java	(working copy)
@@ -193,29 +193,22 @@
     DocsEnum docsEnum;
     DocsEnum reuse;
     int scoreUpto;
+    int doc;
 
     SVInnerScorer(Weight weight, Bits acceptDocs, TermsEnum termsEnum, long cost) {
       super(weight);
       this.acceptDocs = acceptDocs;
       this.termsEnum = termsEnum;
       this.cost = cost;
+      this.doc = -1;
     }
 
     @Override
     public void score(Collector collector) throws IOException {
-      score(collector, NO_MORE_DOCS, nextDocOutOfOrder());
-    }
-
-    @Override
-    public boolean score(Collector collector, int max, int firstDocID)
-        throws IOException {
-      assert collector.acceptsDocsOutOfOrder();
       collector.setScorer(this);
-      int doc;
-      for (doc = firstDocID; doc < max; doc = nextDocOutOfOrder()) {
+      for (int doc = nextDocOutOfOrder(); doc != NO_MORE_DOCS; doc = nextDocOutOfOrder()) {
         collector.collect(doc);
       }
-      return doc != NO_MORE_DOCS;
     }
 
     @Override
@@ -229,7 +222,7 @@
 
     @Override
     public int docID() {
-      return docsEnum != null ? docsEnum.docID() : DocIdSetIterator.NO_MORE_DOCS;
+      return doc;
     }
 
     int nextDocOutOfOrder() throws IOException {
@@ -238,13 +231,13 @@
         if (docId == DocIdSetIterator.NO_MORE_DOCS) {
           docsEnum = null;
         } else {
-          return docId;
+          return doc = docId;
         }
       }
 
       do {
         if (upto == terms.size()) {
-          return DocIdSetIterator.NO_MORE_DOCS;
+          return doc = DocIdSetIterator.NO_MORE_DOCS;
         }
 
         scoreUpto = upto;
@@ -253,7 +246,7 @@
         }
       } while (docsEnum == null);
 
-      return docsEnum.nextDoc();
+      return doc = docsEnum.nextDoc();
     }
 
     @Override
