make And() propagate MatchMayChangeInTheFuture()
- considers both Match() cases and considers the appropriate matcher(s) in making decision
- also added a comment to WithTransform.MatchMayChangeInTheFuture(), as it will not have correct behavior with non-deterministic transformer
diff --git a/matchers/and.go b/matchers/and.go
index 5092463..9acf470 100644
--- a/matchers/and.go
+++ b/matchers/and.go
@@ -3,6 +3,7 @@
 import (
 	"fmt"
 	"github.com/onsi/gomega/format"
+	"github.com/onsi/gomega/internal/asyncassertion"
 	"github.com/onsi/gomega/types"
 )
 
@@ -10,25 +11,53 @@
 	Matchers []types.GomegaMatcher
 
 	// state
-	firstFailedMatchErrMsg string
+	firstFailedMatcher types.GomegaMatcher
 }
 
 func (m *AndMatcher) Match(actual interface{}) (success bool, err error) {
+	m.firstFailedMatcher = nil
 	for _, matcher := range m.Matchers {
 		success, err := matcher.Match(actual)
 		if !success || err != nil {
-			m.firstFailedMatchErrMsg = matcher.FailureMessage(actual)
+			m.firstFailedMatcher = matcher
 			return false, err
 		}
 	}
 	return true, nil
 }
 
-func (m *AndMatcher) FailureMessage(_ interface{}) (message string) {
-	return m.firstFailedMatchErrMsg
+func (m *AndMatcher) FailureMessage(actual interface{}) (message string) {
+	return m.firstFailedMatcher.FailureMessage(actual)
 }
 
 func (m *AndMatcher) NegatedFailureMessage(actual interface{}) (message string) {
 	// not the most beautiful list of matchers, but not bad either...
 	return format.Message(actual, fmt.Sprintf("To not satisfy all of these matchers: %s", m.Matchers))
 }
+
+func (m *AndMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
+	/*
+		Example with 3 matchers: A, B, C
+
+		Match evaluates them: T, F, <?>  => F
+		So match is currently F, what should MatchMayChangeInTheFuture() return?
+		Seems like it only depends on B, since currently B MUST change to allow the result to become T
+
+		Match eval: T, T, T  => T
+		So match is currently T, what should MatchMayChangeInTheFuture() return?
+		Answer: Seems to depend on ANY of them being able to change to F.
+	*/
+
+	if m.firstFailedMatcher == nil {
+		// so all matchers succeeded.. Any one of them changing would change the result.
+		for _, matcher := range m.Matchers {
+			if asyncassertion.MatchMayChangeInTheFuture(matcher, actual) {
+				return true
+			}
+		}
+		return false // none of were going to change
+	} else {
+		// one of the matchers failed.. it must be able to change in order to affect the result
+		return asyncassertion.MatchMayChangeInTheFuture(m.firstFailedMatcher, actual)
+	}
+}
diff --git a/matchers/and_test.go b/matchers/and_test.go
index 955e4ae..5e281ca 100644
--- a/matchers/and_test.go
+++ b/matchers/and_test.go
@@ -3,6 +3,7 @@
 import (
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+	. "github.com/onsi/gomega/matchers"
 	"github.com/onsi/gomega/types"
 )
 
@@ -61,4 +62,46 @@
 			})
 		})
 	})
+
+	Context("MatchMayChangeInTheFuture", func() {
+		// setup a closed channel
+		closedChannel := make(chan int)
+		close(closedChannel)
+		var i int
+		Context("Match returned false", func() {
+			Context("returns value of the failed matcher", func() {
+				It("false if failed matcher not going to change", func() {
+					// 3 matchers: 1st returns true, 2nd returns false and is not going to change, 3rd is never called
+					m := And(Not(BeNil()), Receive(&i), Equal(1))
+					Expect(m.Match(closedChannel)).To(BeFalse())
+					Expect(m.(*AndMatcher).MatchMayChangeInTheFuture(closedChannel)).To(BeFalse()) // closed channel, so not going to change
+				})
+				It("true if failed matcher indicates it might change", func() {
+					// 3 matchers: 1st returns true, 2nd returns false and "might" change, 3rd is never called
+					m := And(Not(BeNil()), Equal(5), Equal(1))
+					Expect(m.Match(closedChannel)).To(BeFalse())
+					Expect(m.(*AndMatcher).MatchMayChangeInTheFuture(closedChannel)).To(BeTrue()) // Equal(5) indicates it might change
+				})
+			})
+		})
+		Context("Match returned true", func() {
+			It("returns true if any of the matchers could change", func() {
+				// 3 matchers, all return true, and all could change
+				m := And(Not(BeNil()), Equal("hi"), HaveLen(2))
+				Expect(m.Match("hi")).To(BeTrue())
+				Expect(m.(*AndMatcher).MatchMayChangeInTheFuture("hi")).To(BeTrue()) // all 3 of these matchers default to 'true'
+			})
+			It("returns false if none of the matchers could change", func() {
+				// empty And() has the property of always matching, and never can change since there are no sub-matchers that could change
+				m := And()
+				Expect(m.Match("anything")).To(BeTrue())
+				Expect(m.(*AndMatcher).MatchMayChangeInTheFuture("anything")).To(BeFalse())
+
+				// And() with 3 sub-matchers that return true, and can't change
+				m = And(And(), And(), And())
+				Expect(m.Match("hi")).To(BeTrue())
+				Expect(m.(*AndMatcher).MatchMayChangeInTheFuture("hi")).To(BeFalse()) // the 3 empty And()'s won't change
+			})
+		})
+	})
 })
diff --git a/matchers/with_transform.go b/matchers/with_transform.go
index a8d2a7c..21d9fe0 100644
--- a/matchers/with_transform.go
+++ b/matchers/with_transform.go
@@ -62,5 +62,10 @@
 }
 
 func (m *WithTransformMatcher) MatchMayChangeInTheFuture(_ interface{}) bool {
+	// TODO: Maybe this should always just return true? (Only an issue for non-deterministic transformers.)
+	//
+	// Querying the next matcher is fine if the transformer always will return the same value.
+	// But if the transformer is non-deterministic and returns a different value each time, then there
+	// is no point in querying the next matcher, since it can only comment on the last transformed value.
 	return asyncassertion.MatchMayChangeInTheFuture(m.Matcher, m.transformedValue)
 }