This problem arose in a module I'm writing, but I have made a minimal case that exhibits the same behaviour.
class Minimal[T](x : T) {
def doSomething = x
}
object Sugar {
type S[T] = { def doSomething : T }
def apply[T, X <: S[T]] (x: X) = x.doSomething
}
object Error {
val a = new Minimal(4)
Sugar(a) // error: inferred [Nothing, Minimal[Int]] does not fit the bounds of apply
Sugar[Int, Minimal[Int]](a) // works as expected
}
The problem is that the compiler manages to figure out the inner parameter for Minimal
(Int
), but then sets the other occurrence of T
to Nothing
, which obviously does not match apply
. These are definitely the same T
, as removing the first parameter makes the second complain that T is not defined.
Is there some ambiguity that means that the compiler cannot infer the first parameter, or is this a bug? Can I work around this gracefully?
Further information: This code is a simple example of an attempt at syntactic sugar. The original code tries to make |(a)|
mean the modulus of a
, where a is a vector. Clearly |(a)|
is better than writing |[Float,Vector3[Float]](a)|
, but unfortunately I can't use unary_|
to make this easier.
The actual error:
inferred type arguments [Nothing,Minimal[Int]] do not conform to method apply's type parameter bounds [T,X <: Sugar.S[T]]
There's some weirdness with bounds on structural types, try using a view bound on S[T] instead.
def apply[T, X <% S[T]] (x: X) = x.doSomething
works fine.This isn't a Scala compiler bug, but it's certainly a limitation of Scala's type inference. The compiler wants to determine the bound on
X
,S[T]
, before solving forX
, but the bound mentions the so far unconstrained type variableT
which it therefore fixes atNothing
and proceeds from there. It doesn't revisitT
onceX
has been fully resolved ... currently type inference always proceeds from left to right in this sort of case.If your example accurately represents your real situation then there is a simple fix,
Here
T
will be inferred such thatMinimal
conforms toS[T]
directly rather than via an intermediary bounded type variable.Update
Joshua's solution also avoids the problem of inferring type
T
, but in a completely different way.desugars to,
The type variables
T
andX
can now be solved for independently (becauseT
is no longer mentioned inX
's bound). This means thatX
is inferred asMinimal
immediately, andT
is solved for as a part of the implicit search for a value of typeX => S[T]
to satisfy the implicit argumentconv
.conforms
inscala.Predef
manufactures values of this form, and in context will guarantee that given an argument of typeMinimal
,T
will be inferred as Int. You could view this as an instance of functional dependencies at work in Scala.