ekk-cb / test-dest

0 stars 0 forks source link

Issue with sealed traits #48

Open ekk-cb opened 3 years ago

ekk-cb commented 3 years ago

I think this particular bug has to do with a a sealed trait with only a single case class or case object (See random notes).

In MacroTests.scala, adding the following lines:

object DeepHierarchy {
  sealed trait A
  case class B(i: Int) extends A
  sealed trait C extends A
  case class D(s: String) extends C
  case class E(b: Boolean) extends C
  sealed trait Q //new line
  case object AnQ extends Q //new line 
  case class F(q: Q) extends C //new line
}

and running test:compile causes:

[error] one error found [error] /home/nick/projects/upickle/js/../shared/test/scala/upickle/MacroTests.scala:138: could not find implicit value for evidence parameter of type upickle.Writer[upickle.DeepHierarchy.A] [error] rw(B(1): A, """["upickle.DeepHierarchy.B", {"i": 1}]""

...but then adding

case object AnOtherQ extends Q

leads to success ???

Random notes:

Adding a third other other Q is still a success...

going back to just one AnQ recreates the error...

Using:

case object AnQ 
case class F(q: AnQ.type) extends C

Throws the same compile error (removed sealed trait Q).

However,

case class AnQ(i: Int)
case class F(q: AnQ) extends C

Is a success...

But

  sealed trait Q
  case class AnQ(i: Int) extends Q
  case class F(q: Q) extends C

errors...

Which is again fixed if the seconds case object is added (AnOtherQ extends Q )is added...

ID: 9 Original Author: Voltir ID: 8 Original Author: ekk-cb

ekk-cb commented 3 years ago

Ok, I am pretty sure maroRImpl is throwing some kind of exception when it fails. If I define the function like

def macroRImpl[T: c.WeakTypeTag](c: Context) = { 
  assert(false)
}

I get similar errors about not being able to find implicits.

I have also noticed that in the valid case, for each invocation of macroRImpl, I see each "tpe" once -- in the failing case, it looks as if there are multiple calls to the same tpe (upickle.DeepHierarchy.A in this case)

Original Author:Voltir Original Author:ekk-cb

ekk-cb commented 3 years ago

Random speculation...

What if it has to do with the type inferred by the generated code when the treeMaker is reduced?

I believe that because this is working on sealed traits, the LUB of all the reduce calls will infact be the sealed trait type, which happens to be the reader we are attempting to generate... except in the case when there is exactly one subclass. Then the type inferred will simply be the exact subclass type and not the type of the parent sealed trait.

Maybe? I wish I could see the generated "val x"...

Original Author:Voltir Original Author:ekk-cb

ekk-cb commented 3 years ago

Replace reader with writer in the above...

Perhaps

_.map(p => q"$p.write": Tree)
.reduce((a, b) => q"upickle.Internal.mergeable($a) merge $b")

In the case of only a single "tree", reduce is ignored and the output is just p.write -- does p.write and upickle.Internal.mergeable($a) merge $b have the same type?

Original Author:Voltir Original Author:ekk-cb

ekk-cb commented 3 years ago

This has been fixed in 0.2.4; you were correct in identifying the problem with a solitary p.write not having the correct type, since merge does an implicit (but safe) cast.

Original Author:lihaoyi Original Author:ekk-cb