Skip to content

Extension methods with recursive implicit resolution do not work #7056

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

Closed
anatoliykmetyuk opened this issue Aug 16, 2019 · 5 comments
Closed
Labels
area:implicits related to implicits itype:bug

Comments

@anatoliykmetyuk
Copy link
Contributor

anatoliykmetyuk commented Aug 16, 2019

import Tuple.{ Head, Tail }

trait Idnt[T1 <: Tuple] {
  type Res <: Tuple
  extension (t1: T1) def idnt: Res
}

type Aux[T1 <: Tuple, Res0] = Idnt[T1] { type Res = Res0 }

given [T1 <: NonEmptyTuple, TZ <: Tuple](using Aux[Tail[T1], TZ]) : Aux[T1, Head[T1] *: TZ] = new Idnt[T1] {
  type Res = Head[T1] *: TZ
  extension (t1: T1) def idnt: Res = t1.head *: t1.tail.idnt
}

given Aux[Unit, Unit] = new Idnt[Unit] {
  type Res = Unit
  extension (t1: Unit) def idnt: Unit = ()
}

val x: (1, 2, 3) = (1, 2, 3)
val z: (1, 2, 3) = x.idnt

Says:

-- [E008] Member Not Found Error: ../pg/Main.scala:23:21 -----------------------
23 |val z: (1, 2, 3) = x.idnt
   |                   ^^^^^^
   |value idnt is not a member of (Int(1), Int(2), Int(3)) - did you mean x._1?.
   |An extension method was tried, but could not be fully constructed:
   |
   |    Main$package.Aux_T1_Head_given[(Int(1), Int(2), Int(3)), Tuple](
   |      Main$package.Aux_T1_Head_given[T1, TZ]
   |    ).idnt()
one error found

But:

import Tuple.{ Head, Tail }

trait Idnt[T1 <: Tuple] {
  type Res <: Tuple
  def (t1: T1) idnt: Res
}

type Aux[T1 <: Tuple, Res0] = Idnt[T1] { type Res = Res0 }

given [T1 <: NonEmptyTuple] as Aux[T1, Head[T1] *: Tail[T1]]
  = new Idnt[T1] {
  type Res = Head[T1] *: Tail[T1]
  def (t1: T1) idnt: Res = t1.head *: t1.tail
}

given as Aux[Unit, Unit] = new Idnt[Unit] {
  type Res = Unit
  def (t1: Unit) idnt: Unit = ()
}

val x: (1, 2, 3) = (1, 2, 3)
val z: (1, 2, 3) = x.idnt

Works. My gut feeling tells me it is related to #7049 and #7050.

@odersky
Copy link
Contributor

odersky commented Aug 25, 2019

We'd need a better minimization here. What extension method call should have been synthesized?

@anatoliykmetyuk
Copy link
Contributor Author

anatoliykmetyuk commented Aug 27, 2019

@odersky I minimized this as follows:

type A
type B <: A

type PartialId[X] = X match {
  case B => X
}

trait T1[T] {
  extension (t1: T) def idnt1: Any
}

given [T <: A](using PartialId[T]): T1[T] = new T1[T] {
  extension (t1: T) def idnt1: Any = ???
}

given PartialId[B] = ???

val x: B = ???
val z = x.idnt1

Out:

-- [E008] Member Not Found Error: ../pg/i7056/Main.scala:19:10 -----------------
19 |val z = x.idnt1
   |        ^^^^^^^
   |      value idnt1 is not a member of B.
   |      An extension method was tried, but could not be fully constructed:
   |
   |          Main$package.T1_T_given[A](PartialId_B_given).idnt1()
one errors found

To make it work, define PartialId as follows:

type PartialId[X] = X match {
  case _ => X
}

Also, if you leave PartialId as it is and replace the last two lines as follows, it will compile:

// val x: B = ???
// val z = x.idnt1
val a = the[T1[B]]

Note what the error message says:

Main$package.T1_T_given[A]

The argument to T1_T_given is A (the specified upper bound for that argument) and not B (the actual argument).

My guess is that the match type that matches against a non-wildcard pattern messes up the precision of the type inference. And it does so only for the extension methods, as demonstrated by the the[T1[B]] example.

Related to #7078?

@anatoliykmetyuk
Copy link
Contributor Author

Another way to make the example work is to define the second given as:

given as PartialId[A] = ???

Which supports the hypothesis that the inference happens for the upper bound and not for the actual type argument.

@bishabosha
Copy link
Member

bishabosha commented Apr 5, 2020

I believe this is a duplicate of #8311

@odersky
Copy link
Contributor

odersky commented Dec 28, 2020

Since #8311 is closed, we should do the same here.

@odersky odersky closed this as completed Dec 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:implicits related to implicits itype:bug
Projects
None yet
Development

No branches or pull requests

3 participants