diff --git a/build.sbt b/build.sbt index b022e055c..cd45f4dad 100644 --- a/build.sbt +++ b/build.sbt @@ -111,6 +111,30 @@ val boilerplate = Def.taskDyn { (Compile / sourceManaged).map(Boilerplate.gen(scalaBinaryVersion.value)) } +lazy val macroAnnotationSettings = Seq( + scalacOptions ++= { + CrossVersion.partialVersion(scalaVersion.value) match { + case Some((2, v)) if v >= 13 => Seq("-Ymacro-annotations") + case _ => Nil + } + }, + libraryDependencies ++= { + CrossVersion.partialVersion(scalaVersion.value) match { + case Some((2, v)) if v <= 12 => + Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)) + case _ => Nil + } + }, +) + +lazy val coreTestMacros = crossProject(JSPlatform, JVMPlatform, NativePlatform) + .crossType(CrossType.Full) + .settings(moduleName := "core-test-macros") + .settings(commonSettings) + .settings(noPublishSettings) + .configureCross(buildInfoSetup) + .settings(macroAnnotationSettings) + lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform) .crossType(CrossType.Full) .configureCross(configureJUnit) @@ -123,6 +147,8 @@ lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform) .settings(Compile / sourceManaged := baseDirectory.value.getParentFile / "shared" / "src" / "main" / "managed") .settings(Compile / sourceGenerators += boilerplate.taskValue) .settings(mimaSettings) + .dependsOn(coreTestMacros % "test->compile") + .settings(macroAnnotationSettings) lazy val coreJVM = core.jvm lazy val coreJS = core.js diff --git a/core/shared/src/main/scala/shapeless/conversions.scala b/core/shared/src/main/scala/shapeless/conversions.scala index 71f299348..14f4c2e07 100644 --- a/core/shared/src/main/scala/shapeless/conversions.scala +++ b/core/shared/src/main/scala/shapeless/conversions.scala @@ -22,12 +22,12 @@ import ops.hlist.Tupler * Higher ranked function which converts `HLists` to tuples. */ object tupled extends Poly1 { - implicit def caseHList[L <: HList](implicit tupler: Tupler[L]) = at[L](tupler(_)) + implicit def caseHList[L <: HList](implicit tupler: Tupler[L]): Case.Aux[L, tupler.Out] = at[L](tupler(_)) } /** * Higher ranked function which converts products to `HLists`. */ object productElements extends Poly1 { - implicit def caseProduct[P](implicit gen: Generic[P]) = at[P](p => gen.to(p)) + implicit def caseProduct[P](implicit gen: Generic[P]): Case.Aux[P, gen.Repr] = at[P](p => gen.to(p)) } diff --git a/core/shared/src/main/scala/shapeless/coproduct.scala b/core/shared/src/main/scala/shapeless/coproduct.scala index 05b776740..ced87a429 100644 --- a/core/shared/src/main/scala/shapeless/coproduct.scala +++ b/core/shared/src/main/scala/shapeless/coproduct.scala @@ -130,7 +130,7 @@ object Coproduct extends Dynamic { def apply[C <: Coproduct] = new MkCoproduct[C] - implicit def cpOps[C <: Coproduct](c: C) = new CoproductOps(c) + implicit def cpOps[C <: Coproduct](c: C): CoproductOps[C] = new CoproductOps(c) def unsafeMkCoproduct(length: Int, value: Any) = (0 until length).foldLeft[Coproduct](Inl(value))((accum, _) => Inr(accum)) diff --git a/core/shared/src/main/scala/shapeless/generic.scala b/core/shared/src/main/scala/shapeless/generic.scala index cb3432c0e..96806393d 100644 --- a/core/shared/src/main/scala/shapeless/generic.scala +++ b/core/shared/src/main/scala/shapeless/generic.scala @@ -1021,9 +1021,12 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { // case 3: case class case tpe if tpe.typeSymbol.asClass.isCaseClass => val companion = patchedCompanionSymbolOf(tpe.typeSymbol) + val apply = companion.typeSignature.member(TermName("apply")) val unapply = companion.typeSignature.member(TermName("unapply")) val fields = fieldsOf(tpe) - (fromApply(fields), if (unapply.isSynthetic) toUnapply(fields) else toGetters(fields)) + val ctor = if (apply == NoSymbol) fromConstructor(fields) else fromApply(fields) + val dtor = if (unapply.isSynthetic) toUnapply(fields) else toGetters(fields) + (ctor, dtor) // case 4: exactly one matching public apply/unapply case HasApplyUnapply(args) => (fromApply(args), toUnapply(args)) diff --git a/core/shared/src/main/scala/shapeless/hmap.scala b/core/shared/src/main/scala/shapeless/hmap.scala index cdba5c2b3..b4b192930 100644 --- a/core/shared/src/main/scala/shapeless/hmap.scala +++ b/core/shared/src/main/scala/shapeless/hmap.scala @@ -36,7 +36,7 @@ class HMap[R[_, _]](underlying : Map[Any, Any] = Map.empty) extends Poly1 { def +[K, V](kv : (K, V))(implicit ev : R[K, V]) : HMap[R] = new HMap[R](underlying+kv) def -[K](k : K) : HMap[R] = new HMap[R](underlying-k) - implicit def caseRel[K, V](implicit ev : R[K, V]) = Case1[this.type, K, V](get(_).get) + implicit def caseRel[K, V](implicit ev : R[K, V]): Case1.Aux[this.type, K, V] = Case1[this.type, K, V](get(_).get) } object HMap { diff --git a/core/shared/src/main/scala/shapeless/lenses.scala b/core/shared/src/main/scala/shapeless/lenses.scala index 531c4a908..524402d01 100644 --- a/core/shared/src/main/scala/shapeless/lenses.scala +++ b/core/shared/src/main/scala/shapeless/lenses.scala @@ -159,7 +159,7 @@ object OpticDefns { def apply[C] = id[C] object compose extends Poly2 { - implicit def default[A, B, C] = at[Lens[B, C], Lens[A, B]](_ compose _) + implicit def default[A, B, C]: Case.Aux[Lens[B, C], Lens[A, B], Lens[A, C]] = at[Lens[B, C], Lens[A, B]](_ compose _) } class RootLens[C] extends Lens[C, C] { @@ -245,10 +245,10 @@ object MkFieldLens { implicit def mkFieldLens[A, K, R <: HList, B] (implicit mkGen: MkLabelledGenericLens.Aux[A, R], - mkLens: MkRecordSelectLens[R, K]): Aux[A, K, mkLens.Elem] = + mkLens: MkRecordSelectLens.Aux[R, K, B]): Aux[A, K, B] = new MkFieldLens[A, K] { - type Elem = mkLens.Elem - def apply(): Lens[A, mkLens.Elem] = mkLens() compose mkGen() + type Elem = B + def apply(): Lens[A, B] = mkLens() compose mkGen() } } diff --git a/core/shared/src/main/scala/shapeless/ops/hlists.scala b/core/shared/src/main/scala/shapeless/ops/hlists.scala index 0de769267..6930bcf8f 100644 --- a/core/shared/src/main/scala/shapeless/ops/hlists.scala +++ b/core/shared/src/main/scala/shapeless/ops/hlists.scala @@ -121,35 +121,35 @@ object hlist { object NatTRel { def apply[L1 <: HList, F1[_], L2 <: HList, F2[_]](implicit natTRel: NatTRel[L1, F1, L2, F2]) = natTRel - implicit def hnilNatTRel1[F1[_], F2[_]] = new NatTRel[HNil, F1, HNil, F2] { + implicit def hnilNatTRel1[F1[_], F2[_]]: NatTRel[HNil, F1, HNil, F2] = new NatTRel[HNil, F1, HNil, F2] { def map(f: F1 ~> F2, fa: HNil): HNil = HNil } - implicit def hnilNatTRel2[F1[_], H2] = new NatTRel[HNil, F1, HNil, Const[H2]#λ] { + implicit def hnilNatTRel2[F1[_], H2]: NatTRel[HNil, F1, HNil, Const[H2]#λ] = new NatTRel[HNil, F1, HNil, Const[H2]#λ] { def map(f: F1 ~> Const[H2]#λ, fa: HNil): HNil = HNil } - implicit def hlistNatTRel1[H, F1[_], F2[_], T1 <: HList, T2 <: HList](implicit nt : NatTRel[T1, F1, T2, F2]) = + implicit def hlistNatTRel1[H, F1[_], F2[_], T1 <: HList, T2 <: HList](implicit nt : NatTRel[T1, F1, T2, F2]): NatTRel[F1[H] :: T1, F1, F2[H] :: T2, F2] = new NatTRel[F1[H] :: T1, F1, F2[H] :: T2, F2] { def map(f: F1 ~> F2, fa: F1[H] :: T1): F2[H] :: T2 = f(fa.head) :: nt.map(f, fa.tail) } - implicit def hlistNatTRel2[H, F2[_], T1 <: HList, T2 <: HList](implicit nt : NatTRel[T1, Id, T2, F2]) = + implicit def hlistNatTRel2[H, F2[_], T1 <: HList, T2 <: HList](implicit nt : NatTRel[T1, Id, T2, F2]): NatTRel[H :: T1, Id, F2[H] :: T2, F2] = new NatTRel[H :: T1, Id, F2[H] :: T2, F2] { def map(f: Id ~> F2, fa: H :: T1): F2[H] :: T2 = f(fa.head) :: nt.map(f, fa.tail) } - implicit def hlistNatTRel3[H, F1[_], T1 <: HList, T2 <: HList](implicit nt : NatTRel[T1, F1, T2, Id]) = + implicit def hlistNatTRel3[H, F1[_], T1 <: HList, T2 <: HList](implicit nt : NatTRel[T1, F1, T2, Id]): NatTRel[F1[H] :: T1, F1, H :: T2, Id] = new NatTRel[F1[H] :: T1, F1, H :: T2, Id] { def map(f: F1 ~> Id, fa: F1[H] :: T1): H :: T2 = f(fa.head) :: nt.map(f, fa.tail) } - implicit def hlistNatTRel4[H1, F1[_], T1 <: HList, H2, T2 <: HList](implicit nt : NatTRel[T1, F1, T2, Const[H2]#λ]) = + implicit def hlistNatTRel4[H1, F1[_], T1 <: HList, H2, T2 <: HList](implicit nt : NatTRel[T1, F1, T2, Const[H2]#λ]): NatTRel[F1[H1] :: T1, F1, H2 :: T2, Const[H2]#λ] = new NatTRel[F1[H1] :: T1, F1, H2 :: T2, Const[H2]#λ] { def map(f: F1 ~> Const[H2]#λ, fa: F1[H1] :: T1): H2 :: T2 = f(fa.head) :: nt.map(f, fa.tail) } - implicit def hlistNatTRel5[H1, T1 <: HList, H2, T2 <: HList](implicit nt : NatTRel[T1, Id, T2, Const[H2]#λ]) = + implicit def hlistNatTRel5[H1, T1 <: HList, H2, T2 <: HList](implicit nt : NatTRel[T1, Id, T2, Const[H2]#λ]): NatTRel[H1 :: T1, Id, H2 :: T2, Const[H2]#λ] = new NatTRel[H1 :: T1, Id, H2 :: T2, Const[H2]#λ] { def map(f: Id ~> Const[H2]#λ, fa: H1 :: T1): H2 :: T2 = f(fa.head) :: nt.map(f, fa.tail) } @@ -214,12 +214,12 @@ object hlist { type Aux[L <: HList, Out0 <: HKernel] = HKernelAux[L] { type Out = Out0 } - implicit def mkHNilHKernel = new HKernelAux[HNil] { + implicit def mkHNilHKernel: Aux[HNil, HNilHKernel] = new HKernelAux[HNil] { type Out = HNilHKernel def apply() = HNilHKernel } - implicit def mkHListHKernel[H, T <: HList, CtOut <: HKernel](implicit ct: HKernelAux.Aux[T, CtOut]) = new HKernelAux[H :: T] { + implicit def mkHListHKernel[H, T <: HList, CtOut <: HKernel](implicit ct: HKernelAux.Aux[T, CtOut]): Aux[H :: T, HConsHKernel[H, CtOut]] = new HKernelAux[H :: T] { type Out = HConsHKernel[H, CtOut] def apply() = HConsHKernel[H, CtOut](ct()) } @@ -2740,7 +2740,7 @@ object hlist { type Aux[L <: HList, V, P <: Poly, Out0 <: HList] = RightScanner0[L, V, P] { type Out = Out0 } } - implicit def hlistRightScanner0[H, H0, T <: HList, P <: Poly, C2Result](implicit ev: Case2.Aux[P, H0, H, C2Result]) = + implicit def hlistRightScanner0[H, H0, T <: HList, P <: Poly, C2Result](implicit ev: Case2.Aux[P, H0, H, C2Result]): RightScanner0.Aux[H :: T, H0, P, C2Result :: H :: T] = new RightScanner0[H :: T, H0, P]{ type Out = C2Result :: H :: T @@ -2845,7 +2845,7 @@ object hlist { } implicit def hlistPatch2[M <: Nat, L <: HList, In <: HList, OutL <: HList, OutP <: HList] - (implicit drop: Drop.Aux[L, M, OutL], prepend: Prepend.Aux[In, OutL, OutP]) = + (implicit drop: Drop.Aux[L, M, OutL], prepend: Prepend.Aux[In, OutL, OutP]): Patcher.Aux[_0, M, L, In, OutP] = new Patcher[_0, M, L, In]{ type Out = OutP @@ -3049,7 +3049,7 @@ object hlist { } trait LowPriorityCombinations { - implicit def combinationHNil[N <: Nat] = + implicit def combinationHNil[N <: Nat]: Combinations.Aux[N, HNil, HNil] = new Combinations[N, HNil] { type Out = HNil def apply(l: HNil): Out = HNil diff --git a/core/shared/src/main/scala/shapeless/ops/nat.scala b/core/shared/src/main/scala/shapeless/ops/nat.scala index 6f5502683..e6b100e4d 100644 --- a/core/shared/src/main/scala/shapeless/ops/nat.scala +++ b/core/shared/src/main/scala/shapeless/ops/nat.scala @@ -140,14 +140,14 @@ object nat { object LT extends LT0 { def apply[A <: Nat, B <: Nat](implicit lt: A < B): LT[A, B] = lt - implicit def lt1[B <: Nat] = new <[_0, Succ[B]] {} - implicit def lt2[A <: Nat, B <: Nat](implicit lt : A < B) = new <[Succ[A], Succ[B]] {} + implicit def lt1[B <: Nat]: _0 < Succ[B] = new <[_0, Succ[B]] {} + implicit def lt2[A <: Nat, B <: Nat](implicit lt : A < B): Succ[A] < Succ[B] = new <[Succ[A], Succ[B]] {} } trait LT0 { type <[A <: Nat, B <: Nat] = LT[A, B] - implicit def lt3[A <: Nat] = new <[A, Succ[A]] {} + implicit def lt3[A <: Nat]: A < Succ[A] = new <[A, Succ[A]] {} } /** @@ -160,15 +160,15 @@ object nat { object LTEq extends LTEq0 { def apply[A <: Nat, B <: Nat](implicit lteq: A <= B): LTEq[A, B] = lteq - implicit def ltEq1[A <: Nat] = new <=[A, A] {} - implicit def ltEq2[A <: Nat] = new <=[A, Succ[A]] {} + implicit def ltEq1[A <: Nat]: A <= A = new <=[A, A] {} + implicit def ltEq2[A <: Nat]: A <= Succ[A] = new <=[A, Succ[A]] {} } trait LTEq0 { type <=[A <: Nat, B <: Nat] = LTEq[A, B] - implicit def ltEq3[B <: Nat] = new <=[_0, B] {} - implicit def ltEq4[A <: Nat, B <: Nat](implicit lteq : A <= B) = new <=[Succ[A], Succ[B]] {} + implicit def ltEq3[B <: Nat]: _0 <= B = new <=[_0, B] {} + implicit def ltEq4[A <: Nat, B <: Nat](implicit lteq : A <= B): Succ[A] <= Succ[B] = new <=[Succ[A], Succ[B]] {} } /** diff --git a/core/shared/src/main/scala/shapeless/ops/tuples.scala b/core/shared/src/main/scala/shapeless/ops/tuples.scala index e1eb014eb..ec735601a 100644 --- a/core/shared/src/main/scala/shapeless/ops/tuples.scala +++ b/core/shared/src/main/scala/shapeless/ops/tuples.scala @@ -1243,7 +1243,7 @@ object tuple { (implicit gen: Generic.Aux[T, L], genIn: Generic.Aux[InT, InL], patch: hl.Patcher.Aux[N, M, L, InL, OutL], - tp: hl.Tupler[OutL]) = + tp: hl.Tupler[OutL]): Patcher[N, M, T, InT] { type Out = tp.Out } = new Patcher[N, M, T, InT]{ type Out = tp.Out diff --git a/core/shared/src/main/scala/shapeless/poly.scala b/core/shared/src/main/scala/shapeless/poly.scala index c3add45cc..cd73c6ddf 100644 --- a/core/shared/src/main/scala/shapeless/poly.scala +++ b/core/shared/src/main/scala/shapeless/poly.scala @@ -73,7 +73,7 @@ object PolyDefns extends Cases { object Compose { implicit def composeCase[C, F <: Poly, G <: Poly, T, U, V] - (implicit unpack: Unpack2[C, Compose, F, G], cG : Case1.Aux[G, T, U], cF : Case1.Aux[F, U, V]) = new Case[C, T :: HNil] { + (implicit unpack: Unpack2[C, Compose, F, G], cG : Case1.Aux[G, T, U], cF : Case1.Aux[F, U, V]): Case.Aux[C, T :: HNil, V] = new Case[C, T :: HNil] { type Result = V val value = (t : T :: HNil) => cF(cG.value(t)) } @@ -170,11 +170,11 @@ object PolyDefns extends Cases { * Base class for lifting a `Function1` to a `Poly1` */ class ->[T, R](f : T => R) extends Poly1 { - implicit def subT[U <: T] = at[U](f) + implicit def subT[U <: T]: Case.Aux[U, R] = at[U](f) } trait LowPriorityLiftFunction1 extends Poly1 { - implicit def default[T] = at[T](_ => HNil : HNil) + implicit def default[T]: Case.Aux[T, HNil] = at[T](_ => HNil : HNil) } /** @@ -182,11 +182,11 @@ object PolyDefns extends Cases { * its only element if the argument is in the original functions domain, `HNil` otherwise. */ class >->[T, R](f : T => R) extends LowPriorityLiftFunction1 { - implicit def subT[U <: T] = at[U](f(_) :: HNil) + implicit def subT[U <: T]: Case.Aux[U, R :: HNil] = at[U](f(_) :: HNil) } trait LowPriorityLiftU extends Poly { - implicit def default[L <: HList] = new ProductCase[L] { + implicit def default[L <: HList]: ProductCase.Aux[L, HNil] = new ProductCase[L] { type Result = HNil val value = (l : L) => HNil } @@ -197,7 +197,7 @@ object PolyDefns extends Cases { * only element if the argument is in the original functions domain, `HNil` otherwise. */ class LiftU[P <: Poly](p : P) extends LowPriorityLiftU { - implicit def defined[L <: HList](implicit caseT : Case[P, L]) = new ProductCase[L] { + implicit def defined[L <: HList](implicit caseT : Case[P, L]): ProductCase.Aux[L, caseT.Result :: HNil] = new ProductCase[L] { type Result = caseT.Result :: HNil val value = (l : L) => caseT(l) :: HNil } diff --git a/core/shared/src/main/scala/shapeless/syntax/std/functions.scala b/core/shared/src/main/scala/shapeless/syntax/std/functions.scala index 5aa6e1e39..0c1ae3189 100644 --- a/core/shared/src/main/scala/shapeless/syntax/std/functions.scala +++ b/core/shared/src/main/scala/shapeless/syntax/std/functions.scala @@ -29,12 +29,12 @@ package std object function { import ops.function._ - implicit def fnHListOps[F, T <: HList, R](t: F)(implicit fnHLister: FnToProduct.Aux[F, T => R]) = new FnHListOps[T => R] { + implicit def fnHListOps[F, T <: HList, R](t: F)(implicit fnHLister: FnToProduct.Aux[F, T => R]): FnHListOps[T => R] = new FnHListOps[T => R] { def toProduct = fnHLister(t) } - implicit def fnUnHListOps[F](t : F)(implicit fnUnHLister : FnFromProduct[F]) = new FnUnHListOps[fnUnHLister.Out] { + implicit def fnUnHListOps[F](t : F)(implicit fnUnHLister : FnFromProduct[F]): FnUnHListOps[fnUnHLister.Out] = new FnUnHListOps[fnUnHLister.Out] { def fromProduct = fnUnHLister(t) } } diff --git a/core/shared/src/main/scala/shapeless/syntax/std/maps.scala b/core/shared/src/main/scala/shapeless/syntax/std/maps.scala index 65cf90fd7..ba85c3b4e 100644 --- a/core/shared/src/main/scala/shapeless/syntax/std/maps.scala +++ b/core/shared/src/main/scala/shapeless/syntax/std/maps.scala @@ -23,7 +23,7 @@ import shapeless.ops.maps.FromMap * Conversions between `Map` and `Records`. */ object maps { - implicit def mapOps[K, V](m: Map[K, V]) = new MapOps[K, V](m) + implicit def mapOps[K, V](m: Map[K, V]): MapOps[K, V] = new MapOps[K, V](m) } final class MapOps[K, V](m: Map[K, V]) { diff --git a/core/shared/src/main/scala/shapeless/syntax/zipper.scala b/core/shared/src/main/scala/shapeless/syntax/zipper.scala index 1fb1eb5bf..1de1c3062 100644 --- a/core/shared/src/main/scala/shapeless/syntax/zipper.scala +++ b/core/shared/src/main/scala/shapeless/syntax/zipper.scala @@ -18,8 +18,8 @@ package shapeless package syntax object zipper { - implicit def toZipper[L <: HList](l: L) = new HListZipperOps(l) - implicit def toZipper[C, CL <: HList](c : C)(implicit gen : Generic.Aux[C, CL]) = new GenericZipperOps(c) + implicit def toZipper[L <: HList](l: L): HListZipperOps[L] = new HListZipperOps(l) + implicit def toZipper[C, CL <: HList](c : C)(implicit gen : Generic.Aux[C, CL]): GenericZipperOps[C, CL] = new GenericZipperOps(c) } /** Enhances values of any type with a representation via `Generic` with a method supporting conversion to a `Zipper`. */ diff --git a/core/shared/src/main/scala/shapeless/typeoperators.scala b/core/shared/src/main/scala/shapeless/typeoperators.scala index 98e731db4..1f26b83d4 100644 --- a/core/shared/src/main/scala/shapeless/typeoperators.scala +++ b/core/shared/src/main/scala/shapeless/typeoperators.scala @@ -195,7 +195,7 @@ trait Lub[-A, -B, Out] extends Serializable { } object Lub { - implicit def lub[T] = new Lub[T, T, T] { + implicit def lub[T]: Lub[T, T, T] = new Lub[T, T, T] { def left(a : T): T = a def right(b : T): T = b } diff --git a/core/shared/src/main/scala/shapeless/unwrapped.scala b/core/shared/src/main/scala/shapeless/unwrapped.scala index bedf51ada..ef8674d04 100644 --- a/core/shared/src/main/scala/shapeless/unwrapped.scala +++ b/core/shared/src/main/scala/shapeless/unwrapped.scala @@ -34,7 +34,7 @@ trait UnwrappedInstances extends LowPriorityUnwrappedInstances { gen: Generic.Aux[W, Repr], avh: AnyValHelper.Aux[Repr, UI], chain: Strict[Unwrapped.Aux[UI, UF]] - ) = new Unwrapped[W] { + ): Unwrapped.Aux[W, UF] = new Unwrapped[W] { type U = UF def unwrap(w: W): U = chain.value.unwrap(avh.unwrap(gen.to(w))) def wrap(u: U): W = gen.from(avh.wrap(chain.value.wrap(u))) @@ -47,7 +47,7 @@ trait UnwrappedInstances extends LowPriorityUnwrappedInstances { } object AnyValHelper { type Aux[Repr, U0] = AnyValHelper[Repr] { type U = U0 } - implicit def sizeOneHListHelper[T] = + implicit def sizeOneHListHelper[T]: Aux[T :: HNil, T] = SizeOneHListHelper.asInstanceOf[AnyValHelper.Aux[T :: HNil, T]] val SizeOneHListHelper = new AnyValHelper[Any :: HNil] { type U = Any @@ -58,11 +58,11 @@ trait UnwrappedInstances extends LowPriorityUnwrappedInstances { implicit def newtypeUnwrapped[UI, Ops, UF](implicit chain: Strict[Unwrapped.Aux[UI, UF]] - ) = chain.value.asInstanceOf[Unwrapped.Aux[Newtype[UI, Ops], UF]] + ): Unwrapped.Aux[Newtype[UI, Ops], UF] = chain.value.asInstanceOf[Unwrapped.Aux[Newtype[UI, Ops], UF]] implicit def tagUnwrapped[T[UI, TT] <: tag.@@[UI, TT], UI, TT, UF](implicit chain: Strict[Unwrapped.Aux[UI, UF]] - ) = chain.value.asInstanceOf[Unwrapped.Aux[T[UI, TT], UF]] + ): Unwrapped.Aux[T[UI, TT], UF] = chain.value.asInstanceOf[Unwrapped.Aux[T[UI, TT], UF]] } @@ -73,6 +73,6 @@ trait LowPriorityUnwrappedInstances { def unwrap(t: Any) = t def wrap(t: Any) = t } - implicit def selfUnwrapped[T] = + implicit def selfUnwrapped[T]: Unwrapped.Aux[T,T] = theSelfUnwrapped.asInstanceOf[Unwrapped.Aux[T, T]] } diff --git a/core/shared/src/test/scala/shapeless/generic.scala b/core/shared/src/test/scala/shapeless/generic.scala index a5cf69928..9aa6610d6 100644 --- a/core/shared/src/test/scala/shapeless/generic.scala +++ b/core/shared/src/test/scala/shapeless/generic.scala @@ -171,6 +171,13 @@ package GenericTestsAux { def apply(y: String): Priv = new Priv(y) def unapply(p: Priv): Some[String] = Some(p.y) } + + object macroAnnotations { + case class A(i: Int, s: String) + + @generateGeneric + object A + } } class GenericTests { diff --git a/coreTestMacros/shared/src/main/scala/shapeless/generateGeneric.scala b/coreTestMacros/shared/src/main/scala/shapeless/generateGeneric.scala new file mode 100644 index 000000000..3f4000fc9 --- /dev/null +++ b/coreTestMacros/shared/src/main/scala/shapeless/generateGeneric.scala @@ -0,0 +1,35 @@ +package shapeless + +import scala.annotation.{StaticAnnotation, compileTimeOnly} +import scala.reflect.macros.blackbox +import scala.language.experimental.macros + +@compileTimeOnly("enable macro annotations") +class generateGeneric extends StaticAnnotation { + def macroTransform(annottees: Any*): Any = macro GenerateGenericMacroImpl.macroTransformImpl +} + +object GenerateGenericMacroImpl { + def macroTransformImpl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = { + import c.universe._ + + def modifyObject(obj: Tree): Tree = obj match { + case q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }" => + q"""$mods object $tname extends { ..$earlydefns } with ..$parents { $self => + ..$body + _root_.shapeless.Generic[${tname.toTypeName}](_root_.shapeless.Generic.materialize) + }""" + case _ => sys.error("impossible") + } + + def modify(cls: Tree, obj: Tree): Tree = q"..${Seq(cls, modifyObject(obj))}" + + annottees match { + case (cls: ClassDef) :: (obj: ModuleDef) :: Nil => modify(cls, obj) + case (cls: ClassDef) :: Nil => modify(cls, q"object ${cls.name.toTermName}") + // this works for the companion object of a sealed trait or top-level case class but not nested case class + case (obj: ModuleDef) :: Nil => modifyObject(obj) + case _ => c.abort(c.enclosingPosition, "@generateGeneric can annotate only traits, classes, and objects") + } + } +} \ No newline at end of file