Skip to content

Commit

Permalink
Merge branch 'main' into SO-74364545-nested-macro-annotation-generic
Browse files Browse the repository at this point in the history
  • Loading branch information
joroKr21 authored Apr 25, 2024
2 parents b1e70c0 + 977f354 commit daee253
Show file tree
Hide file tree
Showing 23 changed files with 102 additions and 107 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
scala: [2.12.17, 2.13.10]
scala: [2.12.19, 2.13.11]
java: [adopt@1.8]
platform: [jvm, js, native]
runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -75,7 +75,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [2.13.10]
scala: [2.13.11]
java: [adopt@1.8]
runs-on: ${{ matrix.os }}
steps:
Expand Down
38 changes: 16 additions & 22 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import com.typesafe.sbt.SbtGit.GitKeys._
import com.github.sbt.git.SbtGit.GitKeys.*
import sbtcrossproject.CrossProject

val Scala212 = "2.12.17"
val Scala213 = "2.13.10"
val Scala212 = "2.12.19"
val Scala213 = "2.13.11"

commonSettings
noPublishSettings
Expand Down Expand Up @@ -59,32 +59,26 @@ addCommandAlias("runAll", ";examplesJVM/runAll")

def scalacOptionsAll(pluginJar: File) = List(
"-feature",
"-language:higherKinds,implicitConversions",
"-Xfatal-warnings",
"-deprecation",
"-unchecked",
"-language:higherKinds,implicitConversions",
"-Xfatal-warnings",
"-Wconf:cat=other-implicit-type:s",
s"-Xplugin:${pluginJar.getAbsolutePath}",
s"-Jdummy=${pluginJar.lastModified}"
)

val scalacOptions212 = Seq(
"-Xlint:-adapted-args,-delayedinit-select,-nullary-unit,-package-object-classes,-type-parameter-shadow,_",
"-Ywarn-unused:-implicits"
)

val scalacOptions213 = Seq(
"-Xlint:-adapted-args,-delayedinit-select,-nullary-unit,-package-object-classes,-type-parameter-shadow,-byname-implicit,_",
"-Ywarn-unused:-implicits"
)

lazy val commonSettings = crossVersionSharedSources ++ Seq(
resolvers ++= Resolver.sonatypeOssRepos("releases"),
resolvers ++= Resolver.sonatypeOssRepos("snapshots"),
incOptions := incOptions.value.withLogRecompileOnMacro(false),
scalacOptions := scalacOptionsAll((plugin / Compile / packageBin).value),
Compile / compile / scalacOptions ++= (CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 12)) => scalacOptions212
case Some((2, 13)) => scalacOptions213
Compile / compile / scalacOptions ++= Seq(
"-Ywarn-unused:-implicits",
"-Xlint:-adapted-args,-delayedinit-select,-nullary-unit,-package-object-classes,-type-parameter-shadow,_"
),
Compile / compile / scalacOptions ++= (scalaBinaryVersion.value match {
case "2.13" => Seq("-Xlint:-byname-implicit")
case _ => Nil
}),
Compile / console / scalacOptions -= "-Xfatal-warnings",
Expand Down Expand Up @@ -184,7 +178,7 @@ lazy val examples = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.configureCross(configureJUnit)
.dependsOn(core)
.settings(moduleName := "examples")
.settings(libraryDependencies += "org.scala-lang.modules" %%% "scala-parser-combinators" % "2.2.0")
.settings(libraryDependencies += "org.scala-lang.modules" %%% "scala-parser-combinators" % "2.3.0")
.settings(runAllIn(Compile))
.settings(commonSettings)
.settings(noPublishSettings)
Expand All @@ -194,7 +188,7 @@ lazy val examplesJVM = examples.jvm
lazy val examplesJS = examples.js
lazy val examplesNative = examples.native

lazy val crossVersionSharedSources: Seq[Setting[_]] =
lazy val crossVersionSharedSources: Seq[Setting[?]] =
Seq(Compile, Test).map { sc =>
(sc / unmanagedSourceDirectories) ++= {
(sc / unmanagedSourceDirectories).value.flatMap { dir: File =>
Expand All @@ -211,10 +205,10 @@ lazy val publishSettings = Seq(
Test / publishArtifact := false,
pomIncludeRepository := (_ => false),
homepage := Some(url("https://github.com/milessabin/shapeless")),
licenses := Seq("Apache 2" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt")),
licenses := Seq("Apache 2" -> url("https://www.apache.org/licenses/LICENSE-2.0.txt")),
scmInfo := Some(ScmInfo(url("https://github.com/milessabin/shapeless"), "scm:git:git@github.com:milessabin/shapeless.git")),
developers := List(
Developer("milessabin", "Miles Sabin", "", url("http://milessabin.com/blog")),
Developer("milessabin", "Miles Sabin", "", url("https://milessabin.com/blog")),
Developer("joroKr21", "Georgi Krastev", "joro.kr.21@gmail.com", url("https://twitter.com/Joro_Kr"))
)
)
Expand Down
4 changes: 2 additions & 2 deletions core/shared/src/main/scala/shapeless/conversions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
2 changes: 1 addition & 1 deletion core/shared/src/main/scala/shapeless/coproduct.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion core/shared/src/main/scala/shapeless/hmap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
8 changes: 4 additions & 4 deletions core/shared/src/main/scala/shapeless/lenses.scala
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,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] {
Expand Down Expand Up @@ -248,10 +248,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()
}
}

Expand Down
24 changes: 12 additions & 12 deletions core/shared/src/main/scala/shapeless/ops/hlists.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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())
}
Expand Down Expand Up @@ -2749,7 +2749,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

Expand Down Expand Up @@ -2854,7 +2854,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

Expand Down Expand Up @@ -3058,7 +3058,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
Expand Down
14 changes: 7 additions & 7 deletions core/shared/src/main/scala/shapeless/ops/nat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]] {}
}

/**
Expand All @@ -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]] {}
}

/**
Expand Down
4 changes: 2 additions & 2 deletions core/shared/src/main/scala/shapeless/ops/traversables.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ object traversable {

import syntax.typeable._

implicit def hnilFromTraversable[T] = new FromTraversable[HNil] {
implicit def hnilFromTraversable[T]: FromTraversable[HNil] = new FromTraversable[HNil] {
def apply(l : Iterable[_]) =
if(l.isEmpty) Some(HNil) else None
}

implicit def hlistFromTraversable[OutH, OutT <: HList]
(implicit flt : FromTraversable[OutT], oc : Typeable[OutH]) = new FromTraversable[OutH :: OutT] {
(implicit flt : FromTraversable[OutT], oc : Typeable[OutH]): FromTraversable[OutH :: OutT] = new FromTraversable[OutH :: OutT] {
def apply(l : Iterable[_]) : Option[OutH :: OutT] =
if(l.isEmpty) None
else for(h <- l.head.cast[OutH]; t <- flt(l.tail)) yield h :: t
Expand Down
2 changes: 1 addition & 1 deletion core/shared/src/main/scala/shapeless/ops/tuples.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
12 changes: 6 additions & 6 deletions core/shared/src/main/scala/shapeless/poly.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
Expand Down Expand Up @@ -170,23 +170,23 @@ 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)
}

/**
* Base class for lifting a `Function1` to a `Poly1` over the universal domain, yielding an `HList` with the result as
* 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
}
Expand All @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions core/shared/src/main/scala/shapeless/syntax/sized.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ package syntax

object sized {
implicit def genTraversableSizedConv[Repr](cc : Repr)
(implicit iil: IsRegularIterable[Repr], ev : AdditiveCollection[Repr]) =
(implicit iil: IsRegularIterable[Repr], ev : AdditiveCollection[Repr]): SizedConv[Repr] =
new SizedConv[Repr](cc)

implicit def stringSizedConv(s : String) = new SizedConv[String](s)
implicit def stringSizedConv(s : String): SizedConv[String] = new SizedConv[String](s)
}

final class SizedConv[Repr](r : Repr)(implicit iil: IsRegularIterable[Repr], ev2: AdditiveCollection[Repr]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/shared/src/main/scala/shapeless/syntax/std/maps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]) {
Expand Down
Loading

0 comments on commit daee253

Please sign in to comment.