Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implicit search + type inference is order-dependent #8341

Closed
scabug opened this issue Feb 26, 2014 · 28 comments
Closed

implicit search + type inference is order-dependent #8341

scabug opened this issue Feb 26, 2014 · 28 comments
Assignees
Labels
Milestone

Comments

@scabug
Copy link

scabug commented Feb 26, 2014

Minimized from scalatest:

import scala.collection.GenTraversableOnce
import scala.collection.generic.CanBuildFrom
import scala.collection.GenSet

object Every {
  def apply[T](firstElement: T, otherElements: T): Every[T] = ???
}
class Every[+T](underlying: Vector[T]) {
  def iterator: Iterator[T] = ???
}
case class One[+T](loneElement: T) extends Every[T](Vector(loneElement))

abstract class Or[+G,+B] {
  def map[H](f: G => H): H Or B = ???
}
case class Bad[+G,+B](b: B) extends Or[G,B]
case class Good[+G,+B](g: G) extends Or[G,B]

trait Combinable[G, ERR, COLL[_]] {
  def combined: COLL[G] Or Every[ERR]
}

class OrSpec  {
  implicit def convertGenTraversableOnceToCombinable[G, ERR, TRAVONCE[+e] <: GenTraversableOnce[e]]
    (xs: TRAVONCE[G Or Every[ERR]])
    (implicit cbf: CanBuildFrom[TRAVONCE[G Or Every[ERR]], G, TRAVONCE[G]]): Combinable[G, ERR, TRAVONCE] = 
    new Combinable[G, ERR, TRAVONCE] { def combined: TRAVONCE[G] Or Every[ERR] = ??? }

  implicit def convertGenSetToCombinable[G, ERR, X, SET[e] <: GenSet[e]]
    (xs: SET[X with (G Or Every[ERR])])
    (implicit cbf: CanBuildFrom[SET[X with (G Or Every[ERR])], G, SET[G]]): Combinable[G, ERR, SET] = 
    new Combinable[G, ERR, SET] { def combined: SET[G] Or Every[ERR] = ??? }

  // def a = 
  {
    // comment out these lines or move them after the Set ones, and it all compiles
    // to trigger, must be lubbing Good & Bad, and inferring both TRAVONCE and SET type constructors
    // things behave differently when this block is a method's body,
    // so I'm thinking skolemization may be involved (different context.owner?)
    List(Good(3), Bad(One("oops"))).iterator.combined
    List(Good(3)).iterator.combined

    Set(Bad(One("oops"))).combined
    Set(Bad(One("darn")), Bad(One("oops"))).combined
  }
}
/* Reported errors when lines are ordered as given. No errors when reordering applied / List ones are commented out.

OrSpec.scala:43: error: type mismatch;
 found   : scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set.Coll,Nothing,scala.collection.immutable.Set[Nothing]]
    (which expands to)  scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set[_],Nothing,scala.collection.immutable.Set[Nothing]]
 required: scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set[Bad[Nothing,One[String]] with Or[G,Every[String]]],G,scala.collection.immutable.Set[G]]
    Set(Bad(One("oops"))).combined
       ^
OrSpec.scala:43: error: value combined is not a member of scala.collection.immutable.Set[Bad[Nothing,One[String]]]
    Set(Bad(One("oops"))).combined
                          ^
OrSpec.scala:44: error: type mismatch;
 found   : scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set.Coll,Nothing,scala.collection.immutable.Set[Nothing]]
    (which expands to)  scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set[_],Nothing,scala.collection.immutable.Set[Nothing]]
 required: scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set[Bad[Nothing,One[String]] with Or[G,Every[String]]],G,scala.collection.immutable.Set[G]]
    Set(Bad(One("darn")), Bad(One("oops"))).combined
       ^
OrSpec.scala:44: error: value combined is not a member of scala.collection.immutable.Set[Bad[Nothing,One[String]]]
    Set(Bad(One("darn")), Bad(One("oops"))).combined
                                            ^
four errors found
*/
@scabug
Copy link
Author

scabug commented Feb 26, 2014

Imported From: https://issues.scala-lang.org/browse/SI-8341?orig=1
Reporter: @adriaanm
Affected Versions: 2.11.0-M8
See #7944

@scabug
Copy link
Author

scabug commented Feb 26, 2014

@adriaanm said (edited on Feb 26, 2014 8:29:46 AM UTC):
note the "solving: type G" (undet_s printing context.underparams) that appears in the -Ytyper-debug output for a successful run, but not for the failing one:

+|    |    |    |-- convertGenTraversableOnceToCombinable BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value <local OrSpec> in OrSpec) implicits disabled
+|    |    |    |    [adapt] [G, ERR, TRAVONCE[+e] <: scala.collection.GenTraversableO... adapted to [G, ERR, TRAVONCE[+e] <: scala.collection.GenTraversableO...
+|    |    |    |    \-> (xs: TRAVONCE[Or[G,Every[ERR]]])(implicit cbf: scala.collection.generic.CanBuildFrom[TRAVONCE[Or[G,Every[ERR]]],G,TRAVONCE[G]])Combinable[G,ERR,TRAVONCE]
+|    |    |    solving for (G: ?G, ERR: ?ERR, TRAVONCE: ?TRAVONCE)
 |    |    |    |-- convertGenSetToCombinable BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value <local OrSpec> in OrSpec) implicits disabled
 |    |    |    |    [adapt] [G, ERR, X, SET[e] <: scala.collection.GenSet[e]](xs: SET... adapted to [G, ERR, X, SET[e] <: scala.collection.GenSet[e]](xs: SET...
 |    |    |    |    \-> (xs: SET[X with Or[G,Every[ERR]]])(implicit cbf: scala.collection.generic.CanBuildFrom[SET[X with Or[G,Every[ERR]]],G,SET[G]])Combinable[G,ERR,SET]
@@ -50,22 +40,28 @@
 |    |    |    [adapt] [A]=> scala.collection.generic.CanBuildFrom[scala.collect... adapted to [A]=> scala.collection.generic.CanBuildFrom[scala.collect... based on pt scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set[Bad[Nothing,One[String]] with Or[G,Every[String]]],G,scala.collection.immutable.Set[G]]
 |    |    |    solving for (G: ?G)
 |    |    |    [adapt] convertGenSetToCombinable adapted to [G, ERR, X, SET[e] <: scala.collection.GenSet[e]](xs: SET... based on pt scala.collection.immutable.Set[Bad[Nothing,One[String]]] => ?{def combined: ?}
-|    |    |    solving for (G: ?G, ERR: ?ERR, TRAVONCE: ?TRAVONCE)
-|    |    |    solving for (G: ?G, ERR: ?ERR, X: ?X, SET: ?SET)
-|    |    |    |-- convertGenTraversableOnceToCombinable BYVALmode-EXPRmode-FUNmode-POLYmode (silent solving: type G: value <local OrSpec> in OrSpec) implicits disabled
-|    |    |    |    [adapt] [G, ERR, TRAVONCE[+e] <: scala.collection.GenTraversableO... adapted to [G, ERR, TRAVONCE[+e] <: scala.collection.GenTraversableO...
-|    |    |    |    \-> (xs: TRAVONCE[Or[G,Every[ERR]]])(implicit cbf: scala.collection.generic.CanBuildFrom[TRAVONCE[Or[G,Every[ERR]]],G,TRAVONCE[G]])Combinable[G,ERR,TRAVONCE]
-|    |    |    solving for (G: ?G, G: ?G, ERR: ?ERR, TRAVONCE: ?TRAVONCE)
-|    |    |    |-- [G, ERR, X, SET[e] <: scala.collection.GenSet[e]](xs: SET... EXPRmode-POLYmode-QUALmode (silent: value <local OrSpec> in OrSpec) 
+|    |    |    |-- [G, ERR, X, SET[e] <: scala.collection.GenSet[e]](xs: SET... EXPRmode-POLYmode-QUALmode (silent solving: type G: value <local OrSpec> in OrSpec) 
+|    |    |    |    solving for (G: ?G)
+|    |    |    |    solving for (G: ?G)
 |    |    |    |    solving for (A: ?A)
 |    |    |    |    [adapt] [A]=> scala.collection.generic.CanBuildFrom[scala.collect... adapted to [A]=> scala.collection.generic.CanBuildFrom[scala.collect... based on pt scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set[Bad[Nothing,One[String]] with Or[G,Every[String]]],G,scala.collection.immutable.Set[G]]
-|    |    |    |    |-- [G, ERR, X, SET[e] <: scala.collection.GenSet[e]](xs: SET... EXPRmode-POLYmode-QUALmode (silent: value <local OrSpec> in OrSpec) 
+|    |    |    |    solving for (G: ?G)
+|    |    |    |    |-- [G, ERR, X, SET[e] <: scala.collection.GenSet[e]](xs: SET... EXPRmode-POLYmode-QUALmode (silent solving: type G: value <local OrSpec> in OrSpec) 
+|    |    |    |    |    solving for (G: ?G)
 |    |    |    |    |    \-> Combinable[G,String,scala.collection.immutable.Set]
 |    |    |    |    [adapt] [G, ERR, X, SET[e] <: scala.collection.GenSet[e]](xs: SET... adapted to [G, ERR, X, SET[e] <: scala.collection.GenSet[e]](xs: SET...
 |    |    |    |    \-> Combinable[G,String,scala.collection.immutable.Set]
-|    |    |    |-- OrSpec.this.convertGenSetToCombinable[G, String, Bad[Noth... BYVALmode-EXPRmode (site: value <local OrSpec> in OrSpec) 
-|    |    |    |    \-> Or[scala.collection.immutable.Set[G],Every[String]]
-|    |    |    \-> Or[scala.collection.immutable.Set[G],Every[String]]
+/Users/adriaan/Desktop/bugs/t8341_nok.scala:43: error: type mismatch;
+ found   : scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set.Coll,Nothing,scala.collection.immutable.Set[Nothing]]
+    (which expands to)  scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set[_],Nothing,scala.collection.immutable.Set[Nothing]]
+ required: scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set[Bad[Nothing,One[String]] with Or[G,Every[String]]],G,scala.collection.immutable.Set[G]]
+    Set(Bad(One("oops"))).combined
+       ^
+/Users/adriaan/Desktop/bugs/t8341_nok.scala:43: error: value combined is not a member of scala.collection.immutable.Set[Bad[Nothing,One[String]]]
+    Set(Bad(One("oops"))).combined
+                          ^
+|    |    |    solving for (G: ?G)
+|    |    |    \-> <error>

@scabug
Copy link
Author

scabug commented Feb 26, 2014

Chua Chee Seng (cheeseng) said:
For reproducing from scalatest source, you could do:

git clone https://github.com/cheeseng/scalatest.git

cd scalatest

git checkout test-2.11-RC1

sbt test

I'll keep the branch around until this issue is fixed. :)

@scabug
Copy link
Author

scabug commented Mar 18, 2014

Chua Chee Seng (cheeseng) said:
The same problem persist in 2.11.0-RC2, you can reproduce it with:

git clone https://github.com/cheeseng/scalatest.git
cd scalatest
git checkout test-2.11.0-RC2
sbt test

@scabug
Copy link
Author

scabug commented Mar 18, 2014

@adriaanm said:
Jason, do you have any sense of what may be going on here? I suspect mutating the context (.undetParams?) and re-entrance in the type checker.

I don't think we'll be able to fix this in 2.11.0 anymore. To be honest, I forgot to set the fix version on this one. My bad. Too much context-switching going on these last couple of weeks.... I'll hold off pushing RC2 to maven until my Tuesday morning, but the tag has already been pushed...

@scabug
Copy link
Author

scabug commented Mar 18, 2014

@adriaanm said:
The awesome RUNNER=scalac scala-bisector v2.11.0-M6 v2.11.0-M7 t8341.scala from libscala traced it back to scala/scala@251c2b9

@scabug
Copy link
Author

scabug commented Mar 18, 2014

@adriaanm said:
This is a small enough commit that I think we should diagnose before deciding on RC2. I've deleted the RC2 tag for now (if we decide to cut RC2 as-is, I can always push the same one again).

@scabug
Copy link
Author

scabug commented Mar 18, 2014

@adriaanm said:
It's likely this commit revealed an existing problem, because it still looks like a valid improvement to me.

@scabug
Copy link
Author

scabug commented Mar 18, 2014

@retronym said:
Yeah, look at -Xprint:typer in 2.10.3

      OrSpec.this.convertGenTraversableOnceToCombinable[Int, String, Iterator](immutable.this.List.apply[Product with Serializable with Or[Int,One[String]]](Good.apply[Int, Nothing](3), Bad.apply[Nothing, One[String]](One.apply[String]("oops"))).iterator)(collection.this.Iterator.IteratorCanBuildFrom[Int]).combined;
      OrSpec.this.convertGenTraversableOnceToCombinable[Int, ERR, Iterator](immutable.this.List.apply[Good[Int,Nothing]](Good.apply[Int, Nothing](3)).iterator)(collection.this.Iterator.IteratorCanBuildFrom[Int]).combined;
      
      OrSpec.this.convertGenSetToCombinable[G, String, Bad[Nothing,One[String]], scala.collection.immutable.Set](scala.this.Predef.Set.apply[Bad[Nothing,One[String]]](Bad.apply[Nothing, One[String]](One.apply[String]("oops"))))(immutable.this.Set.canBuildFrom[G]).combined;
      OrSpec.this.convertGenSetToCombinable[G, String, Bad[Nothing,One[String]], scala.collection.immutable.Set](scala.this.Predef.Set.apply[Bad[Nothing,One[String]]](Bad.apply[Nothing, One[String]](One.apply[String]("darn")), Bad.apply[Nothing, One[String]](One.apply[String]("oops"))))(immutable.this.Set.canBuildFrom[G]).combined
                                            ^
                                            |_ undetermined!

The G is an undetermined type param.

@scabug
Copy link
Author

scabug commented Mar 18, 2014

@retronym said:
The cross talk comes from way that implicit search statistics from previous searches are used sort the eligible bachelors before getting into the serious business of rankImplicits. This is reminiscent of #8065.

This patch disables the sorting:

git diff -- src
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala
index c8ac362..1a8219b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -849,15 +849,10 @@ trait Implicits {

       /** Sorted list of eligible implicits.
        */
-      val eligible = {
-        val matches = iss flatMap { is =>
-          val result = is filter (info => checkValid(info.sym) && survives(info))
-          shadower addInfos is
-          result
-        }
-
-        // most frequent one first
-        matches sortBy (x => if (isView) -x.useCountView else -x.useCountArg)
+      val eligible = iss flatMap { is =>
+        val result = is filter (info => checkValid(info.sym) && survives(info))
+        shadower addInfos is
+        result
       }

The test then happens to pass unconditionally. But if you invert the declaration order of the two implicits, it then fails on all four.

So two key questions here:

  1. why does the typer fail to infer G or fail to report a failure to do so?
  2. why does the rankImplicits influence the result? It is documented to be a faster way to find the best implicit, not to find some eligible implicit.

@scabug
Copy link
Author

scabug commented Mar 18, 2014

@retronym said:
Here's a cut down case mostly disentangled from the standard library.

trait Combinable[A] {
  def combined = 9
}

trait Trav0[+A]
trait Set0[A] extends T[A @annotation.unchecked.uncheckedVariance]

trait CB[-Elem, +To]

trait List[+A]
 
object O  {
  implicit def listCB[A]: CB[A, List[A]] = ???
  implicit def CovariantMCombinable[G, M[+e]] (xs: M[Option[G]]): Combinable[G] = ???
  implicit def Set0Combinable[G] (xs: Set0[_ <: Option[G]])(implicit cbf: CB[G, List[Any]]): Combinable[G] = ???
}

class T1 {
  import O.listCB
  import O.CovariantMCombinable
  import O.Set0Combinable
  val s: Set0[Option[Nothing]] = ???
  s.combined // okay
}

class T2 {
  import O.listCB
  import O.Set0Combinable
  import O.CovariantMCombinable
  val s: Set0[Option[Nothing]] = ???
  s.combined // fails
}

@scabug
Copy link
Author

scabug commented Mar 18, 2014

@retronym said:
I think that minimization is bogus; I was working with a wrongheadedly patched compiler.

@scabug
Copy link
Author

scabug commented Mar 18, 2014

@retronym said (edited on Mar 18, 2014 10:35:27 AM UTC):
Okay, here's a more faithful whittlin'

trait Covariant[+A]
trait Invariant[A] extends Covariant[A @annotation.unchecked.uncheckedVariance] 
 
trait Combinable[G] {
  def combined = 0
}

trait CanBuildFrom[+C]
 
object C {
  implicit def convert1[G, TRAVONCE[+e] <: Covariant[e]]
    (xs: TRAVONCE[G]): Combinable[G] = ???
 
  implicit def convert2[G, SET[e] <: Invariant[e]]
    (xs: SET[_ <: G])
    (implicit cbf: CanBuildFrom[SET[G]]): Combinable[G] = ???

  implicit def cbf[A]: CanBuildFrom[Invariant[A]] = ???
}

class Test1 {
  import C.{cbf, convert1, convert2}
  val s: Invariant[Nothing] = ???
  s.combined // fail
}

class Test2 {
  import C.{cbf, convert2, convert1}

  val s: Invariant[Nothing] = ???
  s.combined // okay
}

class Test3 {
  import C.{cbf, convert1, convert2}
  val s: Invariant[Null] = ???
  s.combined // okay
}

class Test4 {
  import C.{cbf, convert2, convert1}

  val s: Invariant[Null] = ???
  s.combined // okay
}

Running that with the patch above to remove usage-count-based implicit sorting:

qbin/scalac  test/files/pos/t8431.scala; rm *.class 2>/dev/null
test/files/pos/t8431.scala:24: error: type mismatch;
 found   : CanBuildFrom[Invariant[Nothing]]
 required: CanBuildFrom[Invariant[G]]
  s.combined // fail
  ^
test/files/pos/t8431.scala:24: error: value combined is not a member of Invariant[Nothing]
  s.combined // fail
    ^
two errors found

@scabug
Copy link
Author

scabug commented Mar 18, 2014

@retronym said:
I've got a fix for this on the way. Actually it makes things fail uniformly. Stay tuned.

@scabug
Copy link
Author

scabug commented Mar 18, 2014

@retronym said:
scala/scala#3639

@scabug
Copy link
Author

scabug commented Mar 18, 2014

@adriaanm said:
Excellent. Just in time for RC3 :-)
I'll push all the other tickets fix-by RC2 to RC3

@scabug scabug closed this as completed Mar 19, 2014
@scabug
Copy link
Author

scabug commented Mar 19, 2014

Chua Chee Seng (cheeseng) said:
Great thanks Adriaan and Jason, is the fix included in 2.11.0-SNAPSHOT?(or RC3 is coming out soon?) Just eager to try it out.. :)

@scabug
Copy link
Author

scabug commented Mar 19, 2014

@adriaanm said:
Both :-) 2.11.0-RC3 is on its way to maven. To be clear, and sorry to disappoint: the bug was that it compiled. Now it fails to typecheck no matter in which order you call it...

@scabug
Copy link
Author

scabug commented Mar 19, 2014

Chua Chee Seng (cheeseng) said:
Oh I see, hmm, at least it is consistent. I'll try to inform Bill so that he can try to adjust accordingly to work.

@scabug
Copy link
Author

scabug commented Mar 19, 2014

@adriaanm said:
I think Jason may have an idea for a fix on your side, but I'll let him comment.

@scabug
Copy link
Author

scabug commented Mar 19, 2014

Chua Chee Seng (cheeseng) said:
Just to report that when I tried to build with RC3 in the private repo, and the error counts increase from 4 errors to 16 errors, it did is more consistent now as all org.scalautils.Bad lines fail to compile (name does sound aim to be problematic though :) ). Anyway, I asked Bill to join and watch this ticket and comment, he can explain better on that part of code and the reason he's doing it that way.

@scabug
Copy link
Author

scabug commented Mar 19, 2014

@adriaanm said:
Thanks for the feedback. Sorry to hear it broke more stuff. The original success was pretty hollow, as implicit search happened to mutate shared state in the type checker that caused type inference to succeed for completely unrelated expressions.

@scabug
Copy link
Author

scabug commented Mar 19, 2014

@bvenners said:
I'm in here. The reason there is a separate implicit for Sets is that I needed the + for the GenTraversable one, and Set isn't covariant. I can't remember right now why I needed to say covariant, but there was some good reason. Hopefully there's another way to accomplish the same thing. I'll wait for Jason to comment on his suggestion.

@scabug
Copy link
Author

scabug commented Mar 19, 2014

@retronym said (edited on Mar 19, 2014 12:55:55 PM UTC):
Adding this implicit conversion:

  implicit def convertGenSetToCombinableNothing[ERR, X, SET[e] <: GenSet[e]]
    (xs: SET[X with (Nothing Or Every[ERR])])
    (implicit cbf: CanBuildFrom[SET[X with (Nothing Or Every[ERR])], Nothing, SET[Nothing]]): Combinable[Nothing, ERR, SET] =
    new Combinable[Nothing, ERR, SET] { def combined: SET[Nothing] Or Every[ERR] = ??? }

Makes things compile again.

Background: In uses like:

Set(Bad(One("oops"))).combined

The inferred type is Set[Nothing Or Every[String]]. Scala's type inference has a few rough edges when you actually want a type argument (G) to be inferred as Nothing.

So even the explicit call to that converter fails:

convertGenSetToCombinable(Set(Bad(One("oops")))).combined

After our patch, the implicit view fails in the same way as the explicit way in all cases.

@scabug
Copy link
Author

scabug commented Mar 19, 2014

@bvenners said:
Hi Jason,

Unfortunately adding that implicit didn't seem to solve our type errors in the real ScalaTest. I put the build that exhibits the problem in this branch:

https://github.com/scalatest/scalatest/tree/problem-in-2.11.0-RC3

I updated the ant build, not yet the sbt one, so to reproduce the problem just checkout the problem-in-2.11.0-RC3 branch, cd into it, and type:

ant test

You'll get 22 compiler errors. I will keep investigating, but since this is holding up the show I thought I'd share it with you in case you can more quickly see the way to a solution.

@scabug
Copy link
Author

scabug commented Mar 20, 2014

@bvenners said (edited on Mar 20, 2014 12:11:43 AM UTC):
Hi All,

Sorry I didn't have time to look carefully early today. 10 of the errors were because I merged a pull request into master instead of 2.1.x. I removed unused BeanProperty imports and that zapped 10 of the errors. The problem-in-2.11.0-RC3 branch is down to the 12 that are really caused by the implicit resolution issue.

... And now that I look at the remaining errors they are not about Set. I'll try the same trick for GenTraversable...

Bill

@scabug
Copy link
Author

scabug commented Mar 20, 2014

@adriaanm said:

  implicit def convertGenTraversableOnceToCombinableNothing[ERR, EVERY[b] <: Every[b], TRAVONCE[+e] <: GenTraversableOnce[e]](xs: TRAVONCE[Nothing Or EVERY[ERR]])(implicit cbf: CanBuildFrom[TRAVONCE[Nothing Or EVERY[ERR]], Nothing, TRAVONCE[Nothing]]): Combinable[Nothing, ERR, TRAVONCE]  = convertGenTraversableOnceToCombinable[Nothing, ERR, EVERY, TRAVONCE](xs)(cbf)
  implicit def convertGenSetToCombinableNothing[ERR, X, EVERY[b] <: Every[b], SET[e] <: GenSet[e]](xs: SET[X with (Nothing Or EVERY[ERR])])(implicit cbf: CanBuildFrom[SET[X with (Nothing Or EVERY[ERR])], Nothing, SET[Nothing]]): Combinable[Nothing, ERR, SET] = convertGenSetToCombinable[Nothing, ERR, X, EVERY, SET](xs)(cbf)
  implicit def convertEveryToCombinableNothing[ERR](oneToMany: Every[Nothing Or Every[ERR]]): Combinable[Nothing, ERR, Every] =    convertEveryToCombinable[Nothing, ERR](oneToMany)
  implicit def convertOptionToCombinableNothing[ERR](option: Option[Nothing Or Every[ERR]]): Combinable[Nothing, ERR, Option] =    convertOptionToCombinable[Nothing, ERR](option)

did it for me

@scabug
Copy link
Author

scabug commented Mar 20, 2014

@bvenners said:
Bingo! Adding an implicit for GenTraversableNothing got it all compiling again. Thanks for your help.

Bill

@scabug scabug added the infer label Apr 7, 2017
@scabug scabug added this to the 2.11.0-RC3 milestone Apr 7, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants