diff options
author | Jon Pretty <jon.pretty@propensive.com> | 2017-11-30 20:45:22 +0000 |
---|---|---|
committer | Jon Pretty <jon.pretty@propensive.com> | 2017-11-30 20:45:22 +0000 |
commit | fba0c1cb94d4d67c48db8fb283c5dc1fedbf215a (patch) | |
tree | 25158dcdef93b1e7a58c961e3e20cc54c02129c7 | |
parent | e1bb3f9c514a2b473076e5fd98b87c26885cd223 (diff) | |
parent | 7df3e96d3137e78813d5bdcb4daac8531db6b860 (diff) | |
download | magnolia-fba0c1cb94d4d67c48db8fb283c5dc1fedbf215a.tar.gz magnolia-fba0c1cb94d4d67c48db8fb283c5dc1fedbf215a.tar.bz2 magnolia-fba0c1cb94d4d67c48db8fb283c5dc1fedbf215a.zip |
Merge branch 'patch-1' of https://github.com/shadaj/magnolia
-rw-r--r-- | CONTRIBUTORS | 1 | ||||
-rw-r--r-- | core/shared/src/main/scala/magnolia.scala | 52 | ||||
-rw-r--r-- | tests/src/main/scala/tests.scala | 17 |
3 files changed, 68 insertions, 2 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS index e376ca4..28be510 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -1,3 +1,4 @@ Jon Pretty <jon.pretty@propensive.com> [@propensive](https://twitter.com/propensive/) Loïc Descotte Georgi Krastev <jorokr21@gmail.com> [@joro_kr](https://twitter.com/joro_kr/) +Shadaj Laddad [@shadaj](https://twitter.com/shadajl)
\ No newline at end of file diff --git a/core/shared/src/main/scala/magnolia.scala b/core/shared/src/main/scala/magnolia.scala index a748561..f55dfa7 100644 --- a/core/shared/src/main/scala/magnolia.scala +++ b/core/shared/src/main/scala/magnolia.scala @@ -201,6 +201,56 @@ object Magnolia { } } + // From Shapeless: https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/generic.scala#L698 + // Cut-n-pasted (with most original comments) and slightly adapted from + // https://github.com/scalamacros/paradise/blob/c14c634923313dd03f4f483be3d7782a9b56de0e/plugin/src/main/scala/org/scalamacros/paradise/typechecker/Namers.scala#L568-L613 + def patchedCompanionSymbolOf(original: c.Symbol): c.Symbol = { + // see https://github.com/scalamacros/paradise/issues/7 + // also see https://github.com/scalamacros/paradise/issues/64 + + val global = c.universe.asInstanceOf[scala.tools.nsc.Global] + val typer = c.asInstanceOf[scala.reflect.macros.runtime.Context].callsiteTyper.asInstanceOf[global.analyzer.Typer] + val ctx = typer.context + val owner = original.owner + + import global.analyzer.Context + + original.companion.orElse { + import global.{ abort => aabort, _ } + implicit class PatchedContext(ctx: Context) { + trait PatchedLookupResult { def suchThat(criterion: Symbol => Boolean): Symbol } + def patchedLookup(name: Name, expectedOwner: Symbol) = new PatchedLookupResult { + override def suchThat(criterion: Symbol => Boolean): Symbol = { + var res: Symbol = NoSymbol + var ctx = PatchedContext.this.ctx + while (res == NoSymbol && ctx.outer != ctx) { + // NOTE: original implementation says `val s = ctx.scope lookup name` + // but we can't use it, because Scope.lookup returns wrong results when the lookup is ambiguous + // and that triggers https://github.com/scalamacros/paradise/issues/64 + val s = { + val lookupResult = ctx.scope.lookupAll(name).filter(criterion).toList + lookupResult match { + case Nil => NoSymbol + case List(unique) => unique + case _ => aabort(s"unexpected multiple results for a companion symbol lookup for $original#{$original.id}") + } + } + if (s != NoSymbol && s.owner == expectedOwner) + res = s + else + ctx = ctx.outer + } + res + } + } + } + ctx.patchedLookup(original.asInstanceOf[global.Symbol].name.companionName, owner.asInstanceOf[global.Symbol]).suchThat(sym => + (original.isTerm || sym.hasModuleFlag) && + (sym isCoDefinedWith original.asInstanceOf[global.Symbol]) + ).asInstanceOf[c.universe.Symbol] + } + } + def directInferImplicit(genericType: c.Type, typeConstructor: Type): Option[Typeclass] = { val genericTypeName: String = genericType.typeSymbol.name.decodedName.toString.toLowerCase @@ -288,7 +338,7 @@ object Magnolia { val preAssignments = caseParams.map(_.typeclass) val defaults = if (!isValueClass) { - val caseClassCompanion = genericType.companion + val caseClassCompanion = patchedCompanionSymbolOf(genericType.typeSymbol).asModule.info // If a companion object is defined with alternative apply methods // it is needed get all the alternatives diff --git a/tests/src/main/scala/tests.scala b/tests/src/main/scala/tests.scala index df4dfd6..a6e32d4 100644 --- a/tests/src/main/scala/tests.scala +++ b/tests/src/main/scala/tests.scala @@ -215,7 +215,6 @@ object Tests extends TestApp { Show.gen[Length].show(new Length(100)) }.assert(_ == "100") - // Corrupt being covariant in L <: Seq[Company] enables the derivation for Corrupt[String, _] test("show a Politician with covariant lobby") { Show.gen[Politician[String]].show(Corrupt("wall", Seq(Company("Alice Inc")))) @@ -231,6 +230,22 @@ object Tests extends TestApp { |""") } + class ParentClass() { + case class LocalClass(name: String) + + test("serialize a case class inside another class") { + implicitly[Show[String, LocalClass]].show(LocalClass("foo")) + }.assert(_ == "LocalClass(name=foo)") + + case class LocalClassWithDefault(name: String = "foo") + + test("construct a default case class inside another class") { + Default.gen[LocalClassWithDefault].default + }.assert(_ == LocalClassWithDefault("foo")) + } + + new ParentClass() + test("show an Account") { Show.gen[Account].show(Account("john_doe", "john.doe@yahoo.com", "john.doe@gmail.com")) }.assert(_ == "Account(id=john_doe,emails=[john.doe@yahoo.com,john.doe@gmail.com])") |