Why this fails with typecheck:
The type controller operates as follows.
xml.should(matchXML(expected))
- Since the
should method is not part of NodeSeq , the compiler tries to find the implicit conversion for xml for a ShouldMatcher . Scala's Programming book states that such an implicit conversion should be the most specific:
"Prior to Scala 2.7, this was the end of the story. Multiple implicit conversions, the compiler refused to choose between them .... Scala 2.8 loosens this rule. If one of the available conversions is strictly more specific than the others, then the compiler will choose a more specific one .... one implicit conversion is more specific than another if one of the following applies: the argument type of the first is a subtype of the latter ... "
Since NodeSeq extends Seq[Node] , the following function
convertToSeqShouldWrapper[T](o : scala.GenSeq[T]) : SeqShouldWrapper[T]
therefore, is the most specific among all the others.
The program is rewritten as:
`convertToSeqShouldWrapper(xml).should(matchXML(expected))`
where convertToSeqShouldWrapper(xml) is SeqShouldWrapper[T] where T = GenSeq[Node] .
The should method of SeqShouldWrapper accepts Matcher[T] , which is a function of type T => MatchResult . Therefore, it accepts Matcher[GenSeq[Node]] .
Since T appears to the left of the arrow, the matches are not covariant in T , but contravariant. A NodeSeq is GenSeq[Node] , so a Matcher[GenSeq[Node]] is Matcher[NodeSeq] , and not vice versa. This explains the above error when the should method cannot accept Matcher[NodeSeq] and requires a Matcher[GenSeq[Node]] .
2 solutions
- Replace all instances of
NodeSeq with GenSeq[Node] so that the type matches everywhere. Alternatively, wrap xml explicitly with a transform function.
convertToAnyShouldWrapper(xml).should(matchXML(expected))
source share