-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Can't find implicit delegating to lower-priority implicit via path-dependent type #17212
Comments
Just for the context, here is more meaningful example. Repo https://github.com/DmytroMitin/phantom, branch I define instances of a type class trait SingleGeneric[T, Store, GenR] {
type Repr = Store
def to(t: T): Repr
def from(r: Repr): T
}
trait LowPrioritySingleGeneric {
implicit def single[T, HL](implicit gen: shapeless.Generic.Aux[T, HL]): SingleGeneric[T, T :: HNil, HL] =
new SingleGeneric[T, T :: HNil, HL] {
def to(source: T): T :: HNil = source :: HNil
def from(hl: T :: HNil): T = hl.head
}
}
object SingleGeneric extends LowPrioritySingleGeneric {
implicit def generic[T, HL](implicit gen: shapeless.Generic.Aux[T, HL]): SingleGeneric[T, HL, HL] =
new SingleGeneric[T, HL, HL] {
def to(source: T): HL = gen to source
def from(hl: HL): T = gen from hl
}
} but if I remove the extra type parameter in instance declarations and use path-dependent type instead then the project will not compile (Scala 2.13) trait LowPrioritySingleGeneric {
implicit def single[T](implicit gen: Generic[T]): SingleGeneric[T, T :: HNil, gen.Repr] =
new SingleGeneric[T, T :: HNil, gen.Repr] {
def to(source: T): T :: HNil = source :: HNil
def from(hl: T :: HNil): T = hl.head
}
}
object SingleGeneric extends LowPrioritySingleGeneric {
implicit def generic[T](implicit gen: Generic[T]): SingleGeneric[T, gen.Repr, gen.Repr] =
new SingleGeneric[T, gen.Repr, gen.Repr] {
def to(source: T): gen.Repr = gen to source
def from(hl: gen.Repr): T = gen from hl
}
} Here If I split the type class into two then package object macros {
type SingleGeneric[T, Store, GenR] = SingleGeneric1.Aux[T, Store, GenR]
}
trait SingleGeneric1[T] extends Serializable {
type Store
type GenR
type Repr = Store
def to(t: T): Store
def from(s: Store): T
}
object SingleGeneric1 {
type Aux[T, S, R] = SingleGeneric1[T] {type Store = S; type GenR = R}
def instance[T, S, R](f: T => S, g: S => T): Aux[T, S, R] = new SingleGeneric1[T] {
override type Store = S
override type GenR = R
override def to(t: T): Store = f(t)
override def from(s: Store): T = g(s)
}
// the project compiles
implicit def mkSingleGeneric1[T, S](implicit
sgen2: SingleGeneric2.Aux[T, S],
gen: Generic[T]
): Aux[T, S, gen.Repr] = instance(sgen2.to(_), sgen2.from)
// the project doesn't compile
//implicit def mkSingleGeneric1[T](implicit
// sgen2: SingleGeneric2[T],
// gen: Generic[T]
//): Aux[T, sgen2.Store, gen.Repr] = instance(sgen2.to(_), sgen2.from)
}
trait SingleGeneric2[T] extends Serializable {
type Store
def to(t: T): Store
def from(s: Store): T
}
trait LowPrioritySingleGeneric2 {
type Aux[T, S] = SingleGeneric2[T] {type Store = S}
def instance[T, S](f: T => S, g: S => T): Aux[T, S] = new SingleGeneric2[T] {
override type Store = S
override def to(t: T): Store = f(t)
override def from(s: Store): T = g(s)
}
implicit def single[T]: Aux[T, T :: HNil] = instance(_ :: HNil, _.head)
}
object SingleGeneric2 extends LowPrioritySingleGeneric2 {
implicit def generic[T](implicit gen: Generic[T]): Aux[T, gen.Repr] =
instance(gen.to(_), gen.from)
} In Scala 3 this doesn't compile either: https://scastie.scala-lang.org/DmytroMitin/C8ziePLmSfifN2Je2Wsbcw/6 This is kind of item 3 in the current issue. |
Compiler version
3.3.0-RC3
Motivation
I have two type classes. They are working on type level. They accept a type and return a type. The 1st type class delegates to the 2nd (it can do some extra work but for minimality it just delegates). The 2nd type class returns
Int
for any typeT
(higher-priority instance) orString
for any typeT
(lower-priority instance). In a more meaningful example the "return type" is calculated in some way and the higher-priority instance manages the case with additional upper bound or additional type-class constraint but for minimality it's just two similar instances, higher-priority and lower-priority. I make the "return type" of the 1st type class a type member.https://scastie.scala-lang.org/DmytroMitin/MEyLY8TkRfaif5C778wkRw/1
https://scastie.scala-lang.org/DmytroMitin/MEyLY8TkRfaif5C778wkRw/2
Minimized code
https://scastie.scala-lang.org/DmytroMitin/MEyLY8TkRfaif5C778wkRw
Output
Expectation
summon[TC1.Aux[Boolean, String]]
in 3) should compile too.Or is it intended difference between type parameters and type members? (Functional dependencies?)
In Scala 2.13 behavior is the same
But in 2.13 there is easier reproduction (without lower priority) scala/bug#12767
The text was updated successfully, but these errors were encountered: